#!/usr/bin/env python3 """Draw desktop/icon-source.png — the 1024² master the icon set is cut from. The wiki's own mark is the ∑ in the sidebar (AppHeader.vue's .logo-mark) over the dark reading surface, so the app icon is that: the sigma, in the accent the wiki wears by default, on the dark navy of its dark theme. python3 desktop/make-icon.py # writes desktop/icon-source.png npm run desktop:icons # cuts src-tauri/icons/ from it Requires Pillow (pip install pillow). Nothing else in the project uses it — this is build tooling, not app code. """ from pathlib import Path from PIL import Image, ImageDraw, ImageFont SIZE = 1024 PAD = 64 # the margin macOS wants round an app icon; harmless elsewhere RADIUS = 200 TOP = (16, 21, 44) # the navy a touch above --bg, so the square reads as an object BOTTOM = (6, 8, 14) # ... down to just under it ACCENT = (124, 140, 255) # --accent, dark theme (#7c8cff) MARK = "\u2211" # ∑ — the wiki's mark FONTS = [ "/usr/share/fonts/truetype/dejavu/DejaVuSerif-Bold.ttf", "/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", "/usr/share/fonts/truetype/liberation/LiberationSerif-Bold.ttf", ] OUT = Path(__file__).resolve().parent / "icon-source.png" def load_font(size: int) -> ImageFont.FreeTypeFont: """The first system font that actually carries a sigma.""" for path in FONTS: try: font = ImageFont.truetype(path, size) except OSError: continue if font.getbbox(MARK)[2] > 0: return font raise SystemExit(f"no font with a {MARK} found — look for one of: {', '.join(FONTS)}") def main() -> None: # vertical gradient, then clipped to a rounded square gradient = Image.new("RGB", (1, SIZE)) for y in range(SIZE): t = y / (SIZE - 1) gradient.putpixel((0, y), tuple(round(a + (b - a) * t) for a, b in zip(TOP, BOTTOM))) gradient = gradient.resize((SIZE, SIZE)) mask = Image.new("L", (SIZE, SIZE), 0) ImageDraw.Draw(mask).rounded_rectangle( [PAD, PAD, SIZE - PAD, SIZE - PAD], radius=RADIUS, fill=255 ) icon = Image.new("RGBA", (SIZE, SIZE), (0, 0, 0, 0)) icon.paste(gradient, (0, 0), mask) draw = ImageDraw.Draw(icon) # a hairline of accent light along the edge, so the dark square does not # vanish into a dark taskbar draw.rounded_rectangle( [PAD, PAD, SIZE - PAD, SIZE - PAD], radius=RADIUS, outline=(124, 140, 255, 56), width=3 ) font = load_font(600) left, top, right, bottom = draw.textbbox((0, 0), MARK, font=font) w, h = right - left, bottom - top # centred on the box the glyph is drawn in, not on its typographic cell: # an ascent-based centre would sit the sigma high draw.text( ((SIZE - w) / 2 - left, (SIZE - h) / 2 - top), MARK, font=font, fill=ACCENT + (255,), ) icon.save(OUT) print(f"wrote {OUT}") if __name__ == "__main__": main()