如何在 Swift 中旋转图像?
How to rotate image in Swift?
我无法在 swift 中将图像旋转 90 度。我已经写了下面的代码但是有一个错误并且没有编译
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, in: CGRect(origin: (x: -oldImage.size.width / 2, y: -oldImage.size.height / 2, width: oldImage.size.width, height: oldImage.size.height), size: oldImage.cgImage))
let newImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return newImage
}
下面是我不确定的代码
bitmap.draw(oldImage, in: CGRect(origin: (x: -oldImage.size.width / 2, y: -oldImage.size.height / 2, width: oldImage.size.width, height: oldImage.size.height), size: oldImage.cgImage))
let angle = CGFloat(M_PI_2)
let tr = CGAffineTransform.identity.rotated(by: angle)
ImageView.transform = tr
设置ImageView图片
ImageView.transform = ImageView.transform.rotated(by: CGFloat(M_PI_2))
Swift 5
ImageView.transform = ImageView.transform.rotated(by: .pi) // 180˚
ImageView.transform = ImageView.transform.rotated(by: .pi / 2) // 90˚
ImageView.transform = ImageView.transform.rotated(by: .pi * 1.5) // 270˚
您的代码离正常运行不远了。您可以直接对位图应用变换,不需要中间视图:
func imageRotatedByDegrees(oldImage: UIImage, deg degrees: CGFloat) -> UIImage {
let size = oldImage.size
UIGraphicsBeginImageContext(size)
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: size.width / 2, y: size.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)
let origin = CGPoint(x: -size.width / 2, y: -size.width / 2)
bitmap.draw(oldImage.cgImage!, in: CGRect(origin: origin, size: size))
let newImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return newImage
}
此外,如果您要创建一个旋转图像的函数,通常最好包含一个 clockwise: Bool
参数,该参数会将 degrees
参数解释为是否顺时针旋转.我留给你的实现和适当的弧度转换。
另请注意,我认为 oldImage.size
不为零有点牵强。如果是,强制展开 UIGraphicsGetCurrentContext()!
可能会崩溃。您应该验证 oldImage
的大小,如果它无效只是 return oldImage
.
您的问题是您对 CGRect 使用了不存在的初始值设定项。如果你想使用 CGRect(origin:size:),然后正确创建原点,没有宽度和高度参数。或者删除大小参数并使用 CGRect(x:y:width:height:).
只需替换这一行
bitmap.draw(oldImage, in: CGRect(origin: (x: -oldImage.size.width / 2, y: -oldImage.size.height / 2, width: oldImage.size.width, height: oldImage.size.height), size: oldImage.cgImage))
这个:
let rect = CGRect(origin: CGPoint(x: -oldImage.size.width / 2, y: -oldImage.size.height / 2), size: oldImage.size)
bitmap.draw(oldImage.cgImage!, in: rect)
您可以使用下面的代码 Swift 3:
extension UIImage {
func fixImageOrientation() -> UIImage? {
var flip:Bool = false //used to see if the image is mirrored
var isRotatedBy90:Bool = false // used to check whether aspect ratio is to be changed or not
var transform = CGAffineTransform.identity
//check current orientation of original image
switch self.imageOrientation {
case .down, .downMirrored:
transform = transform.rotated(by: CGFloat(M_PI));
case .left, .leftMirrored:
transform = transform.rotated(by: CGFloat(M_PI_2));
isRotatedBy90 = true
case .right, .rightMirrored:
transform = transform.rotated(by: CGFloat(-M_PI_2));
isRotatedBy90 = true
case .up, .upMirrored:
break
}
switch self.imageOrientation {
case .upMirrored, .downMirrored:
transform = transform.translatedBy(x: self.size.width, y: 0)
flip = true
case .leftMirrored, .rightMirrored:
transform = transform.translatedBy(x: self.size.height, y: 0)
flip = true
default:
break;
}
// calculate the size of the rotated view's containing box for our drawing space
let rotatedViewBox = UIView(frame: CGRect(origin: CGPoint(x:0, y:0), size: size))
rotatedViewBox.transform = transform
let rotatedSize = rotatedViewBox.frame.size
// Create the bitmap context
UIGraphicsBeginImageContext(rotatedSize)
let bitmap = 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.0, y: rotatedSize.height / 2.0);
// Now, draw the rotated/scaled image into the context
var yFlip: CGFloat
if(flip){
yFlip = CGFloat(-1.0)
} else {
yFlip = CGFloat(1.0)
}
bitmap!.scaleBy(x: yFlip, y: -1.0)
//check if we have to fix the aspect ratio
if isRotatedBy90 {
bitmap?.draw(self.cgImage!, in: CGRect(x: -size.width / 2, y: -size.height / 2, width: size.height,height: size.width))
} else {
bitmap?.draw(self.cgImage!, in: CGRect(x: -size.width / 2, y: -size.height / 2, width: size.width,height: size.height))
}
let fixedImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return fixedImage
}
您可以先在 imageView 中设置图片,然后在 imageView 中旋转获取图片
这里:
let customImageView = UIImageView()
customImageView.frame = CGRect.init(x: 0, y: 0, w: 250, h: 250)
customImageView.image = UIImage(named: "yourImage")
customImageView .transform = customImageView .transform.rotated(by: CGFloat.init(M_PI_2))
var rotatedImage = UIImage()
rotatedImage = customImageView.image!
这是 UIImage
的扩展,目标是 Swift 4.0,可以只旋转图像而不需要 UIImageView
。成功测试图像已旋转,而不仅仅是其 exif 数据已更改。
import UIKit
extension UIImage {
func rotate(radians: CGFloat) -> UIImage {
let rotatedSize = CGRect(origin: .zero, size: size)
.applying(CGAffineTransform(rotationAngle: CGFloat(radians)))
.integral.size
UIGraphicsBeginImageContext(rotatedSize)
if let context = UIGraphicsGetCurrentContext() {
let origin = CGPoint(x: rotatedSize.width / 2.0,
y: rotatedSize.height / 2.0)
context.translateBy(x: origin.x, y: origin.y)
context.rotate(by: radians)
draw(in: CGRect(x: -origin.y, y: -origin.x,
width: size.width, height: size.height))
let rotatedImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return rotatedImage ?? self
}
return self
}
}
要执行180度旋转,可以这样调用:
let rotatedImage = image.rotate(radians: .pi)
如果由于某种原因旋转失败,将返回原始图像。
一行:
rotatedViewBox.transform = CGAffineTransform(rotationAngle: CGFloat.pi/2)
在 Swift 4.2 和 Xcode 10.0
dropDownImageView.transform = dropDownImageView.transform.rotated(by: CGFloat(Double.pi / 2))
如果要添加动画...
UIView.animate(withDuration: 2.0, animations: {
self.dropDownImageView.transform = self.dropDownImageView.transform.rotated(by: CGFloat(Double.pi / 2))
})
通过UIGraphics Context旋转图片是比较繁重的操作。您可能会看到质量下降和内存增加的问题。
我建议您尝试旋转图层或查看自身。
extension UIView {
func rotate(degrees: CGFloat) {
let degreesToRadians: (CGFloat) -> CGFloat = { (degrees: CGFloat) in
return degrees / 180.0 * CGFloat.pi
}
self.transform = CGAffineTransform(rotationAngle: degreesToRadians(degrees))
// If you like to use layer you can uncomment the following line
//layer.transform = CATransform3DMakeRotation(degreesToRadians(degrees), 0.0, 0.0, 1.0)
}
}
如何使用
yourImageView.rotate(degrees: 40)
ImageView?.transform = transform.rotated(by: (CGFloat(Double.pi / 2)))
Swift 4.2
旋转 - 右。工作正常。
如果你只是不想特定的旋转,喜欢一个一个地使用所有方向。
func rotateImage() -> UIImage {
let newOrientation = Orientation(rawValue: self.imageOrientation.rawValue + 1) ?? UIImage.Orientation(rawValue: 0)
return UIImage(cgImage: self.cgImage!, scale: self.scale, orientation: newOrientation!)
}
UIGraphicsBeginImageContext(CGSize(width: bitmap.width, height: bitmap.height))
UIImage(cgImage: oldImage.cgImage, scale: 1, orientation: .leftMirrored).draw(at: .zero)
let image = UIGraphicsGetImageFromCurrentImageContext()!
短得多。
要开始旋转图像视图:
func startSpinning() {
UIView.animate(withDuration: 0.5, delay: 0, options: .repeat, animations: { () -> Void in
self.gearImageView!.transform = self.gearImageView!.transform.rotated(by: .pi / 2)
})
}
停止旋转:
func stopSpinning() {
self.gearImageView.layer.removeAllAnimations()
}
我无法在 swift 中将图像旋转 90 度。我已经写了下面的代码但是有一个错误并且没有编译
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, in: CGRect(origin: (x: -oldImage.size.width / 2, y: -oldImage.size.height / 2, width: oldImage.size.width, height: oldImage.size.height), size: oldImage.cgImage))
let newImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return newImage
}
下面是我不确定的代码
bitmap.draw(oldImage, in: CGRect(origin: (x: -oldImage.size.width / 2, y: -oldImage.size.height / 2, width: oldImage.size.width, height: oldImage.size.height), size: oldImage.cgImage))
let angle = CGFloat(M_PI_2)
let tr = CGAffineTransform.identity.rotated(by: angle)
ImageView.transform = tr
设置ImageView图片
ImageView.transform = ImageView.transform.rotated(by: CGFloat(M_PI_2))
Swift 5
ImageView.transform = ImageView.transform.rotated(by: .pi) // 180˚
ImageView.transform = ImageView.transform.rotated(by: .pi / 2) // 90˚
ImageView.transform = ImageView.transform.rotated(by: .pi * 1.5) // 270˚
您的代码离正常运行不远了。您可以直接对位图应用变换,不需要中间视图:
func imageRotatedByDegrees(oldImage: UIImage, deg degrees: CGFloat) -> UIImage {
let size = oldImage.size
UIGraphicsBeginImageContext(size)
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: size.width / 2, y: size.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)
let origin = CGPoint(x: -size.width / 2, y: -size.width / 2)
bitmap.draw(oldImage.cgImage!, in: CGRect(origin: origin, size: size))
let newImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return newImage
}
此外,如果您要创建一个旋转图像的函数,通常最好包含一个 clockwise: Bool
参数,该参数会将 degrees
参数解释为是否顺时针旋转.我留给你的实现和适当的弧度转换。
另请注意,我认为 oldImage.size
不为零有点牵强。如果是,强制展开 UIGraphicsGetCurrentContext()!
可能会崩溃。您应该验证 oldImage
的大小,如果它无效只是 return oldImage
.
您的问题是您对 CGRect 使用了不存在的初始值设定项。如果你想使用 CGRect(origin:size:),然后正确创建原点,没有宽度和高度参数。或者删除大小参数并使用 CGRect(x:y:width:height:).
只需替换这一行
bitmap.draw(oldImage, in: CGRect(origin: (x: -oldImage.size.width / 2, y: -oldImage.size.height / 2, width: oldImage.size.width, height: oldImage.size.height), size: oldImage.cgImage))
这个:
let rect = CGRect(origin: CGPoint(x: -oldImage.size.width / 2, y: -oldImage.size.height / 2), size: oldImage.size)
bitmap.draw(oldImage.cgImage!, in: rect)
您可以使用下面的代码 Swift 3:
extension UIImage {
func fixImageOrientation() -> UIImage? {
var flip:Bool = false //used to see if the image is mirrored
var isRotatedBy90:Bool = false // used to check whether aspect ratio is to be changed or not
var transform = CGAffineTransform.identity
//check current orientation of original image
switch self.imageOrientation {
case .down, .downMirrored:
transform = transform.rotated(by: CGFloat(M_PI));
case .left, .leftMirrored:
transform = transform.rotated(by: CGFloat(M_PI_2));
isRotatedBy90 = true
case .right, .rightMirrored:
transform = transform.rotated(by: CGFloat(-M_PI_2));
isRotatedBy90 = true
case .up, .upMirrored:
break
}
switch self.imageOrientation {
case .upMirrored, .downMirrored:
transform = transform.translatedBy(x: self.size.width, y: 0)
flip = true
case .leftMirrored, .rightMirrored:
transform = transform.translatedBy(x: self.size.height, y: 0)
flip = true
default:
break;
}
// calculate the size of the rotated view's containing box for our drawing space
let rotatedViewBox = UIView(frame: CGRect(origin: CGPoint(x:0, y:0), size: size))
rotatedViewBox.transform = transform
let rotatedSize = rotatedViewBox.frame.size
// Create the bitmap context
UIGraphicsBeginImageContext(rotatedSize)
let bitmap = 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.0, y: rotatedSize.height / 2.0);
// Now, draw the rotated/scaled image into the context
var yFlip: CGFloat
if(flip){
yFlip = CGFloat(-1.0)
} else {
yFlip = CGFloat(1.0)
}
bitmap!.scaleBy(x: yFlip, y: -1.0)
//check if we have to fix the aspect ratio
if isRotatedBy90 {
bitmap?.draw(self.cgImage!, in: CGRect(x: -size.width / 2, y: -size.height / 2, width: size.height,height: size.width))
} else {
bitmap?.draw(self.cgImage!, in: CGRect(x: -size.width / 2, y: -size.height / 2, width: size.width,height: size.height))
}
let fixedImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return fixedImage
}
您可以先在 imageView 中设置图片,然后在 imageView 中旋转获取图片
这里:
let customImageView = UIImageView()
customImageView.frame = CGRect.init(x: 0, y: 0, w: 250, h: 250)
customImageView.image = UIImage(named: "yourImage")
customImageView .transform = customImageView .transform.rotated(by: CGFloat.init(M_PI_2))
var rotatedImage = UIImage()
rotatedImage = customImageView.image!
这是 UIImage
的扩展,目标是 Swift 4.0,可以只旋转图像而不需要 UIImageView
。成功测试图像已旋转,而不仅仅是其 exif 数据已更改。
import UIKit
extension UIImage {
func rotate(radians: CGFloat) -> UIImage {
let rotatedSize = CGRect(origin: .zero, size: size)
.applying(CGAffineTransform(rotationAngle: CGFloat(radians)))
.integral.size
UIGraphicsBeginImageContext(rotatedSize)
if let context = UIGraphicsGetCurrentContext() {
let origin = CGPoint(x: rotatedSize.width / 2.0,
y: rotatedSize.height / 2.0)
context.translateBy(x: origin.x, y: origin.y)
context.rotate(by: radians)
draw(in: CGRect(x: -origin.y, y: -origin.x,
width: size.width, height: size.height))
let rotatedImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return rotatedImage ?? self
}
return self
}
}
要执行180度旋转,可以这样调用:
let rotatedImage = image.rotate(radians: .pi)
如果由于某种原因旋转失败,将返回原始图像。
一行:
rotatedViewBox.transform = CGAffineTransform(rotationAngle: CGFloat.pi/2)
在 Swift 4.2 和 Xcode 10.0
dropDownImageView.transform = dropDownImageView.transform.rotated(by: CGFloat(Double.pi / 2))
如果要添加动画...
UIView.animate(withDuration: 2.0, animations: {
self.dropDownImageView.transform = self.dropDownImageView.transform.rotated(by: CGFloat(Double.pi / 2))
})
通过UIGraphics Context旋转图片是比较繁重的操作。您可能会看到质量下降和内存增加的问题。
我建议您尝试旋转图层或查看自身。
extension UIView {
func rotate(degrees: CGFloat) {
let degreesToRadians: (CGFloat) -> CGFloat = { (degrees: CGFloat) in
return degrees / 180.0 * CGFloat.pi
}
self.transform = CGAffineTransform(rotationAngle: degreesToRadians(degrees))
// If you like to use layer you can uncomment the following line
//layer.transform = CATransform3DMakeRotation(degreesToRadians(degrees), 0.0, 0.0, 1.0)
}
}
如何使用
yourImageView.rotate(degrees: 40)
ImageView?.transform = transform.rotated(by: (CGFloat(Double.pi / 2)))
Swift 4.2
旋转 - 右。工作正常。
如果你只是不想特定的旋转,喜欢一个一个地使用所有方向。
func rotateImage() -> UIImage {
let newOrientation = Orientation(rawValue: self.imageOrientation.rawValue + 1) ?? UIImage.Orientation(rawValue: 0)
return UIImage(cgImage: self.cgImage!, scale: self.scale, orientation: newOrientation!)
}
UIGraphicsBeginImageContext(CGSize(width: bitmap.width, height: bitmap.height))
UIImage(cgImage: oldImage.cgImage, scale: 1, orientation: .leftMirrored).draw(at: .zero)
let image = UIGraphicsGetImageFromCurrentImageContext()!
短得多。
要开始旋转图像视图:
func startSpinning() {
UIView.animate(withDuration: 0.5, delay: 0, options: .repeat, animations: { () -> Void in
self.gearImageView!.transform = self.gearImageView!.transform.rotated(by: .pi / 2)
})
}
停止旋转:
func stopSpinning() {
self.gearImageView.layer.removeAllAnimations()
}