如何在Python中捕获后台非活动窗口的指定区域?
Python捕获后台非活动窗口指定区域的解决方案
问题背景
已实现后台捕获非活动窗口,但无法精准截取指定区域(需按左上、右下坐标定义),要求不将窗口前置、不使用全屏截图避免干扰。
原代码问题分析
原代码创建的位图大小错误(直接使用窗口屏幕右/下边界值而非窗口宽高),且未针对指定区域做像素复制限制,导致捕获整个窗口。
解决方案1:直接捕获指定区域(高效版)
通过BitBlt精准复制窗口DC中的指定区域,无需先捕获完整窗口:
import win32gui, win32ui from ctypes import windll from PIL import Image def capture_window_region(hwnd, region): # region格式:(窗口内左上x, 窗口内左上y, 窗口内右下x, 窗口内右下y) x1, y1, x2, y2 = region width = x2 - x1 height = y2 - y1 # 初始化DC资源 hwndDC = win32gui.GetWindowDC(hwnd) mfcDC = win32ui.CreateDCFromHandle(hwndDC) saveDC = mfcDC.CreateCompatibleDC() # 创建对应区域大小的位图 saveBitMap = win32ui.CreateBitmap() saveBitMap.CreateCompatibleBitmap(mfcDC, width, height) saveDC.SelectObject(saveBitMap) # 复制窗口指定区域到目标DC(SRCCOPY表示直接复制像素) windll.gdi32.BitBlt(saveDC.GetSafeHdc(), 0, 0, width, height, hwndDC, x1, y1, 0x00CC0020) # 转换为PIL图像 bmpinfo = saveBitMap.GetInfo() bmpstr = saveBitMap.GetBitmapBits(True) image = Image.frombuffer('RGB', (width, height), bmpstr, 'raw', 'BGRX', 0, 1) # 释放系统资源 win32gui.DeleteObject(saveBitMap.GetHandle()) saveDC.DeleteDC() mfcDC.DeleteDC() win32gui.ReleaseDC(hwnd, hwndDC) return image # 目标窗口名称 WINDOW_NAME = 'Play Chrome Dinosaur Game Online - elgooG - Google Chrome' hwnd = win32gui.FindWindow(None, WINDOW_NAME) # 替换为实际需要的窗口内区域坐标 target_region = (100, 200, 800, 600) screen_capture = capture_window_region(hwnd, target_region) screen_capture.save('window_region_capture.png')
解决方案2:先捕获完整窗口再裁剪(简洁版)
保留原PrintWindow逻辑,通过PIL的crop方法裁剪指定区域,代码改动最小:
import win32gui, win32ui from ctypes import windll from PIL import Image def capture_window(hwnd): rect = win32gui.GetWindowRect(hwnd) width = rect[2] - rect[0] height = rect[3] - rect[1] hwndDC = win32gui.GetWindowDC(hwnd) mfcDC = win32ui.CreateDCFromHandle(hwndDC) saveDC = mfcDC.CreateCompatibleDC() saveBitMap = win32ui.CreateBitmap() saveBitMap.CreateCompatibleBitmap(mfcDC, width, height) saveDC.SelectObject(saveBitMap) windll.user32.PrintWindow(hwnd, saveDC.GetSafeHdc(), 2) bmpinfo = saveBitMap.GetInfo() bmpstr = saveBitMap.GetBitmapBits(True) image = Image.frombuffer('RGB', (width, height), bmpstr, 'raw', 'BGRX', 0, 1) # 释放资源 win32gui.DeleteObject(saveBitMap.GetHandle()) saveDC.DeleteDC() mfcDC.DeleteDC() win32gui.ReleaseDC(hwnd, hwndDC) return image # 裁剪指定区域 def crop_image(image, region): return image.crop(region) WINDOW_NAME = 'Play Chrome Dinosaur Game Online - elgooG - Google Chrome' hwnd = win32gui.FindWindow(None, WINDOW_NAME) full_window = capture_window(hwnd) # 替换为实际窗口内区域坐标 target_region = (100, 200, 800, 600) screen_capture = crop_image(full_window, target_region) screen_capture.save('window_region_capture.png')
关键说明
- 区域坐标:需传入窗口内部的相对坐标(以窗口左上角为原点),可通过截图工具获取目标区域的相对位置
- 资源释放:必须严格释放DC和位图资源,避免内存泄漏
- 参数选择:
BitBlt方案适合高性能场景,裁剪方案适合快速调试和修改区域
内容的提问来源于stack exchange,提问作者yakubszatkowski
相关产品推荐
相关产品推荐

