Files

117 lines
4.3 KiB
Python
Raw Permalink Normal View History

"""
Generate icon PNGs for the matrix_messenger integration.
Run once: python generate_icons.py
Requires: pip install Pillow
Output: icon.png, icon@2x.png, dark_icon.png, dark_icon@2x.png
"""
from pathlib import Path
try:
from PIL import Image, ImageDraw
except ImportError:
raise SystemExit("Pillow not found. Install it with: pip install Pillow")
NAVY = (26, 26, 46, 255) # #1A1A2E (background)
PURPLE = (91, 45, 142, 255) # #5B2D8E (speech bubble)
TEAL = ( 3, 218, 198, 255) # #03DAC6 (badge)
WHITE = (255, 255, 255, 255)
TRANSPARENT = (0, 0, 0, 0)
DARK_BG = (18, 18, 18, 255) # near-black for dark-mode variant
def draw_icon(size: int, dark: bool) -> Image.Image:
s = size / 256
img = Image.new("RGBA", (size, size), TRANSPARENT)
d = ImageDraw.Draw(img)
bg = DARK_BG if dark else NAVY
# ── Outer rounded background ────────────────────────────────────────────
d.rounded_rectangle([0, 0, size - 1, size - 1], radius=int(48 * s), fill=bg)
# ── Speech bubble ───────────────────────────────────────────────────────
# Body (rounded rect, top + sides)
bx0, by0 = int(36 * s), int(36 * s)
bx1, by1 = int(220 * s), int(168 * s)
d.rounded_rectangle([bx0, by0, bx1, by1], radius=int(16 * s), fill=PURPLE)
# Tail triangle pointing down-center
cx = int(128 * s)
ty = int(168 * s)
tw = int(28 * s)
th = int(34 * s)
d.polygon(
[(cx - tw, ty), (cx + tw, ty), (cx, ty + th)],
fill=PURPLE,
)
# ── Left bracket [ ──────────────────────────────────────────────────────
lx = int(60 * s)
bw = int(11 * s)
bh = int(60 * s)
cap = int(26 * s)
cr = int(3 * s)
by_top = int(78 * s)
by_bot = int(127 * s)
d.rounded_rectangle([lx, by_top, lx + bw, by_top + bh], radius=cr, fill=WHITE) # vertical
d.rounded_rectangle([lx, by_top, lx + cap, by_top + bw], radius=cr, fill=WHITE) # top cap
d.rounded_rectangle([lx, by_bot, lx + cap, by_bot + bw], radius=cr, fill=WHITE) # bottom cap
# ── Right bracket ] ─────────────────────────────────────────────────────
rx = int(185 * s)
d.rounded_rectangle([rx, by_top, rx + bw, by_top + bh], radius=cr, fill=WHITE)
d.rounded_rectangle([rx - cap + bw, by_top, rx + bw, by_top + bw], radius=cr, fill=WHITE)
d.rounded_rectangle([rx - cap + bw, by_bot, rx + bw, by_bot + bw], radius=cr, fill=WHITE)
# ── M letter (polyline: left-up, peak, right-up, right-down) ────────────
sw = int(12 * s)
pts = [
(int(97 * s), int(132 * s)),
(int(97 * s), int(84 * s)),
(int(128 * s), int(114 * s)),
(int(159 * s), int(84 * s)),
(int(159 * s), int(132 * s)),
]
for i in range(len(pts) - 1):
x0, y0 = pts[i]
x1, y1 = pts[i + 1]
d.line([x0, y0, x1, y1], fill=WHITE, width=sw)
# round caps
for px, py in pts:
r = sw // 2
d.ellipse([px - r, py - r, px + r, py + r], fill=WHITE)
# ── Teal badge with three dots ───────────────────────────────────────────
bc = int(196 * s)
br = int(36 * s)
d.ellipse([bc - br, bc - br, bc + br, bc + br], fill=TEAL)
dot_r = int(7 * s)
for dx in (-12, 0, 12):
cx2 = bc + int(dx * s)
d.ellipse([cx2 - dot_r, bc - dot_r, cx2 + dot_r, bc + dot_r], fill=bg)
return img
HERE = Path(__file__).parent / "brand"
HERE.mkdir(exist_ok=True)
variants = [
("icon.png", 256, False),
("icon@2x.png", 512, False),
("dark_icon.png", 256, True),
("dark_icon@2x.png", 512, True),
]
for filename, size, dark in variants:
path = HERE / filename
draw_icon(size, dark).save(path, "PNG")
print(f" created brand/{path.name} ({size}×{size})")
print("\nDone. Restart Home Assistant to pick up the new icons.")