eyewitness / game /poster.py
Fcabla's picture
Upload folder using huggingface_hub
448f595 verified
Raw
History Blame Contribute Delete
3.16 kB
"""Shareable WANTED-poster card: the social/share artifact of a finished case.
Renders 'what you said vs who it was' as a vintage poster PNG the player
downloads and dares friends with. Pure PIL — zero GPU, zero model.
"""
from __future__ import annotations
from PIL import Image, ImageDraw, ImageFont
from .face import FaceSpec
from .render import face_image as _face_img
PAPER = (244, 239, 228)
INK = (43, 42, 40)
RED = (163, 51, 39)
GREEN = (29, 107, 47)
TAPE = (201, 162, 39)
def _font(size: int, bold: bool = False) -> ImageFont.FreeTypeFont:
candidates = [
"/usr/share/fonts/TTF/DejaVuSansMono-Bold.ttf" if bold else "/usr/share/fonts/TTF/DejaVuSansMono.ttf",
"/usr/share/fonts/truetype/dejavu/DejaVuSansMono-Bold.ttf" if bold else "/usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf",
]
for path in candidates:
try:
return ImageFont.truetype(path, size)
except OSError:
continue
return ImageFont.load_default(size)
def make_wanted_poster(
sketch: FaceSpec,
culprit: FaceSpec,
correct: bool,
accuracy_pct: int,
case_name: str,
rank: str,
) -> Image.Image:
W, H = 820, 1000
img = Image.new("RGB", (W, H), PAPER)
d = ImageDraw.Draw(img)
# border + header
d.rectangle([14, 14, W - 14, H - 14], outline=INK, width=4)
d.rectangle([22, 22, W - 22, H - 22], outline=INK, width=1)
d.text((W // 2, 64), "W A N T E D", font=_font(58, bold=True), fill=INK, anchor="mm")
d.text((W // 2, 112), f"CASE: {case_name.upper()} · RANK: {rank}",
font=_font(20), fill=INK, anchor="mm")
d.line([60, 140, W - 60, 140], fill=INK, width=2)
# faces
f1 = _face_img(sketch, 330)
f2 = _face_img(culprit, 330)
img.paste(f1, (70, 180))
img.paste(f2, (W - 70 - 330, 180))
d.rectangle([70, 180, 70 + 330, 180 + 396], outline=INK, width=3)
d.rectangle([W - 70 - 330, 180, W - 70, 180 + 396], outline=INK, width=3)
d.text((70 + 165, 610), "THE WITNESS SAID", font=_font(19, bold=True), fill=INK, anchor="mm")
d.text((W - 70 - 165, 610), "WHO IT ACTUALLY WAS", font=_font(19, bold=True), fill=INK, anchor="mm")
# accuracy + verdict stamp
d.text((W // 2, 680), f"MEMORY ACCURACY: {accuracy_pct}%",
font=_font(30, bold=True), fill=INK, anchor="mm")
stamp_text = "ARREST CONFIRMED" if correct else "STILL AT LARGE"
stamp_color = GREEN if correct else RED
stamp_font = _font(44, bold=True)
# rotated stamp
stamp = Image.new("RGBA", (620, 110), (0, 0, 0, 0))
sd = ImageDraw.Draw(stamp)
sd.rectangle([4, 4, 616, 106], outline=stamp_color, width=6)
sd.text((310, 55), stamp_text, font=stamp_font, fill=stamp_color, anchor="mm")
stamp = stamp.rotate(-5, expand=True, resample=Image.BICUBIC)
img.paste(stamp, (W // 2 - stamp.width // 2, 716), stamp)
# footer
d.text((W // 2, 900), "Could YOUR memory do better?", font=_font(26), fill=INK, anchor="mm")
d.text((W // 2, 944), "EYEWITNESS · build-small-hackathon · 3s glimpse, then you're on your own",
font=_font(16), fill=(93, 86, 74), anchor="mm")
return img