¿Es posible configurarlo UIImageView
para manejar la orientación de la imagen? Cuando configuro la UIImageView
imagen con la orientación DERECHA (es una foto del rollo de la cámara), la imagen se gira hacia la derecha, pero quiero mostrarla en la orientación adecuada, tal como fue tomada.
Sé que puedo rotar datos de imagen pero ¿es posible hacerlo de forma más elegante?
ios
uiimageview
uiimage
orientation
Martín Pilch
fuente
fuente
CGContext
conCGBitmapContextCreate
(o con laUIGraphicsBeginImageContext
abreviatura), usaríaCGContextRotateCTM
para establecer una rotación, usaríadrawInRect:
enUIImage
oCGContextDrawImage
con laCGImage
propiedad de la imagen , luego convertiría el contexto en una imagen conUIGraphicsGetImageFromCurrentImageContext
(y, luego,UIGraphicsEndImageContext
) si usó UIKit para crear el contexto, oCGBitmapContextCreateImage
si se quedaba con Core Graphics. UIKit no es muy seguro para subprocesos, pero el código sería más ordenado.Puede evitar por completo hacer manualmente las transformaciones y escalar usted mismo, como sugiere an0 en esta respuesta aquí :
- (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 tamaño de los métodos UIImage y drawInRect declara explícitamente que tienen en cuenta la orientación.
fuente
Convertí el código en la respuesta de Anomie aquí (copia y pegó 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 ocurrencias del parámetro
image
conself
, porque mi código es una extensión activadaUIImage
).EDITAR: Swift 3 versión.
El método devuelve un opcional, porque muchas de las llamadas intermedias pueden fallar y no me gusta usar
!
.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: las versiones de Swift 3 se compilan bajo Xcode 8.1, pero no lo he probado en realidad funciona. Puede haber un error tipográfico en alguna parte, mezcla de ancho / alto, etc. No dude en señalar / corregir cualquier error).
fuente
func viewDidLoad
. Esta imagen es del teléfono samsung photos.google.com/share/… y tiene datos exif de orientación 270 CW. Aquí cómo lo usolet background: UIImage? = UIImage(named: "background_image")?.fixOrientation() backgroundImage.image = background
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 devuelve UIImage. Puede mostrar esta imagen como
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; }
Versión Swift 4
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 }
fuente
Swift 3.1
func fixImageOrientation(_ image: UIImage)->UIImage { UIGraphicsBeginImageContext(image.size) image.draw(at: .zero) let newImage = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() return newImage ?? image }
fuente
Extensión de UIImage en Swift. En realidad, no es necesario que hagas todos esos giros. El original de Objective-C está aquí , pero agregué el bit que respeta el alfa de la imagen original (crudamente, pero funciona para diferenciar imágenes opacas de imágenes 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 }
fuente
aquí hay un bacalao de muestra viable, considerando 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; }
fuente
Convertí el código de la respuesta de @Nicolas Miari 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; }
fuente
imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any] let imageCaptured:UIImage = info[UIImagePickerControllerOriginalImage] as! UIImage
imagen siempre es correcta La orientación y este método devuelve la imagen :(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 principal así:
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 entonces todo estuvo bien! Apple debería facilitar el descarte de la orientación cuando no necesitamos la cámara frontal / trasera y los metadatos de orientación del dispositivo arriba / abajo / izquierda / derecha.
fuente
Si necesita rotar y corregir la orientación de la imagen debajo de la extensión, sería útil.
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) } }
fuente
extension UIImage { func fixImageOrientation() -> UIImage { UIGraphicsBeginImageContext(self.size) self.draw(at: .zero) let newImage = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() return newImage ?? self } }
Llámalo:
imageView.image?.fixImageOrientation()
oUIImage(named: "someImage").fixImageOrientation()
¡Buena suerte a todos!
fuente
Versión rápida 3.0 de la respuesta de Tommy
let imageToDisplay = UIImage.init(cgImage: originalImage.cgImage!, scale: originalImage.scale, orientation: UIImageOrientation.up)
fuente
Inspirado en @Aqua Answer .....
en el objetivo C
- (UIImage *)fixImageOrientation:(UIImage *)img { UIGraphicsBeginImageContext(img.size); [img drawAtPoint:CGPointZero]; UIImage *newImg = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); if (newImg) { return newImg; } return img; }
fuente