CreateDCFromHandle select object Python 中的 TOP 坐标

CreateDCFromHandle select object TOP coordinate in Python

我需要在 Windows 上捕获特定应用程序 window,即使它没有聚焦或在前台,也没有 window 的顶部 header bar,为了简单起见,我在 'application_window_topbar_size' 变量中手动指定了哪个高度。

monitor_info = GetMonitorInfo(MonitorFromPoint((0,0))) # get screen information
work_area = monitor_info.get("Work")
screen_width = work_area[2] # if taskbar is on the left
screen_height = work_area[3] # if taskbar is on the left

target_window_hwnd = win32gui.FindWindow(None, ("Math Analysis - Google Chrome"))
application_window_topbar_size = 200 # just roughly for testing

    hwndDC = win32gui.GetWindowDC(target_window_hwnd) 
    mfcDC  = win32ui.CreateDCFromHandle(hwndDC)    
    saveDC = mfcDC.CreateCompatibleDC()
    saveBitMap = win32ui.CreateBitmap()
    saveBitMap.CreateCompatibleBitmap(mfcDC, screen_width, screen_height)
    saveDC.SelectObject(saveBitMap)

#    saveDC.BitBlt((0, 0), (screen_width, screen_height), mfcDC, (0, application_window_topbar_size),win32con.SRCCOPY)
    
    result = windll.user32.PrintWindow(target_window_hwnd, saveDC.GetSafeHdc(), 3)
    bmpinfo = saveBitMap.GetInfo()
    bmpstr = saveBitMap.GetBitmapBits(True)
    screen_image = Image.frombuffer('RGB', (bmpinfo['bmWidth'], bmpinfo['bmHeight']), bmpstr, 'raw', 'BGRX', 0, 1)
    win32gui.DeleteObject(saveBitMap.GetHandle())
    saveDC.DeleteDC()
    mfcDC.DeleteDC()
    win32gui.ReleaseDC(target_window_hwnd, hwndDC)

捕获例程应该适用于 windows 句柄“WM_PRINT”(感谢 IInspectable 的评论),但是 我无法弄清楚如何设置捕获区域的TOP坐标。换句话说,我想在没有顶栏的情况下捕获目标window。改变高度是一回事,从逻辑上讲,如果捕获矩形坐标从 0,0 开始,那么它只切割 window 的底部区域,而不是顶部。我尝试使用 BitBlt() 但失败了。

---------------- 以下替代版本基于 IInspectable 评论

target_window_hwnd = win32gui.FindWindow(None, ("Math Analysis - Google Chrome"))
application_window_topbar_size = 200 # just roughly for testing

    hwndDC = win32gui.GetWindowDC(target_window_hwnd) 
    mfcDC  = win32ui.CreateDCFromHandle(hwndDC)    
    saveDC = mfcDC.CreateCompatibleDC()
    saveBitMap = win32ui.CreateBitmap()

    l, t, r, b = win32gui.GetClientRect(target_window_hwnd)
    screen_width = r - l
    screen_height = b -t

    saveBitMap.CreateCompatibleBitmap(mfcDC, screen_width, screen_height)
    saveDC.SelectObject(saveBitMap)   
    result = windll.user32.PrintWindow(target_window_hwnd, saveDC.GetSafeHdc(), 3)
    bmpinfo = saveBitMap.GetInfo()
    bmpstr = saveBitMap.GetBitmapBits(True)
    screen_image = Image.frombuffer('RGB', (bmpinfo['bmWidth'], bmpinfo['bmHeight']), bmpstr, 'raw', 'BGRX', 0, 1)
    win32gui.DeleteObject(saveBitMap.GetHandle())
    saveDC.DeleteDC()
    mfcDC.DeleteDC()
    win32gui.ReleaseDC(target_window_hwnd, hwndDC)

仍然,改变顶部坐标只影响高度,不影响捕获的内容(能够只捕获 window 的 'document area',不包括地址 bar/toolbar)。

经过长时间的搜索和尝试,我意识到最明显的解决方案是在制作屏幕截图后对其进行裁剪。这样,不需要的部分(在我的例子中是顶部栏)可以很容易地去掉。

使用 PIL Image 可以轻松裁剪:

box = (left, top, right, bottom)
screen_image.crop(box)