A while ago, it was sug­gested that GTK+ themes pro­vide an abil­ity to define cer­tain col­ors. The rea­son­ing behind this was that if a theme had a red back­ground for some­thing, just defin­ing red as #ff0000 could result in unread­able text. As usual, some objec­tions were raised, and IIRC noth­ing has yet hap­pened with it.I was inter­ested in this, because xchat-gnome is one of the very few things where it actu­ally makes sense to define col­ors by name. It’s all well and good if a theme pro­vides defined col­ors for head­ing and alert, but IRC allows peo­ple to mark text as red or aqua. Theme based col­ors weren’t an issue yet, because xchat-gnome worked on purely pre-defined color schemes for the con­ver­sa­tion panel. Until now.

Per­haps it’s just been too long since I did any graph­ics pro­gram­ming, but when I thought this idea up in the shower (as an aside: I have, in the past, been known to take show­ers for the sole pur­pose of think­ing up ideas), I just had to imple­ment it.

Basi­cally, instead of defin­ing a color as a spe­cific 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 col­ors. It’s a cylin­dri­cal coor­di­nate sys­tem where the angle defines hue, the radius defines sat­u­ra­tion, and the ver­ti­cal axis defines “value” (basi­cally white to black). The col­ors within this cylin­dri­cal space fill a conic region.HSV_cone.png
The actual map­ping between RGB and HSV forms a hexa­cone, due to col­ors in HSV that can­not be rep­re­sented in RGB. Any­how, we’re defin­ing col­ors as a kind of wedge of this coor­di­nate sys­tem. That means that when we say blue, we’re not actu­ally defin­ing a color, but a range of col­ors. Blue can be dark, it can be light, and it can range from purpleish-blue to cyanish-blue.

When the back­ground color is not known a pri­ori, some col­ors within this region may be too low a con­trast to be read­able. The back­ground color is a point in HSV space, and by choos­ing the point within the region which is fur­thest from our back­ground point, we get a fore­ground blue which is readable.

Of course, there are still some prob­lems with this. The back­ground color may lie right in the mid­dle of a color region. In this case, even the fur­thest point within that region is going to have very low con­trast against the back­ground. To guard against this, if the hue of the fore­ground point is too close to the back­ground and the sat­u­ra­tion is high, the value gets pushed a lit­tle fur­ther out. Value (light­ness) is a pri­mary influ­ence on how we per­cieve con­trast, so by empha­siz­ing it, the text becomes (mostly) legible.

color_optimization.png As a result of this, col­ors against a white back­ground tend to be dark, while col­ors against a black back­ground tend to be light. By defin­ing white and black as regions which have some breadth in the value dimen­sion, white-on-white text and black-on-black text become read­able. When on a grey back­ground, text gets pushed in either direc­tion depend­ing on whichever is fur­thest away in the HSV color space. For the most part, this works very well (you can see the pur­ple color has some prob­lems on this par­tic­u­lar shade of grey). Because col­ors have some breadth in the H and S dimen­sions, even highly sat­u­rated col­ored back­grounds work well.

Of course, xchat-gnome allows image and trans­par­ent back­grounds, which are com­pletely ignored by this. Noth­ing can deal with high-frequency high-contrast back­grounds, so I’m just going to say if you’re fool­ish enough to try that, you get what you deserve :) . This code has landed in xchat-gnome SVN, and there’s been enough awe­some stuff since 0.11 that a new release should be com­ing soon.