Cocoa – Adding mask and overlay to an image
Masking an image in cocoa framework sometimes is not that straightforward as it should be, therefore I’m sharing a code that accomplishes that task in a very simple and neat way.
Simply applying mask to an image using CGImageMaskCreate and assigning result image to UIImageView’s image property often doesn’t work properly – the result has black colour instead of transparent in masked regions. It may work only when your image has alpha channel.
But there is a more convenient way to achieve image mask. I have prepared a small class that extends UIView. It displays an image masked by given mask and in addition applies an overlay to the image. The class can display image with mask or overlay or with both at the same time.
Class is available for download here: DSMaskAndOverlayView.zip
In order to use it place a UIView in your layout using Interface Builder, make it subclass of DSMaskAndOverlayView (you can also layout it from code) and configure it by assigning images (UIImage) to image, mask and overlay properties.
The method used for image masking in the class is very simple. It actually makes use of CGImageMaskCreate to create masked image and draws it in drawRect method. This way we don’t need to worry about alpha channel in our image. Overlay is achieved by simply drawing given overlay image on top of the base or masked base image with use of kCGBlendModeOverlay blend mode.
That’s just a sample, you can easily add your own effects to this class.
The essential code of the class is listed below:
- (void)drawRect:(CGRect)rect
{
if (_image == nil) {
return;
}
if (_mask != nil) {
UIImage *masked = [self maskImage:_image withMask:_mask];
[masked drawInRect:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height) blendMode:kCGBlendModeNormal alpha:1.0];
} else {
[_image drawInRect:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height) blendMode:kCGBlendModeNormal alpha:1.0];
}
if (_overlay != nil) {
[_overlay drawInRect:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height) blendMode:kCGBlendModeOverlay alpha:1.0];
}
}
Masking function:
- (UIImage*) maskImage:(UIImage *)image withMask:(UIImage *)maskImage {
CGImageRef maskRef = maskImage.CGImage;
CGImageRef mask = CGImageMaskCreate(CGImageGetWidth(maskRef),
CGImageGetHeight(maskRef),
CGImageGetBitsPerComponent(maskRef),
CGImageGetBitsPerPixel(maskRef),
CGImageGetBytesPerRow(maskRef),
CGImageGetDataProvider(maskRef), NULL, false);
CGImageRef masked = CGImageCreateWithMask([image CGImage], mask);
UIImage *result = [UIImage imageWithCGImage:masked];
CGImageRelease(mask);
CGImageRelease(masked);
CGImageRelease(maskRef);
return result;
}
Usage:
... maskAndOverlayView.image = [UIImage imageNamed:@"my_image.png"]; maskAndOverlayView.mask = [UIImage imageNamed:@"my_mask.png"]; maskAndOverlayView.overlay = [UIImage imageNamed:@"my_overlay.png"];
In: Uncategorized · Tagged with: cocoa, objective-c
