I found several methods to rotate image by degrees in Swift but noone that works allright all the time. I want to rotate image by 90 degrees left or right. I think the best one is this:
class func imageRotated(_ oldImage: UIImage, byDegrees 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
}
It works and do what I want but there are few times when it deformes result so it's not rotated and just image size is changed or it's rotated by 180 degrees and image size is changed.
Before rotation:
Afteer rotation (menu is missing because it's automatically hidden):
What's weird is that this happens when I take photo in portrait. When I take photo in landscape the rotation works fine (even if I try to rotate several times and even if I rotate from landscape to portrait and than again to landscape, it's still works fine).
I saw some discussion about auto layout constraints problem but I am not sure if it's my problem and why it would for some cases work and for some won't. I have photos in collection cells and each cell has first UIScrollView and than in UIScrollView there is UIImageView with photo. All constraints are set to bounds.
If it helps I want only rotate by 90 or -90 degrees. This could maybe make method more simple andn fix easier.
Thanks for any help.
Actually the easiest and probably the best way is to create a view, put an image view on it, rotate the image view, resize the superview and create a screenshot of that view.
You do not actually add these views in the view hierarchy, you just use them to easily generate an image.
Why this is a good procedure is because the UIView
already has all the code written in it to fully support the core graphics. So there is no downside at all and you can be sure these procedures have already been polished by Apple.
So try this:
func transformImage(image: UIImage?, transform: CGAffineTransform) -> UIImage? {
guard let image = image else {
return nil
}
let view = UIView(frame: CGRect.zero)
let imageView = UIImageView(image: image)
imageView.transform = transform
view.addSubview(imageView)
imageView.frame.origin = CGPoint.zero
view.frame = CGRect(x: 0.0, y: 0.0, width: imageView.frame.size.width, height: imageView.frame.size.height)
UIGraphicsBeginImageContext(view.frame.size)
view.layer.render(in: UIGraphicsGetCurrentContext()!)
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
if let cgImage = newImage?.cgImage {
return UIImage(cgImage: cgImage)
} else {
return nil
}
}
As for issue in your procedure it is most likely because you discard the transform from the UIImage
. The CGImage
is basically a raw image representation and it has no idea about the rotations. The UIImage
does have imageOrientation
though. So what you would need to do to fix that is you need to generate the transformation matrix from the image orientation and use it.
So when you take an image with your device the CGImage
will always have the same orientation (landscape left or right). But the UIImage
will change the image orientation which is then used for representation.