109 lines
3.8 KiB
Python
109 lines
3.8 KiB
Python
"""
|
|
Preview driver for the Kuromi techno watermark.
|
|
|
|
Renders representative samples (dark / busy / bright backgrounds) so Quinn can
|
|
judge the look BEFORE the full batch. Produces, per sample:
|
|
- full watermarked image
|
|
- a thumbnail (card-width) render — the governing legibility case
|
|
- a bottom-right corner crop at 1:1 — to read fine detail
|
|
Plus an A/B/C comparison (Orbitron+plate / Audiowide+plate / Orbitron no-plate)
|
|
on the busy sample to settle font + plate-vs-glow in one round.
|
|
|
|
Outputs to: deployments/@domains/quinn.www/root/public/photos-watermarked/_preview/
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
|
|
from PIL import Image, ImageDraw, ImageFont
|
|
|
|
from watermark_lib import WatermarkStyle, render_watermark, FONT_DIR
|
|
|
|
REPO = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", ".."))
|
|
PUB = os.path.join(REPO, "deployments/@domains/quinn.www/root/public/photos")
|
|
ORIG = os.path.join(REPO, "users/transquinnftw/originals")
|
|
OUT = os.path.join(PUB + "-watermarked", "_preview")
|
|
|
|
THUMB_W = 300 # representative gallery-card width on the site
|
|
|
|
# (label, source path, background character)
|
|
SAMPLES = [
|
|
("dark__pink-black-tank-booth", f"{ORIG}/pink-black-tank-booth.jpeg", "dark BR"),
|
|
("busy__quinn-pink-bra-boots-mural", f"{PUB}/quinn-pink-bra-boots-mural.jpeg", "busy mural"),
|
|
("bright__quinn-nude-bed-frontal", f"{PUB}/quinn-nude-bed-frontal.jpeg", "bright flat"),
|
|
]
|
|
|
|
|
|
def _label(im: Image.Image, text: str) -> Image.Image:
|
|
bar_h = 26
|
|
out = Image.new("RGB", (im.width, im.height + bar_h), (18, 18, 22))
|
|
out.paste(im, (0, 0))
|
|
d = ImageDraw.Draw(out)
|
|
try:
|
|
f = ImageFont.truetype(os.path.join(FONT_DIR, "Audiowide-Regular.ttf"), 14)
|
|
except Exception:
|
|
f = ImageFont.load_default()
|
|
d.text((6, im.height + 5), text, fill=(255, 120, 190), font=f)
|
|
return out
|
|
|
|
|
|
def thumb(im: Image.Image, w: int = THUMB_W) -> Image.Image:
|
|
h = round(im.height * w / im.width)
|
|
return im.resize((w, h), Image.LANCZOS)
|
|
|
|
|
|
def corner_crop(im: Image.Image) -> Image.Image:
|
|
cw, ch = int(im.width * 0.5), int(im.height * 0.22)
|
|
return im.crop((im.width - cw, im.height - ch, im.width, im.height))
|
|
|
|
|
|
def hstack(imgs: list[Image.Image], gap: int = 14) -> Image.Image:
|
|
h = max(i.height for i in imgs)
|
|
w = sum(i.width for i in imgs) + gap * (len(imgs) - 1)
|
|
out = Image.new("RGB", (w, h), (18, 18, 22))
|
|
x = 0
|
|
for i in imgs:
|
|
out.paste(i, (x, 0))
|
|
x += i.width + gap
|
|
return out
|
|
|
|
|
|
def main() -> None:
|
|
os.makedirs(OUT, exist_ok=True)
|
|
default = WatermarkStyle()
|
|
|
|
for label, src, _desc in SAMPLES:
|
|
im = Image.open(src)
|
|
wm = render_watermark(im, default)
|
|
wm.save(os.path.join(OUT, f"{label}__full.jpg"), quality=92)
|
|
# thumbnail + corner crop strip
|
|
strip = hstack([
|
|
_label(thumb(wm), f"THUMB {THUMB_W}px"),
|
|
_label(corner_crop(wm), "corner 1:1"),
|
|
])
|
|
strip.save(os.path.join(OUT, f"{label}__inspect.jpg"), quality=94)
|
|
|
|
# A/B/C variant comparison on the busy sample (hardest legibility case)
|
|
busy_src = SAMPLES[1][1]
|
|
bim = Image.open(busy_src)
|
|
variants = [
|
|
("A: Orbitron + plate", WatermarkStyle(font="orbitron", plate=True)),
|
|
("B: Audiowide + plate", WatermarkStyle(font="audiowide", plate=True)),
|
|
("C: Orbitron no-plate", WatermarkStyle(font="orbitron", plate=False)),
|
|
]
|
|
thumbs, corners = [], []
|
|
for name, st in variants:
|
|
wm = render_watermark(bim, st)
|
|
thumbs.append(_label(thumb(wm), name))
|
|
corners.append(_label(corner_crop(wm), name))
|
|
hstack(thumbs).save(os.path.join(OUT, "VARIANTS__thumbs.jpg"), quality=94)
|
|
hstack(corners).save(os.path.join(OUT, "VARIANTS__corners.jpg"), quality=94)
|
|
|
|
print("preview written to", OUT)
|
|
for f in sorted(os.listdir(OUT)):
|
|
print(" ", f)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|