栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Python

【练手小项目】Python截图工具

Python 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

【练手小项目】Python截图工具

目录
  • 功能描述
  • 功能拆解
  • 技术方案
    • 依赖
      • tkinter
        • 全屏显示窗口
        • 监听鼠标动作
        • 显示按钮到指定位置
      • pillow
        • 截取全屏截图
        • 绘制矩形
        • 裁剪图片
      • ctypes
        • windows剪贴板函数
        • ctypes调用
    • 执行流程
  • 具体实现

功能描述

运行脚本后用鼠标拖拽选择屏幕上需要截图的区域,确认后将选中的区域放到剪贴版中,可粘贴其他程序中进行使用

功能拆解

截取屏幕画面
获取鼠标移动、点击、位置信息
裁剪图片
实时显示选中的部分
将图片添加到剪切板

技术方案 依赖 tkinter

tkinter 负责显示和处理鼠标的操作

全屏显示窗口
# 置顶
root.attributes('-topmost', True)
# 全屏
root.attributes('-fullscreen', True)
监听鼠标动作
label.bind('', self.onHoldLeftButton)
label.bind('', self.onHoldLeftButtonMove)
显示按钮到指定位置
toolkit.place(x=self.end_x, y=self.end_y, anchor='ne')
pillow

pillow 负责图片操作

截取全屏截图
 ImageGrab.grab()
绘制矩形
dImage = ImageDraw.Draw(img)
dImage.rectangle(pos, outline='red', width=2)
裁剪图片
image.crop(pos)
ctypes

ctypes 调用Windows原生API操作剪切板

windows剪贴板函数
HANDLE SetClipboardData(
  [in]           UINT   uFormat,
  [in, optional] HANDLE hMem
);

文档

ctypes调用
user32 = ctypes.windll.user32

user32.SetClipboardData.argtypes = [UINT, HANDLE]
user32.SetClipboardData.restype = HANDLE

user32.SetClipboardData(type, ctypes.c_char_p(alloc))
执行流程
  1. 截取全屏截图,全屏显示到屏幕上。
  2. 监听鼠标点击和移动操作,将点击位置和光标当前位置作为矩形的对角。
  3. 根据光标当前位置显示确认按钮
  4. 在全屏截图上将这个矩形描边绘制,重新显示到屏幕上
  5. 点击确认后将选中区域裁剪出来存入剪贴板
具体实现

通过tkinter定义窗口

import tkinter as tk

from PIL import ImageGrab, ImageTk

import image

class Window:
    def __init__(self) -> None:
        root = tk.Tk()
        root.attributes('-topmost', True)
        root.attributes('-fullscreen', True)
        
        root.bind('', lambda _: root.destroy())

        backgroud_frame = tk.Frame(root)
        backgroud_frame.grid()

        # 用于显示全屏截图
        label = tk.Label(backgroud_frame, text='123')
        label.grid()

        label.bind('', self.onHoldLeftButton)
        label.bind('', self.onHoldLeftButtonMove)

        # 截图按钮
        toolkit = tk.Frame(backgroud_frame)
        tk.Button(toolkit, text='截图', command=self.save_to_clipboard).pack()

        self.toolkit = toolkit
        self.label = label
        self.background_frame = backgroud_frame
        self.root = root
        self.start_x = 0
        self.start_y = 0
        self.end_x = 0
        self.end_y = 0

    def onHoldLeftButtonMove(self, event):
        self.end_x, self.end_y = event.x, event.y
        # 绘制矩形
        self.draw_rectangle()
        # 根据光标当前位置重新摆放截图按钮
        self.show_toolkit()

    def onHoldLeftButton(self, event):
        self.start_x, self.start_y = event.x, event.y

    def draw_rectangle(self):
        pos = (self.start_x, self.start_y, self.end_x, self.end_y)
        img = image.highlight_area(self.image, pos)
        img = image.draw_rectangle(img, pos)
        self.label_image =ImageTk.PhotoImage(img)
        self.label.configure(image= self.label_image)

    def show_toolkit(self):
        self.toolkit.place(x=self.end_x, y=self.end_y, anchor='ne')
    
    def save_to_clipboard(self):
        pos = (self.start_x, self.start_y, self.end_x, self.end_y)
        image.save_to_clipboard(image.get_area(self.image, pos))
        self.root.destroy()

    def show_forever(self):
        self.image = ImageGrab.grab()
        # 需要label_image保存引用,否则会被回收,导致无法显示
        self.label_image =ImageTk.PhotoImage(self.image)
        self.label.configure(image= self.label_image)
        self.root.mainloop()
    
if __name__ == '__main__':
    Window().show_forever()

封装图片操作

from PIL import Image, ImageGrab, ImageDraw
import numpy as np

import clipboard

def draw_rectangle(image: Image.Image, pos):
    img = image.copy()
    dImage = ImageDraw.Draw(img)
    dImage.rectangle(pos, outline='red', width=2)
    return img

def highlight_area(image: Image.Image, pos):
    background = get_dark_iamge(image)
    interest = get_area(image, pos)
    background.paste(interest, pos)
    return background

def get_area(image: Image.Image, pos):
    return image.crop(pos)

def get_dark_iamge(image: Image.Image):
    dark_arr = np.array(image) * 0.4
    return Image.fromarray(dark_arr.astype('uint8'))

def save_to_clipboard(image: Image.Image):
    image.convert('RGB')
    image.save('temp.bmp', 'BMP')
    clipboard.save_bitmap_to_clipboard('temp.bmp', image.width, image.height)

封装剪贴板操作

import ctypes
from ctypes.wintypes import HANDLE,HGLOBAL,UINT, LPVOID, BOOL,LPCSTR

def save_bitmap_to_clipboard(path, width, height):
    CF_BITMAP = 2
    user32 = ctypes.windll.user32
   
    user32.OpenClipboard(None) # 获取剪贴板的锁,传NULL表示用当前进程获取
    user32.EmptyClipboard()

    alloc = loadBitMapInMem(path, width, height)
   
    # 把内存空间地址传给剪贴板
    setClipboardData(CF_BITMAP, alloc)

    user32.CloseClipboard()

def loadBitMapInMem(path:str, width, height):
    user32 = ctypes.windll.user32
    h = user32.LoadImageA(None, LPCSTR(path.encode('utf8')), 0,  width, height, 0x00000010)
    return h

def setClipboardData(type, alloc):
    user32 = ctypes.windll.user32

    user32.SetClipboardData.argtypes = [UINT, HANDLE]
    user32.SetClipboardData.restype = HANDLE

    user32.SetClipboardData(type, ctypes.c_char_p(alloc))
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/928241.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号