# Genera docs/calle.svg: ilustración stencil "a la calle"
import sys, random
from fontTools.ttLib import TTFont
from fontTools.pens.svgPathPen import SVGPathPen
from fontTools.pens.transformPen import TransformPen
random.seed(26)
FONT, OUT = sys.argv[1], sys.argv[2]
W, H = 1200, 640
INK, RED = "#000", "#ff1f1f"
out = []
def add(s): out.append(s)
def text_path(txt, x, y, size, fill, anchor="middle", font=FONT):
f = TTFont(font); gs = f.getGlyphSet(); cmap = f.getBestCmap()
upm = f["head"].unitsPerEm; k = size / upm
widths = [f["hmtx"][cmap[ord(c)]][0] for c in txt]
total = sum(widths) * k
cx = x - total / 2 if anchor == "middle" else x
d = []
for c, w in zip(txt, widths):
pen = SVGPathPen(gs)
gs[cmap[ord(c)]].draw(TransformPen(pen, (k, 0, 0, -k, cx, y)))
d.append(pen.getCommands()); cx += w * k
return f''
def blob(cx, cy, r, n, jit, fill, op=1):
import math
pts = []
for i in range(n):
a = 2 * math.pi * i / n
rr = r * (1 + random.uniform(-jit, jit))
if random.random() < .25: rr *= 1.25
pts.append((cx + rr * math.cos(a), cy + rr * math.sin(a)))
d = f"M{pts[0][0]:.0f},{pts[0][1]:.0f} " + " ".join(
f"Q{p[0]:.0f},{p[1]:.0f} {(p[0]+q[0])/2:.0f},{(p[1]+q[1])/2:.0f}"
for p, q in zip(pts, pts[1:] + pts[:1])) + "Z"
add(f'')
def splats(cx, cy, spread, n, rmax, fill):
for _ in range(n):
x = cx + random.gauss(0, spread); y = cy + random.gauss(0, spread * .6)
add(f'')
def drips(x0, x1, y, fill, n):
for _ in range(n):
x = random.uniform(x0, x1); l = random.uniform(15, 70); w = random.uniform(5, 11)
add(f'')
def tent(x, y, w, h):
add(f'')
add(f'')
add(f'')
def fig(x, y, s=1.0, pose="down", step=1):
L = lambda *p: " ".join(f"{a:.0f}" for a in p)
sw = 19 * s
st = f'stroke="{INK}" stroke-width="{sw:.0f}" stroke-linecap="round" stroke-linejoin="round" fill="none"'
hipy = y - 78 * s; shy = y - 150 * s
# piernas (andando)
add(f'')
add(f'')
# torso (chupa)
add(f'')
# cresta (detrás) + cabeza
if pose in ("fist", "cresta"):
for i in range(5):
dx = (i - 2) * 11 * s
add(f'')
add(f'')
# brazos
ls, rs = (x - 27 * s, shy + 8 * s), (x + 27 * s, shy + 8 * s)
if pose == "fist":
add(f'')
add(f'')
add(f'')
elif pose.startswith("pole"):
side = -1 if pose == "poleL" else 1
px = x + side * 46 * s
add(f'')
add(f'')
else:
add(f'')
add(f'')
add(f'')
open(OUT, "w").write("\n".join(out))