0 流程总览
要解决 3 个未知数:目录在哪几页 / 有哪些条目 / 印刷页码与 PDF 物理页序差多少。
条目靠「渲染图片 + 模型识别」获取。流程四步:
第 1 步 定位目录页
├─ 用户已说「目录在第 N 页」→ 跳过定位,直接用 --toc N(跨页 --toc N M)
└─ 用户没说 → 跑 --find-toc(渲缩略图供模型识别)
第 2 步 识别目录条目
└─ --dump-toc-images → 产出 entries.json
第 3 步 确定页码偏移
└─ --anchor 印刷页:物理页(无偏移时不必给;罗马页码见 §3)
第 4 步 生成书签文件(机器做)
└─ entries.json 逐条换算物理页 → 书签 txt(首条自动为「目录」)
1 定位目录页
已知目录页 → 跳过定位,直接进第 2 步:--toc N(单页)或 --toc N M(跨页)。
未知 → 渲染前 12 页缩略图,供模型识别目录页:
python pdf_toc_to_bookmarks.py <你的PDF> --find-toc ./toc_scan
前 12 页未见目录 → 加大 --scan-pages(如 --scan-pages 40)重跑。
2 识别目录条目
python pdf_toc_to_bookmarks.py <你的PDF> --toc 11 12 --dump-toc-images ./toc_imgs
模型识别产出 entries.json 前注意:
- 存疑行必须复核:看不清或疑似识别错的,用
--dpi 400重渲目录页后重识别(--dump-toc-images ./toc_hi --dpi 400)。 - 非目录页(封面 / 前言正文页)跳过。
- 层级:章 / 附录 / 前言 / 参考文献 = 1,
x.y/A.x= 2,x.y.z= 3。
entries.json 格式:
{
"entries": [
{"title": "1 范围", "page": 1, "level": 1},
{"title": "1.1 通用要求", "page": 1, "level": 2},
{"title": "1.1.1 总体要求", "page": 2, "level": 3}
]
}
- 键为
title(非text)。 - 页码 / 层级可省:脚本按编号 X/X.Y/X.Y.Z 定级,缺页码继承下一条 −1。
- 罗马页码:
roman填罗马值(如 1/2/3 或 I/II/III)、page留null。 - 「目录」条目不必写,脚本生成时自动补为第一条(见 §4)。
3 确定页码偏移
- 偏移 = 物理页 − 印刷页:用
--anchor 印刷页:物理页给(如--anchor 2:7);两者一致时不必给。 - 罗马页码(前言等前置页 = Ⅰ/Ⅱ/Ⅲ):
phys = 罗马值 + roman_offset。 roman_offset默认取首个目录页索引,即默认假设目录页 = 罗马 Ⅰ。- 该假设不成立时(目录页不编罗马号、罗马号从前言起),用
--anchor-roman 罗马值:物理页纠正(如--anchor-roman Ⅰ:13)。
4 生成书签文件
python pdf_toc_to_bookmarks.py <你的PDF> \
--entries-json ./entries.json \
--toc 11 12 --anchor 2:7
- 输出格式:
标题;物理页码,层级用制表符缩进(一级 0 / 二级 1 / 三级 2 个),UTF-8(utf-8-sig,带 BOM);福昕 / Adobe(AutoBookmark 插件)/ PDF-XChange 等均可直接导入。 - 首条固定为「目录」,页码取
--toc的物理首页(目录页自身,不经偏移换算);JSON 已含「目录 / 目次」条目时不再重复添加。
5 参数速查
| 参数 | 默认 | 作用 |
|---|---|---|
--find-toc DIR |
— | 定位目录页:扫描前若干页并渲染缩略图到 DIR 供模型识别(第 1 步) |
--scan-pages N |
12 | --find-toc 扫描页数(目录更深时加大) |
--toc N [M] |
— | 目录所在物理页码(1 基、均含):单页 --toc 5,跨页 --toc 5 8;脚本内部转 0 基 |
--entries-json FILE |
— | 读取条目 JSON(模型识别产出)并生成书签(第 4 步) |
--anchor N:I |
— | 偏移 = 物理页 I − 印刷页 N(如 --anchor 2:7 → 5);无偏移时不必给 |
--anchor-roman R:I |
— | 罗马偏移 = 物理页 I − 罗马值 R(如 --anchor-roman Ⅰ:1 → 0);不给则取首个目录页索引(设目录页 = 罗马 Ⅰ) |
--dump-toc-images DIR |
— | 渲染目录页图片(第 2 步 模型识别) |
--dpi N |
200 | --dump-toc-images 渲染 DPI |
--sep CHAR |
; |
标题与页码分隔符 |
--out FILE |
<PDF名>_bookmarks.txt |
书签输出路径 |
6 验证案例
| 序号 | 样本 | 页数 | 条数 | offset | 备注 |
|---|---|---|---|---|---|
| 1 | GB/T 42300-2022 | 27页 | 36 全对 | 6 | — |
| 2 | AQ 3063-2025 | 28页 | 36 全对 | 3 | 2 处存疑行 400dpi 重渲复核后修正 |
| 3 | SPMP-STD-EM2001-2015 | 20页 | 32 全对 | 0 | 目录页脚 = 物理页 |
| 4 | AQ/T 3033-2022 | 27页 | 17 全对 | 3 | 全自动定位实测:--find-toc 命中第 2 页,产物与人工版逐行一致 |
| 5 | 化工过程开发设计 第2版 | 408页 | 181 全对 | 10 | 7 处存疑行重渲复核,纠正 2 处初读 |
| 6 | 化工工艺系统设计(769页) | 769页 | 40 全对 | 12 | 大页数书籍全流程实测 |
7 交付核对
- 依赖仅
pymupdf(pip install pymupdf),零密钥、零在线服务。 - 交付前核对条数:脚本末行「共 N 条」应等于 JSON entries 条数,对不上不交付。
- 页码识别错 1~2 处属正常,交付前对页码抽查复核即可。