Files
STM32F4-Base/simulator/tests/regen_ref_png.py
T
wandering1 a38f862fb9 chore(ui-golden): 像素黄金参考 ref/*.bin 入库(把门禁改成可移植)
问题:ui-golden 是逐字节比对(check_content_pages.py 里 data == refdata),
而基准 simulator/tests/ref/ 整目录被 .gitignore 忽略、从未入库。后果不是
"少几个文件",而是这条门禁在任何新克隆 / 新并行工作树里必然报「缺黄金
参考」——只在有老副本的机器上它才是真的回归门禁。本会话已两次实测踩到
(并行工作树里只能现场 --update 造基准,而现场造出来的基准恰好失去意义)。

入库前先证明基线可复现,否则等于把一条天天误报的门禁写进仓库:
- 主树 ref/ 生成于 2026-10-11,其间合入 B6~B9 与 UI 令牌化等多次改动;
  今天用刚重建的 lvgl_sim 重跑 → 11 页 + 开页-关页往返池水位逐字节全过
- 主树与新工作树两份**独立构建**的 lvgl_sim(不同构建目录、不同绝对路径)
  各自生成基准 → 11 个 .bin 的 SHA-256 全部一致
即渲染是 CPU 侧确定性输出,可以当仓库内容。

改动:
- .gitignore:整目录忽略 → 只忽略派生的目检 PNG。另加一条
  !simulator/tests/ref/*.bin 反选——第 115 行的全仓 *.bin 兜底(挡
  sim_netcfg.bin 之类运行产物)会把基线一起挡掉,且反选必须排在它之后
  才生效
- 不引入 LFS:11 x 3200 B = 34.4 KB(160x160 单色打包)。走 LFS 反而新增
  失效面——没拉 LFS 的克隆会拿 pointer 文本去比像素,把"缺基准"换成
  "比不中"。.gitattributes 已有 *.bin binary,check-attr 确认 text unset,
  不会被行尾转换改写
- 基线不会被改写型钩子毁掉:trailing-whitespace / end-of-file-fixer 声明
  types: [text],位图含 NUL 被判二进制 → 实测 Skipped;索引 blob、磁盘、
  主树参照三方哈希 11/11 一致
- 新增 11 个基线;同步 5 份文档与 3 处脚本口径:缺基准的提示从"首次/换机
  请加 --update"改为"检出不完整 → git checkout -- simulator/tests/ref/ 取回,
  不要用 --update 就地造基准"(旧提示正是自我实现型基准的来源)
- 顺带修掉 simulator/tests/README.md 两处与实现不符的描述:基准写成 PNG
  (实为 .bin)、regen_ref_png.py 写成"重建黄金参考"(它只出目检图,基准
  由 check_content_pages.py --update 刷)
- .pre-commit-config.yaml 只改注释(原文明确断言 ref/ "永远不会进 git
  索引",已被本改动推翻);ui-golden 的 files 面覆盖 simulator/tests/,
  基线被改即触发回归,刷参考从此在 git diff 里显形

历史口径按纪律冻结:UI_自动化测试流程 2026-09-10 的"整目录不入库"等 6 处
变更记录行不改写,以新行登记反转。

实测:@build 0 错 0 警(Code=213520,与内存台账一致);ui-golden Passed;
pre-commit run --all-files = 36 Passed / 0 Failed(RC=0)。
2026-10-22 06:17:00 +08:00

72 lines
2.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
regen_ref_png.py — 由黄金参考 .bin 批量重生成目检用 PNG(simulator/tests/ref/*.png)。
背景:ref/*.png 是本地目检调试产物(.gitignore 忽略;入库的基准是同名 .bin),
**不会**随 .bin 参考自动更新。
刷过 `check_content_pages.py --update` 或改了字体/视觉后,必须重跑本脚本,否则 PNG
仍是旧渲染(缺字/错位,看似"乱码")。
用法(仓库根目录;PIL 依赖用 .venv,见 AGENTS.md「Python 环境」):
.venv\\Scripts\\python.exe simulator/tests/regen_ref_png.py
.venv\\Scripts\\python.exe simulator/tests/regen_ref_png.py --scale 4
.venv\\Scripts\\python.exe simulator/tests/regen_ref_png.py --no-invert # 白字黑底(设备原样)
默认 `--scale 6 --invert`(深字白底,便于目检)。
退出码:0 全部成功;1 无 .bin 参考 / 有文件转换失败。
"""
import argparse
import importlib.util
import sys
from pathlib import Path
HERE = Path(__file__).resolve().parent # simulator/tests/
REF_DIR = HERE / "ref"
I1_TO_PNG = HERE.parent / "i1_to_png.py" # simulator/i1_to_png.py
def _load_i1_to_png():
"""从 simulator/i1_to_png.py 载入转换模块(目录不同,不能直接 import)。"""
spec = importlib.util.spec_from_file_location("i1_to_png", I1_TO_PNG)
mod = importlib.util.module_from_spec(spec)
spec.loader.exec_module(mod)
return mod
def main():
ap = argparse.ArgumentParser(description="由 ref/*.bin 批量重生成目检 PNG")
ap.add_argument("--scale", type=int, default=6, help="放大倍数(默认 6)")
ap.add_argument("--invert", dest="invert", action="store_true", default=True,
help="前景/背景互换:深字白底(默认开,便于目检)")
ap.add_argument("--no-invert", dest="invert", action="store_false",
help="关闭互换:白字黑底(与设备显示一致)")
args = ap.parse_args()
if not I1_TO_PNG.exists():
print("FAIL: 找不到 %s" % I1_TO_PNG)
return 1
bins = sorted(REF_DIR.glob("*.bin"))
if not bins:
print("FAIL: %s 下没有 .bin 参考(先运行 check_content_pages.py --update)" % REF_DIR)
return 1
i1_to_png = _load_i1_to_png()
ok = 0
for b in bins:
try:
out = i1_to_png.i1_to_png(str(b), scale=args.scale, invert=args.invert)
print(" %-24s -> %s" % (b.name, Path(out).name))
ok += 1
except Exception as e: # 单文件失败不中断其余
print(" %-24s FAIL: %s" % (b.name, e))
print("%s: %d/%d 张 PNG 已生成(scale=%d invert=%s)"
% ("PASS" if ok == len(bins) else "FAIL", ok, len(bins), args.scale, args.invert))
return 0 if ok == len(bins) else 1
if __name__ == "__main__":
sys.exit(main())