解決UIImage顯示方向和記憶體方向不一致的問題
阿新 • • 發佈:2019-02-06
iOS中的UIImage中有imageOrientation屬性,該屬性決定了UIImage在手機上顯示時的方向。如果imageOrientation的值為left或right,那麼顯示出來的影象和實際影象在記憶體中的儲存就存在90度的旋轉問題。比如顯示出來的圖片是720*1280的,實際上該圖在記憶體中是按1280*720儲存的。
在stackoverflow上折騰了一番,找到了下面靠譜的解決辦法。
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
}