55

I want to load images from UIImagePickerController, then save the selected photo to my app's document directory.

UIImage *image = [info objectForKey:UIImagePickerControllerOriginalImage];
NSData *data1 = UIImagePNGRepresentation(image);

NSString *fileName = "1.png";
NSString *path = //get Document path, then add fileName
BOOL succ = [data1 writeToFile:path atomically:YES];

but after I save the image to my document, I found that, the image was rotated 90 degree, then I change the method UIImagePNGRepresentation to UIImageJPEGRepresentation, this time it's fine, anyone know what's the problem?

Titouan de Bailleul
  • 12,920
  • 11
  • 66
  • 121
disorderdev
  • 1,458
  • 1
  • 14
  • 28
  • possible duplicate of [iOS UIImagePickerController result image orientation after upload](http://stackoverflow.com/questions/5427656/ios-uiimagepickercontroller-result-image-orientation-after-upload) – Axel Guilmin Apr 03 '15 at 00:12

6 Answers6

99

I had the same problem and just figured out the reason: starting with iOS 4.0 when the camera takes a photo it does not rotate it before saving, it simply sets a rotation flag in the EXIF data of the JPEG.

If you save a UIImage as a JPEG, it will set the rotation flag.

PNGs do not support a rotation flag, so if you save a UIImage as a PNG, it will be rotated incorrectly and not have a flag set to fix it. So if you want PNGs you must rotate them yourself.

I would call this a bug in the PNG saving function but that's just an opinion (they should at least warn you about this).

jasongregori
  • 11,451
  • 5
  • 43
  • 41
  • I spent probably an hour or so trying to get my PNG CGImageSource (created from data) to be rotated properly when the thumb was created... inserting exif data into my CGImageSource creation options, etc. etc. and UIImageJPEGRepresentation fixed it right away! Thanks! – taber Sep 28 '11 at 06:11
  • 3
    @jasongregori: Even saving it as a JPEG it does not solve my problem. Image still rotates. – rohan-patel Jan 02 '12 at 10:57
  • 1
    It solved my problem partially!! When I take the image in Landscape mode, It saved properly and when I retrieve it is in Landscape. But If I take an image in Portrait mode, when I retrieve its in Landscape still. That is for Portrait alone its rotates. – Bharathi Jul 03 '12 at 09:36
  • I had the same issue and the category proposed here : http://stackoverflow.com/a/5427890/1327557 solved it for good – Axel Guilmin Apr 03 '15 at 00:19
31

Please try this.

func rotateImage(image: UIImage) -> UIImage? {
    if image.imageOrientation == UIImage.Orientation.up {
        return image /// already upright, no need for changes
    }
    UIGraphicsBeginImageContext(image.size)
    image.draw(in: CGRect(origin: CGPoint.zero, size: image.size))
    let copy = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    return copy
}

Happy coding :)

aheze
  • 24,434
  • 8
  • 68
  • 125
Stefan
  • 5,203
  • 8
  • 27
  • 51
15

I solve this issue with the following code.

- (UIImage *)scaleAndRotateImage:(UIImage *)image
{
    int kMaxResolution = 640; 

    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;
}
İbrahim Özbölük
  • 3,162
  • 23
  • 20
  • I like this code and somehow its the only one that works in terms of rotating my image. Anyway I'm having trouble getting it to work in iOS 7.1 and the ARC cycle. Any idea where the problem could lie? – Matthias Max Aug 29 '14 at 13:37
  • Thank you for this! Worked like a charm! I translated it to swift 2.0 for my current project. Here's a gist: https://gist.github.com/fnk0/2e108700bdbe4a92766c – Marcus Gabilheri Oct 13 '15 at 03:33
  • @MarcusGabilheri how would i use your code to rotate 90 degrees? – alex Oct 22 '15 at 20:04
6

The following swift function resolves the problem.

func rotateImage(image: UIImage) -> UIImage? {
        if (image.imageOrientation == UIImage.Orientation.up ) {
            return image
        }
        UIGraphicsBeginImageContext(image.size)
        image.draw(in: CGRect(origin: CGPoint.zero, size: image.size))
        let copy = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return copy
    }

Yup it is that simple, just because the drawInRect function will take image orientation in consideration.

Ilesh P
  • 3,940
  • 1
  • 24
  • 49
devfreak
  • 1,201
  • 2
  • 17
  • 27
  • how would i use this? at the moment my imageHolder code looks like this: `invoiceImageHolder.image = loadImageFromPath(fileInDocumentsDirectory(("\(imagePath!)")))` and i am getting errors Use of unresolved identifier 'imageOrientation' – alex Oct 22 '15 at 19:45
2

I have created this UIImage extension to fix this problem with UIImagePNGRepresentation, based on this response. So I propose to use this class func UIImage.PNGRepresentation(img: UIImage) instead of UIKit func UIImagePNGRepresentation.

Swift 3 code :

//  MyUIImage.swift
//  MyEasyMovie-Public-App
//
//  Created by Ahmed Zahraz on 19/12/2016.
//  Copyright © 2016 AhmedZahraz. All rights reserved.    

import Foundation
import UIKit

extension UIImage {


    public class func PNGRepresentation(_ img: UIImage) -> Data? {
        // No-op if the orientation is already correct
        if (img.imageOrientation == UIImageOrientation.up) {
            return UIImagePNGRepresentation(img);
        }
        // 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 = CGAffineTransform.identity

        if (img.imageOrientation == UIImageOrientation.down
            || img.imageOrientation == UIImageOrientation.downMirrored) {

            transform = transform.translatedBy(x: img.size.width, y: img.size.height)
            transform = transform.rotated(by: CGFloat(M_PI))
        }

        if (img.imageOrientation == UIImageOrientation.left
            || img.imageOrientation == UIImageOrientation.leftMirrored) {

            transform = transform.translatedBy(x: img.size.width, y: 0)
            transform = transform.rotated(by: CGFloat(M_PI_2))
        }

        if (img.imageOrientation == UIImageOrientation.right
            || img.imageOrientation == UIImageOrientation.rightMirrored) {

            transform = transform.translatedBy(x: 0, y: img.size.height);
            transform = transform.rotated(by: CGFloat(-M_PI_2));
        }

        if (img.imageOrientation == UIImageOrientation.upMirrored
            || img.imageOrientation == UIImageOrientation.downMirrored) {

            transform = transform.translatedBy(x: img.size.width, y: 0)
            transform = transform.scaledBy(x: -1, y: 1)
        }

        if (img.imageOrientation == UIImageOrientation.leftMirrored
            || img.imageOrientation == UIImageOrientation.rightMirrored) {

            transform = transform.translatedBy(x: img.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(img.size.width), height: Int(img.size.height),
                                      bitsPerComponent: img.cgImage!.bitsPerComponent, bytesPerRow: 0,
                                      space: img.cgImage!.colorSpace!,
                                      bitmapInfo: img.cgImage!.bitmapInfo.rawValue)!

        ctx.concatenate(transform)


        if (img.imageOrientation == UIImageOrientation.left
            || img.imageOrientation == UIImageOrientation.leftMirrored
            || img.imageOrientation == UIImageOrientation.right
            || img.imageOrientation == UIImageOrientation.rightMirrored
            ) {


            ctx.draw(img.cgImage!, in: CGRect(x:0,y:0,width:img.size.height,height:img.size.width))

        } else {
            ctx.draw(img.cgImage!, in: CGRect(x:0,y:0,width:img.size.width,height:img.size.height))
        }


        // And now we just create a new UIImage from the drawing context
        let cgimg:CGImage = ctx.makeImage()!
        let imgEnd:UIImage = UIImage(cgImage: cgimg)

        return UIImagePNGRepresentation(imgEnd)
    }

}
Community
  • 1
  • 1
AhmedZah
  • 1,203
  • 2
  • 9
  • 9
2

Stefan's answer updated for Swift 4:

func rotateImage(image: UIImage) -> UIImage {
        if (image.imageOrientation == UIImage.Orientation.up) {
            return image
        }
        UIGraphicsBeginImageContext(image.size)
        image.draw(in: CGRect(origin: .zero, size: image.size))
        let copy = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()

        return copy!
    }

And then:

var originalImage = yourImage.image!
image = rotateImage(image: originalImage)
squarehippo10
  • 1,855
  • 1
  • 15
  • 45