fix: Wiki 圖片其實是破圖(HTML img 不被改寫);形象圖加高解析度與五官細節
1. Wiki 形象圖「沒有同步」的真正原因
內容其實一直是一致的(md5 相同),但**頁面上看不到圖**:
Icon.md/Home.md 用了 HTML `<img src="icon.svg">`,而 Gitea **只改寫
Markdown 圖片語法**(`` → `/wiki/raw/icon.png`)。HTML 的 src
被瀏覽器解析成 `/wiki/icon.svg` → 303 轉址 → 破圖。
用公開的臨時庫實測四種寫法後確認,全部改成 Markdown 語法。
同時發現攤平規則過頭了:原本所有子目錄檔案都被壓成 `icon-portrait.svg`。
實測 `/wiki/raw/<資料夾>/<圖>` 是取得到的,所以**只有 .md 需要攤平**
(頁面必須在根層),圖片與附件保留資料夾結構。
2. icon/ 資料夾 + 高解析度
每次 `icon generate` 都會輸出並同步:
icon.svg / icon.png 512,Wiki 頁面與存取庫頭像
icon/portrait.svg 向量原稿
icon/portrait-512.png 高解析度
icon/portrait-1024.png 高解析度
柵格器加上每個圖形的 bounding box 裁剪,1024×1024(3× 超取樣)約 1.8 秒;
沒有裁剪的話要跑上億次點測試。
3. 更貼近原圖、更可愛
眼睛放大約 15%,虹膜改成四層(暗環→本色→下緣提亮→瞳孔)+雙高光,
眼線壓扁成細弧、外眼角加睫毛;頭髮加高光弧、髮絲與側髮反光;
臉型再圓一點、加下巴陰影與鼻子。
眉色改成隨髮色明暗調整:深髮往膚色提亮、淺髮比頭髮更深——否則不是和瀏海
連成黑帶,就是變成兩條灰槓。
selftest 168 項全綠(新增第 ⑱ 節:icon/ 多解析度、PNG 實際尺寸、只攤平 .md、
Wiki 頁面不得用 HTML img、bounding box 裁剪效能)。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -93,6 +93,7 @@ export const AREAS = {
|
||||
"USER.md",
|
||||
"icon.svg",
|
||||
"icon.png",
|
||||
"icon/",
|
||||
"memory/INDEX.md",
|
||||
"memory/long-term/",
|
||||
"mindmap/semantic.mmd",
|
||||
@@ -316,6 +317,10 @@ const WIKI_PREFIX = { memory: "Memory", mindmap: "Mindmap", relations: "Relation
|
||||
*/
|
||||
export function wikiName(rel) {
|
||||
if (!rel.includes("/")) return rel;
|
||||
// 只有 .md 需要攤平——Gitea 只把「根目錄的 .md」當成頁面。
|
||||
// 其他附件(圖片、mmd、json)放子資料夾沒問題:實測 /wiki/raw/icon/portrait.svg 取得到,
|
||||
// 而且 Markdown 圖片語法會被自動改寫成那個 raw 路徑。
|
||||
if (!/\.md$/i.test(rel)) return rel;
|
||||
const parts = rel.split("/");
|
||||
const file = parts.pop();
|
||||
return `${WIKI_PREFIX[parts[0]] || parts[0]}-${file}`;
|
||||
@@ -401,6 +406,19 @@ export function wikiIconPage(slug, code) {
|
||||
const root = pl.personaDir(slug);
|
||||
const hasSvg = fs.existsSync(path.join(root, "icon.svg"));
|
||||
const hasPng = fs.existsSync(path.join(root, "icon.png"));
|
||||
let renders = [];
|
||||
try {
|
||||
renders = fs.readdirSync(path.join(root, "icon"))
|
||||
.filter((n) => /\.(svg|png)$/i.test(n))
|
||||
.sort()
|
||||
.map((name) => ({
|
||||
name,
|
||||
ext: name.split(".").pop(),
|
||||
note: /(\d+)/.test(name) ? `${name.match(/(\d+)/)[1]}×${name.match(/(\d+)/)[1]} 高解析度` : "向量原稿",
|
||||
}));
|
||||
} catch {
|
||||
renders = [];
|
||||
}
|
||||
const styleLabel = {
|
||||
photo: "真實照片裁臉",
|
||||
portrait: "向量人物形象(有臉),配色取自參考照片",
|
||||
@@ -411,13 +429,16 @@ export function wikiIconPage(slug, code) {
|
||||
"",
|
||||
`\`${code}\` ${styleLabel}`,
|
||||
"",
|
||||
// Gitea 只會改寫 **Markdown 圖片語法** 的路徑(→ /wiki/raw/...);
|
||||
// 用 HTML <img> 會被瀏覽器當成相對於頁面網址,變成 303 破圖。
|
||||
...(hasSvg || hasPng
|
||||
? [
|
||||
"| SVG(向量,可無限放大) | PNG(點陣,Gitea 頭像用) |",
|
||||
"| --- | --- |",
|
||||
`| ${hasSvg ? '<img src="icon.svg" alt="icon.svg" width="200">' : "(缺)"} ` +
|
||||
`| ${hasPng ? '<img src="icon.png" alt="icon.png" width="200">' : "(缺)"} |`,
|
||||
`| [icon.svg](icon.svg) | [icon.png](icon.png) |`,
|
||||
...(hasPng ? [``, ""] : []),
|
||||
"| 格式 | 檔案 | 用途 |",
|
||||
"| --- | --- | --- |",
|
||||
...(hasSvg ? [`| SVG | [icon.svg](icon.svg) | 向量,可無限放大 |`] : []),
|
||||
...(hasPng ? [`| PNG | [icon.png](icon.png) | 點陣,存取庫頭像 |`] : []),
|
||||
...renders.map((r) => `| ${r.ext.toUpperCase()} | [icon/${r.name}](icon/${r.name}) | ${r.note} |`),
|
||||
"",
|
||||
]
|
||||
: ["(尚未產生形象圖,執行 `/jsc-persona:persona-icon`。)", ""]),
|
||||
@@ -446,11 +467,11 @@ export function wikiHome(slug, code) {
|
||||
const ident = pl.identityFields(slug);
|
||||
const longTerm = pl.longTermEntries(slug);
|
||||
const relations = pl.loadRelations(slug);
|
||||
const hasIcon = fs.existsSync(path.join(pl.personaDir(slug), "icon.svg"));
|
||||
const hasIcon = fs.existsSync(path.join(pl.personaDir(slug), "icon.png"));
|
||||
const lines = [
|
||||
`# ${ident.Emoji ? `${ident.Emoji} ` : ""}${ident.Name || slug} \`${code}\``,
|
||||
"",
|
||||
...(hasIcon ? [`<img src="icon.svg" alt="${code}" width="128" height="128">`, ""] : []),
|
||||
...(hasIcon ? [``, ""] : []),
|
||||
"> 由 jsc-persona 自動產生的人格設定百科。**低頻資料**(身分、長期記憶、心智圖、關係圖)放這裡;",
|
||||
"> 每輪都在變的活狀態(情緒、短期記憶、心裡話、逐字稿)在存取庫的檔案區。",
|
||||
"",
|
||||
@@ -489,7 +510,7 @@ export function wikiHome(slug, code) {
|
||||
"",
|
||||
"- `Mindmap-semantic.mmd` — 心智圖(Mermaid)",
|
||||
"- `Relations-graph.mmd` — 人際關係圖(Mermaid)/ `Relations-graph.json` — 原始資料",
|
||||
"- `_paths.json` — 攤平前的原始路徑對照(同步用,勿手改)",
|
||||
"- `icon/` — 高解析度形象圖(多尺寸) - `_paths.json` — 攤平前的路徑對照(勿手改)",
|
||||
"",
|
||||
"> Gitea 的 wiki 只有根目錄的 `.md` 會變成頁面,所以子目錄的檔案在這裡是攤平的檔名。",
|
||||
"",
|
||||
|
||||
Reference in New Issue
Block a user