tags:

views:

70

answers:

0

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:

  1. I'd like to remove the intermediate Bitmap from the above code entirely, and go directly from my int[,] array to the device-compatible bitmap (i.e. the IntPtr). I presume this would involve calling CreateCompatibleBitmap, but I don't know how to go from that call to actually manipulating the pixel values.
  2. 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?