iOS – UIImageView – 如何处理UIImage图像的方向

是否有可能设置UIImageView来处理图像的方向? 当我将UIImageView设置为方向为RIGHT的图像(这是来自相机胶卷的照片)时,图像被旋转到正确的位置,但是我想按正确的方向显示它,因为它已经拍摄了。

我知道我可以旋转图像数据,但它可以做到更优雅?

谢谢

如果我明白了,你想要做的就是无视UIImage的方向? 如果是这样的话,你可以这样做:

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

所以你正在创build一个新的UIImage,它的像素数据与原始数据相同(通过它的CGImage属性引用),但是你指定了一个不旋转数据的方向。

您可以完全避免手动进行转换和缩放自己,正如在这里回答an0所build议的:

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

UIImage方法大小和drawInRect的文档明确指出,他们考虑到方向。

我把Anomie的答案中的代码转换成了Swift的forms (复制粘贴上面的suvish valsan)

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

(我用自己replace了参数image所有参数,因为我的代码是UIImage上的扩展)。


编辑:斯威夫特3版本。

该方法返回一个可选的,因为许多中间调用可能会失败,我不喜欢使用!

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

(注意:Swift 3的版本是在Xcode 8.1下编译的,但是没有经过testing,可能会有拼写错误,宽度和高度混在一起,等等。

此方法首先检查UIImage的当前方向,然后以顺时针方向更改方向并返回UIImage。您可以将此图像显示为

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

这里是一个可行的示例鳕鱼,考虑到图像的方向:

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

UIImage在Swift中的扩展。 你根本不需要做所有的翻转。 Objective-C 原件在这里 ,但我已经添加了尊重原始图像的alpha(粗略地说,但它可以区分不透明图像和透明图像)的位。

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

我把@Nicolas Miari的代码转换成了Swift 3,以防有人需要

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

Swift 3.1

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

感谢Waseem05他的Swift 3的翻译,但是他的方法只有当我把它包装到UIImage的扩展中,并且放在父类的外部/下面时才工作,像这样:

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

然后用它来调用它:

 let correctedImage:UIImage = wonkyImage.fixOrientation() 

一切都很好! 当我们不需要前/后摄像头和上/下/左/右设备方向元数据时,苹果应该更容易放弃方向。

汤米的答案Swift 3.0版本

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