web-dev-qa-db-fra.com

iOS - UIImageView - Comment gérer l'orientation des images UIImage

Est-il possible de configurer IImageView pour gérer l'orientation de l'image? Lorsque je règle IImageView sur une image avec orientation [~ # ~] à droite [~ # ~] (photo de pellicule), l’image est tournée à droite, mais je souhaite l’afficher dans l’orientation appropriée, comme elle l’a été.

Je sais que je peux faire pivoter les données d'image, mais est-il possible de le faire plus élégant?

Merci

73
Martin Pilch

Si je comprends bien, ce que vous voulez faire, c'est ignorer l'orientation de UIImage? Si oui, alors vous pouvez faire ceci:

UIImage *originalImage = [... whatever ...];

UIImage *imageToDisplay =
     [UIImage imageWithCGImage:[originalImage CGImage]
              scale:[originalImage scale]
              orientation: UIImageOrientationUp];

Vous créez donc une nouvelle UIImage avec les mêmes données de pixel que l'original (référencée via sa propriété CGImage), mais vous spécifiez une orientation qui ne fait pas pivoter les données.

135
Tommy

Vous pouvez complètement éviter de faire manuellement les transformations et les redimensionnements, comme suggéré par an0 dans cette réponse ici :

- (UIImage *)normalizedImage {
    if (self.imageOrientation == UIImageOrientationUp) return self; 

    UIGraphicsBeginImageContextWithOptions(self.size, NO, self.scale);
    [self drawInRect:(CGRect){0, 0, self.size}];
    UIImage *normalizedImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return normalizedImage;
}

La documentation des méthodes UIImage size et drawInRect indique explicitement qu'elles prennent en compte l'orientation.

45
user2067021

J'ai converti le code en la réponse d'Anomie ici (copier-coller ci-dessus par suvish valsan) en Swift :

func fixOrientation() -> UIImage {
    if self.imageOrientation == UIImageOrientation.Up {
        return self
    }

    var transform = CGAffineTransformIdentity

    switch self.imageOrientation {
    case .Down, .DownMirrored:
        transform = CGAffineTransformTranslate(transform, self.size.width, self.size.height)
        transform = CGAffineTransformRotate(transform, CGFloat(M_PI));

    case .Left, .LeftMirrored:
        transform = CGAffineTransformTranslate(transform, self.size.width, 0);
        transform = CGAffineTransformRotate(transform, CGFloat(M_PI_2));

    case .Right, .RightMirrored:
        transform = CGAffineTransformTranslate(transform, 0, self.size.height);
        transform = CGAffineTransformRotate(transform, CGFloat(-M_PI_2));

    case .Up, .UpMirrored:
        break
    }

    switch self.imageOrientation {

    case .UpMirrored, .DownMirrored:
        transform = CGAffineTransformTranslate(transform, self.size.width, 0)
        transform = CGAffineTransformScale(transform, -1, 1)

    case .LeftMirrored, .RightMirrored:
        transform = CGAffineTransformTranslate(transform, self.size.height, 0)
        transform = CGAffineTransformScale(transform, -1, 1);

    default:
        break;
    }

    // Now we draw the underlying CGImage into a new context, applying the transform
    // calculated above.
    let ctx = CGBitmapContextCreate(
        nil,
        Int(self.size.width),
        Int(self.size.height),
        CGImageGetBitsPerComponent(self.CGImage),
        0,
        CGImageGetColorSpace(self.CGImage),
        UInt32(CGImageGetBitmapInfo(self.CGImage).rawValue)
    )

    CGContextConcatCTM(ctx, transform);

    switch self.imageOrientation {
    case .Left, .LeftMirrored, .Right, .RightMirrored:
        // Grr...
        CGContextDrawImage(ctx, CGRectMake(0, 0, self.size.height,self.size.width), self.CGImage);

    default:
        CGContextDrawImage(ctx, CGRectMake(0, 0, self.size.width,self.size.height), self.CGImage);
        break;
    }

    // And now we just create a new UIImage from the drawing context
    let cgimg = CGBitmapContextCreateImage(ctx)

    let img = UIImage(CGImage: cgimg!)

    return img;
}

(J'ai remplacé toutes les occurrences du paramètre image par self, car mon code est une extension de UIImage).


EDIT: Swift 3 version.

La méthode retourne une option, car beaucoup d'appels intermédiaires peuvent échouer et je n'aime pas utiliser !.

func fixOrientation() -> UIImage? {

    guard let cgImage = self.cgImage else {
        return nil
    }

    if self.imageOrientation == UIImageOrientation.up {
        return self
    }

    let width  = self.size.width
    let height = self.size.height

    var transform = CGAffineTransform.identity

    switch self.imageOrientation {
    case .down, .downMirrored:
        transform = transform.translatedBy(x: width, y: height)
        transform = transform.rotated(by: CGFloat.pi)

    case .left, .leftMirrored:
        transform = transform.translatedBy(x: width, y: 0)
        transform = transform.rotated(by: 0.5*CGFloat.pi)

    case .right, .rightMirrored:
        transform = transform.translatedBy(x: 0, y: height)
        transform = transform.rotated(by: -0.5*CGFloat.pi)

    case .up, .upMirrored:
        break
    }

    switch self.imageOrientation {
    case .upMirrored, .downMirrored:
        transform = transform.translatedBy(x: width, y: 0)
        transform = transform.scaledBy(x: -1, y: 1)

    case .leftMirrored, .rightMirrored:
        transform = transform.translatedBy(x: height, y: 0)
        transform = transform.scaledBy(x: -1, y: 1)

    default:
        break;
    }

    // Now we draw the underlying CGImage into a new context, applying the transform
    // calculated above.
    guard let colorSpace = cgImage.colorSpace else {
        return nil
    }

    guard let context = CGContext(
        data: nil,
        width: Int(width),
        height: Int(height),
        bitsPerComponent: cgImage.bitsPerComponent,
        bytesPerRow: 0,
        space: colorSpace,
        bitmapInfo: UInt32(cgImage.bitmapInfo.rawValue)
        ) else {
            return nil
    }

    context.concatenate(transform);

    switch self.imageOrientation {

    case .left, .leftMirrored, .right, .rightMirrored:
        // Grr...
        context.draw(cgImage, in: CGRect(x: 0, y: 0, width: height, height: width))

    default:
        context.draw(cgImage, in: CGRect(x: 0, y: 0, width: width, height: height))
    }

    // And now we just create a new UIImage from the drawing context
    guard let newCGImg = context.makeImage() else {
        return nil
    }

    let img = UIImage(cgImage: newCGImg)

    return img;
}

(Remarque: Swift 3 odes version sont compilées sous Xcode 8.1, mais n’ont pas été testées. Cela fonctionne. Il peut y avoir une faute de frappe quelque part, une largeur/hauteur mélangée, etc. N'hésitez pas à pointer/corriger les erreurs).

24
Nicolas Miari

Cette méthode vérifie d'abord l'orientation actuelle de UIImage, puis la modifie dans le sens des aiguilles d'une montre et renvoie UIImage.Vous pouvez afficher cette image sous la forme

self.imageView.image = rotationImage (currentUIImage)

   func rotateImage(image:UIImage)->UIImage
    {
        var rotatedImage = UIImage();
        switch image.imageOrientation
        {
            case UIImageOrientation.Right:
            rotatedImage = UIImage(CGImage:image.CGImage!, scale: 1, orientation:UIImageOrientation.Down);

           case UIImageOrientation.Down:
            rotatedImage = UIImage(CGImage:image.CGImage!, scale: 1, orientation:UIImageOrientation.Left);

            case UIImageOrientation.Left:
            rotatedImage = UIImage(CGImage:image.CGImage!, scale: 1, orientation:UIImageOrientation.Up);

             default:
            rotatedImage = UIImage(CGImage:image.CGImage!, scale: 1, orientation:UIImageOrientation.Right);
        }
        return rotatedImage;
    }

Swift 4 version

func rotateImage(image:UIImage) -> UIImage
    {
        var rotatedImage = UIImage()
        switch image.imageOrientation
        {
        case .right:
            rotatedImage = UIImage(cgImage: image.cgImage!, scale: 1.0, orientation: .down)

        case .down:
            rotatedImage = UIImage(cgImage: image.cgImage!, scale: 1.0, orientation: .left)

        case .left:
            rotatedImage = UIImage(cgImage: image.cgImage!, scale: 1.0, orientation: .up)

        default:
            rotatedImage = UIImage(cgImage: image.cgImage!, scale: 1.0, orientation: .right)
        }

        return rotatedImage
    }
20
varender singh

Swift 3.1

func fixImageOrientation(_ image: UIImage)->UIImage {
    UIGraphicsBeginImageContext(image.size)
    image.draw(at: .zero)
    let newImage = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    return newImage ?? image
}
15
Aqua

voici un échantillon de morue exploitable, tenant compte de l'orientation de l'image:

#define rad(angle) ((angle) / 180.0 * M_PI)
- (CGAffineTransform)orientationTransformedRectOfImage:(UIImage *)img
{
    CGAffineTransform rectTransform;
    switch (img.imageOrientation)
    {
        case UIImageOrientationLeft:
            rectTransform = CGAffineTransformTranslate(CGAffineTransformMakeRotation(rad(90)), 0, -img.size.height);
            break;
        case UIImageOrientationRight:
            rectTransform = CGAffineTransformTranslate(CGAffineTransformMakeRotation(rad(-90)), -img.size.width, 0);
            break;
        case UIImageOrientationDown:
            rectTransform = CGAffineTransformTranslate(CGAffineTransformMakeRotation(rad(-180)), -img.size.width, -img.size.height);
            break;
        default:
            rectTransform = CGAffineTransformIdentity;
    };

    return CGAffineTransformScale(rectTransform, img.scale, img.scale);
}


- (UIImage *)croppedImage:(UIImage*)orignialImage InRect:(CGRect)visibleRect{
    //transform visible rect to image orientation
    CGAffineTransform rectTransform = [self orientationTransformedRectOfImage:orignialImage];
    visibleRect = CGRectApplyAffineTransform(visibleRect, rectTransform);

    //crop image
    CGImageRef imageRef = CGImageCreateWithImageInRect([orignialImage CGImage], visibleRect);
    UIImage *result = [UIImage imageWithCGImage:imageRef scale:orignialImage.scale orientation:orignialImage.imageOrientation];
    CGImageRelease(imageRef);
    return result;
}
8
lbsweek

Extension UIImage à Swift. Vous n'avez pas vraiment besoin de faire tout ce que vous feuilletez. Objective-C original is here , mais j'ai ajouté le bit qui respecte l'alpha de l'image d'origine (grossièrement, mais cela permet de différencier les images opaques des images transparentes).

// from https://github.com/mbcharbonneau/UIImage-Categories/blob/master/UIImage%2BAlpha.m
// Returns true if the image has an alpha layer
    private func hasAlpha() -> Bool {
        guard let cg = self.cgImage else { return false }
        let alpha = cg.alphaInfo
        let retVal = (alpha == .first || alpha == .last || alpha == .premultipliedFirst || alpha == .premultipliedLast)
        return retVal
    }

    func normalizedImage() -> UIImage? {
        if self.imageOrientation == .up {
            return self
        }
        UIGraphicsBeginImageContextWithOptions(self.size, !self.hasAlpha(), self.scale)
        var rect = CGRect.zero
        rect.size = self.size
        self.draw(in: rect)
        let retVal = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return retVal
    }
7
Dan Rosenstark

J'ai converti le code de @Nicolas Miari answer en Swift 3 au cas où quelqu'un en aurait besoin

func fixOrientation() -> UIImage
{

    if self.imageOrientation == UIImageOrientation.up {
        return self
    }

    var transform = CGAffineTransform.identity

    switch self.imageOrientation {
    case .down, .downMirrored:
        transform = transform.translatedBy(x: self.size.width, y: self.size.height)
        transform = transform.rotated(by: CGFloat(M_PI));

    case .left, .leftMirrored:
        transform = transform.translatedBy(x: self.size.width, y: 0);
        transform = transform.rotated(by: CGFloat(M_PI_2));

    case .right, .rightMirrored:
        transform = transform.translatedBy(x: 0, y: self.size.height);
        transform = transform.rotated(by: CGFloat(-M_PI_2));

    case .up, .upMirrored:
        break
    }


    switch self.imageOrientation {

    case .upMirrored, .downMirrored:
        transform = transform.translatedBy(x: self.size.width, y: 0)
        transform = transform.scaledBy(x: -1, y: 1)

    case .leftMirrored, .rightMirrored:
        transform = transform.translatedBy(x: self.size.height, y: 0)
        transform = transform.scaledBy(x: -1, y: 1);

    default:
        break;
    }

    // Now we draw the underlying CGImage into a new context, applying the transform
    // calculated above.
    let ctx = CGContext(
        data: nil,
        width: Int(self.size.width),
        height: Int(self.size.height),
        bitsPerComponent: self.cgImage!.bitsPerComponent,
        bytesPerRow: 0,
        space: self.cgImage!.colorSpace!,
        bitmapInfo: UInt32(self.cgImage!.bitmapInfo.rawValue)
    )



    ctx!.concatenate(transform);

    switch self.imageOrientation {

    case .left, .leftMirrored, .right, .rightMirrored:
        // Grr...
        ctx?.draw(self.cgImage!, in: CGRect(x:0 ,y: 0 ,width: self.size.height ,height:self.size.width))

    default:
        ctx?.draw(self.cgImage!, in: CGRect(x:0 ,y: 0 ,width: self.size.width ,height:self.size.height))
        break;
    }

    // And now we just create a new UIImage from the drawing context
    let cgimg = ctx!.makeImage()

    let img = UIImage(cgImage: cgimg!)

    return img;

}
6
Waseem05

Merci à Waseem05 pour sa traduction Swift 3 mais sa méthode ne fonctionnait que pour moi lorsque je l’enveloppais dans une extension de UIImage et que je la plaçais à l’extérieur/au-dessous de la classe parente de la manière suivante:

extension UIImage {

        func fixOrientation() -> UIImage
        {

            if self.imageOrientation == UIImageOrientation.up {
            return self
        }

        var transform = CGAffineTransform.identity

        switch self.imageOrientation {
        case .down, .downMirrored:
            transform = transform.translatedBy(x: self.size.width, y: self.size.height)
            transform = transform.rotated(by: CGFloat(M_PI));

        case .left, .leftMirrored:
            transform = transform.translatedBy(x: self.size.width, y: 0);
            transform = transform.rotated(by: CGFloat(M_PI_2));

        case .right, .rightMirrored:
            transform = transform.translatedBy(x: 0, y: self.size.height);
            transform = transform.rotated(by: CGFloat(-M_PI_2));

        case .up, .upMirrored:
            break
        }


        switch self.imageOrientation {

        case .upMirrored, .downMirrored:
            transform = transform.translatedBy(x: self.size.width, y: 0)
            transform = transform.scaledBy(x: -1, y: 1)

        case .leftMirrored, .rightMirrored:
            transform = transform.translatedBy(x: self.size.height, y: 0)
            transform = transform.scaledBy(x: -1, y: 1);

        default:
            break;
        }

        // Now we draw the underlying CGImage into a new context, applying the transform
        // calculated above.
        let ctx = CGContext(
            data: nil,
            width: Int(self.size.width),
            height: Int(self.size.height),
            bitsPerComponent: self.cgImage!.bitsPerComponent,
            bytesPerRow: 0,
            space: self.cgImage!.colorSpace!,
            bitmapInfo: UInt32(self.cgImage!.bitmapInfo.rawValue)
        )



        ctx!.concatenate(transform);

        switch self.imageOrientation {

        case .left, .leftMirrored, .right, .rightMirrored:
            // Grr...
            ctx?.draw(self.cgImage!, in: CGRect(x:0 ,y: 0 ,width: self.size.height ,height:self.size.width))

        default:
            ctx?.draw(self.cgImage!, in: CGRect(x:0 ,y: 0 ,width: self.size.width ,height:self.size.height))
            break;
        }

        // And now we just create a new UIImage from the drawing context
        let cgimg = ctx!.makeImage()

        let img = UIImage(cgImage: cgimg!)

        return img;

    }
}

Puis appelé avec:

let correctedImage:UIImage = wonkyImage.fixOrientation()

Et tout allait bien alors! Apple devrait faciliter la suppression de l'orientation lorsque nous n'avons pas besoin de métadonnées d'orientation appareil photo avant/arrière et haut/bas/gauche/droite.

3
hawtakshun

Si vous avez besoin de faire pivoter et de fixer l'orientation de l'image en dessous de l'extension, cela serait utile.

extension UIImage {

public func imageRotatedByDegrees(degrees: CGFloat) -> UIImage {
    //Calculate the size of the rotated view's containing box for our drawing space
    let rotatedViewBox: UIView = UIView(frame: CGRect(x: 0, y: 0, width: self.size.width, height: self.size.height))
    let t: CGAffineTransform = CGAffineTransform(rotationAngle: degrees * CGFloat.pi / 180)
    rotatedViewBox.transform = t
    let rotatedSize: CGSize = rotatedViewBox.frame.size
    //Create the bitmap context
    UIGraphicsBeginImageContext(rotatedSize)
    let bitmap: CGContext = UIGraphicsGetCurrentContext()!
    //Move the Origin to the middle of the image so we will rotate and scale around the center.
    bitmap.translateBy(x: rotatedSize.width / 2, y: rotatedSize.height / 2)
    //Rotate the image context
    bitmap.rotate(by: (degrees * CGFloat.pi / 180))
    //Now, draw the rotated/scaled image into the context
    bitmap.scaleBy(x: 1.0, y: -1.0)
    bitmap.draw(self.cgImage!, in: CGRect(x: -self.size.width / 2, y: -self.size.height / 2, width: self.size.width, height: self.size.height))
    let newImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()!
    UIGraphicsEndImageContext()
    return newImage
}


public func fixedOrientation() -> UIImage {
    if imageOrientation == UIImageOrientation.up {
        return self
    }

    var transform: CGAffineTransform = CGAffineTransform.identity

    switch imageOrientation {
    case UIImageOrientation.down, UIImageOrientation.downMirrored:
        transform = transform.translatedBy(x: size.width, y: size.height)
        transform = transform.rotated(by: CGFloat.pi)
        break
    case UIImageOrientation.left, UIImageOrientation.leftMirrored:
        transform = transform.translatedBy(x: size.width, y: 0)
        transform = transform.rotated(by: CGFloat.pi/2)
        break
    case UIImageOrientation.right, UIImageOrientation.rightMirrored:
        transform = transform.translatedBy(x: 0, y: size.height)
        transform = transform.rotated(by: -CGFloat.pi/2)
        break
    case UIImageOrientation.up, UIImageOrientation.upMirrored:
        break
    }

    switch imageOrientation {
    case UIImageOrientation.upMirrored, UIImageOrientation.downMirrored:
        transform.translatedBy(x: size.width, y: 0)
        transform.scaledBy(x: -1, y: 1)
        break
    case UIImageOrientation.leftMirrored, UIImageOrientation.rightMirrored:
        transform.translatedBy(x: size.height, y: 0)
        transform.scaledBy(x: -1, y: 1)
    case UIImageOrientation.up, UIImageOrientation.down, UIImageOrientation.left, UIImageOrientation.right:
        break
    }

    let ctx: CGContext = CGContext(data: nil,
                                   width: Int(size.width),
                                   height: Int(size.height),
                                   bitsPerComponent: self.cgImage!.bitsPerComponent,
                                   bytesPerRow: 0,
                                   space: self.cgImage!.colorSpace!,
                                   bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue)!

    ctx.concatenate(transform)

    switch imageOrientation {
    case UIImageOrientation.left, UIImageOrientation.leftMirrored, UIImageOrientation.right, UIImageOrientation.rightMirrored:
        ctx.draw(self.cgImage!, in: CGRect(x: 0, y: 0, width: size.height, height: size.width))
    default:
        ctx.draw(self.cgImage!, in: CGRect(x: 0, y: 0, width: size.width, height: size.height))
        break
    }

    let cgImage: CGImage = ctx.makeImage()!

    return UIImage(cgImage: cgImage)
}

}

2
Dhaval H. Nena
extension UIImage {
    func fixImageOrientation() -> UIImage {
        UIGraphicsBeginImageContext(self.size)
        self.draw(at: .zero)
        let newImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return newImage ?? self
    }
}
  1. Créez une extension comme en haut.
  2. Appelez-le: imageView.image?.fixImageOrientation() ou UIImage(named: "someImage").fixImageOrientation()

  3. Bonne chance à tous!

1
Mihail Salari

Swift 3.0 version de la réponse de Tommy

let imageToDisplay = UIImage.init(cgImage: originalImage.cgImage!, scale: originalImage.scale, orientation: UIImageOrientation.up)
1

Inspiré de @Aqua Answer .....

en Objectif C

- (UIImage *)fixImageOrientation:(UIImage *)img {

   UIGraphicsBeginImageContext(img.size);
   [img drawAtPoint:CGPointZero];

   UIImage *newImg = UIGraphicsGetImageFromCurrentImageContext();
   UIGraphicsEndImageContext();

   if (newImg) {
       return newImg;
   }

   return img;
}
0
umakanta