objective animatedimage ios uiimageview uiimage orientation

ios - animatedimage - objective c uiimage



iOS-UIImageView-cómo manejar la orientación de la imagen UIImage (10)

Convertí el código de @Nicolas Miari en respuesta a Swift 3 en caso de que alguien lo necesite

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; }

¿Es posible configurar UIImageView para manejar la orientación de la imagen? Cuando configuro el UIImageView en la imagen con la orientación DERECHA (es una foto del rollo de la cámara), la imagen se gira a la derecha, pero quiero mostrarla en la orientación correcta, tal como se tomó.

Sé que puedo rotar los datos de imagen, pero es posible hacerlo de forma más elegante?

Gracias


Convertí el código en la respuesta de Anomie aquí (copia-pegada arriba por 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; }

(Reemplacé todas las occurencies de la image parámetro con self , porque mi código es una extensión en UIImage ).

EDITAR: versión Swift 3.

El método devuelve una opción, porque muchas de las llamadas intermedias pueden fallar y no me gusta usarlas ! .

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; }

(Nota: Swift 3 version odes compila bajo Xcode 8.1, pero no lo ha probado realmente funciona. Puede haber un error tipográfico en alguna parte, mezclado de ancho / alto, etc. No dude en señalar / corregir cualquier error).


Este método primero verifica la orientación actual de UIImage y luego cambia la orientación en el sentido de las agujas del reloj y regresa el UIImage. Puedes mostrar esta imagen como

self.imageView.image = rotateImage (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 versión

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 }


Extensión UIImage en Swift. No es necesario que hagas todo eso volteando, en realidad. El original de Objective-C está aquí , pero he agregado el bit que respeta el alfa de la imagen original (crudamente, pero funciona para diferenciar las imágenes opacas de las 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 }


Gracias a Waseem05 por su traducción de Swift 3, pero su método solo funcionó para mí cuando lo envolví dentro de una extensión de UIImage y lo coloqué fuera / debajo de la clase de padres como tal:

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; } }

Luego lo llamó con:

let correctedImage:UIImage = wonkyImage.fixOrientation()

¡Y todo fue bien entonces! Apple debería facilitar la descarte de la orientación cuando no necesitamos la cámara frontal / posterior y los metadatos de orientación hacia arriba / abajo / izquierda / derecha del dispositivo.


Puede evitar por completo hacer las transformaciones y escalar manualmente, como lo sugiere an0 en esta respuesta here :

- (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 documentación para el size métodos UIImage y drawInRect establece explícitamente que tienen en cuenta la orientación.


Si lo entiendo, ¿qué quieres hacer es ignorar la orientación del UIImage? Si es así, podrías hacer esto:

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

Así que está creando un nuevo UIImage con los mismos datos de píxeles que el original (al que se hace referencia a través de su propiedad CGImage) pero está especificando una orientación que no rota los datos.


Swift 3.0 versión de la respuesta de Tommy

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


Swift 3.1

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


aquí hay un bacalao de muestra viable, teniendo en cuenta la orientación de la imagen:

#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; }