V0.3
This commit is contained in:
@@ -0,0 +1,123 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Génère les deux images de l'installeur NSIS à partir du logo de l'app.
|
||||
|
||||
python scripts/installer-art.py
|
||||
|
||||
NSIS impose du BMP à des tailles fixes :
|
||||
· sidebar.bmp 164 x 314 — panneau de gauche (accueil et fin)
|
||||
· header.bmp 150 x 57 — bandeau des pages intermédiaires
|
||||
|
||||
Les images sont versionnées dans src-tauri/installer/ : ce script n'est à
|
||||
relancer que si le logo ou les couleurs de marque changent (il demande
|
||||
Pillow, qui n'est PAS une dépendance du projet).
|
||||
"""
|
||||
|
||||
from pathlib import Path
|
||||
from PIL import Image, ImageDraw, ImageFont
|
||||
|
||||
ROOT = Path(__file__).resolve().parent.parent
|
||||
OUT = ROOT / "src-tauri" / "installer"
|
||||
ICON = ROOT / "src-tauri" / "icons" / "128x128@2x.png"
|
||||
|
||||
# Dégradé du logo (public/logo.svg)
|
||||
INDIGO = (99, 102, 241)
|
||||
TEAL = (20, 184, 166)
|
||||
INK = (16, 16, 24)
|
||||
INK_SOFT = (30, 29, 48)
|
||||
|
||||
|
||||
def font(size: int, bold: bool = False):
|
||||
"""Segoe UI si disponible, repli sur la police par défaut de Pillow."""
|
||||
for name in (["segoeuib.ttf", "seguisb.ttf"] if bold else ["segoeui.ttf"]):
|
||||
try:
|
||||
return ImageFont.truetype(f"C:/Windows/Fonts/{name}", size)
|
||||
except OSError:
|
||||
continue
|
||||
return ImageFont.load_default()
|
||||
|
||||
|
||||
def lerp(a, b, t):
|
||||
return tuple(round(a[i] + (b[i] - a[i]) * t) for i in range(3))
|
||||
|
||||
|
||||
def vertical_gradient(size, top, bottom):
|
||||
w, h = size
|
||||
img = Image.new("RGB", size)
|
||||
d = ImageDraw.Draw(img)
|
||||
for y in range(h):
|
||||
d.line([(0, y), (w, y)], fill=lerp(top, bottom, y / max(h - 1, 1)))
|
||||
return img
|
||||
|
||||
|
||||
def horizontal_gradient(size, left, right):
|
||||
w, h = size
|
||||
img = Image.new("RGB", size)
|
||||
d = ImageDraw.Draw(img)
|
||||
for x in range(w):
|
||||
d.line([(x, 0), (x, h)], fill=lerp(left, right, x / max(w - 1, 1)))
|
||||
return img
|
||||
|
||||
|
||||
def logo(px: int) -> Image.Image:
|
||||
return Image.open(ICON).convert("RGBA").resize((px, px), Image.LANCZOS)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------
|
||||
# Panneau latéral 164 x 314 — fond sombre, logo, nom, liseré de marque
|
||||
# ---------------------------------------------------------------------
|
||||
def sidebar() -> Image.Image:
|
||||
W, H = 164, 314
|
||||
img = vertical_gradient((W, H), INK_SOFT, INK)
|
||||
d = ImageDraw.Draw(img, "RGBA")
|
||||
|
||||
# Halo indigo diffus derrière le logo, pour éviter le fond plat.
|
||||
cx, cy = W // 2, 96
|
||||
for r in range(92, 0, -4):
|
||||
alpha = int(30 * (1 - r / 92) ** 2)
|
||||
d.ellipse([cx - r, cy - r, cx + r, cy + r], fill=(*INDIGO, alpha))
|
||||
|
||||
mark = logo(76)
|
||||
img.paste(mark, (cx - 38, cy - 38), mark)
|
||||
|
||||
title = font(15, bold=True)
|
||||
sub = font(11)
|
||||
d.text((cx, 168), "GameDev", font=title, fill=(255, 255, 255), anchor="mm")
|
||||
d.text((cx, 186), "Tracker", font=title, fill=(255, 255, 255), anchor="mm")
|
||||
d.text((cx, 210), "Gestion de projet", font=sub, fill=(150, 148, 170), anchor="mm")
|
||||
d.text((cx, 225), "de jeu vidéo", font=sub, fill=(150, 148, 170), anchor="mm")
|
||||
|
||||
# Liseré dégradé en pied de panneau : la signature visuelle de la marque.
|
||||
bar = horizontal_gradient((W, 4), INDIGO, TEAL)
|
||||
img.paste(bar, (0, H - 4))
|
||||
return img
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------
|
||||
# Bandeau 150 x 57 — fond SOMBRE, accordé à MUI_BGCOLOR du template
|
||||
# ---------------------------------------------------------------------
|
||||
def header() -> Image.Image:
|
||||
W, H = 150, 57
|
||||
img = Image.new("RGB", (W, H), INK)
|
||||
d = ImageDraw.Draw(img)
|
||||
|
||||
mark = logo(34)
|
||||
img.paste(mark, (W - 34 - 12, (H - 34) // 2), mark)
|
||||
|
||||
name = font(11, bold=True)
|
||||
d.text((W - 56, H // 2 - 7), "GameDev", font=name, fill=(255, 255, 255), anchor="rm")
|
||||
d.text((W - 56, H // 2 + 7), "Tracker", font=name, fill=(255, 255, 255), anchor="rm")
|
||||
|
||||
bar = horizontal_gradient((W, 3), INDIGO, TEAL)
|
||||
img.paste(bar, (0, H - 3))
|
||||
return img
|
||||
|
||||
|
||||
OUT.mkdir(parents=True, exist_ok=True)
|
||||
for name, image in (("sidebar", sidebar()), ("header", header())):
|
||||
path = OUT / f"{name}.bmp"
|
||||
# BMP 24 bits sans alpha : le seul format que NSIS accepte partout.
|
||||
image.convert("RGB").save(path, "BMP")
|
||||
print(f" {path.relative_to(ROOT)} {image.width}x{image.height}")
|
||||
|
||||
print("\nImages générées.")
|
||||
Reference in New Issue
Block a user