Rotating an image context (CGContextRotateCTM) causing it to become blank. Why?

前端 未结 5 1170
一生所求
一生所求 2020-12-05 00:23
#define radians(degrees) (degrees * M_PI/180)

UIImage *rotate(UIImage *image) {
  CGSize size = image.size;;

  UIGraphicsBeginImageContext(size);
  CGContextRef co         


        
相关标签:
5条回答
  • 2020-12-05 00:38

    Expanding on Nielsbot's answer, I created the following snippet. Note that this should preferably be made a function rather than a code snippet, to prevent 'copy/paste programming'. I didn't get to that yet, so feel free to adapt it.

    Code snippet:

    // <Draw in frame with orientation>
    UIImage* imageToDrawRotated = <#image#>;
    float rotationAngle = <#angle#>;
    CGRect drawFrame = CGRectMake(<#CGFloat x#>, <#CGFloat y#>, <#CGFloat width#>, <#CGFloat height#>);
    CGContextTranslateCTM(UIGraphicsGetCurrentContext(), floor(drawFrame.origin.x + drawFrame.size.width/2), floor(drawFrame.origin.y + drawFrame.size.height/2));
    CGContextRotateCTM(UIGraphicsGetCurrentContext(), rotationAngle);
    [imageToDrawRotated drawInRect:CGRectMake(-floor(drawFrame.size.width/2), -floor(drawFrame.size.height/2), drawFrame.size.width, drawFrame.size.height)];
    CGContextRotateCTM(UIGraphicsGetCurrentContext(), -rotationAngle);
    CGContextTranslateCTM(UIGraphicsGetCurrentContext(), -floor(drawFrame.origin.x + drawFrame.size.width/2), -floor(drawFrame.origin.y + drawFrame.size.height/2));
    // </Draw in frame with orientation>
    

    Also, I welcome a better way to reset the CGContext to its previous state.

    0 讨论(0)
  • 2020-12-05 00:43

    I try followed code, it works, get from http://www.catamount.com/blog/1015/uiimage-extensions-for-cutting-scaling-and-rotating-uiimages/

    + (UIImage *)rotateImage:(UIImage*)src byRadian:(CGFloat)radian
    {
        // calculate the size of the rotated view's containing box for our drawing space
        //UIView *rotatedViewBox = [[UIView alloc] initWithFrame:CGRectMake(0,0, src.size.width, src.size.height)];
        //CGAffineTransform t = CGAffineTransformMakeRotation(radian);
        //rotatedViewBox.transform = t;
        //CGSize rotatedSize = rotatedViewBox.frame.size;
        CGRect rect = CGRectApplyAffineTransform(CGRectMake(0,0, src.size.width, src.size.height), CGAffineTransformMakeRotation(radian));
        CGSize rotatedSize = rect.size;
    
        // Create the bitmap context
        UIGraphicsBeginImageContext(rotatedSize);
        CGContextRef bitmap = UIGraphicsGetCurrentContext();
    
        // Move the origin to the middle of the image so we will rotate and scale around the center.
        CGContextTranslateCTM(bitmap, rotatedSize.width/2, rotatedSize.height/2);
    
        //   // Rotate the image context
        CGContextRotateCTM(bitmap, radian);
    
        // Now, draw the rotated/scaled image into the context
        CGContextScaleCTM(bitmap, 1.0, -1.0);
        CGContextDrawImage(bitmap, CGRectMake(-src.size.width / 2, -src.size.height / 2, src.size.width, src.size.height), [src CGImage]);
    
        UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
        return newImage;
    }
    
    0 讨论(0)
  • 2020-12-05 00:48

    The problem is your context is being rotated around (0,0) which is the top left corner. If you rotate 90 degrees around the top left corner, all your drawing will occur out of the bounds of the context. You need a 2-step transform to move the origin of the context to it's middle, and THEN rotate. Also you need to draw your image centered around the moved/rotated origin, like this:

    CGContextTranslateCTM( context, 0.5f * size.width, 0.5f * size.height ) ;
    CGContextRotateCTM( context, radians( 90 ) ) ;
    
    [ image drawInRect:(CGRect){ { -size.width * 0.5f, -size.height * 0.5f }, size } ] ;
    

    HTH

    0 讨论(0)
  • 2020-12-05 00:52

    I liked the solution by @lbsweek but I was bit worried about alloc ing UIView just for transform, instead I tried the below

    - (UIImage *)rotateImage:(UIImage *)sourceImage byDegrees:(float)degrees
    {
        CGFloat radian = degrees * (M_PI/ 180);
        CGRect contextRect = CGRectMake(0, 0, sourceImage.size.width, sourceImage.size.height);
        float newSide = MAX([sourceImage size].width, [sourceImage size].height);
        CGSize newSize =  CGSizeMake(newSide, newSide);
        UIGraphicsBeginImageContext(newSize);
        CGContextRef ctx = UIGraphicsGetCurrentContext();
        CGPoint contextCenter = CGPointMake(CGRectGetMidX(contextRect), CGRectGetMidY(contextRect));
        CGContextTranslateCTM(ctx, contextCenter.x, contextCenter.y);
        CGContextRotateCTM(ctx, radian);
        CGContextTranslateCTM(ctx, -contextCenter.x, -contextCenter.y);
        [sourceImage drawInRect:contextRect];
        UIImage* rotatedImage = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
        return rotatedImage;
    }
    
    0 讨论(0)
  • 2020-12-05 00:54

    If you don't want to change all the origins and sizes, move the center, rotate and change the center to corner again like this:

    CGContextTranslateCTM( context, 0.5f * size.width, 0.5f * size.height ) ; CGContextRotateCTM( context, radians( 90 ) ) ; CGContextTranslateCTM( context, -0.5f * size.width, -0.5f * size.height ) ;

    Then draw normally like this:

    [image drawInRect:CGRectMake(0, 0, size.width, size.height)];

    0 讨论(0)
提交回复
热议问题