← back to Wallco Ai
Add pilot-build-tifs.py (PG-drift-proof TIF builder via by-id route)
d668131a28b0d2c6d0a578423cb36bc1cd1b22eb · 2026-06-02 08:23:54 -0700 · Steve Abrams
Builds data/tif/<id>.tif by pulling each source from the server's own
/designs/img/by-id/:id route (resolves correctly on prod regardless of the
sparse all_designs / designs.json-has-no-tif_path drift). Shipped via deploy.
For the 20-design prod pilot of the full-res TIF features. Verified locally:
build -> hires route serves 200 image/jpeg.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Files touched
M deploy-kamatera.shA scripts/pilot-build-tifs.py
Diff
commit d668131a28b0d2c6d0a578423cb36bc1cd1b22eb
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Tue Jun 2 08:23:54 2026 -0700
Add pilot-build-tifs.py (PG-drift-proof TIF builder via by-id route)
Builds data/tif/<id>.tif by pulling each source from the server's own
/designs/img/by-id/:id route (resolves correctly on prod regardless of the
sparse all_designs / designs.json-has-no-tif_path drift). Shipped via deploy.
For the 20-design prod pilot of the full-res TIF features. Verified locally:
build -> hires route serves 200 image/jpeg.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---
deploy-kamatera.sh | 2 +-
scripts/pilot-build-tifs.py | 74 +++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 75 insertions(+), 1 deletion(-)
diff --git a/deploy-kamatera.sh b/deploy-kamatera.sh
index 0095d99..b1c4916 100755
--- a/deploy-kamatera.sh
+++ b/deploy-kamatera.sh
@@ -106,7 +106,7 @@ rsync -az "$LOCAL_DIR/scripts/refresh_designs_snapshot.py" \
# for those features to work. List grows narrowly as endpoints add deps;
# don't unbox scripts/ wholesale.
echo "[2d/6] ship runtime-endpoint scripts..."
-for script in scripts/seam-defect-boxes.py scripts/mint-shopify-download-token.js scripts/generate_designs.js scripts/generator_tick.js scripts/seam-heal-feather.py scripts/quantize-no-ghost.py scripts/recolor-tif.py scripts/tif-to-web.py; do
+for script in scripts/seam-defect-boxes.py scripts/mint-shopify-download-token.js scripts/generate_designs.js scripts/generator_tick.js scripts/seam-heal-feather.py scripts/quantize-no-ghost.py scripts/recolor-tif.py scripts/tif-to-web.py scripts/pilot-build-tifs.py; do
if [ -f "$LOCAL_DIR/$script" ]; then
rsync -az "$LOCAL_DIR/$script" "$REMOTE:$REMOTE_DIR/$script" && echo " $script shipped"
fi
diff --git a/scripts/pilot-build-tifs.py b/scripts/pilot-build-tifs.py
new file mode 100644
index 0000000..ccd39a9
--- /dev/null
+++ b/scripts/pilot-build-tifs.py
@@ -0,0 +1,74 @@
+#!/usr/bin/env python3
+"""pilot-build-tifs.py — build full-size design TIFs for a set of ids, sourcing
+the image from the running server's own /designs/img/by-id/:id route.
+
+Why not scripts/build-tif.py for the pilot: that one reads metadata + local_path
+from `all_designs`, which is the SPARSE ~350-row table on prod (the catalog
+lives in data/designs.json / spoon_all_designs) — so it returns "not found" for
+most published designs, and its source resolution depends on local_path being
+present + correct. The by-id route already resolves the on-disk source PNG
+correctly on prod (PG-drift-proof), so we pull from it over localhost and write
+data/tif/<id>.tif. /designs/hires/:id (findTifOnDisk) then serves it, and the
+colorway recolor can use it as the full-res source.
+
+NOTE: the TIF is exactly as sharp as the source PNG the server serves (≈1024px
+for current generations) — this does NOT synthesize detail. It makes the TIF
+asset + the single-image mural preview real, and lets the edge-preserving
+recolor run server-side. A genuinely higher-res master needs a higher-res
+generation/upscale pipeline (separate decision).
+
+CLI: pilot-build-tifs.py [--base http://127.0.0.1:9905] [--force] <id> [<id> ...]
+Prints one line per id. Exit 0 if all ok, 1 if any failed.
+"""
+import sys, os, io, argparse, urllib.request
+from pathlib import Path
+
+ROOT = Path(__file__).resolve().parents[1]
+TIF_DIR = ROOT / "data" / "tif"
+
+
+def build(base, design_id, force):
+ out = TIF_DIR / f"{design_id}.tif"
+ if out.exists() and not force:
+ return True, f"{design_id}: exists ({out.stat().st_size:,} B) — --force to rebuild"
+ url = f"{base}/designs/img/by-id/{design_id}"
+ try:
+ req = urllib.request.Request(url, headers={"User-Agent": "pilot-build-tifs"})
+ with urllib.request.urlopen(req, timeout=30) as r:
+ if r.status != 200:
+ return False, f"{design_id}: source HTTP {r.status}"
+ data = r.read()
+ except Exception as e:
+ return False, f"{design_id}: fetch fail: {e}"
+ try:
+ from PIL import Image
+ Image.MAX_IMAGE_PIXELS = None
+ im = Image.open(io.BytesIO(data)).convert("RGB")
+ w, h = im.size
+ TIF_DIR.mkdir(parents=True, exist_ok=True)
+ im.save(out, format="TIFF", compression="tiff_lzw", dpi=(150, 150))
+ return True, f"{design_id}: TIF {w}x{h} -> {out} ({out.stat().st_size:,} B)"
+ except Exception as e:
+ return False, f"{design_id}: build fail: {e}"
+
+
+def main():
+ ap = argparse.ArgumentParser()
+ ap.add_argument("--base", default="http://127.0.0.1:9905")
+ ap.add_argument("--force", action="store_true")
+ ap.add_argument("ids", nargs="+")
+ a = ap.parse_args()
+ ok_all = True
+ for raw in a.ids:
+ try:
+ did = int(raw)
+ except ValueError:
+ print(f"{raw}: not an int"); ok_all = False; continue
+ ok, msg = build(a.base, did, a.force)
+ print((" ok " if ok else " FAIL ") + msg)
+ ok_all = ok_all and ok
+ return 0 if ok_all else 1
+
+
+if __name__ == "__main__":
+ sys.exit(main())
← c9f7813 TIF lookup: match both <id>.tif and <category>/design_<id>.t
·
back to Wallco Ai
·
edges-review + seam-debug + PDP: status filter + per-surface 2b09de8 →