97

For the past few weeks I've been working with images in objective-c and noticing a lot of strange behavior. First, like many other people, I've been having this problem where images taken with the camera (or taken with somebody else's camera and MMS'd to me) are rotated 90 degrees. I wasn't sure why in the world this was happening (hence my question) but I was able to come up with a cheap work around.

My question this time is why is this happening? Why is Apple rotating images? When I take a photo with my camera right-side up, unless I perform my code mentioned above, when I save the photo it gets saved rotated. Now, my workaround was okay up until a few days ago.

My application modifies individual pixels of an image, specifically the alpha channel of a PNG (so any JPEG conversion gets thrown out of the window for my scenario). A few days ago I noticed that even though the image is displayed properly in my app thanks to my workaround code, when my algorithm modifies the individual pixels of the image, it thinks the image is rotated. So instead of modifying the pixels at the top of the image, it modifies the pixels on the side of the image (because it thinks it should be rotated)! I can't figure out how to rotate the image in memory - ideally I would prefer to just wipe away that imageOrientation flag all together.

Here's something else that has been baffling me as well... When I take the photo, the imageOrientation is set to 3. My workaround code is smart enough to realize this and flip it so the user never notices. Additionally, my code to save the image to the library realizes this, flips it, then saves it so it appears in the camera roll properly.

That code looks like so:

NSData* pngdata = UIImagePNGRepresentation (self.workingImage); //PNG wrap 
UIImage* img = [self rotateImageAppropriately:[UIImage imageWithData:pngdata]];   
UIImageWriteToSavedPhotosAlbum(img, nil, nil, nil);

When I load this newly saved image into my app, the imageOrientation is 0 - exactly what I want to see, and my rotation workaround doesn't even need to run (note: when loading images from the internet as opposed to images taken with a camera, the imageOrientation is always 0, resulting in perfect behavior). For some reason, my save code seems to wipe away this imageOrientation flag. I was hoping to just steal that code and use it to wipe away my imageOrientation as soon as the user takes a photo and has it added to the app, but it doesn't seem to work. Does UIImageWriteToSavedPhotosAlbum do something special with imageOrientation?

Would the best fix for this problem be to just blow away imageOrientation as soon as the user is done taking an image. I assume Apple has the rotation behavior done for a reason, right? A few people suggested that this is an Apple defect.

(... if you're not lost yet... Note2: When I take a horizontal photo, everything seems to work perfectly, just like photos taken from the internet)

EDIT:

Here are what some of the images and scenarios actually look like. Based off the comments so far, it looks like this strange behavior is more than just an iPhone behavior, which I think is good.

This is a picture of the photo I took with my phone (note the proper orientation), it appears exactly as it did on my phone when I snapped the photo:

Actual Photo taken on iPhone

Here is what the image looks like in Gmail after I emailed it to myself (looks like Gmail handles it properly):

Photo as it appears in Gmail

Here is what the image looks like as a thumbnail in windows (doesn't look like it is handled properly):

Windows Thumbnail

And here is what the actual image looks like when opened with Windows Photo Viewer (still not handled properly):

Windows Photo Viewer Version

After all of the comments on this question, here's what I'm thinking... The iPhone takes an image, and says "to display this properly, it needs to be rotated 90 degrees". This information would be in the EXIF data. (Why it needs to be rotated 90 degrees, rather than defaulting to straight vertical, I don't know). From here, Gmail is smart enough to read and analyze that EXIF data, and properly display it. Windows however, is not smart enough to read the EXIF data, and therefore displays the image improperly. Are my assumptions correct?

Community
  • 1
  • 1
Boeckm
  • 3,264
  • 4
  • 36
  • 41
  • Interesting... if that's true, why are the images taken being set to right angle? I know this isn't an iPhone defect, because I've noticed similar behavior when a friend (with a BlackBerry) takes an image and MMS's it to me. – Boeckm May 15 '12 at 12:45
  • See your camera writes metadata to rotate it at 90 degree, some OS read that metadata and rest don't. – HarshIT May 15 '12 at 12:49
  • Pretty good read (see @Hadley's answer below - used to be in a comment). So my app clearly needs to be smart enough to handle images that contain EXIF data, as well as images that don't contain it... I still don't understand why when I take a photo right-side up, the orientation flag says it should be rotated 90 degrees? – Boeckm May 15 '12 at 13:04
  • You set your photo mode to Portrait and you are not rotating your camera to right angle or Landscape mode is set and the camera has captured image in right angled position, the sensor will automatically set the orientation to proper one. Check it out – HarshIT May 15 '12 at 13:06
  • 1
    Solution is most probably , your app needs to read the meta data and rotate image and/or modify the metadata as per requirement. – HarshIT May 15 '12 at 13:12
  • Check out my Edit. I added images to show exactly what I'm seeing. Is my assumption correct, that the behavior is entirely intended, it is just up to the end-application to determine how to display the image? – Boeckm May 15 '12 at 13:25
  • I am seeing this become a huge problem for me right now. I have made a website using WooCommerce. Adding items into the marketplace via an ipad (taking pictures on the ipad) is causing the images to show up in the store rotated 90 degrees to the left, where they show up on a mobile device just fine. – leigero Mar 26 '14 at 04:38

13 Answers13

54

I had the same problem when I get the image from Camera, I put the following code to fix it.. Added the method scaleAndRotateImage from here

- (void) imagePickerController:(UIImagePickerController *)thePicker didFinishPickingMediaWithInfo:(NSDictionary *)imageInfo {
            // Images from the camera are always in landscape, so rotate
                    UIImage *image = [self scaleAndRotateImage: [imageInfo objectForKey:UIImagePickerControllerOriginalImage]];
    //then save the image to photo gallery or wherever  
        }


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

    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;
}
VH-NZZ
  • 5,248
  • 4
  • 31
  • 47
Dilip Rajkumar
  • 7,006
  • 6
  • 60
  • 76
  • 3
    What does your scaleAndRotateImage code look like? After doing a google, is it the same as the one here? https://discussions.apple.com/thread/1537011?start=0&tstart=0 – Boeckm May 15 '12 at 21:15
  • 2
    WOW... Haha! That worked extremely well! I used the code in my comment above. I got two amazing answers to my question! I think that means I asked too big of a question... Thanks a ton. I'll have some in depth testing to do, but so far the orientation problem works great with vertically and horizontally taken photos. – Boeckm May 15 '12 at 21:23
  • 3
    I think there is a part of your method missing, but that and the link still was enough for me to work out the rest and finally get my image cropping view working properly, so thanks :) – Vic Smith Aug 08 '12 at 14:36
  • does this code block preserve the how the original image looks like but change the orientation to be up? – Junchao Gu Jun 18 '15 at 06:13
  • Hi @JunchaoGu, I am not currently under iOS development. However as far as I know. If the image is rotated and saved we wont have the original image. If you need original image also then you have to save as two images original one and the rotated one. – Dilip Rajkumar Jun 18 '15 at 07:18
  • This Work Perfect, You have it just for Rotation? No Scale. Cause I try to remove the size, but it result in stretch image. – Brian Nezhad Sep 24 '15 at 19:06
  • I am not developing iOS apps anymore so I am not sure how the code behaves now.. however, I believe it should work.. – Dilip Rajkumar Sep 28 '15 at 19:25
  • I used this and it worked. If you'd like to keep your image resolution, set scaleRatio = 1.0 instead of what is in there. – Jake T. Nov 11 '15 at 01:58
  • I sometimes had the problem, that a white line appeared at the bottom of the image after scaling it. This is because CGFloat seems to be not precise enough. I fixed this with `bounds.size.height.round()` and `bounds.size.width.round()` (this is Swift syntax, don't know how to write it in Obj-C) – ndreisg Feb 28 '18 at 08:56
50

I did R&D on it and discovered , every image file has metadata property. If the metadata specifies the orientation of the image which is generally ignored by other OS but Mac. Most of images taken are having their meta data property set to right angle. So Mac shows it 90 degree rotated manner. You can see the same image in proper way in windows OS.

For more detail read this answer http://graphicssoft.about.com/od/digitalphotography/f/sideways-pictures.htm

try reading your image's exif here http://www.exifviewer.org/ , or http://regex.info/exif.cgi , or http://www.addictivetips.com/internet-tips/view-complete-exif-metadata-information-of-any-jpeg-image-online/

HarshIT
  • 4,583
  • 2
  • 30
  • 60
  • 1
    WOW! I had no idea there was THAT MUCH information in EXIF data! http://regex.info/exif.cgi is an incredible site! I will certainly be playing around with images tonight on this site. I'll have to test every scenario, images take straight up, images taken from the internet, images taken rotated, etc. Thanks a ton! – Boeckm May 15 '12 at 13:50
  • The first exif link is broken now, and the second has been updated to http://exif.regex.info/exif.cgi I tried to edit the answer but @cj-dennis rejected it for some reason. – Ryan Apr 12 '18 at 05:19
25

My question this time is why is this happening? Why is Apple rotating images?

The answer to this is very simple. Apple is NOT rotating the image. That's where the confusion lies.

The CCD camera doesn't rotate, so it's always taking the photo in landscape mode.

Apple did a very smart thing - instead of spending all the time to rotate the image - shuffling megabytes of data around - just tag it with HOW the picture was taken.

OpenGL does translations very easily - so the DATA never gets shuffled - just HOW ITS DRAWN.

Hence the orientation meta data.

This becomes a problem if you want to crop, resize etc - but once you know what's happening, you just define your matrix and everything works out.

Roy
  • 251
  • 3
  • 2
  • 1
    Thank you for this explanation. Common sense once you think about it, but no other googled result explained it. – Dakine83 Nov 03 '16 at 07:35
18

Quick copy/paste Swift translation of Dilip's excellent answer.

import Darwin

class func rotateCameraImageToProperOrientation(imageSource : UIImage, maxResolution : CGFloat) -> UIImage {

    let imgRef = imageSource.CGImage;

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

    var bounds = CGRectMake(0, 0, width, height)

    var scaleRatio : CGFloat = 1
    if (width > maxResolution || height > maxResolution) {

        scaleRatio = min(maxResolution / bounds.size.width, maxResolution / bounds.size.height)
        bounds.size.height = bounds.size.height * scaleRatio
        bounds.size.width = bounds.size.width * scaleRatio
    }

    var transform = CGAffineTransformIdentity
    let orient = imageSource.imageOrientation
    let imageSize = CGSizeMake(CGFloat(CGImageGetWidth(imgRef)), CGFloat(CGImageGetHeight(imgRef)))


    switch(imageSource.imageOrientation) {
    case .Up :
        transform = CGAffineTransformIdentity

    case .UpMirrored :
        transform = CGAffineTransformMakeTranslation(imageSize.width, 0.0);
        transform = CGAffineTransformScale(transform, -1.0, 1.0);

    case .Down :
        transform = CGAffineTransformMakeTranslation(imageSize.width, imageSize.height);
        transform = CGAffineTransformRotate(transform, CGFloat(M_PI));

    case .DownMirrored :
        transform = CGAffineTransformMakeTranslation(0.0, imageSize.height);
        transform = CGAffineTransformScale(transform, 1.0, -1.0);

    case .Left :
        let storedHeight = bounds.size.height
        bounds.size.height = bounds.size.width;
        bounds.size.width = storedHeight;
        transform = CGAffineTransformMakeTranslation(0.0, imageSize.width);
        transform = CGAffineTransformRotate(transform, 3.0 * CGFloat(M_PI) / 2.0);

    case .LeftMirrored :
        let storedHeight = bounds.size.height
        bounds.size.height = bounds.size.width;
        bounds.size.width = storedHeight;
        transform = CGAffineTransformMakeTranslation(imageSize.height, imageSize.width);
        transform = CGAffineTransformScale(transform, -1.0, 1.0);
        transform = CGAffineTransformRotate(transform, 3.0 * CGFloat(M_PI) / 2.0);

    case .Right :
        let storedHeight = bounds.size.height
        bounds.size.height = bounds.size.width;
        bounds.size.width = storedHeight;
        transform = CGAffineTransformMakeTranslation(imageSize.height, 0.0);
        transform = CGAffineTransformRotate(transform, CGFloat(M_PI) / 2.0);

    case .RightMirrored :
        let storedHeight = bounds.size.height
        bounds.size.height = bounds.size.width;
        bounds.size.width = storedHeight;
        transform = CGAffineTransformMakeScale(-1.0, 1.0);
        transform = CGAffineTransformRotate(transform, CGFloat(M_PI) / 2.0);

    default : ()
    }

    UIGraphicsBeginImageContext(bounds.size)
    let context = UIGraphicsGetCurrentContext()

    if orient == .Right || orient == .Left {
        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);

    let imageCopy = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return imageCopy;
}
Community
  • 1
  • 1
thattyson
  • 718
  • 8
  • 17
17

Swift 4 version with safety checks of Dilip's answer.

public static func rotateCameraImageToProperOrientation(imageSource : UIImage, maxResolution : CGFloat = 320) -> UIImage? {

    guard let imgRef = imageSource.cgImage else {
        return nil
    }

    let width = CGFloat(imgRef.width)
    let height = CGFloat(imgRef.height)

    var bounds = CGRect(x: 0, y: 0, width: width, height: height)

    var scaleRatio : CGFloat = 1
    if (width > maxResolution || height > maxResolution) {

        scaleRatio = min(maxResolution / bounds.size.width, maxResolution / bounds.size.height)
        bounds.size.height = bounds.size.height * scaleRatio
        bounds.size.width = bounds.size.width * scaleRatio
    }

    var transform = CGAffineTransform.identity
    let orient = imageSource.imageOrientation
    let imageSize = CGSize(width: CGFloat(imgRef.width), height: CGFloat(imgRef.height))

    switch(imageSource.imageOrientation) {
    case .up:
        transform = .identity
    case .upMirrored:
        transform = CGAffineTransform
            .init(translationX: imageSize.width, y: 0)
            .scaledBy(x: -1.0, y: 1.0)
    case .down:
        transform = CGAffineTransform
            .init(translationX: imageSize.width, y: imageSize.height)
            .rotated(by: CGFloat.pi)
    case .downMirrored:
        transform = CGAffineTransform
            .init(translationX: 0, y: imageSize.height)
            .scaledBy(x: 1.0, y: -1.0)
    case .left:
        let storedHeight = bounds.size.height
        bounds.size.height = bounds.size.width;
        bounds.size.width = storedHeight;
        transform = CGAffineTransform
            .init(translationX: 0, y: imageSize.width)
            .rotated(by: 3.0 * CGFloat.pi / 2.0)
    case .leftMirrored:
        let storedHeight = bounds.size.height
        bounds.size.height = bounds.size.width;
        bounds.size.width = storedHeight;
        transform = CGAffineTransform
            .init(translationX: imageSize.height, y: imageSize.width)
            .scaledBy(x: -1.0, y: 1.0)
            .rotated(by: 3.0 * CGFloat.pi / 2.0)
    case .right :
        let storedHeight = bounds.size.height
        bounds.size.height = bounds.size.width;
        bounds.size.width = storedHeight;
        transform = CGAffineTransform
            .init(translationX: imageSize.height, y: 0)
            .rotated(by: CGFloat.pi / 2.0)
    case .rightMirrored:
        let storedHeight = bounds.size.height
        bounds.size.height = bounds.size.width;
        bounds.size.width = storedHeight;
        transform = CGAffineTransform
            .init(scaleX: -1.0, y: 1.0)
            .rotated(by: CGFloat.pi / 2.0)
    }

    UIGraphicsBeginImageContext(bounds.size)
    if let context = UIGraphicsGetCurrentContext() {
        if orient == .right || orient == .left {
            context.scaleBy(x: -scaleRatio, y: scaleRatio)
            context.translateBy(x: -height, y: 0)
        } else {
            context.scaleBy(x: scaleRatio, y: -scaleRatio)
            context.translateBy(x: 0, y: -height)
        }

        context.concatenate(transform)
        context.draw(imgRef, in: CGRect(x: 0, y: 0, width: width, height: height))
    }

    let imageCopy = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()

    return imageCopy
}
Dávid Tímár
  • 719
  • 9
  • 15
  • You can also do `(bounds.size.height, bounds.size.width) = (bounds.size.width, bounds.size.height)` without creating variable as storage. – Almas Sapargali Apr 23 '17 at 06:32
  • I sometimes had the problem, that a white line appeared at the bottom of the image after scaling it. This is because CGFloat seems to be not precise enough. I fixed this with `bounds.size.height.round()` and `bounds.size.width.round()` – ndreisg Feb 28 '18 at 08:53
13

Any image generated by iPhone/iPad is saved as Landscape Left with EXIF Orientation tag (Exif.Image.Orientation) specifying the actual orientation.

It have the following values: 1 : Landscape Left 6 : Portrait Normal 3 : Landscape Right 4 : Portrait Upside Down

In IOS, the EXIF info is properly read and the images are displayed in the same way it was taken. But in Windows, the EXIF info is NOT used.

If you open one of these images in GIMP, it will say that the image has rotation info.

ATOzTOA
  • 34,814
  • 22
  • 96
  • 117
9

For anyone else using Xamarin, here's a C# translation of Dilip's great answer, and a thanks to thattyson for the Swift translation.

public static UIImage RotateCameraImageToProperOrientation(UIImage imageSource, nfloat maxResolution) {

    var imgRef = imageSource.CGImage;

    var width = (nfloat)imgRef.Width;
    var height = (nfloat)imgRef.Height;

    var bounds = new CGRect(0, 0, width, height);

    nfloat scaleRatio = 1;

    if (width > maxResolution || height > maxResolution) 
    {
        scaleRatio = (nfloat)Math.Min(maxResolution / bounds.Width, maxResolution / bounds.Height);
        bounds.Height = bounds.Height * scaleRatio;
        bounds.Width = bounds.Width * scaleRatio;
    }

    var transform = CGAffineTransform.MakeIdentity();
    var orient = imageSource.Orientation;
    var imageSize = new CGSize(imgRef.Width, imgRef.Height);
    nfloat storedHeight;

    switch(imageSource.Orientation) {
        case UIImageOrientation.Up:
            transform = CGAffineTransform.MakeIdentity();
            break;

        case UIImageOrientation.UpMirrored :
            transform = CGAffineTransform.MakeTranslation(imageSize.Width, 0.0f);
            transform = CGAffineTransform.Scale(transform, -1.0f, 1.0f);
            break;

        case UIImageOrientation.Down :
            transform = CGAffineTransform.MakeTranslation(imageSize.Width, imageSize.Height);
            transform = CGAffineTransform.Rotate(transform, (nfloat)Math.PI);
            break;

        case UIImageOrientation.DownMirrored :
            transform = CGAffineTransform.MakeTranslation(0.0f, imageSize.Height);
            transform = CGAffineTransform.Scale(transform, 1.0f, -1.0f);
            break;

        case UIImageOrientation.Left:
            storedHeight = bounds.Height;
            bounds.Height = bounds.Width;
            bounds.Width = storedHeight;
            transform = CGAffineTransform.MakeTranslation(0.0f, imageSize.Width);
            transform = CGAffineTransform.Rotate(transform, 3.0f * (nfloat)Math.PI / 2.0f);
            break;

        case UIImageOrientation.LeftMirrored :
            storedHeight = bounds.Height;
            bounds.Height = bounds.Width;
            bounds.Width = storedHeight;
            transform = CGAffineTransform.MakeTranslation(imageSize.Height, imageSize.Width);
            transform = CGAffineTransform.Scale(transform, -1.0f, 1.0f);
            transform = CGAffineTransform.Rotate(transform, 3.0f * (nfloat)Math.PI / 2.0f);
            break;

        case UIImageOrientation.Right :
            storedHeight = bounds.Height;
            bounds.Height = bounds.Width;
            bounds.Width = storedHeight;
            transform = CGAffineTransform.MakeTranslation(imageSize.Height, 0.0f);
            transform = CGAffineTransform.Rotate(transform, (nfloat)Math.PI / 2.0f);
            break;

        case UIImageOrientation.RightMirrored :
            storedHeight = bounds.Height;
            bounds.Height = bounds.Width;
            bounds.Width = storedHeight;
            transform = CGAffineTransform.MakeScale(-1.0f, 1.0f);
            transform = CGAffineTransform.Rotate(transform, (nfloat)Math.PI / 2.0f);
            break;

        default :
            break;
    }

    UIGraphics.BeginImageContext(bounds.Size);
    var context = UIGraphics.GetCurrentContext();

    if (orient == UIImageOrientation.Right || orient == UIImageOrientation.Left) {
        context.ScaleCTM(-scaleRatio, scaleRatio);
        context.TranslateCTM(-height, 0);
    } else {
        context.ScaleCTM(scaleRatio, -scaleRatio);
        context.TranslateCTM(0, -height);
    }

    context.ConcatCTM(transform);
    context.DrawImage(new CGRect(0, 0, width, height), imgRef);

    var imageCopy = UIGraphics.GetImageFromCurrentImageContext();
    UIGraphics.EndImageContext();

    return imageCopy;
}
Community
  • 1
  • 1
tetowill
  • 91
  • 1
  • 3
  • This has helped resolve my issue after spending many hours playing with this! Unbelievable that Xamarin doesn't have some in-built support for this given it is now a Microsoft product. – Sami.C Jan 11 '18 at 02:47
4

I came across this question because I was having a similar problem, but using Swift. Just wanted to link to the answer that worked for me for any other Swift developers: https://stackoverflow.com/a/26676578/3904581

Here's a Swift snippet that fixes the problem efficiently:

let orientedImage = UIImage(CGImage: initialImage.CGImage, scale: 1, orientation: initialImage.imageOrientation)!

Super simple. One line of code. Problem solved.

Community
  • 1
  • 1
Melly
  • 675
  • 5
  • 6
  • This didn't work for me, I used this solution: http://stackoverflow.com/a/27775741/945247 – Leon Jul 01 '16 at 10:09
0

I know exactly what your problem is. You are using UIImagePicker, which is weird in every sense. I would suggest you use AVFoundation for the camera which gives flexibility in orientation as well as quality. Use AVCaptureSession. You can get the code here How to save photos taken using AVFoundation to Photo Album?

Community
  • 1
  • 1
Gautam Jain
  • 2,913
  • 30
  • 25
0

Quickly refactored for Swift 3 (can someone test it and confirm everything works ok?):

static func rotateCameraImageToProperOrientation(imageSource : UIImage, maxResolution : CGFloat) -> UIImage {
    let imgRef = imageSource.cgImage

    let width = CGFloat(imgRef!.width)
    let height = CGFloat(imgRef!.height)

    var bounds = CGRect(x: 0, y: 0, width: width, height: height)

    var scaleRatio : CGFloat = 1
    if width > maxResolution || height > maxResolution {

        scaleRatio = min(maxResolution / bounds.size.width, maxResolution / bounds.size.height)
        bounds.size.height = bounds.size.height * scaleRatio
        bounds.size.width = bounds.size.width * scaleRatio
    }

    var transform = CGAffineTransform.identity
    let orient = imageSource.imageOrientation
    let imageSize = CGSize(width: imgRef!.width, height: imgRef!.height)

    switch imageSource.imageOrientation {
    case .up :
        transform = CGAffineTransform.identity

    case .upMirrored :
        transform = CGAffineTransform(translationX: imageSize.width, y: 0)
        transform = transform.scaledBy(x: -1, y: 1)

    case .down :
        transform = CGAffineTransform(translationX: imageSize.width, y: imageSize.height)
        transform = transform.rotated(by: CGFloat.pi)

    case .downMirrored :
        transform = CGAffineTransform(translationX: 0, y: imageSize.height)
        transform = transform.scaledBy(x: 1, y: -1)

    case .left :
        let storedHeight = bounds.size.height
        bounds.size.height = bounds.size.width
        bounds.size.width = storedHeight
        transform = CGAffineTransform(translationX: 0, y: imageSize.width)
        transform = transform.rotated(by: 3.0 * CGFloat.pi / 2.0)

    case .leftMirrored :
        let storedHeight = bounds.size.height
        bounds.size.height = bounds.size.width
        bounds.size.width = storedHeight
        transform = CGAffineTransform(translationX: imageSize.height, y: imageSize.width)
        transform = transform.scaledBy(x: -1, y: 1)
        transform = transform.rotated(by: 3.0 * CGFloat.pi / 2.0)

    case .right :
        let storedHeight = bounds.size.height
        bounds.size.height = bounds.size.width
        bounds.size.width = storedHeight
        transform = CGAffineTransform(translationX: imageSize.height, y: 0)
        transform = transform.rotated(by: CGFloat.pi / 2.0)

    case .rightMirrored :
        let storedHeight = bounds.size.height
        bounds.size.height = bounds.size.width
        bounds.size.width = storedHeight
        transform = CGAffineTransform(scaleX: -1, y: 1)
        transform = transform.rotated(by: CGFloat.pi / 2.0)

    }

    UIGraphicsBeginImageContext(bounds.size)
    let context = UIGraphicsGetCurrentContext()

    if orient == .right || orient == .left {

        context!.scaleBy(x: -scaleRatio, y: scaleRatio)
        context!.translateBy(x: -height, y: 0)
    } else {
        context!.scaleBy(x: scaleRatio, y: -scaleRatio)
        context!.translateBy(x: 0, y: -height)
    }

    context!.concatenate(transform)
    context!.draw(imgRef!, in: CGRect(x: 0, y: 0, width: width, height: height))

    let imageCopy = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()

    return imageCopy!
}
Slavcho
  • 2,792
  • 3
  • 30
  • 48
sabiland
  • 2,526
  • 1
  • 25
  • 24
0

Here is Swift3 version of Dilip's awesome answer

func rotateCameraImageToProperOrientation(imageSource : UIImage, maxResolution : CGFloat) -> UIImage {
    let imgRef = imageSource.cgImage!;

    let width = CGFloat(imgRef.width);
    let height = CGFloat(imgRef.height);

    var bounds = CGRect(x: 0, y: 0, width: width, height: height)

    var scaleRatio : CGFloat = 1
    if (width > maxResolution || height > maxResolution) {
        scaleRatio = min(maxResolution / bounds.size.width, maxResolution / bounds.size.height)
        bounds.size.height = bounds.size.height * scaleRatio
        bounds.size.width = bounds.size.width * scaleRatio
    }

    var transform = CGAffineTransform.identity
    let orient = imageSource.imageOrientation
    let imageSize = CGSize(width: width, height: height)


    switch(imageSource.imageOrientation) {
        case .up :
            transform = CGAffineTransform.identity

        case .upMirrored :
            transform = CGAffineTransform(translationX: imageSize.width, y: 0.0);
            transform = transform.scaledBy(x: -1, y: 1);

        case .down :
            transform = CGAffineTransform(translationX: imageSize.width, y: imageSize.height);
            transform = transform.rotated(by: CGFloat(Double.pi));

        case .downMirrored :
            transform = CGAffineTransform(translationX: 0.0, y: imageSize.height);
            transform = transform.scaledBy(x: 1, y: -1);

        case .left :
            let storedHeight = bounds.size.height
            bounds.size.height = bounds.size.width;
            bounds.size.width = storedHeight;
            transform = CGAffineTransform(translationX: 0.0, y: imageSize.width);
            transform = transform.rotated(by: 3.0 * CGFloat(Double.pi) / 2.0);

        case .leftMirrored :
            let storedHeight = bounds.size.height
            bounds.size.height = bounds.size.width;
            bounds.size.width = storedHeight;
            transform = CGAffineTransform(translationX: imageSize.height, y: imageSize.width);
            transform = transform.scaledBy(x: -1, y: 1);
            transform = transform.rotated(by: 3.0 * CGFloat(Double.pi) / 2.0);

        case .right :
            let storedHeight = bounds.size.height
            bounds.size.height = bounds.size.width;
            bounds.size.width = storedHeight;
            transform = CGAffineTransform(translationX: imageSize.height, y: 0.0);
            transform = transform.rotated(by: CGFloat(Double.pi) / 2.0);

        case .rightMirrored :
            let storedHeight = bounds.size.height
            bounds.size.height = bounds.size.width;
            bounds.size.width = storedHeight;
            transform = CGAffineTransform(scaleX: -1.0, y: 1.0);
            transform = transform.rotated(by: CGFloat(Double.pi) / 2.0);
    }

    UIGraphicsBeginImageContext(bounds.size)
    let context = UIGraphicsGetCurrentContext()!

    if orient == .right || orient == .left {
        context.scaleBy(x: -scaleRatio, y: scaleRatio);
        context.translateBy(x: -height, y: 0);
    } else {
        context.scaleBy(x: scaleRatio, y: -scaleRatio);
        context.translateBy(x: 0, y: -height);
    }

    context.concatenate(transform);
    context.draw(imgRef, in: CGRect(x: 0, y: 0, width: width, height: height))

    let imageCopy = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return imageCopy!;
}
Sandip Mane
  • 1,420
  • 1
  • 9
  • 14
0

you can fix this HECI rotate image by this code

Swift 5 Extension:

extension UIImage {
    /// Fix image orientaton to protrait up
    func fixedOrientation() -> UIImage? {
        guard imageOrientation != UIImage.Orientation.up else {
            // This is default orientation, don't need to do anything
            return self.copy() as? UIImage
        }

        guard let cgImage = self.cgImage else {
            // CGImage is not available
            return nil
        }

        guard let colorSpace = cgImage.colorSpace, let ctx = CGContext(data: nil, width: Int(size.width), height: Int(size.height), bitsPerComponent: cgImage.bitsPerComponent, bytesPerRow: 0, space: colorSpace, bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue) else {
            return nil // Not able to create CGContext
        }

        var transform: CGAffineTransform = CGAffineTransform.identity

        switch imageOrientation {
        case .down, .downMirrored:
            transform = transform.translatedBy(x: size.width, y: size.height)
            transform = transform.rotated(by: CGFloat.pi)
        case .left, .leftMirrored:
            transform = transform.translatedBy(x: size.width, y: 0)
            transform = transform.rotated(by: CGFloat.pi / 2.0)
        case .right, .rightMirrored:
            transform = transform.translatedBy(x: 0, y: size.height)
            transform = transform.rotated(by: CGFloat.pi / -2.0)
        case .up, .upMirrored:
            break
        @unknown default:
            fatalError("Missing...")
            break
        }

        // Flip image one more time if needed to, this is to prevent flipped image
        switch imageOrientation {
        case .upMirrored, .downMirrored:
            transform = transform.translatedBy(x: size.width, y: 0)
            transform = transform.scaledBy(x: -1, y: 1)
        case .leftMirrored, .rightMirrored:
            transform = transform.translatedBy(x: size.height, y: 0)
            transform = transform.scaledBy(x: -1, y: 1)
        case .up, .down, .left, .right:
            break
        @unknown default:
            fatalError("Missing...")
            break
        }

        ctx.concatenate(transform)

        switch imageOrientation {
        case .left, .leftMirrored, .right, .rightMirrored:
            ctx.draw(cgImage, in: CGRect(x: 0, y: 0, width: size.height, height: size.width))
        default:
            ctx.draw(cgImage, in: CGRect(x: 0, y: 0, width: size.width, height: size.height))
            break
        }

        guard let newCGImage = ctx.makeImage() else { return nil }
        return UIImage.init(cgImage: newCGImage, scale: 1, orientation: .up)
    }
}

Objective C Code :

-(UIImage *)scaleAndRotateImage:(UIImage *)image{
        // No-op if the orientation is already correct
        if (image.imageOrientation == UIImageOrientationUp) return image;
        
        // 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 (image.imageOrientation) {
            case UIImageOrientationDown:
            case UIImageOrientationDownMirrored:
                transform = CGAffineTransformTranslate(transform, image.size.width, image.size.height);
                transform = CGAffineTransformRotate(transform, M_PI);
                break;
                
            case UIImageOrientationLeft:
            case UIImageOrientationLeftMirrored:
                transform = CGAffineTransformTranslate(transform, image.size.width, 0);
                transform = CGAffineTransformRotate(transform, M_PI_2);
                break;
                
            case UIImageOrientationRight:
            case UIImageOrientationRightMirrored:
                transform = CGAffineTransformTranslate(transform, 0, image.size.height);
                transform = CGAffineTransformRotate(transform, -M_PI_2);
                break;
            case UIImageOrientationUp:
            case UIImageOrientationUpMirrored:
                break;
        }
        
        switch (image.imageOrientation) {
            case UIImageOrientationUpMirrored:
            case UIImageOrientationDownMirrored:
                transform = CGAffineTransformTranslate(transform, image.size.width, 0);
                transform = CGAffineTransformScale(transform, -1, 1);
                break;
                
            case UIImageOrientationLeftMirrored:
            case UIImageOrientationRightMirrored:
                transform = CGAffineTransformTranslate(transform, image.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, image.size.width, image.size.height,
                                                 CGImageGetBitsPerComponent(image.CGImage), 0,
                                                 CGImageGetColorSpace(image.CGImage),
                                                 CGImageGetBitmapInfo(image.CGImage));
        CGContextConcatCTM(ctx, transform);
        switch (image.imageOrientation) {
            case UIImageOrientationLeft:
            case UIImageOrientationLeftMirrored:
            case UIImageOrientationRight:
            case UIImageOrientationRightMirrored:
                // Grr...
                CGContextDrawImage(ctx, CGRectMake(0,0,image.size.height,image.size.width), image.CGImage);
                break;
                
            default:
                CGContextDrawImage(ctx, CGRectMake(0,0,image.size.width,image.size.height), image.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;
}

Use of code

 UIImage *img=[info objectForKey:UIImagePickerControllerOriginalImage];

 img=[self scaleAndRotateImage:img];
 NSData *image = UIImageJPEGRepresentation(img, 0.1);
Muhammad Numan
  • 23,222
  • 6
  • 63
  • 80
-3

Try changing the image format to .jpeg. This worked for me

Victor Rius
  • 4,566
  • 1
  • 20
  • 28