Tuesday, October 13, 2009

Colors. Part 2.

Enumerate all Known Colors and put them in the dictionary
Dictionary<KnownColor, int> colorsRGB;
can be done this way:
int
    numAliceBlue = (int)KnownColor.AliceBlue,
    numYellowGreen = (int)KnownColor.YellowGreen,
    numColors = numYellowGreen - numAliceBlue + 1;
colorsRGB = new Dictionary<KnownColor, int>(numColors);
for (int i = numAliceBlue; i <= numYellowGreen; i++)
{
    KnownColor kc = (KnownColor)i;
    colorsRGB.Add(kc, Color.FromKnownColor(kc).ToArgb());
}

Then I can sort the collection using LINQ:
Sort by name:
var sortedColors = (from clr in colorsRGB
                    orderby clr.Key
                    select clr).ToArray();
by RGB value:
var sortedColors = (from clr in colorsRGB
                   orderby clr.Value descending
                   select clr).ToArray();

I created a function ColorWeight to “weight” a color (just sum of R, G, and B components),
And even can sort by the “weight”:
var sortedColors = (from clr in colorsRGB
                    orderby ColorWeight(clr.Key) descending
                    select clr).ToArray();

I do like LINQ!

For the test I draw buttons with KnownColor as background. I wanted to have foreground color to be recognizable on the background.
This turn out to be not easy task. I did not want to mess with non-RGB presentations (like HSV or HSL) which would simplify the task.
At first I tried “inverted” color:
return Color.FromArgb((int)backColor.ToArgb() ^ 0xF0F0F0);
It did not work well.
So I created “color weight”
private int ColorWeight(Color color)
{
    int bColor = (int)color.ToArgb(),
        r = (bColor & 0x00FF0000) >> 16,
        g = (bColor & 0x0000FF00) >> 8,
        b = bColor & 0x000000FF;
    return r + g + b;
}

It is not perfect, but kind of fit the purpose: after all I put Black text if “weight” > 0x60+0x60+0x60 and White text otherwise.
This is the result:



No comments:

Post a Comment