diff --git a/deployments/@domains/quinn.www/root/public/photos-watermarked/_preview/bc/bright__bc.jpg b/deployments/@domains/quinn.www/root/public/photos-watermarked/_preview/bc/bright__bc.jpg new file mode 100644 index 00000000..048adda8 Binary files /dev/null and b/deployments/@domains/quinn.www/root/public/photos-watermarked/_preview/bc/bright__bc.jpg differ diff --git a/deployments/@domains/quinn.www/root/public/photos-watermarked/_preview/bc/busy__bc.jpg b/deployments/@domains/quinn.www/root/public/photos-watermarked/_preview/bc/busy__bc.jpg new file mode 100644 index 00000000..d66e8293 Binary files /dev/null and b/deployments/@domains/quinn.www/root/public/photos-watermarked/_preview/bc/busy__bc.jpg differ diff --git a/deployments/@domains/quinn.www/root/public/photos-watermarked/_preview/offfocal/CROP_ATTACK.jpg b/deployments/@domains/quinn.www/root/public/photos-watermarked/_preview/offfocal/CROP_ATTACK.jpg new file mode 100644 index 00000000..b7b169a4 Binary files /dev/null and b/deployments/@domains/quinn.www/root/public/photos-watermarked/_preview/offfocal/CROP_ATTACK.jpg differ diff --git a/deployments/@domains/quinn.www/root/public/photos-watermarked/_preview/offfocal/bright__modes.jpg b/deployments/@domains/quinn.www/root/public/photos-watermarked/_preview/offfocal/bright__modes.jpg new file mode 100644 index 00000000..c9a2b293 Binary files /dev/null and b/deployments/@domains/quinn.www/root/public/photos-watermarked/_preview/offfocal/bright__modes.jpg differ diff --git a/deployments/@domains/quinn.www/root/public/photos-watermarked/_preview/offfocal/busy__modes.jpg b/deployments/@domains/quinn.www/root/public/photos-watermarked/_preview/offfocal/busy__modes.jpg new file mode 100644 index 00000000..65b71735 Binary files /dev/null and b/deployments/@domains/quinn.www/root/public/photos-watermarked/_preview/offfocal/busy__modes.jpg differ diff --git a/tooling/scripts/watermark/preview_bc.py b/tooling/scripts/watermark/preview_bc.py new file mode 100644 index 00000000..907f6f32 --- /dev/null +++ b/tooling/scripts/watermark/preview_bc.py @@ -0,0 +1,70 @@ +""" +B vs C, fairly matched: dual-corner (C) vs edge-rail with a stronger plate (B+) +to address the legibility hit Quinn flagged. Rendered on busy + bright. + +Output: public/photos-watermarked/_preview/bc/ +""" + +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") +OUT = os.path.join(PUB + "-watermarked", "_preview", "bc") +CARD_W = 380 + +SAMPLES = [ + ("busy", f"{PUB}/quinn-pink-bra-boots-mural.jpeg"), + ("bright", f"{PUB}/quinn-nude-bed-frontal.jpeg"), +] +MODES = [ + ("C: dual-corner", WatermarkStyle(mode="dual-corner", text_width_frac=0.34)), + ("B: edge-rail (orig)", WatermarkStyle(mode="edge-rail", rail_width_frac=0.46)), + ("B+: edge-rail solid plate", WatermarkStyle(mode="edge-rail", rail_width_frac=0.46, + plate_alpha=215, plate_pad_frac=0.55)), +] + + +def label(im, text): + bar = 24 + out = Image.new("RGB", (im.width, im.height + bar), (18, 18, 22)) + out.paste(im, (0, 0)) + try: + f = ImageFont.truetype(os.path.join(FONT_DIR, "Audiowide-Regular.ttf"), 13) + except Exception: + f = ImageFont.load_default() + ImageDraw.Draw(out).text((5, im.height + 5), text, fill=(255, 120, 190), font=f) + return out + + +def thumb(im, w=CARD_W): + return im.resize((w, round(im.height * w / im.width)), Image.LANCZOS) + + +def hstack(imgs, gap=12): + h = max(i.height for i in imgs) + out = Image.new("RGB", (sum(i.width for i in imgs) + gap * (len(imgs) - 1), h), (18, 18, 22)) + x = 0 + for i in imgs: + out.paste(i, (x, 0)); x += i.width + gap + return out + + +def main(): + os.makedirs(OUT, exist_ok=True) + for sname, src in SAMPLES: + im = Image.open(src) + hstack([label(thumb(render_watermark(im, st)), ml) for ml, st in MODES]) \ + .save(os.path.join(OUT, f"{sname}__bc.jpg"), quality=94) + print("written", OUT) + for f in sorted(os.listdir(OUT)): + print(" ", f) + + +if __name__ == "__main__": + main() diff --git a/tooling/scripts/watermark/preview_offfocal.py b/tooling/scripts/watermark/preview_offfocal.py new file mode 100644 index 00000000..76aa82ef --- /dev/null +++ b/tooling/scripts/watermark/preview_offfocal.py @@ -0,0 +1,88 @@ +""" +Off-focal, crop-resistant candidates — keep the crisp corner look but park the +mark off the subject and out of easy-crop range. + + corner — reference (clippable) + edge-rail — wordmark up a side margin at mid-height (auto-picks calmer side) + dual-corner — top-left + bottom-right; one crop can't remove both + +Output: public/photos-watermarked/_preview/offfocal/ +""" + +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") +OUT = os.path.join(PUB + "-watermarked", "_preview", "offfocal") +CARD_W = 360 + +SAMPLES = [ + ("busy", f"{PUB}/quinn-pink-bra-boots-mural.jpeg"), + ("bright", f"{PUB}/quinn-nude-bed-frontal.jpeg"), +] +MODES = [ + ("corner (clippable)", WatermarkStyle(mode="corner", position="bottom-right")), + ("edge-rail (mid-height)", WatermarkStyle(mode="edge-rail", rail_width_frac=0.46)), + ("dual-corner", WatermarkStyle(mode="dual-corner", text_width_frac=0.34)), +] + + +def label(im, text): + bar = 24 + out = Image.new("RGB", (im.width, im.height + bar), (18, 18, 22)) + out.paste(im, (0, 0)) + try: + f = ImageFont.truetype(os.path.join(FONT_DIR, "Audiowide-Regular.ttf"), 13) + except Exception: + f = ImageFont.load_default() + ImageDraw.Draw(out).text((5, im.height + 5), text, fill=(255, 120, 190), font=f) + return out + + +def thumb(im, w=CARD_W): + return im.resize((w, round(im.height * w / im.width)), Image.LANCZOS) + + +def hstack(imgs, gap=12): + h = max(i.height for i in imgs) + out = Image.new("RGB", (sum(i.width for i in imgs) + gap * (len(imgs) - 1), h), (18, 18, 22)) + x = 0 + for i in imgs: + out.paste(i, (x, 0)); x += i.width + gap + return out + + +def crop_bottom(im, frac=0.18): + return im.crop((0, 0, im.width, int(im.height * (1 - frac)))) + + +def main(): + os.makedirs(OUT, exist_ok=True) + for sname, src in SAMPLES: + im = Image.open(src) + hstack([label(thumb(render_watermark(im, st)), ml) for ml, st in MODES]) \ + .save(os.path.join(OUT, f"{sname}__modes.jpg"), quality=94) + + im = Image.open(SAMPLES[0][1]) + corner = render_watermark(im, MODES[0][1]) + rail = render_watermark(im, MODES[1][1]) + dual = render_watermark(im, MODES[2][1]) + hstack([ + label(thumb(crop_bottom(corner)), "corner — bottom crop: GONE"), + label(thumb(crop_bottom(rail)), "edge-rail — bottom crop: SURVIVES"), + label(thumb(crop_bottom(dual)), "dual-corner — bottom crop: 1 SURVIVES"), + ]).save(os.path.join(OUT, "CROP_ATTACK.jpg"), quality=94) + + print("written", OUT) + for f in sorted(os.listdir(OUT)): + print(" ", f) + + +if __name__ == "__main__": + main() diff --git a/tooling/scripts/watermark/watermark_lib.py b/tooling/scripts/watermark/watermark_lib.py index 07f086fb..964433c5 100644 --- a/tooling/scripts/watermark/watermark_lib.py +++ b/tooling/scripts/watermark/watermark_lib.py @@ -24,10 +24,15 @@ FONT_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "fonts") WATERMARK_TEXT = "transquinnftw.com" -# Kuromi palette -PINK = (255, 46, 151) # electric hot pink — the wordmark fill -PINK_GLOW = (255, 38, 138) # slightly deeper pink for the neon halo -BLACK = (8, 8, 12) # near-black for stroke + plate +# Kuromi palette — SHARED BRAND SOURCE OF TRUTH. +# These MUST match the canonical hex in the provider-site theme tokens: +# deployments/@domains/quinn.www/root/src/themes/kuromi-tokens.ts +# (pink #FF2E97 → PINK, pinkGlow #FF268A → PINK_GLOW, black #08080C → BLACK) +# This is Python with no cross-language import; keep the two in lockstep by +# hand and update both when the brand palette changes. +PINK = (255, 46, 151) # #FF2E97 — electric hot pink — the wordmark fill +PINK_GLOW = (255, 38, 138) # #FF268A — slightly deeper pink for the neon halo +BLACK = (8, 8, 12) # #08080C — near-black for stroke + plate @dataclass(frozen=True)