18

I'm developing an iOS app for iPad. Is there any way to rotate a UIImage 90º and then add it to a UIImageView? I've tried a lot of different codes but none worked...

Thanks!

Ben Lu
  • 2,982
  • 4
  • 31
  • 54
Marti Serra Vivancos
  • 1,195
  • 5
  • 17
  • 33

10 Answers10

22

You may rotate UIImageView itself with:

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

Or if you really want to change image, you may use code from this answer, it works.

Community
  • 1
  • 1
kovpas
  • 9,553
  • 6
  • 40
  • 44
  • I'm doing like it says, but I have a problem... I rotates the image from the top left corner, how can I set that it rotates the image from the center of the UIImage? – Marti Serra Vivancos Feb 13 '13 at 16:41
  • You can play with `iv.layer.anchorPoint`, but it's default value is the center of a layer, so I'm not sure why it rotates image from the top-left corner. – kovpas Feb 13 '13 at 16:47
  • NO but I've used the code from the link you've given to me. So it is CGContextRotateCTM – Marti Serra Vivancos Feb 13 '13 at 16:57
  • 2
    I see. Here you go: http://stackoverflow.com/questions/5983090/rotating-an-image-context-cgcontextrotatectm-causing-it-to-become-blank-why – kovpas Feb 13 '13 at 17:10
  • I tried that but only works with square pictures. Other images get distorted... What can I do? – Marti Serra Vivancos Feb 13 '13 at 21:06
  • Change imageView's frame, I think. – kovpas Feb 13 '13 at 21:40
  • The `frame` of a `UIView` is undefined when the transform is not the identity transform. To stop it from becoming distorted, *don’t* modify the frame after you have transformed it. To position the view, you can modify the `center` property. – Zev Eisenberg May 20 '14 at 14:22
19

To rotate the pixels you can use the following. This creates an intermediate UIImage with rotated metadata and renders it into a image context with width/height dimensions transposed. The resulting image has the pixels rotated (i.e the underlying 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;
}

There are other possible values that can be passed for the orientation parameter to achieve 180 degree rotation and flips etc.

Jason Crocker
  • 491
  • 5
  • 8
  • If the original image is `UIImageOrientationRight` and you set `UIImageOrientationLeft` here, then the resulting output will be squished to fit the new dimensions. – ray Apr 29 '16 at 17:26
9

This will rotate an image by any given degrees.

Note this works 2x and 3x retina as well

- (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;
}
combinatorial
  • 9,132
  • 4
  • 40
  • 58
RyanG
  • 4,393
  • 2
  • 39
  • 64
  • That's great, but is there a way of doing it without having to create a UIView? My understanding is that UIView is a pretty heavyweight object. Thanks! – Mario Dec 29 '16 at 21:55
  • I've found a CALayer can be used in lieu of a UIView. You have to set the frame property after you create the layer. You also have to apply the CATransform3DMakeAffineTransform function to the CAAffineTransform object ("t") to set the transform property on the layer. Everything else works as is. My understanding is that a CALayer is a more lightweight object. – Mario Dec 30 '16 at 16:24
  • UIView has to be executed on main thread so it's better to avoid it. I found very similar answer to this one that doesn't use UIView - https://stackoverflow.com/a/20860719/2870783 – h3dkandi Dec 06 '18 at 14:26
8

There is also imageWithCIImage:scale:orientation if you wanted to rotate the UIImage not the UIImageView

with one of these orientations:

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;
Jaybit
  • 1,864
  • 1
  • 13
  • 20
5

Here is the swift version of @RyanG's Objective C code as an extension to UIImage:

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
    }

}

The usage is image.rotate(degree).

kingkps
  • 156
  • 1
  • 13
RawMean
  • 8,374
  • 6
  • 55
  • 82
4
UIImage *img = [UIImage imageWithName@"aaa.png"];
UIImage *image = [UIImage imageWithCGImage:img.CGImage scale:1.0 orientation:UIImageOrientationRight];
Seslyn
  • 807
  • 10
  • 19
vualoaithu
  • 936
  • 10
  • 9
4

With Swift, you can rotate an image by doing:

var image: UIImage = UIImage(named: "headerBack.png")
var imageRotated: UIImage = UIImage(CGImage: image.CGImage, scale:1, orientation: UIImageOrientation.UpMirrored)
rsc
  • 10,348
  • 5
  • 39
  • 36
1

Another way of doing this would be to render the UIImage again using Core Graphics.

Once you have the context, use CGContextRotateCTM.

More info on this Apple Doc

luksfarris
  • 1,313
  • 19
  • 38
1

Thanks Jason Crocker this solved my problem. Only one minor correction, interchange height and width in both locations and no distortion occurs, ie,

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)]; 

My problem could not be solved by CGContextRotateCTM, I don't know why. My issue is that I'm transmitting my image to a server and it was alway displayed off by 90 degrees. You can easily test if your images are going to work in the non apple world by copying the image to an MS Office Program that you are running on your mac.

Steig Hallquist
  • 111
  • 1
  • 5
1

This is what i've done when i wanted to change the orientation of an image (rotate 90 degree clockwise).

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

The rotated image may be of size >= 15MB (from my experience). So you should compress it and use it. Otherwise, you may met with crash causing memory pressure. Code I used for compressing is given below.

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

Now your yourImage can be used for anywhere.. Happy coding...

Soorej Babu
  • 350
  • 2
  • 19
  • imageToRotate is not compiling, you are using the wrong parameter name image instead imageToRotate parameter – FedeH Dec 04 '18 at 13:46