照片轉 PDF
目標是產生順序正確、邊界緊密且保留邊緣筆觸的單獨頁面。在本地處理照片。此流程不需要特殊外掛或 MCP。
經過驗證的方法
- 檢查原始檔案。 考量 EXIF 資訊。根據檔案名稱/時間和內容檢查順序;拍攝時間本身無法證明連續性。找出封面、跨頁、重複拍攝的副本、空白頁。亮度無法可靠區分淡色圖稿與空白頁。如果紙張放在淺色背景(白色桌子、紙張、旁邊的螢幕)上且輪廓無法找到,請要求重新在深色霧面表面上拍攝。
- 標記頁面。 對於單頁(文件、A4,包含橫向),執行
prepare --layout pages。auto僅在出現摺痕跡象(書脊陰影或摺線)時分割寬輪廓,但在非標準頁面上可能會出錯。scan.py prepare會建立草稿 manifest 和附有輪廓的聯絡頁。偵測器將紙張視為淺色低飽和度區域,將邊緣吸引到「紙張 → 深色背景」的銳利過渡處,並為跨頁尋找摺痕。摺痕是格線斷裂的地方。書脊陰影位於同一頁上,因此對於深陰影,摺痕設置在亮度落差深色側的基部。在標準筆記本上,摺痕中位數誤差為 2–3 像素。這仍然是假設。帶有非空flags(gutter-*、partner-mismatch、touches-frame、aspect-outlier、one-side-unruled、margin-ink、contour、full-frame-fallback、duplicate)的頁面應優先手動標記。其餘頁面透過照片檢查:偵測器可能會誤取顯示器、收據或跨頁的一半。scan.py inspect提供每個角落的大尺寸裁切區域,並帶有畫面比例刻度 — 據此在 manifest 中修正角落。每個頁面都有自己的四個角 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 頁一批給使用廉價圖像模型的平行代理(在 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 頁無瑕疵頁面 — 使用它沒有節省成本。該方案僅在一本筆記本上驗證過,任務是根據相同的頁面編寫的:對於重要文件或有疑問時,請親自查看所有頁面。檢查員回應中的頁碼同時也用於驗證順序。裁切後重新檢查受影響的頁面;更改幾何演算法後重新檢查整個文件。頁面數和正確的 config 不能替代視覺檢查。
對於此類數位化,使用者傾向於刪除經確認的空白頁面;明確要求保留則優先。重複頁面在視覺檢查後排除,而非根據網格/筆跡相似度。除非另有指示,否則保留封面。橫向閱讀跨頁時從左到右,當原始資料如此排列時。
命令
腳本路徑相對於此技能定義。Schema 和參數: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(用於照片);pypdfium2(用於 crop);Poppler pdftoppm(用於 review 和 measure PDF)。匯入按命令分離。檢查可用的直譯器/預建環境;必要時使用單獨的 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:這是代理對標記進行檢查的標記,而非需要與使用者額外協商。不要為已傳送照片的常規處理請求許可。
偵測器回歸。 經過驗證的筆記本 manifest 是基準。在更改 scan.py 後,對同一組照片執行 prepare 和 eval <new manifest> --reference <基準>。該命令將顯示以頁面寬度百分比表示的角落誤差、標記頁面的比例以及「靜默」錯誤 — 未標記但誤差大於 --tolerance(預設 3%)的頁面。如果靜默錯誤多於 --max-silent,則返回碼為 1。不要將包含個人照片的基準放入技能儲存庫。
完成
- 不要修改原始照片。在驗證新版本後取代現有 PDF。保留標記和參數以進行局部修正。
- 重新修正時,首先檢查檔案是否為最新。避免累積的 JPEG 重新壓縮。
- 報告結果、頁面數量和原始檔案的重要限制。如果部分筆記已在畫面外,請說明這一點,而非聲稱已還原。
- 此技能節省了準備和重新撰寫程式碼的時間;它不承諾完全自動化的邊界辨識或免除視覺檢查。