Python中基于Tkinte设计图片查看编辑器(第30节)


在日常的生活和工作中, 我们经常需要对照片进行涂鸦或者备注重要信息,就像在纸上绘画一样。除了通过手机涂鸦照片,我们也可以通过电脑在指定图像上“画画”或“写字”。

Python作为一门功能强大且易于学习的编程语言,拥有许多强大的库来处理图像。本节教程将介绍如何通过Python的Tkinter模块和Python的第三方图像处理Pillow库制作一个简单的图像编辑器和查看器,它完全可以执行基本的图像操作,包括应用滤镜、调整图像亮度和对比度、旋转图像、翻转图像、剪切图像以及在指定图像上用铅笔绘制图形。

1、图片查看编辑器介绍

我们的目标是使用Python的Tkinter模块构建一个简易的图片查看和编辑应用程序,支持查看指定文件夹内的所有图片文件,支持前后翻页查看图片,并提供了图片编辑功能包括在图片上绘制图形、对图片进行旋转或翻转等基础操作,以及各种特效操作包括灰度、彩色反转、高斯模糊、锐化等,还可以在指定图片上裁剪部分图像。

编辑图像方法:点击“打开图片”按钮后导入后缀名为jpg、png、gif、bmp的图像,导入后可在画布上根据原始图片大小呈现图片,再点击“编辑图片”按钮后就可以对已导入的图像进行绘图。程序通过监听鼠标左键的按下(开始绘图)和抬起(停止绘图)完成整个绘图过程。

剪切图像方法:在右侧的工具栏中,点击“剪切图片”工具按钮。此时,在图片上拖动鼠标产生虚线裁剪框,调整裁剪框的大小和位置,选择想要裁剪的部分图片区域,最后按“保存剪切”按钮保存到指定文件夹内。

图片格式:支持查看和编辑常见的图片格式(JPG、PNG、BMP、GIF)。

保存图像方法:点击“保存”按钮即可保存已绘制的图像,可以保存为指定后缀名的图像文件,包括jpg、png、gif图像。

2、图片查看编辑器界面演示

Python中基于Tkinte设计图片查看编辑器

Python中基于Tkinte设计图片查看编辑器

Python中基于Tkinte设计图片查看编辑器

3、代码实现

(1)安装PIL库

首先,确保你已经安装了imagehash库和PIL库(Pillow)。如果还没有安装,可以通过pip安装:

pip install Pillow
pip install imagehash

(2)图片查看编辑器,完整代码如下所示:

动手练一练:

import os, webbrowser, imagehash
import tkinter as tk
from tkinter import colorchooser, ttk, messagebox, filedialog
from PIL import ImageTk, Image, ImageGrab, ImageEnhance, ImageFilter, ImageOps

# 定义函数,用于创建新图像
def create_image(width, height, color=(32, 99, 252)):
    # 创建新图像
    image = Image.new("RGB", (width, height), color)
    return image

# 创建一个40x40的绿色图像,用于显示启动画面
loader_image = create_image(40, 40)

# 定义ImageEditor类,用于封装程序的功能
class ImageEditor(tk.Tk):
    # 初始化程序数据
    def __init__(self):
        super().__init__()

        # 参数设为1,隐藏窗口边框和任务栏图标,只显示启动画面
        self.wm_overrideredirect(1)

        self.title("图片查看编辑器")

        self.loading_label = None

        self.pencil_color = '#FF0000' # 默认铅笔颜色为红色

        # 创建启动页面框架
        self.splash_frame = tk.Frame(self, background='#7bdfff', highlightbackground="#055aba", highlightthickness=2)
        self.splash_frame.pack(fill="both", expand=True)

        self.image_editor_window = tk.Frame(self)

        self.loading = loader_image.resize((39, 39), Image.Resampling.LANCZOS)
        self.loading = ImageTk.PhotoImage(self.loading)

        self.delay = 50

        self.title_label = tk.Label(self, text='图片查看编辑器', foreground="#032f93",
                                        font=12, background='#7bdfff')
        self.title_label.place(x=180, y=65)

        self.x = 8

        # 始化参数
        self.button_background = 'grey'
        self.original_image_resized = None
        self.image_copy_resized = None
        self.modified_img_resized = None
        self.image_before_draw = None
        self.draw_state = False
        self.cut_state = False
        self.mirrored = False
        self.vertical = False
        self.current_index = None
        self.image_paths = []
        self.lines_drawn = []
        self.current_image_size = None
        self.current_resized_image_size = None
        self.original_image = None
        self.modified_img = None
        self.image_copy = None
        self.rect = None
        self.event_x = self.event_y = None
        self.rectangles = []
        self.point_x = self.point_y = None
        self.image_x_co = self.image_y_co = None
        self.original_hash = None
        self.max_height = 812
        self.max_width = 1220
        self.degree = 90
        self.error = None

        # 在窗口上创建一个Canvas组件,用于绘制图形
        self.canvas = tk.Canvas(self.image_editor_window, bd=0, highlightbackground="#BCBCBC", background="#BCBCBC")
        self.canvas.bind('<B1-Motion>', self.draw_image)
        self.canvas.bind('<ButtonPress-1>', self.mouse_position_get)
        self.canvas.bind('<ButtonRelease-1>', self.button_release)
        self.canvas.pack(fill="both", expand=True)

        self.button_frame_color = "#e6e6e6"

        # 创建左下角图片信息栏,用于显示图片位置和大小
        self.info_frame = tk.Frame(self.image_editor_window, background="#BCBCBC")
        self.info_frame.pack(fill="x")

        self.state_var = tk.StringVar()
        ttk.Label(self.info_frame, 
                  textvariable=self.state_var, 
                  font=('宋体', 12), 
                  background="#BCBCBC",
                  foreground="black").pack(side=tk.LEFT, padx=5, pady=5)
        self.state_var.set("请选择一张图片进行处理")

        # 创建底部框架
        self.bottom_frame = tk.Frame(self.image_editor_window)
        self.bottom_frame.pack(fill="x")

        self.button_frame = tk.Frame(self.bottom_frame)
        self.button_frame.pack()

        # 选择上一张图片
        previous_button = tk.Button(self.button_frame, text="< 上一个", background=self.button_frame_color,
                               command=self.previous_image,
                               padx=5, bd=0, cursor="hand2",
                               font=('宋体', 12), foreground="black", borderwidth=2)
        previous_button.bind("<Enter>", lambda e: mouse_hover(previous_button, color='#aceafc'))
        previous_button.bind("<Leave>", lambda e: mouse_not_hover(previous_button, color=self.button_frame_color))
        previous_button.pack(side="left", padx=2, pady=8)

        # 逆时针旋转按键布置
        rotate_n = tk.Button(self.button_frame, text="逆时针旋转", background=self.button_frame_color,
                             command=lambda: self.image_rotate(0), padx=5, bd=0, cursor="hand2",
                             font=('宋体', 12), foreground="black", borderwidth=2)
        rotate_n.bind("<Enter>", lambda e: mouse_hover(rotate_n, color='#aceafc'))
        rotate_n.bind("<Leave>", lambda e: mouse_not_hover(rotate_n, color=self.button_frame_color))
        rotate_n.pack(side="left", padx=6, pady=8)

        # 顺时针旋转按键布置
        rotate_s = tk.Button(self.button_frame, text="顺时针旋转", background=self.button_frame_color,
                             command=lambda: self.image_rotate(1), padx=5, bd=0, cursor="hand2",
                             font=('宋体', 12), foreground="black", borderwidth=2)
        rotate_s.bind("<Enter>", lambda e: mouse_hover(rotate_s, color='#aceafc'))
        rotate_s.bind("<Leave>", lambda e: mouse_not_hover(rotate_s, color=self.button_frame_color))
        rotate_s.pack(side="left", padx=6, pady=8)

        # 水平翻转按键布置
        level_flip = tk.Button(self.button_frame, text="水平翻转", background=self.button_frame_color,
                            command=self.mirror, padx=5, bd=0, cursor="hand2",
                            font=('宋体', 12), foreground="black", borderwidth=2)
        level_flip.bind("<Enter>", lambda e: mouse_hover(level_flip, color='#aceafc'))
        level_flip.bind("<Leave>", lambda e: mouse_not_hover(level_flip, color=self.button_frame_color))
        level_flip.pack(side="left", padx=6, pady=8)

        # 垂直翻转按键布置
        vertical_flip = tk.Button(self.button_frame, text="垂直翻转", background=self.button_frame_color,
                            command=self.vertical_image, padx=5, bd=0, cursor="hand2",
                            font=('宋体', 12), foreground="black", borderwidth=2)
        vertical_flip.bind("<Enter>", lambda e: mouse_hover(vertical_flip, color='#aceafc'))
        vertical_flip.bind("<Leave>", lambda e: mouse_not_hover(vertical_flip, color=self.button_frame_color))
        vertical_flip.pack(side="left", padx=6, pady=8)

        # 选择下一张图片
        next_button = tk.Button(self.button_frame, text="下一个 >", command=self.next_image,
                           background=self.button_frame_color, padx=5, bd=0, cursor="hand2", 
                           font=('宋体', 12), foreground="black", borderwidth=2)
        next_button.bind("<Enter>", lambda e: mouse_hover(next_button, color='#aceafc'))
        next_button.bind("<Leave>", lambda e: mouse_not_hover(next_button, color=self.button_frame_color))
        next_button.pack(side="left", padx=2, pady=8)

        # 退出按钮
        window_close = tk.Button(self.image_editor_window, compound="left", width=10,
                                text="退出", font=('宋体', 12), foreground="black", bd=0, background="#feacb6", borderwidth=4,
                                command=self.window_close, cursor="hand2")
        window_close.bind("<Enter>", lambda e: mouse_hover(window_close, color='#e6e6e6'))
        window_close.bind("<Leave>", lambda e: mouse_not_hover(window_close, color="#feacb6"))
        window_close.place(x=1418, y=720)

        # 创建右边工具栏框架
        self.side_frame = tk.Frame(self.image_editor_window, background="#BCBCBC")

        adjust_button = tk.Button(self.side_frame, text="调整", cursor="hand2",
                            width=15, padx=4, pady=4, font=('宋体', 13),
                            command=self.open_adjustment_window)
        adjust_button.bind("<Enter>", lambda e: mouse_hover(adjust_button, color='#aceafc'))
        adjust_button.bind("<Leave>", lambda e: mouse_not_hover(adjust_button, color="#e6e6e6"))
        adjust_button.pack(padx=5, pady=5)

        filter_button = tk.Button(self.side_frame, text="过滤", cursor="hand2",
                             width=15, padx=4, pady=4, font=('宋体', 13),
                             command=self.open_filter_window)
        filter_button.bind("<Enter>", lambda e: mouse_hover(filter_button, color='#aceafc'))
        filter_button.bind("<Leave>", lambda e: mouse_not_hover(filter_button, color="#e6e6e6"))
        filter_button.pack(padx=5, pady=5)

        self.reset_button = tk.Button(self.image_editor_window, text="还原",
                                 width=15, padx=4, pady=4, font=('宋体', 13),
                                 command=self.reset, cursor="hand2")
        self.reset_button.bind("<Enter>", lambda e: mouse_hover(self.reset_button, color='#aceafc'))
        self.reset_button.bind("<Leave>", lambda e: mouse_not_hover(self.reset_button, color="#e6e6e6"))

        self.cut_var = tk.BooleanVar()  # 创建一个BooleanVar变量来存储复选框的状态
        self.cut_button = tk.Checkbutton(self.image_editor_window, text="剪切图片", variable=self.cut_var, padx=4, 
                                     pady=4,command=self.start_cut, cursor="hand2", font=('宋体', 13), width=8)
        self.cut_button.bind("<Enter>", lambda e: mouse_hover(self.cut_button, color='#aceafc'))
        self.cut_button.bind("<Leave>", lambda e: mouse_not_hover(self.cut_button, color="#e6e6e6"))

        self.warn_label = tk.Label(self.image_editor_window, text="请按住鼠标左键拖动鼠标,选择想要剪切的部分", background="#BCBCBC", font=('宋体', 13))

        self.check_var = tk.BooleanVar()  # 创建一个BooleanVar变量来存储复选框的状态
        self.draw_button = tk.Checkbutton(self.image_editor_window, text="编辑图片", variable=self.check_var, padx=4, 
                                     pady=4,command=self.start_draw, cursor="hand2", font=('宋体', 13), width=8)
        self.draw_button.bind("<Enter>", lambda e: mouse_hover(self.draw_button, color='#aceafc'))
        self.draw_button.bind("<Leave>", lambda e: mouse_not_hover(self.draw_button, color="#e6e6e6"))

        # 绘制图片区域
        self.editor_frame = ttk.LabelFrame(self.image_editor_window)

        self.pencil_frame = ttk.LabelFrame(self.editor_frame)
        self.pencil_frame.pack(side=tk.TOP)

        self.pencil_size_label = tk.Label(self.pencil_frame, text="铅笔尺寸:", width=10)
        self.pencil_size_label.pack(side=tk.LEFT, padx=5, pady=5)
        self.choose_pencil_size = tk.Scale(self.pencil_frame, from_=1, to=20, orient=tk.HORIZONTAL)
        self.choose_pencil_size.pack(side=tk.LEFT, padx=5)

        # 选择铅笔颜色
        self.fore_color_frame = ttk.LabelFrame(self.editor_frame)
        self.fore_color_frame.pack(side=tk.TOP)

        fore_color_chooser = tk.Button(self.fore_color_frame,
            text="铅笔颜色",
            command = self.fore_color_change,
            width=10,
            )
        fore_color_chooser.pack(side=tk.LEFT, padx=5, pady=5)

        self.input_fore_color = tk.StringVar()
        self.input_fore_color.set("#FF0000")
        change_fore_color = self.register(self.change_fore_color)
        self.enter_fore_color = tk.Entry(self.fore_color_frame,
                textvariable=self.input_fore_color,
                width=8,
                validate='key', # 当输入框被编辑时启用验证
                validatecommand=(change_fore_color, '%P'),
                )
        self.enter_fore_color.pack(side=tk.LEFT, padx=5)

        self.show_fore_color = tk.Frame(self.fore_color_frame)
        self.show_fore_color.pack(expand=tk.YES, fill=tk.BOTH, side=tk.LEFT, padx=5)

        self.fore_color_set= tk.Button(self.show_fore_color, text="", bg="#FF0000", command=self.fore_color_change, width=5)
        self.fore_color_set.pack(fill=tk.BOTH, expand=True)

        self.draw_save = tk.Button(self.editor_frame, compound='left', text="保存编辑", width=10,
                                   foreground="black", font=('宋体', 12), background="#a8cdfe",
                                   command=self.image_after_draw, cursor="hand2", borderwidth=4)
        self.draw_save.pack(side=tk.LEFT, padx=10, pady=10)
        self.draw_save.bind("<Enter>", lambda e: mouse_hover(self.draw_save, color='#e6e6e6'))
        self.draw_save.bind("<Leave>", lambda e: mouse_not_hover(self.draw_save, color='#a8cdfe'))

        self.draw_cancel = tk.Button(self.editor_frame, compound='left', text="取消编辑", width=10,
                                   foreground="black", font=('宋体', 12), background="#feacb6",
                                   command=self.image_draw_cancel, cursor="hand2", borderwidth=4)
        self.draw_cancel.pack(side=tk.LEFT, padx=10, pady=10)
        self.draw_cancel.bind("<Enter>", lambda e: mouse_hover(self.draw_cancel, color='#e6e6e6'))
        self.draw_cancel.bind("<Leave>", lambda e: mouse_not_hover(self.draw_cancel, color='#feacb6'))

        # 剪切图片时弹出按钮
        self.crop_save = tk.Button(self.image_editor_window, compound='left', text="保存剪切", width=10,
                                   foreground="black", font=('宋体', 12), background="#a8cdfe",
                                   command=self.cut_image, cursor="hand2", borderwidth=4)
        self.crop_save.bind("<Enter>", lambda e: mouse_hover(self.crop_save, color='#e6e6e6'))
        self.crop_save.bind("<Leave>", lambda e: mouse_not_hover(self.crop_save, color='#a8cdfe'))

        self.crop_cancel = tk.Button(self.image_editor_window, compound='left', text="取消保存", width=10,
                                   foreground="black", font=('宋体', 12), background="#feacb6",
                                   command=self.cut_image_cancel, cursor="hand2", borderwidth=4)
        self.crop_cancel.bind("<Enter>", lambda e: mouse_hover(self.crop_cancel, color='#e6e6e6'))
        self.crop_cancel.bind("<Leave>", lambda e: mouse_not_hover(self.crop_cancel, color='#feacb6'))

        # 创建右下角保存按钮
        self.save_button = tk.Button(self.image_editor_window, text="保存", compound="left", width=10,
                                foreground="black", font=('宋体', 12), background="#a8cdfe",
                                command=self.save, cursor="hand2", borderwidth=4)
        self.save_button.bind("<Enter>", lambda e: mouse_hover(self.save_button, color='#e6e6e6'))
        self.save_button.bind("<Leave>", lambda e: mouse_not_hover(self.save_button, color='#a8cdfe'))

        # 左下角显示版本信息
        version_label = tk.Label(self.bottom_frame,text="版本V2.10", background=self.button_frame_color,
                                   foreground="black", font=('宋体', 12))
        version_label.place(x=20, y=10)

        # 右下角统计图片数量
        self.status_bar = tk.Label(self.bottom_frame, background=self.button_frame_color,
                                   foreground="black", font=('宋体', 12))
        self.status_bar.place(x=1200, y=10)

        # 打开图片按钮
        self.open_image_button = tk.Button(self.image_editor_window, command=self.open_image, cursor="hand2",
                                           compound='top', text="请点击打开图片",
                                           font=('宋体', 20), foreground="black", bd=0, background="#e6e6e6", borderwidth=4)
        self.open_image_button.bind("<Enter>", lambda e: mouse_hover(self.open_image_button, color='#cfcfcf'))
        self.open_image_button.bind("<Leave>", lambda e: mouse_not_hover(self.open_image_button, color='#e6e6e6'))
        self.open_image_button.place(x=685, y=350)

        self.error_b = tk.Button(self.image_editor_window, text="不支持这种文件格式。", font=('宋体', 11), padx=8, pady=8)

        # 将窗口关闭事件与window_close函数关联
        self.protocol("WM_DELETE_WINDOW", self.window_close)

        self.show_splash_window()
        self.mainloop()

    # 定义函数,用于改变铅笔颜色
    def change_fore_color(self, color):
        try:
            self.fore_color_set['bg'] = color
        except:
            pass
        return True

    # 选择指定的颜色
    def fore_color_change(self):
        try:
            # 使用askcolor显示颜色选择器,并设置初始颜色
            color = colorchooser.askcolor(title="请选择填充颜色", initialcolor=self.enter_fore_color.get())
            if color[1] != None:
                self.input_fore_color.set(color[1])
                self.pencil_color = color[1]
            self.canvas.configure(cursor='arrow')
        except:
            # 如果颜色值输入错误,则弹出提示框
            messagebox.showerror("错误", f"颜色输入值错误“{self.enter_fore_color.get()}”")
            color = colorchooser.askcolor(title="请选择填充颜色", initialcolor="#000000")
            if color[1] != None:
                self.input_fore_color.set(color[1])
                self.pencil_color = color[1]
            self.canvas.configure(cursor='arrow')

    # 创建启动动画
    def show_splash_window(self):
        # 设置窗口居中
        window_width = 500
        window_height = 100
        screen_width = self.winfo_screenwidth()
        screen_height = self.winfo_screenheight()
        x = (screen_width - window_width) / 2
        y = (screen_height - window_height) / 2
        self.geometry('%dx%d+%d+%d' % (window_width, window_height, x, y))

        self.loading_label = tk.Label(self.splash_frame, image=self.loading, bd=0)
        self.loading_label.place(x=self.x, y=15)
        self.x += 42
        if self.x != 470:
            self.after(self.delay, self.show_splash_window)
        else:
            self.title_label.destroy()
            self.splash_frame.destroy()
            self.loading_label.destroy()
            self.wm_overrideredirect(0)

            self.image_editor_window.pack(fill="both", expand=True)

            self.state('zoomed')  # 最大化窗口

    # 打开图片
    def open_image(self):
        # 创建顶部菜单栏
        self.menu = tk.Menu(self, bg='#33b3fd')
        self.config(menu=self.menu)
        filemenu = tk.Menu(self.menu, tearoff=0)
        self.menu.add_cascade(label='文件', menu=filemenu)
        filemenu.add_command(label='打开', command=self.open_image)
        filemenu.add_command(label='另存为', command=self.save)

        help_menu = tk.Menu(self.menu, tearoff=0)
        help_menu.add_command(label="关于程序", command=self.about_image_editor)
        help_menu.add_command(label="程序讲解", command=self.image_editor_help)
        help_menu.add_separator()  
        help_menu.add_command(label="退出", command=self.window_close)
        self.menu.add_cascade(label="帮助", menu=help_menu)

        # 选择打开图片的类型
        file_types = [
            ("所有图像文件", ".png .gif .jpg .jpeg .bmp"),
            ('jpg文件', '*.jpg'), 
            ('png文件', '*.png'), 
            ('gif文件', '*.gif'), 
            ('bmp文件', '*.bmp'), 
            ('jpeg文件', '*.jpeg')
        ]
        file_object = filedialog.askopenfile(filetype=file_types)
        if file_object:
            self.open_image_button.configure(text="打开图片", compound="left", width=10,
                                             font=('宋体', 12), foreground="black", 
                                             bd=0, background="#b5fec1", borderwidth=4)
            self.open_image_button.bind("<Enter>", lambda e: mouse_hover(self.open_image_button, color='#e6e6e6'))
            self.open_image_button.bind("<Leave>", lambda e: mouse_not_hover(self.open_image_button, color='#b5fec1'))
            self.open_image_button.place(x=1418, y=680)
            self.side_frame.place(x=1380, y=90)
            self.save_button.place(x=1418, y=640)
            self.draw_button.place(x=1460, y=232)
            self.cut_button.place(x=1340, y=232)
            self.reset_button.place(x=1385, y=190)
            self.save_button.configure(state="normal")
            filename = file_object.name
            directory = filename.replace(os.path.basename(filename), "")
            files_list = os.listdir(directory)
            self.image_paths = []

            for file in files_list:
                if '.jpg' in file or \
                    '.png' in file or \
                    '.gif' in file or \
                    '.bmp' in file or \
                    '.jpeg' in file or \
                    '.GIF' in file or \
                    '.BMP' in file or \
                    '.JPG' in file or \
                    '.JPEG' in file or \
                    '.PNG' in file:
                    self.image_paths.append(os.path.join(directory, file))

            for i, image in enumerate(self.image_paths):
                if image == filename:
                    self.current_index = i
            self.show_image(image=self.image_paths[self.current_index])

    def resize_image(self, image):
        image.thumbnail((self.max_width, self.max_height))

        self.original_hash = imagehash.average_hash(image)

        self.current_resized_image_size = (image.size[0], image.size[1])
        return image

    # 定义打开图片方法
    def create_image_object(self, image):
        # 打开图像
        self.original_image = Image.open(image)
        # 检查图像模式,如果是透明背景,则转换为白色背景
        if self.original_image.mode == 'RGBA':
            # 转换图像模式为RGB,并添加白色背景
            background = Image.new('RGB', self.original_image.size, (255, 255, 255))
            background.paste(self.original_image, mask=self.original_image.split()[-1])  # 使用透明度通道作为蒙版
            self.original_image = background
        self.current_image_size = self.original_image.size
        self.modified_img = self.original_image
        self.image_copy = self.original_image

        # 打开图像
        self.original_image_resized = Image.open(image)
        # 检查图像模式,如果是透明背景,则转换为白色背景
        if self.original_image_resized.mode == 'RGBA':
            # 转换图像模式为RGB,并添加白色背景
            background = Image.new('RGB', self.original_image_resized.size, (255, 255, 255))
            background.paste(self.original_image_resized, mask=self.original_image_resized.split()[-1])  # 使用透明度通道作为蒙版
            self.original_image_resized = background
        self.modified_img_resized = self.original_image_resized
        self.image_copy_resized = self.original_image_resized

        im = self.resize_image(self.original_image_resized)
        im = ImageTk.PhotoImage(im)
        return im

    # 显示图片
    def show_image(self, image=None, modified=None):
        self.status_bar.configure(text=f"图片  :  {self.current_index + 1}  of  {len(self.image_paths)}")
        if self.error:
            self.error_b.place_forget()
            self.error = None

        im = None
        if image:
            try:
                im = self.create_image_object(image)
            except:
                self.image_copy = self.modified_img = self.original_image_resized = self.original_image = None
                self.canvas.image = ''
                self.error_b.place(x=600, y=380)
                self.error = True
                return

        elif modified:
            im = modified

        image_width, image_height = self.current_resized_image_size[0], self.current_resized_image_size[1]
        self.image_x_co, self.image_y_co = (self.winfo_screenwidth() / 2) - image_width / 2, (
                self.max_height / 2) - image_height / 2
        self.canvas.image = im

        if image_height < self.max_height:
            self.canvas.create_image(self.image_x_co, self.image_y_co, image=im, anchor="nw")
        else:
            self.canvas.create_image(self.image_x_co, 0, image=im, anchor="nw")

        self.state_var.set(f'图片信息 | {self.image_paths[self.current_index]}【尺寸:{image_width}x{image_height}】')

    # 选择上一张图片函数
    def previous_image(self):
        if self.image_paths:
            if self.current_index != 0:
                self.current_index -= 1
            self.show_image(image=self.image_paths[self.current_index])

    # 选择下一张图片函数
    def next_image(self):
        if self.image_paths:
            if self.current_index != len(self.image_paths) - 1:
                self.current_index += 1
            self.show_image(image=self.image_paths[self.current_index])

    # 图像旋转函数
    def image_rotate(self, direction):
        if self.original_image and not self.error:
            angle = 90
            # direction=1为顺时针,否则逆时针
            if direction:
                angle = -90
            self.modified_img_resized = self.image_copy_resized.rotate(angle, expand=True)
            self.image_copy_resized = self.modified_img_resized

            self.modified_img = self.image_copy.rotate(angle, expand=True)

            self.image_copy = self.modified_img
            self.image_copy_resized = self.modified_img_resized

            self.current_resized_image_size = self.modified_img_resized.size

            im = ImageTk.PhotoImage(self.modified_img_resized)
            self.show_image(modified=im)

    # 水平翻转函数
    def mirror(self):
        if self.original_image and not self.error:
            if not self.mirrored:
                self.modified_img = self.image_copy.transpose(Image.Transpose.FLIP_LEFT_RIGHT)
                self.modified_img_resized = self.image_copy_resized.transpose(Image.Transpose.FLIP_LEFT_RIGHT)
                self.mirrored = True
            else:
                self.modified_img = self.modified_img.transpose(Image.Transpose.FLIP_LEFT_RIGHT)
                self.modified_img_resized = self.modified_img_resized.transpose(Image.Transpose.FLIP_LEFT_RIGHT)
                self.mirrored = False

            self.image_copy = self.modified_img
            self.image_copy_resized = self.modified_img_resized

            im = ImageTk.PhotoImage(self.modified_img_resized)
            self.show_image(modified=im)

    # 垂直翻转
    def vertical_image(self):
        if self.original_image and not self.error:
            if not self.vertical:
                self.modified_img = self.image_copy.transpose(Image.Transpose.FLIP_TOP_BOTTOM)
                self.modified_img_resized = self.image_copy_resized.transpose(Image.Transpose.FLIP_TOP_BOTTOM)
                self.vertical = True
            else:
                self.modified_img = self.modified_img.transpose(Image.Transpose.FLIP_TOP_BOTTOM)
                self.modified_img_resized = self.modified_img_resized.transpose(Image.Transpose.FLIP_TOP_BOTTOM)
                self.vertical = False

            self.image_copy = self.modified_img
            self.image_copy_resized = self.modified_img_resized

            im = ImageTk.PhotoImage(self.modified_img_resized)
            self.show_image(modified=im)

    # 获取鼠标位置
    def mouse_position_get(self, event):
        if not self.draw_state and self.cut_state:
            if self.rect:
                self.rectangles = []
                self.canvas.delete(self.rect)

            self.rect = self.canvas.create_rectangle(0, 0, 0, 0, outline="black", width=2)

        self.point_x, self.point_y = event.x, event.y

    # 释放鼠标按钮
    def button_release(self, event):
        if self.cut_state:
            self.crop_save.place(x=1290, y=280)
            self.crop_cancel.place(x=1400, y=280)
            self.warn_label.place_forget()

    # 开始绘制图片
    def start_draw(self):
        if self.original_image and not self.error:
            if self.check_var.get() and not self.draw_state:
                # 创建一个新的白色背景图片,尺寸与原图相同
                self.image_before_draw = Image.new('RGB', size=self.current_image_size)
                self.image_before_draw.paste(self.image_copy, (0, 0))

                self.canvas.configure(cursor='pencil')
                self.editor_frame.place(x=1330, y=280)
                self.button_frame.pack_forget()
                self.side_frame.place_forget()
                self.cut_button.place_forget()
                self.save_button.configure(state="disable")
                self.draw_state = True
            else:
                if self.lines_drawn:
                    for line in self.lines_drawn:
                        self.canvas.delete(line)
                    self.lines_drawn = []
                    self.image_before_draw = None
                    self.image_before_draw = self.image_copy

                self.canvas.configure(cursor='arrow')

                self.draw_state = False
                self.button_frame.pack()

                self.side_frame.place(x=1380, y=90)
                self.save_button.place(x=1418, y=640)
                self.cut_button.place(x=1340, y=232)
                self.open_image_button.place(x=1418, y=680)

                self.editor_frame.place_forget()

    # 开始剪切图片
    def start_cut(self):
        if self.original_image and not self.error:

            # 确保绘图状态和裁剪状态两者不能同时处于活动状态
            if self.draw_state:
                self.start_draw()

            if self.cut_var.get() and not self.cut_state:
                self.canvas.configure(cursor='plus')
                self.cut_state = True
                self.reset_button.place_forget()
                self.button_frame.pack_forget()
                self.side_frame.place_forget()
                self.draw_button.place_forget()
                self.warn_label.place(x=1200, y=280)
            else:
                self.canvas.configure(cursor='arrow')
                self.crop_save.place_forget()
                self.crop_cancel.place_forget()
                self.warn_label.place_forget()
                if self.rect:
                    self.canvas.delete(self.rect)

                self.cut_state = False
                self.side_frame.place(x=1380, y=90)
                self.save_button.place(x=1418, y=640)
                self.draw_button.place(x=1460, y=232)
                self.cut_button.place(x=1340, y=232)
                self.reset_button.place(x=1385, y=190)
                self.button_frame.pack()

    # 定义绘图和剪切方法
    def draw_image(self, event):
        if self.cut_state:
            if not self.rectangles:
                self.rectangles.append(self.rect)

            image_width, image_height = self.current_resized_image_size[0], self.current_resized_image_size[1]
            x_co_1, x_co_2 = int((self.winfo_screenwidth() / 2) - image_width / 2), int(
                (self.winfo_screenwidth() / 2) + image_width / 2)
            y_co_1, y_co_2 = int(self.max_height / 2 - image_height / 2), int((self.max_height / 2) + image_height / 2)

            if x_co_2 > event.x > x_co_1 and y_co_1 + 2 < event.y < y_co_2:
                self.canvas.coords(self.rect, self.point_x, self.point_y, event.x, event.y)
                self.canvas.itemconfig(self.rect, dash=(10, 10))  # 设置虚线样式
                self.event_x, self.event_y = event.x, event.y

        elif self.draw_state:
            image_width, image_height = self.current_resized_image_size[0], self.current_resized_image_size[1]
            x_co_1, x_co_2 = int((self.winfo_screenwidth() / 2) - image_width / 2), int(
                (self.winfo_screenwidth() / 2) + image_width / 2)
            y_co_1, y_co_2 = int(self.max_height / 2 - image_height / 2), int((self.max_height / 2) + image_height / 2)

            if x_co_2 > self.point_x > x_co_1 and y_co_1 < self.point_y < y_co_2:
                if x_co_2 > event.x > x_co_1 and y_co_1 < event.y < y_co_2:
                    self.pencil_size = self.choose_pencil_size.get()
                    lines = self.canvas.create_line(self.point_x, self.point_y, event.x, event.y,
                                                          fill=self.pencil_color, width=self.pencil_size,
                                                          capstyle=tk.ROUND, smooth=tk.TRUE, splinesteps=36)
                    x_co_1, y_co_1, x_co_2, y_co2 = ((self.point_x - self.image_x_co) * self.current_image_size[0])/self.current_resized_image_size[0], ((self.point_y - self.image_y_co)*self.current_image_size[1])/self.current_resized_image_size[1], ((event.x - self.image_x_co)*self.current_image_size[0])/self.current_resized_image_size[0], ((event.y - self.image_y_co)*self.current_image_size[1])/self.current_resized_image_size[1]
                    self.lines_drawn.append(lines)
                    self.point_x, self.point_y = event.x, event.y

    # 保存已剪切的图像
    def cut_image(self):
        if self.rectangles:
            x_co_1, y_co_1, x_co_2, y_co2 = ((self.point_x - self.image_x_co) * self.current_image_size[0])/self.current_resized_image_size[0], ((self.point_y - self.image_y_co) * self.current_image_size[1]) / self.current_resized_image_size[1], ((self.event_x - self.image_x_co) * self.current_image_size[0]) / self.current_resized_image_size[0], ((self.event_y - self.image_y_co) * self.current_image_size[1]) / self.current_resized_image_size[1]

            self.image_copy = self.image_copy.crop((int(x_co_1), int(y_co_1), int(x_co_2), int(y_co2)))
            x_co_1, y_co_1, x_co_2, y_co2 = self.point_x - self.image_x_co, self.point_y - self.image_y_co, self.event_x - self.image_x_co, self.event_y - self.image_y_co

            self.save()
            self.cut_var.set(False)  # 确保初始状态
        else:
            messagebox.showinfo(title="无法剪切!", message="请按住鼠标左键拖动鼠标,选择想要剪切的部分")

    # 关闭绘图功能
    def image_draw_cancel(self):
        self.check_var.set(False)  # 确保初始状态
        self.draw_state = False

        if self.lines_drawn:
            for line in self.lines_drawn:
                self.canvas.delete(line)
            self.lines_drawn = []
            self.image_before_draw = None
            self.image_before_draw = self.image_copy

        self.canvas.configure(cursor='arrow')
        self.crop_save.place_forget()
        self.crop_cancel.place_forget()
        self.side_frame.place(x=1380, y=90)
        self.save_button.place(x=1418, y=640)
        self.draw_button.place(x=1460, y=232)
        self.cut_button.place(x=1340, y=232)
        self.reset_button.place(x=1385, y=190)
        self.button_frame.pack()
        self.reset()
        self.editor_frame.place_forget()

    # 保存已绘制的图像
    def image_after_draw(self):
        if self.lines_drawn:
            self.save()
        else:
            messagebox.showinfo(title='无法保存!', message='您尚未在图像上绘制任何内容。')

    # 关闭剪切功能
    def cut_image_cancel(self):
        self.cut_var.set(False)  # 确保初始状态
        self.cut_state = False
        self.canvas.configure(cursor='arrow')
        self.crop_save.place_forget()
        self.crop_cancel.place_forget()
        self.side_frame.place(x=1380, y=90)
        self.save_button.place(x=1418, y=640)
        self.draw_button.place(x=1460, y=232)
        self.cut_button.place(x=1340, y=232)
        self.reset_button.place(x=1385, y=190)
        self.button_frame.pack()
        self.reset()
        self.warn_label.place_forget()
        if self.rect:
            self.canvas.delete(self.rect)

    # 定义保存图片方法
    def save(self):
        image_path_object = filedialog.asksaveasfile(
            defaultextension='*.jpg',
                filetypes=[
                ("JPG文件", "*.jpg"),
                ("PNG文件", "*.png"),
                ("GIF文件", "*.gif"),
                ],
            )

        if image_path_object:
            image_path = image_path_object.name
            try:
                self.image_copy.save(image_path, quality=95)
                # 判断是绘图动态
                if self.draw_state:
                    for line in self.lines_drawn:
                        self.canvas.delete(line)
                    self.lines_drawn = []

                    # 开始绘图
                    self.start_draw()
                    # 左点坐标
                    x = self.image_x_co
                    # 上点坐标
                    y = self.image_y_co + 43
                    # 右点坐标
                    x1 = self.image_x_co + self.current_resized_image_size[0]
                    # 下点坐标
                    y1 = self.image_y_co + self.current_resized_image_size[1] + 43
                    # crop()方法定义剪切区域(坐标为左、上、右、下四个点)
                    # save()方法保存结果图片,压缩质量为95%最高质量
                    ImageGrab.grab().crop((x, y, x1, y1)).save(image_path, quality=95)

                # 判断是剪切动态
                if self.cut_state:
                    self.canvas.delete(self.rect)

                    # 开始剪切
                    self.start_cut()
                    self.image_copy.save(image_path, quality=95)

                self.image_paths.insert(self.current_index + 1, image_path)
                self.current_index += 1
                self.save_button.configure(state="normal")
                self.show_image(image=image_path)
                messagebox.showinfo('保存成功', f'图像已成功保存为“{image_path}”')
            except Exception as e:
                messagebox.showinfo('失败', f'图像保存失败:“{e}”')

        self.check_var.set(False)  # 确保初始状态

    # 定义还原方法
    def reset(self):
        if self.original_image and not self.error:
            if self.draw_state:
                for line in self.lines_drawn:
                    self.canvas.delete(line)
                    self.lines_drawn = []
                self.image_before_draw = self.image_copy
            else:
                current_original_image = self.image_paths[self.current_index]
                self.show_image(image=current_original_image)

    # 打开调整窗口
    def open_adjustment_window(self):
        if self.original_image and not self.error:
            Adjustments(self, self.image_copy, self.modified_img, self.image_copy_resized, self.modified_img_resized)

    # 打开过滤窗口
    def open_filter_window(self):
        if self.original_image and not self.error:
            Filters(self, self.image_copy, self.modified_img, self.image_copy_resized, self.modified_img_resized)

    # 点击关闭窗口触发函数
    def window_close(self):
        # 弹出确认对话框
        if messagebox.askokcancel("退出", "你确定要退出吗?"):
            # 点击确定后关闭窗口
            self.destroy()

    # 关于图片查看编辑程序
    def about_image_editor(self):
        about = tk.Tk()
        about.title('关于图片查看编辑程序')

        # 设置窗口居中
        window_width = 610
        window_height = 480
        screen_width = about.winfo_screenwidth()
        screen_height = about.winfo_screenheight()
        x = (screen_width - window_width) / 2
        y = (screen_height - window_height) / 2
        about.geometry('%dx%d+%d+%d' % (window_width, window_height, x, y))
        about.resizable(width=False, height=False)

        about_frame = tk.Frame(about, width=610, height=480)
        about_frame.pack()
        tk.Label(about_frame, text='图片查看编辑器', font=("宋体", 16)).place(x=220, y=20)
        tk.Label(about_frame, text='使用编程语言:Python', font=("宋体", 14)).place(x=50, y=90)
        tk.Label(about_frame, text='导入图像:可导入后缀名为jpg、png、gif、bmp的图像', font=("宋体", 14)).place(x=50, y=150)
        tk.Label(about_frame, text='保存图像:可以将图像保存为指定后缀名的图像文件', font=("宋体", 14)).place(x=50, y=210)
        tk.Label(about_frame, text='编辑图像:打开指定图像,再点击“编辑图片”按钮', font=("宋体", 14)).place(x=50, y=270)
        tk.Label(about_frame, text='剪切图像:按住鼠标左键拖动鼠标,选择想要剪切的部分', font=("宋体", 14)).place(x=50, y=330)
        tk.Label(about_frame, text='创作者:www.pyhint.com', font=("宋体", 14)).place(x=50, y=390)
        about.mainloop()

    # 绘图程序讲解页面
    def image_editor_help(self):
        webbrowser.open("https://www.pyhint.com/article/163.html")

def mouse_not_hover(button, color=None):
    if not color:
        color = 'black'
    button.configure(bg=color)

def mouse_hover(button, color=None):
    if not color:
        color = '#473f3f'
    button.configure(bg=color)

# 图片调整方法
class Adjustments(tk.Toplevel):
    def __init__(self, parent, image_copy, modified_img, image_copy_resized, modified_img_resized):
        super().__init__(parent)

        self.parent = parent
        self.wm_overrideredirect(True)
        self.grab_set()
        self.winfo_parent()
        self.geometry("245x260+1260+180")

        self.image_copy = image_copy
        self.modified_img = modified_img

        self.image_copy_resized = image_copy_resized
        self.modified_img_resized = modified_img_resized

        self.modifications = {'contrast': 1.0, 'sharpness': 1.0, 'brightness': 1.0}

        f1 = tk.Frame(self, borderwidth=1, relief='solid')
        f1.pack(fill="both", expand=True)

        tk.Label(f1, text="调整", font=('宋体', 14), pady=5).pack(fill="x")

        contrast_l = tk.Label(f1, text="对比", relief="solid", font=('宋体', 12), width=10)
        contrast_l.place(x=15, y=60)

        self.contrast_b = tk.Scale(f1, from_=0, to=20, orient=tk.HORIZONTAL,
                                   command=lambda e: self.adjust(e, 'contrast'),
                                    )
        self.contrast_b.place(x=120, y=40)

        sharpness_l = tk.Label(f1, text="锐利", relief="solid", font=('宋体', 12), width=10)
        sharpness_l.place(x=15, y=100)

        self.sharpness_b = tk.Scale(f1, from_=0, to=30, orient=tk.HORIZONTAL,
                                    command=lambda e: self.adjust(e, 'sharpness'),
                                    )
        self.sharpness_b.place(x=120, y=80)
        #
        brightness_l = tk.Label(f1, text="亮度", relief="solid", font=('宋体', 12), width=10)
        brightness_l.place(x=15, y=140)

        self.brightness_b = tk.Scale(f1, from_=0, to=20, orient=tk.HORIZONTAL,
                                     command=lambda e: self.adjust(e, 'brightness'),
                                     )
        self.brightness_b.place(x=120, y=120)

        cancel_button = tk.Button(f1, text="取消", command=self.cancel, 
                             foreground="black", font=('宋体', 12), width=10,
                             background="#a8cdfe", cursor="hand2", borderwidth=4)
        cancel_button.bind("<Enter>", lambda e: mouse_hover(cancel_button, color='#e6e6e6'))
        cancel_button.bind("<Leave>", lambda e: mouse_not_hover(cancel_button, color='#a8cdfe'))
        cancel_button.place(x=20, y=200)

        apply_b = tk.Button(f1, text="确认", command=self.apply,
                            foreground="black", font=('宋体', 12), width=10,
                             background="#a8cdfe", cursor="hand2", borderwidth=4)
        apply_b.bind("<Enter>", lambda e: mouse_hover(apply_b, color='#e6e6e6'))
        apply_b.bind("<Leave>", lambda e: mouse_not_hover(apply_b, color='#a8cdfe'))
        apply_b.place(x=130, y=200)

    def adjust(self, e, changes):
        im2 = self.image_copy
        im2_resized = self.image_copy_resized

        if 'original_image':
            if self.modifications:
                for modification in self.modifications.copy():

                    if changes == 'sharpness' and modification == 'sharpness':
                        del self.modifications[modification]

                    elif changes == 'contrast' and modification == 'contrast':
                        del self.modifications[modification]

                    elif changes == 'brightness' and modification == 'brightness':
                        del self.modifications[modification]

                    else:
                        property_ = modification
                        value = self.modifications[property_]

                        if property_ == 'sharpness':

                            enhancer = ImageEnhance.Sharpness(im2)
                            self.modified_img = enhancer.enhance(value)

                            enhancer = ImageEnhance.Sharpness(im2_resized)
                            self.modified_img_resized = enhancer.enhance(value)

                            im = ImageTk.PhotoImage(self.modified_img_resized)
                            self.parent.show_image(modified=im)

                            im2 = self.modified_img
                            im2_resized = self.modified_img_resized

                        elif property_ == 'contrast':

                            enhancer = ImageEnhance.Contrast(im2)
                            self.modified_img = enhancer.enhance(value)

                            enhancer = ImageEnhance.Contrast(im2_resized)
                            self.modified_img_resized = enhancer.enhance(value)

                            im = ImageTk.PhotoImage(self.modified_img_resized)
                            self.parent.show_image(modified=im)

                            im2 = self.modified_img
                            im2_resized = self.modified_img_resized

                        elif property_ == 'brightness':

                            enhancer = ImageEnhance.Brightness(im2)
                            self.modified_img = enhancer.enhance(value)

                            enhancer = ImageEnhance.Brightness(im2_resized)
                            self.modified_img_resized = enhancer.enhance(value)

                            im = ImageTk.PhotoImage(self.modified_img_resized)
                            self.parent.show_image(modified=im)

                            im2 = self.modified_img
                            im2_resized = self.modified_img_resized

                if changes == 'sharpness':
                    self.modifications['sharpness'] = int(e) / 10

                    enhancer = ImageEnhance.Sharpness(self.modified_img)
                    self.modified_img = enhancer.enhance(int(e) / 10)

                    enhancer = ImageEnhance.Sharpness(self.modified_img_resized)
                    self.modified_img_resized = enhancer.enhance(int(e) / 10)

                    im = ImageTk.PhotoImage(self.modified_img_resized)
                    self.parent.show_image(modified=im)

                elif changes == 'contrast':
                    self.modifications['contrast'] = int(e) / 10

                    enhancer = ImageEnhance.Contrast(self.modified_img)
                    self.modified_img = enhancer.enhance(int(e) / 10)

                    enhancer = ImageEnhance.Contrast(self.modified_img_resized)
                    self.modified_img_resized = enhancer.enhance(int(e) / 10)

                    im = ImageTk.PhotoImage(self.modified_img_resized)
                    self.parent.show_image(modified=im)

                elif changes == 'brightness':
                    self.modifications['brightness'] = int(e) / 10

                    enhancer = ImageEnhance.Brightness(self.modified_img)
                    self.modified_img = enhancer.enhance(int(e) / 10)

                    enhancer = ImageEnhance.Brightness(self.modified_img_resized)
                    self.modified_img_resized = enhancer.enhance(int(e) / 10)

                    im = ImageTk.PhotoImage(self.modified_img_resized)
                    self.parent.show_image(modified=im)

    def cancel(self):
        self.grab_release()

        im = ImageTk.PhotoImage(self.image_copy_resized)
        self.parent.show_image(modified=im)
        self.destroy()

    def apply(self):
        self.modifications = {'contrast': 1.0, 'sharpness': 1.0, 'brightness': 1.0}
        self.grab_release()

        for i in (self.brightness_b, self.contrast_b, self.sharpness_b):
            if i.get() != 10:
                self.parent.save_button.configure(state="normal")
                break

        self.parent.image_copy = self.modified_img
        self.parent.image_copy_resized = self.modified_img_resized

        im = ImageTk.PhotoImage(self.parent.image_copy_resized)
        self.parent.show_image(modified=im)
        self.destroy()

# 图片过滤方法
class Filters(tk.Toplevel):
    def __init__(self, parent, image_copy, modified_img, image_copy_resized, modified_img_resized):
        super().__init__(parent)

        self.wm_overrideredirect(True)
        self.grab_set()
        self.winfo_parent()
        self.geometry("230x280+1300+230")
        self.filter_ = None

        self.parent = parent

        self.image_copy = image_copy
        self.modified_img = modified_img

        self.image_copy_resized = image_copy_resized
        self.modified_img_resized = modified_img_resized

        f1 = tk.Frame(self, borderwidth=1, relief='solid')
        f1.pack(fill="both", expand=True)

        tk.Label(f1, text="过滤", font=('宋体', 14), pady=5).pack(fill="x")

        filters_frame = tk.Frame(f1)
        filters_frame.pack(fill="both", expand=True)

        emboss_button = tk.Button(filters_frame, text="浮雕", font=('宋体', 12),
                             command=lambda: self.filters(emboss_button),
                            padx=10, cursor="hand2", width=15, background="#e6e6e6")
        emboss_button.bind("<Enter>", lambda e: mouse_hover(button=emboss_button, color='#aceafc'))
        emboss_button.bind("<Leave>", lambda e: mouse_not_hover(button=emboss_button, color='#e6e6e6'))
        emboss_button.place(x=40, y=20)

        grey_button = tk.Button(filters_frame, text="灰度", font=('宋体', 12),
                           command=lambda: self.filters(grey_button),
                            padx=10, cursor="hand2", width=15, background="#e6e6e6")
        grey_button.bind("<Enter>", lambda e: mouse_hover(button=grey_button, color='#aceafc'))
        grey_button.bind("<Leave>", lambda e: mouse_not_hover(button=grey_button, color='#e6e6e6'))
        grey_button.place(x=40, y=60)

        negative_button = tk.Button(filters_frame, text="彩色反转", font=('宋体', 12),
                               command=lambda: self.filters(negative_button), 
                               padx=10, cursor="hand2", width=15, background="#e6e6e6")
        negative_button.bind("<Enter>", lambda e: mouse_hover(button=negative_button, color='#aceafc'))
        negative_button.bind("<Leave>", lambda e: mouse_not_hover(button=negative_button, color='#e6e6e6'))
        negative_button.place(x=40, y=100)

        blur_button = tk.Button(filters_frame, text="高斯模糊", font=('宋体', 12),
                           command=lambda: self.filters(blur_button), 
                           padx=10, cursor="hand2", width=15, background="#e6e6e6")
        blur_button.bind("<Enter>", lambda e: mouse_hover(button=blur_button, color='#aceafc'))
        blur_button.bind("<Leave>", lambda e: mouse_not_hover(button=blur_button, color='#e6e6e6'))
        blur_button.place(x=40, y=140)

        cancel_button = tk.Button(f1, text="取消", command=self.cancel, width=10, font=('宋体', 12),
                              background="#a8cdfe", cursor="hand2", borderwidth=4)
        cancel_button.bind("<Enter>", lambda e: mouse_hover(button=cancel_button, color='#e6e6e6'))
        cancel_button.bind("<Leave>", lambda e: mouse_not_hover(button=cancel_button, color='#a8cdfe'))
        cancel_button.place(x=18, y=220)

        apply_b = tk.Button(f1, text="确认", command=self.apply, width=10, font=('宋体', 12), 
                            background="#a8cdfe", cursor="hand2", borderwidth=4)
        apply_b.bind("<Enter>", lambda e: mouse_hover(button=apply_b, color='#e6e6e6'))
        apply_b.bind("<Leave>", lambda e: mouse_not_hover(button=apply_b, color='#a8cdfe'))
        apply_b.place(x=120, y=220)

    def filters(self, button):
        self.filter_ = button['text'].lower()

        if self.filter_ == '浮雕':
            self.modified_img = self.image_copy.filter(ImageFilter.EMBOSS)

            self.modified_img_resized = self.image_copy_resized.filter(ImageFilter.EMBOSS)
            im = ImageTk.PhotoImage(self.modified_img_resized)
            self.parent.show_image(modified=im)

        elif self.filter_ == '彩色反转':
            self.modified_img = ImageOps.invert(self.image_copy)

            self.modified_img_resized = ImageOps.invert(self.image_copy_resized)
            im = ImageTk.PhotoImage(self.modified_img_resized)
            self.parent.show_image(modified=im)

        elif self.filter_ == '灰度':
            self.modified_img = ImageOps.grayscale(self.image_copy)

            self.modified_img_resized = ImageOps.grayscale(self.image_copy_resized)
            im = ImageTk.PhotoImage(self.modified_img_resized)
            self.parent.show_image(modified=im)

        elif self.filter_ == '高斯模糊':
            self.modified_img = self.image_copy.filter(ImageFilter.GaussianBlur)

            self.modified_img_resized = self.image_copy_resized.filter(ImageFilter.GaussianBlur)
            im = ImageTk.PhotoImage(self.modified_img_resized)
            self.parent.show_image(modified=im)

    def cancel(self):
        self.grab_release()

        im = ImageTk.PhotoImage(self.image_copy_resized)
        self.parent.show_image(modified=im)
        self.destroy()

    def apply(self):
        self.grab_release()

        self.parent.image_copy = self.modified_img

        self.parent.image_copy_resized = self.modified_img_resized
        if self.filter_:
            self.parent.save_button.configure(state="normal")

        im = ImageTk.PhotoImage(self.parent.image_copy_resized)
        self.parent.show_image(modified=im)
        self.destroy()

# 当前模块直接被执行
if __name__ == '__main__':
    # 创建主窗口
    start = ImageEditor()