解决UIImage显示方向和内存方向不一致的问题
程序员文章站
2022-06-24 20:33:33
解决UIImage显示方向和内存方向不一致的问题,iOS中的UIImage中有imageOrientation属性,该属性决定了UIImage在手机上显示时的方向。如果imageO...
解决UIImage显示方向和内存方向不一致的问题,iOS中的UIImage中有imageOrientation属性,该属性决定了UIImage在手机上显示时的方向。如果imageOrientation的值为left或right,那么显示出来的图像和实际图像在内存中的存储就存在90度的旋转问题。比如显示出来的图片是720*1280的,实际上该图在内存中是按1280*720存储的。
在*上折腾了一番,找到了下面靠谱的解决办法。
extension UIImage { func fixImageOrientation() -> 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; } }
上面的代码能根据UIImage中的imageOrientation去翻转图像的实际存储布局。
如果想任意角度旋转图像,比如来个30度?下面的函数可以实现。
func imageRotatedByDegrees(oldImage: UIImage, deg degrees: CGFloat) -> UIImage { //Calculate the size of the rotated view's containing box for our drawing space var rotatedViewBox: UIView = UIView(frame: CGRect(x: 0, y: 0, width: oldImage.size.width, height: oldImage.size.height)) print(oldImage.size.height) if (oldImage.imageOrientation == .right) { rotatedViewBox = UIView(frame: CGRect(x: 0, y: 0, width: oldImage.size.height, height: oldImage.size.width)) } 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(oldImage.cgImage!, in: CGRect(x: -oldImage.size.height / 2, y: -oldImage.size.width / 2, width: oldImage.size.height, height: oldImage.size.width)) let newImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()! UIGraphicsEndImageContext() return newImage }