Over the last couple of weeks, I've been playing around with a little piece of technology that I cann the "Icon Builder". I've been posting this on the IRC chat a couple of times, but figured I'd write a blog about how complicated some random things can get at times.
Before I get to that, though, let me give you a bit of background:
I have a pretty high resolution screen (2560x1440, 27"). The FFB client currently runs at a fixed size which is designed for 1024x768 screens. This is all good, except that the combination of these two make the client appear really small on my screen. The icons, in particular, are very small and I have a hard time telling the icons apart.
A while ago, Kalimar brought up that he's considering a HTML5 version of the client, and the matter of scalability was brought up once more. Add to this that I have been talking a bit loosely with WhatBall about the possibility of having player icons in a scalable format (SVG).
Since Kalimar is working on HTML5 stuff, I decided that this would be a good time to look into HTML5 myself, and I decided to make a framework that takes a set of SVG icon parts (think paper doll style body parts here) and combine them into a single image.
I spent some time to build this framework, slowly improving the framework itself and I now have a relatively powerful proof of concept page set up (
http://playground.fumbbl.com/IconBuilder).
Now.. I wanted to have the ability to change the colours on the images, and to do this, the source images are encoded using specific series of colours. These special colours are set up so that the graphic artist has access to three 8-bit (255 levels) intensity levels which are mapped to the selected colours. In the Icon Builder page, you will see these three shades as "Primary", "Secondary" and "SkinTone".
After playing around with this for a while, I came to the conclusion that the way I applied this colour "intensity" to the specific colour was less than ideal.
To give you more detail about this, I'll explain some really basic things about colours on a traditional monitor. Basically, a colour on your screen has three "channels": Red, Green, and Blue. Each channel has an intensity from 0 to 100%. For example, [0%, 0%, 0%] is black, [100%, 100%, 0%] is yellow and [100%, 100%, 100%] is white.
So, my first approach to applying the shade to the colour was to simply multiply each channel with the intensity level. So for example, a red colour [100, 0, 0] with a 50% intensity would end up as [50, 0, 0], while another one [100, 50, 30] with the same 50% intensity would end up as [50, 25, 15].
Unfortunately, this isn't really a very good formula. With most of us being human, our eyes ability to perceive colours varies depending on the frequency of the light (or effectively the colour of it). This quickly becomes complicated.
At this point, I thought to myself: "I've seen this HSV colour picker thing on Photoshop", and vaguely remember this acronym standing for "Hue, Saturation, Value". So I look up the information on this and it turns out there are two variations of the same concept (HSV and HSL), where Value and Lightness are the respective last letter of the acronym. In short, "Hue" is the type of colour (red, blue, yellow, etc), "Saturation" is the depth of colour (going from a grayish orange to a bold, powerful orange) and finally Lightness and Value is how bright it is.
"Great", I think, "That's exactly what I want". So.. I make the application convert from RGB (which is the name of the "colour space" used by the screens) to HSV and HSL respectively, multiply the intensity level to the "Lightness" and "Value" channels and then convert back to RGB.
Unfortunately, it turned out to not be spectacular either. The colours tended to go through a grayish boring shade, or go super saturated in certain cases making it look strange.
Ok then.. Since I was already on track to check out different colour spaces, I kept on looking. I remembered that there was something called LAB colours in Photoshop as well (L is lightness in that acronym as well as it turns out), so I look that up. And what do I see? There are different versions of this as well (Hunter LAB, standard LAB, etc). Fine.. I implemented both of those and ran tests. These were promising, but still not great. The blue channel in particular seemed to act up and not get dark enough.
At this point, I took a break from this. I've had had enough of colour spaces for the time being. The next day, I was back at it and ran across something called CIECAM02. This is a relatively new standard (I'm expecting 02 designating 2002), and it looked really primising. It's a state of the art colour space designed to match the colour response of the human eye. There are lots of complexities here (for example two intermediate colour spaces called XYZ and LMS, and white points and all sorts of things) and it's also pretty hard to find actual information on it.
In the end, I found a patch from October 02 to the "RawTherapee" open source image editing application that had an implementation of conversions to and from this CIECAM02 colour space. Mind you, this isn't actually in the official program yet as far as I can tell. Either way, I took this source and converted it to Javascript (it's GPLed, so it's fine) and tested it with my code. The first tests were really bad (again, in the blue channel), and it looked like this wasn't working properly.
But.. I persisted and ran some tests and found that taking a pure blue colour and progressively going darker not only reduces the "Lightness" channel in the CIECAM02 colour space, but also affected the saturation channel. So I ended up reducing the saturation in a linear manner together with the lightness and ended up with something that looks really really well.
If you want to play around with this, you can open the Icon Builder app and change over to the "Test" template in the top left dropdown. Then click one of the layer buttons and select the "Test Pattern" image. Finally, choose the colour space you want to see in the rightmost dropdown for the primary, secondary and skin tone rows. Click OK and you can then switch colours around using the buttons on the top.
I find it interesting to see how the different shades of the selected colour appear based on the colour space used to make them darker. Maybe that's just me though :)
That's it for this blog entry. Colours are more complicated than they appear...