mat
mat

Reputation: 11

c# gdi32 bitblt seems to do nothing

I'm trying to use BitBlt to get regions of a graphics and store them in bitmaps. But here, I do something easier to understand my problem:

        Bitmap sourceBitmap = new Bitmap(64, 64, PixelFormat.Format32bppRgb);
        Graphics sourceGraphics = Graphics.FromImage(sourceBitmap);

        Bitmap destBitmap = new Bitmap(64, 64, PixelFormat.Format32bppRgb);
        Graphics destGraphics = Graphics.FromImage(destBitmap);

        sourceGraphics.FillRectangle(new SolidBrush(Color.Red), new Rectangle(0, 0, 30, 30));
        sourceGraphics.FillRectangle(new SolidBrush(Color.Green), new Rectangle(30, 30, 30, 30));

        destGraphics.FillRectangle(new SolidBrush(Color.Blue), new Rectangle(0, 0, 30, 30));
        destGraphics.FillRectangle(new SolidBrush(Color.Yellow), new Rectangle(30, 30, 30, 30));

        IntPtr destDC = destGraphics.GetHdc();
        IntPtr destHB = destBitmap.GetHbitmap();
        IntPtr old = SelectObject(destDC, destHB);

        IntPtr sourceDC = sourceGraphics.GetHdc();
        IntPtr sourceHB = sourceBitmap.GetHbitmap();
        old = SelectObject(sourceDC, sourceHB);

        int success = BitBlt(
            destDC, 0, 0, 64, 64, sourceDC, 0, 0, 0x00CC0020
        );

Why after the BitBlt my destBitmap contains blue/yellow rectangles (initial bitmap in destination) instead of the red/green rectangles which should have been blitted from the source bitmap ?

Imports are done like this :

    [System.Runtime.InteropServices.DllImportAttribute("gdi32.dll")]
    private static extern int BitBlt(
      IntPtr hdcDest,     // handle to destination DC (device context)
      int nXDest,         // x-coord of destination upper-left corner
      int nYDest,         // y-coord of destination upper-left corner
      int nWidth,         // width of destination rectangle
      int nHeight,        // height of destination rectangle
      IntPtr hdcSrc,      // handle to source DC
      int nXSrc,          // x-coordinate of source upper-left corner
      int nYSrc,          // y-coordinate of source upper-left corner
      System.Int32 dwRop  // raster operation code
      );

    [System.Runtime.InteropServices.DllImportAttribute("gdi32.dll")]
    public static extern IntPtr SelectObject(IntPtr hdc, IntPtr obj);

    [System.Runtime.InteropServices.DllImportAttribute("gdi32.dll")]
    public static extern void DeleteObject(IntPtr obj);

And finally cleaning code, and bitmap streaming to see bitmap content :

        DeleteObject(destHB);
        DeleteObject(sourceHB);
        destGraphics.ReleaseHdc();
        sourceGraphics.ReleaseHdc();

        string path = "c:/tmp/dest.png";
        destBitmap.Save(path);

Upvotes: 1

Views: 6819

Answers (1)

Idle_Mind
Idle_Mind

Reputation: 39122

Found a combination that works...but I don't understand why (definitely not a GDI expert):

BitBlt() across Managed Bitmaps

I've added in calls to create compatible DCs with CreateCompatibleDC().

But note that in the actual call to BitBlt(), I'm still using the original DC "destDC" for the destination DC (not the new "destCDC"), but the new compatible DC "sourceCDC" for the source DC. No other combo seemed to work. I still, however, had to create a compatible DC for the destination even though I wasn't using it in the BitBlt() call:

    private const int SRCCOPY = 0xCC0020;

    [System.Runtime.InteropServices.DllImportAttribute("gdi32.dll")]
    private static extern int BitBlt(
      IntPtr hdcDest,     // handle to destination DC (device context)
      int nXDest,         // x-coord of destination upper-left corner
      int nYDest,         // y-coord of destination upper-left corner
      int nWidth,         // width of destination rectangle
      int nHeight,        // height of destination rectangle
      IntPtr hdcSrc,      // handle to source DC
      int nXSrc,          // x-coordinate of source upper-left corner
      int nYSrc,          // y-coordinate of source upper-left corner
      int dwRop  // raster operation code
      );

    [System.Runtime.InteropServices.DllImportAttribute("gdi32.dll")]
    public static extern IntPtr CreateCompatibleDC(IntPtr hdc);

    [System.Runtime.InteropServices.DllImportAttribute("gdi32.dll")]
    public static extern IntPtr SelectObject(IntPtr hdc, IntPtr obj);

    [System.Runtime.InteropServices.DllImportAttribute("gdi32.dll")]
    public static extern void DeleteObject(IntPtr obj);

    private void button1_Click(object sender, EventArgs e)
    {
        Bitmap sourceBitmap = new Bitmap(64, 64, PixelFormat.Format32bppRgb);
        Graphics sourceGraphics = Graphics.FromImage(sourceBitmap);

        Bitmap destBitmap = new Bitmap(64, 64, PixelFormat.Format32bppRgb);
        Graphics destGraphics = Graphics.FromImage(destBitmap);

        sourceGraphics.FillRectangle(new SolidBrush(Color.Red), new Rectangle(0, 0, 30, 30));
        sourceGraphics.FillRectangle(new SolidBrush(Color.Green), new Rectangle(30, 30, 30, 30));

        destGraphics.FillRectangle(new SolidBrush(Color.Blue), new Rectangle(0, 0, 30, 30));
        destGraphics.FillRectangle(new SolidBrush(Color.Yellow), new Rectangle(30, 30, 30, 30));

        IntPtr destDC = destGraphics.GetHdc();
        IntPtr destCDC = CreateCompatibleDC(destDC);
        IntPtr destHB = destBitmap.GetHbitmap();
        IntPtr oldDest = SelectObject(destCDC, destHB);

        IntPtr sourceDC = sourceGraphics.GetHdc();
        IntPtr sourceCDC = CreateCompatibleDC(sourceDC);
        IntPtr sourceHB = sourceBitmap.GetHbitmap();
        IntPtr oldSource = SelectObject(sourceCDC, sourceHB);

        int success = BitBlt(
            destDC, 0, 0, 64, 64, sourceCDC, 0, 0, SRCCOPY
        );

        SelectObject(destCDC, oldDest);
        SelectObject(sourceCDC, oldSource);

        DeleteObject(destCDC);
        DeleteObject(sourceCDC);

        DeleteObject(destHB);
        DeleteObject(sourceHB);

        destGraphics.ReleaseHdc();
        sourceGraphics.ReleaseHdc();

        pictureBox1.Image = sourceBitmap;
        pictureBox2.Image = destBitmap;
    }

Anyone have any insight as to why this combo works?...

Upvotes: 1

Related Questions