WitnessBox / scripts /make_portrait_placeholder.py
Farseen0's picture
Deploy WitnessBox
c519923 verified
Raw
History Blame Contribute Delete
5.21 kB
"""Render a courtroom-sketch witness placard as the portrait placeholder.
python3 scripts/make_portrait_placeholder.py -> assets/marcus_reid.png
app.py shows assets/marcus_reid.png if it exists, else an empty box. A real
AI portrait (HF ZeroGPU) can overwrite this file later; until then this gives the
demo an intentional, on-theme visual instead of a blank frame. Pure PIL — no GPU,
no network — and it matches the app's parchment palette.
"""
from __future__ import annotations
import os
from PIL import Image, ImageDraw, ImageFont
W, H = 768, 960
PARCH = (239, 231, 211) # #efe7d3 page
CARD = (247, 241, 225) # #f7f1e1
BORDER = (201, 183, 141) # #c9b78d
INK = (58, 44, 24) # #3a2c18
SUB = (107, 88, 54) # #6b5836
MAROON = (122, 47, 47) # #7a2f2f
SKETCH = (90, 74, 53) # sepia for the silhouette
SKETCH_HI = (120, 102, 78)
FONT_DIRS = [
"/System/Library/Fonts/Supplemental/",
"/System/Library/Fonts/",
"/Library/Fonts/",
]
SERIF = ["Georgia.ttf", "Palatino.ttc", "Times New Roman.ttf", "Baskerville.ttc"]
SERIF_B = ["Georgia Bold.ttf", "Times New Roman Bold.ttf", "Georgia.ttf"]
def _font(names, size):
for d in FONT_DIRS:
for n in names:
p = os.path.join(d, n)
if os.path.exists(p):
try:
return ImageFont.truetype(p, size)
except Exception:
pass
return ImageFont.load_default()
def _spaced(draw, xy, text, font, fill, spacing=6, anchor_center=None):
"""Draw letter-spaced text; if anchor_center given, center on that x."""
widths = [draw.textlength(c, font=font) for c in text]
total = sum(widths) + spacing * (len(text) - 1)
x = (anchor_center - total / 2) if anchor_center is not None else xy[0]
y = xy[1]
for c, w in zip(text, widths):
draw.text((x, y), c, font=font, fill=fill)
x += w + spacing
return total
def _scales(draw, cx, top):
"""A small balance-scale glyph, drawn from primitives."""
col = INK
draw.line([(cx, top), (cx, top + 54)], fill=col, width=4) # post
draw.ellipse([cx - 5, top - 5, cx + 5, top + 5], fill=col) # finial
beam_y, span = top + 14, 70
draw.line([(cx - span, beam_y), (cx + span, beam_y)], fill=col, width=4)
for sx in (cx - span, cx + span):
draw.line([(sx, beam_y), (sx - 18, beam_y + 34)], fill=col, width=2)
draw.line([(sx, beam_y), (sx + 18, beam_y + 34)], fill=col, width=2)
draw.arc([sx - 20, beam_y + 24, sx + 20, beam_y + 50], 0, 180, fill=col, width=3)
draw.line([(cx - 26, top + 54), (cx + 26, top + 54)], fill=col, width=4) # base
def _silhouette(draw, cx, cy):
"""A courtroom-sketch bust: shoulders, neck, head, with a suit + tie hint."""
# shoulders / suit
draw.ellipse([cx - 165, cy + 70, cx + 165, cy + 360], fill=SKETCH)
draw.rectangle([cx - 165, cy + 215, cx + 165, cy + 360], fill=SKETCH)
# collar V + tie
draw.polygon([(cx - 40, cy + 95), (cx, cy + 185), (cx + 40, cy + 95)], fill=CARD)
draw.polygon([(cx - 12, cy + 120), (cx + 12, cy + 120), (cx + 18, cy + 210),
(cx, cy + 235), (cx - 18, cy + 210)], fill=(64, 40, 40)) # tie
draw.polygon([(cx - 40, cy + 95), (cx - 14, cy + 112), (cx, cy + 150),
(cx - 16, cy + 150)], fill=SKETCH_HI) # lapel L
draw.polygon([(cx + 40, cy + 95), (cx + 14, cy + 112), (cx, cy + 150),
(cx + 16, cy + 150)], fill=SKETCH_HI) # lapel R
# neck + head
draw.rectangle([cx - 26, cy + 40, cx + 26, cy + 110], fill=SKETCH)
draw.ellipse([cx - 70, cy - 110, cx + 70, cy + 60], fill=SKETCH)
# hair sweep
draw.chord([cx - 72, cy - 120, cx + 72, cy + 10], 180, 360, fill=SKETCH_HI)
def main():
root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
out_dir = os.path.join(root, "assets")
os.makedirs(out_dir, exist_ok=True)
out = os.path.join(out_dir, "marcus_reid.png")
img = Image.new("RGB", (W, H), PARCH)
d = ImageDraw.Draw(img)
# card with double frame
m = 28
d.rectangle([m, m, W - m, H - m], fill=CARD, outline=BORDER, width=3)
d.rectangle([m + 12, m + 12, W - m - 12, H - m - 12], outline=BORDER, width=1)
f_top = _font(SERIF_B, 30)
f_name = _font(SERIF_B, 58)
f_sub = _font(SERIF, 27)
f_foot = _font(SERIF, 20)
_scales(d, W // 2, 62)
_spaced(d, (0, 150), "SWORN WITNESS", f_top, MAROON, spacing=10, anchor_center=W // 2)
_silhouette(d, W // 2, 330)
# nameplate bar
bar_y = 720
d.rectangle([m + 40, bar_y, W - m - 40, bar_y + 86], fill=INK)
_spaced(d, (0, bar_y + 16), "MARCUS REID", f_name, CARD, spacing=4, anchor_center=W // 2)
sub = "Chief Financial Officer · Halcyon Dynamics"
tw = d.textlength(sub, font=f_sub)
d.text(((W - tw) / 2, bar_y + 104), sub, font=f_sub, fill=SUB)
foot = "WitnessBox — State's Exhibit"
fw = d.textlength(foot, font=f_foot)
d.text(((W - fw) / 2, H - m - 52), foot, font=f_foot, fill=BORDER)
img.save(out)
print(f"wrote {out} ({W}x{H})")
if __name__ == "__main__":
main()