views:

166

answers:

3

How can I check if two System.Drawing.Color structures represent the same color in 16 bit color depth (or generally based on the value of Screen.PrimaryScreen.BitsPerPixel)?

Let's say I set Form.TransparencyKey to Value1 (of Color type), I want to check that when the user selects a new background color for the form (Value2), I don't set the entire form transparent.

On 32bit color depth screens I simply compare the two values:

if (Value1 == Value2)

However, this does not work on 16bit color depth screens, as more Color values for the Value2 would represent the same actual 16bit color as Value1, as I found out the hard way.

A: 

Since ColorTranslator.ToWin32 is used under the hood, does this work?

if( ColorTranslator.ToWin32(Value1) == ColorTranslator.ToWin32(Value2) )
jyoung
That will not work, because it always results in an integer representation of a 32-bit color.
Webleeuw
The .NET source for ColorTranslator.ToWin32 is:<code>"public static int ToWin32(Color c) { return c.R << Win32RedShift | c.G << Win32GreenShift | c.B << Win32BlueShift;}" </code>where Win32RedShift = 0; Win32GreenShift = 8; Win32BlueShift = 16; Can this be modified in such as that in converts the value to a 16 bit color depth? And more generally, to a Screen.PrimaryScreen.BitsPerPixel color depth?
David
+1  A: 

There are two pixel formats for 16-bit color, 555 and 565. You'd have to mask the R, G and B values with 0xf8 (5 bits) and 0xfc (6 bits) before comparing them. Do keep in mind that the machine on which you run the designer is not representative for the machine on which your program runs.

Hans Passant
A: 

Try the following code:

void MyTestMethod() {
    TransparencyKey = Color.FromArgb(128, 128, 64);
    BackColor = Color.FromArgb(128, 128, 71);

    byte tR = ConvertR(TransparencyKey.R);
    byte tG = ConvertG(TransparencyKey.G);
    byte tB = ConvertB(TransparencyKey.B);

    byte bR = ConvertR(BackColor.R);
    byte bG = ConvertG(BackColor.G);
    byte bB = ConvertB(BackColor.B);

    if (tR == bR &&
        tG == bG &&
        tB == bB) {
        MessageBox.Show("Equal: " + tR + "," + tG + "," + tB + "\r\n" +
            bR + "," + bG + "," + bB);
    }
    else {
        MessageBox.Show("NOT Equal: " + tR + "," + tG + "," + tB + "\r\n" +
            bR + "," + bG + "," + bB);
    }
}

byte ConvertR(byte colorByte) {
    return (byte)(((double)colorByte / 256.0) * 32.0);
}

byte ConvertG(byte colorByte) {
    return (byte)(((double)colorByte / 256.0) * 64.0);
}

byte ConvertB(byte colorByte) {
    return (byte)(((double)colorByte / 256.0) * 32.0);
}

Just fiddle with the TransparancyKey and BackColor to see if it works for you. For me it did. And yes, I know it's bloated and ugly code, it's just meant as example of course.

Webleeuw
Just to understand, if you can give me more details on why you multiply the red value with 32, the green value with 64 and the blue value with 32? Thanks
David
For the same reason as nobugz answer: 16-bit RGB (true)color in Windows are build up from 5, 6 and 5 bits (2 to the power of 5 is 32, 2 to the power of 6 is 64). Therefore, if you divide the original Red and Blue bytes by 256 and multiply them by 32 you get the rounded down 5 bits representation. The same applies to the Green's 6 bits.
Webleeuw