REPO was os.path.join(HERE, '..', '..'), and HERE is <root>/library/scripts/posters
-- so REPO resolved to <root>/library, not the repo root. Both outputs went to
directories nothing reads and nothing serves:
library/plugin-designs/<profile>/assets/previews/ instead of plugin-designs/...
library/data/posters/ instead of data/posters/
★ IT REPORTED SUCCESS WHILE DOING NOTHING USEFUL, which is what makes it worth a
commit of its own. The script printed "[make-previews] N posters" and its two
destination lines, wrote genuine WebPs, and exited 0. Only the files were in a
tree no build stages, so the SERVED previews never changed.
MEASURED, on one poster, before and after:
before the regenerated thumbnail was byte-identical to the shipped one
(same sha256, git status clean) -- 0 pixels changed
after sha differs, git sees both files modified, and 52.9% of the
thumbnail's pixels differ (21.1% by more than 40/255, max delta 255)
Found by DRY-RUNNING this step on a single already-shot poster instead of
discovering it after a 174-sheet reshoot. Without the fix that reshoot would have
produced 174 correct WebPs in the wrong tree, the walls would have kept their old
teal thumbnails, and the landing would have looked complete: a teal thumbnail
over a hued print, which is the exact defect the reshoot exists to remove.
The three-level form is what the other scripts in this folder already use to
reach the root; this one was the odd one out.
72 lines
3.6 KiB
Python
72 lines
3.6 KiB
Python
#!/usr/bin/env python3
|
|
"""make-previews.py — turn the rendered 3000x3000 posters into the TWO WebP sets
|
|
the app ships.
|
|
|
|
python3 make-previews.py
|
|
-> plugin-designs/my-upg-100-list/assets/previews/<zone>.webp 560px card thumbnails
|
|
-> data/posters/<zone>.webp 1500px the download
|
|
|
|
WHY TWO SIZES
|
|
The wall card shows a small thumbnail; tapping "Poster Map" must hand the user
|
|
THE SAME POSTER at a usable size. The button used to re-render a live Mapbox
|
|
canvas through useMapPoster.js — a completely different artefact from the preview
|
|
above it, carrying none of the template. Serving the pre-rendered image makes
|
|
preview and download identical BY CONSTRUCTION, and it works on Android, where a
|
|
Node generator cannot run at all.
|
|
|
|
SIZE BUDGET (measured): 1500px q80 WebP is ~217 KB per poster, 5.9 MB for all 28 —
|
|
small enough to ship in the APK, and 5in at 300dpi / 10in at 150dpi, a real print.
|
|
The 3000px PNG masters (51 MB) stay OUT of the app; export-public.mjs sends those
|
|
to a sibling folder for desktop/CDN use.
|
|
|
|
Uses PIL rather than sharp: sharp is not installed in this repo, PIL is present.
|
|
"""
|
|
import os, sys, glob
|
|
from PIL import Image
|
|
|
|
HERE = os.path.dirname(os.path.abspath(__file__))
|
|
SRC = os.path.join(HERE, 'out', 'posters')
|
|
# ★ THREE LEVELS, NOT TWO. HERE is <root>/library/scripts/posters, so '..','..' lands on
|
|
# <root>/library and every output went to library/plugin-designs/... and library/data/posters --
|
|
# directories nothing reads and nothing serves. The script REPORTED success and wrote real WebPs,
|
|
# so a preview run looked like it had worked while the served previews never changed. Found by
|
|
# dry-running this step on a single poster before a 174-sheet reshoot; it would otherwise have
|
|
# silently produced 174 files in the wrong tree and shipped the old thumbnails.
|
|
REPO = os.path.abspath(os.path.join(HERE, '..', '..', '..'))
|
|
# WHICH APP the previews belong to. The country-posters app renders from the SAME
|
|
# generator into the SAME out/posters, so the only thing that differs is where the
|
|
# WebPs land — parameterize rather than fork this script.
|
|
# PROFILE=my-upg-100-list (default)
|
|
# PROFILE=country-posters python3 make-previews.py
|
|
# ONLY filters by filename prefix so a country run does not re-emit the 28 zone
|
|
# posters sitting in the same folder (and vice versa).
|
|
PROFILE = os.environ.get('PROFILE', 'my-upg-100-list')
|
|
ONLY = os.environ.get('ONLY_PREFIX', '')
|
|
THUMB = os.path.join(REPO, 'plugin-designs', PROFILE, 'assets', 'previews')
|
|
FULL = os.path.join(REPO, 'data', 'posters') # a SOURCE: the build stages it into <tree>/assets/posters on request
|
|
|
|
os.makedirs(THUMB, exist_ok=True)
|
|
os.makedirs(FULL, exist_ok=True)
|
|
|
|
pngs = sorted(glob.glob(os.path.join(SRC, (ONLY + '*.png') if ONLY else '*.png')))
|
|
if not pngs:
|
|
sys.exit(f'[make-previews] no PNGs in {SRC} — run `bun run posters` then `bun run posters:shoot` first.')
|
|
|
|
tkb = fkb = 0
|
|
for p in pngs:
|
|
zone = os.path.basename(p)[:-4]
|
|
im = Image.open(p).convert('RGB')
|
|
|
|
t = im.copy(); t.thumbnail((560, 560), Image.LANCZOS)
|
|
tp = os.path.join(THUMB, zone + '.webp')
|
|
t.save(tp, 'WEBP', quality=82, method=6)
|
|
tkb += os.path.getsize(tp) / 1024
|
|
|
|
f = im.copy(); f.thumbnail((1500, 1500), Image.LANCZOS)
|
|
fp = os.path.join(FULL, zone + '.webp')
|
|
f.save(fp, 'WEBP', quality=80, method=6)
|
|
fkb += os.path.getsize(fp) / 1024
|
|
|
|
print(f'[make-previews] {len(pngs)} posters')
|
|
print(f' thumbnails -> plugin-designs/.../assets/previews {tkb/1024:5.1f} MB (inlined in the bundle)')
|
|
print(f' full size -> data/posters {fkb/1024:5.1f} MB (served + shipped in the APK)')
|