mcpField
S
scanned-pdf-to-epub

scanned-pdf-to-epub

github.com/wmy2981ドキュメント156 回インストール5 週間前に更新
リポジトリ

scanned-pdf-to-epub について

scanned-pdf-to-epubは、テキスト層のない中国語スキャン書籍PDFを、ナビゲーション目次付きEPUBに変換するワークフロースキルです。決定的なコマンドライン処理とエージェントによる認識・校正を分け、マーカー確認と成果物の検証を行います。

主な機能

  1. 01PDFをページ画像に変換
  2. 02アンカー付きでページをバッチ認識
  3. 03マーカー確認とバッチ結合
  4. 04文章校正と章見出しへの変換
  5. 05ナビゲーション目次付きEPUBの生成
  6. 06目次リンクとファイル構造の検証

活用シーン

  1. 01テキスト層のない中国語スキャン書籍を変換
  2. 02認識に失敗したバッチを再処理
  3. 03認識文を整え、元の目次ページを除去
  4. 04EPUBのナビゲーションと章リンクを確認

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/wmy2981/skills --skill scanned-pdf-to-epub

インストール後、Claude Code で/scanned-pdf-to-epubを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

.claude-plugin/
plugin.json
evals/
evals.json
references/
subagent_prompt.md
scripts/
check_markers.py
extract.py
md_to_epub.py
merge_batches.py
verify.py

詳細

プロジェクトの README より

PDF → EPUB(扫描书转换工作流)

何时使用

  • 输入是一本 PDF 书籍,内页全是扫描图片、没有文字层(用 PyMuPDF 提取不出文本,或全是空白)。
  • 目标产物是一本干净、带完整导航目录、目录可点击跳转的 EPUB。
  • 中间产物可以是 Markdown。
  • 本 skill 面向通用流程:任何页数的纯文字中文书籍,不针对某一本书特化。

本 skill 不适用于:有文字层的数字原生 PDF(直接用提取工具即可);漫画书(图为主,本流程去除插图)。

核心原则:职责边界

环节承担方理由
拆页渲染、标记检查、批次合并、分章、打包、校验CLI 脚本(scripts/)确定性、可复现、可重跑
识图、错别字校对、版权页判定、锚点转标题Agent(Claude 子代理 / 主代理)需要视觉与语义判断,不写脚本
全流程编排与规范SKILL.md承载流程与严谨规则

模型约定:识图子代理必须使用 Sonnet 模型;不要使用外部 API。主代理校对由当前会话模型完成。

不要为识图或校对环节编写脚本——那部分是 Agent 的灵活任务,脚本只覆盖五个确定性命令:extract、check-markers、merge-batches、md-to-epub、verify。

工作流总览

1. extract (CLI)        PDF → 每页一张图 page_0001.png...
2. 子代理识图 (Agent)    每子代理一批 → batch_001.md(纯文本行 + 锚点)
3. 批次标记检查 (CLI)    check-markers 检查各 batch 标记 → 有误重跑、无误通过
4. 批次合并 (CLI)        merge-batches 按序合并 → draft.md
5. 草稿标记复查 (CLI)    check-markers 复查 draft.md 标记
6. 主代理校对 (Agent)    修正错别字(不改原文)→ 锚点转 h 标题 → book.md
7. md-to-epub (CLI)     book.md → 按 h 标题切分章节 → 生成导航目录 → book.epub
8. verify (CLI)          校验 EPUB 结构、目录跳转、无残留

依赖

  • Python 3.10+,pymupdf(渲染 PDF 页为图,import fitz 或 import pymupdf)
  • pandoc(Markdown → EPUB,含导航目录)。安装顺序:
    1. 系统 CLI pandoc(winget install JohnMacFarlane.Pandoc / brew install pandoc)
    2. 或 pip install pypandoc-binary(捆绑 pandoc 二进制,无需单独安装)
    3. 兜底:pip install ebooklib(纯 Python 打包,目录同样生成)
  • 脚本自动探测上述任一可用路径。

启动前先检查:python scripts/extract.py --check 会报告缺哪些依赖。

工作目录布局

在临时目录内新建一个项目文件夹 book/,全部产物放其中:

book/
├── pages/            # 1. 拆页图片 page_0001.png...
├── raws/             # 2. 子代理识图输出 batch_001.md...
├── draft.md          # 3-5. 批次合并 + 标记检查后的草稿(仍含 PAGE/CH/__ 标记)
├── book.md           # 6. 校对优化后的全文(干净层级化 Markdown)
└── book.epub         # 7. 最终产物

1. extract:拆页渲染(CLI)

python scripts/extract.py <input.pdf> -o book/pages [--dpi 300]
  • 每页渲染为一张 PNG,文件名按原书页码顺序 page_0001.png、page_0002.png……(从 1 起连续编号,忽略 PDF 内部无关页面偏移)。
  • 默认 300 DPI,足以支撑中文小字识别;输出时打印总页数,供调度子代理参考。
  • 结束后核对 pages/ 图片数量 == PDF 页数。

2. 子代理识图(Sonnet 子代理):逐页转纯文本行 + 锚点

分派规则
  • 模型:本阶段识图一律使用 Sonnet 模型子代理(Sonnet 具备本环境识图能力),严禁使用外部 API 或其他模型;主代理校对由当前会话模型完成。
  • 每个子代理负责连续 10 张图片:子代理 #1 负责 page_0001–page_0010,#2 负责 page_0011–page_0020……批次严格按页码顺序分派。
  • 批次边界:第 k 个子代理负责 page_{(k-1)*10+1:04d} ~ page_{k*10:04d};最后一批不足 10 页则只处理实际存在的页。
  • 并发由主代理自行决定:一次可同时调度多个子代理,各自负责不同批次,批次间不重叠、顺序不乱。并发数与批次划分由主代理按页数规模、成本与运行环境权衡,不设固定上限。
  • 每子代理一个文件:子代理把自己负责的整批页内容写入同一个文件 batch_{k:03d}.md(命名规范见 references/subagent_prompt.md),文件内**每页(含空白页、无正文页)**均以 <!-- PAGE XXXX --> 注释定位(空页只写标记不写内容)。失败重跑以批次为单位。
子代理提示词模板(引用 references/subagent_prompt.md)

调度每个子代理时,直接使用 references/subagent_prompt.md 中的提示词模板:把 {N}、{起始页}、{结束页}、{批次序号}、{pages_dir}、{raws_dir} 替换为实际值后作为子代理任务传入(识别必须用 Sonnet 模型)。该文件是提示词的唯一正式来源,本小节不再内嵌模板正文。 调度子代理时,仅可替换模板中 {占位符} 标记的内容,模板其余部分必须原样保留,禁止增删或修改。

子代理严格输出约束(要点)

子代理的唯一输出规范以 references/subagent_prompt.md 的提示词模板为准,要点归纳如下;完整条款见模板与下方「锚点规范」「内容保留 / 去除规则」:

  • 输出纯文本行:原文一个自然段 = Markdown 一行,段落间空行;不使用列表、表格、代码块等结构标记。
  • 跨页段落:一个自然段被分页截断时,上一页行尾与下一页行首各写 __ 连接标记(两部分间不放空行),校对时合并为一段。
  • 禁止:任何解释、说明、思考过程、结论、"这是第 X 页"之类元评论;禁止页眉页脚文字;禁止对图片的描述性旁白。
  • 每子代理一个文件 batch_{k:03d}.md:严格按 page_XXXX.png 文件名的数字顺序逐页读取,整批页内容顺序写入同一文件;每页(含空页)以 <!-- PAGE XXXX --> 定位(XXXX 严格等于该图片文件名的页码:读 page_0005.png 写 <!-- PAGE 0005 -->)。
  • 遇到章节标题时,插入层级前缀式锚点(见下),正文段落里不重复标题文字;层级如实反映原书结构,不主观合并或拆分。
  • 保留:前言、后记(标题用锚点标注层级)、各章节章号/大标题、正文段落;原书目录页照常识别。
  • 去除:页眉、页脚、插图、二维码/条形码/水印等无关标识。
  • 遇到疑似版权页(整页版权声明模式:ISBN / 版权年份 / 出版信息 / 印次号)时,整页内容以单个锚点 <!-- COPYRIGHT_CANDIDATE --> 起始,交由主代理终审。
  • 完成后汇报:顺利则只返回一句话说明已写入的文件名;遇阻断或不确定点(图片无法读取、内容严重残缺、规则无法判断)如实反馈主代理,不自行臆断、跳过或编造内容。
锚点规范(层级前缀式)

每遇到一个标题,插入一行注释,CH 后的数字表示层级:

<!-- CH1: 第二部 江湖 -->

<!-- CH2: 第1章 初入师门 -->

<!-- CH3: 第一节 拜师 -->
  • CH1 = 全书最高级标题:有部/卷则部/卷为 CH1、章为 CH2、节为 CH3;无部/卷的书,章直接为 CH1(保证顶级章节转成 h1,pandoc 才能按章切分,否则全书挤成单一文件)。
  • 标题文本只出现在锚点中,正文段落不重复标题。
  • 锚点为独立注释行,前后以空行与正文隔开;锚点之间是正文(段落,一个自然段 = 一行)。
  • 规则:遇到一个新标题就按其层级插入对应锚点;层级如实反映原书结构,不要主观合并或拆分。
内容保留 / 去除规则
内容处理
✅ 保留前言、后记作为正文保留(标题用锚点标注层级)
✅ 保留各章节章号/大标题插入锚点,作为分章依据
✅ 保留正文段落每段一行,段落间空行
❌ 去除页眉、页脚直接丢弃,不写入
❌ 去除插图(含示意图、照片)直接丢弃,不写入(本 skill 面向纯文字书籍)
❌ 去除版权页(整页版权声明)用 <!-- COPYRIGHT_CANDIDATE --> 标记,主代理终审
❌ 去除无关标识(二维码、条形码、水印、页码)直接丢弃
⚠️ 特殊原书目录页子代理照常识别正文,但主代理校对阶段会据此提取章节结构并整体丢弃(不进入最终 EPUB,避免与导航目录重复)

3. 批次标记检查:check-markers(CLI)

全部批次子代理完成后,用脚本逐个检查 raws/ 下的 batch_XXX.md:

python scripts/check_markers.py book/raws/*.md

脚本输出每个文件的标记清单与问题:

  • PAGE:列出全部页码;检查顺序递增、无缺号、无重复。
  • CH:列出全部 <!-- CHn: 标题 --> 及行号;检查层级是否跳级(作警告)。
  • __:列出全部行尾/行首 __ 及行号;检查跨页切口是否成对。

判定:无问题 → 通过;有问题(PAGE 缺失/乱序、__ 不成对)→ 单独重派该批次子代理,重跑后复检,直至通过;不重跑全书。若同一批次多次失败,可临时缩小该批次页数(如拆为 5 页)再试,或暂停交由用户处理。

4. 批次合并:merge-batches(CLI)

python scripts/merge_batches.py book/raws -o book/draft.md

按批次序号顺序合并所有 batch_XXX.md 为 draft.md:保留各批内的 PAGE/CH/__ 标记(供校对定位、跨批次 __ 切口衔接);合并时校验批次序号连续(1..K 无缺)。合并后规范化行距:任意两个相邻非空行之间恰好 1 个空行(跨页 __ 切口连接的行除外,保持切口两部分紧密相连),无连续空行堆积、无缺失空行。

5. 草稿标记复查:check-markers(CLI)

python scripts/check_markers.py book/draft.md

合并后对整本草稿复查一次标记:全书画页码连续(无跨批次缺页)、__ 切口在批次边界正确成对、CH 层级全本连续。复查通过后再进入校对。

6. 主代理校对:错别字修正 + 转标题(Agent)

这是 Agent 的灵活任务,不写脚本。基于 draft.md 执行:

  1. 分块通读:按批次分批通读 draft.md,每块在上下文内完整读完。页数多也不爆上下文。主要修正识别出来的错别字,不改变原文、不增删句子。
  2. 标记转换:
    • 删除 <!-- PAGE XXXX --> 页定位注释——空白页/无意义页仅含该注释,删除后自然无痕。
    • 去掉跨页行尾/行首的 __ 连接标记并把两部分合成为一段。
    • 将 <!-- CH1 --> / CH2 / CH3 / CH4 分别转为 # / ## / ### / #### Markdown 标题(以此类推);删除已无用的锚点注释与 COPYRIGHT_CANDIDATE 标记。
  3. 目录页处理:原书目录页仅用于核对章节标题与层级,核对完毕后从正文中移除。
  4. 版权页终审:逐个确认 COPYRIGHT_CANDIDATE 标记的页——确为版权声明则删除;误标(如书名页、献辞页)则保留为正文。
  5. 最终检查:全文无空锚点、无连续空行堆积、无未清除的页眉页脚特征、无 <!-- PAGE 残留、无 __ 残留;h 标题层级连续无跳级。此时产出 book.md,是干净的层级化 Markdown,h1=全书最高级标题(有部/卷则为部/卷,无则为章),h2、h3 依层级递减。

7. md-to-epub:分章与打包(CLI)

python scripts/md_to_epub.py book/book.md -o book/book.epub \
  --title "书名" --author "作者" --lang zh [--cover book/pages/page_0001.png]

脚本行为:

  • 切分:以 h1 为顶级章节切分正文;h2/h3 作为子级保留在章节内。
  • 导航目录:生成 EPUB 导航(NCX 与 nav.xhtml),目录条目与正文 h1/h2 标题一一对应(h3 及以下为章内层级,不进目录),支持点击跳转。
  • 封面(可选):--cover <图片> 指定封面图(PNG/JPG)。实际流程通常用拆页得到的 page_0001.png(原书封面页),也可由用户提供其他图片;pandoc 路径用 --epub-cover-image,ebooklib 路径用 EpubImage 设 cover-image 属性,两条路径均生成封面。
  • 打包:优先调用 pandoc(Markdown → EPUB);若 pandoc 缺失,回退用 ebooklib 手工组包(目录同样生成)。两种路径都保证阅读顺序与原书一致、已去除的内容不出现。
  • 输出 book.epub。

8. verify:校验(CLI)

python scripts/verify.py book/book.epub

脚本检查并完整打印校验报告到终端:

  • EPUB 结构合法:content.opf / manifest / spine 完整一致。
  • 导航目录存在,且每条目录条目在正文中都有对应标题(条目数 ≈ 正文 h1/h2 标题数;封面等非正文页除外)。
  • 目录锚点目标可解析(点击可跳转)。
  • 正文字段抽查:无 <!-- CH 锚点注释残留、无 COPYRIGHT_CANDIDATE、无 <!-- PAGE 页定位注释残留、无 __ 连接标记残留。

校验失败时脚本给出具体条目,修复后重跑 md-to-epub 与 verify 直至通过。

常见问题

  • 某批次识别失败 / 子代理超时:用 check-markers 检查确认问题,单独重跑该批次子代理(batch_XXX),不重跑全书。
  • 正文出现公式/表格(罕见):本 skill 面向纯文字书籍(如小说),子代理不使用结构标记;若某页含公式表格等非常规内容,如实转录为文字段落,主代理校对时人工核对。
  • 某本书需要保留插图:偏离通用默认,需用户单独确认,并放弃"去除插图"规则。

コメント