Search code examples
iphoneobjective-ccocoa-touchuiimage

How can I 'cut' a transparent hole in a UIImage?


I'm trying to cut an transparent square in a UIImage, however I honestly have no idea where/how to start.

Any help would be greatly appreciated.

Thanks!


Solution

  • Presume that your image is being displayed in a view - probably a UIImageView. Then we can punch a rectangular hole in that view by masking the view's layer. Every view has a layer. We will apply to this view's layer a mask which is itself a layer containing an image, which we will generate in code. The image will be black except for a clear rectangle somewhere in the middle. That clear rectangle will cause the hole in the image view.

    So, let self.iv be this UIImageView. Try running this code:

    CGRect r = self.iv.bounds;
    CGRect r2 = CGRectMake(20,20,40,40); // adjust this as desired!
    UIGraphicsBeginImageContextWithOptions(r.size, NO, 0);
    CGContextRef c = UIGraphicsGetCurrentContext();
    CGContextAddRect(c, r2);
    CGContextAddRect(c, r);
    CGContextEOClip(c);
    CGContextSetFillColorWithColor(c, [UIColor blackColor].CGColor);
    CGContextFillRect(c, r);
    UIImage* maskim = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    CALayer* mask = [CALayer layer];
    mask.frame = r;
    mask.contents = (id)maskim.CGImage;
    self.iv.layer.mask = mask;
    

    For example, in this image, the white square is not a superimposed square, it is a hole, showing the white of the window background behind it:

    enter image description here

    EDIT: I feel obligated, since I mentioned it in a comment, to show how to do the same thing with a CAShapeLayer. The result is exactly the same:

    CGRect r = self.iv.bounds;
    CGRect r2 = CGRectMake(20,20,40,40); // adjust this as desired!
    CAShapeLayer* lay = [CAShapeLayer layer];
    CGMutablePathRef path = CGPathCreateMutable();
    CGPathAddRect(path, nil, r2);
    CGPathAddRect(path, nil, r);
    lay.path = path;
    CGPathRelease(path);
    lay.fillRule = kCAFillRuleEvenOdd;
    self.iv.layer.mask = lay;