# Baut aus dem Original-Logo den Satz an Marken-Dateien: # - die Wolfskopf-Marke freigestellt (fuer Favicon, Avatar, kleine Groessen) # - das volle Lockup beschnitten (fuer Kopfzeilen, Discord, OG-Bilder) # - Icons auf dunklem Grund (iOS und Gitea-Standardavatar moegen kein Alpha) # - SVG-Huellen mit eingebettetem PNG (Gitea will .svg, das Original ist # eine Rastergrafik mit Verlaeufen — nachvektorisieren wuerde matschen) import base64 import io import pathlib from PIL import Image, ImageDraw QUELLE = pathlib.Path('A:/Users/DAR/logo.png') MARKE = pathlib.Path('A:/eco/dc_devlog_bot/docs/brand') GITEA = pathlib.Path('A:/eco/Gitea/data/gitea/public/assets/img') FRONTEND = pathlib.Path('A:/eco/dc_devlog_bot/frontend/public') # Kopf mit Ohrenspitzen und etwas Schulter, ohne Schriftzug (im 2048er Original) KOPF = (330, 20, 1740, 1430) DUNKEL = (10, 10, 10, 255) # --bg der Marke for d in (MARKE, GITEA, FRONTEND): d.mkdir(parents=True, exist_ok=True) original = Image.open(QUELLE).convert('RGBA') marke = original.crop(KOPF) lockup = original.crop(original.getchannel('A').getbbox()) def png_bytes(bild, groesse=None): aus = bild if groesse is None else bild.resize((groesse, groesse), Image.LANCZOS) puffer = io.BytesIO() aus.save(puffer, 'PNG', optimize=True) return puffer.getvalue() def gerundet(bild, kante, radius_anteil=0.22, rand=0.08): """Marke mittig auf dunklem, abgerundetem Quadrat — deckend.""" flaeche = Image.new('RGBA', (kante, kante), (0, 0, 0, 0)) maske = Image.new('L', (kante, kante), 0) ImageDraw.Draw(maske).rounded_rectangle( (0, 0, kante - 1, kante - 1), radius=int(kante * radius_anteil), fill=255) flaeche.paste(Image.new('RGBA', (kante, kante), DUNKEL), (0, 0), maske) innen = int(kante * (1 - 2 * rand)) klein = bild.resize((innen, innen), Image.LANCZOS) flaeche.alpha_composite(klein, ((kante - innen) // 2, (kante - innen) // 2)) return flaeche def svg_huelle(daten, kante): """SVG mit eingebettetem PNG — gueltig, und Gitea nimmt nur .svg.""" b64 = base64.b64encode(daten).decode('ascii') return ( f'' f'' f'\n' ) geschrieben = [] def schreib(pfad, daten): pfad.write_bytes(daten if isinstance(daten, bytes) else daten.encode('utf-8')) geschrieben.append((pfad, len(daten))) # ── Quelldateien im Repo, versioniert ──────────────── schreib(MARKE / 'mark.png', png_bytes(marke, 1024)) schreib(MARKE / 'lockup.png', png_bytes(lockup)) # ── Gitea ──────────────────────────────────────────── # Navbar-Logo und Favicon: die Marke, das Lockup ist bei 30 px unlesbar. # 192 px reichen — Gitea zeigt das Logo in der Navbar mit rund 30 px, und die # Datei haengt an jedem Seitenaufruf. schreib(GITEA / 'logo.svg', svg_huelle(png_bytes(marke, 192), 192)) schreib(GITEA / 'favicon.svg', svg_huelle(png_bytes(gerundet(marke, 128), 128), 128)) schreib(GITEA / 'apple-touch-icon.png', png_bytes(gerundet(marke, 180))) schreib(GITEA / 'avatar_default.png', png_bytes(gerundet(marke, 512))) # ── Hub + Bot-Produktseite ─────────────────────────── schreib(FRONTEND / 'favicon.svg', svg_huelle(png_bytes(gerundet(marke, 128), 128), 128)) schreib(FRONTEND / 'apple-touch-icon.png', png_bytes(gerundet(marke, 180))) for pfad, n in geschrieben: print(f'{n/1024:8.1f} KB {pfad}') # ── Vorschau: liest die Marke in klein noch? ───────── # Landet neben diesem Skript, oben auf hellem, unten auf dunklem Grund — # so sieht man vor dem Ausrollen, ab welcher Groesse es kippt. KANTEN = (16, 32, 64, 128) breite = sum(k + 40 for k in KANTEN) + 30 vorschau = Image.new('RGBA', (breite, 200), (24, 24, 28, 255)) x = 30 for kante in KANTEN: for grund, y in (((250, 250, 250, 255), 20), (DUNKEL, 110)): feld = Image.new('RGBA', (kante + 16, kante + 16), grund) feld.alpha_composite(gerundet(marke, kante), (8, 8)) vorschau.alpha_composite(feld, (x, y)) x += kante + 40 ziel = pathlib.Path(__file__).parent / 'preview.png' vorschau.convert('RGB').save(ziel) print(f'\nVorschau ({"/".join(map(str, KANTEN))} px): {ziel}')