|
发表于 2025-5-4 10:27:57
|
显示全部楼层
本帖最后由 kbq1415 于 2025-5-4 10:35 编辑
Windows截屏程序
用的是Python
- import ctypes
- import sys
- import time
- # 定义Windows API所需的结构体和常量
- class BITMAPINFOHEADER(ctypes.Structure):
- _fields_ = [
- ('biSize', ctypes.c_ulong),
- ('biWidth', ctypes.c_long),
- ('biHeight', ctypes.c_long),
- ('biPlanes', ctypes.c_ushort),
- ('biBitCount', ctypes.c_ushort),
- ('biCompression', ctypes.c_ulong),
- ('biSizeImage', ctypes.c_ulong),
- ('biXPelsPerMeter', ctypes.c_long),
- ('biYPelsPerMeter', ctypes.c_long),
- ('biClrUsed', ctypes.c_ulong),
- ('biClrImportant', ctypes.c_ulong)
- ]
- class BITMAPINFO(ctypes.Structure):
- _fields_ = [
- ('bmiHeader', BITMAPINFOHEADER),
- ('bmiColors', ctypes.c_ulong * 3)
- ]
- class POINT(ctypes.Structure):
- _fields_ = [("x", ctypes.c_long), ("y", ctypes.c_long)]
- # GDI常量
- SRCCOPY = 0x00CC0020
- DIB_RGB_COLORS = 0
- WH_MOUSE_LL = 14
- WM_LBUTTONDOWN = 0x0201
- WM_LBUTTONUP = 0x0202
- WM_MOUSEMOVE = 0x0200
- # 全局变量存储选区坐标
- start_point = POINT()
- end_point = POINT()
- dragging = False
- # 鼠标钩子回调函数
- def low_level_mouse_handler(nCode, wParam, lParam):
- global start_point, end_point, dragging
- if nCode == 0:
- event = wParam
- mouse_data = ctypes.cast(lParam, ctypes.POINTER(MSLLHOOKSTRUCT)).contents
- if event == WM_LBUTTONDOWN:
- start_point.x = mouse_data.pt.x
- start_point.y = mouse_data.pt.y
- end_point.x = mouse_data.pt.x
- end_point.y = mouse_data.pt.y
- dragging = True
- elif event == WM_MOUSEMOVE and dragging:
- # 实时更新选区终点
- end_point.x = mouse_data.pt.x
- end_point.y = mouse_data.pt.y
- elif event == WM_LBUTTONUP:
- end_point.x = mouse_data.pt.x
- end_point.y = mouse_data.pt.y
- dragging = False
- return 1 # 终止钩子
- return ctypes.windll.user32.CallNextHookEx(None, nCode, wParam, lParam)
- def select_region():
- """通过鼠标交互选择屏幕区域"""
- print("请按住鼠标左键拖拽选择区域,释放左键完成选择")
-
- # 安装鼠标钩子
- hook_proc = ctypes.WINFUNCTYPE(ctypes.c_int, ctypes.c_int, ctypes.c_int, ctypes.POINTER(ctypes.c_void_p))(low_level_mouse_handler)
- hook = ctypes.windll.user32.SetWindowsHookExA(WH_MOUSE_LL, hook_proc, None, 0)
-
- # 消息循环
- msg = ctypes.wintypes.MSG()
- while ctypes.windll.user32.GetMessageA(ctypes.byref(msg), None, 0, 0) != 0:
- if not dragging:
- break
- ctypes.windll.user32.TranslateMessage(ctypes.byref(msg))
- ctypes.windll.user32.DispatchMessageA(ctypes.byref(msg))
-
- # 卸载钩子
- ctypes.windll.user32.UnhookWindowsHookEx(hook)
-
- # 规范坐标
- x1 = min(start_point.x, end_point.x)
- y1 = min(start_point.y, end_point.y)
- x2 = max(start_point.x, end_point.x)
- y2 = max(start_point.y, end_point.y)
- return (x1, y1, x2, y2)
- def take_screenshot(x1=0, y1=0, x2=None, y2=None, filename='screenshot.bmp'):
- """
- 执行屏幕截图
- :param x1: 区域左上角X坐标
- :param y1: 区域左上角Y坐标
- :param x2: 区域右下角X坐标(None表示屏幕右边缘)
- :param y2: 区域右下角Y坐标(None表示屏幕下边缘)
- :param filename: 输出文件名
- """
- user32 = ctypes.windll.user32
- gdi32 = ctypes.windll.gdi32
-
- # 获取屏幕尺寸
- if x2 is None: x2 = user32.GetSystemMetrics(0)
- if y2 is None: y2 = user32.GetSystemMetrics(1)
- width = x2 - x1
- height = y2 - y1
-
- # 设备上下文操作
- hdc = user32.GetDC(None)
- memdc = gdi32.CreateCompatibleDC(hdc)
- bmp = gdi32.CreateCompatibleBitmap(hdc, width, height)
- old_bmp = gdi32.SelectObject(memdc, bmp)
-
- # 复制屏幕区域
- gdi32.BitBlt(memdc, 0, 0, width, height, hdc, x1, y1, SRCCOPY)
-
- # 准备位图信息结构
- bmi = BITMAPINFO()
- bmi.bmiHeader.biSize = ctypes.sizeof(BITMAPINFOHEADER)
- bmi.bmiHeader.biWidth = width
- bmi.bmiHeader.biHeight = -height # 从上到下
- bmi.bmiHeader.biPlanes = 1
- bmi.bmiHeader.biBitCount = 24
- bmi.bmiHeader.biCompression = 0
-
- # 获取位图数据
- stride = ((width * 3 + 3) // 4) * 4
- buffer_size = stride * height
- buffer = ctypes.create_string_buffer(buffer_size)
- gdi32.GetDIBits(hdc, bmp, 0, height, buffer, ctypes.byref(bmi), DIB_RGB_COLORS)
-
- # 构建BMP文件
- file_header = bytearray(b'BM')
- file_header.extend((14 + 40 + buffer_size).to_bytes(4, 'little'))
- file_header.extend(bytes(4))
- file_header.extend((14 + 40).to_bytes(4, 'little'))
-
- info_header = bytearray()
- info_header.extend(bmi.bmiHeader.biSize.to_bytes(4, 'little'))
- info_header.extend(width.to_bytes(4, 'little', signed=True))
- info_header.extend((-height).to_bytes(4, 'little', signed=True))
- info_header.extend(bmi.bmiHeader.biPlanes.to_bytes(2, 'little'))
- info_header.extend(bmi.bmiHeader.biBitCount.to_bytes(2, 'little'))
- info_header.extend(bmi.bmiHeader.biCompression.to_bytes(4, 'little'))
- info_header.extend((stride * height).to_bytes(4, 'little'))
- info_header.extend(bytes(16))
-
- with open(filename, 'wb') as f:
- f.write(file_header)
- f.write(info_header)
- f.write(buffer)
-
- # 清理资源
- gdi32.SelectObject(memdc, old_bmp)
-
复制代码
|
|