快速旋转 UIImage
Posted
技术标签:
【中文标题】快速旋转 UIImage【英文标题】:Rotate UIImage in swift 【发布时间】:2016-04-15 10:46:15 【问题描述】:我想顺时针旋转 UIImage。但是我当前的代码在某些时候旋转并在某些时候跳过旋转时不准确地执行功能。我希望我的 UIImage 在我的操作按钮上不断顺时针旋转。 这是我当前的代码:
imageView.image = imageView.image!.imageRotatedByDegrees(angle, flip: false)
angle = angle + 90
if angle > 360
angle = 0
【问题讨论】:
需要使用imageView.transform = CGAffineTransformMakeRotation(CGFloat(90) * CGFloat(M_PI) / 180.0) 我想旋转 UIImage,而不是 UIImageView swift 4中最简单的制作旋转图片的方法:http://***.com/a/53491799/341994 【参考方案1】:这对我有用:
工作正常:)
func imageRotatedByDegrees(oldImage: UIImage, deg degrees: CGFloat) -> UIImage
//Calculate the size of the rotated view's containing box for our drawing space
let rotatedViewBox: UIView = UIView(frame: CGRectMake(0, 0, oldImage.size.width, oldImage.size.height))
let t: CGAffineTransform = CGAffineTransformMakeRotation(degrees * CGFloat(M_PI / 180))
rotatedViewBox.transform = t
let rotatedSize: CGSize = rotatedViewBox.frame.size
//Create the bitmap context
UIGraphicsBeginImageContext(rotatedSize)
let bitmap: CGContextRef = UIGraphicsGetCurrentContext()!
//Move the origin to the middle of the image so we will rotate and scale around the center.
CGContextTranslateCTM(bitmap, rotatedSize.width / 2, rotatedSize.height / 2)
//Rotate the image context
CGContextRotateCTM(bitmap, (degrees * CGFloat(M_PI / 180)))
//Now, draw the rotated/scaled image into the context
CGContextScaleCTM(bitmap, 1.0, -1.0)
CGContextDrawImage(bitmap, CGRectMake(-oldImage.size.width / 2, -oldImage.size.height / 2, oldImage.size.width, oldImage.size.height), oldImage.CGImage)
let newImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage
斯威夫特 3:
func imageRotatedByDegrees(oldImage: UIImage, deg 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: oldImage.size.width, height: oldImage.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(oldImage.cgImage!, in: CGRect(x: -oldImage.size.width / 2, y: -oldImage.size.height / 2, width: oldImage.size.width, height: oldImage.size.height))
let newImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return newImage
【讨论】:
失去纵横比 ^^^^【参考方案2】: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)
@Jason,您应该在旋转之前修复图像的方向。
let image = oldimage.fixedOrientation().imageRotatedByDegrees(90.0)
【讨论】:
太棒了!唯一开箱即用的解决方案!谢谢! :) 很好的解决方案。非常感谢你。我在 SO 上尝试了很多解决方案,但这是唯一真正有效的解决方案。 唯一没有丢失纵横比的答案。完美 这太棒了!!谢谢!!干杯!! 这破坏了我的 PDF 图像的质量。 ://【参考方案3】:@Jason Chitla,我还不能发表评论,所以我将其发布为新答案。 @Albert 的上述解决方案有效,但仅适用于方形图像。问题是,
bitmap.draw(oldImage.cgImage!, in: CGRect(x: -oldImage.size.width / 2, y: -oldImage.size.height / 2, width: oldImage.size.width, height: oldImage.size.height))
还是用原来的大小,所以如果你把它旋转90度,纵横比是错误的。
对我有用的是使用新的 rotateSize,如下所示:
func imageRotatedByDegrees(oldImage: UIImage, deg 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: oldImage.size.width, height: oldImage.size.height))
let t: CGAffineTransform = CGAffineTransform(rotationAngle: degrees * CGFloat(M_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(M_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: -rotatedSize.width / 2, y: -rotatedSize.height / 2, width: rotatedSize.width, height: rotatedSize.height))
let newImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return newImage
【讨论】:
【参考方案4】:你可以创建一个这样的函数来让你的图像永远顺时针旋转:
override func viewDidLoad()
super.viewDidLoad()
let kRotationAnimationKey = "com.myapplication.rotationanimationkey"
func rotateView(view: UIView, duration: Double = 1)
if view.layer.animationForKey(kRotationAnimationKey) == nil
let rotationAnimation = CABasicAnimation(keyPath: "transform.rotation")
rotationAnimation.fromValue = 0.0
rotationAnimation.toValue = Float(M_PI * 2.0)
rotationAnimation.duration = duration
rotationAnimation.repeatCount = Float.infinity
view.layer.addAnimation(rotationAnimation, forKey: kRotationAnimationKey)
rotateView(self.imageView)
结果是:
【讨论】:
您正在旋转 UIView 而不是 UIImage,如果您正在使用照片应用程序并需要保存结果,这会产生很大的不同。【参考方案5】:对于那些需要 Swift 3 中 @Mughees 的代码的人:
func imageRotatedByDegrees(oldImage: UIImage, deg 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: oldImage.size.width, height: oldImage.size.height))
let t: CGAffineTransform = CGAffineTransform(rotationAngle: degrees * CGFloat(M_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(M_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.width / 2, y: -oldImage.size.height / 2, width: oldImage.size.width, height: oldImage.size.height))
let newImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return newImage
【讨论】:
这段代码可以很好地旋转图像,但是现在纵横比被颠倒了......旧图像的高度现在是宽度,反之亦然。有谁知道如何解决这一问题?我认为这是因为 rotateSize 不正确,但是当我尝试翻转它时,新图像会更小。【参考方案6】:这可能更简单,它是 Swift 5 语法:
// MARK: Rotate
extension UIImage
func rotate(radians: Float) -> UIImage?
var newSize = CGRect(origin: CGPoint.zero, size: self.size).applying(CGAffineTransform(rotationAngle: CGFloat(radians))).size
// Trim off the extremely small float value to prevent core graphics from rounding it up
newSize.width = floor(newSize.width)
newSize.height = floor(newSize.height)
UIGraphicsBeginImageContextWithOptions(newSize, false, self.scale)
let context = UIGraphicsGetCurrentContext()!
// Move origin to middle
context.translateBy(x: newSize.width/2, y: newSize.height/2)
// Rotate around middle
context.rotate(by: CGFloat(radians))
// Draw the image at its center
self.draw(in: CGRect(x: -self.size.width/2, y: -self.size.height/2, width: self.size.width, height: self.size.height))
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage
【讨论】:
这是唯一对我有用的解决方案,而不会改变我的 UISegementedControl 中图像的分辨率或比例【参考方案7】:我修复了@gleb 回答的第一个功能。那里不需要大小计算。我们应该用反向来做。 因为如果您使用@gleb 的函数将其尺寸设为 1149 x 356,那么您将获得尺寸为 357 x 1149 的图像。
extension UIImage
public func imageRotatedByDegrees(degrees: CGFloat) -> UIImage
let rotatedSize: CGSize = CGRect(x: 0, y: 0, width: self.size.height, height: self.size.width).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
【讨论】:
【参考方案8】:我相信使用CoreImage
发布解决方案是值得的。这只是几行,它对我很有用。
请注意:当得到最终的UIImage
时,必须先转换为CGImage
以尊重CIImage
的范围
extension UIImage
func imageRotated(by degrees: CGFloat) -> UIImage
let orientation = CGImagePropertyOrientation(imageOrientation)
// Create CIImage respecting image's orientation
guard let inputImage = CIImage(image: self)?.oriented(orientation)
else return self
// Rotate the image itself
let rotation = CGAffineTransform(rotationAngle: (degrees * CGFloat.pi / 180))
let outputImage = inputImage.transformed(by: rotation)
// Create CGImage first
guard let cgImage = CIContext().createCGImage(outputImage, from: outputImage.extent)
else return self
// Create output UIImage from CGImage
return UIImage(cgImage: cgImage)
【讨论】:
以上是关于快速旋转 UIImage的主要内容,如果未能解决你的问题,请参考以下文章