#!/usr/bin/env bash # 生成 VI 手册用的 iPhone 桌面模拟图 apple/iphone-home.png(透明背景,3 倍分辨率)。 # 前置:fetch.sh 已下载图标和壁纸;机身 PNG 已按 README.md 放到 apple/bezel.png;logo/.work/venv 可用。 # 用法:docs/design/vi/mockup/build.sh set -euo pipefail cd "$(dirname "$0")" PORT=8799 PY=../../logo/.work/venv/bin/python # 1. 量机身:与中心连通的透明区就是屏幕(圆角形状和机身完全一致)。 # 输出屏幕遮罩 screen-mask.png,以及页面用的尺寸 geometry.css(机身 PNG 是 3 倍图,1pt = 3px) SIZE=$("$PY" -I - <<'EOF' import numpy as np from PIL import Image from scipy import ndimage a = np.asarray(Image.open("apple/bezel.png"))[..., 3] lab, _ = ndimage.label(a < 10) screen = lab == lab[a.shape[0] // 2, a.shape[1] // 2] ys, xs = np.where(screen) x, y, w, h = xs.min(), ys.min(), xs.max() + 1 - xs.min(), ys.max() + 1 - ys.min() # 向外扩 2px 压到机身黑边下面,避免抗锯齿露出白缝;CSS 遮罩读透明通道,所以存成 RGBA m = ndimage.binary_dilation(screen, iterations=2)[y:y + h, x:x + w] rgba = np.zeros(m.shape + (4,), np.uint8) rgba[..., 3] = m * 255 Image.fromarray(rgba, "RGBA").save("apple/screen-mask.png") H, W = a.shape pt = lambda v: f"{v / 3:g}px" open("apple/geometry.css", "w").write( f":root{{--dev-w:{pt(W)};--dev-h:{pt(H)};--scr-x:{pt(x)};--scr-y:{pt(y)};--scr-w:{pt(w)};--scr-h:{pt(h)}}}\n") print(f"{W // 3},{H // 3}") EOF ) cat apple/geometry.css # 2. 临时起本地服务(file:// 下遮罩图片会被浏览器安全策略拦掉;根目录是 docs/design,页面要引用 logo/),按 3 倍截图 python3 -m http.server $PORT --bind 127.0.0.1 --directory ../.. >/dev/null 2>&1 & SERVER=$! trap 'kill $SERVER' EXIT sleep 1 "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" --headless=new --hide-scrollbars \ --default-background-color=00000000 --force-device-scale-factor=3 --window-size="$SIZE" \ --virtual-time-budget=5000 --screenshot="$PWD/apple/iphone-home.png" \ "http://127.0.0.1:$PORT/vi/mockup/iphone-home.html" 2>/dev/null magick identify apple/iphone-home.png