Here's what I'm trying to do: On the left is a generic, unpainted RGBA image that I created off-screen and cached for speed (it creates very slowly initially, but very quickly, to colorize with any color later, as needed). This is a square image with a circular swirl. Inside the circle, the image has alpha / opacity 1. Outside of the circle, it has alpha / opacity 0. I displayed it here inside the UIView with the background color [UIColor scrollViewTexturedBackgroundColor] . On the right , what happens is when I try to colorize an image by filling in a solid red rectangle above it after setting CGContextSetBlendMode(context, kCGBlendModeColor) .


This is not what I want, and what I expected. Obviously, coloring a completely transparent pixel (for example, an alpha value of 0) leads to a full-color fill color for some strange reason, and not to a transparent one, as I expected.
I really want to:

Now, in this particular case, I can set the clipping region to a circle so that the area outside the circle remains untouched - and this is what I did here as a workaround.
But in my application, I also need to be able to colorize arbitrary shapes where I don't know the clipping path / path. One example is to colorize white text by applying a gradient. How it's done? I suspect there must be some way to do this efficiently - and generally, without any weird tracing / cropping tricks - using image masks ... but I still have to find a tutorial on this. Obviously, this is possible because I saw color gradient text in other games.
By the way, what I canโt do is start with a gradient and a clip / clear parts that I donโt need, because (as shown in the example above) my unpainted source images are usually shades of gray and not pure white. So I really need to start with an unpainted image and then colorize it.
ps - kCGBlendModeMultiply also has the same weaknesses / weaknesses / features when it comes to coloring partially transparent images. Does anyone know why Apple decided to do it this way? As if the Quartz coloring code treats RGBA (0,0,0,0) as RGBA (0,0,0,1), i.e. completely ignores and destroys the alpha channel.