I have a WPF BitmapImage which I loaded from a .JPG file, as follows:
this.m_image1.Source = new BitmapImage(new Uri(path));
I want to query as to what the colour is at specific points. For example, what is the RGB value at pixel (65,32)?
How do I go about this? I was taking this approach:
ImageSource ims = m_image1.Source;
BitmapImage bitmapImage = (BitmapImage)ims;
int height = bitmapImage.PixelHeight;
int width = bitmapImage.PixelWidth;
int nStride = (bitmapImage.PixelWidth * bitmapImage.Format.BitsPerPixel + 7) / 8;
byte[] pixelByteArray = new byte[bitmapImage.PixelHeight * nStride];
bitmapImage.CopyPixels(pixelByteArray, nStride, 0);
Though I will confess there's a bit of monkey-see, monkey do going on with this code. Anyway, is there a straightforward way to process this array of bytes to convert to RGB values?
If you want just one Pixel color:
You can get color components in a byte array. First copy the pixels in 32 bit to an array and convert that to 8-bit array with 4 times larger size
I'd like to add to Ray´s answer that you can also declare PixelColor struct as a union:
And that way you'll also have access to the UInit32 BGRA (for fast pixel access or copy), besides the individual byte components.
Much simpler. There's no need to copy the data around, you can get it directly. But this comes at a price: pointers and
unsafe
. In a specific situation, decide whether it's worth the speed and ease for you (but you can simply put the image manipulation into its own separate unsafe class and the rest of the program won't be affected).where
The error checking (whether the format is indeed BGRA and handling the case if not) will be left to the reader.
Here is how I would manipulate pixels in C# using multidimensional arrays:
usage:
If you want to update pixels, very similar code works except you will create a
WriteableBitmap
, and use this:thusly:
Note that this code converts bitmaps to Bgra32 if they arrive in a different format. This is generally fast, but in some cases may be a performance bottleneck, in which case this technique would be modified to match the underlying input format more closely.
Update
Since
BitmapSource.CopyPixels
doesn't accept a two-dimensional array it is necessary to convert the array between one-dimensional and two-dimensional. The following extension method should do the trick:There are two implementations here: The first one is fast but uses unsafe code to get an IntPtr to an array (must compile with /unsafe option). The second one is slower but does not require unsafe code. I use the unsafe version in my code.
WritePixels accepts two-dimensional arrays, so no extension method is required.
A little remark:
If you are trying to use this code (Edit: provided by Ray Burns), but get the error about the array's rank, try to edit the extension methods as follows:
and then call the
CopyPixels
method like this:The problem is, that when the extension method doesn't differ from the original, the original one is called. I guess this is because
PixelColor[,]
matchesArray
as well.I hope this helps you if you got the same problem.