Files
schattenpost/web/_gen_icons.py
Claude Code 2f65935cd7 Web: PWA-Icons neu — Umschlag-Logo auf blauem Verlauf
Ersetzt die dunkle Kachel durch den weißen Umschlag auf blauem Diagonal-Verlauf
(icon-192/512.png). Reproduzierbar via web/_gen_icons.py (Pillow, Supersampling),
Logo mit Safe-Zone-Padding -> taugt auch als maskable Icon.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-15 11:29:24 +00:00

60 lines
2.1 KiB
Python

#!/usr/bin/env python3
"""Generiert die PWA-Icons (icon-192/512.png): weißes Umschlag-Logo auf blauem
Verlauf. Reproduzierbar — bei Logo-Änderungen einfach neu laufen lassen.
python3 web/_gen_icons.py
"""
from PIL import Image, ImageDraw
SS = 4 # Supersampling-Faktor für weiche Kanten
GRAD_TL = (91, 155, 255) # #5b9bff oben links
GRAD_BR = (26, 63, 176) # #1a3fb0 unten rechts
INK = (255, 255, 255, 255) # Umschlag in Weiß
# Logo im 48er-Koordinatensystem (identisch zu favicon.svg / Homepage-SVG)
VB = 48.0
LOGO_CX, LOGO_CY = 24.0, 24.75 # Mittelpunkt der Logo-Bounding-Box
LOGO_W = 34.0 # Breite der Bounding-Box
FILL_FRAC = 0.60 # Logo füllt 60 % der Icon-Breite (Maskable-safe)
def diagonal_gradient(size):
g = Image.new("RGB", (64, 64))
px = g.load()
for y in range(64):
for x in range(64):
t = (x + y) / 126.0
px[x, y] = tuple(round(a + (b - a) * t) for a, b in zip(GRAD_TL, GRAD_BR))
return g.resize((size, size), Image.BILINEAR)
def render(size):
W = size * SS
img = diagonal_gradient(W).convert("RGBA")
d = ImageDraw.Draw(img)
scale = (FILL_FRAC * W) / LOGO_W # px pro viewBox-Einheit
cx = cy = W / 2.0
def T(vx, vy): # viewBox -> Pixel (zentriert)
return (cx + (vx - LOGO_CX) * scale, cy + (vy - LOGO_CY) * scale)
sw = max(1, round(3.0 * scale)) # Strichstärke
r = 4.5 * scale # Eckenradius Umschlag
# Umschlag-Körper (abgerundetes Rechteck)
x0, y0 = T(7, 16); x1, y1 = T(41, 40)
d.rounded_rectangle([x0, y0, x1, y1], radius=r, outline=INK, width=sw)
# Klappe (V)
d.line([T(8, 18.5), T(24, 31), T(40, 18.5)], fill=INK, width=sw, joint="curve")
# Kapuze (oberer Ellipsenbogen)
ax0, ay0 = T(17, 9.5); ax1, ay1 = T(31, 22.5)
d.arc([ax0, ay0, ax1, ay1], start=180, end=360, fill=INK, width=sw)
return img.resize((size, size), Image.LANCZOS)
for s in (192, 512):
render(s).save(f"web/icon-{s}.png")
print(f"web/icon-{s}.png geschrieben")