I have a UIImage that is all black with an alpha channel so some parts are grayish and some parts are completely see-through. I want to use that images as a mask over some o
In iOS 7+ you should use UIImageRenderingModeAlwaysTemplate
instead. See https://stackoverflow.com/a/26965557/870313
Creating arbitrarily-colored icons from a black-with-alpha master image (iOS).
// Usage: UIImage *buttonImage = [UIImage ipMaskedImageNamed:@"UIButtonBarAction.png" color:[UIColor redColor]];
+ (UIImage *)ipMaskedImageNamed:(NSString *)name color:(UIColor *)color
{
UIImage *image = [UIImage imageNamed:name];
CGRect rect = CGRectMake(0, 0, image.size.width, image.size.height);
UIGraphicsBeginImageContextWithOptions(rect.size, NO, image.scale);
CGContextRef c = UIGraphicsGetCurrentContext();
[image drawInRect:rect];
CGContextSetFillColorWithColor(c, [color CGColor]);
CGContextSetBlendMode(c, kCGBlendModeSourceAtop);
CGContextFillRect(c, rect);
UIImage *result = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return result;
}
Credits to Ole Zorn: https://gist.github.com/1102091
I converted this for OSX here as a Category and copied below. Note this is for non-ARC projects. For ARC projects, the autorelease can be removed.
- (NSImage *)cdsMaskedWithColor:(NSColor *)color
{
CGRect rect = CGRectMake(0, 0, self.size.width, self.size.height);
NSImage *result = [[NSImage alloc] initWithSize:self.size];
[result lockFocusFlipped:self.isFlipped];
NSGraphicsContext *context = [NSGraphicsContext currentContext];
CGContextRef c = (CGContextRef)[context graphicsPort];
[self drawInRect:NSRectFromCGRect(rect)];
CGContextSetFillColorWithColor(c, [color CGColor]);
CGContextSetBlendMode(c, kCGBlendModeSourceAtop);
CGContextFillRect(c, rect);
[result unlockFocus];
return [result autorelease];
}
+ (NSImage *)cdsMaskedImageNamed:(NSString *)name color:(NSColor *)color
{
NSImage *image = [NSImage imageNamed:name];
return [image cdsMaskedWithColor:color];
}
Here's a variation in Swift 3, written as an extension to UIImage:
extension UIImage {
func tinted(color:UIColor) -> UIImage? {
let image = self
let rect:CGRect = CGRect(origin: CGPoint(x: 0, y: 0), size: image.size)
UIGraphicsBeginImageContextWithOptions(rect.size, false, image.scale)
let context = UIGraphicsGetCurrentContext()!
image.draw(in: rect)
context.setFillColor(color.cgColor)
context.setBlendMode(.sourceAtop)
context.fill(rect)
if let result:UIImage = UIGraphicsGetImageFromCurrentImageContext() {
UIGraphicsEndImageContext()
return result
}
else {
return nil
}
}
}
// Usage
let myImage = #imageLiteral(resourceName: "Check.png") // any image
let blueImage = myImage.tinted(color: .blue)
Translating Jano's answer into Swift:
func ipMaskedImageNamed(name:String, color:UIColor) -> UIImage {
let image = UIImage(named: name)
let rect:CGRect = CGRect(origin: CGPoint(x: 0, y: 0), size: CGSize(width: image!.size.width, height: image!.size.height))
UIGraphicsBeginImageContextWithOptions(rect.size, false, image!.scale)
let c:CGContextRef = UIGraphicsGetCurrentContext()
image?.drawInRect(rect)
CGContextSetFillColorWithColor(c, color.CGColor)
CGContextSetBlendMode(c, kCGBlendModeSourceAtop)
CGContextFillRect(c, rect)
let result:UIImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return result
}
Usage:
myButton.setImage(ipMaskedImageNamed("grayScalePNG", color: UIColor.redColor()), forState: .Normal)
Edit: According to this article, you can turn an image into a mask whose opaque areas are represented by the tint color. Within the asset catalog, under the Attributes Inspector of the image, change Render As to Template Image. No code necessary.