C# Getting the pixel data efficiently from System.Drawing.Bitmap

Arokh picture Arokh · Sep 10, 2011 · Viewed 20.8k times · Source

I have several (~2GB) raw 24bpp RGB files on HDD. Now I want to retrieve a portion of it and scale it to the desired size.
(The only scales allowed are 1, 1/2, 1/4, 1/8, ..., 1/256)

So I'm currently reading every line from the rectangle of interest into an array, which leaves me with a bitmap which has correct height but wrong width.

As the next step I'm creating a Bitmap from the newly created array.
This is done with by using a pointer so there is no copying of data involved.
Next I'm calling GetThumbnailImage on the Bitmap, which creates a new bitmap with the correct dimensions.

Now I want to return the raw pixel data (as a byte array) of the newly created bitmap. But to achieve that I'm currently copying the data using LockBits into a new array.

So my question is: Is there a way to get the pixel data from a Bitmap into a byte array without copying it?

Something like:

var bitmapData = scaledBitmap.LockBits(...)
byte[] rawBitmapData = (byte[])bitmapData.Scan0.ToPointer()
scaledBitmap.UnlockBits(bitmapData)
return rawBitmapData 

I'm well aware that this doesn't work, it is just an example to what I basically want to achieve.

Answer

TheCodeKing picture TheCodeKing · Sep 10, 2011

I think this is your best bet.

var bitmapData = scaledBitmap.LockBits(...);
var length = bitmapData.Stride * bitmapData.Height;

byte[] bytes = new byte[length];

// Copy bitmap to byte[]
Marshal.Copy(bitmapData.Scan0, bytes, 0, length);
scaledBitmap.UnlockBits(bitmapData);

You have to copy it, if you want a pass around a byte[].

You don't have to delete the bytes that were allocated, you just need to Dispose of the original Bitmap object when done as it implements IDisposable.