Ориентация изображения MFMailComposeViewController

Я разрабатываю универсальное приложение, и я кодирую iOS6.

Я использую imagePickerController, чтобы сделать снимок, а затем отправлю его в виде вложения с помощью MFMailComposeViewController. Все это работает.

Моя проблема в том, что когда я снимаю изображение в портретном режиме, он отображается в MFMailComposeViewController в ландшафтном режиме. Кроме того, когда он достигнет адреса электронной почты адресата, он отображается в ландшафтном режиме.

Если я снимаю изображение в ландшафтном режиме, он отображается в MFMailComposeViewController в ландшафтном режиме, и когда он достигнет адреса электронной почты адресата, он отображается в альбомном режиме. Так что все ОК.

У меня такая же проблема на обоих моих тестовых устройствах; iPhone5 и iPad2.

Как сделать снимок в портретном режиме для адресата электронной почты в портретном режиме?

Вот как я добавляю изображение к 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." );
   }

Ответ 1

Я потратил несколько часов на работу над этой проблемой, и теперь я понимаю, что происходит и как это исправить.

Повторяю, проблема, с которой я столкнулся, это:

Когда я снимаю изображение в портретном режиме на камере с помощью 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

И вот как я E-Mail с помощью 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 высоко.

A UIImage обладает свойством, которое описывает его ориентацию во время захвата изображения, и вы можете получить его так:

UIImageOrientation orient = image.imageOrientation;

Обратите внимание, что свойство ориентации не описывает, как физически настроены данные в 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 и height = 2448.

Если мы снимаем пейзаж, gImage поступает с UIImageOrientationUp и width = 3264 и height = 2448.

Если мы перейдем к коду E-Mailng MFMailComposeViewController, Ive также добавил туда код отладки:

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

Теперь поток управления переходит к коду E-Mailer, и свойство ориентации все еще присутствует в 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." );

Когда мы смотрим на данные отладки для нового UMLmage tmp, получаем UIImageOrientationUp и width = 3264 и height = 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];

Это позволит вам избежать потери свойства ориентации на этом пути, но по-прежнему не будет иметь дело с его потерей в дальнем конце при отправке по электронной почте изображения.

Theres лучший способ, чем все это возиться и беспокоиться о свойстве ориентации.

Я нашел код здесь, что Ive интегрирован в мою программу. Этот код будет физически вращать базовое сохраненное изображение в соответствии со свойством ориентации.

Для UIImage с ориентацией UIImageOrientationRight он будет физически вращать UIImage, чтобы он заканчивался как 2448x3264, и он отделяет свойство ориентации, поэтому он рассматривается как UIImageOrientationUp по умолчанию.

Для UIImage с ориентацией UIImageOrientationUp он ничего не делает. Это позволяет лгать собакам спящего ландшафта.

Если вы сделаете это, я думаю (на основе того, что я видел до сих пор), что свойство ориентации UIImage является излишним после этого. До тех пор, пока он остается отсутствующим или разделенным или установленным на UIImageOrientationUp, ваши изображения должны отображаться правильно на каждом шаге на этом пути и на дальнем конце, когда отображаются изображения, встроенные в ваш E-Mail.

Все, что я обсуждал в ответе, я лично одношаговый и смотрел, как это происходит.

Итак, вот мой последний код, который работает:

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

И, наконец, вот код, который я захватил из здесь, который при необходимости выполняет физическое вращение:

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

Приветствия, из Новой Зеландии.

Ответ 2

Я боролся с ориентациями изображений в iOS SDK7, и я хочу добавить что-то к этому обсуждению в надежде, что он будет полезен другим. UIImageJPEGRepresentation работает отлично, но имейте в виду, что использование UIImagePNGRepresentation может привести к неправильной ориентации изображения.

Я разрабатываю приложение, в котором изображение загружается после съемки с камеры устройства. Я не сохраняю изображение временно на диск, а скорее отправляю его непосредственно на сервер.

При рендеринге UIImage в NSData вы можете выбрать между UIImagePNGRepresentation и UIImageJPEGRepresentation.

При использовании UIImagePNGRepresentation изображение, снятое в портретной и альбомной ориентации, приводит к пейзажному изображению. В этом случае портретное изображение поворачивается на 90 градусов против часовой стрелки.

При использовании UIImageJPEGRepresentation изображение как в портретном, так и в альбомном режиме будет выглядеть с правильной ориентацией.

Ответ 3

быстрая версия части шкалы:

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

Ответ 4

Я думаю, вы можете получить API UIImage для автоматической обработки вращения, без необходимости вручную выполнять преобразования.

Документация для размера методов UIImage и drawInRect: оба говорят, что они учитывают ориентацию, поэтому я рисую InRect 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

Я только что нашел этот лучший ответ на an0, который практически такой же, но также включает в себя оптимизацию не повторного перерисовки изображения, если ориентация уже правильная.

Ответ 5

Вам нужно повернуть изображение в соответствии с его ориентацией. Вот трюк, как сделать это легко:

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

Ответ 6

В случае, если кто-то окажется здесь и требует решения 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()