I'm working on an app where I draw a UIView via code and I fill it with a UIColor. Next thing I want to load a mask.png file (no transparency, just black and white) and mask the UIView to change its visual appearance.
Any idea how to do this?
// Create your mask layer CALayer* maskLayer = [CALayer layer]; maskLayer.frame = CGRectMake(0,0,yourMaskWidth ,yourMaskHeight); maskLayer.contents = (__bridge id)[[UIImage imageNamed:@"yourMaskImage.png"] CGImage]; // Apply the mask to your uiview layer yourUIView.layer.mask = maskLayer; Remember to import QuartzCore and add the framework
#import <QuartzCore/QuartzCore.h> It is very easy but I didn't find the answer anywhere!
iOS 8 introduces the maskView property which allows you to use an alternate view to provide the mask image. In Swift:
if let maskImage = UIImage(named: "MaskImage") { myView.maskView = UIImageView(image: maskImage) } Note that you need to supply an image which actually has transparency; an image with white parts (for opaque) and black parts (for transparent) won't work.
You might be able to use CGContextClipToMask:
-(void) drawRect:(CGRect)dirty { CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSaveGState( context ); CGContextClipToMask( context , [self bounds] , [self maskImage] ); [super drawRect:dirty]; // or draw your color manually CGContextRestoreGState( context ); } I have create a category with the code above :
UIView+ImageMask.h :
#import <UIKit/UIKit.h> @interface UIView (ImageMask) - (void) maskWithImage:(UIImage*) mask; - (void) maskWithImage:(UIImage*)mask size:(CGSize)maskSize; - (void) removeMask; @end UIView+ImageMask.m :
#import <QuartzCore/QuartzCore.h> #import "UIView+ImageMask.h" @implementation UIView (ImageMask) - (void) maskWithImage:(UIImage*) mask { [self maskWithImage:mask size:mask.size]; } - (void) maskWithImage:(UIImage*)mask size:(CGSize)maskSize { CALayer* maskLayer = [CALayer layer]; maskLayer.frame = CGRectMake(0, 0, maskSize.size.width, maskSize.size.height); maskLayer.contents = (__bridge id)[mask CGImage]; // Apply the mask to your uiview layer self.layer.mask = maskLayer; } - (void) removeMask { self.layer.mask = nil; } @end Thanks drawnonward,
ended up with this function:
- (UIImage*) maskImage:(UIView *)image withMask:(UIImage *)maskImage { UIGraphicsBeginImageContext(image.bounds.size); [image.layer renderInContext:UIGraphicsGetCurrentContext()]; UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); CGImageRef maskRef = maskImage.CGImage; CGImageRef mask = CGImageMaskCreate(CGImageGetWidth(maskRef), CGImageGetHeight(maskRef), CGImageGetBitsPerComponent(maskRef), CGImageGetBitsPerPixel(maskRef), CGImageGetBytesPerRow(maskRef), CGImageGetDataProvider(maskRef), NULL, false); CGImageRef masked = CGImageCreateWithMask([viewImage CGImage], mask); return [UIImage imageWithCGImage:masked]; } Swift 2.0
Pass a UIImage and a mask image to this function, and you will get a masked image as a UIImage.
func maskImage(image:UIImage, mask:(UIImage))->UIImage{ let imageReference = image.CGImage let maskReference = mask.CGImage let imageMask = CGImageMaskCreate(CGImageGetWidth(maskReference), CGImageGetHeight(maskReference), CGImageGetBitsPerComponent(maskReference), CGImageGetBitsPerPixel(maskReference), CGImageGetBytesPerRow(maskReference), CGImageGetDataProvider(maskReference), nil, true) let maskedReference = CGImageCreateWithMask(imageReference, imageMask) let maskedImage = UIImage(CGImage:maskedReference!) return maskedImage }