前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Win32/C# 应用不依赖任何库使用纯 GDI+ 对窗口截图(BitBlt)

Win32/C# 应用不依赖任何库使用纯 GDI+ 对窗口截图(BitBlt)

作者头像
walterlv
发布2023-10-22 11:11:17
5150
发布2023-10-22 11:11:17
举报

在 Windows 上有 GDI+ 来操作位图,不止能完成很多的位图操作,还提供了与 Win32 窗口的互操作,可以截到 Win32 窗口的图片。

如果你希望对窗口截图,那么可使用本文提供的方法。

没有依赖

本文对窗口的截图几乎不需要任何额外的依赖(当然,都 GDI 了,Windows 系统还是要的)。

不过,你可以考虑使用 Lsj.Util.Win32 来简化代码,所以如果不介意的话也推荐安装,避免手工写一大堆的 P/Invoke。如果打算自己写 P/Invoke 又不熟的话,你可以参考 使用 PInvoke.net Visual Studio Extension 辅助编写 Win32 函数签名 - walterlv

如果你的项目可以使用 System.Drawing.Bitmap 类的话,那更推荐直接使用 Bitmap,那样更简单。请参考 Win32/C# 应用不依赖任何库使用纯 GDI+ 对窗口截图(BitBlt) - walterlv

开始截图

如果你使用了 Lsj.Util.Win32 库,那么需要引用一些命名空间:

1 2 3 4

using Lsj.Util.Win32; using Lsj.Util.Win32.BaseTypes; using Lsj.Util.Win32.Enums; using Lsj.Util.Win32.Structs;

这个命名空间中已经带了很多我们需要用到的 Win32 互操作需要用到的数据结构,所以本文代码中只会列出库中暂时没有的(不然代码太多了)。

代码如下:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35

public static byte[] CaptureWindow(HWND hWnd, int width, int height) { // 创建兼容内存 DC。 var wdc = User32.GetWindowDC(hWnd); var cdc = Gdi32.CreateCompatibleDC(wdc); // 创建兼容位图 DC。 var hBitmap = Gdi32.CreateCompatibleBitmap(wdc, width, height); // 关联兼容位图和兼容内存,不这么做,下面的像素位块(bit_block)转换不会生效到 hBitmap。 var oldHBitmap = Gdi32.SelectObject(cdc, (IntPtr)hBitmap); // 注:使用 GDI+ 截取“使用硬件加速过的”应用时,截取到的部分是全黑的。 var result = Gdi32.BitBlt(cdc, 0, 0, width, height, wdc, 0, 0, RasterCodes.SRCCOPY); try { // 保存图片。 if (result) { var data = GetImageFromHBitmap(wdc, hBitmap, width, height); return data; } else { var error = Kernel32.GetLastError(); throw new Win32Exception((int)error); } } finally { // 回收资源。 Gdi32.SelectObject(cdc, oldHBitmap); Gdi32.DeleteObject((IntPtr)hBitmap); Gdi32.DeleteDC(cdc); User32.ReleaseDC(hWnd, wdc); } }

其中,GetImageFromHBitmap 方法的实现就比较麻烦了——我们需要手工写图片文件的文件头!

分成三个部分写入:

  1. BMP 位图文件头
  2. BMP 信息
  3. 位图数据

实现如下:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58

private static unsafe byte[] GetImageFromHBitmap(HDC hdc, HBITMAP hBitmap, int width, int height) { var data = new bytesizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + width * height * 3; var bitmapInfoHeader = new BITMAPINFOHEADER { biSize = (uint)sizeof(BITMAPINFOHEADER), biWidth = width, biHeight = height, biPlanes = 1, biBitCount = 24, biCompression = Compression.BI_PNG, biSizeImage = 0, biXPelsPerMeter = 0, biYPelsPerMeter = 0, biClrUsed = 0, biClrImportant = 0, }; fixed (void* lpvBits = data) { var lpvBitsOnData = new IntPtr((long)lpvBits + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER)); var got = Gdi32.GetDIBits(hdc, hBitmap, 0, height, lpvBitsOnData, new BITMAPINFO { bmiColors = new RGBQUAD1, bmiHeader = bitmapInfoHeader }, (uint)DIBColorTableIdentifiers.DIB_RGB_COLORS); } var fileHeader = new BITMAPFILEHEADER { bfOffBits = (uint)sizeof(BITMAPFILEHEADER) + (uint)sizeof(BITMAPINFOHEADER), bfSize = (uint)data.Length, bfType = 0x4D42, // BM }; GetBytes(fileHeader).CopyTo(data, 0); GetBytes(bitmapInfoHeader).CopyTo(data, sizeof(BITMAPFILEHEADER)); return data; } private static byte[] GetBytes<T>(T @struct) where T : struct { int size = Marshal.SizeOf(@struct); byte[] data = new bytesize; IntPtr ptr = Marshal.AllocHGlobal(size); Marshal.StructureToPtr(@struct, ptr, true); Marshal.Copy(ptr, data, 0, size); Marshal.FreeHGlobal(ptr); return data; } StructLayout(LayoutKind.Sequential, Pack = 2) private struct BITMAPFILEHEADER { public ushort bfType; public uint bfSize; public ushort bfReserved1; public ushort bfReserved2; public uint bfOffBits; }

这里代代码不涉及到格式转换,因此你只能生成 BMP 格式。

更多截窗口方法

参考资料

本文会经常更新,请阅读原文: https://blog.walterlv.com/post/pure-win32-capture-window-to-bitmap.html ,以避免陈旧错误知识的误导,同时有更好的阅读体验。

本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。欢迎转载、使用、重新发布,但务必保留文章署名 吕毅 (包含链接: https://blog.walterlv.com ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请 与我联系 ([email protected])

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020-05-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 没有依赖
  • 开始截图
  • 更多截窗口方法
相关产品与服务
图数据库 KonisGraph
图数据库 KonisGraph(TencentDB for KonisGraph)是一种云端图数据库服务,基于腾讯在海量图数据上的实践经验,提供一站式海量图数据存储、管理、实时查询、计算、可视化分析能力;KonisGraph 支持属性图模型和 TinkerPop Gremlin 查询语言,能够帮助用户快速完成对图数据的建模、查询和可视化分析。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档