import tkinter as tk from tkinter import ttk, filedialog, messagebox import os import subprocess import threading # 拖拽支持(Windows) try: from tkinterdnd2 import DND_FILES, TkinterDnD DND_AVAILABLE = True except: DND_AVAILABLE = False class PDFCompressorApp: def __init__(self, root): self.root = root self.root.title("Snail PDF压缩工具") self.root.geometry("650x450") self.files = [] self.quality_map = { "极限压缩(低质量)": "/screen", "标准压缩(推荐)": "/ebook", "高质量(打印)": "/printer" } self.create_widgets() def create_widgets(self): frame = tk.Frame(self.root) frame.pack(fill="both", expand=True, padx=10, pady=10) # 文件列表 self.listbox = tk.Listbox(frame, height=12) self.listbox.pack(fill="both", expand=True) # 拖拽支持 if DND_AVAILABLE: self.listbox.drop_target_register(DND_FILES) self.listbox.dnd_bind("<>", self.drop_files) # 按钮区 btn_frame = tk.Frame(frame) btn_frame.pack(pady=5) tk.Button(btn_frame, text="添加文件", command=self.add_files).pack(side="left", padx=5) tk.Button(btn_frame, text="添加文件夹", command=self.add_folder).pack(side="left", padx=5) tk.Button(btn_frame, text="清空", command=self.clear_files).pack(side="left", padx=5) # 压缩质量 tk.Label(frame, text="压缩质量:").pack() self.quality = tk.StringVar(value="标准压缩(推荐)") ttk.Combobox( frame, textvariable=self.quality, values=list(self.quality_map.keys()) ).pack() # 进度条 self.progress = ttk.Progressbar(frame, length=600) self.progress.pack(pady=10) # 状态 self.status = tk.Label(frame, text="等待开始") self.status.pack() # 开始按钮 tk.Button(frame, text="开始压缩", bg="green", fg="white", command=self.start).pack(pady=10) def add_files(self): files = filedialog.askopenfilenames(filetypes=[("PDF Files", "*.pdf")]) self.add_to_list(files) def add_folder(self): folder = filedialog.askdirectory() if folder: pdfs = [os.path.join(folder, f) for f in os.listdir(folder) if f.lower().endswith(".pdf")] self.add_to_list(pdfs) def add_to_list(self, files): for f in files: if f not in self.files: self.files.append(f) self.listbox.insert(tk.END, f) def drop_files(self, event): files = self.root.tk.splitlist(event.data) self.add_to_list(files) def clear_files(self): self.files.clear() self.listbox.delete(0, tk.END) def start(self): if not self.files: messagebox.showwarning("提示", "请先添加PDF文件") return threading.Thread(target=self.compress_all, daemon=True).start() def compress_all(self): gs_path = os.path.join(os.getcwd(), "bin", "gswin64c.exe") if not os.path.exists(gs_path): messagebox.showerror("错误", "未找到 bin/gswin64c.exe(请检查Ghostscript绿色版)打包后的exe文件放置SnailPDF目录下运行") return total = len(self.files) self.progress["maximum"] = total for i, file in enumerate(self.files): output = file.replace(".pdf", "_compressed.pdf") try: before_size = os.path.getsize(file) cmd = [ gs_path, "-sDEVICE=pdfwrite", "-dCompatibilityLevel=1.4", f"-dPDFSETTINGS={self.quality_map[self.quality.get()]}", "-dNOPAUSE", "-dBATCH", f"-sOutputFile={output}", file ] subprocess.run( cmd, capture_output=True, text=True, creationflags=subprocess.CREATE_NO_WINDOW ) after_size = os.path.getsize(output) ratio = (1 - after_size / before_size) * 100 self.status.config( text=f"完成: {os.path.basename(file)} | 压缩率: {ratio:.1f}%" ) except Exception as e: self.status.config(text=f"失败: {os.path.basename(file)}") self.progress["value"] = i + 1 messagebox.showinfo("完成", "全部压缩完成!") if __name__ == "__main__": if DND_AVAILABLE: root = TkinterDnD.Tk() else: root = tk.Tk() app = PDFCompressorApp(root) root.mainloop() #打包命令 .\python.exe -m PyInstaller --onefile --windowed --icon=icon.ico --name "SnailSend" .\main.py