需求:Mac 端 installer 體驗類比 Windows .exe — 進 DMG 就看到漂亮的視窗
背景 + 拖到 Applications 的視覺引導。
實作:
- installer/macos/ 新資料夾
- make-dmg-background.py:動態生成 640×400 深色背景,配色對齊 Wails
控制台 splash(#111827→#0B0F19 漸層 + #38BDF8 accent)
- background.png + background@2x.png(1x + 2x Retina)
- Makefile dmg 拆三 target:
- dmg:auto-detect,有 create-dmg 走 fancy,沒有 fallback plain(CI 無痛)
- dmg-fancy:強制美化版(需 `brew install create-dmg`)
- dmg-plain:原 hdiutil UDZO(保留為 fallback)
- Windows / Linux 流程零改動
驗證:
- `make dmg-fancy` 產出 157MB DMG,mount 後內容:app + Applications 捷徑
+ .background/background.png + .DS_Store(視窗樣式)
- `hdiutil verify` 通過
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
86 lines
2.6 KiB
Python
86 lines
2.6 KiB
Python
#!/usr/bin/env python3
|
||
"""
|
||
生成 DMG 美化背景圖(640×400),對齊 Wails 控制台深色 splash 風格。
|
||
|
||
用法:
|
||
python3 installer/macos/make-dmg-background.py
|
||
|
||
輸出:
|
||
installer/macos/background.png (1x, 640×400)
|
||
installer/macos/background@2x.png (2x, 1280×800 Retina)
|
||
|
||
create-dmg 會自動挑 @2x 版本用於 Retina 螢幕。
|
||
"""
|
||
from pathlib import Path
|
||
|
||
from PIL import Image, ImageDraw, ImageFont
|
||
|
||
OUT_DIR = Path(__file__).resolve().parent
|
||
W, H = 640, 400
|
||
|
||
BG_TOP = (17, 24, 39)
|
||
BG_BOTTOM = (11, 15, 25)
|
||
TEXT = (229, 231, 235)
|
||
MUTED = (148, 163, 184)
|
||
ACCENT = (56, 189, 248)
|
||
|
||
|
||
def make(scale: int, out_path: Path) -> None:
|
||
w, h = W * scale, H * scale
|
||
img = Image.new("RGB", (w, h), BG_TOP)
|
||
px = img.load()
|
||
for y in range(h):
|
||
t = y / (h - 1)
|
||
r = int(BG_TOP[0] + (BG_BOTTOM[0] - BG_TOP[0]) * t)
|
||
g = int(BG_TOP[1] + (BG_BOTTOM[1] - BG_TOP[1]) * t)
|
||
b = int(BG_TOP[2] + (BG_BOTTOM[2] - BG_TOP[2]) * t)
|
||
for x in range(w):
|
||
px[x, y] = (r, g, b)
|
||
|
||
draw = ImageDraw.Draw(img)
|
||
|
||
try:
|
||
font_title = ImageFont.truetype("/System/Library/Fonts/Helvetica.ttc", 22 * scale)
|
||
font_hint = ImageFont.truetype("/System/Library/Fonts/Helvetica.ttc", 14 * scale)
|
||
except OSError:
|
||
font_title = ImageFont.load_default()
|
||
font_hint = ImageFont.load_default()
|
||
|
||
title = "Drag visionA-local to Applications"
|
||
tw = draw.textlength(title, font=font_title)
|
||
draw.text(((w - tw) / 2, 28 * scale), title, fill=TEXT, font=font_title)
|
||
|
||
hint = "拖曳圖示到右邊的 Applications 即可安裝"
|
||
hw = draw.textlength(hint, font=font_hint)
|
||
draw.text(((w - hw) / 2, 60 * scale), hint, fill=MUTED, font=font_hint)
|
||
|
||
# 箭頭位置:左右兩個 icon 約在 y=230,中心。icon 本身 128×128,由 create-dmg 擺。
|
||
# create-dmg 預設 app icon x=180, Applications x=460(y=200)。箭頭畫在中間 240-400 區段。
|
||
arrow_y = 200 * scale
|
||
arrow_x1 = 260 * scale
|
||
arrow_x2 = 380 * scale
|
||
line_w = 3 * scale
|
||
draw.line([(arrow_x1, arrow_y), (arrow_x2, arrow_y)], fill=ACCENT, width=line_w)
|
||
# 箭頭頭
|
||
head = 12 * scale
|
||
draw.polygon(
|
||
[
|
||
(arrow_x2, arrow_y),
|
||
(arrow_x2 - head, arrow_y - head // 2 - 2 * scale),
|
||
(arrow_x2 - head, arrow_y + head // 2 + 2 * scale),
|
||
],
|
||
fill=ACCENT,
|
||
)
|
||
|
||
img.save(out_path, "PNG", optimize=True)
|
||
print(f"wrote {out_path} ({out_path.stat().st_size // 1024} KB)")
|
||
|
||
|
||
def main() -> None:
|
||
make(1, OUT_DIR / "background.png")
|
||
make(2, OUT_DIR / "background@2x.png")
|
||
|
||
|
||
if __name__ == "__main__":
|
||
main()
|