検証環境:
Xcode 12
Swift 5.3
今回は縦横の長さが違う画像を 90° 回転させた画像を作成する方法について。
表示上、回転するだけでよい場合は UIView の transform
プロパティを使うと簡単にできる。
let radians = 90 * CGFloat.pi / 180
imageView.transform = imageView.transform.rotated(by: radians)
アニメーション付き
UIViewPropertyAnimator.runningPropertyAnimator(
withDuration: 0.3, delay: 0.0, options: [.curveEaseOut]) {
self.imageView.transform = self.imageView.transform.rotated(by: .pi / 2)
} completion: { position in
}
そうではなくて、元の画像から 90° 毎回転させた画像を新たに作成したい場合には ImageContext に書き込んで作成する。
func rotateImage(_ image: UIImage, radians: CGFloat) -> UIImage {
let rotatedSize = CGRect(origin: .zero, size: image.size)
.applying(CGAffineTransform(rotationAngle: radians))
.integral.size
UIGraphicsBeginImageContextWithOptions(rotatedSize, false, image.scale)
let context = UIGraphicsGetCurrentContext()!
context.translateBy(x: rotatedSize.width / 2, y: rotatedSize.height / 2)
context.rotate(by: radians)
context.scaleBy(x: 1, y: -1)
context.translateBy(x: -image.size.width / 2, y: -image.size.height / 2)
context.draw(image.cgImage!, in: .init(origin: .zero, size: image.size))
let newImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return newImage
}
UIImage の Extension にする場合
extension UIImage {
func rotated(by radians: CGFloat) -> UIImage {
let rotatedSize = CGRect(origin: .zero, size: size)
.applying(CGAffineTransform(rotationAngle: radians))
.integral.size
UIGraphicsBeginImageContextWithOptions(rotatedSize, false, scale)
if let context = UIGraphicsGetCurrentContext(), let cgImage = cgImage {
context.translateBy(x: rotatedSize.width / 2, y: rotatedSize.height / 2)
context.rotate(by: radians)
context.scaleBy(x: 1, y: -1)
context.translateBy(x: -size.width / 2, y: -size.height / 2)
context.draw(cgImage, in: .init(origin: .zero, size: size))
let rotatedImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return rotatedImage ?? self
}
return self
}
}
動作確認用のViewControllerサンプル。
class RotateViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
imageView1.contentMode = .scaleAspectFit
imageView2.contentMode = .scaleAspectFit
imageView1.image = UIImage(named: "coffee")!
}
var angle: CGFloat = 0
func rotateImage(_ image: UIImage, clockwise: Bool) -> UIImage {
var newAngle = clockwise ? angle + 90 : angle - 90
if newAngle <= -360 || newAngle >= 360 {
newAngle = 0
}
angle = newAngle
let radians = angle * CGFloat.pi / 180
let rotatedSize = CGRect(origin: .zero, size: image.size)
.applying(CGAffineTransform(rotationAngle: radians))
.integral.size
UIGraphicsBeginImageContextWithOptions(rotatedSize, false, image.scale)
let context = UIGraphicsGetCurrentContext()!
context.translateBy(x: rotatedSize.width / 2, y: rotatedSize.height / 2)
context.rotate(by: radians)
context.scaleBy(x: 1, y: -1)
context.translateBy(x: -image.size.width / 2, y: -image.size.height / 2)
context.draw(image.cgImage!, in: .init(origin: .zero, size: image.size))
let newImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return newImage
}
@IBOutlet weak var imageView1: UIImageView!
@IBOutlet weak var imageView2: UIImageView!
@IBAction func handleLeftButton(_ sender: UIButton) {
let newImage = rotateImage(imageView1.image!, clockwise: false)
imageView2.image = newImage
}
@IBAction func handleRightButton(_ sender: UIButton) {
let newImage = rotateImage(imageView1.image!, clockwise: true)
imageView2.image = newImage
}
}
参考:
Swift - UIImageをCoreGraphicsで回転させる - Qiita