I need to access each pixel of a Bitmap, work with them, then save them to a Bitmap.
Using Bitmap.GetPixel()
and Bitmap.SetPixel()
, my program runs slowly.
How can I quickly convert Bitmap
to byte[]
and back?
I need a byte[]
with length = (4 * width * height)
, containing RGBA data of each pixel.
You can do it a couple of different ways. You can use
unsafe
to get direct access to the data, or you can use marshaling to copy the data back and forth. The unsafe code is faster, but marshaling doesn't require unsafe code. Here's a performance comparison I did a while back.Here's a complete sample using lockbits:
Here's the same thing, but with marshaling:
You want LockBits. You can then extract the bytes you want from the BitmapData object it gives you.
There is another way that is way faster and much more convenient. If you have a look at the Bitmap constructors you will find one that takes and IntPtr as the last parameter. That IntPtr is for holding pixel data. So how do you use it?
What you have now is a simple Integer array and a Bitmap referencing the same memory. Any changes you make to the Integer array will be directly affecting the Bitmap. Let us try this with a simple brightness transform.
You may notice that I have used a little trick to avoid doing floating point math within the loop. This improves performance quite a bit. And when you are done you need to clean up a little of course...
I have ignored the alpha component here but you are free to use that as well. I have thrown together a lot of bitmap editing tools this way. It is much faster and more reliable than Bitmap.LockBits() and best of all, it requires zero memory copying to start editing your bitmap.
You can use Bitmap.LockBits method. Also if you want to use parallel task execution, you can use the Parallel class in System.Threading.Tasks namespace. Following links have some samples and explanations.
Try this C# solution.
Create a winforms app for testing.
Add a Button and a PictureBox, and a click event and a form closing event.
Use the following code for your form:
Now, any edits you make to the array will automatically update the Bitmap.
You will need to call the refresh method on the picturebox to see these changes.
Building on @notJim answer (and with help from http://www.bobpowell.net/lockingbits.htm), I developed the following that makes my life a lot easier in that I end up with an array of arrays that allows me to jump to a pixel by it's
x
andy
coordinates. Of course, thex
coordinate needs to be corrected for by the number of bytes per pixel, but that is an easy extension.