web-dev-qa-db-fra.com

iOS PNG Image pivotée à 90 degrés

Dans mon application iOS que je suis en train d'écrire, je traite avec les PNG parce que je traite avec le canal alpha. Pour une raison quelconque, je peux très bien charger un fichier PNG dans ma imageView, mais lorsque le moment est venu de copier l'image de mon application (sur le PasteBoard) ou de l'enregistrer sur ma pellicule, celle-ci pivote de 90 degrés. 

J'ai cherché partout à ce sujet, et l'une des choses que j'ai apprises est que si j'utilisais des JPEG, je n'aurais pas ce problème (ça sonne), à ​​cause des informations EXIF. 

Mon application a une fonctionnalité complète de copier/coller, et voici le kicker (je vais l'écrire par étapes pour qu'il soit plus facile à suivre): 

  1. Aller à la pellicule et copier une image
  2. Allez dans mon application et appuyez sur "Coller", l'image colle très bien, et je peux le faire toute la journée
  3. Cliquez sur la fonction de copie que j'ai implémentée, puis cliquez sur "Coller". L'image est collée mais tournée.

Je suis sûr à 100% que mon code copier-coller n'est pas ce qui ne va pas ici, car si je reviens à l'étape 2 ci-dessus et que je clique sur "Enregistrer", la photo est enregistrée dans ma bibliothèque, mais elle subit une rotation de 90 degrés!

Ce qui est encore plus étrange, c’est que cela semble bien fonctionner avec les images téléchargées sur Internet, mais est très aléatoire, avec les images que j’ai prises manuellement avec le téléphone. Certains fonctionnent, d'autres non ...

Quelqu'un a-t-il des idées à ce sujet? Des solutions possibles que je peux utiliser? Je suis assez confiant dans le fait que le code fonctionne pour environ 75% de mes images. Je peux poster le code sur demande cependant.

26
Boeckm

Cela a pris quelques jours, mais je l’ai enfin compris grâce à la réponse affichée par @Dondragmer. Mais je me suis dit que je posterais ma solution complète. 

Donc, fondamentalement, je devais écrire une méthode pour faire automatiquement pivoter intelligemment mes images. L’inconvénient est que je dois appeler cette méthode un peu partout dans mon code, ce qui demande beaucoup de ressources processeur, en particulier lorsque vous travaillez sur des appareils mobiles, mais le fait positif est que je peux prendre des images, les copier, les coller et les enregistrer. ils tournent tous correctement. Voici le code que j'ai fini par utiliser (la méthode n'est pas encore complète à 100%, il faut toujours modifier les fuites de mémoire et tout le reste). 

J'ai fini par apprendre que la toute première fois qu'une image était insérée dans mon application (que cela soit dû au fait qu'un utilisateur appuyait sur "prendre une image", "coller une image" ou "sélectionner une image", pour une raison quelconque, l'insertion était très bien sans auto. À ce stade, j’enregistrais quelle que soit la valeur de rotation dans une variable globale appelée imageOrientationWhenAddedToScreen, ce qui me simplifiait la vie, car lorsqu’il était temps de manipuler l’image et de la sauvegarder en dehors du programme, j’avais simplement coché cette variable globale en cache. et déterminé si je devais faire pivoter correctement l'image. 

    - (UIImage*) rotateImageAppropriately:(UIImage*) imageToRotate {
    //This method will properly rotate our image, we need to make sure that
    //We call this method everywhere pretty much...

    CGImageRef imageRef = [imageToRotate CGImage];
    UIImage* properlyRotatedImage;

    if (imageOrientationWhenAddedToScreen == 0) {
       //Don't rotate the image
        properlyRotatedImage = imageToRotate;

    } else if (imageOrientationWhenAddedToScreen == 3) {

        //We need to rotate the image back to a 3
        properlyRotatedImage = [UIImage imageWithCGImage:imageRef scale:1.0 orientation:3];

    } else if (imageOrientationWhenAddedToScreen == 1) {

        //We need to rotate the image back to a 1
        properlyRotatedImage = [UIImage imageWithCGImage:imageRef scale:1.0 orientation:1];        

    }

    return properlyRotatedImage;

}

Je ne suis toujours pas sûr à 100% pourquoi Apple a ce comportement bizarre en matière de rotation des images (essayez ceci ... Prenez votre téléphone, mettez-le à l'envers et prenez une photo. Vous remarquerez que la photo finale est bien droite. Peut-être que cela C’est pourquoi Apple a ce type de fonctionnalité?). 

Je sais que j'ai passé beaucoup de temps à résoudre ce problème, alors j'espère que cela aidera d'autres personnes!

13
Boeckm

Pour ceux qui recherchent une solution Swift, créez une extension de UIImage et ajoutez la méthode suivante:

func correctlyOrientedImage() -> UIImage {
    if self.imageOrientation == .up {
        return self
    }

    UIGraphicsBeginImageContextWithOptions(size, false, scale)
    draw(in: CGRect(x: 0, y: 0, width: size.width, height: size.height))
    let normalizedImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return normalizedImage ?? self;
}
25
Tom J

Si vous rencontrez des problèmes en raison de la propriété existante image imageOrientation, vous pouvez construire une image par ailleurs identique avec une orientation différente, comme ceci:

CGImageRef imageRef = [sourceImage CGImage];

UIImage *rotatedImage = [UIImage imageWithCGImage:imageRef scale:1.0 orientation:UIImageOrientationUp];

Vous devrez peut-être expérimenter avec quelle orientation définir vos images de remplacement, éventuellement en fonction de l'orientation que vous avez utilisée.

Gardez également un œil sur votre utilisation de la mémoire. Les applications de photographie s'épuisent souvent, ce qui doublera votre capacité de stockage par image jusqu'à ce que vous libériez l'image source.

14
Dondragmer

Ce comportement de "rotation étrange" n’est vraiment pas si étrange du tout. C'est intelligent, et par intelligent je veux dire efficace en mémoire. Lorsque vous faites pivoter un périphérique iOS, le matériel de la caméra tourne avec lui. Lorsque vous prenez une photo, celle-ci sera capturée, mais la caméra est orientée. UIImage peut utiliser ces données d’image brutes sans les copier en gardant simplement trace de l’orientation dans laquelle elle doit être placée. Lorsque vous utilisez UIImagePNGRepresentation() vous perdez ces données d’orientation et obtenez un fichier PNG de l’image sous-jacente prise l'appareil photo. Pour résoudre ce problème au lieu de faire une rotation, vous pouvez indiquer à l'image d'origine de se dessiner dans un nouveau contexte et d'obtenir la UIImage correctement orientée à partir de ce contexte.

UIImage *image = ...;

//Have the image draw itself in the correct orientation if necessary
if(!(image.imageOrientation == UIImageOrientationUp ||
    image.imageOrientation == UIImageOrientationUpMirrored))
{
    CGSize imgsize = image.size;
    UIGraphicsBeginImageContext(imgsize);
    [image drawInRect:CGRectMake(0.0, 0.0, imgsize.width, imgsize.height)];
    image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
}

NSData *png = UIImagePNGRepresentation(image);
13
Joe

Voici un autre moyen d'y parvenir:

@IBAction func rightRotateAction(sender: AnyObject) {

    let imgToRotate = CIImage(CGImage: sourceImageView.image?.CGImage)
    let transform = CGAffineTransformMakeRotation(CGFloat(M_PI_2))
    let rotatedImage = imgToRotate.imageByApplyingTransform(transform)
    let extent = rotatedImage.extent()
    let contex = CIContext(options: [kCIContextUseSoftwareRenderer: false])
    let cgImage = contex.createCGImage(rotatedImage, fromRect: extent)
    adjustedImage = UIImage(CGImage: cgImage)!
    UIView.transitionWithView(sourceImageView, duration: 0.5, options: UIViewAnimationOptions.TransitionCrossDissolve, animations: {
            self.sourceImageView.image = self.adjustedImage
        }, completion: nil)
}
0
Dharmesh

Vous pouvez utiliser Image I/O pour enregistrer une image PNG dans un fichier (ou NSMutableData) en ce qui concerne l'orientation de l'image. Dans l'exemple ci-dessous, j'enregistre l'image PNG dans un fichier à path.

- (BOOL)savePngFile:(UIImage *)image toPath:(NSString *)path {
    NSData *data = UIImagePNGRepresentation(image);
    int exifOrientation = [UIImage cc_iOSOrientationToExifOrientation:image.imageOrientation];
    NSDictionary *metadata = @{(__bridge id)kCGImagePropertyOrientation:@(exifOrientation)};
    NSURL *url = [NSURL fileURLWithPath:path];
    CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)data, NULL);
    if (!source) {
        return NO;
    }
    CFStringRef UTI = CGImageSourceGetType(source);
    CGImageDestinationRef destination = CGImageDestinationCreateWithURL((__bridge CFURLRef)url, UTI, 1, NULL);
    if (!destination) {
        CFRelease(source);
        return NO;
    }
    CGImageDestinationAddImageFromSource(destination, source, 0, (__bridge CFDictionaryRef)metadata);
    BOOL success = CGImageDestinationFinalize(destination);
    CFRelease(destination);
    CFRelease(source);
    return success;
}

cc_iOSOrientationToExifOrientation: est une méthode de la catégorie UIImage.

+ (int)cc_iOSOrientationToExifOrientation:(UIImageOrientation)iOSOrientation {
    int exifOrientation = -1;
    switch (iOSOrientation) {
        case UIImageOrientationUp:
            exifOrientation = 1;
            break;

        case UIImageOrientationDown:
            exifOrientation = 3;
            break;

        case UIImageOrientationLeft:
            exifOrientation = 8;
            break;

        case UIImageOrientationRight:
            exifOrientation = 6;
            break;

        case UIImageOrientationUpMirrored:
            exifOrientation = 2;
            break;

        case UIImageOrientationDownMirrored:
            exifOrientation = 4;
            break;

        case UIImageOrientationLeftMirrored:
            exifOrientation = 5;
            break;

        case UIImageOrientationRightMirrored:
            exifOrientation = 7;
            break;

        default:
            exifOrientation = -1;
    }
    return exifOrientation;
}

Vous pouvez également enregistrer l'image dans NSData en utilisant CGImageDestinationCreateWithData et passer NSMutableData au lieu de NSURL dans CGImageDestinationCreateWithURL.

0
KudoCC