照片转 PDF
目标——按正确顺序排列的独立页面、紧凑的边界以及保留边缘的笔触。在本地处理照片。此流程不需要专用插件或 MCP。
经过验证的方法
- 检查原始素材。 留意 EXIF 信息。按文件名/时间和内容检查顺序;拍摄时间本身并不能证明顺序。找到封面、跨页、重复拍摄的副本、空白页。亮度不足以可靠区分淡色图纸和空白页。如果纸张放在浅色背景上(白色桌子、纸张、旁边的屏幕)且无法找到轮廓,请要求重新在深色哑光表面上拍摄。
- 标记页面。 对于单页(文档、A4,包括横向),运行
prepare --layout pages。auto仅在存在折痕迹象(书脊阴影或折痕线)时分割宽轮廓,但在不常见的页面上可能会出错。scan.py prepare创建草稿清单和带轮廓的联系图。检测器将纸张识别为浅色低饱和度区域,将边缘吸引到“纸张→深色背景”的锐利过渡处,并为跨页寻找折痕。折痕是行线断裂的地方。书脊阴影位于一个页面上,因此对于深阴影,折痕设置在亮度变化深色侧的底部。在标准笔记本上,折痕的中值误差为 2–3 像素。这仍然是一个假设。带有非空flags(gutter-*、partner-mismatch、touches-frame、aspect-outlier、one-side-unruled、margin-ink、contour、full-frame-fallback、duplicate)的页面应优先手动标记。其余页面通过照片检查:检测器可能会误将显示器、收据或跨页的一半当作页面。scan.py inspect提供每个角落的大尺寸裁剪图,并带有以帧为单位的刻度线——根据这些在清单中修正角落。每个页面获得自己的四个角 TL、TR、BR、BL,坐标在 EXIF 旋转之后。 - 校正透视。 默认情况下,每个页面使用一个投影矩阵。不要根据自动检测到的边缘移动单独的行/列:网格、文本、手指和阴影可能被误认为边缘,并导致整个页面出现波纹。对于明确要求的完整弯曲书页展平,需要单独的经过验证的算法和额外的几何检查。
- 调整边界。 首选紧密裁剪,而不是统一的大边距。
bleed_px默认为 0。仅在角落之间的直线确实包含笔记或带有信息的弯曲边缘时,才单独添加少量边距。检查字母顶部、ё/й 上的点、左侧的日期、折痕处的文本以及图纸的底线。底线通常一直延伸到边缘——那里的边界基于边缘的中值,而不是紧密的。如果紧密边缘和纸张边缘之间存在笔划,prepare会将边缘自动移动到它们(margin_ink字段,不超过宽度的 4%)。铅笔笔划不受此保护,因此应目视检查边缘处的铅笔日期和签名。弯曲的边缘近似为直线,因此弯曲页面的角落可能会略微超出边界。使用crop命令对 PDF 进行额外裁剪,无需重新拉伸和 JPEG 重新压缩。 - 保留淡色笔触。 允许进行柔和的照明校正;强二值化可能会擦除铅笔笔迹。对于封面、照片和重要颜色,请禁用
enhance。不要使用生成模型重新绘制字母、图表或缺失的画面部分。仅在需要或要求时添加 OCR。 - 检查最终 PDF。 使用可用的 PDF 技能创建/检查,包括其预定义的操作标记。
review渲染所有页面,生成联系图,并列出带有背景或边缘笔迹的页面(edges.json)。compare显示来自照片的每个页面,带有 4% 的边距和红色的裁剪框——可以轻松看到哪些内容留在了外面。浏览整个文档,而不仅仅是首页。大量页面的经济方案:对所有页面运行compare,将它们分成不超过 16 个批处理,分配给并行的使用廉价图像模型的 Agent(在 Claude Code 中为 Sonnet,在 Codex 中为gpt-5.6-luna),任务来自 references/screening.md 且不做修改。您只需亲自查看检查者标记为defect的页面以及prepare标记了标志的页面;仅修正已确认的错误。在一个包含 32 页的草稿中,有 8 个已知的角误差 > 3%,该方案成功找到了所有 8 个(Sonnet 找到 7 个,标志找到了剩下的 1 个),并伴有 4 个误报;Haiku 找到了 4 个并增加了误报,因此仅使用 Haiku 是不够的。在第二个笔记本(32 页,任务未调整)上,Sonnet 和gpt-5.6-luna找到了可见的背景条纹且没有误报,但漏掉了角误差为 1.5–2% 的页面;gpt-6.1-terra标记了几乎所有内容,包括 19 个干净页面中的 12 个——使用它没有节省成本。该方案已在一个笔记本上测试,任务是根据相同的页面编写的:对于重要文档或存在疑虑时,请亲自查看所有页面。检查者答案中的页码同时验证了顺序。裁剪后,重新检查受影响的页面;更改几何算法后,重新检查整个文档。页面数和正确的配置不能取代实际查看。
对于此类数字化,用户倾向于删除已确认的空白页;明确要求保留的优先级更高。在目视检查后排除重复项,而不是基于网格/笔迹的相似性。除非另有说明,否则保留封面。跨页从左到右阅读,当源文档如此排列时。
命令
根据此技能确定脚本路径。模式和参数:references/commands.md。不要从上个笔记本转移角度、路径、页码和比例。
python3 <skill>/scripts/scan.py prepare <photos> --work <work> --layout auto
python3 <skill>/scripts/scan.py inspect <work>/manifest.json --work <work>/inspect --ids 0006-L,0006-R
python3 <skill>/scripts/scan.py build <work>/manifest.json --output <work>/draft.pdf
python3 <skill>/scripts/scan.py measure <work>/draft-pages --work <work>/measure
python3 <skill>/scripts/scan.py review <work>/draft.pdf --work <work>/review
python3 <skill>/scripts/scan.py compare <work>/draft.scan.json --work <work>/compare
依赖项:照片处理需要 Pillow、NumPy、OpenCV、ReportLab;crop 需要 pypdfium2;基于 PDF 的 review 和 measure 需要 Poppler pdftoppm。导入按命令分离。检查可用的解释器/预配置环境;必要时使用单独的 venv,不要更改全局 Python。如果 OpenCV/NumPy 是系统包,则在相同的解释器上使用 --system-site-packages 创建 venv(python3 -m venv; uv venv 默认使用自己的 Python 且不会看到系统 cv2)。网络不是必需的。不要将特定机器的缓存路径嵌入到技能中。
比例和页面尺寸。 aspect: null 根据轮廓边估计,并且透视角度下可能会有 1-2% 的偏差。对于方格纸,收集草稿并运行 measure。它会找到网格间距,计算页面的物理尺寸,并为整个笔记本提出一个 aspect 和 --width-mm。使用输出中的值,而不是上一个笔记本的值。使用相同的 --width-mm,所有 PDF 页面将具有相同的物理尺寸。否则,尺寸根据像素和 --dpi 计算,并随拍摄距离变化。
build 要求包含的页面具有 reviewed: true:这是 Agent 对标记进行检查的标记,而不是需要用户额外批准。不要询问用户对已传照片的常规处理权限。
检测器回归。 已验证的笔记本清单是基准。在更改 scan.py 后,对相同的照片运行 prepare 和 eval <新 manifest> --reference <基准>。该命令将显示页面宽度百分比形式的角误差、标记页面的比例以及“静默”错误——未标记且误差大于 --tolerance(默认 3%)的页面。如果静默错误数超过 --max-silent,返回代码为 1。不要将包含个人照片的基准放入技能仓库。
完成
- 不要修改原始照片。在验证新版本后替换现有的 PDF。保存标记和参数以便进行定点修正。
- 再次编辑时,首先检查文件是否是最新的。避免累积的 JPEG 重新压缩。
- 报告结果、页数和重要的原始素材限制。如果部分笔记已在画面之外,请说明这一点,而不是声称已恢复。
- 该技能节省了准备和重复编写代码的时间;它不承诺完全自动的边界识别或取消视觉检查。