feat: 從找圖開始優化——高解析度官方設定稿 → 去背 → 合成為形象圖

1. 找圖(icon search)
   從 Fandom API 撈角色頁的所有圖片,依「解析度 + 是不是官方設定稿」排序。
   官方設定稿(Full Body / Character Design / Avatar)是最好的來源:
     * 773×1056 起跳,遠勝角色資料庫的 230px 縮圖
     * **多半本來就是透明底 PNG**,去背幾乎免費、邊緣完美
   新增 icon measure:回報解析度、臉佔比、背景是透明/單色/有場景、去背難度。

2. 去背(icon cutout)→ icon/portrait-cutout.png
   三條路徑自動選:
     source-alpha       原圖已是透明底(官方設定稿常見)→ 完美
     plain-background   純白/單色底,色距去背 + 最大連通區 + 補洞 → 很好
     grabcut            有場景時用臉的位置當前景種子 → 普通
   實測記錄:把臉從 2026 主視覺裁下來再 GrabCut,結衣的黑髮會被整片當成背景切掉;
   換成官方設定稿之後這問題直接消失——所以「找對圖」比「去背演算法」更關鍵。

3. 合成(icon generate --from-cutout)
   自動裁成頭肩構圖再疊到角色配色的漸層底上。官方設定稿常是正反兩面並排,
   不裁會變成兩個人,所以 compose 預設 --crop head(--zoom 可調鬆緊)。
   產出 icon.svg(內嵌同一張 PNG,自成一體不外連)、icon.png,
   以及 icon/portrait.svg 與 512/1024 兩個解析度。

   向量重繪(--features)保留為「找不到可用官方圖」時的退路。

已更新兩個真實人格(皆為 cutout 樣式,Wiki 同步已驗證):
   ASUNA-01  Asuna's SAO Avatar Full Body(773×1056,透明底)— 對應 2026
             《Unanswered//butterfly》重述的早期艾恩葛朗特
   YUI-01    Yui's ALO Pixie Form Full Body(773×1056,透明底)— 現行 Unital Ring
             章的導航妖精形態

順手修掉兩個 bug:
   * 合成路徑下 svg 為 null,回傳時 Buffer.byteLength(null) 直接崩潰。
   * verifyArea 解析 git status --porcelain 時,因為 git() 會 trim 輸出,
     開頭空白已消失(" M x" → "M x"),正規式對不上,檔名前面多一個 M。

selftest 175 項全綠(新增第 ⑲ 節:找圖評分、去背三路徑、compose 預設裁頭肩、
去背圖在 icon/ 會同步、SVG 不外連、沒有去背圖時 --from-cutout 會擋下)。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-30 03:43:45 +00:00
co-authored by Claude Opus 5
parent cd1f4754ab
commit 929ccb3c05
11 changed files with 613 additions and 217 deletions
+12 -17
View File
@@ -26,7 +26,7 @@ skills 是共通標準,**鎖與隔離的強制執行需要 hook,目前只有
| **9. 人格可以匯出匯入** | `export` 把身分/情緒/記憶/心智圖/關係圖打包成單一 JSON bundle(可 `--gzip`、附 sha256),`import` 還原或換名複製;**不帶**載入鎖與 guest 租約,`journal/` 要明確 `--with-journal` 才帶走 |
| **10. 人格有編號** | 編號 = **英文名全大寫 + 兩位索引**(同名才遞增):`ASUNA-01``YUI-01``ASUNA-02`。編號同時是新人格的本機目錄名與 Gitea 存取庫名稱;中文名先轉羅馬拼音並跟使用者確認拼法 |
| **11. 人格存在 Gitea,依更新頻率分區** | 每個人格一個**私有存取庫**(庫名=編號)。**檔案區**放每輪都在變的活狀態(情緒/短期記憶/心裡話/說過的話/逐字),**Wiki 區**放低頻的身分與長期結構(IDENTITY/SOUL/長期記憶/心智圖/關係圖)當設定百科。本機仍是工作副本,同步失敗不阻斷對話 |
| **12. 圖示是重新繪製的人物形象圖(有臉)** | 上網找出該人格**最新一次登場**的官方視覺 → 裁出**大頭照當底稿** → **親眼看過** → 讀出髮型/瀏海/眼型/表情/髮飾等特徵 → **由本工具依人格資料重新繪製**。**絕不把找到的圖片當圖示**:SVG 裡沒有 `<image>`、沒有 base64、沒有外連,底稿只留在 `.sync/` 不同步。來源網址與重繪依據存進 `config.json` 備查 |
| **12. 形象圖來自高解析度官方圖,去背後合成** | `icon search` 從 Fandom 撈官方圖並依「解析度+是否官方設定稿」排序(設定稿多為透明/白底、773×1056 起跳)→ `icon measure` 確認臉夠大、背景好去 → `icon cutout` 去背成透明 PNG(原生 alpha /單色底/GrabCut 三條路徑)→ `icon generate --from-cutout` 裁頭肩、合成到角色配色的漸層底。找不到官方圖才退回依人格資料重繪的向量形象 |
| **13. Wiki 必須保存並同步形象圖** | `icon.svg``icon.png`**`icon/` 資料夾(向量原稿 + 512/1024 高解析度)** 都同步到 Wiki 區,另有自動產生的 **Icon** 頁展示與來源。Wiki 頁面一律用 **Markdown 圖片語法**Gitea 只改寫這種語法為 `/wiki/raw/...`HTML `<img>` 會變成破圖),圖片保留資料夾結構、只有 `.md` 需要攤平。`icon generate` 推完會回頭驗證,另有 `sync verify` |
---
@@ -150,29 +150,24 @@ AI 最容易露餡的三件事:把推理過程講出來、一次講一大段
建立人格**並補齊 IDENTITYSOUL 之後**產生,512×512。**優先是人物形象圖(看得到臉)**,
依環境有無工具分三種樣式:
流程**找圖 → 裁大頭照當底稿 → 親眼看過 → 讀出特徵 → 重新繪製**
流程**找官方圖 → 量測 → 去背 → 裁頭肩 → 合成**
| 步驟 | 指令 | 產出 |
| --- | --- | --- |
| 1. 找 | `icon faces --photo <圖>` | 圖裡所有臉的座標(多角色務必先看 |
| 2. 裁底稿 | `icon headshot --photo <圖> --pick N` | `.sync/headshot.png`**不是圖示、不同步** |
| 3. | Read 打開底稿 + 讀 IDENTITY/SOUL | 髮型、瀏海、眼型、表情、髮飾、領口 |
| 4. 重繪 | `icon generate --palette ... --features ...` | `icon.svg` + `icon.png` |
| 1. 找 | `icon search --wiki <sub> --page <角色>` | 候選清單,📐 = 官方設定稿(優先 |
| 2. 量測 | `icon measure --photo <網址>` | 解析度、臉多大、背景透明/單色/有場景 |
| 3. 去背 | `icon cutout --photo <網址>` | `icon/portrait-cutout.png`(透明 PNG |
| 4. 合成 | `icon generate --from-cutout --palette ...` | `icon.svg` + `icon.png` + `icon/` 多解析度 |
去背三條路徑自動選:**原生 alpha**(官方設定稿常見,完美)→ **單色底移除**(很好)→
**GrabCut**(有場景時,邊緣普通;黑髮角色容易被誤切,這時該換設定稿)。
| 樣式 | 條件 | 長什麼樣 |
| --- | --- | --- |
| **`portrait`** | 有底稿(給了調色盤)→ 預設 | 依特徵重繪的人物頭像:漸層虹膜+雙高光+睫毛、髮絲與反光、腮紅與下巴陰影 |
| **`cutout`** | 有去背圖 → 最佳 | 官方原圖裁頭肩,疊在角色配色的漸層底上 |
| **`portrait`** | 沒有可用官方圖 | 依特徵重繪的人物頭像,五官俱全 |
| **`badge`** | 完全沒有參考圖 | 雙色漸層 + 編號前兩個字母 |
輸出(每次 `icon generate` 都會全部更新):
```
icon.svg / icon.png 根目錄:Wiki 頁面與存取庫頭像用(512)
icon/portrait.svg 向量原稿,可無限放大
icon/portrait-512.png 高解析度
icon/portrait-1024.png 高解析度
```
柵格器對每個圖形先算 bounding box 再逐點測試,1024×1024(3× 超取樣)約 1.8 秒。
**找到的圖片只能當底稿**:產出的 SVG 沒有 `<image>`、沒有 base64、沒有外連,每個像素都是畫出來的。
@@ -389,7 +384,7 @@ node scripts/persona.mjs said check --session <id> --text "<話>" # 這句是
node scripts/persona.mjs room script --session <id> --room <room> # 乾淨對話稿(劇場模式用)
node scripts/persona.mjs export --session <id> --out lumi.json # 離線搬家(單檔)
node scripts/persona.mjs sync status --session <id> # Gitea 同步狀態
node scripts/selftest.mjs # 168 項驗證:鎖、隔離、情緒、固化、說話節制、劇場模式、匯出匯入、編號與 Gitea、形象圖重繪、高解析輸出與 Wiki 同步、hooks
node scripts/selftest.mjs # 175 項驗證:鎖、隔離、情緒、固化、說話節制、劇場模式、匯出匯入、編號與 Gitea、找圖去背合成、高解析輸出與 Wiki 同步、hooks
```
檔案結構:`scripts/persona-lib.mjs`(核心:鎖/隔離/情緒/記憶)、`scripts/persona.mjs`CLI)、