测试[C#]GDI+中使用BitBlt绘制图像到窗口
安神颗粒的哈喽
### 2024-5-28 WindowsFormPaint FormTES_ESEB 测试[C#]GDI+中使用BitBlt绘制图像到窗口 ``` #region 测试[C#]GDI+中使用BitBlt绘制图像到窗口 private void pbx01_Paint(object sender, PaintEventArgs e) { #region MyRegion //using (Bitmap bp = new Bitmap("1234.png")) ////using (Bitmap bp = (Bitmap)Bitmap.FromFile("123.png")) //{ // using (var mHdcGraphics = Graphics.FromHwnd(pbx01.Handle))//主设备 // { // using (var aHdcGraphics = Graphics.FromImage(bp))//辅助设备 // { // //var mHdc = mHdcGraphics.GetHdc(); // //var aHdc = aHdcGraphics.GetHdc(); // ////BitBlt(mHdc,0,0,pbx01.Width,pbx01.Height, aHdc, 0,0, (uint)TernaryRasterOperations.SRCCOPY); // 0x00CC0020 // ////BitBlt(mHdc, 0, 0, pbx01.Width, pbx01.Height, aHdc, 0, 0, 0x00CC0020); // 0x00CC0020 // //BitBlt(mHdc, 0, 0, pbx01.Width, pbx01.Height, aHdc, 0, 0, (uint)RasterOperationMode.SRCCOPY); // 0x00CC0020 // //mHdcGraphics.ReleaseHdc(mHdc); // //aHdcGraphics.ReleaseHdc(aHdc); // //也就是说,在BitBlt之前,先将和Graphics有联系的Bitmap选作DC的背景图。 // //猜测,使用Graphics.FromImage的时候,.Net底层并没有将Bitmap对应的HBitmap选入HDC而只是将两个.Net对象联系起来了,而后在DrawImage中有两次SelectObject分别选入和选出以在HBitmap上绘图。所以独立于.Net进行GDI操作的时候,需要在GDI层面再将两者联系起来,使用SelectObject。 // //下面解决方式如下 // var mHdc = mHdcGraphics.GetHdc(); // var auxiliaryHdc = aHdcGraphics.GetHdc(); // var hbitmap = bp.GetHbitmap(); // var holdObject = SelectObject(auxiliaryHdc, hbitmap); // if (holdObject != IntPtr.Zero) // { // //BitBlt(mHdc,0,0,pbx01.Width,pbx01.Height, aHdc, 0,0, (uint)TernaryRasterOperations.SRCCOPY); // 0x00CC0020 // //BitBlt(mHdc, 0, 0, pbx01.Width, pbx01.Height, aHdc, 0, 0, 0x00CC0020); // 0x00CC0020 // bool result = BitBlt(mHdc, 0, 0, pbx01.Width, pbx01.Height, auxiliaryHdc, 0, 0, (uint)RasterOperationMode.SRCCOPY); // 0x00CC0020 // if (result) // { // TraceLog($"[C#]GDI+中使用BitBlt绘制图像到窗口 成功:{result}"); // } // else // { // TraceLog($"[C#]GDI+中使用BitBlt绘制图像到窗口 失败:{result}"); // } // } // //pbx01.Refresh(); // //释放资源 // DeleteObject(hbitmap); // mHdcGraphics.ReleaseHdc(mHdc); // aHdcGraphics.ReleaseHdc(auxiliaryHdc); // } // } //} #endregion } private void btnTestGDI_Click(object sender, EventArgs e) { //pbx01.Invalidate(); //pbx01.Update(); //pbx01.Refresh(); using (Bitmap bp = new Bitmap("1234.png")) //using (Bitmap bp = (Bitmap)Bitmap.FromFile("123.png")) { using (var mHdcGraphics = Graphics.FromHwnd(pbx01.Handle))//主设备 { using (var aHdcGraphics = Graphics.FromImage(bp))//辅助设备 { //var mHdc = mHdcGraphics.GetHdc(); //var aHdc = aHdcGraphics.GetHdc(); ////BitBlt(mHdc,0,0,pbx01.Width,pbx01.Height, aHdc, 0,0, (uint)TernaryRasterOperations.SRCCOPY); // 0x00CC0020 ////BitBlt(mHdc, 0, 0, pbx01.Width, pbx01.Height, aHdc, 0, 0, 0x00CC0020); // 0x00CC0020 //BitBlt(mHdc, 0, 0, pbx01.Width, pbx01.Height, aHdc, 0, 0, (uint)RasterOperationMode.SRCCOPY); // 0x00CC0020 //mHdcGraphics.ReleaseHdc(mHdc); //aHdcGraphics.ReleaseHdc(aHdc); //也就是说,在BitBlt之前,先将和Graphics有联系的Bitmap选作DC的背景图。 //猜测,使用Graphics.FromImage的时候,.Net底层并没有将Bitmap对应的HBitmap选入HDC而只是将两个.Net对象联系起来了,而后在DrawImage中有两次SelectObject分别选入和选出以在HBitmap上绘图。所以独立于.Net进行GDI操作的时候,需要在GDI层面再将两者联系起来,使用SelectObject。 //下面解决方式如下 var mHdc = mHdcGraphics.GetHdc(); var auxiliaryHdc = aHdcGraphics.GetHdc(); var hbitmap = bp.GetHbitmap(); var holdObject = SelectObject(auxiliaryHdc, hbitmap); if (holdObject != IntPtr.Zero) { //BitBlt(mHdc,0,0,pbx01.Width,pbx01.Height, aHdc, 0,0, (uint)TernaryRasterOperations.SRCCOPY); // 0x00CC0020 //BitBlt(mHdc, 0, 0, pbx01.Width, pbx01.Height, aHdc, 0, 0, 0x00CC0020); // 0x00CC0020 bool result = BitBlt(mHdc, 0, 0, pbx01.Width, pbx01.Height, auxiliaryHdc, 0, 0, (uint)RasterOperationMode.SRCCOPY); // 0x00CC0020 if (result) { TraceLog($"[C#]GDI+中使用BitBlt绘制图像到窗口 成功:{result}"); } else { TraceLog($"[C#]GDI+中使用BitBlt绘制图像到窗口 失败:{result}"); } } //pbx01.Refresh(); //释放资源 DeleteObject(hbitmap); mHdcGraphics.ReleaseHdc(mHdc); aHdcGraphics.ReleaseHdc(auxiliaryHdc); } } } } [DllImport("User32.dll", SetLastError = true)] public static extern IntPtr FindWindow(string lpClassName, string lpWindowName); [DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool GetWindowRect(IntPtr hWnd, out Rect lpRect); [DllImport("user32.dll")] public static extern bool GetClientRect(IntPtr hWnd, out Rect lpRect); [DllImport("user32.dll", EntryPoint = "GetWindowDC")] public static extern IntPtr GetWindowDC(IntPtr hWnd); [DllImport("gdi32.dll")] public static extern IntPtr CreateCompatibleDC(IntPtr hDc); [DllImport("gdi32.dll")] public static extern IntPtr CreateCompatibleBitmap(IntPtr hDc, int nWidth, int nHeight); [DllImport("gdi32.dll")] public static extern bool DeleteDC(IntPtr hDc); [DllImport("user32.dll")] public static extern IntPtr ReleaseDC(IntPtr hwnd, IntPtr hdc); [DllImport("gdi32.dll")] public static extern IntPtr CreateDIBSection(IntPtr hdc, ref BitmapInfo bmi, uint usage, out IntPtr ppvBits, IntPtr hSection, uint dwOffset); [DllImport("gdi32.dll")] public static extern IntPtr SelectObject(IntPtr hDc, IntPtr hObject); [DllImport("gdi32.dll")] public static extern bool DeleteObject(IntPtr hObject); [DllImport("gdi32.dll", SetLastError = true)] public static extern bool BitBlt(IntPtr hObject, int nXDest, int nYDest, int nWidth, int nHeight, IntPtr hObjectSource, int nXSrc, int nYSrc, uint dwRop); [DllImport("user32.dll")] public static extern bool PrintWindow(IntPtr hwnd, IntPtr hdcBlt, uint nFlags); [StructLayout(LayoutKind.Sequential)] public struct Point { public int x; public int y; public Point(int x, int y) { this.x = x; this.y = y; } } [StructLayout(LayoutKind.Sequential)] public struct Rect { public int Left; //最左坐标 public int Top; //最上坐标 public int Right; //最右坐标 public int Bottom; //最下坐标 public int Width => Right - Left; public int Height => Bottom - Top; } [StructLayout(LayoutKind.Sequential, Pack = 2)] public struct BitmapFileHeader { public ushort bfType; public uint bfSize; public ushort bfReserved1; public ushort bfReserved2; public uint bfOffBits; } [StructLayout(LayoutKind.Sequential)] public struct BitmapInfoHeader { public uint biSize; public int biWidth; public int biHeight; public ushort biPlanes; public ushort biBitCount; public uint biCompression; public uint biSizeImage; public int biXPelsPerMeter; public int biYPelsPerMeter; public uint biClrUsed; public uint biClrImportant; public void Init() { biSize = (uint)Marshal.SizeOf(this); } } [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct RgbQuad { public byte rgbBlue; public byte rgbGreen; public byte rgbRed; public byte rgbReserved; } [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct BitmapInfo { public BitmapInfoHeader bmiHeader; public RgbQuad bmiColors; } public enum DibColorMode : uint { DIB_RGB_COLORS = 0x00, DIB_PAL_COLORS = 0x01, DIB_PAL_INDICES = 0x02 } public enum BitmapCompressionMode : uint { BI_RGB = 0, BI_RLE8 = 1, BI_RLE4 = 2, BI_BITFIELDS = 3, BI_JPEG = 4, BI_PNG = 5 } public enum RasterOperationMode : uint { SRCCOPY = 0x00CC0020, SRCPAINT = 0x00EE0086, SRCAND = 0x008800C6, SRCINVERT = 0x00660046, SRCERASE = 0x00440328, NOTSRCCOPY = 0x00330008, NOTSRCERASE = 0x001100A6, MERGECOPY = 0x00C000CA, MERGEPAINT = 0x00BB0226, PATCOPY = 0x00F00021, PATPAINT = 0x00FB0A09, PATINVERT = 0x005A0049, DSTINVERT = 0x00550009, BLACKNESS = 0x00000042, WHITENESS = 0x00FF0062, CAPTUREBLT = 0x40000000 //only if WinVer >= 5.0.0 (see wingdi.h) } public enum PrintWindowMode : uint { [Description("Only the client area of the window is copied to hdcBlt. By default, the entire window is copied.")] PW_CLIENTONLY = 0x00000001, [Description("works on windows that use DirectX or DirectComposition")] PW_RENDERFULLCONTENT = 0x00000002 } #endregion ```
龙腾一族至尊龙骑
合集:
GDI++
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义