win32gui.GetWindowDC 方法的作用是获取指定窗口的设备上下文(Device Context,简称 DC)。DC 是 Windows 中用于绘制图形的核心对象,它包含了绘图所需的各种属性和状态,可以用于在窗口或屏幕上进行绘制操作。
GetWindowDC 方法返回的是一个窗口的 DC,可以用于在该窗口上进行绘制操作。需要注意的是,获取到的 DC 必须在使用完毕后通过调用 ReleaseDC 方法进行释放,否则可能会导致内存泄漏或其他问题。
# 获取窗口的设备上下文DC(Device Context)
hwnd_dc = win32gui.GetWindowDC(hwnd)
win32ui.CreateDCFromHandle 方法的作用是根据给定的设备上下文句柄(DC 句柄),创建一个 Python 对象表示该 DC,以便在 Python 代码中对该 DC 进行操作。
该方法通常用于在 Python 代码中获取某个窗口或设备的 DC,以便进行绘制操作。在 Windows 系统中,每个窗口、设备或打印机都有一个与之关联的 DC,可以通过调用 Windows API 函数(如 GetDC、GetWindowDC 等)获取该 DC 的句柄。然后,可以使用该方法将该句柄转换为 Python 对象,以便在 Python 代码中进行绘制操作。
需要注意的是,使用完 DC 后,需要及时释放该 DC,以避免资源泄漏。可以通过调用 Python 对象的 ReleaseHdc 方法或者调用 Windows API 函数(如 ReleaseDC、DeleteDC 等)释放该 DC。
# 根据窗口的DC创建一个内存中的DC
mfc_dc = win32ui.CreateDCFromHandle(hwnd_dc)
mfc_dc.CreateCompatibleDC 方法的作用是创建一个与指定设备上下文(Device Context,简称 DC)兼容的内存 DC(Memory DC)。内存 DC 是一个虚拟的 DC,它并不与任何物理设备相关联,所有的绘制操作都在内存中进行。内存 DC 可以用于离屏绘制、双缓冲等操作,可以大大提高绘制效率和图形质量。
创建内存 DC 时,需要指定一个已有的 DC 对象作为参考,以便确定内存 DC 的属性(如分辨率、颜色格式等)与参考 DC 相同。创建完成后,可以将 GDI 对象(如位图、画笔、字体等)选入内存 DC 中,进行绘制操作。绘制完成后,可以将内存 DC 中的内容复制到物理设备的 DC 中,或者直接将内存 DC 中的内容作为位图保存到文件中。
# 创建一个设备兼容的DC
save_dc = mfc_dc.CreateCompatibleDC()
save_bitmap = win32ui.CreateBitmap 方法的作用是创建一个空的位图对象,并返回该位图对象的句柄。该方法不需要传入任何参数,创建的位图对象可以在之后的操作中用来存储绘制结果或者作为绘制目标。
需要注意的是,创建的空位图对象并没有指定宽度、高度和颜色位数等信息,因此在使用之前需要调用其 CreateCompatibleBitmap 方法来创建一个与指定设备上下文(Device Context,简称 DC)兼容的位图对象,并指定其宽度、高度和颜色位数等信息。
# 创建一个位图对象准备保存图片
save_bitmap = win32ui.CreateBitmap()
save_bitmap.CreateCompatibleBitmap 方法的作用是创建一个与指定设备上下文(Device Context,简称 DC)兼容的位图对象,并返回该位图对象的句柄。该方法的参数可以指定该位图的宽度、高度和颜色位数等信息,也可以直接传入一个已有的位图对象来创建一个与之兼容的位图对象。
该方法通常用于在内存中创建一个位图对象,以便进行离屏绘制等操作。创建完成后,可以通过将该位图对象选入一个 DC 中,来在该 DC 上进行绘制操作。
# 在内存中创建与指定DC兼容的位图对象
save_bitmap.CreateCompatibleBitmap(mfc_dc, width, height)
save_dc.SelectObject 方法的作用是将一个 GDI 对象(如位图、画笔、字体等)选入设备上下文(Device Context,简称 DC)中,使得该 GDI 对象可以在该 DC 上进行绘制操作。同时,该方法返回的是原来在该 DC 中被选中的 GDI 对象的句柄,可以在之后的操作中用来恢复该 DC 的状态。
# 将内存中与指定DC设备兼容的位图对象选入指定DC中
save_dc.SelectObject(save_bitmap)
save_dc.BitBlt 方法的作用是将一个设备上下文(Device Context,简称 DC)中的图像复制到另一个 DC 中。该方法的参数包括源 DC、目标 DC、源矩形区域、目标矩形区域以及复制方式等信息。
BitBlt 是 Bit Block Transfer 的缩写,表示位块传输。该方法可以用于在不同的 DC 之间传输位图、图像或者其他像素数据。它可以在不同的设备之间进行传输,例如从内存到屏幕、从屏幕到内存、从打印机到屏幕等等。BitBlt 方法是 GDI(图形设备接口)中的一个核心函数,常用于图像处理、图形界面设计等领域。
# 形参从左到右依次为:
# hdcDest:目标设备上下文(DC),即要将图像复制到的 DC。(Optional)
# nXDest:目标矩形区域的左上角 x 坐标。
# nYDest:目标矩形区域的左上角 y 坐标。
# nWidth:要复制的矩形区域的宽度。
# nHeight:要复制的矩形区域的高度。
# hdcSrc:源设备上下文(DC),即要从哪个 DC 复制图像。
# nXSrc:源矩形区域的左上角 x 坐标。
# nYSrc:源矩形区域的左上角 y 坐标。
# dwRop:复制方式,即如何将源图像复制到目标 DC 中。可以使用 GDI 的常量来指定复制方式,例如
# SRCCOPY、SRCINVERT、MERGECOPY 等。
# 其中,hdcDest 和 hdcSrc 表示设备上下文(DC),可以是窗口 DC、位图 DC、打印 DC 等等。
# nXDest、nYDest、nWidth 和 nHeight 表示目标矩形区域的左上角坐标和宽度、高度。
# nXSrc 和 nYSrc 表示源矩形区域的左上角坐标。
# dwRop 表示复制方式,可以指定如何将源图像复制到目标 DC 中,例如直接复制、取反、合并等等。
save_dc.BitBlt((0, 0), (width, height), mfc_dc, (0, 0), win32con.SRCCOPY)
# 如果没有指定 hdcDest 参数,则 BitBlt 方法将使用当前设备上下文作为目标 DC。
# 在绘制窗口或者位图等图形时,通常需要先创建一个 DC,然后将其选入窗口或者位图中,这样就可以在该 DC 上进行绘制操作。
# 在这种情况下,如果没有指定 hdcDest 参数,则 BitBlt 方法将使用当前选中的 DC 作为目标 DC。
# 如果当前没有选中任何 DC,则该方法将会失败。
# 因此,在使用 BitBlt 方法时,需要先将目标 DC 选入设备上下文中,或者显式地指定 hdcDest 参数。
将位图对象(save_bitmap)转换为OpenCV可以直接读取的格式
# 将位图转换为OpenCV格式的数组
signed_ints_array = save_bitmap.GetBitmapBits(True)
frame = np.frombuffer(signed_ints_array, dtype='uint8')
frame.shape = (height, width, 4)
frame = cv2.cvtColor(frame, cv2.COLOR_BGRA2RGB)
最后要释放被占用的内存资源
# 删除位图对象以便释放资源
win32gui.DeleteObject(save_bitmap.GetHandle())
# 删除内存中的DC对象,释放资源
save_dc.DeleteDC()
mfc_dc.DeleteDC()
win32gui.ReleaseDC(hwnd, hwnd_dc)
这里简单总结一下整个流程
1. 创建各类DC,最终目的是要创建一个与指定DC(设备上下文)设备兼容的内存DC
2. 创建位图对象,并将设备兼容的内存对象选入指定的DC中(也就是文中的save_dc)
3. 利用save_dc.BitBlt方法进行截图操作,本质上是将mfc_dc中的图像复制到save_bitmap中
4. 转换位图对象(save_bitmap)为OpenCV的格式
5. 删除各类对象,以便释放资源
如果要对视频或游戏进行循环截图,这其中除了第3步需要循环执行以外剩下的步骤只需执行一次即可,因为调用save_dc.BitBlt方法是进行截图的实质性操作,其它步骤只是在做准备和收尾工作。