Search code examples
iosswiftuigraphicscontext

CGContextClipToMask is not clipping Image in iOS


I am trying to save a UIImage to the Photos gallery and am using the following method to do so:

func savePhoto() {
    UIGraphicsBeginImageContextWithOptions(CGSize(width: device.x, height: device.y), false, 2.0)
    CGContextClipToRect(UIGraphicsGetCurrentContext(), self.drawingCanvas)
    self.mainImageView.image?.drawInRect(CGRect(x: 0, y: 0, width: device.x, height: device.y), blendMode: CGBlendMode.Normal, alpha: 1.0)
    let image = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()

    UIImageWriteToSavedPhotosAlbum(image, self, "image:didFinishSavingWithError:contextInfo:", nil)
}

The image saves successfully, but the problem is that the image is not cropped to the size of the CGRect drawingCanvas but the exported image is the size of the respective screen.

Since drawingCanvas is only the size of about 2/3 of the screen, a large blank white area is left in the final image.

Also, if I print CGContextGetClipBoundingBox(UIGraphicsGetCurrentContext()) it prints the correct size, which is the same as drawingCanvas.

Anyone know why the final image is not being clipped?


Solution

  • CoreGraphics is clipping exactly how it's supposed to. "Clip" means "for subsequent drawing calls, draw only inside the rect I provide, and don't draw outside of it". That's why there are white areas outside of the image that you see.

    Clipping does not make your context smaller, and does not make the result image smaller. Clipping is not the same as cropping.

    If you want the result image to be smaller, you should change the size that you pass to UIGraphicsBeginImageContextWithOptions. It does not have to be based on any particular device.

    It's unclear from your question what size you really want. But, if you want it to be based on the size of the drawing canvas, use that instead:

    UIGraphicsBeginImageContextWithOptions(self.drawingCanvas, false, 2.0)
    self.mainImageView.image?.drawInRect(CGRect(origin: CGPoint.zero, size:self.drawingCanvas))
    let image = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()