La orientación de la imagen de iOS tiene un comportamiento extraño

94

Durante las últimas semanas he estado trabajando con imágenes en objetivo-c y he notado muchos comportamientos extraños. Primero, como muchas otras personas, he tenido este problema en el que las imágenes tomadas con la cámara (o tomadas con la cámara de otra persona y MMS enviadas a mí) se rotan 90 grados. No estaba seguro de por qué en el mundo estaba sucediendo esto (de ahí mi pregunta ), pero pude encontrar una solución barata.

Mi pregunta esta vez es ¿por qué está sucediendo esto ? ¿Por qué Apple rota las imágenes? Cuando tomo una foto con mi cámara hacia arriba, a menos que realice mi código mencionado anteriormente, cuando guardo la foto, se guarda rotada. Ahora, mi solución estaba bien hasta hace unos días.

Mi aplicación modifica píxeles individuales de una imagen, específicamente el canal alfa de un PNG (por lo que cualquier conversión de JPEG se descarta de la ventana para mi escenario). Hace unos días noté que aunque la imagen se muestra correctamente en mi aplicación gracias a mi código de solución, cuando mi algoritmo modifica los píxeles individuales de la imagen, cree que la imagen está rotada. Entonces, en lugar de modificar los píxeles en la parte superior de la imagen, modifica los píxeles en el costado de la imagen (¡porque cree que debería rotarse)! No puedo entender cómo rotar la imagen en la memoria; idealmente, preferiría borrar esa imageOrientationbandera por completo.

Aquí hay algo más que también me ha desconcertado ... Cuando tomo la foto, el imageOrientationestá configurado en 3. Mi código de solución es lo suficientemente inteligente como para darse cuenta de esto y darle la vuelta para que el usuario nunca se dé cuenta. Además, mi código para guardar la imagen en la biblioteca se da cuenta de esto, la voltea y luego la guarda para que aparezca correctamente en el rollo de la cámara.

Ese código se ve así:

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

Cuando cargo esta imagen recién guardada en mi aplicación, el imageOrientationes 0, exactamente lo que quiero ver, y mi solución alternativa de rotación ni siquiera necesita ejecutarse (nota: al cargar imágenes de Internet en lugar de imágenes tomadas con una cámara , el imageOrientationes siempre 0, lo que resulta en un comportamiento perfecto). Por alguna razón, mi código de guardado parece borrar esta imageOrientationbandera. Esperaba robar ese código y usarlo para borrar mi orientación de imagen tan pronto como el usuario toma una foto y la agrega a la aplicación, pero no parece funcionar. ¿Hace UIImageWriteToSavedPhotosAlbumalgo especial con imageOrientation?

¿La mejor solución para este problema sería simplemente desaparecer imageOrientationtan pronto como el usuario haya terminado de tomar una imagen? Supongo que Apple ha realizado el comportamiento de rotación por una razón, ¿verdad? Algunas personas sugirieron que se trata de un defecto de Apple.

(... si aún no estás perdido ... Nota 2: cuando tomo una foto horizontal, todo parece funcionar perfectamente, como las fotos tomadas de Internet)

EDITAR:

Así es como se ven realmente algunas de las imágenes y escenarios. Según los comentarios hasta ahora, parece que este comportamiento extraño es más que un comportamiento de iPhone, que creo que es bueno.

Esta es una imagen de la foto que tomé con mi teléfono (tenga en cuenta la orientación correcta), aparece exactamente como estaba en mi teléfono cuando tomé la foto:

Foto real tomada con iPhone

Así es como se ve la imagen en Gmail después de enviármela por correo electrónico (parece que Gmail la maneja correctamente):

Foto como aparece en Gmail

Así es como se ve la imagen como miniatura en Windows (no parece que se maneje correctamente):

Miniatura de Windows

Y así es como se ve la imagen real cuando se abre con el Visor de fotos de Windows (aún no se maneja correctamente):

Versión del visor de fotos de Windows

Después de todos los comentarios sobre esta pregunta, esto es lo que estoy pensando ... El iPhone toma una imagen y dice "para mostrarla correctamente, es necesario girarla 90 grados". Esta información estaría en los datos EXIF. (No sé por qué es necesario rotarlo 90 grados, en lugar de tomar la vertical recta por defecto). A partir de aquí, Gmail es lo suficientemente inteligente como para leer y analizar esos datos EXIF ​​y mostrarlos correctamente. Sin embargo, Windows no es lo suficientemente inteligente para leer los datos EXIF ​​y, por lo tanto, muestra la imagen incorrecta . ¿Son correctas mis suposiciones?

Boeckm
fuente
Interesante ... si eso es cierto, ¿por qué las imágenes tomadas se configuran en ángulo recto? Sé que esto no es un defecto del iPhone, porque he notado un comportamiento similar cuando un amigo (con un BlackBerry) toma una imagen y me envía un mensaje multimedia.
Boeckm
Vea que su cámara escribe metadatos para rotarla en 90 grados, algunos sistemas operativos leen que los metadatos y el resto no lo hacen.
HarshIT
Bastante buena lectura (vea la respuesta de @ Hadley a continuación, solía estar en un comentario). Entonces, mi aplicación claramente debe ser lo suficientemente inteligente como para manejar imágenes que contienen datos EXIF, así como imágenes que no los contienen ... Todavía no entiendo por qué cuando tomo una foto con el lado derecho hacia arriba, la bandera de orientación dice que debería rotarse 90 grados?
Boeckm
Si configura el modo de fotografía en Retrato y no está girando la cámara en ángulo recto o el modo Paisaje está configurado y la cámara ha capturado la imagen en posición de ángulo recto, el sensor establecerá automáticamente la orientación en la posición adecuada. Compruébalo
HarshIT
1
Lo más probable es que la solución sea que su aplicación necesite leer los metadatos y rotar la imagen y / o modificar los metadatos según los requisitos.
HarshIT

Respuestas:

50

Hice I + D y descubrí que cada archivo de imagen tiene propiedades de metadatos. Si los metadatos especifican la orientación de la imagen, la cual generalmente es ignorada por otros sistemas operativos excepto Mac. La mayoría de las imágenes tomadas tienen sus propiedades de metadatos configuradas en ángulo recto. Entonces Mac lo muestra de manera girada 90 grados. Puede ver la misma imagen de forma adecuada en el sistema operativo Windows.

Para obtener más detalles, lea esta respuesta http://graphicssoft.about.com/od/digitalphotography/f/sideways-pictures.htm

intente leer el exif de su imagen aquí http://www.exifviewer.org/ , o http://regex.info/exif.cgi , o http://www.addictivetips.com/internet-tips/view-complete-exif -información-de-metadatos-de-cualquier-imagen-jpeg-online /

HarshIT
fuente
1
¡GUAUU! ¡No tenía idea de que había TANTA información en los datos EXIF! ¡regex.info/exif.cgi es un sitio increíble! Ciertamente jugaré con las imágenes esta noche en este sitio. Tendré que probar todos los escenarios, las imágenes tomadas directamente, las imágenes tomadas de Internet, las imágenes tomadas rotadas, etc. ¡Muchas gracias!
Boeckm
El primer enlace exif está roto ahora y el segundo se ha actualizado a exif.regex.info/exif.cgi Intenté editar la respuesta pero @ cj-dennis la rechazó por alguna razón.
Ryan
55

Tuve el mismo problema cuando obtuve la imagen de Camera, puse el siguiente código para solucionarlo .. Agregué el método scaleAndRotateImage desde aquí

- (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;
}
Dilip Rajkumar
fuente
3
¿Cómo se ve su código scaleAndRotateImage? Después de hacer un google, ¿es el mismo que el de aquí? discusiones.apple.com/thread/1537011?start=0&tstart=0
Boeckm
2
¡GUAU ... Jaja! ¡Eso funcionó muy bien! Usé el código en mi comentario anterior. ¡Obtuve dos respuestas increíbles a mi pregunta! Creo que eso significa que hice una pregunta demasiado grande ... Muchas gracias. Tendré que hacer algunas pruebas en profundidad, pero hasta ahora el problema de orientación funciona muy bien con fotos tomadas vertical y horizontalmente.
Boeckm
3
Creo que falta una parte de su método, pero eso y el enlace aún fue suficiente para que yo resolviera el resto y finalmente lograra que mi vista de recorte de imágenes funcionara correctamente, así que gracias :)
Vic Smith
Me alegro de que haya ayudado .. :)
Dilip Rajkumar
¿Este bloque de código conserva el aspecto de la imagen original pero cambia la orientación para que esté hacia arriba?
Junchao Gu
18

Copiar / pegar rápidamente Traducción rápida de la excelente respuesta de Dilip .

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;
}
Thattyson
fuente
1
Gracias, pero ¿qué es "let ratio = width / height;" usando para? No veo ningún lugar usando la proporción en ese {}
Pengzhi Zhou
18

Mi pregunta esta vez es ¿por qué está sucediendo esto? ¿Por qué Apple rota las imágenes?

La respuesta a esto es muy simple. Apple NO está rotando la imagen. Ahí es donde radica la confusión.

La cámara CCD no gira, por lo que siempre toma la foto en modo horizontal.

Apple hizo algo muy inteligente, en lugar de gastar todo el tiempo para rotar la imagen, barajando megabytes de datos, simplemente etiquételo con CÓMO se tomó la foto.

OpenGL realiza traducciones muy fácilmente, por lo que los DATOS nunca se mezclan, solo CÓMO SE DIBUJAN.

De ahí los metadatos de orientación.

Esto se convierte en un problema si desea recortar, cambiar el tamaño, etc., pero una vez que sepa lo que está sucediendo, simplemente defina su matriz y todo funcionará.

Roy
fuente
1
Gracias por esta explicacion. Sentido común una vez que lo piensa, pero ningún otro resultado buscado en Google lo explica.
Dakine83
16

Versión Swift 4 con comprobaciones de seguridad de la respuesta de Dilip .

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
}
Dávid Tímár
fuente
También puede (bounds.size.height, bounds.size.width) = (bounds.size.width, bounds.size.height)prescindir de crear una variable como almacenamiento.
Almas Sapargali
A veces tuve el problema de que aparecía una línea blanca en la parte inferior de la imagen después de escalarla. Esto se debe a que CGFloat parece no ser lo suficientemente preciso. bounds.size.height.round()bounds.size.width.round()
Arreglé
13

Cualquier imagen generada por iPhone / iPad se guarda como Horizontal Left con etiqueta EXIF ​​Orientation (Exif.Image.Orientation) que especifica la orientación real.

Tiene los siguientes valores: 1: horizontal a la izquierda 6: vertical normal 3: horizontal a la derecha 4: vertical al revés

En IOS, la información EXIF ​​se lee correctamente y las imágenes se muestran de la misma forma en que se tomaron. Pero en Windows, NO se usa la información EXIF.

Si abre una de estas imágenes en GIMP, dirá que la imagen tiene información de rotación.

ATOzTOA
fuente
8

Para cualquier otra persona que use Xamarin, aquí hay una traducción en C # de la excelente respuesta de Dilip y un agradecimiento a thattyson por la traducción 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;
}
tetowill
fuente
¡Esto ha ayudado a resolver mi problema después de pasar muchas horas jugando con esto! Increíble que Xamarin no tenga algún soporte incorporado para esto dado que ahora es un producto de Microsoft.
Sami.C
4

Me encontré con esta pregunta porque estaba teniendo un problema similar, pero usando Swift. Solo quería vincular a la respuesta que me funcionó para otros desarrolladores de Swift: https://stackoverflow.com/a/26676578/3904581

Aquí hay un fragmento de Swift que soluciona el problema de manera eficiente:

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

Super simple. Una línea de código. Problema resuelto.

Melly
fuente
Esto no funcionó para mí, utilicé esta solución: stackoverflow.com/a/27775741/945247
Leon
0

Refactorizado rápidamente para Swift 3 (¿alguien puede probarlo y confirmar que todo funciona bien?):

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!
}
sabiland
fuente
0

Aquí está la versión Swift3 de la increíble respuesta de Dilip

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!;
}
Sandip Mane
fuente
-3

Intente cambiar el formato de imagen a .jpeg. Esto funcionó para mi

Victor Rius
fuente