A while ago, it was suggested that GTK+ themes provide an ability to define certain colors. The reasoning behind this was that if a theme had a red background for something, just defining red as #ff0000 could result in unreadable text. As usual, some objections were raised, and IIRC nothing has yet happened with it.I was interested in this, because xchat-gnome is one of the very few things where it actually makes sense to define colors by name. It’s all well and good if a theme provides defined colors for heading and alert, but IRC allows people to mark text as red or aqua. Theme based colors weren’t an issue yet, because xchat-gnome worked on purely pre-defined color schemes for the conversation panel. Until now.

Perhaps it’s just been too long since I did any graphics programming, but when I thought this idea up in the shower (as an aside: I have, in the past, been known to take showers for the sole purpose of thinking up ideas), I just had to implement it.

Basically, instead of defining a color as a specific RGB triplet, we define it as a region in HSV space. HSV is a color space that matches more closely to how we as humans tend to define colors. It’s a cylindrical coordinate system where the angle defines hue, the radius defines saturation, and the vertical axis defines “value” (basically white to black). The colors within this cylindrical space fill a conic region.HSV_cone.png
The actual mapping between RGB and HSV forms a hexacone, due to colors in HSV that cannot be represented in RGB. Anyhow, we’re defining colors as a kind of wedge of this coordinate system. That means that when we say blue, we’re not actually defining a color, but a range of colors. Blue can be dark, it can be light, and it can range from purpleish-blue to cyanish-blue.

When the background color is not known a priori, some colors within this region may be too low a contrast to be readable. The background color is a point in HSV space, and by choosing the point within the region which is furthest from our background point, we get a foreground blue which is readable.

Of course, there are still some problems with this. The background color may lie right in the middle of a color region. In this case, even the furthest point within that region is going to have very low contrast against the background. To guard against this, if the hue of the foreground point is too close to the background and the saturation is high, the value gets pushed a little further out. Value (lightness) is a primary influence on how we percieve contrast, so by emphasizing it, the text becomes (mostly) legible.

color_optimization.png As a result of this, colors against a white background tend to be dark, while colors against a black background tend to be light. By defining white and black as regions which have some breadth in the value dimension, white-on-white text and black-on-black text become readable. When on a grey background, text gets pushed in either direction depending on whichever is furthest away in the HSV color space. For the most part, this works very well (you can see the purple color has some problems on this particular shade of grey). Because colors have some breadth in the H and S dimensions, even highly saturated colored backgrounds work well.

Of course, xchat-gnome allows image and transparent backgrounds, which are completely ignored by this. Nothing can deal with high-frequency high-contrast backgrounds, so I’m just going to say if you’re foolish enough to try that, you get what you deserve :). This code has landed in xchat-gnome SVN, and there’s been enough awesome stuff since 0.11 that a new release should be coming soon.