Files
matrix-screen-controller/核桃派软件源代码/scripts/proof_bus_font.py
T

86 lines
4.5 KiB
Python

"""Generate offline inspection sheets from the actual text-layer renderer."""
from __future__ import annotations
import argparse
from collections import defaultdict
import hashlib
import json
from pathlib import Path
import sys
from PIL import Image, ImageDraw
ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT))
from app.display.text_renderer import TextOptions, render_text_layer
from app.fonts.store import FontCatalog
from build_bus_font import gb2312_codepoints
def proof(output: Path, reference: Path | None = None, height: int = 16) -> None:
output.mkdir(parents=True, exist_ok=True)
catalog = FontCatalog(output / "isolated-data")
width = height // 2
font_id = f"builtin:walnut-bus-{width}x{height}"
cps = sorted(gb2312_codepoints())
fingerprints = defaultdict(list)
grey, blank, boundary = [], [], []
densities = []
for cp in cps:
layer = render_text_layer(TextOptions(text=chr(cp), font=font_id, size=height),
size=(width, height), font_resolver=catalog.resolve)
alpha = layer.getchannel("A")
values = set(alpha.tobytes())
if values - {0, 255}:
grey.append(cp)
if not alpha.getbbox() and cp not in (32, 0x3000):
blank.append(cp)
if alpha.crop((width - 1, 0, width, height)).getbbox():
boundary.append(cp)
fingerprints[hashlib.sha256(alpha.tobytes()).hexdigest()].append(cp)
densities.append((sum(value != 0 for value in alpha.tobytes()), f"{cp:04X}"))
per_page = 256 if height == 32 else 512
scale = 2 if height == 32 else 3
cell_y = 84 if height == 32 else 64
for page, start in enumerate(range(0, len(cps), per_page)):
sheet = Image.new("RGB", (16 * 48, (per_page // 16) * cell_y), "#111111")
draw = ImageDraw.Draw(sheet)
for index, cp in enumerate(cps[start:start + per_page]):
x, y = (index % 16) * 48, (index // 16) * cell_y
draw.text((x + 1, y), f"{cp:04X}", fill="#aaaaaa")
layer = render_text_layer(TextOptions(text=chr(cp), font=font_id, size=height),
size=(width, height), font_resolver=catalog.resolve)
scaled = layer.resize((width * scale, height * scale), Image.Resampling.NEAREST)
sheet.paste(scaled, (x + 8, y + 14), scaled.getchannel("A"))
sheet.save(output / f"glyphs-{page + 1:02}.png")
samples = ["高铁北站21路", "花鸟市场公交", "开往火车站", "鹤警藏赢鬻", "口日目田由甲", "未末土士人入", "0O1Il5S8B", "ABCxyz0123", ",。!?:;"]
comparison = Image.new("RGB", (768, len(samples) * 160), "#111111")
draw = ImageDraw.Draw(comparison)
for row, text in enumerate(samples):
for column, font in enumerate([font_id] + ([str(reference)] if reference else [])):
layer = render_text_layer(TextOptions(text=text, font=font, size=height),
size=(64, height), font_resolver=catalog.resolve)
draw.text((column * 384 + 4, row * 160 + 2), f"BUS {width}x{height}" if column == 0 else f"REFERENCE {height}px", fill="white")
scaled = layer.resize((256, height * 4), Image.Resampling.NEAREST)
comparison.paste(scaled, (column * 384 + 4, row * 160 + 22), scaled.getchannel("A"))
comparison.save(output / "comparison.png")
result = {"glyph_count": len(cps), "grey": grey, "blank": blank,
"right_edge_lit": boundary,
"duplicates": [[f"{cp:04X}" for cp in group] for group in fingerprints.values() if len(group) > 1]}
result["densest_32"] = [{"codepoint": cp, "lit_pixels": count, "density": count / 128}
for count, cp in sorted(densities, reverse=True)[:32]]
for item in result["densest_32"]:
item["density"] = item["lit_pixels"] / (width * height)
(output / "audit.json").write_text(json.dumps(result, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
print(json.dumps({"grey": len(grey), "blank": len(blank), "right_edge_lit": len(boundary),
"duplicate_groups": len(result["duplicates"])}))
if __name__ == "__main__":
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--output", required=True, type=Path)
parser.add_argument("--reference", type=Path)
parser.add_argument("--height", type=int, choices=(16, 32), default=16)
args = parser.parse_args()
proof(args.output, args.reference, args.height)