[Python] 纯文本查看 复制代码
import tkinter as tk
from tkinter import ttk
from tkinter import filedialog
from tkinter import messagebox
from PIL import Image, ImageTk
import os
import threading
import time
import json
class FirstTimeGuide:
def __init__(self, parent):
self.parent = parent
self.dialog = tk.Toplevel(parent)
self.dialog.title("新手引导")
self.dialog.protocol("WM_DELETE_WINDOW", self.on_close)
intro_text = (
"欢迎使用图片压缩工具!\n\n"
"1. 选择输入文件夹:点击‘浏览’选择图片目录。\n"
"2. 选择输出文件夹:设置压缩后图片存放位置。\n"
"3. 调整压缩质量:滑块控制压缩程度。\n"
"4. 高级设置:更多自定义选项。\n"
"5. 开始压缩:点击按钮开始任务。\n\n"
"了解后,点击‘开始使用’开始体验。"
)
ttk.Label(self.dialog, text=intro_text, justify="left", wraplength=400).pack(pady=20)
ttk.Button(self.dialog, text="开始使用", command=self.on_start).pack(pady=10)
def on_close(self):
with open("first_launch.json", "w") as file:
json.dump({"shown": True}, file)
self.dialog.destroy()
def on_start(self):
self.dialog.destroy()
class AdvancedOptionsDialog:
def __init__(self, parent, compressor):
self.parent = parent
self.compressor = compressor
self.dialog = tk.Toplevel(parent)
self.dialog.title("高级设置")
ttk.Label(self.dialog, text="压缩质量 (1-100):").pack(pady=10)
self.quality_var = tk.IntVar()
self.quality_var.set(self.compressor.quality_var.get())
ttk.Scale(self.dialog, variable=self.quality_var, from_=1, to=100, orient=tk.HORIZONTAL).pack()
ttk.Label(self.dialog, text="线程数:").pack(pady=10)
self.threads_var = tk.IntVar()
self.threads_var.set(4)
ttk.Spinbox(self.dialog, from_=1, to=10, textvariable=self.threads_var).pack()
ttk.Button(self.dialog, text="保存设置", command=self.save_and_close).pack(pady=10)
def save_and_close(self):
self.compressor.quality_var.set(self.quality_var.get())
self.dialog.destroy()
class ImageCompressorGUI:
def __init__(self, master):
self.master = master
master.title("[color=#2c2c36][font=-apple-system, BlinkMacSystemFont, "][size=16px]像素减肥所:逗趣图片紧身衣[/size][/font][/color]")
self.quality_var = tk.IntVar(value=75)
self.setup_ui()
self.progress_var = tk.DoubleVar()
self.progress_bar = ttk.Progressbar(self.master, orient="horizontal", length=300, mode="determinate", variable=self.progress_var)
self.progress_bar.grid(row=7, column=0, columnspan=3, padx=5, pady=5)
self.status_label = ttk.Label(master, text="准备就绪", foreground="green")
self.status_label.grid(row=8, column=0, columnspan=3, padx=5, pady=5)
self.compress_thread = None
self.load_history()
def setup_ui(self):
self.input_label = ttk.Label(self.master, text="选择输入文件夹:")
self.input_label.grid(row=0, column=0, padx=5, pady=5)
self.input_var = tk.StringVar()
self.input_entry = ttk.Entry(self.master, textvariable=self.input_var, width=50)
self.input_entry.grid(row=0, column=1, padx=5, pady=5)
self.browse_input_button = ttk.Button(self.master, text="浏览", command=self.browse_input_folder)
self.browse_input_button.grid(row=0, column=2, padx=5, pady=5)
self.output_label = ttk.Label(self.master, text="选择输出文件夹:")
self.output_label.grid(row=1, column=0, padx=5, pady=5)
self.output_var = tk.StringVar()
self.output_entry = ttk.Entry(self.master, textvariable=self.output_var, width=50)
self.output_entry.grid(row=1, column=1, padx=5, pady=5)
self.browse_output_button = ttk.Button(self.master, text="浏览", command=self.browse_output_folder)
self.browse_output_button.grid(row=1, column=2, padx=5, pady=5)
self.quality_label = ttk.Label(self.master, text="压缩质量:")
self.quality_label.grid(row=2, column=0, padx=5, pady=5)
ttk.Scale(self.master, variable=self.quality_var, from_=1, to=100, orient=tk.HORIZONTAL).grid(row=2, column=1, columnspan=2, padx=5, pady=5)
self.compress_button = ttk.Button(self.master, text="开始压缩", command=self.start_compression)
self.compress_button.grid(row=4, column=0, columnspan=3, padx=5, pady=10)
self.advanced_button = ttk.Button(self.master, text="高级设置", command=self.show_advanced_options)
self.advanced_button.grid(row=6, column=0, columnspan=3, padx=5, pady=5)
def browse_input_folder(self):
folder_path = filedialog.askdirectory()
self.input_var.set(folder_path)
def browse_output_folder(self):
folder_path = filedialog.askdirectory()
self.output_var.set(folder_path)
def start_compression(self):
input_folder = self.input_var.get()
output_folder = self.output_var.get()
if not os.path.isdir(input_folder) or not os.path.isdir(output_folder):
self.status_label.config(text="输入或输出路径无效,请检查", foreground="red")
return
self.status_label.config(text="压缩进行中...", foreground="black")
self.progress_var.set(0)
self.compress_thread = threading.Thread(target=self.compress_images, args=(input_folder, output_folder))
self.compress_thread.start()
def compress_images(self, input_folder, output_folder):
total_files = sum(len(files) for _, _, files in os.walk(input_folder))
processed_files = 0
for root, dirs, files in os.walk(input_folder):
for file in files:
img_path = os.path.join(root, file)
output_path = os.path.join(output_folder, file)
try:
with Image.open(img_path) as im:
# 根据文件类型调整压缩参数
if file.lower().endswith(('.jpg', '.jpeg')):
im.save(output_path, optimize=True, quality=self.quality_var.get())
elif file.lower().endswith('.png'):
# 尝试使用更高的压缩级别来压缩PNG图像
im.save(output_path, format='PNG', optimize=True, compress_level=9)
else:
messagebox.showinfo("提示", f"{file} 不是支持的图片格式,已跳过。")
continue
processed_files += 1
self.progress_var.set(processed_files / total_files * 100)
self.master.update_idletasks()
except Exception as e:
messagebox.showerror("错误", f"处理{file}时出错: {e}")
self.status_label.config(text="压缩出错,请查看错误信息", foreground="red")
break
if processed_files == total_files:
self.status_label.config(text="压缩完成", foreground="green")
else:
self.status_label.config(text="压缩中断", foreground="orange")
def show_advanced_options(self):
AdvancedOptionsDialog(self.master, self)
def load_history(self):
try:
with open("history.json", "r") as file:
history = json.load(file)
self.input_var.set(history.get("last_input", ""))
self.output_var.set(history.get("last_output", ""))
except FileNotFoundError:
pass
def save_history(self):
history = {"last_input": self.input_var.get(), "last_output": self.output_var.get()}
with open("history.json", "w") as file:
json.dump(history, file)
def check_first_time(self):
try:
with open("first_launch.json", "r") as file:
return json.load(file).get("shown", False)
except FileNotFoundError:
return False
def on_closing(self):
self.save_history()
self.master.destroy()
if __name__ == "__main__":
root = tk.Tk()
app = ImageCompressorGUI(root)
# 新手引导
if not app.check_first_time():
FirstTimeGuide(root)
root.protocol("WM_DELETE_WINDOW", app.on_closing)
root.mainloop()