Search code examples
iosimagerotationcore-graphicsimage-rotation

iOS rotate image inside canvas with CoreGraphics


I am trying to rotate an image that is placed inside rect and is covering only part of it.

enter image description here

I've came to this solution but could not get image to be rotated:

override func drawRect(rect: CGRect) {
    let context = UIGraphicsGetCurrentContext()

    // drawing some texts and lines

    // rotate myImage by 'angle'
    CGContextSaveGState(context)

    CGContextTranslateCTM(context, imageOffset.x, imageOffset.y)
    CGContextRotateCTM(context, angle)
    CGContextTranslateCTM(context, -imageOffset.x, -imageOffset.y)
    myImage?.drawInRect(CGRect(x: imageOffset.x, y: imageOffset.y, width: imageSize.width, height: imageSize.height))

    CGContextRestoreGState(context)

    // draw other stuff
}

Well, how to do it properly?


Solution

  • You're creating an image context, drawing an image into it, and then ending the context without ever outputting an image. Therefore you'll never see the output.

    You'll want to UIGraphicsGetImageFromCurrentImageContext() to get your rotated image out from the context, and then re-draw it in your view's context.

    Something like this should do the trick:

    /// returns the transform equivalent of rotating a rect around its center
    private func rotateTransformRectAroundCenter(rect:CGRect, angle:CGFloat) -> CGAffineTransform {
        let t = CGAffineTransformConcat(
            CGAffineTransformMakeTranslation(-rect.origin.x-rect.size.width*0.5, -rect.origin.y-rect.size.height*0.5),
            CGAffineTransformMakeRotation(angle)
        )
        return CGAffineTransformConcat(t, CGAffineTransformMakeTranslation(rect.size.width*0.5, rect.size.height*0.5))
    }
    
    override func drawRect(rect: CGRect) {
    
        // get current context
        let ctx = UIGraphicsGetCurrentContext()
    
        // the rect to draw the image in
        let rect = CGRect(x: 50, y: 50, width: 300, height: 300)
    
        // angle to rotate image by
        let angle = CGFloat(M_PI*0.25)
    
        // the image bounds
        let imgRect = CGRect(origin: CGPointZero, size: img.size)
    
        // transform of rotating image
        let imgRotate = rotateTransformRectAroundCenter(imgRect, angle: angle)
    
        // rotated image frame
        let rotatedImgFrame = CGRectApplyAffineTransform(imgRect, imgRotate)
    
        // transform of rotating image context
        let rotateContext = rotateTransformRectAroundCenter(rotatedImgFrame, angle: angle)
    
    
        // begin image context
        UIGraphicsBeginImageContextWithOptions(rotatedImgFrame.size, false, img.scale)
    
        let imgContext = UIGraphicsGetCurrentContext()
    
        // rotate image context
        CGContextConcatCTM(imgContext, rotateContext)
    
        // draw image in context
        img.drawInRect(CGRect(origin: CGPointZero, size: img.size))
    
        // get output from context
        let output = UIGraphicsGetImageFromCurrentImageContext()
    
        // end context
        UIGraphicsEndImageContext()
    
        // get the rotated rect for the image to be drawn in the main context
        var outputRect = CGRectApplyAffineTransform(rect, rotateTransformRectAroundCenter(rect, angle: angle))
        outputRect.origin = CGPoint(x: outputRect.origin.x+rect.origin.x, y: outputRect.origin.y+rect.origin.y)
    
        // draw image
        output.drawInRect(outputRect)
    }