← back to Quadrille Showroom

scripts/img_tools.py

67 lines

#!/usr/bin/env python3
"""img_tools.py — local ($0) image helpers for the Quadrille showroom gen pipeline.

  python3 img_tools.py score <url|path>            -> prints LR seam score (float)
  python3 img_tools.py mirror <url|path> <out.png> -> writes a 2x2 mirror book-match
                                                        tile (guaranteed seamless,
                                                        preserves the real design),
                                                        prints "<before> <after>"

The mirror book-match is a legitimate wallcovering technique: reflecting the swatch
makes every tile edge match its neighbour exactly, so the genuine China Seas pattern
tiles cleanly on a wall WITHOUT any AI re-generation (which would misrepresent the
real product). $0 — no API, ~150ms/image.
"""
import sys, urllib.request, tempfile
import numpy as np
from PIL import Image

STRIP = 3
THRESHOLD = 30


def _resolve(src):
    if src.startswith('http'):
        tmp = tempfile.NamedTemporaryFile(suffix='.img', delete=False)
        urllib.request.urlretrieve(src, tmp.name)
        return tmp.name
    return src


def lr_score(img):
    w, h = img.size
    sw, sh = min(w, 400), min(h, 800)
    d = np.array(img.resize((sw, sh)).convert('RGB')).astype(int)
    left = d[:, :STRIP, :]
    right = d[:, sw - STRIP:, :][:, ::-1, :]   # mirror so col0<->last
    return float(np.abs(left - right).sum() / (sh * STRIP) / 3)


def score(src):
    print(round(lr_score(Image.open(_resolve(src))), 1))


def mirror(src, out):
    im = Image.open(_resolve(src)).convert('RGB')
    before = round(lr_score(im), 1)
    w, h = im.size
    fh = im.transpose(Image.FLIP_LEFT_RIGHT)
    fv = im.transpose(Image.FLIP_TOP_BOTTOM)
    fb = fh.transpose(Image.FLIP_TOP_BOTTOM)
    tile = Image.new('RGB', (w * 2, h * 2))
    tile.paste(im, (0, 0)); tile.paste(fh, (w, 0))
    tile.paste(fv, (0, h)); tile.paste(fb, (w, h))
    tile.save(out, 'PNG')
    after = round(lr_score(tile), 1)
    print(f"{before} {after}")


if __name__ == '__main__':
    cmd = sys.argv[1] if len(sys.argv) > 1 else ''
    if cmd == 'score' and len(sys.argv) == 3:
        score(sys.argv[2])
    elif cmd == 'mirror' and len(sys.argv) == 4:
        mirror(sys.argv[2], sys.argv[3])
    else:
        print(__doc__); sys.exit(2)