2012-05-15 5 views
79

В течение последних нескольких недель я работал с изображениями в объективе-c и замечал много странного поведения. Во-первых, как и многие другие люди, у меня возникла такая проблема, когда изображения, снятые камерой (или снятые с камерой другого человека и MMS), повернуты на 90 градусов. Я не был уверен, почему в мире это происходило (следовательно, my question), но я смог придумать дешевую работу.iOS Ориентация изображения имеет странное поведение

Мой вопрос на этот раз Почему это происходит? Почему Apple поворачивает изображения? Когда я снимаю фотографию с правой стороны камеры, если я не выполнил свой код, упомянутый выше, когда я сохраняю фотографию, она будет сохранена, повернута. Теперь, мой обходной путь был в порядке до нескольких дней назад.

Мое приложение изменяет отдельные пиксели изображения, в частности, альфа-канал PNG (поэтому любое преобразование JPEG выбрасывается из окна для моего сценария). Несколько дней назад я заметил, что хотя изображение отображается правильно в моем приложении благодаря моему обходному коду, когда мой алгоритм изменяет отдельные пиксели изображения, он думает, что изображение повернуто. Поэтому вместо того, чтобы изменять пиксели в верхней части изображения, он изменяет пиксели на стороне изображения (потому что он думает, что он должен быть повернут)! Я не могу понять, как повернуть изображение в памяти - в идеале я бы предпочел просто стереть этот флаг imageOrientation.

Вот что-то еще, что меня озадачило ... Когда я снимаю фото, imageOrientation настроен на 3. Мой код обходного пути достаточно умен, чтобы понять это и перевернуть его, чтобы пользователь никогда не замечал. Кроме того, мой код для сохранения изображения в библиотеке реализует это, переворачивает его, , затем сохраняет его, чтобы он отображался в кадре камеры должным образом.

Этот код выглядит так:

NSData* pngdata = UIImagePNGRepresentation (self.workingImage); //PNG wrap 
UIImage* img = [self rotateImageAppropriately:[UIImage imageWithData:pngdata]]; 
UIImageWriteToSavedPhotosAlbum(img, nil, nil, nil); 

Когда я загружаю эту сохраненную картинку в мое приложение, то imageOrientation 0 - именно то, что я хочу видеть, и мое вращение обходного пути даже не нужен (обратите внимание: при загрузке изображений из Интернета, в отличие от изображений, сделанных с помощью камеры, imageOrientation всегда 0, что приводит к идеальному поведению). По какой-то причине мой код сохранения, похоже, уничтожит этот флаг imageOrientation. Я надеялся просто украсть этот код и использовать его, чтобы уничтожить мой образОриентации, как только пользователь сделает снимок и добавит его в приложение, но он, похоже, не работает. Делает ли UIImageWriteToSavedPhotosAlbum что-то особенное с imageOrientation?

Лучшее решение этой проблемы - просто сдуть imageOrientation, как только пользователь будет сделан с изображением. Я предполагаю, что у Apple есть поворот, сделанный по какой-то причине, не так ли? Несколько человек предположили, что это дефект Apple.

(... если вы еще не потеряли ... Примечание 2: Когда я принять горизонтальное фото, кажется, что все работает отлично, так же, как фотографии, сделанные из Интернета)

EDIT:

Вот некоторые из изображений и сценариев на самом деле. Исходя из комментариев до сих пор, похоже, что это странное поведение - это не просто поведение iPhone, которое, я думаю, хорошо.

Это изображение фотографии я взял с моего телефона (обратите внимание на правильную ориентацию), он появляется именно так, как это было на моем телефоне, когда я щелкнул фото:

Actual Photo taken on iPhone

Вот что изображение выглядит как в Gmail после того, как я по электронной почте его к себе (выглядит как Gmail обрабатывает его правильно):

Photo as it appears in Gmail

Вот что изображение выглядит как эскиз в окнах (не выглядит л икэ он обрабатывается должным образом):

Windows Thumbnail

А вот что фактическое изображение выглядит при открытии в Windows Photo Viewer (до сих пор не обрабатываются должным образом):

Windows Photo Viewer Version

После всех комментарии по этому вопросу, вот что я думаю ... iPhone берет образ и говорит: «Чтобы отобразить это правильно, его нужно поворачивать на 90 градусов». Эта информация будет в данных EXIF. (Почему его нужно поворачивать на 90 градусов, а не по умолчанию вертикально, я не знаю). Отсюда Gmail достаточно умен, чтобы читать и анализировать данные EXIF ​​и правильно отображать их. Однако Windows недостаточно умна, чтобы читать данные EXIF, и поэтому отображает изображение неправильно. Правильны ли мои предположения?

+0

Интересно ... если это правда, почему образы взяты быть установлен под прямым углом? Я знаю, что это не iPhone-дефект, потому что я заметил подобное поведение, когда друг (с BlackBerry) принимает изображение, а MMS - мне. – Boeckm

+0

Смотрите, как ваша камера записывает метаданные, чтобы повернуть ее на 90 градусов, некоторые операционные системы прочитали, что метаданные и остальные нет. – HarshIT

+0

Довольно хорошо читайте (см. Ниже ответ Хэдли - раньше был в комментарии).Поэтому мое приложение явно должно быть достаточно умным, чтобы обрабатывать изображения, содержащие данные EXIF, а также изображения, которые его не содержат ... Я все еще не понимаю, почему, когда я делаю снимок с правой стороны, флаг ориентации говорит, что он должен вращаться на 90 градусов? – Boeckm

ответ

41

Я сделал R & D на нем и обнаружил, что каждый файл изображения имеет свойство метаданных. Если метаданные определяют ориентацию изображения, которое обычно игнорируется другими ОС, но Mac. Большинство принятых изображений имеют свойство метаданных, заданное в прямом направлении. Итак, Mac показывает вращение на 90 градусов. Вы можете увидеть то же изображение в Windows.

Более подробно этот ответ http://graphicssoft.about.com/od/digitalphotography/f/sideways-pictures.htm

попробовать чтение Exif вашего изображения в здесь http://www.exifviewer.org/ или http://regex.info/exif.cgi или http://www.addictivetips.com/internet-tips/view-complete-exif-metadata-information-of-any-jpeg-image-online/

+0

WOW! Я не знал, что в данных EXIF ​​есть ТОЧНАЯ информация! http://regex.info/exif.cgi - невероятный сайт! Сегодня я буду играть с изображениями на этом сайте. Мне нужно будет протестировать каждый сценарий, изображения начнутся, изображения, взятые из Интернета, изображения повернуты и т. Д. Спасибо! – Boeckm

53

У меня была такая же проблема, когда я получаю изображение с камеры, я поставил следующий код чтобы исправить это .. Добавлена ​​scaleAndRotateImage метод from here

- (void) imagePickerController:(UIImagePickerController *)thePicker didFinishPickingMediaWithInfo:(NSDictionary *)imageInfo { 
      // Images from the camera are always in landscape, so rotate 
        UIImage *image = [self scaleAndRotateImage: [imageInfo objectForKey:UIImagePickerControllerOriginalImage]]; 
    //then save the image to photo gallery or wherever 
     } 


- (UIImage *)scaleAndRotateImage:(UIImage *) image { 
    int kMaxResolution = 320; 

    CGImageRef imgRef = image.CGImage; 

    CGFloat width = CGImageGetWidth(imgRef); 
    CGFloat height = CGImageGetHeight(imgRef); 


    CGAffineTransform transform = CGAffineTransformIdentity; 
    CGRect bounds = CGRectMake(0, 0, width, height); 
    if (width > kMaxResolution || height > kMaxResolution) { 
     CGFloat ratio = width/height; 
     if (ratio > 1) { 
      bounds.size.width = kMaxResolution; 
      bounds.size.height = bounds.size.width/ratio; 
     } 
     else { 
      bounds.size.height = kMaxResolution; 
      bounds.size.width = bounds.size.height * ratio; 
     } 
    } 

    CGFloat scaleRatio = bounds.size.width/width; 
    CGSize imageSize = CGSizeMake(CGImageGetWidth(imgRef), CGImageGetHeight(imgRef)); 
    CGFloat boundHeight; 
    UIImageOrientation orient = image.imageOrientation; 
    switch(orient) { 

     case UIImageOrientationUp: //EXIF = 1 
      transform = CGAffineTransformIdentity; 
      break; 

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

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

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

     case UIImageOrientationLeftMirrored: //EXIF = 5 
      boundHeight = bounds.size.height; 
      bounds.size.height = bounds.size.width; 
      bounds.size.width = boundHeight; 
      transform = CGAffineTransformMakeTranslation(imageSize.height, imageSize.width); 
      transform = CGAffineTransformScale(transform, -1.0, 1.0); 
      transform = CGAffineTransformRotate(transform, 3.0 * M_PI/2.0); 
      break; 

     case UIImageOrientationLeft: //EXIF = 6 
      boundHeight = bounds.size.height; 
      bounds.size.height = bounds.size.width; 
      bounds.size.width = boundHeight; 
      transform = CGAffineTransformMakeTranslation(0.0, imageSize.width); 
      transform = CGAffineTransformRotate(transform, 3.0 * M_PI/2.0); 
      break; 

     case UIImageOrientationRightMirrored: //EXIF = 7 
      boundHeight = bounds.size.height; 
      bounds.size.height = bounds.size.width; 
      bounds.size.width = boundHeight; 
      transform = CGAffineTransformMakeScale(-1.0, 1.0); 
      transform = CGAffineTransformRotate(transform, M_PI/2.0); 
      break; 

     case UIImageOrientationRight: //EXIF = 8 
      boundHeight = bounds.size.height; 
      bounds.size.height = bounds.size.width; 
      bounds.size.width = boundHeight; 
      transform = CGAffineTransformMakeTranslation(imageSize.height, 0.0); 
      transform = CGAffineTransformRotate(transform, M_PI/2.0); 
      break; 

     default: 
      [NSException raise:NSInternalInconsistencyException format:@"Invalid image orientation"]; 

    } 

    UIGraphicsBeginImageContext(bounds.size); 

    CGContextRef context = UIGraphicsGetCurrentContext(); 

    if (orient == UIImageOrientationRight || orient == UIImageOrientationLeft) { 
     CGContextScaleCTM(context, -scaleRatio, scaleRatio); 
     CGContextTranslateCTM(context, -height, 0); 
    } 
    else { 
     CGContextScaleCTM(context, scaleRatio, -scaleRatio); 
     CGContextTranslateCTM(context, 0, -height); 
    } 

    CGContextConcatCTM(context, transform); 

    CGContextDrawImage(UIGraphicsGetCurrentContext(), CGRectMake(0, 0, width, height), imgRef); 
    UIImage *imageCopy = UIGraphicsGetImageFromCurrentImageContext(); 
    UIGraphicsEndImageContext(); 

    return imageCopy; 
} 
+3

Как выглядит ваш масштабный код AndRotateImage? После того, как вы делаете google, это то же самое, что и здесь? https://discussions.apple.com/thread/1537011?start=0&tstart=0 – Boeckm

+2

WOW ... Ха-ха! Это работало очень хорошо! Я использовал код в своем комментарии выше. У меня есть два замечательных ответа на мой вопрос! Я думаю, это означает, что я задал слишком большой вопрос ... Спасибо тонну. У меня будет некоторое углубленное тестирование, но до сих пор проблема ориентации отлично работает с вертикально и горизонтально взятыми фотографиями. – Boeckm

+0

Это отличная ссылка Boeckm..It дает больше информации о ориентации изображения. –

10

Любое изображение, формируемое iPhone/IPad сохраняется в ландшафтном слева с EXIF ​​Orientat (Exif.Image.Orientation) с указанием фактической ориентации.

Он имеет следующие значения: 1: Пейзаж левый 6: Портрет Нормальный 3: Пейзаж Правый 4: Портрет Upside Down

В IOS, информация EXIF ​​правильно читать и изображения отображаются в так же, как это было принято. Но в Windows информация EXIF ​​НЕ используется.

Если вы откроете одно из этих изображений в GIMP, оно скажет, что изображение имеет информацию о ротации.

0

Я точно знаю, в чем проблема. Вы используете UIImagePicker, что странно во всех смыслах.Я предлагаю вам использовать AVFoundation для камеры, которая обеспечивает гибкость в ориентации, а также качество. Используйте AVCaptureSession. Вы можете получить здесь код How to save photos taken using AVFoundation to Photo Album?

2

Я столкнулся с этим вопросом, потому что у меня была аналогичная проблема, но с использованием Swift. Просто хотел сделать ссылку на ответ, который работал для меня для любых других Swift разработчиков: https://stackoverflow.com/a/26676578/3904581

Вот Swift сниппет, который исправляет эту проблему эффективно:

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

Супер простой. Одна строка кода. Задача решена.

+0

не мог получить это работать. – BananaAcid

+0

не получилось – mehmetsen80

+0

Это работает для меня !! благодаря! –

17

Краткая копия/вставка Swift translation of Dilip's excellent answer.

import Darwin 

class func rotateCameraImageToProperOrientation(imageSource : UIImage, maxResolution : CGFloat) -> UIImage { 

    let imgRef = imageSource.CGImage; 

    let width = CGFloat(CGImageGetWidth(imgRef)); 
    let height = CGFloat(CGImageGetHeight(imgRef)); 

    var bounds = CGRectMake(0, 0, width, height) 

    var scaleRatio : CGFloat = 1 
    if (width > maxResolution || height > maxResolution) { 

     scaleRatio = min(maxResolution/bounds.size.width, maxResolution/bounds.size.height) 
     bounds.size.height = bounds.size.height * scaleRatio 
     bounds.size.width = bounds.size.width * scaleRatio 
    } 

    var transform = CGAffineTransformIdentity 
    let orient = imageSource.imageOrientation 
    let imageSize = CGSizeMake(CGFloat(CGImageGetWidth(imgRef)), CGFloat(CGImageGetHeight(imgRef))) 


    switch(imageSource.imageOrientation) { 
    case .Up : 
     transform = CGAffineTransformIdentity 

    case .UpMirrored : 
     transform = CGAffineTransformMakeTranslation(imageSize.width, 0.0); 
     transform = CGAffineTransformScale(transform, -1.0, 1.0); 

    case .Down : 
     transform = CGAffineTransformMakeTranslation(imageSize.width, imageSize.height); 
     transform = CGAffineTransformRotate(transform, CGFloat(M_PI)); 

    case .DownMirrored : 
     transform = CGAffineTransformMakeTranslation(0.0, imageSize.height); 
     transform = CGAffineTransformScale(transform, 1.0, -1.0); 

    case .Left : 
     let storedHeight = bounds.size.height 
     bounds.size.height = bounds.size.width; 
     bounds.size.width = storedHeight; 
     transform = CGAffineTransformMakeTranslation(0.0, imageSize.width); 
     transform = CGAffineTransformRotate(transform, 3.0 * CGFloat(M_PI)/2.0); 

    case .LeftMirrored : 
     let storedHeight = bounds.size.height 
     bounds.size.height = bounds.size.width; 
     bounds.size.width = storedHeight; 
     transform = CGAffineTransformMakeTranslation(imageSize.height, imageSize.width); 
     transform = CGAffineTransformScale(transform, -1.0, 1.0); 
     transform = CGAffineTransformRotate(transform, 3.0 * CGFloat(M_PI)/2.0); 

    case .Right : 
     let storedHeight = bounds.size.height 
     bounds.size.height = bounds.size.width; 
     bounds.size.width = storedHeight; 
     transform = CGAffineTransformMakeTranslation(imageSize.height, 0.0); 
     transform = CGAffineTransformRotate(transform, CGFloat(M_PI)/2.0); 

    case .RightMirrored : 
     let storedHeight = bounds.size.height 
     bounds.size.height = bounds.size.width; 
     bounds.size.width = storedHeight; 
     transform = CGAffineTransformMakeScale(-1.0, 1.0); 
     transform = CGAffineTransformRotate(transform, CGFloat(M_PI)/2.0); 

    default :() 
    } 

    UIGraphicsBeginImageContext(bounds.size) 
    let context = UIGraphicsGetCurrentContext() 

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

    CGContextConcatCTM(context, transform); 
    CGContextDrawImage(UIGraphicsGetCurrentContext(), CGRectMake(0, 0, width, height), imgRef); 

    let imageCopy = UIGraphicsGetImageFromCurrentImageContext(); 
    UIGraphicsEndImageContext(); 

    return imageCopy; 
} 
+1

Большое спасибо –

+1

Спасибо, но что такое «let ratio = width/height;» используя для? Я не вижу никакого места, использующего соотношение в этом {} –

+0

Отлично! Это работает отлично. – sabiland

9

Мой вопрос этот раз почему это происходит? Почему Apple поворачивает изображения?

Ответ на этот вопрос очень прост. Apple не поворачивает изображение. Вот где смущение.

ПЗС-камера не вращается, поэтому она всегда фотографирует в ландшафтном режиме.

Apple сделала очень умную вещь - вместо того, чтобы тратить все время на поворот изображения - перетасовка мегабайт данных вокруг - просто пометьте его КАК, как было сделано изображение.

OpenGL делает переводы очень легко - поэтому DATA никогда не перетасовывается - просто КАК ЕГО ДРАЙН.

Следовательно, метаданные ориентации.

Это становится проблемой, если вы хотите обрезать, изменять размер и т. Д. - но как только вы знаете, что происходит, вы просто определяете свою матрицу, и все работает.

+0

Благодарим вас за это объяснение. Здравый смысл, когда вы думаете об этом, но ни один другой результат в Google не объяснил это. – Dakine83

-1

Попробуйте изменить формат изображения на .jpeg. Это сработало для меня

7

Для кого-либо другого, использующего Xamarin, вот C# перевод Dilip's great answer и спасибо thattyson для Swift translation.

public static UIImage RotateCameraImageToProperOrientation(UIImage imageSource, nfloat maxResolution) { 

    var imgRef = imageSource.CGImage; 

    var width = (nfloat)imgRef.Width; 
    var height = (nfloat)imgRef.Height; 

    var bounds = new CGRect(0, 0, width, height); 

    nfloat scaleRatio = 1; 

    if (width > maxResolution || height > maxResolution) 
    { 
     scaleRatio = (nfloat)Math.Min(maxResolution/bounds.Width, maxResolution/bounds.Height); 
     bounds.Height = bounds.Height * scaleRatio; 
     bounds.Width = bounds.Width * scaleRatio; 
    } 

    var transform = CGAffineTransform.MakeIdentity(); 
    var orient = imageSource.Orientation; 
    var imageSize = new CGSize(imgRef.Width, imgRef.Height); 
    nfloat storedHeight; 

    switch(imageSource.Orientation) { 
     case UIImageOrientation.Up: 
      transform = CGAffineTransform.MakeIdentity(); 
      break; 

     case UIImageOrientation.UpMirrored : 
      transform = CGAffineTransform.MakeTranslation(imageSize.Width, 0.0f); 
      transform = CGAffineTransform.Scale(transform, -1.0f, 1.0f); 
      break; 

     case UIImageOrientation.Down : 
      transform = CGAffineTransform.MakeTranslation(imageSize.Width, imageSize.Height); 
      transform = CGAffineTransform.Rotate(transform, (nfloat)Math.PI); 
      break; 

     case UIImageOrientation.DownMirrored : 
      transform = CGAffineTransform.MakeTranslation(0.0f, imageSize.Height); 
      transform = CGAffineTransform.Scale(transform, 1.0f, -1.0f); 
      break; 

     case UIImageOrientation.Left: 
      storedHeight = bounds.Height; 
      bounds.Height = bounds.Width; 
      bounds.Width = storedHeight; 
      transform = CGAffineTransform.MakeTranslation(0.0f, imageSize.Width); 
      transform = CGAffineTransform.Rotate(transform, 3.0f * (nfloat)Math.PI/2.0f); 
      break; 

     case UIImageOrientation.LeftMirrored : 
      storedHeight = bounds.Height; 
      bounds.Height = bounds.Width; 
      bounds.Width = storedHeight; 
      transform = CGAffineTransform.MakeTranslation(imageSize.Height, imageSize.Width); 
      transform = CGAffineTransform.Scale(transform, -1.0f, 1.0f); 
      transform = CGAffineTransform.Rotate(transform, 3.0f * (nfloat)Math.PI/2.0f); 
      break; 

     case UIImageOrientation.Right : 
      storedHeight = bounds.Height; 
      bounds.Height = bounds.Width; 
      bounds.Width = storedHeight; 
      transform = CGAffineTransform.MakeTranslation(imageSize.Height, 0.0f); 
      transform = CGAffineTransform.Rotate(transform, (nfloat)Math.PI/2.0f); 
      break; 

     case UIImageOrientation.RightMirrored : 
      storedHeight = bounds.Height; 
      bounds.Height = bounds.Width; 
      bounds.Width = storedHeight; 
      transform = CGAffineTransform.MakeScale(-1.0f, 1.0f); 
      transform = CGAffineTransform.Rotate(transform, (nfloat)Math.PI/2.0f); 
      break; 

     default : 
      break; 
    } 

    UIGraphics.BeginImageContext(bounds.Size); 
    var context = UIGraphics.GetCurrentContext(); 

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

    context.ConcatCTM(transform); 
    context.DrawImage(new CGRect(0, 0, width, height), imgRef); 

    var imageCopy = UIGraphics.GetImageFromCurrentImageContext(); 
    UIGraphics.EndImageContext(); 

    return imageCopy; 
} 
+0

Это помогло решить мою проблему, проведя много часов с этим! Невероятно, что Xamarin не имеет встроенной поддержки для этого, поскольку теперь это продукт Microsoft. –

0

Быстро переработан для Swift 3 (может кто-то проверить его и подтвердить все работает нормально?):

static func rotateCameraImageToProperOrientation(imageSource : UIImage, maxResolution : CGFloat) -> UIImage { 
    let imgRef = imageSource.cgImage 

    let width = CGFloat(imgRef!.width) 
    let height = CGFloat(imgRef!.height) 

    var bounds = CGRect(x: 0, y: 0, width: width, height: height) 

    var scaleRatio : CGFloat = 1 
    if width > maxResolution || height > maxResolution { 

     scaleRatio = min(maxResolution/bounds.size.width, maxResolution/bounds.size.height) 
     bounds.size.height = bounds.size.height * scaleRatio 
     bounds.size.width = bounds.size.width * scaleRatio 
    } 

    var transform = CGAffineTransform.identity 
    let orient = imageSource.imageOrientation 
    let imageSize = CGSize(width: imgRef!.width, height: imgRef!.height) 

    switch imageSource.imageOrientation { 
    case .up : 
     transform = CGAffineTransform.identity 

    case .upMirrored : 
     transform = CGAffineTransform(translationX: imageSize.width, y: 0) 
     transform = transform.scaledBy(x: -1, y: 1) 

    case .down : 
     transform = CGAffineTransform(translationX: imageSize.width, y: imageSize.height) 
     transform = transform.rotated(by: CGFloat.pi) 

    case .downMirrored : 
     transform = CGAffineTransform(translationX: 0, y: imageSize.height) 
     transform = transform.scaledBy(x: 1, y: -1) 

    case .left : 
     let storedHeight = bounds.size.height 
     bounds.size.height = bounds.size.width 
     bounds.size.width = storedHeight 
     transform = CGAffineTransform(translationX: 0, y: imageSize.width) 
     transform = transform.rotated(by: 3.0 * CGFloat.pi/2.0) 

    case .leftMirrored : 
     let storedHeight = bounds.size.height 
     bounds.size.height = bounds.size.width 
     bounds.size.width = storedHeight 
     transform = CGAffineTransform(translationX: imageSize.height, y: imageSize.width) 
     transform = transform.scaledBy(x: -1, y: 1) 
     transform = transform.rotated(by: 3.0 * CGFloat.pi/2.0) 

    case .right : 
     let storedHeight = bounds.size.height 
     bounds.size.height = bounds.size.width 
     bounds.size.width = storedHeight 
     transform = CGAffineTransform(translationX: imageSize.height, y: 0) 
     transform = transform.rotated(by: CGFloat.pi/2.0) 

    case .rightMirrored : 
     let storedHeight = bounds.size.height 
     bounds.size.height = bounds.size.width 
     bounds.size.width = storedHeight 
     transform = CGAffineTransform(scaleX: -1, y: 1) 
     transform = transform.rotated(by: CGFloat.pi/2.0) 

    } 

    UIGraphicsBeginImageContext(bounds.size) 
    let context = UIGraphicsGetCurrentContext() 

    if orient == .right || orient == .left { 

     context!.scaleBy(x: -scaleRatio, y: scaleRatio) 
     context!.translateBy(x: -height, y: 0) 
    } else { 
     context!.scaleBy(x: scaleRatio, y: -scaleRatio) 
     context!.translateBy(x: 0, y: -height) 
    } 

    context!.concatenate(transform) 
    context!.draw(imgRef!, in: CGRect(x: 0, y: 0, width: width, height: height)) 

    let imageCopy = UIGraphicsGetImageFromCurrentImageContext() 
    UIGraphicsEndImageContext() 

    return imageCopy! 
} 
11

Swift 3 версия с проверками безопасности Dilip's answer.

public static func rotateCameraImageToProperOrientation(imageSource : UIImage, maxResolution : CGFloat = 320) -> UIImage? { 

    guard let imgRef = imageSource.cgImage else { 
     return nil 
    } 

    let width = CGFloat(imgRef.width) 
    let height = CGFloat(imgRef.height) 

    var bounds = CGRect(x: 0, y: 0, width: width, height: height) 

    var scaleRatio : CGFloat = 1 
    if (width > maxResolution || height > maxResolution) { 

     scaleRatio = min(maxResolution/bounds.size.width, maxResolution/bounds.size.height) 
     bounds.size.height = bounds.size.height * scaleRatio 
     bounds.size.width = bounds.size.width * scaleRatio 
    } 

    var transform = CGAffineTransform.identity 
    let orient = imageSource.imageOrientation 
    let imageSize = CGSize(width: CGFloat(imgRef.width), height: CGFloat(imgRef.height)) 

    switch(imageSource.imageOrientation) { 
    case .up: 
     transform = .identity 
    case .upMirrored: 
     transform = CGAffineTransform 
      .init(translationX: imageSize.width, y: 0) 
      .scaledBy(x: -1.0, y: 1.0) 
    case .down: 
     transform = CGAffineTransform 
      .init(translationX: imageSize.width, y: imageSize.height) 
      .rotated(by: CGFloat.pi) 
    case .downMirrored: 
     transform = CGAffineTransform 
      .init(translationX: 0, y: imageSize.height) 
      .scaledBy(x: 1.0, y: -1.0) 
    case .left: 
     let storedHeight = bounds.size.height 
     bounds.size.height = bounds.size.width; 
     bounds.size.width = storedHeight; 
     transform = CGAffineTransform 
      .init(translationX: 0, y: imageSize.width) 
      .rotated(by: 3.0 * CGFloat.pi/2.0) 
    case .leftMirrored: 
     let storedHeight = bounds.size.height 
     bounds.size.height = bounds.size.width; 
     bounds.size.width = storedHeight; 
     transform = CGAffineTransform 
      .init(translationX: imageSize.height, y: imageSize.width) 
      .scaledBy(x: -1.0, y: 1.0) 
      .rotated(by: 3.0 * CGFloat.pi/2.0) 
    case .right : 
     let storedHeight = bounds.size.height 
     bounds.size.height = bounds.size.width; 
     bounds.size.width = storedHeight; 
     transform = CGAffineTransform 
      .init(translationX: imageSize.height, y: 0) 
      .rotated(by: CGFloat.pi/2.0) 
    case .rightMirrored: 
     let storedHeight = bounds.size.height 
     bounds.size.height = bounds.size.width; 
     bounds.size.width = storedHeight; 
     transform = CGAffineTransform 
      .init(scaleX: -1.0, y: 1.0) 
      .rotated(by: CGFloat.pi/2.0) 
    } 

    UIGraphicsBeginImageContext(bounds.size) 
    if let context = UIGraphicsGetCurrentContext() { 
     if orient == .right || orient == .left { 
      context.scaleBy(x: -scaleRatio, y: scaleRatio) 
      context.translateBy(x: -height, y: 0) 
     } else { 
      context.scaleBy(x: scaleRatio, y: -scaleRatio) 
      context.translateBy(x: 0, y: -height) 
     } 

     context.concatenate(transform) 
     context.draw(imgRef, in: CGRect(x: 0, y: 0, width: width, height: height)) 
    } 

    let imageCopy = UIGraphicsGetImageFromCurrentImageContext() 
    UIGraphicsEndImageContext() 

    return imageCopy 
} 
+0

Вы также можете сделать '(bounds.size.height, bounds.size.width) = (bounds.size.width, bounds.size.height)' без создания переменной в качестве хранилища. –

+0

У меня иногда возникала проблема, что после масштабирования появилась белая линия внизу изображения. Это потому, что CGFloat, кажется, недостаточно точен. Я исправил это с помощью 'bounds.size.height.round()' и 'bounds.size.width.round()' – ndreisg

0

Вот Swift3 версия удивительный ответ Дилип в

func rotateCameraImageToProperOrientation(imageSource : UIImage, maxResolution : CGFloat) -> UIImage { 
    let imgRef = imageSource.cgImage!; 

    let width = CGFloat(imgRef.width); 
    let height = CGFloat(imgRef.height); 

    var bounds = CGRect(x: 0, y: 0, width: width, height: height) 

    var scaleRatio : CGFloat = 1 
    if (width > maxResolution || height > maxResolution) { 
     scaleRatio = min(maxResolution/bounds.size.width, maxResolution/bounds.size.height) 
     bounds.size.height = bounds.size.height * scaleRatio 
     bounds.size.width = bounds.size.width * scaleRatio 
    } 

    var transform = CGAffineTransform.identity 
    let orient = imageSource.imageOrientation 
    let imageSize = CGSize(width: width, height: height) 


    switch(imageSource.imageOrientation) { 
     case .up : 
      transform = CGAffineTransform.identity 

     case .upMirrored : 
      transform = CGAffineTransform(translationX: imageSize.width, y: 0.0); 
      transform = transform.scaledBy(x: -1, y: 1); 

     case .down : 
      transform = CGAffineTransform(translationX: imageSize.width, y: imageSize.height); 
      transform = transform.rotated(by: CGFloat(Double.pi)); 

     case .downMirrored : 
      transform = CGAffineTransform(translationX: 0.0, y: imageSize.height); 
      transform = transform.scaledBy(x: 1, y: -1); 

     case .left : 
      let storedHeight = bounds.size.height 
      bounds.size.height = bounds.size.width; 
      bounds.size.width = storedHeight; 
      transform = CGAffineTransform(translationX: 0.0, y: imageSize.width); 
      transform = transform.rotated(by: 3.0 * CGFloat(Double.pi)/2.0); 

     case .leftMirrored : 
      let storedHeight = bounds.size.height 
      bounds.size.height = bounds.size.width; 
      bounds.size.width = storedHeight; 
      transform = CGAffineTransform(translationX: imageSize.height, y: imageSize.width); 
      transform = transform.scaledBy(x: -1, y: 1); 
      transform = transform.rotated(by: 3.0 * CGFloat(Double.pi)/2.0); 

     case .right : 
      let storedHeight = bounds.size.height 
      bounds.size.height = bounds.size.width; 
      bounds.size.width = storedHeight; 
      transform = CGAffineTransform(translationX: imageSize.height, y: 0.0); 
      transform = transform.rotated(by: CGFloat(Double.pi)/2.0); 

     case .rightMirrored : 
      let storedHeight = bounds.size.height 
      bounds.size.height = bounds.size.width; 
      bounds.size.width = storedHeight; 
      transform = CGAffineTransform(scaleX: -1.0, y: 1.0); 
      transform = transform.rotated(by: CGFloat(Double.pi)/2.0); 
    } 

    UIGraphicsBeginImageContext(bounds.size) 
    let context = UIGraphicsGetCurrentContext()! 

    if orient == .right || orient == .left { 
     context.scaleBy(x: -scaleRatio, y: scaleRatio); 
     context.translateBy(x: -height, y: 0); 
    } else { 
     context.scaleBy(x: scaleRatio, y: -scaleRatio); 
     context.translateBy(x: 0, y: -height); 
    } 

    context.concatenate(transform); 
    context.draw(imgRef, in: CGRect(x: 0, y: 0, width: width, height: height)) 

    let imageCopy = UIGraphicsGetImageFromCurrentImageContext(); 
    UIGraphicsEndImageContext(); 

    return imageCopy!; 
} 
Смежные вопросы