Орієнтація зображень iOS має дивну поведінку


94

Протягом останніх кількох тижнів я працював із зображеннями в об’єкті-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? Після того, як зробити google, це те саме, що і тут? discussions.apple.com/thread/1537011?start=0&tstart=0
Boeckm

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

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

Я радий, що це допомогло .. :)
Діліп Раджкумар

чи зберігає цей блок коду, як виглядає оригінальне зображення, але змінює орієнтацію так, щоб вона була вгору?
Junchao Gu

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
Дякую, але що таке "нехай співвідношення = ширина / висота;" використовуючи для? Я не бачу жодного місця з використанням коефіцієнта в цьому {}
Пеньчжоу Чжоу

18

Цього разу моє запитання - чому це відбувається? Чому Apple обертає зображення?

Відповідь на це дуже проста. Apple НЕ обертає зображення. У цьому полягає плутанина.

CCD-камера не обертається, тому вона завжди робить фотографію в альбомному режимі.

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

OpenGL робить переклади дуже легко - тому ДАНІ ніколи не перемішуються - просто ЯК ЇЇ МАЛЮЮТЬ.

Звідси метадані орієнтації.

Це стає проблемою, якщо ви хочете обрізати, змінити розмір тощо - але коли ви дізнаєтесь, що відбувається, ви просто визначаєте свою матрицю, і все виходить.


1
Дякую за це пояснення. Здоровий глузд, коли ти задумаєшся, але жоден інший результат Google не пояснив цього.
Dakine83

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()іbounds.size.width.round()
ndreisg

13

Будь-яке зображення, згенероване iPhone / iPad, зберігається як альбомний лівий із тегом орієнтації EXIF ​​(Exif.Image.Orientation) із зазначенням фактичної орієнтації.

Він має такі значення: 1: Пейзаж ліворуч 6: Портрет Звичайний 3: Пейзаж праворуч 4: Портрет догори дном

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

Якщо ви відкриєте одне з цих зображень у GIMP, він скаже, що зображення має інформацію про обертання.


8

Для всіх, хто використовує Xamarin, ось переклад C # чудової відповіді Діліпа та подяка Тетісону за переклад 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: https://stackoverflow.com/a/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.