仅在某些应用程序中使用winAPI BitBlt捕获窗口时出现问题

2024-05-16 06:51:49 发布

您现在位置:Python中文网/ 问答频道 /正文

我已经编写了一个简单的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标志,没有任何区别。在


Tags: nameself脚本sizereturnifdefpair
1条回答
网友
1楼 · 发布于 2024-05-16 06:51:49

来自MSDN

BitBlt returns an error if the source and destination device contexts represent different devices. To transfer data between DCs for different devices, convert the memory bitmap to a DIB by calling GetDIBits. To display the DIB to the second device, call SetDIBits or StretchDIBits.

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

再次从MSDN

The desktop composition feature, introduced in Windows Vista, fundamentally changed the way applications display pixels on the screen. When desktop composition is enabled, individual windows no longer draw directly to the screen or primary display device as they did in previous versions of Windows. Instead, their drawing is redirected to off-screen surfaces in video memory, which are then rendered into a desktop image and presented on the display.

由于DWM的blitting具有这些know issues,您可以:

  1. 尝试使用其他技术;您有a nice list here

  2. 您可以使用DwmEnableComposition(DWM_EC_DISABLECOMPOSITION);

试试看有没有对你有用的。在

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

相关问题 更多 >