You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
160 lines
4.9 KiB
160 lines
4.9 KiB
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
|