#!/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()