扫描版PDF清洁器
用手机拍摄的打开书籍照片,在书脊附近会出现弯曲、倾斜、发灰,边缘还有拇指印和下一页的碎片。此技能可将它们转换为如同干净印刷品般可读的页面。
脚本负责像素处理,而您负责判断:您需要追踪每页的角落,查看被移除的内容,并决定文本外部的标记是印刷体(保留)还是非印刷体(移除)。每一步都会生成可读的接触印片,请务必查看,不要假设步骤已完美执行。
设置(每台机器只需一次)
SKILL=<此技能所在文件夹> # 存放此 SKILL.md 的文件夹
python3 -m venv ~/.cache/scanned-pdf-cleaner-venv
~/.cache/scanned-pdf-cleaner-venv/bin/pip install -q -r "$SKILL/requirements.txt"
PY=~/.cache/scanned-pdf-cleaner-venv/bin/python
以下所有命令均以 cd "$SKILL/scripts" && $PY <脚本> ... 的形式运行。每个文档使用一个新的、空的工作文件夹,位于用户项目之外(例如临时文件夹)。用户的文件仅被读取。
工作流程
1. 准备
$PY prepare.py INPUT.pdf WORK # 或者:图片文件夹,或图片文件(HEIC:请先转换)
生成 WORK/src/p-NNN.jpg(竖立照片)、WORK/grid/g-NNN.jpg(每张照片上叠加每100像素的红色网格,四边标有百位数字)以及 WORK/rough.json(包含每张照片的占位轮廓)。
如果照片侧向或倒置,请旋转:$PY prepare.py --turn WORK p-003.jpg 90|180|270(顺时针)。
2. 追踪页面角落(由您完成)
阅读每张网格图像。为每张照片找到属于文档的页面。将其四个角点写入 WORK/rough.json,使用源像素坐标,按页面阅读顺序排序:左上、右上、右下、左下。对于横向标签7、纵向标签12的点,写为 [700, 1200]。
{"001": {"src": "p-000.jpg", "quad": [[96,72],[930,92],[945,1468],[70,1480]]}}
- 键是输出页面顺序(
001,002, ...)。保持该顺序与阅读顺序一致。 - 取页面的纸张边缘,而非文本。靠近书脊处,取页面弯曲进入装订线的线条。如果页面超出照片范围,则角点放在照片边缘上。
- 双页跨页照片给出两个具有相同
src的条目,每页一个,例如"005"和"006"。 - 精度在约30像素内即可。下一步会自动吸附到真实边缘。
3. 吸附到纸张边缘
$PY refine.py WORK
生成 WORK/quads.json 和 WORK/sheets/quads-NN.jpg:橙色 = 您的追踪,红色 = 吸附后,绿色圆点 = 左上角。阅读这些印片。如果红色轮廓跳到了阴影、桌面或邻页上,请修正该追踪并重新运行此步骤。
4. 展平、调色并清洁边缘
$PY clean.py WORK # 或者:clean.py WORK 004 007 来重做某些页面
对于每一页,此步骤:
- 查找文本行和已对齐的列边缘;
- 将文本块方正,并为每一行拟合一个平滑弯曲表面,使弯曲的行变直;
- 将纸张调为白色,墨迹调为黑色;
- 移除接触页面边缘的暗色标记:手指、书脊卷曲、折痕和邻页碎片。
对于少于5行文本的页面(如标题页和全页图),改用简单的四角扭曲。输出:WORK/pages/、WORK/blocks.json 和 WORK/sheets/review-NN.jpg,其中红色 = 已移除,蓝色 = 留给您决定,绿色 = 文本块。
阅读审查印片。需要检查的事项:
- 行仍然弯曲或页面倾斜:追踪有误。修正
rough.json,然后为该页面重新运行 refine 和 clean。 - 绿色框内的文本显示为红色:告知用户。边缘清洁从不移除文本框内的文本,除非文本位于页面边缘带上。
5. 列出文本外部的标记
$PY flags.py WORK
生成 WORK/flags/flags-N.jpg:文本块外每个暗色标记的编号图块。
6. 决定保留或移除(由您完成)
阅读标记印片,并编写 WORK/decisions.json:
{"keep": [0, 3, 4, 7], "strokes_only": [23], "erase": [{"page": "014", "box": [1500, 300, 80, 900], "mode": "strokes"}]}
- keep:所有印刷内容。包括页码、页眉、章节编号、图注、侧边标签、表格线、插图和绘图。印刷体的文字清晰规则。书籍中的绘图也属于印刷内容,即使是涂鸦式的儿童画。
- remove:不将其编号列出。包括手写、钢笔和铅笔笔记、污渍、斑点、指纹、灰色条和撕裂边缘阴影。钢笔线条细、不均匀且常倾斜,与字体不匹配。
- strokes_only:带有穿过或划过印刷字母的笔画。仅移除高于1.5行的笔画。
- erase:在
pages/page-KEY.jpg上以页面像素为单位指定方框,用于处理文本框内您被要求移除的标记。"mode": "all"将方框变白;"strokes"仅移除高笔画。
在移除用户可能想要保留的内容前请询问用户。这包括文本内部的钢笔下划线和行间注释,以及荧光笔。默认:移除页边注释,保留文本内的下划线。当您无法区分印刷体和手写时也请询问。展示图块,不要描述它。
7. 完成
$PY finish.py WORK OUT.pdf # --no-frame 保留每页自身的边框;--dpi 默认为 300
功能:
- 将文本块外的所有内容变白,但保留的项目除外。
- 移除紧贴文本块两侧的细长钢笔括号。
- 将所有页面统一到一种页面尺寸:
- 文本大小一致:近拍或远拍的照片匹配。缩放使用文本块的宽度,或者当图形缩窄列时使用行距。
- 左右边距相等,因此原来靠一边的内容或因书籍厚度偏移的内容居中。
- 每页顶部边距相同。
请阅读 WORK/sheets/final-NN.jpg 后交付。检查每页是否有残留污渍、被裁切的文本以及误保留的内容。然后向用户提供PDF路径。将PDF保存在输入文件旁边(例如 <名称>_clean.pdf),除非用户另有说明。
理想效果
- 文本行从头到尾笔直且水平,包括靠近书脊的那一行。
- 纸张纯白,墨迹纯黑,细笔画保持完整。大面积的暗色绘图保留其填充。
- 没有手指、阴影、邻页碎片或斑点。左右边距相等,每页文本大小一致。
实际使用中的注意事项
- 修正器通过阅读文本工作,因此对于充满对齐行的页面效果最佳。它适用于任何文字系统,包括从右至左(希伯来语、阿拉伯语),因为它仅查看行的形状。
- 图形内的短行(标注)在拟合弯曲时会被忽略,因此图形不会导致页面折叠。
- 大面积暗色绘图如果使用简单调色会被洗成灰色。
tone()会利用周围纸张信息保持纸张估算值。 - 当页面的卷曲吞没了书脊附近的几个字母时,照片中已无信息可恢复。请如实告知,不要虚构文本。
- 双栏论文:文本块跨越两栏。检查审查印片,确认跨栏区域的线条拟合正确。