15

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.

Arokh
  • 614
  • 1
  • 10
  • 18
  • to work, Instead of unsafe{} void* to byte[] , try IntPtr ptr = bitmapData.Scan0; int bytes = Math.Abs(bitmapData.Stride) * bitmapData.Height; raw = new byte[bytes]; Marshal.Copy(ptr, raw, 0, bytes); return raw; // byte[] – antonio Oct 06 '16 at 08:34

1 Answers1

23

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.

Quonux
  • 2,975
  • 1
  • 24
  • 32
TheCodeKing
  • 19,064
  • 3
  • 47
  • 70
  • Not exactly the answer I was hoping for, but using Marshal.Copy makes it look a lot nicer than copying it integer per integer. Thanks – Arokh Sep 10 '11 at 21:32