from __future__ import annotations import struct import zlib from pathlib import Path ROOT = Path(__file__).resolve().parents[1] / "app" / "static" / "images" def png_chunk(tag: bytes, data: bytes) -> bytes: return struct.pack("!I", len(data)) + tag + data + struct.pack("!I", zlib.crc32(tag + data) & 0xFFFFFFFF) def save_png(path: Path, width: int, height: int, rgba_rows: list[bytes]) -> None: raw = b"".join(b"\x00" + row for row in rgba_rows) header = struct.pack("!IIBBBBB", width, height, 8, 6, 0, 0, 0) content = b"".join( [ b"\x89PNG\r\n\x1a\n", png_chunk(b"IHDR", header), png_chunk(b"IDAT", zlib.compress(raw, 9)), png_chunk(b"IEND", b""), ] ) path.write_bytes(content) def lerp(a: int, b: int, t: float) -> int: return int(a + (b - a) * t) def rounded_square_icon(size: int) -> list[bytes]: rows = [] radius = size * 0.22 for y in range(size): row = bytearray() for x in range(size): dx = min(x, size - 1 - x) dy = min(y, size - 1 - y) in_corner = (dx < radius and dy < radius) if in_corner: cx = radius - dx cy = radius - dy inside = cx * cx + cy * cy <= radius * radius else: inside = True if not inside: row.extend((0, 0, 0, 0)) continue t = (x + y) / (2 * size) r = lerp(37, 52, t) g = lerp(99, 211, t) b = lerp(235, 153, t) if (x - size * 0.5) ** 2 + (y - size * 0.48) ** 2 < (size * 0.33) ** 2: r, g, b = 250, 252, 255 roof = abs(x - size * 0.5) + (y - size * 0.40) if roof < size * 0.19 and y < size * 0.55: r, g, b = 37, 99, 235 if size * 0.33 < x < size * 0.67 and size * 0.52 < y < size * 0.80: r, g, b = 159, 208, 255 star_x = x - size * 0.68 star_y = y - size * 0.28 if abs(star_x) + abs(star_y) < size * 0.06 or (abs(star_x) < size * 0.018 or abs(star_y) < size * 0.018): r, g, b = 245, 158, 11 row.extend((r, g, b, 255)) rows.append(bytes(row)) return rows def badge_icon(size: int) -> list[bytes]: rows = [] radius = size * 0.48 cx = cy = size / 2 for y in range(size): row = bytearray() for x in range(size): if (x - cx) ** 2 + (y - cy) ** 2 > radius ** 2: row.extend((0, 0, 0, 0)) continue row.extend((37, 99, 235, 255)) rows.append(bytes(row)) return rows def main() -> None: ROOT.mkdir(parents=True, exist_ok=True) save_png(ROOT / "pwa-icon-192.png", 192, 192, rounded_square_icon(192)) save_png(Path(__file__).resolve().parents[1] / "icon.png", 256, 256, rounded_square_icon(256)) save_png(ROOT / "pwa-icon-512.png", 512, 512, rounded_square_icon(512)) save_png(ROOT / "apple-touch-icon.png", 180, 180, rounded_square_icon(180)) save_png(ROOT / "pwa-badge.png", 96, 96, badge_icon(96)) if __name__ == "__main__": main()