L'orientation de l'image iOS a un comportement étrange

94

Au cours des dernières semaines, j'ai travaillé avec des images en objective-c et j'ai remarqué beaucoup de comportements étranges. Tout d'abord, comme beaucoup d'autres personnes, j'ai eu ce problème où les images prises avec l'appareil photo (ou prises avec l'appareil photo de quelqu'un d'autre et le MMS vers moi) sont pivotées de 90 degrés. Je ne savais pas pourquoi dans le monde cela se produisait (d'où ma question ) mais j'ai pu trouver un travail bon marché.

Ma question cette fois est pourquoi cela se produit-il ? Pourquoi Apple fait-il pivoter les images? Lorsque je prends une photo avec mon appareil photo à l'endroit, à moins d'exécuter le code mentionné ci-dessus, lorsque j'enregistre la photo, elle est enregistrée en rotation. Maintenant, ma solution de contournement était correcte jusqu'à il y a quelques jours.

Mon application modifie les pixels individuels d'une image, en particulier le canal alpha d'un PNG (ainsi toute conversion JPEG est jetée hors de la fenêtre pour mon scénario). Il y a quelques jours, j'ai remarqué que même si l'image s'affiche correctement dans mon application grâce à mon code de contournement, lorsque mon algorithme modifie les pixels individuels de l'image, il pense que l'image est tournée. Alors au lieu de modifier les pixels en haut de l'image, il modifie les pixels sur le côté de l'image (car il pense qu'il faut la faire pivoter)! Je ne peux pas comprendre comment faire pivoter l'image en mémoire - idéalement, je préférerais simplement effacer ce imageOrientationdrapeau tous ensemble.

Voici quelque chose d'autre qui m'a également déconcerté ... Lorsque je prends la photo, le imageOrientationest réglé sur 3. Mon code de contournement est assez intelligent pour réaliser cela et le retourner afin que l'utilisateur ne le remarque jamais. De plus, mon code pour enregistrer l'image dans la bibliothèque le réalise, le retourne, puis l' enregistre pour qu'il apparaisse correctement dans la pellicule.

Ce code ressemble à ceci:

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

Lorsque je charge cette image nouvellement enregistrée dans mon application, la valeur imageOrientationest 0 - exactement ce que je veux voir, et ma solution de contournement de rotation n'a même pas besoin de s'exécuter (remarque: lors du chargement d'images depuis Internet par opposition aux images prises avec un appareil photo , la imageOrientationvaut toujours 0, ce qui donne un comportement parfait). Pour une raison quelconque, mon code de sauvegarde semble effacer cet imageOrientationindicateur. J'espérais simplement voler ce code et l'utiliser pour effacer mon imageOrientation dès que l'utilisateur prend une photo et l'ajoute à l'application, mais cela ne semble pas fonctionner. Fait UIImageWriteToSavedPhotosAlbumquelque chose de spécial avec imageOrientation?

La meilleure solution à ce problème serait-elle de simplement souffler imageOrientationdès que l'utilisateur a terminé de prendre une image. Je suppose qu'Apple a fait le comportement de rotation pour une raison, non? Quelques personnes ont suggéré qu'il s'agissait d'un défaut Apple.

(... si vous n'êtes pas encore perdu ... Note 2: Quand je prends une photo horizontale, tout semble fonctionner parfaitement, tout comme les photos prises sur Internet)

ÉDITER:

Voici à quoi ressemblent réellement certaines images et scénarios. Sur la base des commentaires jusqu'à présent, il semble que ce comportement étrange est plus qu'un simple comportement d'iPhone, ce que je pense être bon.

Ceci est une photo de la photo que j'ai prise avec mon téléphone (notez l'orientation correcte), elle apparaît exactement comme elle le faisait sur mon téléphone lorsque j'ai pris la photo:

Photo réelle prise sur iPhone

Voici à quoi ressemble l'image dans Gmail une fois que je l'ai envoyée par courrier électronique (on dirait que Gmail la gère correctement):

Photo telle qu'elle apparaît dans Gmail

Voici à quoi ressemble l'image sous forme de vignette dans les fenêtres (ne semble pas être gérée correctement):

Vignette Windows

Et voici à quoi ressemble l'image réelle lorsqu'elle est ouverte avec la visionneuse de photos Windows (toujours pas gérée correctement):

Version de la visionneuse de photos Windows

Après tous les commentaires sur cette question, voici ce que je pense ... L'iPhone prend une image, et dit "pour l'afficher correctement, il doit être tourné de 90 degrés". Ces informations figureraient dans les données EXIF. (Pourquoi il doit être tourné de 90 degrés, plutôt que de passer par défaut à la verticale droite, je ne sais pas). À partir de là, Gmail est suffisamment intelligent pour lire et analyser ces données EXIF ​​et les afficher correctement. Cependant, Windows n'est pas assez intelligent pour lire les données EXIF ​​et affiche donc l'image de manière incorrecte . Mes hypothèses sont-elles correctes?

Boeckm
la source
Intéressant ... si c'est vrai, pourquoi les images prises sont-elles réglées à angle droit? Je sais que ce n'est pas un défaut de l'iPhone, car j'ai remarqué un comportement similaire lorsqu'un ami (avec un BlackBerry) prend une image et me la MMS.
Boeckm
Voir votre caméra écrit des métadonnées pour la faire pivoter à 90 degrés, certains systèmes d'exploitation lisent que les métadonnées et le reste ne le font pas.
HarshIT
Très bonne lecture (voir la réponse de @ Hadley ci-dessous - c'était dans un commentaire) Mon application doit donc clairement être suffisamment intelligente pour gérer les images qui contiennent des données EXIF, ainsi que les images qui ne les contiennent pas ... Je ne comprends toujours pas pourquoi lorsque je prends une photo à l'endroit, le drapeau d'orientation dit qu'il devrait être tourné de 90 degrés?
Boeckm
Vous définissez votre mode photo sur Portrait et vous ne faites pas pivoter votre appareil photo à angle droit ou le mode Paysage est défini et l'appareil photo a capturé l'image dans la position à angle droit, le capteur définira automatiquement l'orientation sur la bonne. Check it out
HarshIT
1
La solution est très probablement, votre application doit lire les métadonnées et faire pivoter l'image et / ou modifier les métadonnées selon les besoins.
HarshIT

Réponses:

50

J'ai fait de la R&D dessus et j'ai découvert que chaque fichier image avait une propriété de métadonnées. Si les métadonnées spécifient l'orientation de l'image qui est généralement ignorée par d'autres OS mais Mac. La plupart des images prises ont leur propriété de métadonnées définie sur l'angle droit. Donc Mac le montre de manière pivotée à 90 degrés. Vous pouvez voir la même image de manière appropriée dans le système d'exploitation Windows.

Pour plus de détails, lisez cette réponse http://graphicssoft.about.com/od/digitalphotography/f/sideways-pictures.htm

essayez de lire l'exif de votre image ici http://www.exifviewer.org/ , ou http://regex.info/exif.cgi , ou http://www.addictivetips.com/internet-tips/view-complete-exif -métadonnées-informations-de-toute-image-jpeg-en ligne /

HarshIT
la source
1
HOU LA LA! Je n'avais aucune idée qu'il y avait BEAUCOUP d'informations dans les données EXIF! regex.info/exif.cgi est un site incroyable! Je vais certainement jouer avec les images ce soir sur ce site. Je vais devoir tester tous les scénarios, les images sont prises directement, les images prises sur Internet, les images prises en rotation, etc. Merci beaucoup!
Boeckm
Le premier lien exif est maintenant rompu, et le second a été mis à jour vers exif.regex.info/exif.cgi J'ai essayé de modifier la réponse mais @ cj-dennis l'a rejetée pour une raison quelconque.
Ryan
55

J'ai eu le même problème lorsque j'obtiens l'image de Camera, j'ai mis le code suivant pour le réparer .. Ajout de la méthode scaleAndRotateImage à partir d'ici

- (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
la source
3
À quoi ressemble votre code scaleAndRotateImage? Après avoir fait un google, est-ce le même que celui ici? discussions.apple.com/thread/1537011?start=0&tstart=0
Boeckm
2
WOW ... Haha! Cela a très bien fonctionné! J'ai utilisé le code dans mon commentaire ci-dessus. J'ai eu deux réponses incroyables à ma question! Je pense que cela signifie que j'ai posé une trop grande question ... Merci beaucoup. J'aurai des tests approfondis à faire, mais jusqu'à présent, le problème d'orientation fonctionne très bien avec des photos prises verticalement et horizontalement.
Boeckm
3
Je pense qu'il manque une partie de votre méthode, mais cela et le lien me suffisaient toujours pour travailler sur le reste et enfin faire fonctionner correctement ma vue de recadrage d'image, alors merci :)
Vic Smith
Je suis heureux que cela ait aidé .. :)
Dilip Rajkumar
ce bloc de code préserve-t-il l'apparence de l'image d'origine mais change-t-il l'orientation pour être vers le haut?
Junchao Gu
18

Copier / coller rapide Traduction rapide de l' excellente réponse 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
la source
1
Merci, mais qu'est-ce que "let ratio = largeur / hauteur;" utiliser pour? Je ne vois aucun endroit utilisant le ratio dans ce {}
Pengzhi Zhou
18

Ma question cette fois est pourquoi cela se produit-il? Pourquoi Apple fait-il pivoter les images?

La réponse à cela est très simple. Apple ne fait PAS pivoter l'image. C'est là que réside la confusion.

La caméra CCD ne tourne pas, elle prend donc toujours la photo en mode paysage.

Apple a fait une chose très intelligente - au lieu de passer tout le temps à faire pivoter l'image - en mélangeant des mégaoctets de données - il suffit de marquer avec COMMENT la photo a été prise.

OpenGL fait des traductions très facilement - donc les DONNÉES ne sont jamais mélangées - juste COMMENT ILS SONT DESSINÉES.

D'où les métadonnées d'orientation.

Cela devient un problème si vous voulez recadrer, redimensionner, etc. - mais une fois que vous savez ce qui se passe, vous définissez simplement votre matrice et tout fonctionne.

Roy
la source
1
Merci pour cette explication. Le bon sens une fois que vous y pensez, mais aucun autre résultat googlé ne l'explique.
Dakine83
16

Version Swift 4 avec contrôles de sécurité de la réponse 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
la source
Vous pouvez également vous (bounds.size.height, bounds.size.width) = (bounds.size.width, bounds.size.height)passer de la création de variable comme stockage.
Almas Sapargali
J'ai parfois eu le problème, qu'une ligne blanche apparaissait en bas de l'image après l'avoir mise à l'échelle. En effet, CGFloat ne semble pas assez précis. J'ai corrigé cela avec bounds.size.height.round()etbounds.size.width.round()
ndreisg
13

Toute image générée par iPhone / iPad est enregistrée en tant que Paysage à gauche avec une balise d'orientation EXIF ​​(Exif.Image.Orientation) spécifiant l'orientation réelle.

Il a les valeurs suivantes: 1: Paysage à gauche 6: Portrait Normal 3: Paysage à droite 4: Portrait à l'envers

Dans IOS, les informations EXIF ​​sont correctement lues et les images sont affichées de la même manière qu'elles ont été prises. Mais sous Windows, les informations EXIF ​​ne sont PAS utilisées.

Si vous ouvrez l'une de ces images dans GIMP, cela indiquera que l'image a des informations de rotation.

ATOzTOA
la source
8

Pour tous ceux qui utilisent Xamarin, voici une traduction C # de l' excellente réponse de Dilip , et un merci à thattyson pour la traduction 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
la source
Cela a aidé à résoudre mon problème après avoir passé de nombreuses heures à jouer avec ça! Incroyable que Xamarin n'ait pas de prise en charge intégrée pour cela étant donné qu'il s'agit désormais d'un produit Microsoft.
Sami.C
4

Je suis tombé sur cette question parce que j'avais un problème similaire, mais en utilisant Swift. Je voulais juste faire un lien vers la réponse qui a fonctionné pour moi pour tous les autres développeurs Swift: https://stackoverflow.com/a/26676578/3904581

Voici un extrait de code Swift qui résout efficacement le problème:

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

Super simple. Une ligne de code. Problème résolu.

Melly
la source
Cela n'a pas fonctionné pour moi, j'ai utilisé cette solution: stackoverflow.com/a/27775741/945247
Leon
0

Refactorisé rapidement pour Swift 3 (quelqu'un peut-il le tester et confirmer que tout fonctionne 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
la source
0

Voici la version Swift3 de la réponse géniale 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
la source
-3

Essayez de changer le format d'image en .jpeg. Cela a fonctionné pour moi

Victor Rius
la source