Python调用Win32 API捕获后台窗口时如何设置捕获顶部坐标排除标题栏
解决方案
根因说明
PrintWindow 本身不支持指定偏移捕获,只能完整写入目标窗口的全量内容到指定DC,因此仅调整位图大小只会裁剪底部区域,无法去掉顶部内容。你可以选择两种方案实现指定高度的顶部裁剪:
方案1:PIL图像裁剪(最易实现,适合90%以上场景)
先捕获完整窗口内容,再通过PIL的裁剪方法去掉顶部指定高度区域即可:
import win32gui import win32ui from ctypes import windll from PIL import Image target_window_hwnd = win32gui.FindWindow(None, "Math Analysis - Google Chrome") # 手动指定需要排除的顶部总高度,包含Chrome自绘标题栏、地址栏、书签栏等 application_window_topbar_size = 200 # 获取窗口客户区完整尺寸 l, t, r, b = win32gui.GetClientRect(target_window_hwnd) full_width = r - l full_height = b - t # 捕获完整窗口内容 hwndDC = win32gui.GetWindowDC(target_window_hwnd) mfcDC = win32ui.CreateDCFromHandle(hwndDC) saveDC = mfcDC.CreateCompatibleDC() saveBitMap = win32ui.CreateBitmap() saveBitMap.CreateCompatibleBitmap(mfcDC, full_width, full_height) saveDC.SelectObject(saveBitMap) # 传参3兼容捕获Chrome等开启硬件加速的窗口内容 windll.user32.PrintWindow(target_window_hwnd, saveDC.GetSafeHdc(), 3) # 转PIL图像后裁剪顶部区域 bmpinfo = saveBitMap.GetInfo() bmpstr = saveBitMap.GetBitmapBits(True) full_image = Image.frombuffer('RGB', (bmpinfo['bmWidth'], bmpinfo['bmHeight']), bmpstr, 'raw', 'BGRX', 0, 1) # 核心裁剪逻辑:保留从顶部指定高度以下到窗口底部的所有内容 cropped_image = full_image.crop((0, application_window_topbar_size, full_width, full_height)) # 资源释放 win32gui.DeleteObject(saveBitMap.GetHandle()) saveDC.DeleteDC() mfcDC.DeleteDC() win32gui.ReleaseDC(target_window_hwnd, hwndDC) # 可直接使用cropped_image,或保存验证 # cropped_image.save("cropped_result.png")
方案2:内存DC层BitBlt裁剪(适合高性能需求场景)
如果需要避免生成全量PIL图像的开销,可以通过双DC实现内存层面的偏移裁剪:
import win32gui import win32ui import win32con from ctypes import windll from PIL import Image target_window_hwnd = win32gui.FindWindow(None, "Math Analysis - Google Chrome") application_window_topbar_size = 200 # 获取窗口完整尺寸 l, t, r, b = win32gui.GetClientRect(target_window_hwnd) full_width = r - l full_height = b - t # 计算裁剪后的尺寸 cropped_width = full_width cropped_height = full_height - application_window_topbar_size # 临时DC:捕获完整窗口内容 hwndDC = win32gui.GetWindowDC(target_window_hwnd) sourceDC = win32ui.CreateDCFromHandle(hwndDC) tempDC = sourceDC.CreateCompatibleDC() tempBitMap = win32ui.CreateBitmap() tempBitMap.CreateCompatibleBitmap(sourceDC, full_width, full_height) tempDC.SelectObject(tempBitMap) windll.user32.PrintWindow(target_window_hwnd, tempDC.GetSafeHdc(), 3) # 目标DC:从临时DC偏移复制需要的区域 targetDC = sourceDC.CreateCompatibleDC() targetBitMap = win32ui.CreateBitmap() targetBitMap.CreateCompatibleBitmap(sourceDC, cropped_width, cropped_height) targetDC.SelectObject(targetBitMap) # 核心偏移复制:从临时DC的(0, 顶部裁剪高度)位置开始复制对应大小的内容到目标DC targetDC.BitBlt((0, 0), (cropped_width, cropped_height), tempDC, (0, application_window_topbar_size), win32con.SRCCOPY) # 转换为PIL图像 bmpinfo = targetBitMap.GetInfo() bmpstr = targetBitMap.GetBitmapBits(True) cropped_image = Image.frombuffer('RGB', (bmpinfo['bmWidth'], bmpinfo['bmHeight']), bmpstr, 'raw', 'BGRX', 0, 1) # 资源释放 win32gui.DeleteObject(tempBitMap.GetHandle()) win32gui.DeleteObject(targetBitMap.GetHandle()) tempDC.DeleteDC() targetDC.DeleteDC() sourceDC.DeleteDC() win32gui.ReleaseDC(target_window_hwnd, hwndDC)
注意事项
- 对于Chrome、Edge这类自绘界面的软件,系统API无法区分软件自身的地址栏、菜单栏,手动指定
application_window_topbar_size是最简化的实现方式 - 捕获常规无硬件加速的软件时,可将
PrintWindow的第三个参数改为1,仅捕获系统级客户区,自动排除系统自带标题栏
内容的提问来源于stack exchange,提问作者D.Moore
相关产品推荐
相关产品推荐

