MFMailComposeViewController 图像方向 [英] MFMailComposeViewController image orientation

查看:21
本文介绍了MFMailComposeViewController 图像方向的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发一个通用应用程序,我正在为 iOS6 编写代码.

I'm developing a Universal app and I'm coding for iOS6.

我使用 imagePickerController 拍摄照片,然后使用 MFMailComposeViewController 将其作为附件发送.所有这些都在起作用.

I'm using the imagePickerController to take a photo and then I am sending it as an attachment using MFMailComposeViewController. All of that is working.

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

My problem is that when I shoot a picture in portrait mode, it is displayed by the MFMailComposeViewController in landscape mode. Also, when it arrives at the destination E-Mail address, it is displayed in landscape mode.

如果我以横向模式拍摄图片,MFMailComposeViewController 以横向模式显示它,当它到达目标电子邮件地址时,它以横向模式显示.这样就可以了.

If I shoot the picture in landscape mode, it is displayed by the MFMailComposeViewController in landscape mode and when it arrives at the destination E-Mail address, it is displayed in landscape mode. So that's all OK.

我的两台测试设备都遇到了同样的问题;一部 iPhone5 一部 iPad2.

I have the same issue on both of my test devices; an iPhone5 and an iPad2.

如何让人像模式下的照片在人像模式下到达电子邮件目的地?

How can I make a picture shot in portrait mode arrive at the E-Mail destination in portrait mode?

这是我将图像添加到电子邮件的方法:

Here's how I am adding the image to the E-Mail:

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

推荐答案

我已经花了几个小时来解决这个问题,现在我很清楚发生了什么以及如何解决它.

I've spent a number of hours working on this issue and I am now clear about what's going on and how to fix it.

再说一遍,我遇到的问题是:

To repeat, the problem I ran into is:

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

When I shoot an image in portrait mode on the camera using the imagePickerController and pass that image to the MFMailComposeViewController and e-mail it, it arrives at the destination E-Mail address and is displayed there incorrectly in landscape mode.

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

However, if I shoot the picture in landscape mode and then send it, it is displayed at the E-mail's destination correctly in landscape mode

那么,怎样才能使人像模式拍摄的照片以人像模式到达电子邮件目的地?那是我最初的问题.

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

Here's the code, as I showed it in the original question, except that I am now sending the image as a JPEG rather than a PNG but this has made no difference.

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

This is how I'm capturing the image with the imagePickerController and placing it into a global called gImag:

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

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

And this is how I E-Mail it using the 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 进行拍摄,只是为了让事情变得简单.但是,此问题确实会影响其他设备和分辨率.

When I describe how to solve this, I’m going to focus on working with an iPhone 5 and using its main camera which shoots at 3264x2448 just to keep things simple. This problem does, however, affect other devices and resolutions.

解开这个问题的关键是认识到,当你拍摄图像时,无论是风景还是人像,iPhone 总是以相同的方式存储 UIImage:3264 宽和 2448 高.

The key to unlocking this problem is to realize that when you shoot an image, in either portrait of landscape, the iPhone always stores the UIImage the same way: as 3264 wide and 2448 high.

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

A UIImage has a property which describes its orientation at the time the image was captured and you can get it like this:

UIImageOrientation orient = image.imageOrientation;

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

Note that the orientation property does not describe how the data in the UIImage is physically configured (as as 3264w x 2448h); it only describes its orientation at the time the image was captured.

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

The property’s use is to tell software, which is about to display the image, how to rotate it so it will appear correctly.

如果您以纵向模式拍摄图像,image.imageOrientation 将返回 UIImageOrientationRight.这告诉显示软件它需要将图像旋转 90 度才能正确显示.请注意,这种旋转"不会影响 UIImage 的底层存储,它仍然为 3264w x 2448h.

If you capture an image in portrait mode, image.imageOrientation will return UIImageOrientationRight. This tells displaying software that it needs to rotate the image 90 degrees so it will display correctly. Be clear that this ‘rotation’ does not effect the underlying storage of the UIImage which remains as 3264w x 2448h.

如果您在横向模式下拍摄图像,image.imageOrientation 将返回 UIImageOrientationUp.UIImageOrientationUp 告诉显示软件图像可以按原样显示;不需要旋转.同样,UIIMage 的底层存储是 3264w x 2448h.

If you capture an image in landscape mode, image.imageOrientation will return UIImageOrientationUp. UIImageOrientationUp tells displaying software that the image is fine to display as it is; no rotation is necessary. Again, the underlying storage of the UIIMage is 3264w x 2448h.

一旦您清楚数据的物理存储方式与方向属性在捕获时如何用于描述其方向之间的区别,事情就会开始变得更加清晰.

Once you are clear about the difference between how the data is physically stored vs. how the orientation property is used to describe its orientation at the time it was captured, things begin to get clearer.

我创建了几行调试代码来查看"所有这些.

I created a few lines of debugging code to ‘see’ all of this.

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

Here’s the imagePickerController code again with the debugging code added:

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 和 width = 3264 and height = 2448 到达.

If we shoot portrait, gImage arrives with UIImageOrientationRight and width = 3264 and height = 2448.

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

If we shoot landscape, gImage arrives with UIImageOrientationUp and width = 3264 and height = 2448.

如果我们继续阅读 E-Mailng MFMailComposeViewController 代码,我也在其中添加了调试代码:

If we continue on to the E-Mailng MFMailComposeViewController code, I’ve added the debugging code in there as well:

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 代码中所做的完全相同.

Nothing amazing to see here. We get exactly the same values as we did back in the imagePickerController code.

让我们看看问题的具体表现:

首先,相机拍摄人像照片,并在人像模式下按行正确显示:

To begin, the camera takes a portrait shot and it is displayed correctly in portrait mode by the line:

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

它显示正确,因为这行代码看到了方向属性并适当地旋转了图像(同时不接触 3264x2448 的底层存储).

It is display correctly because this line of code sees the orientation property and rotates the image appropriately (while NOT touching the underlying storage at 3264x2448).

控制流现在转到电子邮件程序代码,方向属性仍然存在于 gImag 中,因此当 MFMailComposeViewController 代码在外发电子邮件中显示图像时,它的方向是正确的.物理图像仍然存储为 3264x2448.

Flow-of-control goes to the E-Mailer code now and the orientation property is still present in gImag so when the MFMailComposeViewController code displays the image in the outgoing E-Mail, it is correctly oriented. The physical image is still stored as 3264x2448.

电子邮件被发送,在接收端,方向属性的知识已经丢失,因此接收软件将图像显示为物理布局为 3264x2448,即横向.

The E-Mail is sent and, on the receiving end, knowledge of the orientation property has been lost so the receiving software displays the image as it is physically laid out as 3264x2448, i.e. landscape.

在调试这个时,我遇到了额外的困惑.也就是说,如果您错误地复制了 UIImage,则可以从 UIImage 中删除该方向属性.

In debugging this, I ran into an additional confusion. And that is that the orientation property can be stripped from the UIImage, if you make a copy of it incorrectly.

这段代码说明了问题:

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.

When we look at the debugging data for the new UIImage tmp, we get UIImageOrientationUp and width = 3264 and height = 2448.

方向属性被剥离,默认方向是向上.如果你不知道剥离正在进行,它真的会混淆事情.

The orientation property was stripped and the default orientation is Up. If you do not know the stripping is going on, it can really confuse things.

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

If I run this code, I now get the following results:

imagePickerController 代码中的东西没有改变;图像像以前一样捕获.

Things are unchanged in the imagePickerController code; the image is captured as before.

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

Flow-of-control goes on to the E-Mailer code but now the orientation property has been stripped from the tmp image so when the MFMailComposeViewController code displays the tmp image in the outgoing E-Mail, it is shown in landscape mode (because the default orientation is UIImageOrientationUp so there is no rotation done of the 3264x2448 image).

电子邮件已发送,但在接收端,方向属性的知识也缺失,因此接收软件将图像显示为物理布局为 3264x2448,即横向.

The E-Mail is sent and on the receiving end, knowledge of the orientation property is missing as well so the receiving software displays the image as it is physically laid out as 3264x2448, i.e. landscape.

在制作 UIImage 副本时可以避免这种剥离"方向属性,如果知道它正在发生,可以使用以下代码制作 UIImage 副本:

This ‘stripping’ of the orientation property when making copies of the UIImage can be avoided, if one is aware it is going on, by using the following code to make the UIImage copy:

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

这将使您能够避免沿途丢失方向属性,但当您通过电子邮件发送图像时,它仍然不会处理远端的丢失.

That would allow you to avoid losing the orientation property along the way but it would still not deal with its loss on the far end when you e-mail the image.

有一个更好的方法,而不是纠结和担心方向属性.

我在这里找到了一些代码已经集成到我的程序中.此代码将根据其方向属性物理旋转底层存储的图像.

I found some code here that that I’ve integrated into my program. This code will physically rotate the underlying stored image according to its orientation property.

对于方向为 UIImageOrientationRight 的 UIImage,它会物理旋转 UIImage,使其最终为 2448x3264,并且它将剥离方向属性,以便此后将其视为默认的 UIImageOrientationUp.

For a UIImage with an orientation of UIImageOrientationRight, it will physically rotate the UIImage so it ends up as 2448x3264 and it will strip away the orientation property so it is seen thereafter as the default UIImageOrientationUp.

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

For an UIImage with an orientation of UIImageOrientationUp, it does nothing. It lets the sleeping landscape dogs lie.

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

If you do this then I think (based on what I’ve seen so far), that the orientation property of the UIImage is superfluous thereafter. So long as it remains missing/stripped or set to UIImageOrientationUp, your images should be displayed correctly at each step along the way and on the distant end when the images embedded in your E-Mail is displayed.

我在答案中讨论的所有内容,我都亲自一步一步地看着它发生.

Everything I’ve discussed in the answer, I have personally single-stepped and watched it happen.

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

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." );   

最后,这是我从这里中抓取的代码,它执行物理旋转,如有必要:

And, finally, here's the code I grabbed from here that does the physical rotation, if necessary:

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

干杯,来自新西兰.

这篇关于MFMailComposeViewController 图像方向的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆