如何旋转UIImage

18

我正在为iPad开发一款iOS应用程序。有没有办法将UIImage旋转90度,然后将其添加到UIImageView中?我尝试了很多不同的代码,但都没有成功...

谢谢!

10个回答

22

您可以通过以下方式旋转 UIImageView 本身:

UIImageView *iv = [[UIImageView alloc] initWithImage:image];
iv.transform = CGAffineTransformMakeRotation(M_PI_2);

或者,如果你真的想改变图像,你可以使用这个答案中的代码,它有效。


你可以使用 iv.layer.anchorPoint 进行调整,但它的默认值是图层的中心点,所以我不确定为什么它会从左上角旋转图像。 - kovpas
不,我没有自己编写代码,而是使用了你给我的链接中的代码。所以正确的写法是CGContextRotateCTM。 - Marti Serra Vivancos
2
我明白了。这是链接:https://dev59.com/22025IYBdhLWcg3weV4s - kovpas
我尝试过了,但只适用于正方形图片。其他图像会变形... 我该怎么办? - Marti Serra Vivancos
当变换不是标识变换时,UIView的frame未定义。为了防止它变形,不要在变换后修改frame。要定位视图,可以修改center属性。 - Zev Eisenberg
显示剩余2条评论

19
为了旋转像素,您可以使用以下方法。这将创建一个带有旋转元数据的中间UIImage,并在具有转置宽度/高度尺寸的图像上下文中呈现它。结果图像的像素被旋转(即底层CGImage)。
- (UIImage*)rotateUIImage:(UIImage*)sourceImage clockwise:(BOOL)clockwise
{
    CGSize size = sourceImage.size;
    UIGraphicsBeginImageContext(CGSizeMake(size.height, size.width));
    [[UIImage imageWithCGImage:[sourceImage CGImage] scale:1.0 orientation:clockwise ? UIImageOrientationRight : UIImageOrientationLeft] drawInRect:CGRectMake(0,0,size.height ,size.width)];
    UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return newImage;
}

还有其他可能的值可以传递到方向参数以实现180度旋转和翻转等效果。


如果原始图像是UIImageOrientationRight,并且您在此处设置为UIImageOrientationLeft,那么生成的输出将被压缩以适应新的尺寸。 - ray

9
这将按任意给定的角度旋转一张图片。
请注意,这也适用于2x和3x视网膜屏幕。
- (UIImage *)imageRotatedByDegrees:(CGFloat)degrees {
    CGFloat radians = DegreesToRadians(degrees);

    UIView *rotatedViewBox = [[UIView alloc] initWithFrame:CGRectMake(0,0, self.size.width, self.size.height)];
    CGAffineTransform t = CGAffineTransformMakeRotation(radians);
    rotatedViewBox.transform = t;
    CGSize rotatedSize = rotatedViewBox.frame.size;

    UIGraphicsBeginImageContextWithOptions(rotatedSize, NO, [[UIScreen mainScreen] scale]);
    CGContextRef bitmap = UIGraphicsGetCurrentContext();

    CGContextTranslateCTM(bitmap, rotatedSize.width / 2, rotatedSize.height / 2);

    CGContextRotateCTM(bitmap, radians);

    CGContextScaleCTM(bitmap, 1.0, -1.0);
    CGContextDrawImage(bitmap, CGRectMake(-self.size.width / 2, -self.size.height / 2 , self.size.width, self.size.height), self.CGImage );

    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return newImage;
}

太好了,但有没有一种方法可以不必创建UIView来完成它?我的理解是UIView是一个相当重量级的对象。谢谢! - Mario
我发现可以使用CALayer代替UIView。创建图层后,您必须设置frame属性。您还必须将CATransform3DMakeAffineTransform函数应用于CAAffineTransform对象(“t”),以设置图层上的transform属性。其他所有内容都按原样工作。我的理解是,CALayer是一个更轻量级的对象。 - Mario
UIView必须在主线程上执行,因此最好避免使用它。我找到了一个非常类似的答案,它不使用UIView-https://dev59.com/22025IYBdhLWcg3weV4s#20860719 - h3dkandi

8

如果您想旋转UIImage而不是UIImageView,也可以使用imageWithCIImage:scale:orientation其中之一的方向:

typedef enum {
   UIImageOrientationUp,
   UIImageOrientationDown,   // 180 deg rotation
   UIImageOrientationLeft,   // 90 deg CW
   UIImageOrientationRight,   // 90 deg CCW
   UIImageOrientationUpMirrored,    // vertical flip
   UIImageOrientationDownMirrored,  // horizontal flip
   UIImageOrientationLeftMirrored,  // 90 deg CW then perform horizontal flip
   UIImageOrientationRightMirrored, // 90 deg CCW then perform vertical flip
} UIImageOrientation;

5

这是将@RyanG的Objective C代码作为UIImage扩展的Swift版本:

extension UIImage {

    func rotate(byDegrees degree: Double) -> UIImage {
        let radians = CGFloat(degree*M_PI)/180.0 as CGFloat
        let rotatedViewBox = UIView(frame: CGRect(x: 0, y: 0, width: self.size.width, height: self.size.height))
        let t = CGAffineTransform(rotationAngle: radians)
        rotatedViewBox.transform = t
        let rotatedSize = rotatedViewBox.frame.size
        let scale = UIScreen.main.scale
        UIGraphicsBeginImageContextWithOptions(rotatedSize, false, scale)
        let bitmap = UIGraphicsGetCurrentContext()
        CGContextTranslateCTM(bitmap, rotatedSize.width / 2, rotatedSize.height / 2);

        bitmap!.rotate(by: radians);

        bitmap!.scaleBy(x: 1.0, y: -1.0);
        CGContextDrawImage(bitmap, CGRectMake(-self.size.width / 2, -self.size.height / 2 , self.size.width, self.size.height), self.CGImage );

        let newImage = UIGraphicsGetImageFromCurrentImageContext()

        return newImage
    }

}

使用方法为 image.rotate(degree)

4
UIImage *img = [UIImage imageWithName@"aaa.png"];
UIImage *image = [UIImage imageWithCGImage:img.CGImage scale:1.0 orientation:UIImageOrientationRight];

4

使用Swift,您可以通过以下方式旋转图像:

var image: UIImage = UIImage(named: "headerBack.png")
var imageRotated: UIImage = UIImage(CGImage: image.CGImage, scale:1, orientation: UIImageOrientation.UpMirrored)

1
感谢Jason Crocker解决了我的问题。只需要一个小修改,在两个位置上交换高度和宽度,就不会出现畸变,即:
UIGraphicsBeginImageContext(CGSizeMake(size.width, size.height));
[[UIImage imageWithCGImage:[sourceImage CGImage] scale:1.0 orientation:clockwise ? UIImageOrientationRight : UIImageOrientationLeft]  drawInRect:CGRectMake(0,0,size.width,size.height)]; 

我的问题无法通过CGContextRotateCTM解决,我不知道为什么。我的问题是,我将图像传输到服务器时,它总是显示偏了90度。您可以通过将图像复制到在Mac上运行的MS Office程序中来轻松测试您的图像是否适用于非苹果世界。

1
当我想要改变图像的方向(顺时针旋转90度)时,我所做的是这样的。
//Checking for the orientation ie, image taken from camera is in portrait or not.
if(yourImage.imageOrientation==3)
{
    //Image is in portrait mode.
    yourImage=[self imageToRotate:yourImage RotatedByDegrees:90.0];
}

- (UIImage *)image:(UIImage *)imageToRotate RotatedByDegrees:(CGFloat)degrees
{
    CGFloat radians = degrees * (M_PI / 180.0);

    UIView *rotatedViewBox = [[UIView alloc] initWithFrame:CGRectMake(0,0, image.size.height, image.size.width)];
    CGAffineTransform t = CGAffineTransformMakeRotation(radians);
    rotatedViewBox.transform = t;
    CGSize rotatedSize = rotatedViewBox.frame.size;

    UIGraphicsBeginImageContextWithOptions(rotatedSize, NO, [[UIScreen mainScreen] scale]);
    CGContextRef bitmap = UIGraphicsGetCurrentContext();

    CGContextTranslateCTM(bitmap, rotatedSize.height / 2, rotatedSize.width / 2);

    CGContextRotateCTM(bitmap, radians);

    CGContextScaleCTM(bitmap, 1.0, -1.0);
    CGContextDrawImage(bitmap, CGRectMake(-image.size.width / 2, -image.size.height / 2 , image.size.height, image.size.width), image.CGImage );
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return newImage;
}

旋转后的图片大小可能大于或等于15MB(根据我的经验)。所以你应该压缩并使用它。否则,可能会因内存压力而导致崩溃。我用于压缩的代码如下。

NSData *imageData = UIImageJPEGRepresentation(yourImage, 1);
//1 - it represents the quality of the image.
NSLog(@"Size of Image(bytes):%d",[imageData length]);
//Here I used a loop because my requirement was, the image size should be <= 4MB.
//So put an iteration for more than 1 time upto when the image size is gets <= 4MB.
for(int loop=0;loop<100;loop++)
{
    if([imageData length]>=4194304)  //4194304 = 4MB in bytes.
    {
        imageData=UIImageJPEGRepresentation(yourImage, 0.3);
        yourImage=[[UIImage alloc]initWithData:imageData];
    }
    else
    {
        NSLog(@"%d time(s) compressed.",loop);
        break;
    }
}

现在你的yourImage可以用于任何地方。。 愉快的编码...

imageToRotate无法编译,您正在使用错误的参数名称image而不是imageToRotate参数。 - FedeH

1
另一种方法是使用Core Graphics再次渲染UIImage。
一旦您获得了上下文,请使用CGContextRotateCTM
更多信息请参见此Apple文档

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接