【问题标题】:Trouble capturing window with winAPI BitBlt for some applications only仅对某些应用程序使用 winAPI BitBlt 捕获窗口时遇到问题
【发布时间】:2013-12-16 00:45:48
【问题描述】:

我已经编写了一个简单的 python 脚本,它可以截取名称包含特定字符串的窗口的屏幕截图。我使用的代码如下,

import win32gui, win32ui, win32con import PIL.Image def getWindowHandle(name): windowList = [] win32gui.EnumWindows(lambda hwnd, wndList: wndList.append((win32gui.GetWindowText(hwnd), hwnd)), windowList) for pair in windowList: if name in pair[0]: return pair[1] return None class Window(): def __init__(self, hwnd = None): if not hwnd: return l, t, r, b = win32gui.GetClientRect(hwnd) sl, st, _, _ = win32gui.GetWindowRect(hwnd) cl, ct = win32gui.ClientToScreen(hwnd, (l, t)) self.size = (r - l, b - t) self.position = (cl - sl, ct - st) hDC = win32gui.GetWindowDC(hwnd) self.windowDC = win32ui.CreateDCFromHandle(hDC) self.newDC = self.windowDC.CreateCompatibleDC() #win32gui.ReleaseDC(hwnd, hDC) self.bitmap = win32ui.CreateBitmap() self.bitmap.CreateCompatibleBitmap(self.windowDC, self.size[0], self.size[1]) self.newDC.SelectObject(self.bitmap) def __del__(self): self.newDC.DeleteDC() self.windowDC.DeleteDC() del self.bitmap def screenshot(self, location = 'C:\\Users\\Grieverheart\\Desktop\\'): self.newDC.BitBlt((0, 0), self.size, self.windowDC, self.position, win32con.SRCCOPY) self.bitmap.Paint(self.newDC) bmpinfo = self.bitmap.GetInfo() bmpstr = self.bitmap.GetBitmapBits(True) im = PIL.Image.frombuffer('RGB', self.size, bmpstr, 'raw', 'BGRX', 0, 1) try: im.save(location + 'test.png', 'PNG') except IOError: return def main(): handle = getWindowHandle("Blender") if not handle: return window = Window(handle) window.screenshot() if __name__ == "__main__": main()

脚本为我提供了一些应用程序的黑色屏幕截图,例如 Blender 或 DOSBox。

有谁知道仅在某些应用程序中导致此问题的原因以及我该如何解决?

编辑:看来我的问题可能与this 帖子有关,尽管我不确定我必须做些什么来解决我的问题。我还想补充一点,我也尝试过添加 CAPTUREBLT 标志,没有任何区别。

【问题讨论】:

  • 尝试添加 CAPTUREBLT 标志。
  • 您使用的是启用 Aero 的 Windows Vista/7 吗?

标签: python windows winapi screenshot pywin32


【解决方案1】:

来自MSDN

如果源设备上下文和目标设备上下文代表不同的设备,BitBlt 将返回错误。要在不同设备的 DC 之间传输数据,请通过调用 GetDIBits 将内存位图转换为 DIB。要将 DIB 显示到第二个设备,请调用 SetDIBits 或 StretchDIBits。

这是什么意思?简而言之,混合 DWM(即 Aero)和非 GDI 应用程序(例如 OpenGL)会使 BiBlt 变得不可预测/不可靠。

再次来自MSDN

Windows Vista 中引入的桌面合成功能从根本上改变了应用程序在屏幕上显示像素的方式。启用桌面合成后,各个窗口不再像在以前版本的 Windows 中那样直接绘制到屏幕或主显示设备上。相反,他们的绘图被重定向到显存中的屏幕外表面,然后呈现为桌面图像并呈现在显示器上。

由于使用 DWM 进行 blitting 有这些 know issues,您可以:

  1. 尝试使用替代技术;你有a nice list here

  2. 您可以使用 DwmEnableComposition(DWM_EC_DISABLECOMPOSITION); 禁用 DWM(临时)

试试看有没有适合你的。

AFAIK 然而,可靠地获取使用 3D 渲染(DirectX 或 OpenGL)的应用程序内容的唯一方法是将自己注入到进程中并复制这些位(参见 this answer for DirectX,或挂钩 @987654327 @ 并使用 glReadPixels 回读 OpenGL)

【讨论】:

    猜你喜欢
    • 2019-10-18
    • 2020-11-03
    • 2011-01-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-12-05
    • 2021-06-02
    • 1970-01-01
    相关资源
    最近更新 更多