21bfd2f7de
Add LISAEL_MODE_ROUTINE to the UI shell: enum entry, build_screen() case, home carousel tile (8th, broom icon U+1F9F9, periwinkle pastel), minimal navigable stub in modes/routine.c, CMakeLists srcs update, Twemoji icon generated (17/17 ok). s_adots[8] now at capacity.
75 lines
2.9 KiB
Python
75 lines
2.9 KiB
Python
#!/usr/bin/env python3
|
|
"""Generate LVGL colour icon descriptors from Twemoji PNGs.
|
|
|
|
Downloads the Twemoji 72x72 PNGs for the glyphs the Lisael Box UI needs,
|
|
downscales them (Pillow/Lanczos) and converts each to an LVGL RGB565A8
|
|
`lv_image_dsc_t` C source in ``main/ui/assets/``.
|
|
|
|
Run with a Python that has both Pillow and pypng available, e.g. the
|
|
ESP-IDF venv:
|
|
|
|
~/.espressif/python_env/idf5.4_py3.14_env/bin/python tools/gen_icons.py
|
|
|
|
Twemoji artwork is CC-BY 4.0 (https://github.com/jdecked/twemoji).
|
|
"""
|
|
import os
|
|
import ssl
|
|
import subprocess
|
|
import sys
|
|
import urllib.request
|
|
|
|
# name -> (twemoji codepoint, target size px)
|
|
SPECS = {
|
|
# home mode tiles
|
|
"radio": ("1f4fb", 50), "sound": ("1f50a", 50), "calm": ("1fae7", 50),
|
|
"clock": ("1f550", 50), "games": ("1f3ae", 50),
|
|
# weather (open-meteo WMO codes)
|
|
"wsun": ("2600", 42), "wpartly": ("26c5", 42), "wfog": ("1f32b", 42),
|
|
"wdrizzle": ("1f326", 42), "wrain": ("1f327", 42), "wsleet": ("1f328", 42),
|
|
"wsnow": ("2744", 42), "wthunder": ("26c8", 42), "wunknown": ("2753", 42),
|
|
"book": ("1f4d6", 50), # "Lire" home tile (open book). Word icons for the
|
|
# reading game are generated to the SD by gen_lire_content.py.
|
|
"reglages": ("2699", 50), # "Réglages WiFi" home tile (gear)
|
|
"routine": ("1f9f9", 50), # "Routine" home tile (broom 🧹) — chores/steps
|
|
}
|
|
BASE = "https://raw.githubusercontent.com/jdecked/twemoji/main/assets/72x72"
|
|
|
|
HERE = os.path.dirname(os.path.abspath(__file__))
|
|
ROOT = os.path.dirname(HERE)
|
|
OUT = os.path.join(ROOT, "main", "ui", "assets")
|
|
CONV = os.path.join(ROOT, "managed_components", "lvgl__lvgl", "scripts",
|
|
"LVGLImage.py")
|
|
TMP = "/tmp"
|
|
|
|
|
|
def main():
|
|
from PIL import Image
|
|
os.makedirs(OUT, exist_ok=True)
|
|
ctx = ssl.create_default_context()
|
|
ok, bad = [], []
|
|
for name, (cp, sz) in SPECS.items():
|
|
try:
|
|
req = urllib.request.Request(f"{BASE}/{cp}.png",
|
|
headers={"User-Agent": "curl/8"})
|
|
data = urllib.request.urlopen(req, timeout=15, context=ctx).read()
|
|
src = os.path.join(TMP, f"em_{name}.png")
|
|
open(src, "wb").write(data)
|
|
im = Image.open(src).convert("RGBA").resize((sz, sz), Image.LANCZOS)
|
|
rs = os.path.join(TMP, f"lisael_ic_{name}.png")
|
|
im.save(rs)
|
|
r = subprocess.run(
|
|
[sys.executable, CONV, "--ofmt", "C", "--cf", "RGB565A8",
|
|
"--name", f"lisael_ic_{name}", "-o", OUT, rs],
|
|
capture_output=True, text=True)
|
|
(ok if r.returncode == 0 else bad).append(name)
|
|
if r.returncode != 0:
|
|
print("CONV FAIL", name, r.stderr[-200:])
|
|
except Exception as e: # noqa: BLE001
|
|
bad.append(name)
|
|
print("FAIL", name, str(e)[:200])
|
|
print(f"converted {len(ok)}/{len(SPECS)}", "bad:", bad)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|