mirror of
https://github.com/torlando-tech/pyxis.git
synced 2026-03-30 13:45:38 +00:00
Consolidate #ifndef/#ifdef into single #ifdef/#else/#endif block. Add warning comment to generated header about static linkage. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
102 lines
3.9 KiB
Python
102 lines
3.9 KiB
Python
"""
|
|
PlatformIO pre-build script: Convert pyxis-icon.svg to RGB565 PROGMEM header.
|
|
|
|
Generates lib/tdeck_ui/Hardware/TDeck/SplashImage.h containing a 320x240
|
|
pixel splash image as a PROGMEM byte array. Skips regeneration if the
|
|
header is already newer than the source SVG.
|
|
|
|
Requires: cairosvg, Pillow (gracefully skips if not installed)
|
|
"""
|
|
|
|
Import("env")
|
|
|
|
import os
|
|
import struct
|
|
|
|
SPLASH_WIDTH = 320
|
|
SPLASH_HEIGHT = 240
|
|
SVG_FILE = "pyxis-icon.svg"
|
|
HEADER_FILE = os.path.join("lib", "tdeck_ui", "Hardware", "TDeck", "SplashImage.h")
|
|
BG_COLOR = (0x1D, 0x1A, 0x1E) # #1D1A1E — matches fill_screen in show_splash()
|
|
|
|
|
|
def rgb888_to_rgb565(r, g, b):
|
|
"""Convert 8-bit RGB to 16-bit RGB565 (big-endian bytes)."""
|
|
rgb565 = ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3)
|
|
return struct.pack(">H", rgb565)
|
|
|
|
|
|
def should_regenerate(svg_path, header_path):
|
|
"""Return True if the header needs regeneration."""
|
|
if not os.path.exists(header_path):
|
|
return True
|
|
return os.path.getmtime(svg_path) > os.path.getmtime(header_path)
|
|
|
|
|
|
project_dir = env.get("PROJECT_DIR", os.getcwd())
|
|
svg_path = os.path.join(project_dir, SVG_FILE)
|
|
header_path = os.path.join(project_dir, HEADER_FILE)
|
|
|
|
if not os.path.exists(svg_path):
|
|
print(f"[generate_splash] {SVG_FILE} not found, skipping splash generation")
|
|
elif not should_regenerate(svg_path, header_path):
|
|
print(f"[generate_splash] {HEADER_FILE} is up-to-date, skipping")
|
|
else:
|
|
try:
|
|
import cairosvg
|
|
from PIL import Image
|
|
import io
|
|
except ImportError as e:
|
|
print(f"[generate_splash] Missing dependency ({e}), skipping splash generation")
|
|
print(f"[generate_splash] Install with: pip install cairosvg Pillow")
|
|
else:
|
|
print(f"[generate_splash] Rendering {SVG_FILE} -> {HEADER_FILE} ({SPLASH_WIDTH}x{SPLASH_HEIGHT} RGB565)")
|
|
|
|
# Render SVG to PNG — scale to fit height, center horizontally
|
|
png_data = cairosvg.svg2png(
|
|
url=svg_path,
|
|
output_width=SPLASH_HEIGHT, # Square SVG scaled to screen height
|
|
output_height=SPLASH_HEIGHT,
|
|
)
|
|
|
|
icon = Image.open(io.BytesIO(png_data)).convert("RGBA")
|
|
|
|
# Composite onto full-screen background (handles transparency)
|
|
bg = Image.new("RGBA", (SPLASH_WIDTH, SPLASH_HEIGHT), BG_COLOR + (255,))
|
|
x_offset = (SPLASH_WIDTH - icon.width) // 2
|
|
bg.paste(icon, (x_offset, 0), icon)
|
|
img = bg.convert("RGB")
|
|
|
|
# Convert to RGB565 big-endian byte array
|
|
pixels = list(img.getdata())
|
|
rgb565_bytes = bytearray()
|
|
for r, g, b in pixels:
|
|
rgb565_bytes.extend(rgb888_to_rgb565(r, g, b))
|
|
|
|
# Write C header
|
|
os.makedirs(os.path.dirname(header_path), exist_ok=True)
|
|
|
|
with open(header_path, "w") as f:
|
|
f.write("// AUTO-GENERATED by generate_splash.py — do not edit\n")
|
|
f.write("#ifndef SPLASH_IMAGE_H\n")
|
|
f.write("#define SPLASH_IMAGE_H\n\n")
|
|
f.write("#include <Arduino.h>\n\n")
|
|
f.write(f"#define SPLASH_WIDTH {SPLASH_WIDTH}\n")
|
|
f.write(f"#define SPLASH_HEIGHT {SPLASH_HEIGHT}\n")
|
|
f.write(f"#define HAS_SPLASH_IMAGE 1\n\n")
|
|
f.write(f"// {SPLASH_WIDTH}x{SPLASH_HEIGHT} RGB565 big-endian ({len(rgb565_bytes)} bytes)\n")
|
|
f.write("// WARNING: static linkage — include from exactly ONE translation unit\n")
|
|
f.write("static const uint8_t PROGMEM splash_image[] = {\n")
|
|
|
|
# Write bytes, 16 per line
|
|
for i in range(0, len(rgb565_bytes), 16):
|
|
chunk = rgb565_bytes[i:i+16]
|
|
hex_str = ", ".join(f"0x{b:02X}" for b in chunk)
|
|
trailing = "," if i + 16 < len(rgb565_bytes) else ""
|
|
f.write(f" {hex_str}{trailing}\n")
|
|
|
|
f.write("};\n\n")
|
|
f.write("#endif // SPLASH_IMAGE_H\n")
|
|
|
|
print(f"[generate_splash] Generated {len(rgb565_bytes)} bytes ({SPLASH_WIDTH}x{SPLASH_HEIGHT} RGB565)")
|