【python】分享一个在Windows下对应用程序python窗口后台截图的方法

最近心血来潮想自己用python写一个图色操作游戏的脚本,于是上百度一查“python后台截图”,事实上能用的也就是pywin32读取内存截图(什么设备环境、设备描述表、内存设备描述表的),而且翻来翻去就是这一套代码。

类似这个:

#获取后台窗口的句柄,注意后台窗口不能最小化
hWnd = win32gui.FindWindow("NotePad",None) #窗口的类名可以用Visual Studio的SPY++工具获取
#获取句柄窗口的大小信息
left, top, right, bot = win32gui.GetWindowRect(hWnd)
width = right - left
height = bot - top
#返回句柄窗口的设备环境,覆盖整个窗口,包括非客户区,标题栏,菜单,边框
hWndDC = win32gui.GetWindowDC(hWnd)
#创建设备描述表
mfcDC = win32ui.CreateDCFromHandle(hWndDC)
#创建内存设备描述表
saveDC = mfcDC.CreateCompatibleDC()
#创建位图对象准备保存图片
saveBitMap = win32ui.CreateBitmap()
#为bitmap开辟存储空间
saveBitMap.CreateCompatibleBitmap(mfcDC,width,height)
#将截图保存到saveBitMap中
saveDC.SelectObject(saveBitMap)
#保存bitmap到内存设备描述表
saveDC.BitBlt((0,0), (width,height), mfcDC, (0, 0), win32con.SRCCOPY)

但这个代码似乎只是针对MFC应用(不知到有多过时了),在win10下对某些游戏截图总是不完整,还被被各路神仙转来转去,乍一看博文 发布时间2021年,其实早就是20年前的代码(就连后面的print都python是不带括号的,2.x的代码)。

思来想去,PyQt不是自带一个screen模块,可以对句柄窗口就行截图吗,不知道内部实现的原理是啥,不妨试试看了:

# -*- coding: utf-8 -*-

from PyQt5.QtWidgets import QApplication
import win32gui
from numpy import array,uint8,ndarray

# 直接写一个类,方便以后使用
class Screen:
    def __init__(self,win_title=None,win_class=None,hwnd=None) -> None:
        self.app = QApplication(['WindowCapture'])
        self.screen = QApplication.primaryScreen()
        self.bind(win_title,win_class,hwnd)
    def bind(self, win_title=None,win_class=None,hwnd=None):
        '可以直接传入句柄,否则就根据class和title来查找,并把句柄做为实例属性 self._hwnd'
        if not hwnd: self._hwnd = win32gui.FindWindow(win_class, win_title)
        else: self._hwnd = hwnd
    def capture(self, savename='') -> ndarray:
        '截图方法,在窗口为 1920 x 1080 大小下,最快速度25ms (grabWindow: 17ms, to_cvimg: 8ms)'
        def to_cvimg(pix):
            '将self.screen.grabWindow 返回的 Pixmap 转换为 ndarray,方便opencv使用'
            qimg = pix.toImage()
            temp_shape = (qimg.height(), qimg.bytesPerLine() * 8 // qimg.depth())
            temp_shape += (4,)
            ptr = qimg.bits()
            ptr.setsize(qimg.byteCount())
            result = array(ptr, dtype=uint8).reshape(temp_shape)
            return result[..., :3]
        self.pix = self.screen.grabWindow(self._hwnd)
        self.img = to_cvimg(self.pix)
        if savename: self.pix.save(savename)
        return self.img

if __name__ =='__main__':
    screen = Screen(win_title='')
    screen.capture('test.bmp')

一顿操作+实验,总结如下:

1.在对某些大型应用截图时,PyQt更完整,至少不会出现漏缺的情况,虽然在windows的不同缩放比例下会出现大的黑边,但都是分布在右、下,对实际使用影响不大。

2.缺点也很明显:当窗口被拖动到屏幕可视区域之外时,无法捕捉。

这时候有的同学就急了,啥?那不是跟前台截图一样事儿的吗?那我还用个屁的PyQt,用XXX一行代码搞定了。

事实上只要这个窗口不被拖动到屏幕之外或者最小化,你想堆叠多少个都没问题(即使被其他应用遮挡),你自己看着办咯。

猜你喜欢

转载自blog.csdn.net/weixin_42117463/article/details/122283525