5 changed files with 160 additions and 0 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,160 @@ |
|||||
|
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("<<Drop>>", 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 |
||||
Loading…
Reference in new issue