Zonza : dictée vocale locale macOS (MLX-Whisper + cercle pulsant)
Reconstruction propre de l'ancien projet Dictée. Bundle id neuf (cloud.mrtechlab.zonza), chemin de build unique vers /Applications (plus jamais de builds /tmp enregistrés dans LaunchServices). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
Executable
+22
@@ -0,0 +1,22 @@
|
||||
#!/bin/bash
|
||||
# Convertit assets/icon.png (1024²) en assets/icon.icns (multi-résolution macOS).
|
||||
# Utilise sips + iconutil (natifs macOS). Lancer : ./assets/make_icns.sh
|
||||
set -euo pipefail
|
||||
HERE="$(cd "$(dirname "$0")" && pwd)"
|
||||
PNG="$HERE/icon.png"
|
||||
ICONSET="$HERE/icon.iconset"
|
||||
ICNS="$HERE/icon.icns"
|
||||
|
||||
[ -f "$PNG" ] || { echo "icon.png manquant — lance d'abord make_icon.py"; exit 1; }
|
||||
rm -rf "$ICONSET"; mkdir -p "$ICONSET"
|
||||
|
||||
# tailles requises par iconutil (px et @2x)
|
||||
for SZ in 16 32 64 128 256 512; do
|
||||
sips -z $SZ $SZ "$PNG" --out "$ICONSET/icon_${SZ}x${SZ}.png" >/dev/null
|
||||
DBL=$((SZ * 2))
|
||||
sips -z $DBL $DBL "$PNG" --out "$ICONSET/icon_${SZ}x${SZ}@2x.png" >/dev/null
|
||||
done
|
||||
|
||||
iconutil -c icns "$ICONSET" -o "$ICNS"
|
||||
rm -rf "$ICONSET"
|
||||
echo "icns écrit : $ICNS"
|
||||
@@ -0,0 +1,64 @@
|
||||
"""Génère assets/icon.png (1024×1024) : un micro stylisé sur un carré violet dégradé.
|
||||
|
||||
Reproductible et sans dépendance externe (Pillow seulement). Lancer : python assets/make_icon.py
|
||||
"""
|
||||
import os
|
||||
|
||||
from PIL import Image, ImageDraw
|
||||
|
||||
SIZE = 1024
|
||||
BG_TOP = (130, 80, 235) # violet
|
||||
BG_BOT = (85, 50, 180) # violet plus foncé (dégradé vertical)
|
||||
MIC = (255, 255, 255)
|
||||
|
||||
|
||||
def _rounded_gradient(size, radius):
|
||||
"""Carré arrondi avec dégradé vertical."""
|
||||
base = Image.new("RGBA", (size, size), (0, 0, 0, 0))
|
||||
grad = Image.new("RGBA", (size, size))
|
||||
for y in range(size):
|
||||
t = y / (size - 1)
|
||||
r = int(BG_TOP[0] * (1 - t) + BG_BOT[0] * t)
|
||||
g = int(BG_TOP[1] * (1 - t) + BG_BOT[1] * t)
|
||||
b = int(BG_TOP[2] * (1 - t) + BG_BOT[2] * t)
|
||||
for x in range(size):
|
||||
grad.putpixel((x, y), (r, g, b, 255))
|
||||
mask = Image.new("L", (size, size), 0)
|
||||
ImageDraw.Draw(mask).rounded_rectangle([0, 0, size, size], radius=radius, fill=255)
|
||||
base.paste(grad, (0, 0), mask)
|
||||
return base
|
||||
|
||||
|
||||
def make_icon(path):
|
||||
img = _rounded_gradient(SIZE, radius=int(SIZE * 0.22))
|
||||
d = ImageDraw.Draw(img)
|
||||
cx = SIZE / 2
|
||||
# corps du micro (capsule arrondie)
|
||||
mic_w, mic_h = SIZE * 0.26, SIZE * 0.40
|
||||
top = SIZE * 0.20
|
||||
d.rounded_rectangle(
|
||||
[cx - mic_w / 2, top, cx + mic_w / 2, top + mic_h],
|
||||
radius=mic_w / 2, fill=MIC,
|
||||
)
|
||||
# arceau (support en U sous le micro)
|
||||
arc_r = SIZE * 0.20
|
||||
arc_cy = top + mic_h * 0.55
|
||||
d.arc(
|
||||
[cx - arc_r, arc_cy - arc_r, cx + arc_r, arc_cy + arc_r],
|
||||
start=20, end=160, fill=MIC, width=int(SIZE * 0.035),
|
||||
)
|
||||
# pied du micro
|
||||
foot_top = arc_cy + arc_r
|
||||
d.line([cx, foot_top, cx, foot_top + SIZE * 0.10], fill=MIC, width=int(SIZE * 0.035))
|
||||
d.line(
|
||||
[cx - SIZE * 0.10, foot_top + SIZE * 0.10, cx + SIZE * 0.10, foot_top + SIZE * 0.10],
|
||||
fill=MIC, width=int(SIZE * 0.035),
|
||||
)
|
||||
os.makedirs(os.path.dirname(path), exist_ok=True)
|
||||
img.save(path)
|
||||
print(f"icône écrite : {path}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
here = os.path.dirname(os.path.abspath(__file__))
|
||||
make_icon(os.path.join(here, "icon.png"))
|
||||
Reference in New Issue
Block a user