47

I have researched enough to get this working but not able to fix it. After taking picture from camera as long as I have image stored as UIImage, it's fine but as soon as I stored this image as PNG representation, its get rotated 90 degree.

Following is my code and all things I tried:

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info 
{
    NSString *mediaType = [info valueForKey:UIImagePickerControllerMediaType];

    if([mediaType isEqualToString:(NSString*)kUTTypeImage]) 
    {
        AppDelegate *delegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
        delegate.originalPhoto  = [info objectForKey:@"UIImagePickerControllerOriginalImage"];
        NSLog(@"Saving photo");
        [self saveImage];
        NSLog(@"Fixing orientation");
        delegate.fixOrientationPhoto  = [self fixOrientation:[UIImage imageWithContentsOfFile:[delegate filePath:imageName]]];      
        NSLog(@"Scaling photo");
        delegate.scaledAndRotatedPhoto  =  [self scaleAndRotateImage:[UIImage imageWithContentsOfFile:[delegate filePath:imageName]]];
    }
    [picker dismissModalViewControllerAnimated:YES];
    [picker release];
}


- (void)saveImage
{
    AppDelegate *delegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
    NSData *imageData = UIImagePNGRepresentation(delegate.originalPhoto);
    [imageData writeToFile:[delegate filePath:imageName] atomically:YES];
}

Here fixOrientation and scaleAndRotateImage functions taken from here and here respectively. They works fine and rotate image when I apply them on UIImage but doesn't work if I save image as PNG representation and apply them.

Please refere the following picture after executing above functions:

The first photo is original, second is saved, and third and fourth after applying fixorientation and scaleandrotate functions on saved image

Community
  • 1
  • 1
Paresh Masani
  • 7,474
  • 12
  • 73
  • 139
  • 1.[image clicked from iPhone in Portrait mode gets rotated by 90 degree](http://stackoverflow.com/questions/5973105/image-clicked-from-iphone-in-portrait-mode-gets-rotated-by-90-degree) 2. [Camera image changes orientation](http://stackoverflow.com/questions/4565507/camera-image-changes-orientation) – rohan-patel Jun 01 '12 at 12:52
  • 1
    Nope buddy. You paste all the links regarding this issue. I went through them all! – Paresh Masani Jun 01 '12 at 12:58
  • 1
    Anonymous, if you downmark this question then you haven't understood the question! I could see that you have this issue here - http://stackoverflow.com/questions/3554244/uiimagepngrepresentation-issues :-) Did you solve it? – Paresh Masani Jun 01 '12 at 13:04
  • Possible duplicate of [iphone image captured from camera rotate -90 degree automatically](http://stackoverflow.com/questions/9324130/iphone-image-captured-from-camera-rotate-90-degree-automatically) – Septronic Dec 09 '15 at 22:39
  • Hugely useful: 1. **natural output is landscape** 2. .width / .height ARE affected by .imageOrientation – Fattie Jul 11 '16 at 16:18

8 Answers8

75

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 PNG

images you must rotate them yourself, for that check this link.

Community
  • 1
  • 1
Mudit Bajpai
  • 3,010
  • 19
  • 34
  • I would recommend reading this [answer.](http://stackoverflow.com/questions/5427656/ios-uiimagepickercontroller-result-image-orientation-after-upload) Specifically the answer by 'an0' seems to be the most concise. – Mike Casa Jun 28 '14 at 05:37
30

Swift 4.2

Add the following as UIImage extension,

extension UIImage {
    func fixOrientation() -> UIImage? {
        if self.imageOrientation == UIImage.Orientation.up {
            return self
        }

        UIGraphicsBeginImageContext(self.size)
        self.draw(in: CGRect(origin: .zero, size: self.size))
        let normalizedImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return normalizedImage
    }
}

Example usage:

let cameraImage = //image captured from camera
let orientationFixedImage = cameraImage.fixOrientation()

Explanation:

The magic happens when you call UIImage's draw(in:) function, which redraws the image respecting originally captured orientation settings. [link to docs]

Make sure to call UIGraphicsBeginImageContext with image's size before calling draw to let draw rewrite the UIImage in current context's space.

UIGraphicsGetImageFromCurrentImageContext lets you capture whatever is the result of the redrawn image, & UIGraphicsEndImageContext ends and frees up the graphics context.

Nagendra Rao
  • 7,016
  • 5
  • 54
  • 92
  • Very helpful. Thank you!! – Baylor Mitchell Sep 24 '16 at 23:06
  • 2
    Probably the best answer so far that doesn't use hacking fuctions together. Very beautiful. – Munib Feb 24 '17 at 03:57
  • @return0 Thanks! Please consider upvoting the answer. – Nagendra Rao Feb 25 '17 at 07:31
  • error `Cannot assign to value: function call returns immutable value` – King Sep 12 '18 at 22:58
  • Upvoted because this works, but it would be nice if you could add an explanation of why that works, because I can´t understand. – xleon Apr 02 '19 at 14:25
  • Thank you, this worked great! But like others, if you could provide some insight into exactly how it's working I'd greatly appreciate it. If I recall correctly, Core Graphics uses a different coordinate scheme (drawn from the origin differently) than other View elements in iOS. I believe that's what's being made use of here, I'm just not sure on the specifics. – bluewraith Jan 25 '20 at 15:10
  • 2
    Explanation added. @bluewraith & xleon. – Nagendra Rao Jan 28 '20 at 13:18
29

Swift 3.1 version of the UIImage extension posted by Rao:

extension UIImage {
    func fixOrientation() -> UIImage {
        if self.imageOrientation == UIImageOrientation.up {
            return self
        }
        UIGraphicsBeginImageContextWithOptions(self.size, false, self.scale)
        self.draw(in: CGRect(x: 0, y: 0, width: self.size.width, height: self.size.height))
        if let normalizedImage: UIImage = UIGraphicsGetImageFromCurrentImageContext() {
            UIGraphicsEndImageContext()
            return normalizedImage
        } else {
            return self
        }
    }
}

Usage:

let cameraImage = //image captured from camera
let orientationFixedImage = cameraImage.fixOrientation()

Swift 4/5:

UIImageOrientation.up has been renamed to UIImage.Orientation.up

Andreas
  • 656
  • 9
  • 7
6

I have found the following tips to be hugely useful:

1. natural output is landscape

2. .width / .height ARE affected by .imageOrientation

3 use short dimension rather than .width


(1) the 'natural' output of the camera for stills IS LANDSCAPE.

this is counterintuitive. portrait is the only way offered by UIImagePickerController etc. But you will get UIImageOrientationRight as the "normal" orientation when using the "normal" portrait camera

(The way I remember this - the natural output for video is (of course) landscape; so stills are the same - even though the iPhone is all about portrait.)


(2) .width and .height are indeed affected by the .imageOrientation!!!!!!!!!

Be sure to do this, and try it both ways on your iPhone,

NSLog(@"fromImage.imageOrientation is %d", fromImage.imageOrientation);
NSLog(@"fromImage.size.width  %f   fromImage.size.height  %f",
            fromImage.size.width, fromImage.size.height);

you'll see that the .height and .width swap, "even though" the real pixels are landscape.


(3) simply using the "short dimension" rather than .width, can often solve many problems

I found this to be incredibly helpful. Say you want maybe the top square of the image:

CGRect topRectOfOriginal = CGRectMake(0,0, im.size.width,im.size.width);

that actually won't work, you'll get a squished image, when the camera is ("really") being held landscape.

however if you very simply do this

float shortDimension = fminf(im.size.width, im.size.height);
CGRect topRectOfOriginal = CGRectMake(0,0, shortDimension,shortDimension);

then "everything is fixed" and you actually "do not need to worry about" the orientation flag. Again point (3) is not a cure-all, but it very often does solve all problems.

Hope it helps someone save some time.

Community
  • 1
  • 1
Fattie
  • 27,874
  • 70
  • 431
  • 719
  • I suppose that in the last example you should use `shortDimension` somewhere (maybe instead of `im.size.width` in the second line?) – furins Aug 30 '14 at 14:03
3

I found this code here, which actually fixed it for me. For my app, I took a picture and saved it, and everytime I loaded it, it would have the annoying rotation attached (I looked up, and it's apparently something to do with the EXIF and the way iPhone takes and stores images). This code fixed it for me. I have to say, it was originally as an addition to a class / an extension /category (you can find the original from the link. I used it like below as a simple method, as I didn't really want to make a whole class or category for just this. I only used portrait, but I think the code works for any orientation. I'm not sure though

Rant over, here's the code:

- (UIImage *)fixOrientationForImage:(UIImage*)neededImage {

    // No-op if the orientation is already correct
    if (neededImage.imageOrientation == UIImageOrientationUp) return neededImage;

    // 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.
    CGAffineTransform transform = CGAffineTransformIdentity;

    switch (neededImage.imageOrientation) {
        case UIImageOrientationDown:
        case UIImageOrientationDownMirrored:
            transform = CGAffineTransformTranslate(transform, neededImage.size.width, neededImage.size.height);
            transform = CGAffineTransformRotate(transform, M_PI);
            break;

        case UIImageOrientationLeft:
        case UIImageOrientationLeftMirrored:
            transform = CGAffineTransformTranslate(transform, neededImage.size.width, 0);
            transform = CGAffineTransformRotate(transform, M_PI_2);
            break;

        case UIImageOrientationRight:
        case UIImageOrientationRightMirrored:
            transform = CGAffineTransformTranslate(transform, 0, neededImage.size.height);
            transform = CGAffineTransformRotate(transform, -M_PI_2);
            break;
        case UIImageOrientationUp:
        case UIImageOrientationUpMirrored:
            break;
    }

    switch (neededImage.imageOrientation) {
        case UIImageOrientationUpMirrored:
        case UIImageOrientationDownMirrored:
            transform = CGAffineTransformTranslate(transform, neededImage.size.width, 0);
            transform = CGAffineTransformScale(transform, -1, 1);
            break;

        case UIImageOrientationLeftMirrored:
        case UIImageOrientationRightMirrored:
            transform = CGAffineTransformTranslate(transform, neededImage.size.height, 0);
            transform = CGAffineTransformScale(transform, -1, 1);
            break;
        case UIImageOrientationUp:
        case UIImageOrientationDown:
        case UIImageOrientationLeft:
        case UIImageOrientationRight:
            break;
    }

    // Now we draw the underlying CGImage into a new context, applying the transform
    // calculated above.
    CGContextRef ctx = CGBitmapContextCreate(NULL, neededImage.size.width, neededImage.size.height,
                                             CGImageGetBitsPerComponent(neededImage.CGImage), 0,
                                             CGImageGetColorSpace(neededImage.CGImage),
                                             CGImageGetBitmapInfo(neededImage.CGImage));
    CGContextConcatCTM(ctx, transform);
    switch (neededImage.imageOrientation) {
        case UIImageOrientationLeft:
        case UIImageOrientationLeftMirrored:
        case UIImageOrientationRight:
        case UIImageOrientationRightMirrored:
            // Grr...
            CGContextDrawImage(ctx, CGRectMake(0,0,neededImage.size.height,neededImage.size.width), neededImage.CGImage);
            break;

        default:
            CGContextDrawImage(ctx, CGRectMake(0,0,neededImage.size.width,neededImage.size.height), neededImage.CGImage);
            break;
    }

    // And now we just create a new UIImage from the drawing context
    CGImageRef cgimg = CGBitmapContextCreateImage(ctx);
    UIImage *img = [UIImage imageWithCGImage:cgimg];
    CGContextRelease(ctx);
    CGImageRelease(cgimg);
    return img;
}

I'm not sure how useful this will be for you, but I hope it helped :)

Jay Shin
  • 914
  • 1
  • 7
  • 12
Septronic
  • 1,156
  • 13
  • 32
  • It works fine, but compresses the image quality. the quality of the image after rotation is not good. – Ananta Prasad May 23 '18 at 07:12
  • Thank you for your answer. I use your code in my app but I get crash reports, the image returned from this function somehow gets corrupted it seems this function makes memory leak that's why. Do you get the same issues and how can I resolve it ? – Karen Karapetyan May 28 '18 at 13:52
  • @Ananta Prasad hmm, I’ll check it out and get back to you. – Septronic Jun 16 '18 at 20:52
  • @Karapetyan I will look into what causes you the issue. What Xcode are you using? – Septronic Jun 16 '18 at 20:53
3

Try this, You can use

NSData *somenewImageData = UIImageJPEGRepresentation(newimg,1.0);

instead of

NSData *somenewImageData = UIImagePNGRepresentation(newimg);
vijay
  • 1,475
  • 2
  • 16
  • 26
1

Pls Try the following code

UIImage *sourceImage = ... // Our image
CGRect selectionRect = CGRectMake(100.0, 100.0, 300.0, 400.0);
CGImageRef resultImageRef = CGImageCreateWithImageInRect(sourceImage.CGImage,
selectionRect);
UIImage *resultImage = [[UIImage alloc] initWithCGImage:resultImageRef];

And

CGRect TransformCGRectForUIImageOrientation(CGRect source, UIImageOrientation orientation, CGSize imageSize) {
switch (orientation) {
case UIImageOrientationLeft: { // EXIF #8
  CGAffineTransform txTranslate = CGAffineTransformMakeTranslation(imageSize.height, 0.0);
  CGAffineTransform txCompound = CGAffineTransformRotate(txTranslate,M_PI_2);
  return CGRectApplyAffineTransform(source, txCompound);
}
case UIImageOrientationDown: { // EXIF #3
  CGAffineTransform txTranslate = CGAffineTransformMakeTranslation(imageSize.width, imageSize.height);
  CGAffineTransform txCompound = CGAffineTransformRotate(txTranslate,M_PI);
  return CGRectApplyAffineTransform(source, txCompound);
}
case UIImageOrientationRight: { // EXIF #6
  CGAffineTransform txTranslate = CGAffineTransformMakeTranslation(0.0, imageSize.width);
  CGAffineTransform txCompound = CGAffineTransformRotate(txTranslate,M_PI + M_PI_2);
  return CGRectApplyAffineTransform(source, txCompound);
}
case UIImageOrientationUp: // EXIF #1 - do nothing
  default: // EXIF 2,4,5,7 - ignore
  return source;
}
}
  ...
UIImage *sourceImage = ... // Our image
 CGRect selectionRect = CGRectMake(100.0, 100.0, 300.0, 400.0);
CGRect transformedRect = TransformCGRectForUIImageOrientation(selectionRect,  sourceImage.imageOrientation, sourceImage.size);
CGImageRef resultImageRef = CGImageCreateWithImageInRect(sourceImage.CGImage, transformedRect);
UIImage *resultImage = [[UIImage alloc] initWithCGImage:resultImageRef];

I have referanced from following link have look for more detail

Best Regards :-)

NIKHIL
  • 2,719
  • 1
  • 26
  • 50
  • Thanks but it doesn't worked either. I used CGRect selectionRect = CGRectMake(0, 0, sourceImage.size.width, sourceImage.size.height); to rotate full image but still it appears 90 degree rotated. Please note that I do this operation after storing image locally in documents folder. Thanks. – Paresh Masani Jun 01 '12 at 12:58
  • From where you are passing the value of “orientation” in “CGRect TransformCGRectForUIImageOrientation(CGRect source, UIImageOrientation orientation, CGSize imageSize) – Developer Feb 04 '15 at 13:54
0

Try this code:

NSData *imageData = UIImageJPEGRepresentation(delegate.originalPhoto,100);
Jaimin Soni
  • 1,061
  • 1
  • 13
  • 29
  • This does not provide an answer to the question. To critique or request clarification from an author, leave a comment below their post - you can always comment on your own posts, and once you have sufficient [reputation](http://stackoverflow.com/help/whats-reputation) you will be able to [comment on any post](http://stackoverflow.com/help/privileges/comment). – ericbn May 26 '15 at 17:48
  • 1
    rotation problem come when you store image as PNGRepresentation. if you store image as JPEGRepresentation,image will not rotate! – Mubasher May 27 '15 at 05:12