Color contrast correction

Tuesday 23 November 2010 Emacs

I finally took some time to finish my color contrast corrector.

It's now able to compare two colors and to tell if they are readable when used as foreground and background color for text rendering. If they are too close, the code corrects both colors so to they'll become distant enough to be readable.

To do that, it uses color coordinates in the CIE Lab* colorspace. This allows to determine the luminance difference between 2 colors very easily by comparing the L component of the coordinates. The default threshold used to determine readability based on luminance difference is 40 (on 100), which seems to give pretty good results so far.

Then it uses the CIE Delta E 2000 formula to obtain the distance between colors. A distance of 6 is considered to be enough for the colors to be distinctive in our case, but that can be adjusted anyway. That depends on reader's eyes.

If both the color and luminance distances are big enough, the color pair is considered readable when used upon each other.

If these criteria are not satisfied, the code simply tries to correct the color by adjusting the L (luminance) component of the colors so their difference is 40. Optionally, the background color can be fixed so only the foreground color would be adjusted; this is especially handy when the color background is not provided by any external style, but it the screen one (like the Emacs frame background in my case).

Here is an example result generated over 10 pairs of random colors. Left colors are randomly generated, and right colors are the corrected one.

bg: DarkSeaGreen4 fg: gray67 ->                             bg: #4a6b4b fg: #cccccc
bg: SlateGray4 fg: forest green ->                          bg: #9faec0 fg: #005700
bg: grey13 fg: grey36 ->                                    bg: #131313 fg: #6c6c6c
bg: MediumPurple2 fg: honeydew ->                           bg: #9e78ed fg: #f0fff0
bg: grey43 fg: chartreuse3 ->                               bg: #5e5e5e fg: #79de25
bg: linen fg: DeepPink2 ->                                  bg: linen fg: DeepPink2
bg: CadetBlue4 fg: blue1 ->                                 bg: #6c9fa4 fg: #0000e1
bg: gray33 fg: NavajoWhite3 ->                              bg: #525252 fg: #cfb58c
bg: chartreuse1 fg: RosyBrown3 ->                           bg: #9cff38 fg: #b28282
bg: medium violet red fg: DeepPink1 ->                      bg: #9c0060 fg: #ff55b9

All this has been written in Emacs Lisp. The code is now available in Gnus (and therefore in Emacs 24) in the packages color-lab and shr-color.

A future work would be to add support for colour blindness.

As a side note, several people pointed me at the WCAG formulas to determine luminance and contrast ratio. These are probably good criteria to choose your color when designing a user interface. However, they are not enough to determine if displayed color will be readable. This means you can use them if you are a designer, but IMHO they are pretty weak for detecting and correcting colors you did not choose.

Get notified of my next blog post