MagicCode/packages/ui/scripts/make-mask.py

66 lines
2.8 KiB
Python
Raw Permalink Normal View History

2026-10-15 22:54:08 +00:00
#!/usr/bin/env python3
"""Génère src/mask-data.ts à partir de assets/mask.png (nécessite Pillow : pip install pillow).
Usage : python3 scripts/make-mask.py [taille] (32 par défaut ; l'image affichée fait taille × taille pixels,
soit taille colonnes × taille/2 lignes de terminal)
Le fond uni (couleur des coins) est rendu transparent, l'image est recadrée au carré puis réduite
en moyennant les couleurs : aucune pixelisation par blocs, aucune réduction de palette.
"""
import sys
from collections import deque
from pathlib import Path
from PIL import Image
N = int(sys.argv[1]) if len(sys.argv) > 1 else 32
root = Path(__file__).resolve().parent.parent
im = Image.open(root / "assets" / "mask.png").convert("RGB")
W, H = im.size
px = im.load()
bg = px[0, 0]
near = lambda c: all(abs(c[i] - bg[i]) <= 12 for i in range(3))
# Fond = zone connectée aux coins et proche de la couleur du fond (le visage crème est isolé par son contour noir).
transparent = [[False] * W for _ in range(H)]
queue = deque([(0, 0), (W - 1, 0), (0, H - 1), (W - 1, H - 1)])
while queue:
x, y = queue.popleft()
if x < 0 or y < 0 or x >= W or y >= H or transparent[y][x] or not near(px[x, y]):
continue
transparent[y][x] = True
queue.extend([(x + 1, y), (x - 1, y), (x, y + 1), (x, y - 1)])
xs = [x for y in range(H) for x in range(W) if not transparent[y][x]]
ys = [y for y in range(H) for x in range(W) if not transparent[y][x]]
x0, x1, y0, y1 = min(xs), max(xs) + 1, min(ys), max(ys) + 1
side = max(x1 - x0, y1 - y0)
ox = x0 - (side - (x1 - x0)) // 2
oy = y0 - (side - (y1 - y0)) // 2
rows = []
for gy in range(N):
row = ""
for gx in range(N):
total = opaque = 0
acc = [0, 0, 0]
for y in range(int(oy + gy * side / N), int(oy + (gy + 1) * side / N) + 1):
for x in range(int(ox + gx * side / N), int(ox + (gx + 1) * side / N) + 1):
total += 1
if 0 <= x < W and 0 <= y < H and not transparent[y][x]:
opaque += 1
for i in range(3):
acc[i] += px[x, y][i]
# moyenne des pixels opaques uniquement (évite le liseré clair du fond) ; transparent si moins de la moitié est opaque
row += "......" if opaque * 2 < total or opaque == 0 else "".join("%02x" % round(a / opaque) for a in acc)
rows.append(row)
lines = "\n".join(f' "{r}",' for r in rows)
(root / "src" / "mask-data.ts").write_text(
"// Fichier généré par scripts/make-mask.py à partir de assets/mask.png : ne pas modifier à la main.\n"
"// Une chaîne par ligne de pixels ; chaque pixel = 6 chiffres hexadécimaux rrggbb, \"......\" = transparent.\n"
f"export const MASK_SIZE = {N};\n\n"
f"export const MASK_DATA: string[] = [\n{lines}\n];\n",
encoding="utf-8",
)
print(f"{N}x{N} écrit dans src/mask-data.ts")