185

I have a UIImage that is UIImageOrientationUp (portrait) that I would like to rotate counter-clockwise by 90 degrees (to landscape). I don't want to use a CGAffineTransform. I want the pixels of the UIImage to actually shift position. I am using a block of code (shown below) originally intended to resize a UIImage to do this. I set a target size as the current size of the UIImage but I get an error:

(Error): CGBitmapContextCreate: invalid data bytes/row: should be at least 1708 for 8 integer bits/component, 3 components, kCGImageAlphaPremultipliedLast.

(I don't get an error whenever I provide a SMALLER size as the target size BTW). How can I ROTATE my UIImage 90 degrees CCW using just core graphics functions while preserving the current size?

-(UIImage*)reverseImageByScalingToSize:(CGSize)targetSize:(UIImage*)anImage
{
    UIImage* sourceImage = anImage; 
    CGFloat targetWidth = targetSize.height;
    CGFloat targetHeight = targetSize.width;

    CGImageRef imageRef = [sourceImage CGImage];
    CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(imageRef);
    CGColorSpaceRef colorSpaceInfo = CGImageGetColorSpace(imageRef);

    if (bitmapInfo == kCGImageAlphaNone) {
        bitmapInfo = kCGImageAlphaNoneSkipLast;
    }

    CGContextRef bitmap;

    if (sourceImage.imageOrientation == UIImageOrientationUp || sourceImage.imageOrientation == UIImageOrientationDown) {
        bitmap = CGBitmapContextCreate(NULL, targetHeight, targetWidth, CGImageGetBitsPerComponent(imageRef), CGImageGetBytesPerRow(imageRef), colorSpaceInfo, bitmapInfo);

    } else {


        bitmap = CGBitmapContextCreate(NULL, targetWidth, targetHeight, CGImageGetBitsPerComponent(imageRef), CGImageGetBytesPerRow(imageRef), colorSpaceInfo, bitmapInfo);

    }       


    if (sourceImage.imageOrientation == UIImageOrientationRight) {
        CGContextRotateCTM (bitmap, radians(90));
        CGContextTranslateCTM (bitmap, 0, -targetHeight);

    } else if (sourceImage.imageOrientation == UIImageOrientationLeft) {
        CGContextRotateCTM (bitmap, radians(-90));
        CGContextTranslateCTM (bitmap, -targetWidth, 0);

    } else if (sourceImage.imageOrientation == UIImageOrientationDown) {
        // NOTHING
    } else if (sourceImage.imageOrientation == UIImageOrientationUp) {
        CGContextRotateCTM (bitmap, radians(90));
        CGContextTranslateCTM (bitmap, 0, -targetHeight);
    }

    CGContextDrawImage(bitmap, CGRectMake(0, 0, targetWidth, targetHeight), imageRef);
    CGImageRef ref = CGBitmapContextCreateImage(bitmap);
    UIImage* newImage = [UIImage imageWithCGImage:ref];

    CGContextRelease(bitmap);
    CGImageRelease(ref);

    return newImage; 
}
4

19 Answers 19

425

I believe the easiest way (and thread safe too) is to do:

//assume that the image is loaded in landscape mode from disk
UIImage * landscapeImage = [UIImage imageNamed:imgname];
UIImage * portraitImage = [[UIImage alloc] initWithCGImage: landscapeImage.CGImage
                                                     scale: 1.0
                                               orientation: UIImageOrientationRight];

Note: As Brainware said this only modifies the orientation data of the image - the pixel data is untouched. For some applications, this may not be enough.

Or in Swift:

guard
    let landscapeImage = UIImage(named: "imgname"),
    let landscapeCGImage = landscapeImage.cgImage
else { return }
let portraitImage = UIImage(cgImage: landscapeCGImage, scale: landscapeImage.scale, orientation: .right)
5
  • 1
    Make it more general: UIImage * origImg = [UIImage imageNamed:@"1.JPG"]; UIImage* fixed=[UIImage imageWithCGImage:[origImg CGImage] scale:1.0 orientation:origImg.imageOrientation];
    – Cullen SUN
    Commented Aug 2, 2013 at 10:23
  • 16
    This doesn't actually rotate the image. It makes a copy of the image and sets the imageOrientation bits of the imageFlags property of the image to 0, 1, 2, or 3. Some classes ignore these flags such as the UIActivityViewController. If you really need the image rotated, then see Ben Groot's answer which Hardy Macia's UIImage extension.
    – Brainware
    Commented Sep 18, 2013 at 23:44
  • Putting the scale as 1.0 won't work if your app is used on both retina and non-retina screens you have to take the originalImage.scale and pass it in as the scale component.
    – teradyl
    Commented Jan 22, 2014 at 23:41
  • 2
    Seems to have stopped working in iOS10 as far as I can tell.
    – Nailer
    Commented Sep 26, 2016 at 14:53
  • let img = UIImage(cgImage: myImage!.cgImage!, scale: UIScreen.main.scale, orientation: .right) Commented Jan 25, 2018 at 7:45
115

Check out the simple and awesome code of Hardy Macia at: cutting-scaling-and-rotating-uiimages

Just call

UIImage *rotatedImage = [originalImage imageRotatedByDegrees:90.0];

Thanks Hardy Macia!

Header:

- **(UIImage *)imageAtRect:(CGRect)rect;**
- **(UIImage *)imageByScalingProportionallyToMinimumSize:(CGSize)targetSize;**
- **(UIImage *)imageByScalingProportionallyToSize:(CGSize)targetSize;**
- **(UIImage *)imageByScalingToSize:(CGSize)targetSize;**
- **(UIImage *)imageRotatedByRadians:(CGFloat)radians;**
- **(UIImage *)imageRotatedByDegrees:(CGFloat)degrees;**

Since the link may die, here's the complete code

//
//  UIImage-Extensions.h
//
//  Created by Hardy Macia on 7/1/09.
//  Copyright 2009 Catamount Software. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>

@interface UIImage (CS_Extensions)
- (UIImage *)imageAtRect:(CGRect)rect;
- (UIImage *)imageByScalingProportionallyToMinimumSize:(CGSize)targetSize;
- (UIImage *)imageByScalingProportionallyToSize:(CGSize)targetSize;
- (UIImage *)imageByScalingToSize:(CGSize)targetSize;
- (UIImage *)imageRotatedByRadians:(CGFloat)radians;
- (UIImage *)imageRotatedByDegrees:(CGFloat)degrees;

@end;

//
//  UIImage-Extensions.m
//
//  Created by Hardy Macia on 7/1/09.
//  Copyright 2009 Catamount Software. All rights reserved.
//

#import "UIImage-Extensions.h"

CGFloat DegreesToRadians(CGFloat degrees) {return degrees * M_PI / 180;};
CGFloat RadiansToDegrees(CGFloat radians) {return radians * 180/M_PI;};

@implementation UIImage (CS_Extensions)

-(UIImage *)imageAtRect:(CGRect)rect
{
   
   CGImageRef imageRef = CGImageCreateWithImageInRect([self CGImage], rect);
   UIImage* subImage = [UIImage imageWithCGImage: imageRef];
   CGImageRelease(imageRef);
   
   return subImage;
   
}

- (UIImage *)imageByScalingProportionallyToMinimumSize:(CGSize)targetSize {
   
   UIImage *sourceImage = self;
   UIImage *newImage = nil;
   
   CGSize imageSize = sourceImage.size;
   CGFloat width = imageSize.width;
   CGFloat height = imageSize.height;
   
   CGFloat targetWidth = targetSize.width;
   CGFloat targetHeight = targetSize.height;
   
   CGFloat scaleFactor = 0.0;
   CGFloat scaledWidth = targetWidth;
   CGFloat scaledHeight = targetHeight;
   
   CGPoint thumbnailPoint = CGPointMake(0.0,0.0);
   
   if (CGSizeEqualToSize(imageSize, targetSize) == NO) {
      
      CGFloat widthFactor = targetWidth / width;
      CGFloat heightFactor = targetHeight / height;
      
      if (widthFactor > heightFactor) 
         scaleFactor = widthFactor;
      else
         scaleFactor = heightFactor;
      
      scaledWidth  = width * scaleFactor;
      scaledHeight = height * scaleFactor;
      
      // center the image
      
      if (widthFactor > heightFactor) {
         thumbnailPoint.y = (targetHeight - scaledHeight) * 0.5; 
      } else if (widthFactor < heightFactor) {
         thumbnailPoint.x = (targetWidth - scaledWidth) * 0.5;
      }
   }
   
   
   // this is actually the interesting part:
   
   UIGraphicsBeginImageContext(targetSize);
   
   CGRect thumbnailRect = CGRectZero;
   thumbnailRect.origin = thumbnailPoint;
   thumbnailRect.size.width  = scaledWidth;
   thumbnailRect.size.height = scaledHeight;
   
   [sourceImage drawInRect:thumbnailRect];
   
   newImage = UIGraphicsGetImageFromCurrentImageContext();
   UIGraphicsEndImageContext();
   
   if(newImage == nil) NSLog(@"could not scale image");
   
   
   return newImage ;
}


- (UIImage *)imageByScalingProportionallyToSize:(CGSize)targetSize {
   
   UIImage *sourceImage = self;
   UIImage *newImage = nil;
   
   CGSize imageSize = sourceImage.size;
   CGFloat width = imageSize.width;
   CGFloat height = imageSize.height;
   
   CGFloat targetWidth = targetSize.width;
   CGFloat targetHeight = targetSize.height;
   
   CGFloat scaleFactor = 0.0;
   CGFloat scaledWidth = targetWidth;
   CGFloat scaledHeight = targetHeight;
   
   CGPoint thumbnailPoint = CGPointMake(0.0,0.0);
   
   if (CGSizeEqualToSize(imageSize, targetSize) == NO) {
      
      CGFloat widthFactor = targetWidth / width;
      CGFloat heightFactor = targetHeight / height;
      
      if (widthFactor < heightFactor) 
         scaleFactor = widthFactor;
      else
         scaleFactor = heightFactor;
      
      scaledWidth  = width * scaleFactor;
      scaledHeight = height * scaleFactor;
      
      // center the image
      
      if (widthFactor < heightFactor) {
         thumbnailPoint.y = (targetHeight - scaledHeight) * 0.5; 
      } else if (widthFactor > heightFactor) {
         thumbnailPoint.x = (targetWidth - scaledWidth) * 0.5;
      }
   }
   
   
   // this is actually the interesting part:
   
   UIGraphicsBeginImageContext(targetSize);
   
   CGRect thumbnailRect = CGRectZero;
   thumbnailRect.origin = thumbnailPoint;
   thumbnailRect.size.width  = scaledWidth;
   thumbnailRect.size.height = scaledHeight;
   
   [sourceImage drawInRect:thumbnailRect];
   
   newImage = UIGraphicsGetImageFromCurrentImageContext();
   UIGraphicsEndImageContext();
   
   if(newImage == nil) NSLog(@"could not scale image");
   
   
   return newImage ;
}


- (UIImage *)imageByScalingToSize:(CGSize)targetSize {
   
   UIImage *sourceImage = self;
   UIImage *newImage = nil;
   
   //   CGSize imageSize = sourceImage.size;
   //   CGFloat width = imageSize.width;
   //   CGFloat height = imageSize.height;
   
   CGFloat targetWidth = targetSize.width;
   CGFloat targetHeight = targetSize.height;
   
   //   CGFloat scaleFactor = 0.0;
   CGFloat scaledWidth = targetWidth;
   CGFloat scaledHeight = targetHeight;
   
   CGPoint thumbnailPoint = CGPointMake(0.0,0.0);
   
   // this is actually the interesting part:
   
   UIGraphicsBeginImageContext(targetSize);
   
   CGRect thumbnailRect = CGRectZero;
   thumbnailRect.origin = thumbnailPoint;
   thumbnailRect.size.width  = scaledWidth;
   thumbnailRect.size.height = scaledHeight;
   
   [sourceImage drawInRect:thumbnailRect];
   
   newImage = UIGraphicsGetImageFromCurrentImageContext();
   UIGraphicsEndImageContext();
   
   if(newImage == nil) NSLog(@"could not scale image");
   
   
   return newImage ;
}


- (UIImage *)imageRotatedByRadians:(CGFloat)radians
{
   return [self imageRotatedByDegrees:RadiansToDegrees(radians)];
}

- (UIImage *)imageRotatedByDegrees:(CGFloat)degrees 
{   
   // calculate the size of the rotated view's containing box for our drawing space
   UIView *rotatedViewBox = [[UIView alloc] initWithFrame:CGRectMake(0,0,self.size.width, self.size.height)];
   CGAffineTransform t = CGAffineTransformMakeRotation(DegreesToRadians(degrees));
   rotatedViewBox.transform = t;
   CGSize rotatedSize = rotatedViewBox.frame.size;
   [rotatedViewBox release];
   
   // 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, DegreesToRadians(degrees));
   
   // Now, draw the rotated/scaled image into the context
   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;
   
}

@end;
1
  • 3
    ... the link has died. +1 for including the complete code
    – Greg
    Commented Jan 21, 2018 at 7:29
90

What about something like:

static inline double radians (double degrees) {return degrees * M_PI/180;}
UIImage* rotate(UIImage* src, UIImageOrientation orientation)
{
    UIGraphicsBeginImageContext(src.size);

    CGContextRef context = UIGraphicsGetCurrentContext();

    if (orientation == UIImageOrientationRight) {
        CGContextRotateCTM (context, radians(90));
    } else if (orientation == UIImageOrientationLeft) {
        CGContextRotateCTM (context, radians(-90));
    } else if (orientation == UIImageOrientationDown) {
        // NOTHING
    } else if (orientation == UIImageOrientationUp) {
        CGContextRotateCTM (context, radians(90));
    }

    [src drawAtPoint:CGPointMake(0, 0)];

    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return image;
}
8
  • 1
    My comment was that drawAtPoint may have to be called after the call to set the proper RotateCTM. Try moving drawAtPoint to just before UIGraphicsGetImageFromCurrentImageContext
    – fbrereto
    Commented Aug 23, 2009 at 6:52
  • 4
    This would not work on a background thread. UIGraphicsGetCurrentContext() is not thread-safe and should only be called on the main (UI) thread. Commented Jun 24, 2010 at 14:25
  • 1
    That last call to CGContextRotateCTM() should probably rotate by 180, not 90. In fact, …Down should probably rotate by 180, and …Up should probably not rotate. Commented Dec 6, 2010 at 14:13
  • 5
    In iOS 4 and later, you may call UIGraphicsGetCurrentContext function from any thread of your app.
    – bentford
    Commented Aug 27, 2013 at 17:51
  • 3
    Need to CGContextTranslateCTM(ctx, width/2, height/2) before and reverse after. Commented Dec 3, 2014 at 0:06
31

As strange as this seems, the following code solved the problem for me:

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

    return newImage;
}
3
  • 8
    It works because the image orientation is not preserved once you draw in rect.
    – Mercurial
    Commented Sep 12, 2013 at 13:13
  • Yes, this will be useful remove orientation from an image
    – Shihab
    Commented Dec 10, 2018 at 20:19
  • The function name should have been removeOrientationProperty
    – Shihab
    Commented Dec 10, 2018 at 20:58
29

A thread safe rotation function is the following (it works much better):

-(UIImage*)imageByRotatingImage:(UIImage*)initImage fromImageOrientation:(UIImageOrientation)orientation
{
CGImageRef imgRef = initImage.CGImage;

CGFloat width = CGImageGetWidth(imgRef);
CGFloat height = CGImageGetHeight(imgRef);

CGAffineTransform transform = CGAffineTransformIdentity;
CGRect bounds = CGRectMake(0, 0, width, height);
CGSize imageSize = CGSizeMake(CGImageGetWidth(imgRef), CGImageGetHeight(imgRef));
CGFloat boundHeight;
UIImageOrientation orient = orientation;
switch(orient) {

    case UIImageOrientationUp: //EXIF = 1
        return initImage;
        break;

    case UIImageOrientationUpMirrored: //EXIF = 2
        transform = CGAffineTransformMakeTranslation(imageSize.width, 0.0);
        transform = CGAffineTransformScale(transform, -1.0, 1.0);
        break;

    case UIImageOrientationDown: //EXIF = 3
        transform = CGAffineTransformMakeTranslation(imageSize.width, imageSize.height);
        transform = CGAffineTransformRotate(transform, M_PI);
        break;

    case UIImageOrientationDownMirrored: //EXIF = 4
        transform = CGAffineTransformMakeTranslation(0.0, imageSize.height);
        transform = CGAffineTransformScale(transform, 1.0, -1.0);
        break;

    case UIImageOrientationLeftMirrored: //EXIF = 5
        boundHeight = bounds.size.height;
        bounds.size.height = bounds.size.width;
        bounds.size.width = boundHeight;
        transform = CGAffineTransformMakeTranslation(imageSize.height, imageSize.width);
        transform = CGAffineTransformScale(transform, -1.0, 1.0);
        transform = CGAffineTransformRotate(transform, 3.0 * M_PI / 2.0);
        break;

    case UIImageOrientationLeft: //EXIF = 6
        boundHeight = bounds.size.height;
        bounds.size.height = bounds.size.width;
        bounds.size.width = boundHeight;
        transform = CGAffineTransformMakeTranslation(0.0, imageSize.width);
        transform = CGAffineTransformRotate(transform, 3.0 * M_PI / 2.0);
        break;

    case UIImageOrientationRightMirrored: //EXIF = 7
        boundHeight = bounds.size.height;
        bounds.size.height = bounds.size.width;
        bounds.size.width = boundHeight;
        transform = CGAffineTransformMakeScale(-1.0, 1.0);
        transform = CGAffineTransformRotate(transform, M_PI / 2.0);
        break;

    case UIImageOrientationRight: //EXIF = 8
        boundHeight = bounds.size.height;
        bounds.size.height = bounds.size.width;
        bounds.size.width = boundHeight;
        transform = CGAffineTransformMakeTranslation(imageSize.height, 0.0);
        transform = CGAffineTransformRotate(transform, M_PI / 2.0);
        break;

    default:
        [NSException raise:NSInternalInconsistencyException format:@"Invalid image orientation"];

}
// Create the bitmap context
CGContextRef    context = NULL;
void *          bitmapData;
int             bitmapByteCount;
int             bitmapBytesPerRow;

// Declare the number of bytes per row. Each pixel in the bitmap in this
// example is represented by 4 bytes; 8 bits each of red, green, blue, and
// alpha.
bitmapBytesPerRow   = (bounds.size.width * 4);
bitmapByteCount     = (bitmapBytesPerRow * bounds.size.height);
bitmapData = malloc( bitmapByteCount );
if (bitmapData == NULL)
{
    return nil;
}

// Create the bitmap context. We want pre-multiplied ARGB, 8-bits
// per component. Regardless of what the source image format is
// (CMYK, Grayscale, and so on) it will be converted over to the format
// specified here by CGBitmapContextCreate.
CGColorSpaceRef colorspace = CGImageGetColorSpace(imgRef);
context = CGBitmapContextCreate (bitmapData,bounds.size.width,bounds.size.height,8,bitmapBytesPerRow,
                                 colorspace, kCGBitmapAlphaInfoMask & kCGImageAlphaPremultipliedLast);

if (context == NULL)
    // error creating context
    return nil;

CGContextScaleCTM(context, -1.0, -1.0);
CGContextTranslateCTM(context, -bounds.size.width, -bounds.size.height);

CGContextConcatCTM(context, transform);

// Draw the image to the bitmap context. Once we draw, the memory
// allocated for the context for rendering will then contain the
// raw image data in the specified color space.
CGContextDrawImage(context, CGRectMake(0,0,width, height), imgRef);

CGImageRef imgRef2 = CGBitmapContextCreateImage(context);
CGContextRelease(context);
free(bitmapData);
UIImage * image = [UIImage imageWithCGImage:imgRef2 scale:initImage.scale orientation:UIImageOrientationUp];
CGImageRelease(imgRef2);
return image;
}
3
  • There's a problem with your code... It adds a weird white frame around the image on UIImageOrientationDown.
    – iosfreak
    Commented Apr 5, 2012 at 20:58
  • 1
    You don't want that call to CGColorSpaceRelease(colorspace), see stackoverflow.com/questions/5269815/… Commented Apr 17, 2014 at 21:10
  • Yeah sorry about that release Commented Apr 18, 2014 at 11:20
18

I had trouble with ll of the above, including the approved answer. I converted Hardy's category back into a method since all i wanted was to rotate an image. Here's the code and usage:

- (UIImage *)imageRotatedByDegrees:(UIImage*)oldImage deg:(CGFloat)degrees{
// calculate the size of the rotated view's containing box for our drawing space
UIView *rotatedViewBox = [[UIView alloc] initWithFrame:CGRectMake(0,0,oldImage.size.width, oldImage.size.height)];
CGAffineTransform t = CGAffineTransformMakeRotation(degrees * M_PI / 180);
rotatedViewBox.transform = t;
CGSize rotatedSize = rotatedViewBox.frame.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, (degrees * M_PI / 180));

// Now, draw the rotated/scaled image into the context
CGContextScaleCTM(bitmap, 1.0, -1.0);
CGContextDrawImage(bitmap, CGRectMake(-oldImage.size.width / 2, -oldImage.size.height / 2, oldImage.size.width, oldImage.size.height), [oldImage CGImage]);

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

And the usage:

UIImage *image2 = [self imageRotatedByDegrees:image deg:90];

Thanks Hardy!

0
17

Rotate Image by 90 degree (clockwise/anti-clockwise direction)

Function call -

 UIImage *rotatedImage = [self rotateImage:originalImage clockwise:YES];

Implementation:

- (UIImage*)rotateImage:(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;
  }
1
  • this increases the image size Commented Sep 13, 2017 at 13:09
6

Simple. Just change the image orientation flag.

UIImage *oldImage = [UIImage imageNamed:@"whatever.jpg"];
UIImageOrientation newOrientation;
switch (oldImage.imageOrientation) {
    case UIImageOrientationUp:
        newOrientation = UIImageOrientationLandscapeLeft;
        break;
    case UIImageOrientationLandscapeLeft:
        newOrientation = UIImageOrientationDown;
        break;
    case UIImageOrientationDown:
        newOrientation = UIImageOrientationLandscapeRight;
        break;
    case UIImageOrientationLandscapeRight:
        newOrientation = UIImageOrientationUp;
        break;
    // you can also handle mirrored orientations similarly ...
}
UIImage *rotatedImage = [UIImage imageWithCGImage:oldImage.CGImage scale:1.0f orientation:newOrientation];
6

Here is a Swift extension to UIImage that rotates the image by any arbitrary angle. Use it like this: let rotatedImage = image.rotated(byDegrees: degree). I used the Objective-C code in one of the other answers and removed a few lines that we incorrect (rotated box stuff) and turned it into an extension for UIImage.

extension UIImage {

func rotate(byDegrees degree: Double) -> UIImage {
    let radians = CGFloat(degree*M_PI)/180.0 as CGFloat
    let rotatedSize = self.size
    let scale = UIScreen.mainScreen().scale
    UIGraphicsBeginImageContextWithOptions(rotatedSize, false, scale)
    let 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 );
    let newImage = UIGraphicsGetImageFromCurrentImageContext()

    return newImage
}
}
3
  • Works great! I changed it a little so that I could swap width and hight: func rotate(byDegrees degree: Double, toSize: CGSize? = nil) -> UIImage { let rotatedSize = toSize ?? self.size Commented Aug 3, 2016 at 7:01
  • 2
    This doesn't set the bounds the image properly. You end up with a rotated image that's overflowing the original bounds. Commented Nov 23, 2016 at 20:47
  • 1
    Thanks very much for this. Amazing how much time I've spent on this today.
    – ChrisH
    Commented Jul 7, 2017 at 0:42
5

If you want to add a photo rotate button that'll keep rotating the photo in 90 degree increments, here you go. (finalImage is a UIImage that's already been created elsewhere.)

- (void)rotatePhoto {
    UIImage *rotatedImage;

    if (finalImage.imageOrientation == UIImageOrientationRight)
        rotatedImage = [[UIImage alloc] initWithCGImage: finalImage.CGImage
                                              scale: 1.0
                                        orientation: UIImageOrientationDown];
    else if (finalImage.imageOrientation == UIImageOrientationDown)
        rotatedImage = [[UIImage alloc] initWithCGImage: finalImage.CGImage
                                              scale: 1.0
                                        orientation: UIImageOrientationLeft];
    else if (finalImage.imageOrientation == UIImageOrientationLeft)
        rotatedImage = [[UIImage alloc] initWithCGImage: finalImage.CGImage
                                              scale: 1.0
                                        orientation: UIImageOrientationUp];
    else
        rotatedImage = [[UIImage alloc] initWithCGImage: finalImage.CGImage
                                                     scale: 1.0
                                               orientation: UIImageOrientationRight];
    finalImage = rotatedImage;
}
0
5

Swift 3 UIImage extension:

func fixOrientation() -> UIImage {

    // No-op if the orientation is already correct
    if ( self.imageOrientation == .up ) {
        return self;
    }

    // We need to calculate the proper transformation to make the image upright.
    // We do it in 2 steps: Rotate if Left/Right/Down, and then flip if Mirrored.
    var transform: CGAffineTransform = .identity

    if ( self.imageOrientation == .down || self.imageOrientation == .downMirrored ) {
        transform = transform.translatedBy(x: self.size.width, y: self.size.height)
        transform = transform.rotated(by: .pi)
    }

    if ( self.imageOrientation == .left || self.imageOrientation == .leftMirrored ) {
        transform = transform.translatedBy(x: self.size.width, y: 0)
        transform = transform.rotated(by: .pi/2)
    }

    if ( self.imageOrientation == .right || self.imageOrientation == .rightMirrored ) {
        transform = transform.translatedBy(x: 0, y: self.size.height);
        transform = transform.rotated(by: -.pi/2);
    }

    if ( self.imageOrientation == .upMirrored || self.imageOrientation == .downMirrored ) {
        transform = transform.translatedBy(x: self.size.width, y: 0)
        transform = transform.scaledBy(x: -1, y: 1)
    }

    if ( self.imageOrientation == .leftMirrored || self.imageOrientation == .rightMirrored ) {
        transform = transform.translatedBy(x: self.size.height, y: 0);
        transform = transform.scaledBy(x: -1, y: 1);
    }

    // Now we draw the underlying CGImage into a new context, applying the transform
    // calculated above.
    let ctx: CGContext = CGContext(data: nil, width: Int(self.size.width), height: Int(self.size.height),
                                   bitsPerComponent: self.cgImage!.bitsPerComponent, bytesPerRow: 0,
                                   space: self.cgImage!.colorSpace!,
                                   bitmapInfo: self.cgImage!.bitmapInfo.rawValue)!;

    ctx.concatenate(transform)

    if ( self.imageOrientation == .left ||
        self.imageOrientation == .leftMirrored ||
        self.imageOrientation == .right ||
        self.imageOrientation == .rightMirrored ) {
        ctx.draw(self.cgImage!, in: CGRect(x: 0.0,y: 0.0,width: self.size.height,height: self.size.width))
    } else {
        ctx.draw(self.cgImage!, in: CGRect(x: 0.0,y: 0.0,width: self.size.width,height: self.size.height))
    }

    // And now we just create a new UIImage from the drawing context and return it
    return UIImage(cgImage: ctx.makeImage()!)
}
3

Swift 4.2 version of RawMean's answer:

extension UIImage {

func rotated(byDegrees degree: Double) -> UIImage {
    let radians = CGFloat(degree * .pi) / 180.0 as CGFloat
    let rotatedSize = self.size
    let scale = UIScreen.main.scale
    UIGraphicsBeginImageContextWithOptions(rotatedSize, false, scale)
    let bitmap = UIGraphicsGetCurrentContext()
    bitmap?.translateBy(x: rotatedSize.width / 2, y: rotatedSize.height / 2)
    bitmap?.rotate(by: radians)
    bitmap?.scaleBy(x: 1.0, y: -1.0)
    bitmap?.draw(
        self.cgImage!,
        in: CGRect.init(x: -self.size.width / 2, y: -self.size.height / 2 , width: self.size.width, height: self.size.height))
    let newImage = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext() // this is needed
    return newImage!
}

}
2
  • The balloons the weight of an image. Im my test: BEFORE ROTATION ============================== width 3024.0 height 3024.0 size 4952213 bytes ============================== AFTER ROTATION ============================== width 3024.0 height 3024.0 size 35191195 bytes ============================== Commented Dec 11, 2018 at 19:40
  • barry is right this method changes the image weight.
    – XYZ
    Commented Nov 6, 2020 at 12:08
2

I try this code, it works, and took 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;

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

Minor change to the other answers that are based on Hardy Macia's code. There is no need to create a whole UIView object simply to calculate the bounding rectangle of the rotated image. Just apply a rotate transform to the image rectangle using CGRectApplyAffineTransform.

static CGFloat DegreesToRadians(CGFloat degrees) {return degrees * M_PI / 180;}
static CGFloat RadiansToDegrees(CGFloat radians) {return radians * 180/M_PI;}


- (CGSize)rotatedImageSize:(CGFloat)degrees
{
    CGAffineTransform t = CGAffineTransformMakeRotation(DegreesToRadians(degrees));
    CGRect originalImageRect = CGRectMake(0, 0, self.size.width, self.size.height);
    CGRect rotatedImageRect = CGRectApplyAffineTransform(originalImageRect, t);
    CGSize rotatedSize = rotatedImageRect.size;

    return rotatedSize;
}

- (UIImage*)imageRotatedByDegrees:(CGFloat)degrees
{
    // calculate the size of the rotated view's containing box for our drawing space
    CGSize rotatedSize = [self rotatedImageSize:degrees];

    // 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, DegreesToRadians(degrees));

    // Now, draw the rotated/scaled image into the context
    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;
}
0

"tint uiimage grayscale" appears to be the appropriate Google-Fu for this one

straight away I get:

https://discussions.apple.com/message/8104516?messageID=8104516&#8104516

https://discussions.apple.com/thread/2751445?start=0&tstart=0

How would I tint an image programmatically on the iPhone?

0

I like the simple elegance of Peter Sarnowski's answer, but it can cause problems when you can't rely on EXIF metadata and the like. In situations where you need to rotate the actual image data I would recommend something like this:

- (UIImage *)rotateImage:(UIImage *) img
{
    CGSize imgSize = [img size];
    UIGraphicsBeginImageContext(imgSize);
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextRotateCTM(context, M_PI_2);
    CGContextTranslateCTM(context, 0, -640);
    [img drawInRect:CGRectMake(0, 0, imgSize.height, imgSize.width)];
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return newImage;
}

The above code takes an image whose orientation is Landscape (can't remember if it's Landscape Left or Landscape Right) and rotates it into Portrait. It is an example which can be modified for your needs.

The key arguments you would have to play with are CGContextRotateCTM(context, M_PI_2) where you decide how much you want to rotate by, but then you have to make sure the picture still draws on the screen using CGContextTranslateCTM(context, 0, -640). This last part is quite important to make sure you see the image and not a blank screen.

For more info check out the source.

1
  • 2
    Downvote for broken link and no explanation of -640 magic number. Will reverse if fixed.
    – Nate
    Commented Dec 10, 2015 at 10:17
0

resize-a-uiimage-the-right-way explains some of the issues many code samples for doing this have, and has some code snippets to help deal with UIImages - the private helper method in UIImage+resize.m accepts a transform to allow rotation, so you'd just need to expose that as a public interface.

// Returns a copy of the image that has been transformed using the given affine transform and scaled to the new size
// The new image's orientation will be UIImageOrientationUp, regardless of the current image's orientation
// If the new size is not integral, it will be rounded up
- (UIImage *)resizedImage:(CGSize)newSize
                transform:(CGAffineTransform)transform
           drawTransposed:(BOOL)transpose
     interpolationQuality:(CGInterpolationQuality)quality {
    CGRect newRect = CGRectIntegral(CGRectMake(0, 0, newSize.width, newSize.height));
    CGRect transposedRect = CGRectMake(0, 0, newRect.size.height, newRect.size.width);
    CGImageRef imageRef = self.CGImage;

    // Build a context that's the same dimensions as the new size
    CGContextRef bitmap = CGBitmapContextCreate(NULL,
                                                newRect.size.width,
                                                newRect.size.height,
                                                CGImageGetBitsPerComponent(imageRef),
                                                0,
                                                CGImageGetColorSpace(imageRef),
                                                CGImageGetBitmapInfo(imageRef));

    // Rotate and/or flip the image if required by its orientation
    CGContextConcatCTM(bitmap, transform);

    // Set the quality level to use when rescaling
    CGContextSetInterpolationQuality(bitmap, quality);

    // Draw into the context; this scales the image
    CGContextDrawImage(bitmap, transpose ? transposedRect : newRect, imageRef);

    // Get the resized image from the context and a UIImage
    CGImageRef newImageRef = CGBitmapContextCreateImage(bitmap);
    UIImage *newImage = [UIImage imageWithCGImage:newImageRef];

    // Clean up
    CGContextRelease(bitmap);
    CGImageRelease(newImageRef);

    return newImage;
}

This is the license from that file:

// Created by Trevor Harmon on 8/5/09.
// Free for personal or commercial use, with or without modification.
// No warranty is expressed or implied.
0

There is a extremely efficient UIImage category named NYXImagesKit. It uses vDSP, CoreImage and vImage to be as fast as possible. It has a UIImage+Rotating category that saved my day :)

https://github.com/Nyx0uf/NYXImagesKit

0

For Swift: Here is a simple extension to UIImage:

//ImageRotation.swift

import UIKit

extension UIImage {  
    public func imageRotatedByDegrees(degrees: CGFloat, flip: Bool) -> UIImage {
        let radiansToDegrees: (CGFloat) -> CGFloat = {
            return $0 * (180.0 / CGFloat(M_PI))
        }
        let degreesToRadians: (CGFloat) -> CGFloat = {
            return $0 / 180.0 * CGFloat(M_PI)
        }

        // calculate the size of the rotated view's containing box for our drawing space
        let rotatedViewBox = UIView(frame: CGRect(origin: CGPointZero, size: size))
        let t = CGAffineTransformMakeRotation(degreesToRadians(degrees));
        rotatedViewBox.transform = t
        let rotatedSize = rotatedViewBox.frame.size

        // Create the bitmap context
        UIGraphicsBeginImageContext(rotatedSize)
        let 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.0, rotatedSize.height / 2.0);

        //   // Rotate the image context
        CGContextRotateCTM(bitmap, degreesToRadians(degrees));

        // Now, draw the rotated/scaled image into the context
        var yFlip: CGFloat

        if(flip){
            yFlip = CGFloat(-1.0)
        } else {
            yFlip = CGFloat(1.0)
        }

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

        let newImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()

        return newImage
    }
}

(Source)

Use it with:

rotatedPhoto = rotatedPhoto?.imageRotatedByDegrees(90, flip: false) 

The former will rotate an image and flip it if flip is set to true.

2
  • Can you please explain that a bit?
    – G.Abhisek
    Commented Mar 3, 2016 at 10:44
  • 2
    this seems to mess with the aspect ratio for some reason
    – fwhenin
    Commented Mar 10, 2016 at 0:49

Not the answer you're looking for? Browse other questions tagged or ask your own question.