#!/usr/bin/env python3 # -*- coding: utf-8 -*- """色板基线生成器——palette_check 双门②基线的建档与刷新件。 产出两张 1×N 条带 PNG 落 game/tests/golden/palette_baseline/(图像白名单在册目录): ui_tokens.png = ui_kit.gd 全量 Color8 常量唯一色值(token 板现役值快照) art_snapshot.png = 现役素材(game/assets/art 递归)全量唯一色快照(像素板+各屏环境子板) palette_check --baseline 取目录下全部 PNG 的唯一色并集为「既有色板」;基线缺一张 即漏判——基线刷新必须重生成全套。维护纪律:素材批收尾跑一次本器刷新并随批提交 (新色过门②后须入基线,否则下批扫描把已过门的新色再报新增)。 用法: python tools/gen_palette_baseline.py [--repo <仓库根>] 退出码: 0 成功 / 2 前置缺位(ui_kit.gd 或素材目录缺 / 素材零 PNG) """ import argparse import os import re import sys from PIL import Image sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) from palette_check import palette_of # 排除全透明的唯一色提取——与检查器同口径 def strip_comments(text): """剔 GDScript 行注释与字符串字面量,防注释里举的色值被误收进 token 快照。""" out = [] for line in text.split("\n"): i = line.find("#") if i != -1: line = line[:i] out.append(line) return "\n".join(out) def token_cols(ui_kit_path): """ui_kit.gd 全量 Color8 唯一色值集合。""" text = strip_comments(open(ui_kit_path, encoding="utf-8").read()) vals = re.findall(r"Color8\((\d+),\s*(\d+),\s*(\d+)\)", text) return sorted(set((int(r), int(g), int(b)) for r, g, b in vals)) def scan_dirs(roots): """递归扫 PNG,唯一色并集(含像素位置首见序不保——并集无序)。""" cols = set() count = 0 for root in roots: for dirpath, _, names in os.walk(root): for fn in sorted(names): if fn.lower().endswith(".png"): c, _n = palette_of(os.path.join(dirpath, fn)) cols |= c count += 1 return cols, count def write_strip(cols, out_path): """1×N 条带 PNG(一色一像素列)。""" cols = sorted(cols) im = Image.new("RGB", (len(cols), 1)) for i, c in enumerate(cols): im.putpixel((i, 0), c) im.save(out_path) return len(cols) def main(): if hasattr(sys.stdout, "reconfigure"): sys.stdout.reconfigure(encoding="utf-8", errors="replace") ap = argparse.ArgumentParser(description="色板基线生成器(token∪素材快照)") ap.add_argument("--repo", default=".", help="仓库根(含 game/ 与 tools/)") args = ap.parse_args() ui_kit = os.path.join(args.repo, "game", "presentation", "views", "ui_kit.gd") artdir = os.path.join(args.repo, "game", "assets", "art") outdir = os.path.join(args.repo, "game", "tests", "golden", "palette_baseline") if not os.path.isfile(ui_kit): print("[gen_palette_baseline] FAIL:ui_kit.gd 缺:%s" % ui_kit) return 2 if not os.path.isdir(artdir): print("[gen_palette_baseline] FAIL:素材目录缺:%s" % artdir) return 2 os.makedirs(outdir, exist_ok=True) tcols = token_cols(ui_kit) n_t = write_strip(tcols, os.path.join(outdir, "ui_tokens.png")) acols, npng = scan_dirs([artdir]) if npng == 0: print("[gen_palette_baseline] FAIL:素材目录零 PNG(素材未同步)——拒绝生成空快照") return 2 n_a = write_strip(acols, os.path.join(outdir, "art_snapshot.png")) union = set(tcols) | set(acols) print("[gen_palette_baseline] 已生成:ui_tokens.png %d 色 / art_snapshot.png %d 色" "(素材 %d 张 PNG);基线并集 %d 色 → %s" % (n_t, n_a, npng, len(union), outdir)) return 0 if __name__ == "__main__": sys.exit(main())