Files
LithosAnanake/tools/svg_to_png.py
T

79 lines
2.5 KiB
Python

#!/usr/bin/env python3
"""One-off: render every tracked .svg to a same-named .png via headless Chromium.
Not part of the build; run manually. Leaves the source .svg untouched."""
import re
import subprocess
import sys
from pathlib import Path
CHROME = "/opt/pw-browsers/chromium-1194/chrome-linux/chrome"
ROOT = Path("/home/user/StarForth")
DIM_RE = re.compile(r'(width|height)\s*=\s*["\']([0-9.]+)(pt|px)?["\']')
VIEWBOX_RE = re.compile(r'viewBox\s*=\s*["\']([\d.\-]+)\s+([\d.\-]+)\s+([\d.\-]+)\s+([\d.\-]+)["\']')
def get_dims(svg_path: Path):
text = svg_path.read_text(errors="replace")
svg_open = re.search(r"<svg\b[^>]*>", text)
head = svg_open.group(0) if svg_open else text[:4000]
dims = {}
for m in DIM_RE.finditer(head):
name, val, unit = m.group(1), float(m.group(2)), m.group(3) or "px"
if name in dims:
continue # keep only the first (root <svg>) match
px = val * (4 / 3) if unit == "pt" else val
dims[name] = px
if "width" in dims and "height" in dims:
return int(round(dims["width"])), int(round(dims["height"]))
vb = VIEWBOX_RE.search(head)
if vb:
w, h = float(vb.group(3)), float(vb.group(4))
return int(round(w)), int(round(h))
return 1024, 768
def render(svg_path: Path) -> bool:
png_path = svg_path.with_suffix(".png")
w, h = get_dims(svg_path)
w = max(w, 16)
h = max(h, 16)
cmd = [
CHROME, "--headless", "--disable-gpu", "--no-sandbox",
"--hide-scrollbars",
f"--screenshot={png_path}",
f"--window-size={w},{h}",
"--force-device-scale-factor=2",
"--default-background-color=00000000",
f"file://{svg_path}",
]
r = subprocess.run(cmd, capture_output=True, text=True, timeout=60)
ok = png_path.exists() and png_path.stat().st_size > 0
if not ok:
print(f"FAIL {svg_path}: {r.stderr[-500:]}", file=sys.stderr)
return ok
def main():
svgs = sorted(ROOT.rglob("*.svg"))
svgs = [s for s in svgs if "node_modules" not in s.parts]
print(f"Found {len(svgs)} SVGs")
failed = []
for i, svg in enumerate(svgs, 1):
rel = svg.relative_to(ROOT)
ok = render(svg)
status = "ok" if ok else "FAIL"
print(f"[{i}/{len(svgs)}] {status} {rel}")
if not ok:
failed.append(rel)
if failed:
print(f"\n{len(failed)} failed:")
for f in failed:
print(f" {f}")
else:
print("\nAll converted.")
if __name__ == "__main__":
main()