MFMailComposeViewController图像方向

时间:2013-11-25 22:15:28

标签: iphone image email ios6 orientation

我正在开发一款通用应用,我正在为iOS6编码。

我正在使用imagePickerController拍摄照片,然后使用MFMailComposeViewController将其作为附件发送。所有这一切都在发挥作用。

我的问题是,当我以纵向模式拍摄照片时,MFMailComposeViewController会以横向模式显示。此外,当它到达目的地电子邮件地址时,它将以横向模式显示。

如果我以横向模式拍摄照片,它将以横向模式显示在MFMailComposeViewController中,当它到达目的地电子邮件地址时,它将以横向模式显示。所以没关系。

我的两个测试设备都有同样的问题; iPhone5和iPad2。

如何以纵向模式拍摄照片以纵向模式到达电子邮件目的地?

以下是我将图像添加到电子邮件的方式:

if ( [MFMailComposeViewController canSendMail] )
   {
   MFMailComposeViewController * mailVC = [MFMailComposeViewController new];
   NSArray * aAddr  = [NSArray arrayWithObjects: gAddr, nil];
   NSData * imageAsNSData = UIImagePNGRepresentation( gImag );

   [mailVC setMailComposeDelegate: self];
   [mailVC        setToRecipients: aAddr];
   [mailVC             setSubject: gSubj];
   [mailVC      addAttachmentData: imageAsNSData
                         mimeType: @"image/png"
                         fileName: @"myPhoto.png"];
   [mailVC         setMessageBody: @"Blah blah"
                          isHTML: NO];

   [self presentViewController: mailVC
                      animated: YES
                    completion: nil];
   }
else
   {
   NSLog( @"Device is unable to send email in its current state." );
   }

6 个答案:

答案 0 :(得分:56)

我已经花了几个小时研究这个问题,现在我已经清楚了解了发生了什么以及如何解决这个问题。

重复一遍,我遇到的问题是:

当我使用imagePickerController在相机上以纵向模式拍摄图像并将该图像传递给MFMailComposeViewController并通过电子邮件发送时,它会到达目标电子邮件地址,并在横向模式下显示错误。

但是,如果我以横向模式拍摄照片然后发送,它将以横向模式正确显示在电子邮件的目的地

那么,如何以纵向模式拍摄照片以纵向模式到达电子邮件目的地?那是我原来的问题。

这是代码,正如我在原始问题中所展示的那样,除了我现在将图像作为JPEG而不是PNG发送,但这没有任何区别。

这就是我用imagePickerController捕获图像并将其放入一个名为gImag的全局图中的方法:

gImag = (UIImage *)[info valueForKey: UIImagePickerControllerOriginalImage];
[[self imageView] setImage: gImag];             // send image to screen
[self imagePickerControllerRelease: picker ];   // free the picker object

这就是我使用MFMailComposeViewController发送电子邮件的方式:

if ( [MFMailComposeViewController canSendMail] )
   {
   MFMailComposeViewController * mailVC = [MFMailComposeViewController new];
   NSArray * aAddr  = [NSArray arrayWithObjects: gAddr, nil];
   NSData * imageAsNSData = UIImageJPEGRepresentation( gImag );

   [mailVC setMailComposeDelegate: self];
   [mailVC        setToRecipients: aAddr];
   [mailVC             setSubject: gSubj];
   [mailVC      addAttachmentData: imageAsNSData
                         mimeType: @"image/jpg"
                         fileName: @"myPhoto.jpg"];
   [mailVC         setMessageBody: @"Blah blah"
                           isHTML: NO];

   [self presentViewController: mailVC
                      animated: YES
                    completion: nil];
   }
else NSLog( @"Device is unable to send email in its current state." );

当我描述如何解决这个问题时,我将专注于使用iPhone 5并使用主摄像头拍摄3264x2448以保持简单。但是,此问题会影响其他设备和分辨率。

解锁此问题的关键是意识到当您拍摄图像时,无论是横向画像,iPhone总是以相同的方式存储UIImage:3264宽和2448高。

UIImage有一个属性,描述了捕获图像时的方向,你可以这样得到它:

UIImageOrientation orient = image.imageOrientation;

请注意,orientation属性 not 描述了UIImage中数据的物理配置方式(如3264w x 2448h);它仅描述了捕获图像时的方向。

该属性的用途是告诉即将显示图像的软件,如何旋转它以使其正确显示。

如果以纵向模式捕获图像,image.imageOrientation将返回UIImageOrientationRight。这告诉显示软件需要将图像旋转90度以便正确显示。要明确的是,这种“旋转”不会影响UIImage的底层存储,它仍然是3264w x 2448h。

如果以横向模式捕获图像,image.imageOrientation将返回UIImageOrientationUp。 UIImageOrientationUp告诉显示软件图像可以正常显示;不需要轮换。同样,UIIMage的底层存储是3264w x 2448h。

一旦你清楚了数据的物理存储方式与方向属性在被捕获时如何用它来描述方向之间的区别,事情就会变得更加清晰。

我创建了几行调试代码来“看到”所有这些。

这是添加了调试代码的imagePickerController代码:

gImag = (PIMG)[info valueForKey: UIImagePickerControllerOriginalImage];

UIImageOrientation orient = gImag.imageOrientation;
CGFloat            width  = CGImageGetWidth(gImag.CGImage);
CGFloat            height = CGImageGetHeight(gImag.CGImage);

[[self imageView] setImage: gImag];                 // send image to screen
[self imagePickerControllerRelease: picker ];   // free the picker object

如果我们拍摄肖像,gImage会以UIImageOrientationRight到达,宽度= 3264,高度= 2448。

如果我们拍摄风景,gImage会以UIImageOrientationUp和width = 3264以及height = 2448到达。

如果我们继续使用E-Mailng MFMailComposeViewController代码,我也在那里添加了调试代码:

if ( [MFMailComposeViewController canSendMail] )
   {
   MFMailComposeViewController * mailVC = [MFMailComposeViewController new];
   NSArray * aAddr  = [NSArray arrayWithObjects: gAddr, nil];

   UIImageOrientation orient = gImag.imageOrientation;
   CGFloat            width  = CGImageGetWidth(gImag.CGImage);
   CGFloat            height = CGImageGetHeight(gImag.CGImage);

   NSData * imageAsNSData = UIImageJPEGRepresentation( gImag );

   [mailVC setMailComposeDelegate: self];
   [mailVC        setToRecipients: aAddr];
   [mailVC             setSubject: gSubj];
   [mailVC      addAttachmentData: imageAsNSData
                         mimeType: @"image/jpg"
                         fileName: @"myPhoto.jpg"];
   [mailVC         setMessageBody: @"Blah blah"
                           isHTML: NO];

   [self presentViewController: mailVC
                      animated: YES
                    completion: nil];
   }
else NSLog( @"Device is unable to send email in its current state." );

在这里看到没什么了不起的。我们得到的值与imagePickerController代码中的值完全相同。

让我们确切了解问题的解决方法:

首先,相机拍摄人像照片,并以纵向模式正确显示:

[[self imageView] setImage: gImag];                 // send image to screen

显示正确,因为这行代码看到了orientation属性并适当地旋转了图像(而不是在3264x2448处触及底层存储)。

控制流现在转到E-Mailer代码并且orientation属性仍然存在于gImag中,因此当MFMailComposeViewController代码在传出电子邮件中显示图像时,它是正确定向的。物理图像仍然存储为3264x2448。

发送电子邮件,并且在接收端,对方向属性的了解已经丢失,因此接收软件显示图像,因为它实际布局为3264x2448,即横向。

在调试中,我遇到了额外的困惑。也就是说,如果你不正确地复制了它,那么可以从UIImage中去除orientation属性。

此代码显示问题:

if ( [MFMailComposeViewController canSendMail] )
   {
   MFMailComposeViewController * mailVC = [MFMailComposeViewController new];
   NSArray * aAddr  = [NSArray arrayWithObjects: gAddr, nil];

   UIImageOrientation orient = gImag.imageOrientation;
   CGFloat            width  = CGImageGetWidth(gImag.CGImage);
   CGFloat            height = CGImageGetHeight(gImag.CGImage);

   UIImage * tmp = [[UIImage alloc] initWithCGImage: gImag.CGImage];

   orient = tmp.imageOrientation;
   width  = CGImageGetWidth(tmp.CGImage);
   height = CGImageGetHeight(tmp.CGImage);

   NSData * imageAsNSData = UIImageJPEGRepresentation( tmp );

   [mailVC setMailComposeDelegate: self];
   [mailVC        setToRecipients: aAddr];
   [mailVC             setSubject: gSubj];
   [mailVC      addAttachmentData: imageAsNSData
                         mimeType: @"image/jpg"
                         fileName: @"myPhoto.jpg"];
   [mailVC         setMessageBody: @"Blah blah"
                           isHTML: NO];

   [self presentViewController: mailVC
                      animated: YES
                    completion: nil];
   }
else NSLog( @"Device is unable to send email in its current state." );

当我们查看新UIImage tmp的调试数据时,我们得到UIImageOrientationUp和width = 3264,height = 2448。

方向属性已被剥离,默认方向为“向上”。如果你不知道正在进行剥离,它确实会让事情变得混乱。

如果我运行此代码,我现在得到以下结果:

imagePickerController代码中的内容没有变化;像以前一样捕捉图像。

控制流程继续使用E-Mailer代码,但现在已从tmp图像中删除了orientation属性,因此当MFMailComposeViewController代码在传出电子邮件中显示tmp图像时,它将以横向模式显示(因为默认方向是UIImageOrientationUp所以没有完成3264x2448图像的旋转)。

电子邮件已发送,并且在接收端,对方向属性的了解也会丢失,因此接收软件会将图像显示为3264x2448(即横向)。

通过使用以下代码制作UIImage副本,可以避免在制作UIImage副本时“取消”方向属性,如果有人知道它正在进行,那么:

UIImage * tmp = [UIImage imageWithCGImage: gImag.CGImage
                                    scale: gImag.scale
                              orientation: gImag.imageOrientation];

这样可以避免在途中丢失方向属性,但是当您通过电子邮件发送图像时,它仍然无法解决远端丢失问题。

有一种更好的方法,比所有这些搞乱和担心方向属性。

我找到了一些我已整合到程序中的代码here。此代码将根据其方向属性物理旋转基础存储图像。

对于方向为UIImageOrientationRight的UIImage,它将物理旋转UIImage,使其最终为2448x3264,它将去除orientation属性,以便此后可以看作默认的UIImageOrientationUp。

对于UIImageOrientationUp方向的UIImage,它什么都不做。它让睡觉的风景狗撒谎。

如果你这样做,那么我认为(基于我到目前为止看到的),UIImage的方向属性此后是多余的。只要它仍然缺失/剥离或设置为UIImageOrientationUp,当您显示嵌入电子邮件中的图像时,您的图像应该在沿途的每一步和远端正确显示。

我在答案中讨论过的所有内容,我个人都是单步进行并观察它发生的。

所以,这里有我的最终代码:

gImag = (PIMG)[info valueForKey: UIImagePickerControllerOriginalImage];
[[self imageView] setImage: gImag];             // send image to screen
[self imagePickerControllerRelease: picker ];   // free the picker object

if ( [MFMailComposeViewController canSendMail] )
   {
   MFMailComposeViewController * mailVC = [MFMailComposeViewController new];
   NSArray                     * aAddr  = [NSArray arrayWithObjects: gAddr, nil];

   //...lets not touch the original UIImage

   UIImage * tmpImag = [UIImage imageWithCGImage: gImag.CGImage
                                           scale: gImag.scale
                                     orientation: gImag.imageOrientation];

   //...do physical rotation, if needed

   PIMG ImgOut = [gU scaleAndRotateImage: tmpImag];

   //...note orientation is UIImageOrientationUp now

   NSData * imageAsNSData = UIImageJPEGRepresentation( ImgOut, 0.9f );

   [mailVC setMailComposeDelegate: self];
   [mailVC        setToRecipients: aAddr];
   [mailVC             setSubject: gSubj];
   [mailVC      addAttachmentData: imageAsNSData
                         mimeType: @"image/jpg"
                         fileName: @"myPhoto.jpg"];
   [mailVC         setMessageBody: @"Blah blah"
                           isHTML: NO];

   [self presentViewController: mailVC
                      animated: YES
                    completion: nil];
   }
else NSLog( @"Device is unable to send email in its current state." );   

最后,如果有必要,我从here抓取的代码执行物理轮换:

- (UIImage *) scaleAndRotateImage: (UIImage *) imageIn
   //...thx: http://blog.logichigh.com/2008/06/05/uiimage-fix/
   {
   int kMaxResolution = 3264; // Or whatever

   CGImageRef        imgRef    = imageIn.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) );
   UIImageOrientation orient       = imageIn.imageOrientation;
   CGFloat            boundHeight;

   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 );
   }
来自新西兰的干杯。

答案 1 :(得分:3)

我自己在iOS SDK7中一直在努力应对图像方向,我想在本次讨论中添加一些东西,希望它对其他人有用。 UIImageJPEGRepresentation工作正常,但要注意使用UIImagePNGRepresentation可能会导致图片方向不正确。

我正在开发一款应用程序,其中使用设备相机拍摄照片后上传照片。我暂时不将图像存储到磁盘,而是将其直接发送到服务器。

将UIImage呈现给NSData时,您可以选择UIImagePNGRepresentationUIImageJPEGRepresentation

使用UIImagePNGRepresentation时,以纵向和横向拍摄的照片都会生成横向图像。在这种情况下,肖像图像逆时针旋转90度。

使用UIImageJPEGRepresentation时,纵向和横向图像都会以正确的方向生成。

答案 2 :(得分:2)

规模部分的快速版本:

class func scaleAndRotateImageUsingOrientation(imageIn : UIImage) -> UIImage
    {
        //takes into account the stored rotation on the image fromt he camera and makes it upright
        let kMaxResolution = 3264; // Or whatever

        let imgRef    = imageIn.CGImage
        let width     = CGImageGetWidth(imgRef)
        let height    = CGImageGetHeight(imgRef)
        var transform = CGAffineTransformIdentity
        var bounds    = CGRectMake( 0.0, 0.0, CGFloat(width), CGFloat(height) )

        if ( width > kMaxResolution || height > kMaxResolution )
        {
            let ratio : CGFloat = CGFloat(width) / CGFloat(height);

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

        let scaleRatio : CGFloat = bounds.size.width / CGFloat(width)
        var imageSize    = CGSizeMake( CGFloat(CGImageGetWidth(imgRef)), CGFloat(CGImageGetHeight(imgRef)) )
        let orient       = imageIn.imageOrientation;
        var boundHeight : CGFloat = 0.0

        switch(orient)
        {
        case UIImageOrientation.Up:                                        //EXIF = 1
            transform = CGAffineTransformIdentity;
            break;

        case UIImageOrientation.UpMirrored:                                //EXIF = 2
            transform = CGAffineTransformMakeTranslation(imageSize.width, 0.0);
            transform = CGAffineTransformScale(transform, -1.0, 1.0);
        break;

        case UIImageOrientation.Down:                                      //EXIF = 3
            transform = CGAffineTransformMakeTranslation(imageSize.width, imageSize.height);
            transform = CGAffineTransformRotate(transform, CGFloat(M_PI));
            break;

        case UIImageOrientation.DownMirrored:                              //EXIF = 4
            transform = CGAffineTransformMakeTranslation(0.0, imageSize.height);
            transform = CGAffineTransformScale(transform, 1.0, -1.0);
            break;

        case UIImageOrientation.LeftMirrored:                              //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 * CGFloat(M_PI) / 2.0);
            break;

        case UIImageOrientation.Left:                                      //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 * CGFloat(M_PI) / 2.0);
            break;

        case UIImageOrientation.RightMirrored:                             //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, CGFloat(M_PI) / 2.0);
            break;

        case UIImageOrientation.Right:                                     //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, CGFloat(M_PI) / 2.0);
            break;

        default:
            break

        }

        UIGraphicsBeginImageContext( bounds.size );

        var context = UIGraphicsGetCurrentContext();

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

        CGContextConcatCTM( context, transform );

        CGContextDrawImage( UIGraphicsGetCurrentContext(), CGRectMake( 0, 0, CGFloat(width), CGFloat(height) ), imgRef );
        let imageCopy = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();

        return( imageCopy );
    }

答案 3 :(得分:1)

我认为您可以让UIImage API自动为您处理旋转,而无需手动执行转换。

UIImage方法 size drawInRect:的文档都说他们考虑了方向,所以我将UIImage绘制到一个新的上下文并抓住结果(从那里自动旋转)图像。这是类别中的代码:

@interface UIImage (Orientation)

- (UIImage*)imageAdjustedForOrientation;

@end

@implementation UIImage (Orientation)
- (UIImage*)imageAdjustedForOrientation
{
    // The UIImage methods size and drawInRect take into account 
    //  the value of its imageOrientation property
    //  so the rendered image is rotated as necessary.
    UIGraphicsBeginImageContextWithOptions(self.size, NO, self.scale);

    [self drawInRect:CGRectMake(0, 0, self.size.width, self.size.height)];

    UIImage *orientedImage = UIGraphicsGetImageFromCurrentImageContext();

    UIGraphicsEndImageContext();

    return orientedImage;
}
@end

我刚刚发现{0}几乎相同的this better answer,但如果方向已经正确,还包括不重新重新绘制图像的优化。

答案 4 :(得分:0)

您需要根据图像的方向旋转图像。这是一个如何轻松完成的技巧:

NSData *data = UIImagePNGRepresentation(sourceImage);
UIImage *tmp = [UIImage imageWithData:data];
UIImage *fixed = [UIImage imageWithCGImage:tmp.CGImage
                                     scale:sourceImage.scale
                               orientation:sourceImage.imageOrientation];

答案 5 :(得分:0)

如果有人在这里结束并需要Swift 4解决方案:

//  UIImage+orientedUp.swift
//  ID Fusion Software Inc
//  Created by Dave Poirier on 2017-12-27
//  Unlicensed
//

import UIKit

extension UIImage {
    func orientedUp() -> UIImage {
        guard self.imageOrientation != UIImageOrientation.up,
            let cgImage = self.cgImage,
            let colorSpace = cgImage.colorSpace
            else { return self }

        guard let ctx: CGContext = CGContext(data: nil,
                                             width: Int(self.size.width), height: Int(self.size.height),
                                             bitsPerComponent: cgImage.bitsPerComponent, bytesPerRow: 0, space: colorSpace,
                                             bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue) else { return self }
        ctx.concatenate(self.orientedUpTransform())

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

        guard let orientedCGImage: CGImage = ctx.makeImage()
            else { return self }

        return UIImage(cgImage: orientedCGImage)
    }

    func orientedUpTransform() -> CGAffineTransform {
        var transform: CGAffineTransform = CGAffineTransform.identity

        switch self.imageOrientation {
        case UIImageOrientation.down, UIImageOrientation.downMirrored:
            transform = transform.translatedBy(x: self.size.width, y: self.size.height)
            transform = transform.rotated(by: CGFloat(Double.pi))
        case UIImageOrientation.left, UIImageOrientation.leftMirrored:
            transform = transform.translatedBy(x: self.size.width, y: 0)
            transform = transform.rotated(by: CGFloat(Double.pi / 2.0))
        case UIImageOrientation.right, UIImageOrientation.rightMirrored:
            transform = transform.translatedBy(x: 0, y: self.size.height)
            transform = transform.rotated(by: CGFloat(-Double.pi / 2.0))
        default:
            break
        }

        switch self.imageOrientation {
        case UIImageOrientation.upMirrored, UIImageOrientation.downMirrored:
            transform = transform.translatedBy(x: self.size.width, y: 0)
            transform = transform.scaledBy(x: -1, y: 1)
        case UIImageOrientation.leftMirrored, UIImageOrientation.rightMirrored:
            transform = transform.translatedBy(x: self.size.height, y: 0)
            transform = transform.scaledBy(x: -1, y: 1)
        default:
            break
        }

        return transform
    }
}

然后您可以像这样使用它:

let image = UIImage(data: imageData)?.orientedUp()