Note: If you find this post helpful, consider purchasing Colored Images: Documented Source Code, an XCode project with well-documented source code to make an app that demonstrates this technique.
In my recent work on Sphericle, there were a few instances where I wanted to use the same image over and over, but colored differently each time. For example, I want to show spheres of different colors on a map; there are 360,000 spheres, each having its own color. I didn't want to draw the sphere algorithmically; I wanted the picture of a sphere to be based on an image, but then colored appropriately. The solution: use a grayscale image of a sphere, then draw a color over it using a color burn blend mode. That's what I want to show you today.
The Basic Idea
The process for generating a dynamically-colored UIImage is pretty simple: draw a grayscale image, mask it with itself (to bound the drawing area to the image itself), then overlay the color you want, with the blend mode set to color burn.
For my example code, I'm using an image of a badge:
Here is the basic code to take the image and color it. But read on for more explanation and example code.
// load the image NSString *name = @"badge.png"; UIImage *img = [UIImage imageNamed:name]; // begin a new image context, to draw our colored image onto UIGraphicsBeginImageContext(img.size); // get a reference to that context we created CGContextRef context = UIGraphicsGetCurrentContext(); // set the fill color [color setFill]; // translate/flip the graphics context (for transforming from CG* coords to UI* coords CGContextTranslateCTM(context, 0, img.size.height); CGContextScaleCTM(context, 1.0, -1.0); // set the blend mode to color burn, and the original image CGContextSetBlendMode(context, kCGBlendModeColorBurn); CGRect rect = CGRectMake(0, 0, img.size.width, img.size.height); CGContextDrawImage(context, rect, img.CGImage); // set a mask that matches the shape of the image, then draw (color burn) a colored rectangle CGContextClipToMask(context, rect, img.CGImage); CGContextAddRect(context, rect); CGContextDrawPath(context,kCGPathFill); // generate a new UIImage from the graphics context we drew onto UIImage *coloredImg = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); //return the color-burned image return coloredImg;
Make it Reusable
Because this is the kind of thing that you might want to use repeatedly in an app, it makes sense to make it reusable somehow. What I did was to create a Category on the UIImage class. The method I created is:
+ (UIImage *)imageNamed:(NSString *)name withColor:(UIColor *)color;
With that, we have a nice convenience method that just needs the name of the image file, and the color you want, and you get your colored image returned to you!
Ask any questions you might have in the Comments! And, since it's more fun to see these things in action, I've put together a simple XCode project that implements the code I've described here, and adds a little animation to generate multiple dynamically-colored copies of a single image. The source code is well-documented, and includes an Interface Builder file. Check it out: Colored Images: Documented Source Code.
Also, if you'd like to know when I post more articles like this, join the Coffeeshopped Newsletter.