PDF拆分与合并工具
使用“万兴PDF”有点麻烦,且无拆分功能
python写
作者:chatGPT && 我(inmark.dev)
GUI版:PDF工具.exe
源码
无GUI版
点击展开/折叠
from pypdf import PdfReader, PdfWriter
import os
import sys
import 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 os
import re
import webbrowser
import tkinter as tk
from tkinter import filedialog, messagebox, ttk
from 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()