iPhone: How to Dynamically Color a UIImage

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:

The Code

Here is the basic code to take the image and color it. But read on for more explanation and example code.

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.

Comments

This is great! I needed to do something very similar to this. It worked great.
New question - how to blend the image on top of another image like in PS? You know, put a layer on multiply over another layer?

You can multiply one image over another by doing something very similar to the code in this article, except that you'd call CGContextSetBlendMode() and pass it the constant kCGBlendModeMultiply, to set the blend mode to multiply.

Then, instead of drawing a clipped rectangle over the first image (like in my code), you would just draw another image instead.

AD, it sounds like what you're trying to achieve is different from using blending modes to color an image. I don't totally follow your situation, but I'd suggest looking into adding a CALayer to a UIButton (to add your background layer), and then adding your image to the button in the normal way.

I have been looking for something like this for a long time. With a slight variation of this -- my images are white and kCGBlendModeNormal works best for apply colour to them -- I should be able to eliminate a huge number of duplicate image files in my app bundle.

I used your code to try to create different colored versions of my .png hand image. I want to use a uislider to change the color of the hand. But I am now just trying to understand how to color a .png in xcode. But for some reason nothing is displaying in my code. Can you help me? attached is my main code. Thanks Charles

and this was working great for me until I started adding retina images (aka @2x) for the app; the color change is still applied but the higher 'resolution' of the retina image is lost in the process...
any ideas on how it could be changed so that the color would be changed and the improved appearance of the retina image would be maintained?

Anonymous, my guess would be that something needs to be tweaked about the width and height that are getting passed around in the code... maybe for some reason the fact that they should all be doubled for Retina images is being lost somewhere. But I haven't had experience with this directly yet.

yes that is what I found after I started looking into it myself; basically, every time in the code where you use img.size.width or img.size.height you need to multiple the value by img.scale; I made these changes and now it works fine for retina-resolution images as well :-)

Thanks for the excellent post and supporting comments. I can confirm that the above code and fixes (namely for the retina display support) work great in iOS 5.

For those that don't have a ton of CG experience, it is worth stating what is now obvious: if you have a low alpha "source" image, you are not going to get very good color fills. If you have problems where the color doesn't seem to be reflected properly, be sure to boost the alpha levels of your source image and give it another shot.

Hi,
thanks very much for this tutorial. I tried this and it worked, but I'm having performance Issues because I always have to redraw the entire Picture. Is there a Possibility to change the Color burned without having to create a new Picture?

Hi,
thanks very much for this tutorial, i want to draw an image(white image with black borders) and after the user choose the color, he can click on any part of the image to fill the selected part with the chosen color.
please if you have any idea share it with me

In your example you apply the color burn effect at the image then it is merge with the color... I need to make this stuff on the opposite way... (to apply the color burn effete to the color and then merge it with image) could you help me please?

I have replicated ios back button and added to the navigation bar using two images. Now the requirement is to have it in different colors to support different color schemes. For that i have been using dozen image files. Then i came across this, and thought why not do this, but this just fills the color, How do i get a gradient with two colors? like in the apple back button? Itll be great if u could help me with this.
Thanks in advance.