Reputation: 11
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
Reputation: 39122
Found a combination that works...but I don't understand why (definitely not a GDI expert):
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