Unify STRETCH layout for all photos, decode GIF 1:1 with disposal restore, and ship a 160x120 sample GIF. Co-authored-by: Cursor <cursoragent@cursor.com>
74 lines
2.4 KiB
Python
74 lines
2.4 KiB
Python
#!/usr/bin/env python3
|
|
"""Generate test photos into assets/photos (solid bg; GIF is 160x120 for 1:1 decode)."""
|
|
from __future__ import annotations
|
|
|
|
from pathlib import Path
|
|
|
|
from PIL import Image, ImageDraw, ImageFont
|
|
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
OUT = ROOT / "assets" / "photos"
|
|
W, H = 320, 240
|
|
GIF_W, GIF_H = 160, 120
|
|
|
|
|
|
def font(size: int = 28) -> ImageFont.ImageFont:
|
|
for name in (
|
|
r"C:\Windows\Fonts\msyh.ttc",
|
|
r"C:\Windows\Fonts\arial.ttf",
|
|
r"C:\Windows\Fonts\consola.ttf",
|
|
):
|
|
try:
|
|
return ImageFont.truetype(name, size)
|
|
except OSError:
|
|
pass
|
|
return ImageFont.load_default()
|
|
|
|
|
|
def card(bg, accent, title: str, subtitle: str, path: Path, fmt: str) -> None:
|
|
im = Image.new("RGB", (W, H), bg)
|
|
d = ImageDraw.Draw(im)
|
|
d.rounded_rectangle((20, 36, W - 20, H - 36), radius=12, fill=bg, outline=accent, width=3)
|
|
d.text((36, 70), title, fill=(234, 240, 246), font=font(36))
|
|
d.text((36, 130), subtitle, fill=(160, 175, 190), font=font(20))
|
|
d.text((36, 170), "CYD ALBUM TEST", fill=accent, font=font(16))
|
|
if fmt == "JPEG":
|
|
im.save(path, "JPEG", quality=92)
|
|
else:
|
|
im.save(path, "PNG")
|
|
print(f"wrote {path} ({path.stat().st_size} bytes)")
|
|
|
|
|
|
def main() -> None:
|
|
OUT.mkdir(parents=True, exist_ok=True)
|
|
card((10, 16, 22), (79, 195, 247), "01 JPG", "tap left / right", OUT / "01_blue.jpg", "JPEG")
|
|
card((28, 12, 18), (232, 93, 76), "02 JPG", "red sample", OUT / "02_red.jpg", "JPEG")
|
|
card((8, 28, 20), (61, 220, 151), "03 PNG", "green sample", OUT / "03_green.png", "PNG")
|
|
|
|
# 160x120 GIF matches decode canvas → no downscale flicker on moving regions.
|
|
frames = []
|
|
for i in range(8):
|
|
im = Image.new("RGB", (GIF_W, GIF_H), (10, 16, 22))
|
|
d = ImageDraw.Draw(im)
|
|
d.text((8, 8), "04 GIF", fill=(234, 240, 246), font=font(22))
|
|
d.text((8, 36), "160x120", fill=(160, 175, 190), font=font(14))
|
|
x = 4 + i * 14
|
|
d.rounded_rectangle((x, 60, x + 40, 100), radius=6, fill=(255, 200, 40))
|
|
frames.append(im)
|
|
gif_path = OUT / "04_bounce.gif"
|
|
frames[0].save(
|
|
gif_path,
|
|
save_all=True,
|
|
append_images=frames[1:],
|
|
duration=80,
|
|
loop=0,
|
|
optimize=False,
|
|
disposal=2, # restore to background — handled in firmware
|
|
)
|
|
print(f"wrote {gif_path} ({gif_path.stat().st_size} bytes)")
|
|
print("DONE")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|