I am storing bitmap-like data in a two-dimensional int
array. To convert this array into a GDI-compatible bitmap (for use with BitBlt
), I am using this function:
public IntPtr GetGDIBitmap(int[,] data)
{
int w = data.GetLength(0);
int h = data.GetLength(1);
IntPtr ret = IntPtr.Zero;
using (Bitmap bmp = new Bitmap(w, h))
{
for (int x = 0; x < w; x++)
{
for (int y = 0; y < h; y++)
{
Color color = Color.FromArgb(data[x, y]);
bmp.SetPixel(x, y, color);
}
}
ret = bmp.GetHbitmap();
}
return ret;
}
This works as expected, but the call to bmp.GetHbitmap()
has to allocate memory for the returned bitmap.
I'd like to modify this method in two (probably related) ways:
- I'd like to remove the intermediate
Bitmap
from the above code entirely, and go directly from myint[,]
array to the device-compatible bitmap (i.e. theIntPtr
). I presume this would involve callingCreateCompatibleBitmap
, but I don't know how to go from that call to actually manipulating the pixel values. - This should logically follow from the answer to the first, but I'd also like my method to re-use existing GDI bitmap handles (instead of creating a new bitmap each time).
How can I do this?
NOTE: I don't really use Bitmap.SetPixel()
, as its performance could best be described as "glacial". The code is just for illustration.
Update: I think a possible answer to #2 (still using Bitmap
but re-using an existing GDI bitmap) is something like this:
public void CopyGDIBitmap(int[,] data, IntPtr dest)
{
int w = data.GetLength(0);
int h = data.GetLength(1);
using (Bitmap bmp = new Bitmap(w, h))
{
for (int x = 0; x < data.GetLength(0); x++)
{
for (int y = 0; y < data.GetLength(1); y++)
{
Color color = Color.FromArgb(data[x, y]);
bmp.SetPixel(x, y, color);
}
}
BitmapData bmpData = bmp.LockBits(
new Rectangle(0, 0, w, h), ImageLockMode.ReadWrite,
PixelFormat.Format32bppRgb);
// this part won't work:
uint length = (uint)(w * h * 4);
RtlCopyMemory(dest, bmpData.Scan0, length);
bmp.UnlockBits(bmpData);
}
}
The BitmapData.Scan0
property exposes a pointer to the start of the bitmap's actual data, but I think the pointer that comes back from Bitmap.GetHbitmap()
doesn't point to the same place in the data, so this code wouldn't work as is (also, the Stride
has to be taken into account).
Anybody know how I could make this work?