import pathlib
import re
import shutil
import subprocess
import sys
import tempfile
TARGETS = [
("branding/logo-mark.svg", "branding/logo-mark.png", 480),
("branding/app-icon.svg", "resources/icon.png", 1024),
]
RENDER_AT = 1600
def need(tool):
if not shutil.which(tool):
sys.exit(f"{tool} not found; it is required to rasterize the brand assets.")
def square_viewbox(svg):
match = re.search(r'viewBox="([-\d.]+)\s+([-\d.]+)\s+([-\d.]+)\s+([-\d.]+)"', svg)
if not match:
sys.exit("no viewBox found")
x, y, w, h = (float(v) for v in match.groups())
side = max(w, h) * 1.1 cx, cy = x + w / 2, y + h / 2
box = f'viewBox="{cx - side / 2:.3f} {cy - side / 2:.3f} {side:.3f} {side:.3f}"'
svg = svg[: match.start()] + box + svg[match.end() :]
return re.sub(r'\swidth="[^"]*"\s+height="[^"]*"',
f' width="{RENDER_AT}" height="{RENDER_AT}"', svg, count=1)
def with_backdrop(svg, colour):
box = re.search(r'viewBox="([-\d.]+)\s+([-\d.]+)\s+([-\d.]+)\s+([-\d.]+)"', svg)
x, y, w, h = box.groups()
rect = f'<rect x="{x}" y="{y}" width="{w}" height="{h}" fill="{colour}"/>'
return re.sub(r"(<svg[^>]*>)", r"\1" + rect, svg, count=1)
def render(svg_text, tmp, tag):
src = tmp / f"{tag}.svg"
src.write_text(svg_text)
out = tmp / tag
out.mkdir(exist_ok=True)
subprocess.run(
["qlmanage", "-t", "-s", str(RENDER_AT), "-o", str(out), str(src)],
capture_output=True, check=False,
)
png = out / f"{tag}.svg.png"
if not png.exists():
sys.exit(f"qlmanage produced no output for {tag}")
return png
def main():
for tool in ("qlmanage", "magick"):
need(tool)
if not pathlib.Path("branding/logo-mark.svg").exists():
sys.exit("run this from the repository root")
for source, target, height in TARGETS:
svg = square_viewbox(pathlib.Path(source).read_text())
with tempfile.TemporaryDirectory() as td:
tmp = pathlib.Path(td)
on_white = render(with_backdrop(svg, "#ffffff"), tmp, "white")
on_black = render(with_backdrop(svg, "#000000"), tmp, "black")
alpha = tmp / "alpha.png"
subprocess.run(
["magick", str(on_white), str(on_black), "-compose", "Difference",
"-composite", "-colorspace", "Gray", "-negate", str(alpha)],
check=True,
)
straight = tmp / "straight.png"
subprocess.run(
["magick", str(on_black), str(alpha),
"-compose", "Divide", "-composite", str(straight)],
check=True,
)
subprocess.run(
["magick", str(straight), str(alpha), "-alpha", "off",
"-compose", "CopyOpacity", "-composite",
"-trim", "+repage", "-resize", f"x{height}", f"PNG32:{target}"],
check=True,
)
size = subprocess.run(["magick", "identify", "-format", "%wx%h", target],
capture_output=True, text=True).stdout
print(f"{source:28} -> {target:24} {size}")
if __name__ == "__main__":
main()