Sunday, April 10, 2011

Revisiting tinting

So, if you look closely at my screenshot from the post before last, you'll notice that I was talking about tinting images on-the-fly. I did a bunch of research on the web to see how other people were tinting their images. After some time, I discovered that the standard tinting algorithm used was as follows:

- where c is the color component (r, g, or b).

Applying various tints gives the following results. The original is on the left, and the tinted version is on the right:


Note that the colored text is supposed to have a black outline. Clearly, this will not do - no matter how brightly it is tinted, it should still retain internal details.

I spent some time playing around with various different blending schemes using different color spaces until I came up with the following modification:


This modification is the same as the previous, except that the tint alpha value is multiplied by the luminance of the source pixel. Thus, the darker the pixel the less it is tinted. This produced results as follows:


Now, this looks pretty good on the letters. The black outline can clearly be seen. However, if you look very closely at the red lettering, there is a faint grey outline visible between the black and the red. This is because the luminance is too low at that point to allow any significant tinting. However, it is still light enough such that the lack of tint can clearly be seen. In general, it seems that luminance alone isn't enough to get us an interesting tint.

It turns out that this has a fairly simple solution. The problem is that the luminance isn't increasing quickly enough for us - the linear relationship between how much we tint and how bright the source pixel is is not quite suitable. What we need instead is a tint level that increases much faster as the luminance increases. To fix this, I chose to multiply by the square root of the luminance. ("Wait," I hear you say, "Square root? Surely that will be smaller?" Well in this case no. The square root of a number between 0 and 1 is larger than the number itself. E.g. the square root of 0.25 is actually 0.5.) 

The adjusted equation now looks like this:


Anyway. Enough mathematics. The result looks like this:


And the full-screen tint looks like this:
Which looks just about right. Now, the big question is, why was this information not easy for me to find online? Was I just searching for the wrong stuff, or is it something that everybody already knew apart from me?

The updated javascript ImpactJS plugin can be downloaded here

4 comments:

Anonymous said...

You should have asked me.

Oh wait, you did!

Unknown said...

And I thank you.... Your comment about multiplying the tint by the destination alpha pointed me in the direction of luminance.

Harry said...

I don't suppose I could be super cheeky and ask for a little snippet showing how to implement this into Impact? Everything I've tried is just stopping images from loading.

Thanks! :)

Unknown said...

That's a good point... I'll do that for my next post!