旋转图像上下文 (CGContextRotateCTM) 使其变为空白。为啥?

Posted

技术标签:

【中文标题】旋转图像上下文 (CGContextRotateCTM) 使其变为空白。为啥?【英文标题】:Rotating an image context (CGContextRotateCTM) causing it to become blank. Why?旋转图像上下文 (CGContextRotateCTM) 使其变为空白。为什么? 【发布时间】:2011-05-12 19:05:06 【问题描述】:
#define radians(degrees) (degrees * M_PI/180)

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

  UIGraphicsBeginImageContext(size);
  CGContextRef context = UIGraphicsGetCurrentContext();

  // If this is commented out, image is returned as it is.
  CGContextRotateCTM (context, radians(90));

  [image drawInRect:CGRectMake(0, 0, size.width, size.height)];
  UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
  UIGraphicsEndImageContext();

  return newImage;

会不会有其他问题?没有想法。

【问题讨论】:

在catamount.com/blog/1015/…查看 Hardy Macia 的简单而令人敬畏的代码,谢谢 Hardy Macia! 【参考方案1】:

问题是您的上下文正在围绕左上角的 (0,0) 旋转。如果您围绕左上角旋转 90 度,您的所有绘图都将出现在上下文范围之外。您需要一个两步变换来将上下文的原点移动到它的中间,然后旋转。您还需要以移动/旋转的原点为中心绘制图像,如下所示:

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

【讨论】:

对,就是图片旋转的轴。但是该代码没有帮助。无论如何,弄清楚了正确的。将尽快发布作为答案。 +1 的答案。非常感谢! hm.. 是旋转然后翻译?我有时会混淆顺序。 谢谢!这对我有用。我通过恢复上下文来扩展这一点,这是我能找到的唯一方法。让我把它贴在一个新的答案中。 Timo——您可以通过调用 CGContextSaveGState() 来保存变换矩阵,然后在完成后调用 CGContextRestoreGState()【参考方案2】:

我尝试遵循代码,它有效,来自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;

【讨论】:

创建一个新视图只是为了获取旋转矩形的边界有点疯狂。您可以简单地将这里的前 4 行代码替换为:CGSize rotatedSize = CGSizeMake(src.size.height, src.size.width); @CraigMcMahon 你是对的。因为我的意思是展示 CTM 功能,所以使用最简单但有效的方法来获取绑定,在使用您的代码时应该是完美的。 @CraigMcMahon 正确的用法应该是这样的:CGSize rotatedSize = CGRectApplyAffineTransform(CGRectMake(0,0, src.size.width, src.size.height), CGAffineTransformMakeRotation(radian));【参考方案3】:

如果您不想更改所有原点和大小,请像这样移动中心、旋转并再次将中心更改为角:

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

然后像这样正常绘制:

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

【讨论】:

如果您能通过一些插图达到预期的效果,我将不胜感激。特别是,这是否需要,因为旋转发生在上下文的中心?【参考方案4】:

扩展 Nielsbot 的答案,我创建了以下 sn-p。请注意,最好将其设为函数而不是代码 sn-p,以防止“复制/粘贴编程”。我还没有做到这一点,所以请随意调整。

代码sn-p:

// <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>

另外,我欢迎使用更好的方法将 CGContext 重置为之前的状态。

【讨论】:

更好的方法?您可以只使用 CGContextSaveGState/CGContextRestoreGState【参考方案5】:

我喜欢@lbsweek 的解决方案,但我有点担心分配 UIView 只是为了进行转换,而是尝试了以下方法

- (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;

【讨论】:

以上是关于旋转图像上下文 (CGContextRotateCTM) 使其变为空白。为啥?的主要内容,如果未能解决你的问题,请参考以下文章

图像的二维旋转

48. 旋转图像

48. 旋转图像

lintcode: 旋转图像

旋转图像---简单

旋转图像