Rotate image with UIGraphicsImageRenderer?
Asked Answered
S

3

7

UIGraphicsImageRenderer was newly introduced in iOS 10. I was wondering if there is any possibility to rotate an UIImage with it (any custom angle). I know there is the classic way with CGContextRotateCTM.

Shook answered 22/8, 2016 at 21:39 Comment(0)
F
6

You can setup UIGraphicsImageRenderer to create an image and with that call the UIGraphicsGetCurrentContext() and rotate the context

let renderer = UIGraphicsImageRenderer(size:sizeOfImage)
let image = renderer.image(actions: { _ in
    let context = UIGraphicsGetCurrentContext()

    context?.translateBy(x: orgin.x, y: orgin.y)
    context?.rotate(by: angle)
    context?.draw(image.cgImage!, in: CGRect(origin: CGPoint(x: -orgin.x,y: -orgin.y), size: size))
}
return image
Fanniefannin answered 25/11, 2016 at 18:4 Comment(2)
Instead of grabbing the current context, I think you'd want to use the renderer's context.cgContext property since it's automatically managed.Belinda
As of 2021.10.23 this code does not work anymore.Fernandez
U
4

Built on @reza23's answer. You don't need to call UIGraphicsGetCurrentContext, you can use renderer's context.

extension UIImage {
    public func rotate(_ angle: Angle) -> UIImage {
        var newSize = CGRect(origin: CGPoint.zero, size: self.size).applying(CGAffineTransform(rotationAngle: angle.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)

        let image = UIGraphicsImageRenderer(size:newSize).image { renderer in
            let context = renderer.cgContext
            //rotate from center
            context.translateBy(x: newSize.width/2, y: newSize.height/2)
            context.rotate(by: angle.radians)
            draw(in:  CGRect(origin: CGPoint(x: -self.size.width/2, y: -self.size.height/2), size: size))
        }

        return image
    }
}
Unsustainable answered 10/7, 2020 at 12:29 Comment(0)
S
2

Going through the documentation and also due to the lack of replies on this question, I assume that it is not possible with the new UIGraphicsImageRenderer. Here is how I solved it at the end of the day:

func changeImageRotation(forImage image:UIImage, rotation alpha:CGFloat) -> UIImage{

    var newSize:CGSize{
        let a = image.size.width
        let b = image.size.height

        let width = abs(cos(alpha)) * a + abs(sin(alpha)) * b
        let height = abs(cos(alpha)) * b + abs(sin(alpha)) * a

        return CGSize(width: width, height: height)
    }

    let size = newSize
    let orgin = CGPoint(x: size.width/2, y: size.height/2)

    UIGraphicsBeginImageContext(size)
    let context = UIGraphicsGetCurrentContext()

    context?.translateBy(x: orgin.x, y: orgin.y)
    context?.rotate(by: alpha)
    context?.draw(image.cgImage!, in: CGRect(origin: CGPoint(x: -orgin.x,y: -orgin.y), size: size))

    let newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return newImage!
}

New Sizecorresponds to the rectangular area that is required to draw the rotated image without changing its overall size. The image is than rotated and drawn in the center. For more information on that, refer to this post.

Shook answered 23/8, 2016 at 21:54 Comment(1)
Cool but expensive (performance). Hope there's a better wayArmenian

© 2022 - 2024 — McMap. All rights reserved.