You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Bitmap的应用截图异常:旧画面/黑屏问题求助

解决窗口截图旧画面/黑屏问题

核心原因

你遇到的问题是BitBlt的局限性导致的:BitBlt从屏幕显示缓冲区取数据,当窗口被遮挡、最小化,或是像Chrome这类启用硬件加速的应用(画面由GPU直接渲染,不经过系统屏幕DC),就只能捕获到缓存的旧画面甚至黑屏。RedrawWindow、UpdateWindow这类操作只会触发窗口重绘,但无法让BitBlt获取到非前台/被遮挡窗口的实时内容。

解决方案:改用PrintWindow

PrintWindow是Windows API专门用于捕获窗口内容的函数,它直接从窗口内部的绘图缓冲区获取数据,不受窗口是否在前台、是否被遮挡的影响,能拿到窗口的真实实时画面。

正确使用PrintWindow的步骤

  1. 导入依赖:通过Python自带的ctypes调用user32.dll中的PrintWindow函数,无需额外安装库。
  2. 替换BitBlt调用:用PrintWindow替代原代码中的BitBlt,注意参数正确性。

修改后的截图函数

def screenshot(window_title):
    import ctypes
    user32 = ctypes.WinDLL('user32', use_last_error=True)
    
    hwnd = win32gui.FindWindow(None, window_title)
    if not hwnd:
        print("未找到指定标题的窗口")
        return None
    
    # 获取窗口尺寸
    region = win32gui.GetWindowRect(hwnd)
    width = abs(region[0] - region[2])
    height = abs(region[1] - region[3])
    
    # 创建绘图上下文和位图
    hwnd_dc = win32gui.GetWindowDC(hwnd)
    mfc_dc = win32ui.CreateDCFromHandle(hwnd_dc)
    save_dc = mfc_dc.CreateCompatibleDC()
    save_bit_map = win32ui.CreateBitmap()
    save_bit_map.CreateCompatibleBitmap(mfc_dc, width, height)
    save_dc.SelectObject(save_bit_map)
    
    # 调用PrintWindow捕获整个窗口(参数1表示捕获整个窗口,0表示仅客户区)
    capture_success = user32.PrintWindow(hwnd, save_dc.GetSafeHdc(), 1)
    if not capture_success:
        print(f"PrintWindow调用失败,错误码: {ctypes.get_last_error()}")
    
    # 转换为PIL图像
    bmp_info = save_bit_map.GetInfo()
    bmp_str = save_bit_map.GetBitmapBits(True)
    img = Image.frombuffer('RGB',
                           (bmp_info['bmWidth'], bmp_info['bmHeight']),
                           bmp_str, 'raw', 'BGRX', 0, 1)
    
    # 释放系统资源
    win32gui.DeleteObject(save_bit_map.GetHandle())
    save_dc.DeleteDC()
    mfc_dc.DeleteDC()
    win32gui.ReleaseDC(hwnd, hwnd_dc)
    
    return img.convert('RGB')

关键修改说明

  • 移除了无效的RedrawWindow和UpdateWindow调用,PrintWindow不需要这些前置操作
  • 增加了窗口不存在的判断,避免后续报错
  • 用PrintWindow替代BitBlt,直接从窗口内部获取画面
  • 加入了错误捕获,方便排查调用失败的问题

额外注意事项

  1. 窗口标题准确性:切换浏览器标签后,窗口标题会变化,要确保传入的window_title是当前窗口的正确标题,否则FindWindow会匹配到旧窗口或找不到窗口
  2. 多显示器裁剪逻辑:检查get_monitors()返回的坐标是否正确,确保裁剪用的box计算无误(可打印坐标值核对)
  3. 捕获选项调整:如果某些应用捕获仍有问题,可以把PrintWindow的第三个参数改成0(仅捕获窗口客户区),部分应用对整个窗口的捕获支持较差

内容的提问来源于stack exchange,提问作者Roland Deschain

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 08:44:52