[Python] 纯文本查看 复制代码
import tkinter as tk
from tkinter import filedialog, messagebox, StringVar
from tkinter import ttk
from PIL import Image, ImageTk
import os
from datetime import datetime
class ImageCompressorApp:
def __init__(self, root):
self.root = root
self.root.title("图片有损压缩工具 by aifeisheng")
self.selected_save_dir = StringVar(value="")
self.file_path = None
# 设置窗口的默认大小为屏幕尺寸的50%
screen_width = root.winfo_screenwidth()
screen_height = root.winfo_screenheight()
default_width = int(screen_width * 0.5)
default_height = int(screen_height * 0.5)
self.root.geometry(f"{default_width}x{default_height}+{int((screen_width - default_width)/2)}+{int((screen_height - default_height)/2)}")
# 主要容器
main_frame = ttk.Frame(root)
main_frame.grid(row=0, column=0, sticky="nsew")
# 左侧选项区域
options_frame = ttk.Frame(main_frame, padding="20")
options_frame.grid(row=0, column=0, sticky="nsew")
# 图片选择按钮
self.select_button = ttk.Button(options_frame, text="选择图片", command=self.select_file)
self.select_button.grid(row=0, column=0, padx=5, pady=5, sticky="ew")
# 压缩级别标签
label_quality = ttk.Label(options_frame, text="压缩级别:")
label_quality.grid(row=1, column=0, padx=5, pady=5, sticky="ew")
# 压缩质量选择
self.quality_scale = ttk.Scale(options_frame, from_=1, to=99, orient=tk.HORIZONTAL, command=self.update_quality_label)
self.quality_scale.set(50) # 默认压缩级别为50
self.quality_scale.grid(row=1, column=1, padx=5, pady=5, sticky="ew")
# 压缩质量标签
self.quality_label_var = StringVar()
self.quality_label = ttk.Label(options_frame, textvariable=self.quality_label_var)
self.quality_label.grid(row=1, column=2, padx=5, pady=5, sticky="w")
self.update_quality_label() # 初始化标签文本
# 压缩按钮
self.compress_button = ttk.Button(options_frame, text="压缩图片", command=self.compress_image)
self.compress_button.grid(row=2, column=0, columnspan=3, padx=5, pady=5, sticky="ew")
# 保存位置标签
save_dir_label = ttk.Label(options_frame, text="保存位置:")
save_dir_label.grid(row=3, column=0, padx=5, pady=5, sticky="ew")
# 保存位置输入框
self.save_dir_entry = ttk.Entry(options_frame, textvariable=self.selected_save_dir)
self.save_dir_entry.grid(row=3, column=1, columnspan=2, padx=5, pady=5, sticky="ew")
# 浏览按钮
self.browse_button = ttk.Button(options_frame, text="浏览...", command=self.choose_save_dir)
self.browse_button.grid(row=4, column=0, columnspan=3, padx=5, pady=5, sticky="ew")
# 右侧预览区域
self.preview_frame = ttk.Frame(main_frame, padding="10", borderwidth=2, relief="flat", style="Preview.TFrame")
self.preview_frame.grid(row=0, column=1, sticky="nsew")
self.preview_label = ttk.Label(self.preview_frame, text="图片预览:", anchor="w")
self.preview_label.pack(side=tk.TOP, fill=tk.X, padx=5, pady=5)
self.image_panel = tk.Label(self.preview_frame, bg="white", width=300, height=300)
self.image_panel.pack(side=tk.TOP, fill=tk.BOTH, expand=True)
# 设置背景颜色
self.root.config(bg="#F5F5F5")
self.preview_frame.config(style="Preview.TFrame")
def select_file(self):
self.file_path = filedialog.askopenfilename(
title="选择图片文件",
filetypes=[("图片文件", "*.jpg;*.jpeg;*.png;*.bmp;*.gif")]
)
if self.file_path:
self.show_preview()
self.selected_save_dir.set(os.path.dirname(self.file_path)) # 默认保存在图片相同目录
def show_preview(self):
if self.file_path:
img = Image.open(self.file_path)
img.thumbnail((300, 300)) # 调整图片大小以适应预览窗口
img_tk = ImageTk.PhotoImage(img)
self.preview_label.config(image=img_tk)
self.preview_label.image = img_tk # 保持对图像的引用
def choose_save_dir(self):
save_dir = filedialog.askdirectory(title="选择保存位置")
if save_dir:
self.selected_save_dir.set(save_dir) # 更新保存目录
def compress_image(self):
if not self.file_path:
messagebox.showwarning("未选择文件", "请先选择一个图片文件。")
return
quality = 100 - int(self.quality_scale.get()) # 转换为压缩质量
if not 1 <= quality <= 99:
messagebox.showerror("错误", "无效的压缩级别设置。")
return
try:
save_dir = self.selected_save_dir.get()
if not save_dir:
save_dir = os.path.dirname(self.file_path) # 如果没有选择保存目录,使用图片所在的目录
new_file_path = self.do_image_compression(quality, save_dir)
messagebox.showinfo("压缩完成", f"图片压缩完成!\n新文件路径: {new_file_path}")
except Exception as e:
messagebox.showerror("错误", f"压缩过程中发生错误: {e}")
def do_image_compression(self, quality, save_dir):
img = Image.open(self.file_path)
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
file_extension = os.path.splitext(self.file_path)[1]
new_file_name = os.path.splitext(os.path.basename(self.file_path))[0] + f"_{timestamp}_comp{file_extension}"
new_file_path = os.path.join(save_dir, new_file_name)
if img.format == "JPEG":
img.save(new_file_path, optimize=True, quality=quality)
else:
new_img = img.convert('RGB')
new_img.save(new_file_path, format='JPEG', quality=quality)
return new_file_path
def update_quality_label(self, *args):
quality = int(self.quality_scale.get())
self.quality_label_var.set(f"({quality})")
if __name__ == "__main__":
root = tk.Tk()
app = ImageCompressorApp(root)
root.mainloop()