I am using a random color for the background in my Windows Forms application. Now I want to display a label.
The problem is that when the random color is white and the label is too, then the label is not visible.
How can I get a perfect color that is visible on my background color? (My background color is a random color from System.Drawing.Color
.)
There are various ways to ensure a proper contrast.
Option one : I usually stick to keeping the text Black or White, depending on the brightness of back color.
To get the brightness one could simply go for the built-in function Color.GetBrightness()
Unfortunately this is not really a good solution, as the result is not perceptually correct; to wit: Green and Yellow have the same values, which is obviously not what our eyes will perceive.
Instead this tiny function will help:
float getBrightness(Color c)
{ return (c.R * 0.299f + c.G * 0.587f + c.B *0.114f) / 256f; }
Now we can pick either Black or White:
Label lbl = new Label();
lbl.BackColor = colors[rnd.Next(colors.Count)]; // get a random color
lbl.ForeColor = getBrightness(lbl.BackColor) < 0.55 ? Color.White : Color.Black;
The code uses a list of known colors:
List<Color> colors = ((KnownColor[])Enum.GetValues(typeof(KnownColor))).
Select(x => Color.FromKnownColor(x)).ToList();
Option two : If you want to get colors in the foreground you could pick it randomly and repeat until you get a decent contrast by comparing e.g.
while (Math.Abs(c1.GetBrightness() - c2.GetBrightness()) < 0.5f )
c2 = colors[rnd.Next(colors.Count)];
Note that you must not push the epsilon value too high or else it won't find a suitable color. This happens when trying to find a color that is too far away from a medium brightness! You could add a counter and after a while pick simply black or white..
Option three : Yet another way would be to construct a color with Color.FromArgb().
You could start by inverting each channel, which will give nice color contrasts; but if the color one is of medium brightness and/or saturation you would have to correct, maybe again by picking black or white..
Note: for the above image I have enumerated all KnownColors, which already looks pretty random.
To add some order you may sort the list by color properties, e.g. by hue, then by brightness:
List<Color> allcolors = ((KnownColor[])Enum.GetValues(typeof(KnownColor)))
.Select(x => Color.FromKnownColor(x))
.OrderBy(x => x.GetHue()).ThenBy(x => getBrightness(x)).ToList();