Calibre 的 --pdf-add-toc 会把目录页插在 PDF 末尾,方便打印但不适合电子阅读。EPUB 自带的目录书签完整,但同样落在尾部。
--use-auto-toc 用 XPath 自动生成目录,效果不稳定,经常只匹配到少量标题。
方案 链接到标题
两步处理:
- Calibre 转换(不加
--pdf-add-toc,保留 EPUB 自带目录) - PyMuPDF 脚本把末尾目录页移到正文前方
ebook-convert input.epub output.pdf
生成的文件目录页在最后两页,用以下脚本移动到第 3 页之后:
import fitz
src = '某书_with_toc.pdf'
dst = '某书_with_toc_moved.pdf'
doc = fitz.open(src)
total = len(doc)
toc_start = total - 2 # 目录页起始位置
# 页面映射:旧页码 → 新页码
old_to_new = {}
idx = 0
for old in range(3): # 前3页:空白、扉页、格言页
old_to_new[old] = idx; idx += 1
for old in range(toc_start, total): # 目录页
old_to_new[old] = idx; idx += 1
for old in range(3, toc_start): # 正文
old_to_new[old] = idx; idx += 1
new_doc = fitz.open()
new_doc.insert_pdf(doc, 0, 2) # 前3页
new_doc.insert_pdf(doc, toc_start, total-1) # 目录页
new_doc.insert_pdf(doc, 3, toc_start-1) # 正文
# 修正书签页码
toc = doc.get_toc()
new_toc = [[lvl, title, old_to_new[page-1]+1] for lvl, title, page in toc]
new_doc.set_toc(new_toc)
new_doc.save(dst)
结果 链接到标题
- 目录页位于扉页/格言页之后,正文之前
- 书签数量不变,页码自动修正,点击跳转正确
注意事项 链接到标题
--use-auto-toc的--level1-toc="//h:h1"等 XPath 对 EPUB 内部结构依赖大,优先用自带目录set_toc需在insert_pdf完成后调用,页码为 1-based- 如果目录页不在末尾,需先确认
toc_start位置(通过get_toc()或观察页内容)