#!/usr/bin/env python3 """ Génère les assets binaires (logo PNG + favicons) depuis la source SVG. Dépendances : Pillow, chromium Usage : python3 scripts/build-assets.py Sorties : docs/assets/alpinux-logo.png → logo 200×200 inclus dans le wiki (MkDocs) /tmp/alpinux-static-assets/ → favicons + logo 512px à uploader sur static.alpinux.org/logo/ """ import subprocess import tempfile import os from pathlib import Path from PIL import Image, ImageDraw, ImageFont REPO = Path(__file__).resolve().parent.parent SVG = REPO / "docs/assets/alpinux-logo.svg" DOCS_OUT = REPO / "docs/assets" CDN_OUT = Path("/tmp/alpinux-static-assets") FONT_R = "/usr/share/fonts/truetype/msttcorefonts/arial.ttf" FONT_B = "/usr/share/fonts/truetype/msttcorefonts/arialbd.ttf" COLOR = (15, 78, 143) # #0f4e8f def render_shapes(svg_path: Path, width: int, height: int) -> Image.Image: """Render SVG shapes via chromium headless (no text).""" html = f""" """ with tempfile.NamedTemporaryFile(suffix=".html", mode="w", delete=False) as f: f.write(html) tmp_html = f.name out_png = tmp_html.replace(".html", ".png") subprocess.run([ "chromium", "--headless", "--disable-gpu", "--no-sandbox", f"--screenshot={out_png}", f"--window-size={width},{height}", f"file://{tmp_html}" ], capture_output=True) img = Image.open(out_png).convert("RGBA") os.unlink(tmp_html) os.unlink(out_png) return img def add_text(canvas: Image.Image) -> Image.Image: """Composite Alpinux text with correct weights onto the canvas.""" draw = ImageDraw.Draw(canvas) size = 30 f_reg = ImageFont.truetype(FONT_R, size) f_bld = ImageFont.truetype(FONT_B, size) parts = [("A", False), ("l", True), ("p", False), ("inux", True)] widths = [] for char, bold in parts: f = f_bld if bold else f_reg bb = f.getbbox(char) widths.append(bb[2] - bb[0]) total_w = sum(widths) x = (canvas.width - total_w) // 2 y = 164 + (36 - size) // 2 + 1 for (char, bold), w in zip(parts, widths): f = f_bld if bold else f_reg bb = f.getbbox(char) draw.text((x - bb[0], y - bb[1]), char, font=f, fill=COLOR) x += w return canvas def build_logo_wiki(docs_out: Path): """Build 200×200 logo PNG → docs/assets/ (servi par MkDocs, non commité).""" shapes = render_shapes(SVG, 200, 164) canvas = Image.new("RGBA", (200, 200), (255, 255, 255, 255)) canvas.paste(shapes, (0, 0)) canvas = add_text(canvas) path = docs_out / "alpinux-logo.png" canvas.convert("RGB").save(path) print(f" {path} (200×200) → wiki MkDocs") def build_logo_cdn(cdn_out: Path): """Build 512×512 logo PNG → CDN (static.alpinux.org/logo/).""" shapes512 = render_shapes(SVG, 512, 421) canvas512 = Image.new("RGBA", (512, 512), (255, 255, 255, 255)) canvas512.paste(shapes512, (0, 0)) draw = ImageDraw.Draw(canvas512) size = 77 f_reg = ImageFont.truetype(FONT_R, size) f_bld = ImageFont.truetype(FONT_B, size) parts = [("A", False), ("l", True), ("p", False), ("inux", True)] widths = [f_bld.getbbox(c)[2]-f_bld.getbbox(c)[0] if b else f_reg.getbbox(c)[2]-f_reg.getbbox(c)[0] for c,b in parts] total_w = sum(widths) x = (512 - total_w) // 2 y = 421 + (91 - size) // 2 + 2 for (char, bold), w in zip(parts, widths): f = f_bld if bold else f_reg bb = f.getbbox(char) draw.text((x - bb[0], y - bb[1]), char, font=f, fill=COLOR) x += w path512 = cdn_out / "alpinux-logo-512.png" canvas512.convert("RGB").save(path512) print(f" {path512} (512×512) → static.alpinux.org/logo/") def build_favicons(cdn_out: Path): """Build favicon PNG set + .ico → CDN (static.alpinux.org/logo/).""" icon_src = render_shapes(SVG, 200, 164).crop((0, 0, 164, 164)) sizes = { "favicon-16.png": 16, "favicon-32.png": 32, "favicon.png": 48, "favicon-96.png": 96, "favicon-192.png": 192, } imgs = {} for name, sz in sizes.items(): img = icon_src.resize((sz, sz), Image.LANCZOS) bg = Image.new("RGBA", (sz, sz), (255, 255, 255, 255)) bg.paste(img, (0, 0)) p = cdn_out / name bg.save(p) imgs[sz] = bg print(f" {p} ({sz}×{sz}) → static.alpinux.org/logo/") ico = cdn_out / "favicon.ico" imgs[16].save(ico, format="ICO", sizes=[(16,16),(32,32),(48,48)], append_images=[imgs[32], imgs[48]]) print(f" {ico} (multi-size: 16+32+48) → static.alpinux.org/logo/") def main(): DOCS_OUT.mkdir(parents=True, exist_ok=True) CDN_OUT.mkdir(parents=True, exist_ok=True) print("Génération des assets Alpinux...") print() print("── Logo wiki (docs/assets/) ──") build_logo_wiki(DOCS_OUT) print() print("── CDN static.alpinux.org/logo/ ──") build_logo_cdn(CDN_OUT) build_favicons(CDN_OUT) print() print(f"Fichiers CDN dans : {CDN_OUT}") print("À uploader sur : static.alpinux.org/logo/") print() print("Ensuite : mkdocs build") if __name__ == "__main__": main()