当前位置: 首页 > article >正文

python调用window库全屏截图生成bmp位图学习

import io
import time
import struct
import ctypes
from ctypes import wintypes, c_int
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):
    for _ in range(100):
        time.sleep(0.01)
        # 获取桌面窗口句柄
        hwnd = user32.GetDesktopWindow()
        # 获取桌面窗口的设备上下文
        hdc_src = user32.GetDC(hwnd)
        if len(str(hdc_src)) > 16:
            time.sleep(0.01)
            # 释放桌面窗口的设备上下文
            user32.ReleaseDC(hwnd, hdc_src)
            continue
        else:
            break
    print(hwnd)
    print(hdc_src)
    if len(str(hdc_src)) > 16:
        return

    # 创建一个与屏幕兼容的内存设备上下文
    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))()  # 4
    # 转换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   32
    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'))

    # 位图标记
    s1 = b"BM"
    # 文件大小 纯粹的字节
    s2 = len(pixel_data) + 54
    # 保留字段1
    s3 = 0
    # 保留字段2
    s4 = 0
    # 像素数据偏移量
    s5 = 54

    start_sign = struct.pack("<2sIHHI", s1, s2, s3, s4, s5)

    print(start_sign)
    # 信息头大小
    n1 = 40
    # 图像宽度
    n2 = screenWidth
    # 图像高度
    n3 = screenHeight
    # 平面数
    n4 = 1
    # 颜色深度
    n5 = 24
    # 压缩方式
    n6 = 0
    # 图像大小
    n7 = len(pixel_data)
    # 水平分辨率
    n8 = 0
    # 垂直分辨率
    n9 = 0
    # 使用的颜色数
    n10 = 0
    # 重要颜色数
    n11 = 0
    print(n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11)
    end_sign = struct.pack('<IIIHHIIIIII', n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11)
    print(end_sign)

    # 写入图片操作,使用BytesIO来构建BMP
    bmp_io = io.BytesIO()
    bmp_io.write(start_sign + end_sign + mv)

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

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


capture_screen(0, 0, screenWidth, screenHeight)
print(time.time() - s)

"""查看图片数据"""
data = b'BM\x86\x00\x00\x00\x00\x00\x00\x006\x00\x00\x00(\x00\x00\x00\x05\x00\x00\x00\x05\x00\x00\x00\x01\x00\x18\x00\x00\x00\x00\x00P\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\x00\x00\xff\x00\x00\xff\x00\x00\xff\x00\x00\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00'

# with open("photo.bmp", "rb+")as f:
#     data = f.read()

# <表示小端序,2sBM,I表示4字节无符号整数,H表示2字节无符号整数
file_header_format = '<2sIHHI'
# 计算结构体的大小
file_header_size = struct.calcsize(file_header_format)
# 提取文件头数据
file_header_data = data[:file_header_size]
print(file_header_data)
# 解析文件头
file_header = struct.unpack(file_header_format, file_header_data)
print("文件头解析结果:")
print(f"文件类型标识: {file_header[0].decode('utf-8')}")  # 应该是 'BM',解码字节串为字符串
print(f"文件大小: {file_header[1]} 字节")
print(f"保留字段1: {file_header[2]}")
print(f"保留字段2: {file_header[3]}")
print(f"像素数据偏移量: {file_header[4]} 字节")

# BMP
info_header_format = '<IIIHHIIIIII'
info_header_size = struct.calcsize(info_header_format)

# 提取信息头数据
info_header_data = data[file_header_size:file_header_size + info_header_size]
print(info_header_data)
info_header = struct.unpack(info_header_format, info_header_data)
print("\n")
print("信息头解析结果:")
print(f"信息头大小: {info_header[0]} 字节")
print(f"图像宽度: {info_header[1]} 像素")
print(f"图像高度: {info_header[2]} 像素")
print(f"平面数: {info_header[3]}")
print(f"颜色深度(每个像素的位数): {info_header[4]} 位")
print(f"压缩方式: {info_header[5]}")
print(f"图像大小: {info_header[6]} 字节")
print(f"水平分辨率: {info_header[7]} 像素/米")
print(f"垂直分辨率: {info_header[8]} 像素/米")
print(f"使用的颜色数: {info_header[9]}")
print(f"重要颜色数: {info_header[10]}")

# 像素数据偏移量为offset,图像宽度为width,高度为height,颜色深度为bit_count
offset = file_header[4]
width = info_header[1]
height = info_header[2]
bit_count = info_header[4]
print(f"偏移量: {offset}")
print(f"图像宽度: {width}")
print(f"图像高度: {height}")
print(f"颜色深度: {bit_count}")

# 计算每行像素数据的字节数
bytes_per_row = (width * bit_count + 7) // 8
if bytes_per_row % 4 != 0:
    bytes_per_row += 4 - (bytes_per_row % 4)
print(bytes_per_row)

# 提取像素数据
pixel_data = data[offset:]
if bit_count == 24:
    for y in range(height):
        for x in range(width):
            blue = pixel_data[(y * bytes_per_row + x * 3)]
            green = pixel_data[(y * bytes_per_row + x * 3 + 1)]
            red = pixel_data[(y * bytes_per_row + x * 3 + 2)]
            print(f"像素坐标({x}, {y}) 的RGB值: ({red}, {green}, {blue})")
        print(f"每行对应的字节:{pixel_data[y * bytes_per_row:(y+1) * bytes_per_row]}")

import io
import time
import struct
import ctypes
from ctypes import wintypes, c_int
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):
    for _ in range(100):
        time.sleep(0.01)
        # 获取桌面窗口句柄
        hwnd = user32.GetDesktopWindow()
        # 获取桌面窗口的设备上下文
        hdc_src = user32.GetDC(hwnd)
        if len(str(hdc_src)) > 16:
            time.sleep(0.01)
            # 释放桌面窗口的设备上下文
            user32.ReleaseDC(hwnd, hdc_src)
            continue
        else:
            break
    print(hwnd)
    print(hdc_src)
    if len(str(hdc_src)) > 16:
        return

    # 创建一个与屏幕兼容的内存设备上下文
    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))()  # 4
    # 转换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   32
    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'))

    # 位图标记
    s1 = b"BM"
    # 文件大小 纯粹的字节
    s2 = len(pixel_data) + 54
    # 保留字段1
    s3 = 0
    # 保留字段2
    s4 = 0
    # 像素数据偏移量
    s5 = 54

    start_sign = struct.pack("<2sIHHI", s1, s2, s3, s4, s5)

    print(start_sign)
    # 信息头大小
    n1 = 40
    # 图像宽度
    n2 = screenWidth
    # 图像高度
    n3 = screenHeight
    # 平面数
    n4 = 1
    # 颜色深度
    n5 = 24
    # 压缩方式
    n6 = 0
    # 图像大小
    n7 = len(pixel_data)
    # 水平分辨率
    n8 = 0
    # 垂直分辨率
    n9 = 0
    # 使用的颜色数
    n10 = 0
    # 重要颜色数
    n11 = 0
    print(n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11)
    end_sign = struct.pack('<IIIHHIIIIII', n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11)
    print(end_sign)

    # 写入图片操作,使用BytesIO来构建BMP
    bmp_io = io.BytesIO()
    bmp_io.write(start_sign + end_sign + mv)

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

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


capture_screen(0, 0, screenWidth, screenHeight)
print(time.time() - s)

"""查看图片数据"""
data = b'BM\x86\x00\x00\x00\x00\x00\x00\x006\x00\x00\x00(\x00\x00\x00\x05\x00\x00\x00\x05\x00\x00\x00\x01\x00\x18\x00\x00\x00\x00\x00P\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\x00\x00\xff\x00\x00\xff\x00\x00\xff\x00\x00\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00'

# with open("photo.bmp", "rb+")as f:
#     data = f.read()

# <表示小端序,2sBM,I表示4字节无符号整数,H表示2字节无符号整数
file_header_format = '<2sIHHI'
# 计算结构体的大小
file_header_size = struct.calcsize(file_header_format)
# 提取文件头数据
file_header_data = data[:file_header_size]
print(file_header_data)
# 解析文件头
file_header = struct.unpack(file_header_format, file_header_data)
print("文件头解析结果:")
print(f"文件类型标识: {file_header[0].decode('utf-8')}")  # 应该是 'BM',解码字节串为字符串
print(f"文件大小: {file_header[1]} 字节")
print(f"保留字段1: {file_header[2]}")
print(f"保留字段2: {file_header[3]}")
print(f"像素数据偏移量: {file_header[4]} 字节")

# BMP
info_header_format = '<IIIHHIIIIII'
info_header_size = struct.calcsize(info_header_format)

# 提取信息头数据
info_header_data = data[file_header_size:file_header_size + info_header_size]
print(info_header_data)
info_header = struct.unpack(info_header_format, info_header_data)
print("\n")
print("信息头解析结果:")
print(f"信息头大小: {info_header[0]} 字节")
print(f"图像宽度: {info_header[1]} 像素")
print(f"图像高度: {info_header[2]} 像素")
print(f"平面数: {info_header[3]}")
print(f"颜色深度(每个像素的位数): {info_header[4]} 位")
print(f"压缩方式: {info_header[5]}")
print(f"图像大小: {info_header[6]} 字节")
print(f"水平分辨率: {info_header[7]} 像素/米")
print(f"垂直分辨率: {info_header[8]} 像素/米")
print(f"使用的颜色数: {info_header[9]}")
print(f"重要颜色数: {info_header[10]}")

# 像素数据偏移量为offset,图像宽度为width,高度为height,颜色深度为bit_count
offset = file_header[4]
width = info_header[1]
height = info_header[2]
bit_count = info_header[4]
print(f"偏移量: {offset}")
print(f"图像宽度: {width}")
print(f"图像高度: {height}")
print(f"颜色深度: {bit_count}")

# 计算每行像素数据的字节数
bytes_per_row = (width * bit_count + 7) // 8
if bytes_per_row % 4 != 0:
    bytes_per_row += 4 - (bytes_per_row % 4)
print(bytes_per_row)

# 提取像素数据
pixel_data = data[offset:]
if bit_count == 24:
    for y in range(height):
        for x in range(width):
            blue = pixel_data[(y * bytes_per_row + x * 3)]
            green = pixel_data[(y * bytes_per_row + x * 3 + 1)]
            red = pixel_data[(y * bytes_per_row + x * 3 + 2)]
            print(f"像素坐标({x}, {y}) 的RGB值: ({red}, {green}, {blue})")
        print(f"每行对应的字节:{pixel_data[y * bytes_per_row:(y+1) * bytes_per_row]}")


http://www.kler.cn/a/488737.html

相关文章:

  • MySQL学习笔记2【函数/约束/多表查询】
  • pytest 参数介绍
  • 使用vue-pdf预览pdf和解决pdf电子签章显示问题
  • YOLOv5改进 | CARAFE提高精度的上采样方法
  • Three.js 渲染技术:打造逼真3D体验的幕后功臣
  • 国产信创实践(国能磐石服务器操作系统CEOS +东方通TongHttpServer)
  • TrustRAG:增强RAG系统鲁棒性与可信度的创新框架
  • 儿童玩具加拿大SOR/2011-17测试安全标准
  • Transformer:深度学习的变革力量
  • ffmpeg 常用命令 案例
  • 【Uniapp-Vue3】在组件中通过props进行数据传递
  • Vue.js 组件开发:从基础到进阶
  • 蓝桥杯嵌入式速通(1)
  • Java的 BIO、NIO、AIO?分别的作用和用法
  • YCM托管YashanDB报错 /home/yashan/.yasboot/.env is not existed
  • Github 2025-01-08 C开源项目日报 Top10
  • 青少年编程与数学 02-006 前端开发框架VUE 13课题、事件处理
  • 2012mfc,自绘列表控件
  • 【Linux】Linux常见指令(上)
  • RK3588上CPU和GPU算力以及opencv resize的性能对比测试
  • RabbitMQ基础(简单易懂)
  • 协同过滤算法私人诊所系统|Java|SpringBoot|VUE|
  • 2025年01月07日Github流行趋势
  • spring task使用
  • STM32: 默认开启ADC中断
  • 记录IDEA与maven兼容版本