71 lines
2.5 KiB
Python
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()
|