PDF拆分与合并工具
2025.10.15
工具推荐 8969 Words
- Views
- Comments
目录索引
目录索引
使用“万兴PDF”有点麻烦,且无拆分功能 python写 作者:chatGPT && 我
GUI版:PDF工具.exe
源码
无GUI版
from pypdf import PdfReader, PdfWriterimport osimport sysimport re
def split_pdf(input_path, output_dir): """将指定 PDF 拆分为单页文件""" if not os.path.exists(input_path): print(f"❌ 找不到文件:{input_path}") return
try: reader = PdfReader(input_path) except Exception as e: print(f"❌ 无法读取 PDF 文件:{e}") return
total_pages = len(reader.pages) print(f"📄 原始 PDF 页数:{total_pages}")
os.makedirs(output_dir, exist_ok=True)
for i in range(total_pages): writer = PdfWriter() writer.add_page(reader.pages[i]) output_path = os.path.join(output_dir, f"{i + 1}.pdf") with open(output_path, "wb") as f: writer.write(f) print(f"[{i + 1}/{total_pages}] ✅ 已保存:{output_path}")
print(f"\n🎉 拆分完成!输出目录:{os.path.abspath(output_dir)}")
def merge_pdfs(input_dir): """将目录下的 PDF 文件按数字顺序合并,并以目录名命名输出文件""" if not os.path.isdir(input_dir): print(f"❌ 目录不存在:{input_dir}") return
pdf_files = [f for f in os.listdir(input_dir) if f.lower().endswith('.pdf')] if not pdf_files: print("⚠️ 该目录下没有找到 PDF 文件。") return
# 提取数字排序,例如 1.pdf, 2.pdf, 10.pdf def extract_num(filename): match = re.search(r"(\d+)", filename) return int(match.group(1)) if match else float("inf")
pdf_files.sort(key=extract_num)
writer = PdfWriter()
for pdf in pdf_files: path = os.path.join(input_dir, pdf) try: reader = PdfReader(path) for page in reader.pages: writer.add_page(page) print(f"✅ 已合并:{pdf}") except Exception as e: print(f"⚠️ 跳过文件 {pdf},原因:{e}")
# 输出文件路径与目录同名 output_path = os.path.abspath(f"{input_dir}.pdf")
with open(output_path, "wb") as f: writer.write(f)
print(f"\n🎉 合并完成!输出文件:{output_path}")
def choose_pdf_in_directory(): """列出当前目录下的 PDF 文件,并让用户选择""" pdf_files = [f for f in os.listdir('.') if f.lower().endswith('.pdf')] if not pdf_files: print("⚠️ 当前目录下没有找到任何 PDF 文件。") sys.exit(0)
print("📂 当前目录下的 PDF 文件:") for idx, pdf in enumerate(pdf_files, start=1): print(f"{idx}. {pdf}")
while True: choice = input("\n请输入要拆分的 PDF 编号:").strip() if not choice.isdigit(): print("❌ 请输入数字编号。") continue
choice = int(choice) if 1 <= choice <= len(pdf_files): selected_pdf = pdf_files[choice - 1] print(f"✅ 已选择:{selected_pdf}") return selected_pdf else: print("❌ 编号超出范围,请重新输入。")
def main(): print("=== PDF 工具 ===") print("1️⃣ 拆分 PDF") print("2️⃣ 合并 PDF") mode = input("\n请选择操作模式 (1 或 2):").strip()
if mode == "1": selected_file = choose_pdf_in_directory() base_name = os.path.splitext(selected_file)[0] output_dir = f"{base_name}_pages" split_pdf(selected_file, output_dir)
elif mode == "2": input_dir = input("\n输入合并PDF文件夹名(PDF按命名1.pdf,2.pdf,3.pdf...合并):").strip() if not input_dir: print("❌ 目录名称不能为空。") return merge_pdfs(input_dir)
else: print("❌ 无效输入,请输入 1 或 2。")
if __name__ == "__main__": main() input("\n按回车键退出程序...")GUI版
import osimport reimport webbrowserimport tkinter as tkfrom tkinter import filedialog, messagebox, ttkfrom pypdf import PdfReader, PdfWriter
def split_pdf(input_path, output_dir, progress_bar, progress_label, window): """将指定 PDF 拆分为单页文件,并更新进度条""" try: reader = PdfReader(input_path) total_pages = len(reader.pages) os.makedirs(output_dir, exist_ok=True)
for i in range(total_pages): writer = PdfWriter() writer.add_page(reader.pages[i]) output_path = os.path.join(output_dir, f"{i + 1}.pdf") with open(output_path, "wb") as f: writer.write(f)
# 更新进度条 percent = int(((i + 1) / total_pages) * 100) progress_bar["value"] = percent progress_label.config(text=f"进度:{percent}% ({i + 1}/{total_pages})") window.update_idletasks()
messagebox.showinfo("完成", f"已成功拆分为 {total_pages} 页。\n输出目录:\n{os.path.abspath(output_dir)}") except Exception as e: messagebox.showerror("错误", f"拆分失败:{e}") finally: progress_bar["value"] = 0 progress_label.config(text="进度:0%")
def merge_pdfs(input_dir, progress_bar, progress_label, window): """将目录下的 PDF 文件按数字顺序合并,并更新进度条""" try: pdf_files = [f for f in os.listdir(input_dir) if f.lower().endswith(".pdf")] if not pdf_files: messagebox.showwarning("提示", "该目录下没有 PDF 文件。") return
def extract_num(filename): match = re.search(r"(\d+)", filename) return int(match.group(1)) if match else float("inf")
pdf_files.sort(key=extract_num) writer = PdfWriter()
total_files = len(pdf_files) for idx, pdf in enumerate(pdf_files, start=1): path = os.path.join(input_dir, pdf) reader = PdfReader(path) for page in reader.pages: writer.add_page(page)
# 更新进度条 percent = int((idx / total_files) * 100) progress_bar["value"] = percent progress_label.config(text=f"进度:{percent}% ({idx}/{total_files})") window.update_idletasks()
output_path = os.path.abspath(f"{input_dir}.pdf") with open(output_path, "wb") as f: writer.write(f)
messagebox.showinfo("完成", f"已成功合并 {total_files} 个文件。\n输出文件:\n{output_path}") except Exception as e: messagebox.showerror("错误", f"合并失败:{e}") finally: progress_bar["value"] = 0 progress_label.config(text="进度:0%")
def choose_split_file(progress_bar, progress_label, window): file_path = filedialog.askopenfilename(title="选择要拆分的 PDF 文件", filetypes=[("PDF 文件", "*.pdf")]) if not file_path: return base_name = os.path.splitext(os.path.basename(file_path))[0] output_dir = f"{base_name}_pages" split_pdf(file_path, output_dir, progress_bar, progress_label, window)
def choose_merge_dir(progress_bar, progress_label, window): dir_path = filedialog.askdirectory(title="选择要合并的 PDF 目录") if not dir_path: return merge_pdfs(dir_path, progress_bar, progress_label, window)
def open_website(event=None): """打开发布网址""" webbrowser.open("https://inmark.dev")
def main(): window = tk.Tk() window.title("PDF 工具 - 拆分与合并") window.geometry("520x440") window.resizable(False, False)
# 标题 tk.Label(window, text="PDF 工具", font=("Microsoft YaHei", 20, "bold")).pack(pady=10)
# 说明文字 desc_text = ( "📄 拆分 PDF:选择单个 PDF → 自动拆页到 {文件名}_pages 文件夹。\n\n" "🧩 合并 PDF:选择一个文件夹 → 自动合并里面的 1.pdf, 2.pdf, 3.pdf... → 生成 {文件夹名}.pdf" ) tk.Label(window, text=desc_text, font=("Microsoft YaHei", 10), justify="left", wraplength=480, fg="#333").pack(pady=10)
# 按钮框 btn_frame = tk.Frame(window) btn_frame.pack(pady=10)
btn_split = tk.Button(btn_frame, text="📄 拆分 PDF", font=("Microsoft YaHei", 12), width=20, height=2, bg="#4CAF50", fg="white", command=lambda: choose_split_file(progress_bar, progress_label, window)) btn_split.grid(row=0, column=0, padx=15, pady=5)
btn_merge = tk.Button(btn_frame, text="🧩 合并 PDF", font=("Microsoft YaHei", 12), width=20, height=2, bg="#2196F3", fg="white", command=lambda: choose_merge_dir(progress_bar, progress_label, window)) btn_merge.grid(row=0, column=1, padx=15, pady=5)
# 进度条区域 progress_frame = tk.Frame(window) progress_frame.pack(pady=20)
progress_label = tk.Label(progress_frame, text="进度:0%", font=("Microsoft YaHei", 10)) progress_label.pack(pady=5)
progress_bar = ttk.Progressbar(progress_frame, length=400, mode='determinate') progress_bar.pack()
# 发布网址(可点击) link_label = tk.Label(window, text="🌐 发布网址:https://inmark.dev", font=("Microsoft YaHei", 9, "underline"), fg="#1E88E5", cursor="hand2") link_label.pack(pady=5) link_label.bind("<Button-1>", open_website)
# 作者信息 tk.Label(window, text="作者:ChatGPT && inmark.dev", font=("Microsoft YaHei", 9), fg="gray").pack(side="bottom", pady=8)
window.mainloop()
if __name__ == "__main__": main()