7ecd740f82
用戶從 rag.arcrun.dev → install.arcrun.dev → 自己的 portal → 托盤, 四個地方應該看到同一個 icon。此前最不一致的就是托盤(Fyne 內建的通用 「儲存」圖示,main.go:1016 留著 TODO)。 素材真身=InkStoneCo/arcrun-cis/(leo 用 Claude Design 做的 CIS)。 托盤(trayicon.go,新檔) - macOS:template 單色(純黑+alpha),系統依選單列深淺自動反色。 ⚠️ fyne v2.5.3 只有 *theme.ThemedResource 才會走 systray.SetTemplateIcon (driver_desktop.go:169);傳一般 StaticResource 會走 SetIcon=不反色。 - Windows:完整墨底 icon(template 是 mac 專有)。 - 兩份都用 go:embed 內嵌,不讀外部路徑——打包後工作目錄不是原始碼目錄。 - 選單列用雙 chevron 而非完整方形字符:CIS 規定 26px 以下降級成 chevron, 方塊裡的字符只佔高度 ~28%,22pt 下只剩 ~4px 會糊掉。 app 圖示 - icon.png 換成 CIS 1024 原生;icns 重產含 16→1024 全套 Retina 階梯。 msix(Store) - 圖示改成預先產好、隨 repo 版控的 assets/store/(含 gen-store-assets.py 可重跑)。 - 修掉一個實際的變形 bug:舊版 `sips -z 150 310 icon.png` 會把方形 icon **橫向拉扁**成寬磚(實測產出的字符明顯變形),違反 CIS「never skew or stretch」。 寬磚改用橫式 lockup 等比置中於墨底。 - 補 71x71/310x310/targetsize-16/24/32/48/256,manifest 一併宣告; BackgroundColor 從 transparent 改成品牌 Ink #17181A。 landing favicon(rag.arcrun.dev) - LOGO_SVG 從琥珀金圓圈暫代圖換成 CIS 正式 mark(單色,CIS:彩色 chevron 在產品裡代表「這條關係是活的」,用在 logo 會是謊話)。 - 修掉名實不符:`/favicon.ico` 過去回的是 SVG 位元組卻標 image/svg+xml (線上實測 200 但 type=image/svg+xml),老瀏覽器與抓圖服務畫不出來。 現在 .ico 回真 ICO(16/32/48 三尺寸)、apple-touch-icon.png 回真 PNG(180)。 - 三個頁面(首頁/privacy/support)補上 icon link 宣告(此前完全沒有)。 ⚠️ installer 這次沒動:`install.arcrun.dev` 的真身是 `installer/oauth-prototype/worker.js`(不在本分支,見 wiki decisions-summary 「installer 有兩個 worker,改錯=白做」),另立一筆處理。 實測證據 - mac .app 執行檔內 grep 到 tray-template.png 位元組(sha f6af940d,位移 14001472); Windows exe 內 grep 到 tray-windows.png(sha 59f4f1ac);各自平台只嵌自己那份 (另一份被 linker 消掉=runtime.GOOS 編譯期常數,正確)。 - msix 重打包過 makemsix unpack 回讀驗證,包內 11 張圖示齊全。 - 已部署 arcrun-landing(版本 b79d19df)。繞快取實測 rag.arcrun.dev: favicon.ico→image/x-icon 1573B(3 icons,sha 151e645b=與本機產出同一顆)、 apple-touch-icon.png→image/png 180x180、首頁 head 三個 link 宣告都在。 ⚠️ 舊版 max-age=86400 的邊緣快取未 purge(無 zone token),24h 內自然過期。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
109 lines
4.1 KiB
Python
109 lines
4.1 KiB
Python
#!/usr/bin/env python3
|
||
"""重新產生 Microsoft Store(msix)的圖示素材。
|
||
|
||
素材真身=leo 的 CIS(`InkStoneCo/arcrun-cis/`),本腳本只做「等比縮 + 置中合成」。
|
||
|
||
守 CIS 的 Don't:**不拉扁、不歪斜、不加第二個顏色**。
|
||
- 方形磚 → 用方形 icon(`arcrun-icon-ink-1024.png`)等比縮。
|
||
- 寬磚 310×150 → 用**橫式 lockup**(`arcrun-lockup-h-paper-on-ink.png`)置中於墨底。
|
||
不能拿方形 icon 硬拉成 310×150——舊版 `sips -z 150 310` 就是這樣把方形字符拉扁的。
|
||
- targetsize-16/24(工作列小圖)→ CIS 規定 26px 以下降級成 chevron,
|
||
完整字符在這尺寸只剩約 4px 高,會糊掉。
|
||
|
||
用法(需要 Pillow):
|
||
python3 gen-store-assets.py
|
||
產物寫回本目錄、隨 repo 版控;`build-msix.sh` 只負責 cp 進包裡。
|
||
"""
|
||
import os
|
||
from pathlib import Path
|
||
|
||
from PIL import Image, ImageDraw
|
||
|
||
HERE = Path(__file__).resolve().parent
|
||
# CIS 住在 InkStoneCo 頂層。預設往上找,找不到時用 ARCRUN_CIS 指過去。
|
||
CIS = Path(os.environ["ARCRUN_CIS"]) if os.environ.get("ARCRUN_CIS") else None
|
||
if CIS is None:
|
||
for parent in HERE.parents:
|
||
cand = parent / "arcrun-cis"
|
||
if cand.is_dir():
|
||
CIS = cand
|
||
break
|
||
|
||
INK = (23, 24, 26, 255)
|
||
PAPER = (253, 252, 251, 255)
|
||
|
||
|
||
def load(name: str) -> Image.Image:
|
||
if CIS is None or not (CIS / name).exists():
|
||
raise SystemExit(
|
||
f"❌ 找不到 CIS 素材 {name}(找過 {CIS})\n"
|
||
f" 指過去:ARCRUN_CIS=/path/to/arcrun-cis python3 {Path(__file__).name}")
|
||
return Image.open(CIS / name).convert("RGBA")
|
||
|
||
|
||
def chevron_on_ink(size: int, inset: float = 0.20) -> Image.Image:
|
||
"""雙 chevron(paper)置中於墨底——給 26px 以下的小尺寸用。
|
||
|
||
幾何與 CIS `chevron-double.svg` 同一組座標(24-grid、stroke 2.8)。
|
||
先超取樣畫再縮,邊緣才不會鋸齒。
|
||
"""
|
||
ss = size * 16
|
||
unit = ss / 24.0
|
||
layer = Image.new("RGBA", (ss, ss), (0, 0, 0, 0))
|
||
d = ImageDraw.Draw(layer)
|
||
w = max(1, round(2.8 * unit))
|
||
for dx in (0, 7):
|
||
d.line([((5 + dx) * unit, 5 * unit),
|
||
((12 + dx) * unit, 12 * unit),
|
||
((5 + dx) * unit, 19 * unit)],
|
||
fill=PAPER, width=w, joint="curve")
|
||
|
||
art = layer.crop(layer.split()[3].getbbox())
|
||
target = ss * (1 - 2 * inset)
|
||
scale = target / max(art.size)
|
||
nw, nh = max(1, round(art.size[0] * scale)), max(1, round(art.size[1] * scale))
|
||
art = art.resize((nw, nh), Image.LANCZOS)
|
||
|
||
out = Image.new("RGBA", (ss, ss), INK)
|
||
out.paste(art, ((ss - nw) // 2, (ss - nh) // 2), art)
|
||
return out.resize((size, size), Image.LANCZOS)
|
||
|
||
|
||
def wide_tile(w: int, h: int, pad_ratio: float = 0.14) -> Image.Image:
|
||
"""寬磚:橫式 lockup 等比 fit 進墨底,四周留白(CIS clear space)。"""
|
||
lock = load("arcrun-lockup-h-paper-on-ink.png")
|
||
canvas = Image.new("RGBA", (w, h), INK)
|
||
lw, lh = lock.size
|
||
scale = min(w * (1 - 2 * pad_ratio) / lw, h * (1 - 2 * pad_ratio) / lh)
|
||
nw, nh = max(1, round(lw * scale)), max(1, round(lh * scale))
|
||
art = lock.resize((nw, nh), Image.LANCZOS)
|
||
canvas.paste(art, ((w - nw) // 2, (h - nh) // 2), art)
|
||
return canvas
|
||
|
||
|
||
def main() -> None:
|
||
square = load("arcrun-icon-ink-1024.png")
|
||
made = []
|
||
|
||
for name, s in [("Square44x44Logo", 44), ("StoreLogo", 50),
|
||
("Square71x71Logo", 71), ("Square150x150Logo", 150),
|
||
("Square310x310Logo", 310)]:
|
||
square.resize((s, s), Image.LANCZOS).save(HERE / f"{name}.png")
|
||
made.append((f"{name}.png", s, s))
|
||
|
||
# 工作列 / 開始功能表多尺寸:26px 以下用 chevron(CIS 規定),其餘用方形 icon
|
||
for s in (16, 24, 32, 48, 256):
|
||
img = chevron_on_ink(s) if s <= 26 else square.resize((s, s), Image.LANCZOS)
|
||
img.save(HERE / f"Square44x44Logo.targetsize-{s}.png")
|
||
made.append((f"Square44x44Logo.targetsize-{s}.png", s, s))
|
||
|
||
wide_tile(310, 150).save(HERE / "Wide310x150Logo.png")
|
||
made.append(("Wide310x150Logo.png", 310, 150))
|
||
|
||
for n, w, h in made:
|
||
print(f"✅ {n}: {w}x{h}")
|
||
|
||
|
||
if __name__ == "__main__":
|
||
main()
|