19

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 other color (let's say white to make it easy), so the final product is now a white image with parts of it transparent.

I've been looking around on the Apple documentation site here: https://developer.apple.com/library/archive/documentation/GraphicsImaging/Conceptual/drawingwithquartz2d/dq_images/dq_images.html#//apple_ref/doc/uid/TP30001066-CH212-CJBHIJEB

But I don't can't really make sense of those examples.

Cœur
  • 37,241
  • 25
  • 195
  • 267
Philip Walton
  • 29,693
  • 16
  • 60
  • 84

4 Answers4

53

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

Community
  • 1
  • 1
Jano
  • 62,815
  • 21
  • 164
  • 192
  • Worth noting. If you are using UIImageView to display the image, here's a simple solution. http://stackoverflow.com/a/26965557/870313 – Andres Canella Apr 26 '16 at 17:54
4

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.

Robert Chen
  • 5,179
  • 3
  • 34
  • 21
1

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)
Pang
  • 9,564
  • 146
  • 81
  • 122
0

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];
}
gregory
  • 79
  • 2
  • 9