Add bundled bus fonts and shared font favorites
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
"""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)
|
||||
Reference in New Issue
Block a user