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
+63 -91
View File
@@ -1,6 +1,6 @@
---
name: persona-icon
description: 產生或更新人格的形象圖(icon.svg + icon.png,人物頭像、看得到臉):先上網找出該人格「最新一次登場」的官方視覺,裁出**大頭照當底稿**,親眼看過之後萃取髮色/瞳色/服裝色與髮型、眼型、表情、配件等特徵,再**由本工具依人格資料重新繪製**——絕不把找到的圖片直接當圖示。來源網址、底稿裁切框與重繪依據都會存進 config 備查,圖示同步到 Gitea Wiki(SVG + PNG)並設為存取庫頭像,且會回頭驗證同步結果。當使用者說要做人格頭像/形象圖/icon、要依角色最新造型更新圖示、說現在的圖示不像或看不到臉、或剛建立完人格要補圖示時觸發。不適用於:建立人格本身(persona-createpersona-anime,它們會叫用本技能的步驟)、同步到 Giteapersona-sync)。
description: 產生或更新人格的形象圖(icon.svg + icon.png):先找出該人格「最新一次登場」對應的**高解析度官方圖**(優先官方人設稿/設定圖,它們通常是透明底或白底、解析度遠高於資料庫縮圖),量測解析度與臉的大小後**去背**成透明 PNG,再裁成頭肩構圖、合成到取自角色配色的漸層底上,成為存取庫頭像並同步到 Gitea Wiki(含 icon/ 多解析度)。找不到可用的官方圖時,退回依人格資料重新繪製的向量人物形象。當使用者說要做人格頭像/形象圖/icon、要依角色最新造型更新圖示、說圖示不像或不夠清楚、或剛建立完人格要補圖示時觸發。不適用於:建立人格本身(persona-createpersona-anime)、同步到 Giteapersona-sync)。
---
# 🎨 persona-icon — 依最新造型產生人格形象圖(有臉)
@@ -9,9 +9,10 @@ description: 產生或更新人格的形象圖(icon.svg + icon.png,人物頭
**時機****人格建立且 IDENTITY/SOUL 補齊之後**——形象綁在最終身分上。
**目標**:圖示要是**人物形象圖,看得到臉**;退而求其次才是抽象徽章。
> **鐵則:找到的圖片只能當底稿,不能當圖示。**
> 網路上的角色圖是別人的美術作品。這裡的做法是「裁出大頭照 → 看清楚 →
> **依人格資料重新繪製**」,產出的每一個像素都是本工具畫的。
**流程**:找高解析度官方圖 → 量測 → **去背** → 裁頭肩 → 合成 → 更新頭像與 Wiki。
> 找不到可用的官方圖時(沒有設定稿、只有場景截圖且去背不乾淨),
> 才退回「依人格資料重新繪製」的向量形象(`--style portrait`)。
---
@@ -24,107 +25,78 @@ description: 產生或更新人格的形象圖(icon.svg + icon.png,人物頭
### 1. 查出「最新一次登場」
用 WebSearch 這個角色最近的官方動向(新作、新章節、新造型),至少確認:
用 WebSearch 確認這個角色最近的官方動向(新作、新章節、新造型)與**對應的形態名稱**
(例:亞絲娜 → 2026《Unanswered//butterfly》重述早期艾恩葛朗特 → 對應 **SAO Avatar**
結衣 → 現行 Unital Ring 章 → 對應 **ALO Pixie Form**)。
- 最新的作品/章節名稱與年份
- 那個版本的造型敘述(髮色、瞳色、服裝主色)
搜尋語彙範例:`<角色> <作品> 2026 新作 主視覺``<character> latest anime key visual outfit`
### 2. 取得一張真的參考圖
要**直接的圖片網址**`.png` / `.jpg`),優先序:
1. 官方新作的主視覺/key visual(新聞稿內的圖)
2. AniList 的官方角色圖——可直接查,不需登入:
```bash
curl -s -X POST -H "Content-Type: application/json" \
-d '{"query":"query{Media(id:<動畫 id>,type:ANIME){characters(perPage:25){nodes{name{full} image{large}}}}}"}' \
https://graphql.anilist.co
```
3. 其他公開的官方素材
下載下來:`curl -sL -o /tmp/ref.png "<圖片網址>"`
### 3. **親眼看過那張圖**(不可省略)
用 Read 工具打開它。**沒看過就不准填顏色**——憑記憶填色等於編造。
從圖上讀出五個顏色(用取樣到的實際色,不是「大概是紅色」):
| 欄位 | 取哪裡 |
| --- | --- |
| `hair` | 頭髮的主色(不是高光也不是陰影) |
| `eye` | 瞳孔顏色 |
| `accent` | 服裝最顯眼的主色 |
| `secondary` | 服裝的第二色/配件色 |
| `light` | 最亮的部位(白袖、皮膚亮面) |
### 4. 裁出大頭照當底稿
### 2. 找高解析度官方圖
```bash
# 先看看圖裡有幾張臉——多角色的主視覺一定要先看
node "${CLAUDE_PLUGIN_ROOT}/scripts/persona.mjs" icon faces --session <PERSONA_SESSION> --photo "<圖片網址或路徑>"
# 裁出底稿(索引由左到右;也可以用 largest/leftmost/rightmost,或 --face x,y,w,h 自己框)
node "${CLAUDE_PLUGIN_ROOT}/scripts/persona.mjs" icon headshot --session <PERSONA_SESSION> --photo "<圖片網址或路徑>" --pick <索引>
node "${CLAUDE_PLUGIN_ROOT}/scripts/persona.mjs" icon search --session <PERSONA_SESSION> --wiki <fandom 子網域> --page <角色頁名>
```
底稿寫到 `<人格>/.sync/headshot.png`,**不是圖示、不會同步、不會發佈**。
結果依「解析度 + 是不是官方設定稿」排序,標 📐 的是設定稿(`Full Body``Character Design`
`Avatar`)。**優先選設定稿**
**多角色的圖務必自己看過再挑**`icon faces` 只給座標,哪張臉是本人要由你判斷。
裁完**一定要用 Read 打開確認是本人**——挑錯就是別人的臉。
- 解析度高(常見 773×1056、1280×880),遠勝角色資料庫的 230px 縮圖
- **多半是透明底或純白底 → 去背幾乎免費、邊緣乾淨**
- 是官方繪製的正式立繪,不是動畫截圖
工具不齊時 CLI 會**印出安裝指令**——不會靜默失敗。需要的工具:
挑「與第 1 步的形態相符」的那一張——同一個角色會有很多套造型。
| 工具 | 做什麼 | 怎麼裝(免 sudo) |
| --- | --- | --- |
| Pillow | 解碼照片、裁切、縮放 | `python3 -m venv ~/.cache/jsc-persona/venv && ~/.cache/jsc-persona/venv/bin/pip install pillow` |
| OpenCV 4.x | 自動找臉的位置 | `~/.cache/jsc-persona/venv/bin/pip install "opencv-python-headless<5"` |
| 動漫臉模型 | OpenCV 內建模型認不出動漫臉 | `curl -sL -o ~/.cache/jsc-persona/lbpcascade_animeface.xml https://raw.githubusercontent.com/nagadomi/lbpcascade_animeface/master/lbpcascade_animeface.xml` |
> OpenCV **5.x 拿掉了 `CascadeClassifier`**,一定要裝 4.x。
> venv 放在 `~/.cache/jsc-persona/venv` 會被自動偵測到;也可以用 `PERSONA_PYTHON` 指定別的。
### 5. 看著底稿,把特徵讀出來
用 Read 打開 `.sync/headshot.png`**同時**讀這個人格的 `IDENTITY.md``SOUL.md`canon 記憶。
形象要同時對得起「他長什麼樣」與「他是誰」:
| 特徵 | 可選值 | 從哪裡判斷 |
| --- | --- | --- |
| `hairstyle` | straight / twintails / ponytail / bob / braid | 底稿的髮型 |
| `length` | short / medium / long / very-long | 底稿的髮長 |
| `fringe` | blunt / parted / swept / curtain | 底稿的瀏海 |
| `eyes` | round / almond / sharp / droopy | 底稿的眼型 |
| `expression` | gentle / bright / calm / neutral | **SOUL 的 Vibe** 底稿的神情 |
| `accessory` | none / ribbon / clip / flower / hairband | 底稿或最新造型的髮飾 |
| `side` | left / right | 髮飾在哪一側 |
| `collar` | round / v / high / sailor | 服裝領口 |
| `ahoge` | yes / no | 有沒有呆毛 |
### 6. 重新繪製
### 3. 量測
```bash
node "${CLAUDE_PLUGIN_ROOT}/scripts/persona.mjs" icon generate --session <PERSONA_SESSION> --force \
--palette "hair=#d9a45b,eye=#9e5b3e,accent=#c0392b,secondary=#e77a8e,light=#f2ebe3,skin=#f7ddc4" \
--features "hairstyle=straight,length=very-long,fringe=parted,eyes=almond,expression=calm,accessory=none,collar=v,ahoge=yes" \
--source-url "<底稿那張圖的網址>" \
--source-note "<作品(年份)+底稿是誰+重繪依據:髮型、眼型、神情、服裝>" \
--source-date <YYYY-MM-DD>
node "${CLAUDE_PLUGIN_ROOT}/scripts/persona.mjs" icon measure --session <PERSONA_SESSION> --photo "<圖片網址>"
```
**畫完一定要用 Read 打開產出的 `icon.png` 看一眼**,不像就調特徵重畫(`--force`
會回報解析度、找到幾張臉、臉佔長邊多少、背景是**透明/單色/有場景**、去背難不難
`去背難度:偏難` 就回第 2 步換一張設定稿,不要硬做。
- **`--palette` 一定要配 `--source-url`**:配色是從哪張圖來的必須留得下來(CLI 會強制)。
- 兩者都會寫進 `state/config.json` 的 `icon` 欄位,之後 `icon show` 查得到。
- 產出的 `icon.svg` + `icon.png` 會自動設成 Gitea 存取庫頭像、同步到 Wiki 區,
並在 Wiki 產生一頁 **Icon**(同時展示 SVG 與 PNG,附上來源網址與裁切框)。
### 4. 去背
找不到可靠的參考圖 → **不要硬掰**,直接 `icon generate` 不帶 `--palette`
用編號雜湊出的配色,並告訴使用者「沒找到最新造型的官方圖,先用預設配色」。
```bash
node "${CLAUDE_PLUGIN_ROOT}/scripts/persona.mjs" icon cutout --session <PERSONA_SESSION> --photo "<圖片網址>" [--pick <索引>]
```
三條路徑,自動選最好的那條:
| 方式 | 什麼時候 | 品質 |
| --- | --- | --- |
| `source-alpha` | 原圖本來就是透明底(官方設定稿常見) | 完美 |
| `plain-background` | 純白/單色底 | 很好 |
| `grabcut` | 有場景,用臉的位置當前景種子 | 普通,邊緣可能不乾淨 |
輸出到 `icon/portrait-cutout.png`。**用 Read 打開確認**:邊緣有沒有殘留、頭髮有沒有被切掉。
黑髮角色在有場景的圖上特別容易被 GrabCut 誤切——真的不行就換設定稿。
### 5. 合成圖示
```bash
node "${CLAUDE_PLUGIN_ROOT}/scripts/persona.mjs" icon generate --session <PERSONA_SESSION> --force --from-cutout [--zoom 1.85] [--pick <索引>] \
--palette "hair=#..,eye=#..,accent=#..,secondary=#..,light=#..,skin=#.." \
--source-url "<那張圖的網址>" --source-note "<作品/形態+為什麼選這張>"
```
- 自動裁成**頭肩構圖**(官方設定稿常是正反兩面並排,不裁會變成兩個人;`--zoom` 調鬆緊)。
- 底色漸層取自 `--palette``light``accent`),所以要先看過圖再填顏色。
- 產出 `icon.svg`(內嵌同一張 PNG,自成一體不外連)、`icon.png`,以及
`icon/portrait.svg``icon/portrait-512.png``icon/portrait-1024.png`
- **畫完用 Read 打開看一眼**,構圖不好就調 `--zoom``--face` 重來。
### 6. 沒有官方圖時:向量重繪(有臉)
裁出大頭照當底稿、親眼看過、讀出特徵,再重繪:
```bash
node "${CLAUDE_PLUGIN_ROOT}/scripts/persona.mjs" icon headshot --session <PERSONA_SESSION> --photo "<圖片網址>" --pick <索引> # 底稿,不同步
node "${CLAUDE_PLUGIN_ROOT}/scripts/persona.mjs" icon generate --session <PERSONA_SESSION> --force --palette "..." --features "hairstyle=..,eyes=..,expression=.."
```
特徵可選值:`hairstyle` straight/twintails/ponytail/bob/braid、`length` short/medium/long/very-long、
`fringe` blunt/parted/swept/curtain、`eyes` round/almond/sharp/droopy、
`expression` gentle/bright/calm/neutral、`accessory` none/ribbon/clip/flower/hairband、
`side` left/right、`collar` round/v/high/sailor、`ahoge` yes/no。
### 7. 回報