手寫字 → PDF
從手寫樣本建立真實的 .ttf 字型,再用該字型將文字渲染成看起來像書寫者自己手寫的 PDF。所有處理都在本機執行,樣本絕不會離開你的機器。
**需要事先告訴使用者的殘酷事實:**這不是一個能從一張照片虛構出 3000 個中文字元的 AI。字型只能包含樣本中實際寫過的字元。所以:拉丁文字需要約 60–100 個書寫字元;中文字則需要文件中每個不同的字元(幾百個是常態,數千個則不切實際)。缺少的字元會以中性的手寫備用字型繪製並回報,絕不會無聲無息地虛構。
0. 找到工具
技能目錄就是包含這個 SKILL.md 的資料夾。透過其啟動器來呼叫 CLI:
- Windows:
<skill>\bin\hwpdf.cmd <command> ... - macOS/Linux:
<skill>/bin/hwpdf <command> ...
如果啟動器遺失,請先安裝(Windows 上執行 <skill>\install.ps1,其他平台執行 <skill>/install.sh),或者當相依套件已經可用時,直接執行 python <skill>/scripts/hwpdf.py <command> ...。hwpdf doctor 必須在執行任何其他指令前顯示 status ok;如果沒有,請執行安裝程式並回報相依性錯誤,不要自行即興處理。
1. 選擇輸入流程
| 情境 | 流程 |
|---|---|
| 預設:使用者想要一份使用他們自己手寫的真實文件 | A. 練習表(最佳品質,全自動的單元格對應) |
| 使用者給你一份已顯示其手寫的 PDF | D. PDF 輸入 — 先嘗試內嵌字型,否則從文字圖層收穫字形 |
| 使用者已經寄來一張手寫照片,且不想再寫更多 | B. 自由形式照片(代理需要標記裁剪出的字形) |
使用者已經有自己的 .ttf/.otf 字型 | C. 僅字型 — 跳到步驟 4,然後儲存設定檔 |
在產生任何東西之前,先詢問文件文字:練習表只需要文件中用到的字元,所以文字簡短,練習表也會簡短。
流程 A — 練習表(推薦)
- 將目標文字放入一個 UTF-8 檔案中,例如
hw/doc.txt,然後:
hwpdf template --text-file hw/doc.txt -d hw
這會寫出 hw/template.pdf(以及 hw/template.json)。每頁 30 個單元格,每 30 個不同的字元一張紙。精確地告訴使用者以下事項:
- 以 100% / 實際大小 列印(絕不「縮放至頁面」);
- 使用深色筆(0.5 公釐或更粗)描繪每一個淺灰色字形——原子筆太淡了;
- 保持四個黑色角落方塊可見且未做記號;
- 從上方以均勻光線拍攝每頁照片,填滿畫面,然後寄送檔案。
- 按頁面順序掃描照片:
hwpdf scan hw/page1.jpg hw/page2.jpg -d hw
透視和輕微的旋轉會從角落方塊進行校正。輸出 hw/glyphs.json 和 hw/glyphs/*.png。如果某個單元格回報「缺失」,表示該字形未被書寫或太模糊——請告知是哪個字元,並提供僅針對這些單元格重新拍攝的選項。
3. 建構字型:
hwpdf font -d hw --family "Alex Hand" -o hw/font.ttf
- 在進行渲染前,先檢查涵蓋範圍:
hwpdf coverage --font hw/font.ttf --text-file hw/doc.txt
非零的退出碼或有 missing 列表,表示那些字元沒有對應的字形。解決方法:僅為這些字元寫一張小練習表,然後合併進來:
hwpdf template --chars "<missing chars>" -d hw2
hwpdf scan hw2/page1.jpg -d hw --append
hwpdf font -d hw -o hw/font.ttf
否則,接受中性的備用字型,並明確地告知使用者。 5. 渲染:
hwpdf render --font hw/font.ttf --text-file hw/doc.txt -o hw/letter.pdf --size 12 --paper ruled
- **查看結果。**將 PDF 頁面渲染為 PNG,並使用視覺能力檢查:
hwpdf preview --pdf hw/letter.pdf -d hw/preview --dpi 150
判斷:筆劃是否太細/太粗?行距是否太擠?字元是否互相碰撞或超出邊界?外觀是否有明顯錯誤?使用 --size、--leading、--jitter、--weight(重建字型)、--paper none|ruled|grid 來修正。
流程 D — 使用者給你一份有手寫的 PDF
當此流程有效時,這是最快的途徑,因為 PDF 已經包含了字形。
- 嘗試內嵌字型程式(最佳:完整的字形集,無需重新描繪):
hwpdf extract-font --pdf user.pdf -d hw
好的輸出 = hw/fonts/ 目錄下有一個具有真實字元對應的 .ttf/.otf 檔案(mapped > 20)。
如果報告顯示「subset/cid」,請跳過此步驟。
2. 否則,如果 PDF 有文字圖層(當你可以選取字元時就表示有),從渲染的頁面中收穫字形——文字圖層提供標籤,點陣圖提供墨跡:
hwpdf pdf-specimen --pdf user.pdf -d hw # 加上 --font-name "<family>" 以只保留他們使用的字型
hwpdf font -d hw --family "Alex Hand" -o hw/font.ttf
- 否則就是掃描檔:
hwpdf rasterize --pdf user.pdf -d hw/pages→ 對頁面影像進行流程 B,或者要求一份練習表(流程 A)。 - 將結果儲存為設定檔(下面的步驟 5),然後渲染。
流程 B — 自由形式照片
hwpdf segment hw/photo.jpg -d hw→hw/contact.png(帶編號的縮圖)+hw/crops/。- 打開
hw/contact.png並讀取編號。將hw/labels.json寫成{"0":"A","1":"b",...},或者使用hwpdf label -d hw --pair "0=A 1=B 2=''"(""表示丟棄該區塊:例如點、污漬、頁面邊緣,或一個分成兩筆畫書寫的字元片段)。 hwpdf font -d hw --labels hw/labels.json -o hw/font.ttf,然後進行上面的步驟 4–6。
連筆草書和多筆畫的中日韓字元使得此流程容易出錯;如果結果看起來不好,請轉換到流程 A 並說明原因。
流程 C — 使用者已有字型
直接跳到 hwpdf coverage 和 hwpdf render,使用 --font <their file>,然後儲存設定檔。
設定檔 — 穩定、可重複使用的方式
設定檔凍結了重現外觀所需的一切:字型檔(複製到設定檔中,並附上 SHA-256 雜湊值)、其預設值,以及一個可直接貼上的提示。
hwpdf profile save --name alex --font hw/font.ttf --source "user's handwriting pdf"
hwpdf profile list
hwpdf render --profile alex --text-file letter.txt -o letter.pdf
- 設定檔存放在
~/.handwriting-pdf/profiles/<name>/目錄下(包含profile.json、font.ttf、PROMPT.md);設定HWPDF_PROFILE_DIR環境變數可重新定位。 PROMPT.md是為使用者撰寫的:將其貼到任何機器上的任何代理,它就會以相同的版面預設值呼叫相同的字型。- 需要反覆調整外觀?一次只改變一個東西——渲染、預覽、比較,然後執行
hwpdf profile save --name alex --font hw/font.ttf --size ... --paper ...將其設為新的預設值。font --weight 1會重建一個更粗的筆劃;之後記得重新儲存設定檔,讓變更生效。 - 從 PDF 建立的設定檔只涵蓋該 PDF 中出現的字元。在承諾能產出完整文件之前,先用
hwpdf coverage --font <profile font> --text-file <new doc>檢查。
合成 — 使用者從未書寫的字元(實驗性)
一份文件幾乎總是會包含使用者從未寫過的字元;在中文裡這是常態而非例外。有兩種填補方式,按誠實程度排序:
- 中性備用字型(預設,可預測):
render --fallback auto會自動選取一個系統手寫字型;頁面會混合使用者的手寫樣式與印刷體或中性的手寫樣式,並且render會報告每一個以此種方式繪製的字元。 - 合成推斷(
hwpdf synth,仍為實驗性):透過借用使用者風格中可測量的部分——傾斜度、筆劃粗細、x 高度、字元寬度——並將這些風格貼到系統骨架字形上,建立一個涵蓋完整字元集的第二個字型。
hwpdf synth doctor # 顯示哪些引擎可用,缺了什麼
hwpdf synth build --style hw/font.ttf --charset common3500 -o hw/synth.ttf
hwpdf synth specimen --font hw/synth.ttf --real hw/font.ttf -o hw/sheet.png # 先檢查
hwpdf synth verify --font hw/synth.ttf --charset common3500 # 涵蓋範圍/缺失
hwpdf synth eval --font hw/synth.ttf --real hw/font.ttf -o hw/report.md # 報告的數值
hwpdf profile save --name alex --font hw/font.ttf --synth-font hw/synth.ttf
hwpdf render --profile alex --text-file doc.txt -o out.pdf # 合成字型填補缺口
引擎:stylefit(分析型 — 無需下載、無需 GPU、確定性;中文字元保留系統無襯線骨架,僅擷取使用者的傾斜度和粗細)和 stub(測試用固定裝置,非風格轉換)。擴散引擎 diff-font 需要的權重檔案其授權尚未解決(請見 PLAN.md §8 S4)—— synth doctor 會如實告知,不會假裝可用。
**說明它是什麼:**使用者寫過的字元會被原樣重現;推斷出來的字元則是「他們的傾斜度和粗細,套用於印刷體骨架上」。不要告訴使用者推斷出來的那一半「看起來像他們」。在出貨前,請檢查 <font>.json 中的 meta.gate(rejected 應為 0)並查看樣本。
規則
- **僅限本機。**絕不將樣本、字型或輸出檔案上傳;不進行任何 API 呼叫。
- **僅限使用者自己的手寫。**拒絕模仿第三方的筆跡、簽名或信紙標頭,並且拒絕產生簽名、合約、證書或官方文件——簡短說明原因(偽造、詐欺、證據規則),並提供一份正常的打字文件作為替代方案。
- **絕不捏造品質。**如果字型只有 40 個字形,就說 40。如果備用字型繪製了半頁文字,就據實以告。逐字報告缺少的字元。
- **在責怪工具之前,先要求重新拍攝:**模糊、有陰影、角落被裁剪或網格線被遮蓋的照片是最常見的失敗原因。
- 保留工作目錄(
hw/)——使用者之後可以增加字元並重建字型。
指令參考
| 指令 | 用途 |
|---|---|
hwpdf doctor | 相依性 + 系統字型檢查 |
hwpdf template --chars "abc" / --text-file doc.txt -d DIR | 練習表 PDF + 元資料 |
hwpdf scan IMG... [-d DIR] [--rotate 90] [--append] | 拍攝的練習表照片 → 字形遮罩(append = 合併到現有工作區) |
hwpdf extract-font --pdf in.pdf -d DIR | 從 PDF 提取內嵌字型(最佳情況:完整的 TTF) |
hwpdf pdf-specimen --pdf in.pdf -d DIR [--font-name F] | 從 PDF 的文字圖層 + 點陣圖收穫已標記的字形 |
hwpdf rasterize --pdf in.pdf -d DIR [--dpi 300] | 掃描的 PDF → 頁面 PNG |
hwpdf segment IMG... [-d DIR] [--thresh N] [--deskew] | 自由形式照片 → 區塊 + 連絡表 |
hwpdf label -d DIR --order "ABC" / --pair "0=A 1=B" | 將區塊對應到字元 |
hwpdf font -d DIR [--labels f] [--family NAME] [--weight -2..2] [--smooth 0..2] -o out.ttf | 建構字型 |
hwpdf coverage --font f --text-file doc.txt | 檢查哪些字元缺少 |
hwpdf render --font f --text-file doc.txt -o out.pdf [--size 12] [--leading 1.8] [--paper ruled] [--jitter 1] [--ink "#1a1c24"] [--fallback auto|none|path] | PDF(--font system:cjk / system:latin = 內建手寫字型,用於當使用者沒有樣本,且只想要一個手寫外觀時) |
hwpdf render --profile NAME --text-file doc.txt -o out.pdf | 使用已儲存設定檔的字型 + 預設值產生 PDF |
hwpdf profile save/list/show/remove ... | 凍結/檢查可重複使用的手寫設定檔(會寫出 PROMPT.md) |
hwpdf preview --pdf out.pdf -d DIR [--dpi 150] | PDF 頁面 → PNG 供視覺檢查 |
hwpdf synth doctor / build / specimen / verify / charsets | 可選的推斷引擎:從書寫子集建立完整字元集字型(請見合成章節) |
hwpdf selftest -d DIR [--messy] | 合成端對端冒煙測試 |
限制(在相關時說明)
- 每個字元只有一個字形:沒有連筆草書,沒有不同出現次數之間的自然變化,沒有壓力/墨跡紋理。間距抖動是模擬的,字形形狀則不是。
- 中日韓字元:字型僅包含書寫過的字元。每頁 30 個單元格;一封 300 字的信需要一份 10 頁的練習表。
hwpdf synth build --charset common3500是捷徑,但推斷出來的中日韓字元是使用者的傾斜度加上系統無襯線骨架,而非他們實際的筆觸。 - PDF 的文字圖層是真實文字(可搜尋/可複製),使用產生的字型。
- 照片必須顯示練習表的全部四個黑色角落方塊。