78 lines
2.5 KiB
Python
78 lines
2.5 KiB
Python
# -*- coding: utf-8 -*-
|
||
"""
|
||
render_mockup.py — 把 mockup HTML 的 1:1 视图渲染成 160×160 PNG(无头 Chrome/Edge)
|
||
|
||
用法:
|
||
python tools/ui_mock/render_mockup.py <mockup.html> <out.png> [--pad 24] [--size 160]
|
||
|
||
原理:
|
||
mockup 的 body 有 padding(默认 24px),1:1 视图是第一个 flex 子项,位于 (pad, pad),
|
||
尺寸 160×160。用无头浏览器截整页,再裁出 (pad, pad, pad+160, pad+160) 即得纯页面位图。
|
||
浏览器抗锯齿会在边缘产生灰阶;对比前由 compare_mockup.py 统一二值化(阈值 128)。
|
||
"""
|
||
import argparse
|
||
import os
|
||
import subprocess
|
||
import sys
|
||
from pathlib import Path
|
||
|
||
from PIL import Image
|
||
import numpy as np
|
||
|
||
BROWSER_CANDIDATES = [
|
||
r"C:\Program Files\Google\Chrome\Application\chrome.exe",
|
||
r"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe",
|
||
r"C:\Program Files\Microsoft\Edge\Application\msedge.exe",
|
||
r"C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe",
|
||
]
|
||
|
||
|
||
def find_browser():
|
||
for c in BROWSER_CANDIDATES:
|
||
if os.path.exists(c):
|
||
return c
|
||
sys.exit("未找到 Chrome/Edge(用于无头渲染)")
|
||
|
||
|
||
def render(html_path, out_png, pad=24, size=160):
|
||
browser = find_browser()
|
||
html_abs = Path(html_path).resolve()
|
||
if not html_abs.exists():
|
||
sys.exit("找不到 HTML: %s" % html_abs)
|
||
out_abs = Path(out_png).resolve()
|
||
out_abs.parent.mkdir(parents=True, exist_ok=True)
|
||
|
||
win = pad + size + pad + 12 # 留一点余量
|
||
cmd = [
|
||
browser,
|
||
"--headless",
|
||
"--disable-gpu",
|
||
"--hide-scrollbars",
|
||
"--force-device-scale-factor=1",
|
||
"--window-size=%d,%d" % (win, win),
|
||
"--screenshot=%s" % out_abs,
|
||
html_abs.as_uri(),
|
||
]
|
||
r = subprocess.run(cmd, capture_output=True, text=True, timeout=90)
|
||
if not out_abs.exists():
|
||
sys.exit("截图失败:\n%s\n%s" % (r.stdout, r.stderr))
|
||
|
||
img = Image.open(out_abs).convert("L")
|
||
box = (pad, pad, pad + size, pad + size)
|
||
page = img.crop(box)
|
||
arr = np.array(page)
|
||
dark = float((arr < 128).mean())
|
||
page.save(out_abs)
|
||
print("OK %s -> %s (%dx%d, 黑像素 %.1f%%)" % (html_abs, out_abs, size, size, dark * 100))
|
||
return out_abs
|
||
|
||
|
||
if __name__ == "__main__":
|
||
ap = argparse.ArgumentParser()
|
||
ap.add_argument("html")
|
||
ap.add_argument("out")
|
||
ap.add_argument("--pad", type=int, default=24, help="mockup body padding(1:1 视图左上偏移)")
|
||
ap.add_argument("--size", type=int, default=160)
|
||
a = ap.parse_args()
|
||
render(a.html, a.out, pad=a.pad, size=a.size)
|