UIImage fix

If you aren’t interested in Objective C Cocoa development for the iPhone… read on.

The problems:

  • UIImage provides no easy way to scale, rotate or transform the underlying CGImage.  While it is easy to transform it by placing the image in a view, if you need the actual image changed then good luck.
  • UIImageJPEGRepresentation(), the easiest (only?) way to convert a UIImage to a JPEG uses the underlying CGImage, and ignores your UIImage imageOrientation, so regardless of camera position when the picture was taken the exported JPEG will always be oriented in landscape or right mode, ending up with pictures that need rotation.

The solution:  Thanks to some help in the Apple Support forums, and the #iphonedev IRC chat groups, I was able to clean up a function that takes a UIImage, and fixes it’s underlying core image.

Update: The “Forever” setting on Pastebin doesn’t seem to be so forever… but still lots of interest in this fix, so enjoy below:

UIImage *scaleAndRotateImage(UIImage *image)
{
    int kMaxResolution = 320; // Or whatever

    CGImageRef imgRef = image.CGImage;

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

    CGAffineTransform transform = CGAffineTransformIdentity;
    CGRect bounds = CGRectMake(0, 0, width, height);
    if (width > kMaxResolution || height > kMaxResolution) {
        CGFloat ratio = width/height;
        if (ratio > 1) {
            bounds.size.width = kMaxResolution;
            bounds.size.height = bounds.size.width / ratio;
        }
        else {
            bounds.size.height = kMaxResolution;
            bounds.size.width = bounds.size.height * ratio;
        }
    }

    CGFloat scaleRatio = bounds.size.width / width;
    CGSize imageSize = CGSizeMake(CGImageGetWidth(imgRef), CGImageGetHeight(imgRef));
    CGFloat boundHeight;
    UIImageOrientation orient = image.imageOrientation;
    switch(orient) {

        case UIImageOrientationUp: //EXIF = 1
            transform = CGAffineTransformIdentity;
            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"];

    }

    UIGraphicsBeginImageContext(bounds.size);

    CGContextRef context = UIGraphicsGetCurrentContext();

    if (orient == UIImageOrientationRight || orient == UIImageOrientationLeft) {
        CGContextScaleCTM(context, -scaleRatio, scaleRatio);
        CGContextTranslateCTM(context, -height, 0);
    }
    else {
        CGContextScaleCTM(context, scaleRatio, -scaleRatio);
        CGContextTranslateCTM(context, 0, -height);
    }

    CGContextConcatCTM(context, transform);

    CGContextDrawImage(UIGraphicsGetCurrentContext(), CGRectMake(0, 0, width, height), imgRef);
    UIImage *imageCopy = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return imageCopy;
}
Share

58 Comments

  • By Michael, July 23, 2008 @ 3:59 am

    Any chance you can re-link the solution’s source…it’s no longer available on pastbin.

    Thanks, Michael.

  • By Mihael, December 19, 2008 @ 7:42 am

    Thanks.

  • By Emilian, January 15, 2009 @ 1:44 am

    Thank you. Just saved a lot of searching and testing. I assume we can use the code a “public domain” no ?

  • By badpirate, January 15, 2009 @ 10:58 am

    Public domain indeed.

  • By Layne, February 6, 2009 @ 3:16 pm

    Thanks SOOO much for this. Helped me out greatly. You rock!

  • By TheSquad, February 10, 2009 @ 8:00 am

    There is a memory leak on this code…

    for fixing it, add those lines before the return :

    CGContextRelease(context);
    CGImageRelease(imgRef);

  • By TheSquad, February 10, 2009 @ 8:09 am

    In fact Fotget about the first line :

    CGContextRelease(context);

    Just use :

    CGImageRelease(imgRef);

    And it will be fine

  • By Kevin, February 10, 2009 @ 10:14 am

    CGImageRelease(imgRef); will cause a crash. imgRef is not allocated but assigned (CGImageRef imgRef = image.CGImage;) therefore it’s not scale and rotates job to deallocate that ref.

    Correct me if I’m wrong…

  • By TheSquad, February 12, 2009 @ 4:27 am

    Yes my bad !

    that was my code :

    UIImage *img = [[UIImage alloc] initWithData:data];
    [data release];
    if ((img.size.width / img.size.height) > 1)
    img = [[self scaleAndRotateImage:img] retain];

    since the old img couldn’t not be released, I was stuck with extra memory allocated, that’s why I had to release the Ref.

    That you for the correction Kevin, I was wrong !

  • By iPhoner, February 12, 2009 @ 2:06 pm

    I’m simply trying to rotate an image to landscape. I’m having troubles picking apart your code, on why you are doing 3*M_PI/2 in certain places, whats the 3* for? Basically if the image is a portrait image, i want to rotate it 90 degrees CCW. Any help is appreciated!

  • By kidproquo, March 23, 2009 @ 12:09 pm

    This code works wonders with camera-sourced images! Thanks for your work. One question – the orientation is messed up for camera-sourced images and is fine for other type images (screenshots, saved images from other apps). So, for camera-sourced images I need to call your method and for other I need to call another. How do I distinguish between the two (camera-sourced/others)?

  • By steve, April 19, 2009 @ 9:27 am

    I’ve got the same issue as kidproquo. Is there any easy way to know it was taken with the iPhone or do I need to parse the exif?

  • By Ken, April 25, 2009 @ 5:45 am

    Hi Guys,

    Please tell me how I can download the entire solution’s source.

    Thanks,

  • By //\\//\\ e [+_+], April 25, 2009 @ 5:03 pm

    good job kevin.

  • By Chris, May 6, 2009 @ 9:24 pm

    Many thanks for this! You just saved me a lot of frustration.

  • By Andy, May 9, 2009 @ 12:09 am

    I think there is an easier solution using the drawAtPoint function. The API documentation says: “This method draws the entire image in the current graphics context, respecting the image’s orientation setting.”

    I did a small test and it seems to work just fine:

    static uint8* GetPixelBufferFromImage(UIImage* image)
    {
    int32 width = image.size.width;
    int32 height = image.size.height;

    uint8* pBuffer = (uint8*)malloc(height*width*4);

    CGColorSpaceRef pColorSpace = CGColorSpaceCreateDeviceRGB();

    CGContextRef pContext = CGBitmapContextCreate(pBuffer,
    width, height,
    8, width*4,
    pColorSpace, kCGImageAlphaNoneSkipLast);

    // Must adjust to upside-down coordinate system
    CGContextTranslateCTM(pContext, 0.0, height);
    CGContextScaleCTM(pContext, 1.0, -1.0);

    UIGraphicsPushContext(pContext);
    [image drawAtPoint:CGPointMake(0,0)];
    UIGraphicsPopContext();

    CGContextRelease(pContext);
    CGColorSpaceRelease(pColorSpace);

    return pBuffer;
    }

  • By Ed, May 28, 2009 @ 11:15 pm

    Holy cow!!! This code rocks! You are the man.

    Its amazing that it takes this much code to perform a simple basic task like take an image from the photo library and display it properly! Apple still has some work to do.

    Anyway, you just saved me like 5 hours of hair pulling. Thanks so much!

  • By raleighr3, June 20, 2009 @ 2:59 pm

    So can anyone explain the magic behind the rotation math (e.g. 3*M_PI/2)? What’s the 3* for? I would like to rotate by arbitrary angles and am trying to understand this code so I can do that. Thanks!

  • By Mike, June 24, 2009 @ 10:19 am

    Where, exactly, can this code be called from? I’ve tried it in a few different places such as the from the imagePickerController’s didFinishPickingMediaWithInfo and the context is always null:

    CGContextRef context = UIGraphicsGetCurrentContext();

    I’ve tried using the code within my viewcontroller as well as a static method in a helper class. Always the same null context.

  • By Kevin Lohman, June 24, 2009 @ 2:00 pm

    the resulting image is retrieved using a command like:

    UIImage *myRotateImage = scaleAndRotateImage(originalImage);

    If your question was a broader one about accessing an image context, you have to first create one before you can call UIGraphicsGetCurrentContext(), notice the:

    UIGraphicsBeginImageContext(bounds.size);

    Command, this begins the context.

  • By jongsma, June 28, 2009 @ 11:39 am

    Do note that dividing M_PI by 2, what you are doing quite often, it not necessary. The variable M_PI_2 represents that value.

  • By zoso, July 5, 2009 @ 12:04 am

    Images taken with the camera are all 1200×1600 so do something like if (imgDimension == 1600){call method}

  • By badpirate, July 20, 2009 @ 5:58 pm

    Not quite that simple, because you can hold the phone any of 4 ways. So if I take a shot with the phone tilted left it would have the same dimensions as a photo with the camera tilted right, but would be 180 degrees out.

  • By AC, March 11, 2010 @ 10:58 am

    Thank you for sharing this code.

  • By RK Tweet, March 15, 2010 @ 9:37 pm

    I get a huge spike in memory usage (~10-12 MB) when I access this code. Anyone else? Anyway around it?

  • By Manoj, April 8, 2010 @ 6:40 pm

    Thanks, this is what i was looking for.

  • By sbudhram, June 24, 2010 @ 10:42 pm

    I literally cut and paste this code, and it fixed my problem. That never happens. Thanks for your generous contribution.

  • By Danny, July 15, 2010 @ 8:55 pm

    Amazing Work. Thank you.

  • By Greg, September 21, 2010 @ 7:39 am

    Copy, paste and problem solved. Thanks for sharing.

  • By zenchemical, September 29, 2010 @ 10:55 am

    This didn’t 100% work for me…

    Scaling was off for some reason in LeftMirrored and RightMirrored code. I ended up using something like

    if (orient == UIImageOrientationRight || orient == UIImageOrientationLeft) {
    CGContextScaleCTM(context, -scaleRatio, scaleRatio);
    CGContextTranslateCTM(context, -height, 0);
    }
    else if (orient == UIImageOrientationRightMirrored || orient == UIImageOrientationLeftMirrored){
    CGContextScaleCTM(context, scaleRatio, -scaleRatio);

    CGContextTranslateCTM(context, 0, -width);

    }
    else {
    CGContextScaleCTM(context, scaleRatio, -scaleRatio);
    CGContextTranslateCTM(context, 0, -height);
    }

    I don’t understand 100% of the intricacies of this function, but this did fix my issue.

  • By Mike, November 12, 2010 @ 6:11 pm

    Thank you!!! This code was an amazing help.

  • By Andrew, November 17, 2010 @ 1:50 pm

    Thank you so much for this code.

    However the same problem occurs for videos too, how could we beat that?

  • By Kevin Lohman, November 22, 2010 @ 2:43 pm

    Andrew – Good question. Not a clue. heh :)

  • By Scott, November 29, 2010 @ 7:09 pm

    Thanks for this!

    One small thing to add. A small bug in this code, when you’re calculating the bounds near the top of this method, you’ll need to take the floor of the result after calculating in the ratio. If you do not do this, it’ll be rounded up to the next integer and leave a white strip on the right or bottom edge. So, just change it to this to fix it:

    if (ratio > 1) {
    bounds.size.width = kMaxResolution;
    bounds.size.height = floor(bounds.size.width / ratio);
    }
    else {
    bounds.size.height = kMaxResolution;
    bounds.size.width = floor(bounds.size.height * ratio);
    }

  • By Stas Dmitrenko, March 31, 2011 @ 11:14 am

    Thank you soooooo much!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

  • By neil, May 23, 2011 @ 10:59 pm

    Thanks for sharing this code, i works on iOS4 but not on iOS3.1 : i have a “EXC_BAD_ACCESS” for the line :
    “CGContextDrawImage(UIGraphicsGetCurrentContext(), CGRectMake(0, 0, width, height), imgRef);”

    How can i fix it ? Please

  • By Kevin Lohman, May 24, 2011 @ 7:39 am

    Neil – Use 3.2 :)

  • By anthony blake, July 19, 2011 @ 5:14 am

    Fixed my orientation and image resolution issues in one method. Thank you, great work.

  • By Marco Gerardo, August 11, 2011 @ 3:53 pm

    YOU ARE THE BEST! Thank you for the code!

  • By Peter M, October 9, 2011 @ 7:46 am

    Saved me from my ignorance of image formats…THANKS for your excellent code that just WORKED first time out of the gate!

  • By Mick, October 9, 2011 @ 11:10 am

    This code is way over my head.
    I Really Really need to figure out how to use it.
    In my app I am attaching a saved image to an email body so I don’t have a UIImage to manipulate. I only specify a path to the image in the documents directory, pull it into NSData and attach it as a mime type.jpg. It works great but there again the image is turned left 90deg when the recipient views the email. Does anyone have a snippet of code that will help me understand how to get the saves image into UIImage so I can expose it to this function?
    Thanks for the code though. Once I grasp this my app is gonna rock big time!

  • By Mick, October 15, 2011 @ 3:18 pm

    Hooray!! I did get this code to work but I guessed my way through it. Still don’t understand it but maybe I will. Thanks so much for the code!!

  • By Chris, February 13, 2012 @ 11:50 am

    Can anybody get this to work in Monotouch (C#)? I feel like I’ve translated the code correctly but when I apply the resulting UIImage to a UIImageView, the result is a blank (white) image view. Has anyone gotten this to work in Mono?

  • By df, March 22, 2012 @ 2:33 am

    Thanks very much, worked a treat for me

  • By Zak, June 8, 2012 @ 11:59 am

    After I take 3 photos which then go through your function, I get a memory warning. It’s leaking somewhere.

  • By Salem Elnahwy, August 30, 2012 @ 9:48 am

    I have been using this method to rotate image for long time now it crashes in iOS 6 beta, did you experience this issue as well? it seems to work when I step through the code but in normal run it crashes app every time. Any ideas here will be greatly appreciated.

  • By nefasto, September 2, 2012 @ 6:42 pm

    WHY are not working with me?….Im been struggle several day with this issue and trying other alternatives, this is the code (ios 5.0) :

    - (void)getNSDATAfromSelectedPicturesArrayURLs:(NSString*)urlString {
    ALAssetsLibraryAssetForURLResultBlock resultblock = ^(ALAsset *myasset)
    {

    ALAssetRepresentation *rep = [myasset defaultRepresentation];

    CGImageRef iref = [rep fullResolutionImage];

    UIImage *coolImage;
    UIImage *toNSData;

    if (iref) {
    coolImage = [UIImage imageWithCGImage:iref];

    }
    toNSData = [self scaleAndRotateImage:coolImage];
    NSData *dataTemp =UIImageJPEGRepresentation(toNSData, .3);
    [PicturesArrayNSDATA addObject:dataTemp];
    [self performSelectorOnMainThread:@selector(checkConversionToNSDATA) withObject:nil waitUntilDone:YES];
    }

  • By Michael, February 5, 2013 @ 9:08 pm

    Good job!
    I’m using this code to get the image data:

    NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageSampleBuffer];
    UIImage *image = [[UIImage alloc] initWithData:imageData];
    self.stillImage = [self scaleAndRotateImage:image];

    I find it really interesting that the EXIF information is stored unused in the UIImage (as I understand):

    UIImageOrientation orient = image.imageOrientation;
    switch(orient) {

    How can I know if the reorientation is already applied to the image data or not?

  • By Michael, February 5, 2013 @ 9:24 pm

    OK, obviously, the EXIF data (eg reorientation) should not be applied to the image data. I’m also using a non-lazy loading image method (via an UIImage category) that ignores the orientation and the other meta data…

  • By xun, April 3, 2013 @ 11:59 pm

    Cool! Thank you.

Other Links to this Post

  1. Snippet: UIImage alterations at Under The Bridge — January 4, 2009 @ 6:06 pm

  2. rotate a UIImage help - iPhone Dev SDK Forum — February 3, 2009 @ 12:50 pm

  3. i’m so full of ideas » Blog Archive » iPhone: UIImage rotation and mirroring — March 29, 2009 @ 10:19 pm

  4. Mmm…food » Scaling UIImages without losing orientation — May 11, 2009 @ 8:15 pm

  5. iPhone – UIImage rotation fix | Advanced App Development — June 13, 2011 @ 10:17 am

  6. UIImage Resize?? | ????????? — May 16, 2012 @ 5:24 am

  7. Scale and Rotate a Photo / Camera to UIImageViewer | iOS Code Samples — June 18, 2012 @ 6:43 am

  8. How to use UIImage+SDAdditions | BlogoSfera — July 30, 2013 @ 2:02 am

RSS feed for comments on this post. TrackBack URI

Leave a comment

WordPress Themes