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.
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.
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.
#1 by Evan on June 14th, 2006
Quote
Cool idea!
#2 by Madeleine Ball on June 14th, 2006
Quote
I think you might want to look into using “luminance” rather than “value” as the quality you’re modifying.
At first thought, perhaps, by calculating the luminance of the background, compare that to foreground luminance to choose which way to shift value (or saturation?), and perhaps normalize the amount of shift to the effect of that shift on the luminance value.
I’m not sure, but this might fix those cases (eg, the purple) in which the algorithm doesn’t seem to be working so well.
This site describes the conversion of RGB to grayscale luminance as:
RGB Luminance value = 0.3 R + 0.59 G + 0.11 B
#3 by David Trowbridge on June 14th, 2006
Quote
HSL is very similar to HSV — it’s essentially what you’d get if you grabbed the center of the cone and pulled it up into a double-cone. It still doesn’t really match how we percieve color, for a couple reasons:
1. Our eyes are just so dang non-linear
2. The way we percieve color is dependant on the surrounding colors
The best way to do this would be to define oddly-shaped regions — this would work regardless of what color space was chosen, but it makes the code a lot more complicated. Right now I just check the corners of the regions, since they’re (by definition) the only places which can be “furthest.” Were the regions to be weird and bulbous, I’d need some really smart way of defining them and finding the furthest extent. Unfortunately, there’s no color space in which a 3D box maps perfectly to our perception of colors.
Keep in mind also that the current regions I’ve chosen aren’t the best — I’ll be tweaking them over the next few weeks.
#4 by doza on June 14th, 2006
Quote
Funny thing, I’ve done the same last month for my jabber client, except that I used only 12 saturated colors and no shades of grey: http://tinyurl.com/k9pqh
#5 by HPReg on June 14th, 2006
Quote
I’m happy to discover I’m not the only one who can stay half an hour under a shower, lost in my thoughts, only to “wake-up” half an hour later and discover that I haven’t grabbed the soap yet! For that alone, your post made my day.
I don’t know HSV a lot, but the unreadable “purple on grey” example makes me think that although your idea is good, you need to find a better color space where the distance really is the contrast.
With respect to xchat-gnome in particular, I think the only good solution for random backgrounds is to basically override the background
I.e. for example surround the shape of each black character with a little transparent white “cloud”. This way no matter what the background is, your foreground color is visible. This is the technique used by mouse cursors, and subtitles in recent (DVD era) movies.
#6 by . on June 15th, 2006
Quote
HSV isn’t very perceptually uniform, so perhaps changing to CIELAB might be useful.
#7 by frej on June 15th, 2006
Quote
Hmm, Ithink windows XP has some effect with the fonts on the desktop. The text always stand out quite well, no matter what background is set.
It might be a simple effect, or a tricky hack
#8 by David Mills on June 15th, 2006
Quote
Nice idea, can’t wait to see what it gives.…
Pingback: Martin Sturm » Blog Archive » Smart people
#9 by Max Howell on June 15th, 2006
Quote
I tried to write somethiong like this for Amarok a while ago, but I just didn’t know enough colour theory to get it working well. So this is very interesting to me!
I tried to find materials for research, but failed, can you recommend something at all?
#10 by Steve Coffman on June 15th, 2006
Quote
You’ve got me idly wondering, but for the image background case, if you take the average of the colors in the image, and pretend it’s a solid color background of that color, would that on average be a better or worse strategy? Are most pictures mostly one color, highly variable, or mostly two near opposite colors, etc.? For mostly one color it would work sure, but for highly variable images, or a half black and half white picture, an average would be better or worse than picking some orthogonal color?
#11 by Ben on June 15th, 2006
Quote
This sounds like a very positive direction to go in. I would love to see this in gtkhtml. I prefer dark interface themes (easier on the eyes), but a lot of HTML mail is unreadable in Evolution because it often defines the text color (black or dark) but not the background color, which it assumes will be light. At least Firefox lets me override the system themes for background color. If gtkhtml could “push” the background color to be lighter if the foreground is dark, that would be a (overengineered, sure) solution to the problem.
#12 by Damián Viano(Des) on June 15th, 2006
Quote
Really cool idea! Congrats, and keep up the good work.
I would also like to see this in a vte.
#13 by zdzichu on June 15th, 2006
Quote
Cool! GNOME Terminal would benefit greatly if those „smart colors” were implement in it.
As for comment with Windows XP — it draws shadow below text, which provides nice dark background for white letters. Eterm works similarly — every letter have one pixel black half-outline (to the right and below character) which greatly improves visibility, but doesn’t solve darkblue-text-on-black problem.
#14 by Madeleine Ball on June 15th, 2006
Quote
I do think you have a very cool idea.
This abstract seems to indicate that luminance is the major issue for readibility, chromatic contrasts only matter if there isn’t enough luminance contrast. Even if it’s a simplification of the real world, it’s a very close approximation — at least, or especially, for reading text. And presumably easier to implement than oddly-shaped regions in color space (I don’t really understand that idea, or how you’d choose the regions…?).
In part, I mentioned it because red != green != blue in luminance. The double-cone analogy fails to recognize this, as the luminance of the saturated edge “circle” won’t be a plane at the middle, but a wobbly curvy up and down thing with green closer to the “white” peak and blue closer to the “black”.
#15 by dataangel on June 15th, 2006
Quote
When I first came to linux and the best eyecandy was pseudo-transparent terminals I remember really wishing that there was some sort of “find best contrasting color” option because I was terrible at eyeballing it and changed wallpapers often.
A lot of people choose wallpapers or terminal backgrounds that have 1 distinct color so as to better match their theme (the default KDE background is blue to match Plastik for instance). So I could see this being a real boon even for images (taking the average or something similar as mentioned above).
Pingback: ScottLog » Blog Archive » I can see!
#16 by Dan on December 11th, 2006
Quote
Nice results! Try it in CIE L*a*b* color space:
http://googlography.org/xyz.hh
(RGBtoLAB and LABtoRGB at the bottom.)
Pingback: Announcing libcontrast | david’s bloggy journal!
#17 by lwatcdr on April 4th, 2007
Quote
I actually wrote function to do that in java a few years ago. I was working on an in house program and decided that I would experiment with some idiot proofing of the software. I also put in code that prevented all the title bar being dragged off screen, Widows size larger than the screens resolution, and colors being too close together. Worked pretty dang well. Maybe I will find the code and post it for you.
#18 by Mike Silva on April 5th, 2007
Quote
I’ve been looking for this to force black (or dark) background in my web surfing…
Is it simple to implement a Firefox plugin to re-arrange the coulors of webpages so I won’t have white backgrounds?…
Like described in this post:
http://www.nabble.com/May-I-sugest-a-new-Firefox-extension–t925703.html