python 标准库调用实现全屏截图以png格式为例

 
已经将截图时间优化到1秒以内
import ctypes
import zlib
import struct
from ctypes import wintypes, c_int, POINTER, create_string_buffer
import io
import time

s = time.time()

# 加载GDI32和User32库
gdi32 = ctypes.WinDLL('gdi32')
user32 = ctypes.WinDLL('user32')

# 函数参数和返回类型设置
gdi32.BitBlt.argtypes = [wintypes.HDC, c_int, c_int, c_int, c_int, wintypes.HDC, c_int, c_int, wintypes.DWORD]
gdi32.BitBlt.restype = wintypes.BOOL

user32.GetDesktopWindow.restype = wintypes.HWND
user32.GetDC.argtypes = [wintypes.HWND]
user32.GetDC.restype = wintypes.HDC
user32.ReleaseDC.argtypes = [wintypes.HWND, wintypes.HDC]
user32.ReleaseDC.restype = wintypes.BOOL
# 定义常量
SM_CXSCREEN = 0
SM_CYSCREEN = 1

# 缩放比例
zoom = 1
screenWidth = int(user32.GetSystemMetrics(SM_CXSCREEN) * zoom)
screenHeight = int(user32.GetSystemMetrics(SM_CYSCREEN) * zoom)


# 屏幕截取
def capture_screen(x, y, width, height):
    # 获取桌面窗口句柄
    hwnd = user32.GetDesktopWindow()
    print(hwnd)
    # 获取桌面窗口的设备上下文
    hdc_src = user32.GetDC(hwnd)

    print(hdc_src)
    if len(str(hdc_src)) > 16:
        return 0

    # 创建一个与屏幕兼容的内存设备上下文
    hdc_dest = gdi32.CreateCompatibleDC(hdc_src)

    # 创建一个位图
    bmp = gdi32.CreateCompatibleBitmap(hdc_src, width, height)

    # 将位图选入内存设备上下文
    old_bmp = gdi32.SelectObject(hdc_dest, bmp)

    # 定义SRCCOPY常量
    SRCCOPY = 0x00CC0020
    # 捕获屏幕
    gdi32.BitBlt(hdc_dest, 0, 0, width, height, hdc_src, x, y, SRCCOPY)
    """
    gdi32.BitBlt(hdc_src,  # 目标设备上下文  
             x_dest,   # 目标矩形左上角的x坐标  
             y_dest,   # 目标矩形左上角的y坐标  
             width,    # 宽度  
             height,   # 高度  
             hdc_dest, # 源设备上下文  
             x_src,    # 源矩形左上角的x坐标(通常是0)  
             y_src,    # 源矩形左上角的y坐标(通常是0)  
             SRCCOPY)  # 复制选项
    """

    # 定义 RGBQUAD 结构体
    class RGBQUAD(ctypes.Structure):
        _fields_ = [("rgbBlue", ctypes.c_ubyte),
                    ("rgbGreen", ctypes.c_ubyte),
                    ("rgbRed", ctypes.c_ubyte),
                    ("rgbReserved", ctypes.c_ubyte)]

    # 定义 BITMAPINFOHEADER 结构体
    class BITMAPINFOHEADER(ctypes.Structure):
        _fields_ = [("biSize", ctypes.c_uint),
                    ("biWidth", ctypes.c_int),
                    ("biHeight", ctypes.c_int),
                    ("biPlanes", ctypes.c_ushort),
                    ("biBitCount", ctypes.c_ushort),
                    ("biCompression", ctypes.c_uint),
                    ("biSizeImage", ctypes.c_uint),
                    ("biXPelsPerMeter", ctypes.c_int),
                    ("biYPelsPerMeter", ctypes.c_int),
                    ("biClrUsed", ctypes.c_uint),
                    ("biClrImportant", ctypes.c_uint)]

    # 定义 BITMAPINFO 结构体
    class BITMAPINFO(ctypes.Structure):
        _fields_ = [("bmiHeader", BITMAPINFOHEADER),
                    ("bmiColors", RGBQUAD * 3)]  # 只分配了3个RGBQUAD的空间

    BI_RGB = 0
    DIB_RGB_COLORS = 0

    # 分配像素数据缓冲区(这里以24位位图为例,每个像素3字节)
    pixel_data = (ctypes.c_ubyte * (width * height * 3))()
    # 转换bytes
    # pixel_data = memoryview(pixel_data).tobytes()

    # 填充 BITMAPINFO 结构体
    bmi = BITMAPINFO()
    bmi.bmiHeader.biSize = ctypes.sizeof(BITMAPINFOHEADER)
    bmi.bmiHeader.biWidth = width
    bmi.bmiHeader.biHeight = -height  # 注意:负高度表示自底向上的位图
    bmi.bmiHeader.biPlanes = 1
    bmi.bmiHeader.biBitCount = 24  # 24即3*8
    bmi.bmiHeader.biCompression = BI_RGB  # 无压缩

    # 调用 GetDIBits 获取像素数据
    ret = gdi32.GetDIBits(hdc_src, bmp, 0, height, pixel_data, ctypes.byref(bmi), DIB_RGB_COLORS)
    if ret == 0:
        print("GetDIBits failed:", ctypes.WinError())


    print(time.time() - s)
    # 像素色彩换位置
    mv = memoryview(pixel_data).cast('B')
    b_stream = bytearray(width * (height+1) * 3)
    k=0
    for i in range(0, len(mv), 3):
        if i % width == 0:
            b_stream[k] == 0
            k += 1
        b_stream[k] = mv[i + 2]
        b_stream[k + 1] = mv[i + 1]
        b_stream[k + 2] = mv[i]
        k+=3
    print(time.time() - s)

    def crc32(data):  # 字节流
        crc = zlib.crc32(data)
        return crc

    def crc32_b(data):
        crc = zlib.crc32(data).to_bytes(4, byteorder='big')
        return crc

    # png图片标识符
    png_signature = b"\x89PNG\r\n\x1a\n"
    # IHDR块
    ihdr = struct.pack("!IIBBBBB", width, height, 8, 2, 0, 0, 0)
    # IHDR的CRC验证
    mid = crc32_b(b"IHDR" + ihdr)
    # 压缩图片数据
    bd = zlib.compress(bytes(b_stream))
    # IDAT的CRC验证
    crc_bytes = crc32_b(bd)
    idat_chunk = b"IDAT" + bd + crc_bytes
    # IEND块
    iend = b"\x00\x00\x00\x00IEND"
    # IEND的CRC验证
    crc_end = crc32_b(b"IEND")
    iend += crc_end

    # 写入图片操作,使用BytesIO来构建PNG
    png_io = io.BytesIO()
    png_io.write(png_signature + b"\x00\x00\x00\rIHDR" + ihdr + mid)
    idat_header = struct.pack("!I", len(bd))
    png_io.write(idat_header + idat_chunk)
    png_io.write(iend)

    # 一次性写入文件
    with open("photo.png", "wb") as f:
        f.write(png_io.getvalue())

    # 恢复设备上下文
    gdi32.SelectObject(hdc_dest, old_bmp)
    # 删除内存设备上下文
    gdi32.DeleteDC(hdc_dest)
    # 释放桌面窗口的设备上下文
    user32.ReleaseDC(hwnd, hdc_src)
    # 假设bmp已经被处理,现在删除它
    gdi32.DeleteObject(bmp)


# 进行截图
for i in range(10):
    x = capture_screen(0, 0, screenWidth, screenHeight)
    if x != 0:
        break
print(time.time() - s)
import ctypes
import zlib
import struct
from ctypes import wintypes, c_int, POINTER, create_string_buffer
import io
import time

s = time.time()

# 加载GDI32和User32库
gdi32 = ctypes.WinDLL('gdi32')
user32 = ctypes.WinDLL('user32')

# 函数参数和返回类型设置
gdi32.BitBlt.argtypes = [wintypes.HDC, c_int, c_int, c_int, c_int, wintypes.HDC, c_int, c_int, wintypes.DWORD]
gdi32.BitBlt.restype = wintypes.BOOL

user32.GetDesktopWindow.restype = wintypes.HWND
user32.GetDC.argtypes = [wintypes.HWND]
user32.GetDC.restype = wintypes.HDC
user32.ReleaseDC.argtypes = [wintypes.HWND, wintypes.HDC]
user32.ReleaseDC.restype = wintypes.BOOL
# 定义常量
SM_CXSCREEN = 0
SM_CYSCREEN = 1

# 缩放比例
zoom = 1
screenWidth = int(user32.GetSystemMetrics(SM_CXSCREEN) * zoom)
screenHeight = int(user32.GetSystemMetrics(SM_CYSCREEN) * zoom)


# 屏幕截取
def capture_screen(x, y, width, height):
    # 获取桌面窗口句柄
    hwnd = user32.GetDesktopWindow()
    print(hwnd)
    # 获取桌面窗口的设备上下文
    hdc_src = user32.GetDC(hwnd)

    print(hdc_src)
    if len(str(hdc_src)) > 16:
        return 0

    # 创建一个与屏幕兼容的内存设备上下文
    hdc_dest = gdi32.CreateCompatibleDC(hdc_src)

    # 创建一个位图
    bmp = gdi32.CreateCompatibleBitmap(hdc_src, width, height)

    # 将位图选入内存设备上下文
    old_bmp = gdi32.SelectObject(hdc_dest, bmp)

    # 定义SRCCOPY常量
    SRCCOPY = 0x00CC0020
    # 捕获屏幕
    gdi32.BitBlt(hdc_dest, 0, 0, width, height, hdc_src, x, y, SRCCOPY)
    """
    gdi32.BitBlt(hdc_src,  # 目标设备上下文  
             x_dest,   # 目标矩形左上角的x坐标  
             y_dest,   # 目标矩形左上角的y坐标  
             width,    # 宽度  
             height,   # 高度  
             hdc_dest, # 源设备上下文  
             x_src,    # 源矩形左上角的x坐标(通常是0)  
             y_src,    # 源矩形左上角的y坐标(通常是0)  
             SRCCOPY)  # 复制选项
    """

    # 定义 RGBQUAD 结构体
    class RGBQUAD(ctypes.Structure):
        _fields_ = [("rgbBlue", ctypes.c_ubyte),
                    ("rgbGreen", ctypes.c_ubyte),
                    ("rgbRed", ctypes.c_ubyte),
                    ("rgbReserved", ctypes.c_ubyte)]

    # 定义 BITMAPINFOHEADER 结构体
    class BITMAPINFOHEADER(ctypes.Structure):
        _fields_ = [("biSize", ctypes.c_uint),
                    ("biWidth", ctypes.c_int),
                    ("biHeight", ctypes.c_int),
                    ("biPlanes", ctypes.c_ushort),
                    ("biBitCount", ctypes.c_ushort),
                    ("biCompression", ctypes.c_uint),
                    ("biSizeImage", ctypes.c_uint),
                    ("biXPelsPerMeter", ctypes.c_int),
                    ("biYPelsPerMeter", ctypes.c_int),
                    ("biClrUsed", ctypes.c_uint),
                    ("biClrImportant", ctypes.c_uint)]

    # 定义 BITMAPINFO 结构体
    class BITMAPINFO(ctypes.Structure):
        _fields_ = [("bmiHeader", BITMAPINFOHEADER),
                    ("bmiColors", RGBQUAD * 3)]  # 只分配了3个RGBQUAD的空间

    BI_RGB = 0
    DIB_RGB_COLORS = 0

    # 分配像素数据缓冲区(这里以24位位图为例,每个像素3字节)
    pixel_data = (ctypes.c_ubyte * (width * height * 3))()
    # 转换bytes
    # pixel_data = memoryview(pixel_data).tobytes()

    # 填充 BITMAPINFO 结构体
    bmi = BITMAPINFO()
    bmi.bmiHeader.biSize = ctypes.sizeof(BITMAPINFOHEADER)
    bmi.bmiHeader.biWidth = width
    bmi.bmiHeader.biHeight = -height  # 注意:负高度表示自底向上的位图
    bmi.bmiHeader.biPlanes = 1
    bmi.bmiHeader.biBitCount = 24  # 24即3*8
    bmi.bmiHeader.biCompression = BI_RGB  # 无压缩

    # 调用 GetDIBits 获取像素数据
    ret = gdi32.GetDIBits(hdc_src, bmp, 0, height, pixel_data, ctypes.byref(bmi), DIB_RGB_COLORS)
    if ret == 0:
        print("GetDIBits failed:", ctypes.WinError())


    print(time.time() - s)
    # 像素色彩换位置
    mv = memoryview(pixel_data).cast('B')
    b_stream = bytearray(width * (height+1) * 3)
    k=0
    for i in range(0, len(mv), 3):
        if i % width == 0:
            b_stream[k] == 0
            k += 1
        b_stream[k] = mv[i + 2]
        b_stream[k + 1] = mv[i + 1]
        b_stream[k + 2] = mv[i]
        k+=3
    print(time.time() - s)

    def crc32(data):  # 字节流
        crc = zlib.crc32(data)
        return crc

    def crc32_b(data):
        crc = zlib.crc32(data).to_bytes(4, byteorder='big')
        return crc

    # png图片标识符
    png_signature = b"\x89PNG\r\n\x1a\n"
    # IHDR块
    ihdr = struct.pack("!IIBBBBB", width, height, 8, 2, 0, 0, 0)
    # IHDR的CRC验证
    mid = crc32_b(b"IHDR" + ihdr)
    # 压缩图片数据
    bd = zlib.compress(bytes(b_stream))
    # IDAT的CRC验证
    crc_bytes = crc32_b(bd)
    idat_chunk = b"IDAT" + bd + crc_bytes
    # IEND块
    iend = b"\x00\x00\x00\x00IEND"
    # IEND的CRC验证
    crc_end = crc32_b(b"IEND")
    iend += crc_end

    # 写入图片操作,使用BytesIO来构建PNG
    png_io = io.BytesIO()
    png_io.write(png_signature + b"\x00\x00\x00\rIHDR" + ihdr + mid)
    idat_header = struct.pack("!I", len(bd))
    png_io.write(idat_header + idat_chunk)
    png_io.write(iend)

    # 一次性写入文件
    with open("photo.png", "wb") as f:
        f.write(png_io.getvalue())

    # 恢复设备上下文
    gdi32.SelectObject(hdc_dest, old_bmp)
    # 删除内存设备上下文
    gdi32.DeleteDC(hdc_dest)
    # 释放桌面窗口的设备上下文
    user32.ReleaseDC(hwnd, hdc_src)
    # 假设bmp已经被处理,现在删除它
    gdi32.DeleteObject(bmp)


# 进行截图
for i in range(10):
    x = capture_screen(0, 0, screenWidth, screenHeight)
    if x != 0:
        break
print(time.time() - s)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值