Ориентация изображения iOS имеет странное поведение


95

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

На этот раз у меня вопрос: почему это происходит ? Почему 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флаг. Я надеялся просто украсть этот код и использовать его, чтобы стереть мой imageOrientation, как только пользователь сделает снимок и добавит его в приложение, но похоже, что это не работает. Есть ли UIImageWriteToSavedPhotosAlbumчто-то особенное imageOrientation?

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

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

РЕДАКТИРОВАТЬ:

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

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

Фактическое фото, сделанное на iPhone

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

Фотография в том виде, в котором она отображается в Gmail

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

Миниатюра Windows

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

Версия программы просмотра фотографий Windows

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


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

Посмотрите, как ваша камера записывает метаданные, чтобы повернуть ее на 90 градусов, некоторые ОС считывают эти метаданные, а остальные - нет.
HarshIT

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

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

1
Решение, скорее всего, заключается в том, что вашему приложению необходимо прочитать метаданные и повернуть изображение и / или изменить метаданные в соответствии с требованиями.
HarshIT

Ответы:


50

Я провел исследования и разработки и обнаружил, что каждый файл изображения имеет свойство метаданных. Если в метаданных указана ориентация изображения, которая обычно игнорируется другими ОС, кроме 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 -метаданные-информация-любого-jpeg-изображения-онлайн /


1
ВОТ ЭТО ДА! Я понятия не имел, что в данных EXIF ​​было ТАКОЕ МНОГО информации! regex.info/exif.cgi - невероятный сайт! Сегодня вечером я обязательно поиграюсь с изображениями на этом сайте. Мне придется протестировать каждый сценарий: изображения будут взяты прямо, изображения взяты из Интернета, сделанные изображения повернуты и т. Д. Большое спасибо!
Boeckm

Первая ссылка exif теперь не работает, а вторая была обновлена ​​до exif.regex.info/exif.cgi. Я пытался отредактировать ответ, но @ cj-dennis по какой-то причине его отклонил.
Райан

55

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

- (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
Как выглядит ваш код scaleAndRotateImage? После гугла он такой же, как здесь? discussions.apple.com/thread/1537011?start=0&tstart=0
Boeckm

2
ВАУ ... Ха-ха! Это сработало очень хорошо! Я использовал код из своего комментария выше. Я получил два потрясающих ответа на свой вопрос! Думаю, это означает, что я задал слишком большой вопрос ... Большое спасибо. Мне нужно провести более глубокое тестирование, но пока проблема ориентации отлично работает с вертикально и горизонтально сделанными фотографиями.
Boeckm

3
Я думаю, что часть вашего метода отсутствует, но этого и ссылки по-прежнему было достаточно для меня, чтобы проработать остальное и, наконец, заставить мое изображение обрезки работать правильно, поэтому спасибо :)
Вик Смит

Я рад, что это помогло .. :)
Дилип Раджкумар

сохраняет ли этот блок кода исходное изображение, но меняет ли его ориентацию вверх?
Цзюньчао Гу

20

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

Ответ на это очень простой. Apple НЕ вращает изображение. Вот в чем путаница.

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

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

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

Отсюда и ориентация метаданных.

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


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

хорошее объяснение, как у профессора. Благодарность!
vkGunasekaran

18

Быстрое копирование / вставка Быстрый перевод отличного ответа Дилипа .

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
Спасибо, но что такое «let ratio = width / height;» использование для? Я не вижу места, где используется коэффициент {}
Pengzhi Zhou

16

Версия Swift 4 с проверками безопасности ответа Дилипа .

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
}

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

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

13

Любое изображение, созданное на iPhone / iPad, сохраняется как альбомная ориентация слева с тегом EXIF ​​Orientation (Exif.Image.Orientation), указывающим фактическую ориентацию.

Он имеет следующие значения: 1: альбомная, слева 6: портретная, нормальная 3: альбомная, правая 4: вертикальная, вверх ногами

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

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


8

Для всех, кто использует Xamarin, вот перевод на C # отличного ответа Дилипа и благодарность thattyson за перевод Swift .

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

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

4

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

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

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

Очень просто. Одна строчка кода. Задача решена.


У меня это не сработало, я использовал следующее решение: stackoverflow.com/a/27775741/945247
Леон

0

Я точно знаю, в чем твоя проблема. Вы используете UIImagePicker, что странно во всех смыслах. Я бы посоветовал вам использовать AVFoundation для камеры, которая дает гибкость в ориентации, а также качество. Используйте AVCaptureSession. Вы можете получить код здесь. Как сохранить фотографии, сделанные с помощью AVFoundation, в фотоальбом?


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!
}

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.