How to tint a transparent PNG image in iPhone? How to tint a transparent PNG image in iPhone? ios ios

How to tint a transparent PNG image in iPhone?


Update: Here is a Gist for a Swift UIColor extension using the code below.


If you have a greyscale image and want white become the tinting color, kCGBlendModeMultiply is the way to go. With this method, you cannot have highlights lighter than your tinting color.

On the contrary, if you have either a non-greyscale image, OR you have highlights and shadows that should be preserved, the blend mode kCGBlendModeColor is the way to go. White will stay white and black will stay black as the lightness of the image is preserved. This mode is just made for tinting - it is the same as Photoshop's Color layer blend mode (disclaimer: slightly differing results may happen).

Note that tinting alpha-pixels does not work correctly neither in iOS nor in Photoshop - half-transparent black pixels would not stay black. I updated the answer below to work around that issue, it took quite a long time to find out.

You can also use one of the blend modes kCGBlendModeSourceIn/DestinationIn instead of CGContextClipToMask.

If you want to create a UIImage, each of the following code sections can be surrounded by the following code:

UIGraphicsBeginImageContextWithOptions (myIconImage.size, NO, myIconImage.scale); // for correct resolution on retina, thanks @MobileVetCGContextRef context = UIGraphicsGetCurrentContext();CGContextTranslateCTM(context, 0, myIconImage.size.height);CGContextScaleCTM(context, 1.0, -1.0);CGRect rect = CGRectMake(0, 0, myIconImage.size.width, myIconImage.size.height);// image drawing code hereUIImage *coloredImage = UIGraphicsGetImageFromCurrentImageContext();UIGraphicsEndImageContext();

So here's the code for tinting a transparent image with kCGBlendModeColor:

// draw black background to preserve color of transparent pixelsCGContextSetBlendMode(context, kCGBlendModeNormal);[[UIColor blackColor] setFill];CGContextFillRect(context, rect);// draw original imageCGContextSetBlendMode(context, kCGBlendModeNormal);CGContextDrawImage(context, rect, myIconImage.CGImage);// tint image (loosing alpha) - the luminosity of the original image is preservedCGContextSetBlendMode(context, kCGBlendModeColor);[tintColor setFill];CGContextFillRect(context, rect);// mask by alpha values of original imageCGContextSetBlendMode(context, kCGBlendModeDestinationIn);CGContextDrawImage(context, rect, myIconImage.CGImage);

If your image has no half-transparent pixels, you could also do it the other way around with kCGBlendModeLuminosity:

// draw tint colorCGContextSetBlendMode(context, kCGBlendModeNormal);[tintColor setFill];CGContextFillRect(context, rect);// replace luminosity of background (ignoring alpha)CGContextSetBlendMode(context, kCGBlendModeLuminosity);CGContextDrawImage(context, rect, myIconImage.CGImage);// mask by alpha values of original imageCGContextSetBlendMode(context, kCGBlendModeDestinationIn);CGContextDrawImage(context, rect, myIconImage.CGImage);

If you don't care for luminosity, as you just have got an image with an alpha channel that should be tinted with a color, you can do it in a more efficient way:

// draw tint colorCGContextSetBlendMode(context, kCGBlendModeNormal);[tintColor setFill];CGContextFillRect(context, rect);// mask by alpha values of original imageCGContextSetBlendMode(context, kCGBlendModeDestinationIn);CGContextDrawImage(context, rect, myIconImage.CGImage);

or the other way around:

// draw alpha-maskCGContextSetBlendMode(context, kCGBlendModeNormal);CGContextDrawImage(context, rect, myIconImage.CGImage);// draw tint color, preserving alpha values of original imageCGContextSetBlendMode(context, kCGBlendModeSourceIn);[tintColor setFill];CGContextFillRect(context, rect);

Have fun!


I had most success with this method, because the others I tried caused distorted colors for semi-transparent pixels for certain color-combinations. This should also be a bit better on the performance side.

+ (UIImage *) imageNamed:(NSString *) name withTintColor: (UIColor *) tintColor {    UIImage *baseImage = [UIImage imageNamed:name];    CGRect drawRect = CGRectMake(0, 0, baseImage.size.width, baseImage.size.height);    UIGraphicsBeginImageContextWithOptions(baseImage.size, NO, 0);    CGContextRef context = UIGraphicsGetCurrentContext();    CGContextTranslateCTM(context, 0, baseImage.size.height);    CGContextScaleCTM(context, 1.0, -1.0);    // draw original image    CGContextSetBlendMode(context, kCGBlendModeNormal);    CGContextDrawImage(context, drawRect, baseImage.CGImage);    // draw color atop    CGContextSetFillColorWithColor(context, tintColor.CGColor);    CGContextSetBlendMode(context, kCGBlendModeSourceAtop);    CGContextFillRect(context, drawRect);    UIImage *tintedImage = UIGraphicsGetImageFromCurrentImageContext();    UIGraphicsEndImageContext();    return tintedImage;}


After searching around, the best solution I've come to thus far is to use a combination of blend mode and the clipping mask to achieve colorizing/tinting a transparent PNG:

CGContextSetBlendMode (context, kCGBlendModeMultiply);CGContextDrawImage(context, rect, myIconImage.CGImage);CGContextClipToMask(context, rect, myIconImage.CGImage);CGContextSetFillColorWithColor(context, tintColor);CGContextFillRect(context, rect);