tags:

views:

2723

answers:

7

In Silverlight 3 there is now a WriteableBitmap which provides get/put pixel abilities. This can be done like so:

// setting a pixel example
WriteableBitmap bitmap = new WriteableBitmap(400, 200);
Color c = Colors.Purple;
bitmap.Pixels[0] = c.A << 24 | c.R << 16 | c.G << 8 | c.B;

Basically, setting a Pixel involves setting its color, and that comes by bitshifting the alpha, red, blue, green values into an integer.

My question is, how would you turn an integer back to a Color? What goes in the missing spot in this example:

// getting a pixel example
int colorAsInt = bitmap.Pixels[0];
Color c;
// TODO:: fill in the color c from the integer ??

Thanks for any help you might have, I'm just not up on my bit shifting and I'm sure others will run into this roadblock at some point.

A: 
Color.FromArgb(intVal)
Nelson
to clarify, there is no FromArgb(int) method in Silverlight.. only FromArgb(byte, byte, byte, byte) - that is part of my problem
SmartyP
A: 

You might be looking for the ColorTranslator class, but I'm not sure it's available in SilverLight or what you need. It's absolutely a good one to be aware of though.

Edit: Here was one person's suggestion (use reflection to duplicate the class, so from then on you have a converter available that people are already familiar with).

280Z28
good suggestion on using the reflector.. it got me to where i could read the R,G,B values, and after a bit more hacking I got the alpha parsing as well.. i added an answer with it using only bit shifting..
SmartyP
+1  A: 

You could possibly use BitConverter.GetBytes() to convert your int to a byte array that would work with the overloads of FromArgb that silverlight has...

Color.FromArgb(BitConverter.GetBytes(intVal)); 

// or if that doesn't work
var bytes = BitConverter.GetBytes(intVal);
Color.FromArgb(bytes[3], bytes[2], bytes[1], bytes[0]);
Scott Ivey
the second suggestion here works great, but the bits are backwards, this works:Color.FromArgb(bytes[3], bytes[2], bytes[1], bytes[0]);
SmartyP
This would be horrendously (unacceptably) slow for operating on the pixels of a bitmap.
280Z28
oops - updated the example accordingly. thanks for catching that :)
Scott Ivey
+2  A: 

using the reflector i found how R,G,B are parsed in the standard .net call (not available in Silverlight):

System.Drawing.ColorTranslator.FromWin32()

from that i guessed how to get the alpha channel as well, and this does the job:

Color c2 = Color.FromArgb((byte)((colorAsInt >> 0x18) & 0xff), 
                          (byte)((colorAsInt >> 0x10) & 0xff), 
                          (byte)((colorAsInt >> 8) & 0xff), 
                          (byte)(colorAsInt & 0xff));
SmartyP
A: 

What hasn't been covered is that WriteableBitmap uses premultiplied ARGB32 so if you have a semitransparent pixel the R, G, and B values are scaled from 0 to the Alpha value. To get the Color value back, you need to do the opposite and scale it back up to 0 to 255. Something like

r = (byte)(r * (255d / alpha))

Bill Reiss
A: 
public static Color ToColor(this uint argb)
{
    return Color.FromArgb((byte)((argb & -16777216) >> 0x18),
                          (byte)((argb & 0xff0000) >> 0x10),
                          (byte)((argb & 0xff00) >> 8),
                          (byte)(argb & 0xff));
}

and using:

Color c = colorAsInt.ToColor()
FFire
A: 

I think something like this should work:

public byte[] GetPixelBytes(WriteableBitmap bitmap)
{
   int[] pixels = bitmap.Pixels;
   int length = pixels.Length * 4;
   byte[] result = new byte[length]; // ARGB
   Buffer.BlockCopy(pixels, 0, result, 0, length);
   return result;
}

Once you have the bytes, getting colors is easy with any of the various Color APIs.

Judah Himango