简单记录一下如何通过脚本完成 PDF 的一些简单处理需求,通过 uv + PyMuPDF 完成。

使用时只需要临时写一个 main.py,直接用 uv 指定依赖运行:

1
uv run --with pymupdf main.py

提取指定页面

1
2
3
4
5
import pymupdf

with pymupdf.open("input.pdf") as doc:
doc.select([p - 1 for p in [1, 3, 5, 6, 7]]) # page 1,3,5,6,7 -> new file
doc.ez_save("output.pdf")

支持对页面顺序进行重排

1
2
3
4
5
import pymupdf

with pymupdf.open("input.pdf") as doc:
doc.select([p - 1 for p in [5, 1, 3]]) # page 5,1,3 -> new file
doc.ez_save("output.pdf")

剔除指定页面

1
2
3
4
5
import pymupdf

with pymupdf.open("input.pdf") as doc:
doc.delete_pages([p - 1 for p in [1, 4, 5]])
doc.ez_save("output.pdf")

单页转 PNG

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import pymupdf

# one page
with pymupdf.open("input.pdf") as doc:
pix = doc[3 - 1].get_pixmap(dpi=300)
pix.save("page-3.png")

# some pages
with pymupdf.open("input.pdf") as doc:
for p in [1, 3, 7, 10]:
pix = doc[p - 1].get_pixmap(dpi=300)
pix.save(f"page-{p}.png")

# all pages
with pymupdf.open("input.pdf") as doc:
for i, page in enumerate(doc, start=1):
pix = page.get_pixmap(dpi=300)
pix.save(f"page-{i}.png")

逐页拆 PDF

1
2
3
4
5
6
7
8
import pymupdf

with pymupdf.open("input.pdf") as src:
for i in range(src.page_count):
dst = pymupdf.open()
dst.insert_pdf(src, from_page=i, to_page=i)
dst.ez_save(f"page-{i + 1}.pdf")
dst.close()

合并 PDF

多个 PDF 合并拼接为一个新的 PDF

1
2
3
4
5
6
7
8
9
10
11
12
import pymupdf

files = ["a.pdf", "b.pdf", "c.pdf"]

out = pymupdf.open()

for filename in files:
with pymupdf.open(filename) as doc:
out.insert_pdf(doc)

out.ez_save("merged.pdf")
out.close()

更复杂的例子

下面是一个更加灵活的拆分合并的例子:从两个 PDF 中分别取页面,再组成一个新 PDF。

1
2
3
4
5
6
7
8
9
10
11
12
import pymupdf

out = pymupdf.open()

with pymupdf.open("a.pdf") as doc:
out.insert_pdf(doc, from_page=4, to_page=9)

with pymupdf.open("b.pdf") as doc:
out.insert_pdf(doc, from_page=1, to_page=3)

out.ez_save("output.pdf")
out.close()

最终得到

1
a.pdf 第 5–10 页 + b.pdf 第 2–4 页

补充

  • PyMuPDF 在早期的使用中沿用了历史模块名 import fitz,现在支持并且更推荐使用 import pymupdf。
  • 对 PDF 文件的页面编号始终从 0 开始,可以使用 doc.page_count 获取总页数。
  • 临时处理后的保存可以使用 doc.ez_save("output.pdf"),相比最简单的 doc.save("output.pdf"),前者会默认进行一些 PDF 对象清理和压缩的优化,这属于 PDF 结构层面的无损整理。