August 22nd, 2003, 09:39 AM
Matching Hex colour values - can a human see white text on white background?!
//Sorry for the formatting of this - not quite sure what happened to the width!
I am trying to devise a way of programmatically deciding if two hex values would be visible to a human viewer.
If for example my webpage had a background colour of #FFFFFF and i set my text value to the same value then you couldn't see the text. That is programmatically a nice simple pattern match. However, if i were to change the text value just a little to ... say #EDFAE, the pattern match would fail... but a user would have a great deal of trouble reading it.
I have looked at a few approaches, and have come up with this.... there is one vital flaw however:-
If one of the values is black - #000000 then I am dividing by zero - causing a major problem... e.g. if #000000 is compared to #FFFFFF - 0*(100/756) = 0 - this is fine... it is visible... but if we compare #000000 to #000033 - 0*(100/51) = 0 - NOT A MATCH, but if you look at this colour combination it is hard to see!
Step 1: Set visibility metric:
Visible text < 90% match
Step 2: Split the hexidecimal representation into the component colour values:
FF, FF, FF
Step 3: Convert each bigram value to decimal:
FF -> 255, FF -> 255, FF -> 255
Step 4: Sum the decimal values:
255 + 255 + 255 = 765
Step 5: Repeats steps 2-4 for second hexidecimal value (e.g. the text value).
Step 6: Compare the two resulting values.
Step 7: Perform visibility calculation:
SMALLEST VALUE * (100/LARGEST VALUE)
Step 8: If the result is less than or equal to our visibility metric, then the text should be visible to the human eye. If the result is larger than the metric then we can assume that the text was designed to be invisible to human viewers.
Let's run the algorithm over our earlier example of #FFFFFF(our background) against #EDFAE6(our text).
#FFFFFF -> 255+255+255=765
#EDFAE6 -> 237+250+230=717
#FFFFFF is the larger decimal value so becomes the denominator in our equation.
717*(100/765) = 93.72%
With our visibility metric set to 90% this comparison would appear to be invisible to human viewers.
I have though about incrementing each hex value by one to prevent the divide by zero issue. However this causes a different problem outlined in the next example
I would dearly welcome any input anyone else might have on this problem, i have covered my desk with bits of paper trying to work this out. I have thought about using a Vector model for each R,G,B value and checking to see if the value we compare is within X places of the original, however I think this might present more problems that it is worth - although programmatically a vector space is a nice array!
This example uses a hex->++dec conversion!
#000000 = 3
#000033 = 54
3*(100/54) = 5% - This is not zero, but 5% suggests it is visible, when it isn't - a value of 95% would be more appropriate
Any comments greatfully received!
August 22nd, 2003, 10:41 AM
Right - the maths was all wrong there... I have worked it out now. If anyone is interested in how, mail me.
August 22nd, 2003, 03:55 PM
just as a matter of interest - would you not be better working with HSB rather than RGB values?
August 26th, 2003, 04:57 AM
A fair point, but the application I had planned for this required me to compare RGB hex.
September 17th, 2003, 03:39 PM
Interesting one that, could you let me in on the solution?
I was going to post that you cannot sum all colours as of course #00FF00 is a very different colour to #FF0000 despite having an identical sum!