picker/tools/make_icons.py
2026-10-09 13:45:54 +02:00

71 lines
2.5 KiB
Python

"""Generate the PNG app icons (stdlib only, no dependencies).
python tools/make_icons.py
Draws three glowing neon rings on a dark background, matching icons/icon.svg.
"""
import math
import os
import struct
import zlib
BG = (5, 5, 11)
# (cx, cy, r, colour) in a 0..1 unit square
RINGS = [
(0.34, 0.40, 0.17, (255, 46, 99)),
(0.66, 0.40, 0.17, (0, 229, 255)),
(0.50, 0.68, 0.17, (255, 229, 0)),
]
LINE = 0.032 # ring stroke width
GLOW = 0.05 # glow falloff
def render(size, scale=1.0):
"""scale < 1 shrinks the artwork towards the centre (maskable safe zone)."""
rows = []
for py in range(size):
row = bytearray([0]) # filter type 0
for px in range(size):
x = ((px + 0.5) / size - 0.5) / scale + 0.5
y = ((py + 0.5) / size - 0.5) / scale + 0.5
r, g, b = (c / 255 for c in BG)
for cx, cy, rr, col in RINGS:
d = abs(math.hypot(x - cx, y - cy) - rr)
aa = 1.0 / (size * scale)
core = min(1.0, max(0.0, (LINE / 2 - d) / aa + 0.5))
glow = math.exp(-max(0.0, d - LINE / 2) / GLOW) * 0.55
k = max(core, glow)
cr, cg, cb = (c / 255 for c in col)
# additive, like the neon theme
r, g, b = r + cr * k, g + cg * k, b + cb * k
if core > 0: # white-hot centre line
w = max(0.0, 1 - d / (LINE * 0.18)) * 0.7
r, g, b = r + w, g + w, b + w
row += bytes(min(255, int(v * 255 + 0.5)) for v in (r, g, b))
rows.append(bytes(row))
return b"".join(rows)
def write_png(path, size, raw):
def chunk(tag, data):
c = struct.pack(">I", len(data)) + tag + data
return c + struct.pack(">I", zlib.crc32(tag + data) & 0xFFFFFFFF)
ihdr = struct.pack(">IIBBBBB", size, size, 8, 2, 0, 0, 0) # 8-bit RGB
png = b"\x89PNG\r\n\x1a\n" + chunk(b"IHDR", ihdr) + chunk(b"IDAT", zlib.compress(raw, 9)) + chunk(b"IEND", b"")
with open(path, "wb") as f:
f.write(png)
print("wrote", path)
def main():
out = os.path.join(os.path.dirname(__file__), "..", "icons")
os.makedirs(out, exist_ok=True)
write_png(os.path.join(out, "icon-192.png"), 192, render(192))
write_png(os.path.join(out, "icon-512.png"), 512, render(512))
write_png(os.path.join(out, "icon-maskable-512.png"), 512, render(512, scale=0.78))
write_png(os.path.join(out, "apple-touch-icon.png"), 180, render(180, scale=0.9))
if __name__ == "__main__":
main()