MFMailComposeViewController 图像方向

13

我正在开发一个通用应用程序,为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个回答

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属性并不描述UIImage中数据的物理配置(例如3264w x 2448h);它仅描述在捕获图像时的方向。该属性的作用是告诉即将显示图像的软件如何旋转它以使其正确显示。

如果您以肖像模式捕获图像,则image.imageOrientation将返回UIImageOrientationRight。这告诉显示软件需要将图像旋转90度以便正确显示。请注意,“旋转”不会影响UIImage的基础存储方式,其仍为3264w x 2448h。

如果您以横向模式捕获图像,则image.imageOrientation将返回UIImageOrientationUp。UIImageOrientationUp告诉显示软件可以按原样显示图像,无需旋转。同样,UIIMage的基础存储方式为3264w x2448h。

一旦您明确了数据的物理存储方式与方向属性用于描述捕获时的方向之间的区别,事情就开始变得更加清晰。

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

以下是添加了调试代码的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形式到达,宽度为3264,高度为2448。

如果我们继续进行E-Mail发送的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

由于这行代码查看了方向属性并适当地旋转了图像(同时不触及底层存储在3264x2448上),因此它会正确地显示。

现在流程控制进入电子邮件程序代码,gImag中仍存在方向属性,因此当MFMailComposeViewController代码在发送的电子邮件中显示图像时,它将被正确定向。物理图像仍存储为3264x2448。

邮件已发送,在接收端,方向属性的信息已丢失,因此接收软件按照物理布局显示图像,即横向3264x2448。

在调试过程中,我遇到了另一个问题。如果你不正确地复制UIImage,则可能会剥离方向属性。下面的代码展示了这个问题:

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、宽度为3264和高度为2448。

方向属性被剥离了, 默认方向是Up。 如果你不知道正在发生的剥离,它可能会使事情变得混乱。

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

在imagePickerController代码中的事情没有改变; 图像仍然像以前一样被捕获。

控制流程继续进行到E-Mailer代码,但现在方向属性已经从tmp图像中剥离掉了,因此当MFMailComposeViewController代码在外发邮件中显示tmp图像时,它显示为横向模式(因为默认方向是UIImageOrientationUp,所以3264x2448图像没有旋转)。

邮件发送成功后,在接收端,方向属性的信息也丢失了,因此接收软件将图像按照物理布局3264x2448显示,即横向。

如果想避免在复制UIImage时剥离方向属性,则可以使用以下代码来制作UIImage副本:

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

那将允许您避免在途中丢失方向属性,但仍无法解决电子邮件中图像的丢失。

有一种比这些繁琐和担心方向属性的更好的方法。

我在这里找到了一些代码,并将其集成到我的程序中。该代码将根据其方向属性实际旋转底层存储的图像。

对于具有UIImageOrientationRight方向的UIImage,它将物理旋转UIImage,使其最终为2448x3264,并剥离方向属性,因此随后以默认的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
and
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." );   

最后,这是我从这里获取的代码,如果需要物理旋转,则进行旋转:

- (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
非常全面和有用的答案,谢谢,我现在要尝试实施这个。只是提醒一下 - 你可能想把这个标记为答案。 - Greg
1
谢谢,Greg。我本来打算这样做,但后来忘了回来处理它。 - Gallymon
运行得非常完美!与我阅读和尝试的许多其他解决方案相比。谢谢! - Nate
4
@Oskariagon,我对我所提供的代码示例中的PIMG和gU表示道歉。我在我的代码中使用了许多定义来创造缩写,以使代码更加紧凑和可读(对我而言)。因此,PIMG代表UIImage*。我以为在发布之前已经清除了它们,但是我错过了这个。而gU指向一个全局可见的对象,其中包含我从代码各处调用的实用程序例程。 - Gallymon
1
这是我在这个话题上找到的最佳答案,最终帮助我理解了发生了什么。谢谢你给我的“恍然大悟”时刻。+1 - therealjohn
显示剩余4条评论

3
我曾经也遇到过iOS SDK7中的图像方向问题,我想在这个讨论中添加一些东西,希望对其他人有所帮助。使用UIImageJPEGRepresentation是可以的,但是请注意,使用UIImagePNGRepresentation可能会导致图像方向不正确。
我正在开发一个应用程序,在该应用程序中,拍摄设备相机拍摄的图片后上传。我不将图像暂时存储到磁盘上,而是直接将其发送到服务器。
在将UIImage渲染为NSData时,您可以选择UIImagePNGRepresentationUIImageJPEGRepresentation之间进行选择。
当使用UIImagePNGRepresentation时,无论是以纵向还是横向方式拍摄的图片都会导致横向图像。在这种情况下,纵向图像逆时针旋转90度。
当使用UIImageJPEGRepresentation时,无论是纵向还是横向图像都会得到正确的方向。

2

Scale部分的Swift版本:

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

1
我认为你可以使用UIImage API自动处理旋转,而不需要手动进行转换。
UIImage方法的文档中size和drawInRect:都表示它们会考虑方向,所以我将UIImage drawInRect到一个新的上下文中,并从那里获取结果(自动旋转)图像。这是类别中的代码:
@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

我刚刚找到了由an0提供的this better answer,内容与此类似,但还包括了如果方向已经正确,则不重新绘制图像的优化。


0

您需要根据图像的方向进行旋转。这里有一个简单的技巧:

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

Leo Natan,抱歉,这并没有任何区别。 我添加了您的代码,在此之前,我进行了image.imageOrientation,并获得了“右”为3。 在您的代码之后,我重复了一遍,并得到了0个'up'。因此,您的代码实现了它的目的,并传递给UIImagePNGRepresentation的gImag具有“up”方向。但是,我仍然得到了相同的结果:肖像是旋转的,而景观则正常。 - Gallymon
我已经确信,在调用setMailComposeDelegate时,image.imageOrientation状态是无关紧要的。它可以是UIOrientation = up或right,结果不会改变。肖像被旋转成了横向,而风景照片则保持原样。 - Gallymon
Leo Natan,您提供的代码并没有旋转UIImage。它只是创建了一个新副本,并将方向设置为您请求的方向。 - Gallymon
@Gallymon 请现在尝试。 - Léo Natan
Leo Natan,我确实尝试过这个方法。我看到第三行代码保留了sourceImage的方向属性。请问您能告诉我,为什么要在前两行中将sourceImage转换为NSData,然后再转换回UIImage呢?此代码不会旋转底层物理图像。请查看我的答案,了解我认为为什么需要旋转来解决这个问题。 - Gallymon
@Gallymon 可能不是必需的。 - Léo Natan

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接