iOS 图像方向有奇怪的行为

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10600613/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 18:23:52  来源:igfitidea点击:

iOS Image Orientation has Strange Behavior

iphoneobjective-cios

提问by Boeckm

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.

在过去的几周里,我一直在使用 Objective-c 处理图像,并注意到许多奇怪的行为。首先,像许多其他人一样,我遇到了这样的问题:用相机拍摄的图像(或用别人的相机拍摄并发送给我的彩信)旋转了 90 度。我不确定为什么会发生这种情况(因此是我的问题),但我能够想出一个便宜的解决方法。

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 imageOrientationflag all together.

我的应用程序修改了图像的单个像素,特别是 PNG 的 alpha 通道(因此对于我的场景,任何 JPEG 转换都会被抛出窗口)。几天前,我注意到即使由于我的解决方法代码,图像在我的应用程序中正确显示,当我的算法修改图像的单个像素时,它认为图像已旋转。所以不是修改图像顶部的像素,而是修改图像侧面的像素(因为它认为应该旋转)!我不知道如何在内存中旋转图像 - 理想情况下,我宁愿一起擦掉那个imageOrientation标志。

Here's something else that has been baffling me as well... When I take the photo, the imageOrientationis 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, thensaves it so it appears in the camera roll properly.

这里还有一些让我感到困惑的东西......当我拍照时,imageOrientation设置为 3。我的解决方法代码足够聪明,可以意识到这一点并翻转它,因此用户永远不会注意到。此外,我将图像保存到库的代码实现了这一点,翻转它,然后保存它,使其正确出现在相机胶卷中。

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 imageOrientationis 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 imageOrientationis always 0, resulting in perfect behavior). For some reason, my save code seems to wipe away this imageOrientationflag. 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 UIImageWriteToSavedPhotosAlbumdo something special with imageOrientation?

当我将这个新保存的图像加载到我的应用程序中时,它imageOrientation是 0 - 正是我想要看到的,我的旋转解决方法甚至不需要运行(注意:从互联网加载图像而不是用相机拍摄的图像,imageOrientation总是 0,导致完美的行为)。出于某种原因,我的保存代码似乎抹去了这个imageOrientation标志。我希望只要用户拍照并将其添加到应用程序中,就可以窃取该代码并使用它来擦除我的 imageOrientation ,但它似乎不起作用。是否UIImageWriteToSavedPhotosAlbum做一些特别的东西用imageOrientation

Would the best fix for this problem be to just blow away imageOrientationas 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.

解决此问题的最佳方法是imageOrientation在用户拍摄完图像后立即吹走。我认为 Apple 的旋转行为是有原因的,对吗?一些人认为这是 Apple 的缺陷。

(... 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)

(...如果你还没有迷路...注2:当我拍横向照片时,一切似乎都完美无缺,就像从互联网上拍摄的照片一样)

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.

以下是一些图像和场景的实际外观。根据目前的评论,这种奇怪的行为似乎不仅仅是 iPhone 的行为,我认为这很好。

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

在 iPhone 上拍摄的实际照片

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

这是我通过电子邮件发送给自己后 Gmail 中的图像(看起来 Gmail 处理得当):

Photo as it appears in Gmail

在 Gmail 中显示的照片

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

这是图像在 Windows 中作为缩略图的样子(看起来处理不当):

Windows Thumbnail

视窗缩略图

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

这是使用 Windows 照片查看器打开时实际图像的样子(仍然没有正确处理):

Windows Photo Viewer Version

Windows 照片查看器版本

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?

在对这个问题的所有评论之后,这就是我的想法...... iPhone 拍摄了一张图像,并说“要正确显示它,它需要旋转 90 度”。此信息将在 EXIF 数据中。(为什么它需要旋转 90 度,而不是默认为直线垂直,我不知道)。从这里开始,Gmail 足够智能,可以读取和分析 EXIF 数据,并正确显示它。然而,Windows 不够智能,无法读取 EXIF 数据,因此无法正确显示图像。我的假设正确吗?

采纳答案by HarshIT

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.

我对它进行了研发并发现,每个图像文件都有元数据属性。如果元数据指定了通常被其他操作系统(但 Mac 除外)忽略的图像的方向。大多数拍摄的图像都将其元数据属性设置为直角。所以 Mac 以 90 度旋转的方式显示它。您可以在 Windows 操作系统中以正确的方式看到相同的图像。

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

有关更多详细信息,请阅读此答案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/

尝试在此处阅读您的图像的 exif http://www.exifviewer.org/http://regex.info/exif.cgihttp://www.addivetips.com/internet-tips/view-complete-exif -metadata-information-of-any-jpeg-image-online/

回答by Dilip Rajkumar

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

当我从相机获取图像时遇到了同样的问题,我把下面的代码来修复它..从这里添加了方法 scaleAndRotateImage

- (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;
}

回答by thattyson

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

快速复制/粘贴 Dilip出色答案的Swift 翻译。

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

回答by Roy

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.

答案很简单。Apple 没有旋转图像。这就是混乱所在。

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

CCD 相机不旋转,因此它始终以横向模式拍摄照片。

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.

OpenGL 可以非常轻松地进行翻译——因此数据永远不会被打乱——只是它是如何绘制的。

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.

如果您想裁剪、调整大小等,这将成为一个问题 - 但是一旦您知道发生了什么,您只需定义您的矩阵,一切都会解决。

回答by Dávid Tímár

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

Swift 4 版本,对Dilip 的回答进行了安全检查。

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
}

回答by ATOzTOA

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

iPhone/iPad 生成的任何图像都保存为横向左侧,并带有指定实际方向的 EXIF 方向标签 (Exif.Image.Orientation)。

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

它具有以下值: 1:横向左侧 6:纵向正常 3:横向右侧 4:纵向倒置

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.

在 IOS 中,EXIF 信息被正确读取,图像以与拍摄相同的方式显示。但在 Windows 中,不使用 EXIF 信息。

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

如果您在 GIMP 中打开这些图像之一,它会说该图像具有旋转信息。

回答by tetowill

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

对于使用 Xamarin 的其他人,这里是 Dilip 的出色答案的 C# 翻译,并感谢thattyson 提供的Swift 翻译

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

回答by ClareHuxtable

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

我遇到了这个问题,因为我遇到了类似的问题,但使用的是 Swift。只是想链接到对任何其他 Swift 开发人员有用的答案:https: //stackoverflow.com/a/26676578/3904581

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

这是一个有效解决问题的 Swift 代码段:

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

Super simple. One line of code. Problem solved.

超级简单。一行代码。问题解决了。

回答by Sandip Mane

Here is Swift3 version of Dilip's awesome answer

这是 Dilip 很棒的答案的 Swift3 版本

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!;
}

回答by sabiland

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

为 Swift 3 快速重构(有人可以测试它并确认一切正常吗?):

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!
}