I am unable to rotate the image by 90 degrees in swift. I have written below code but there is an error and doesn\'t compile
func imageRotatedByDegrees(old
This is an extension of UIImage
that targets Swift 4.0 and can rotate just the image without the need for a UIImageView
. Tested successfully that the image was rotated, and not just had its exif data changed.
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
}
}
To perform a 180 degree rotation, you can call it like this:
let rotatedImage = image.rotate(radians: .pi)
If for whatever reason it fails to rotate, the original image will then be returned.
Rotate image via UIGraphics Context is comparatively heavy operation. The problems you may seen loosing quality and memory increase.
I suggest you should try to rotate the layer or view itself.
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)
}
}
How to use
yourImageView.rotate(degrees: 40)
let angle = CGFloat(M_PI_2)
let tr = CGAffineTransform.identity.rotated(by: angle)
ImageView.transform = tr
Your code is not that far off from functional. You can apply the transform as you are doing directly to the bitmap, you don't need an intermediate view:
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
}
Also, if you're going to create a function that rotates an image, it is typically good form to include a clockwise: Bool
parameter that will interpret the degrees
argument as rotating clockwise or not. The implementation and appropriate conversion to radians I leave to you.
Also note that it's a bit hand-wavy on my part to assume that oldImage.size
is non-zero. If it is, force-unwrapping UIGraphicsGetCurrentContext()!
will probably crash. You should validate the oldImage
's size and if it's invalid just return oldImage
.
Your problem is that you use non-existing initializer for CGRect. If you want to use CGRect(origin:size:), then create origin properly, without width and height parameters. Or remove size parameter and use CGRect(x:y:width:height:).
Just replace this line
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))
with this one:
let rect = CGRect(origin: CGPoint(x: -oldImage.size.width / 2, y: -oldImage.size.height / 2), size: oldImage.size)
bitmap.draw(oldImage.cgImage!, in: rect)
ImageView?.transform = transform.rotated(by: (CGFloat(Double.pi / 2)))
Swift 4.2
Rotation - right. Works fine.