Spaces:
Sleeping
Sleeping
File size: 5,209 Bytes
c519923 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 | """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()
|