## Choosing foreground using Luminosity Contrast Ratio

Sample Source Code

When a background color is chosen by the user, you can use a converter that calculates luminosity contrast ratio to choose the best foreground color for the background given.  In the code sample attached, I use a converter that does this getting the luminosity contrast for the background with a white foreground and a black foreground.  Whichever has the better luminosity contrast ratio, is the foreground color I use.

I got formula for the luminosity contrast ratio from the W3C Recommendation for Web Content Accessiblity Guidelines (WCAG) 2.0.  Outside of code, the formula looks like:

(L1 + 0.05) / (L2 + 0.05), where

• L1 is the relative luminance of the lighter color
• L2 is the relative luminance of the darker color

Next question I had was “how do I calculate relative luminance”?  The formula for this is also within the guidelines.  First of all, a definition:  relative luminance is “the relative brightness of any point in a colorspace, normalized to 0 for the darkest black and 1 for the lightest white.”

It can be calculated using the formula below:

Relative Luminance = 0.2126 * R + 0.7152 * G + 0.0722 * B, where:

R:  If RsRGB <= 0.03928 then R = RsRGB  / 12.92 else R = ((RsRGB  + 0.055)/1.055)2.4
G:  If GsRGB <= 0.03928 then G = GsRGB  / 12.92 else G = ((GsRGB  + 0.055)/1.055)2.4
B:  If BsRGB <= 0.03928 then B = BsRGB  / 12.92 else B = ((BsRGB  + 0.055)/1.055)2.4

Ok, but another variable is introduced here, how are RsRGB, GsRGB, BsRGB each calculated?  This is a bit easier and is defined in the same area as the relative luminance formula.

• RsRGB = R8bit/255
• GsRGB = G8bit/255
• BsRGB = B8bit/255

Finally, now how does all of this look in C#?

Calculate Luminosity Contrast
1. private double LuminosityContrast(Color foreground, Color background)
2. {
3.     var foregroundLuminosity = RelativeLuminance(foreground.R, foreground.G, foreground.B);
4.     var backgroundLuminosity = RelativeLuminance(background.R, background.G, background.B);
5.
6.     if (foregroundLuminosity > backgroundLuminosity)
7.     {
8.         return (foregroundLuminosity + 0.05) / (backgroundLuminosity + 0.05);
9.     }
10.     else
11.     {
12.         return (backgroundLuminosity + 0.05) / (foregroundLuminosity + 0.05);
13.     }
14. }
15.
16. private double RelativeLuminance(byte r, byte g, byte b)
17. {
18.     double rs = ((double)r / 255);
19.     double gs = ((double)g / 255);
20.     double bs = ((double)b / 255);
21.     double R = 0;
22.     double G = 0;
23.     double B = 0;
24.
25.     R = (rs <= 0.03928) ? (double)(rs / 12.92) : Math.Pow(((rs + 0.055) / 1.055), 2.4);
26.     G = (gs <= 0.03928) ? (double)(gs / 12.92) : Math.Pow(((gs + 0.055) / 1.055), 2.4);
27.     B = (bs <= 0.03928) ? (double)(bs / 12.92) : Math.Pow(((bs + 0.055) / 1.055), 2.4);
28.
29.     return ((double)(0.2126 * R)) + ((double)(0.7152 * G)) + ((double)(0.0722 * B));
30. }

And now, I can use this in my Convert method of my IValueConverter:

IValueConverter – Convert
1. public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
2. {
3.     if (value != null && value is Color)
4.     {
5.         Color backgroundColor = (Color)value;
6.
7.         // Calculate the luminosity constrast ratio for the given color against black and white.
8.         var blackContrast = LuminosityContrast(Colors.Black, backgroundColor);
9.         var whiteContrast = LuminosityContrast(Colors.White, backgroundColor);
10.
11.         // return a solid color brush using either black or white, depending on which had the higher luminosity constrast ratio.
12.         return blackContrast >= whiteContrast ? new SolidColorBrush(Colors.Black) : new SolidColorBrush(Colors.White);
13.     }
14.     else
15.     {
16.         return new SolidColorBrush(Colors.Black);
17.     }
18. }

Finally, I can (declare and) use my converter in XAML to pick the better color for use against the background the user of my application has chosen.

Using the converter
1. <Converters:ForegroundColorFromBackgroundColorConverter x:Key="foregroundDetector" />
2. <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center"
3.            Foreground="{Binding SelectedBrush.Color, Converter={StaticResource ResourceKey=foregroundDetector}, Mode=OneWay}">
4.     <Run FontWeight="Bold">Selected Color</Run>
5. </TextBlock>

This entry was posted in C#, WPF and tagged , . Bookmark the permalink.

### 5 Responses to Choosing foreground using Luminosity Contrast Ratio

1. Chris Hutchinson says:

Brilliant! That was very useful for grid headers where the user can change the column colors.

2. cyanos says:

This was perfect for what I needed to accomplish. Thank you!

3. freddy_hh says: