Generating a leather pattern as a tabloid-size PDF
I wanted a coffin-shaped wallet pattern I could print and saddle-stitch. Online templates are mostly rectangles. The interesting work was turning a six-sided silhouette into a multi-panel pattern with stitch holes and registration marks on a single tabloid sheet.
What was happening
The wallet has four pieces: back panel + flap as a single piece, front trapezoidal body, bill divider, and four cascending card slots. Closed silhouette is 5" at the shoulders × 7" tall, with flap dropping 2" past the shoulder edge. Bills load through the shoulder edge; cards stack four-deep with a 1.5" reveal between each.
I wanted to print it at 1:1 on tabloid paper (11" × 17"), cut once, and start stitching. That meant a single SVG with all four panels laid out, scaled correctly, with stitch holes pre-marked at 3/16" inset on a 7 SPI (stitches per inch) spacing.
What I found
Three layers in the SVG:
- Cut lines (red, 0.5 pt) — outer perimeter of each panel
- Stitch holes (small black dots) — 1.5 mm dia, 3/16" inset, 7 SPI
- Registration marks and labels (black, panel names + grain direction)
The coffin silhouette is six straight edges: bottom, two lower slants up to the shoulder, two shoulder edges to the head, top. Parametrized by total height H, shoulder width W_s, head width W_h, and shoulder-position fraction f:
def coffin_outline(H, W_s, W_h, f):
cx = W_s / 2
shoulder_y = H * f
return [
(0, 0), # bottom-left
(-W_s/2 + cx, 0), # (same; bottom is flat)
(W_s, 0), # bottom-right
(W_s, shoulder_y), # right shoulder
((W_s + W_h)/2, H), # head right
((W_s - W_h)/2, H), # head left
(0, shoulder_y), # left shoulder
(0, 0), # back to bottom-left
]
Stitch holes get walked along each edge segment. For a segment of length L, place floor(L / spacing) holes at the right inset offset from the edge:
def stitch_holes(polyline, inset_in, spacing_in):
holes = []
for (x0, y0), (x1, y1) in zip(polyline, polyline[1:]):
dx, dy = x1 - x0, y1 - y0
L = (dx*dx + dy*dy) ** 0.5
if L == 0: continue
# unit normal pointing inward (assumes CCW)
nx, ny = -dy / L, dx / L
n = int(L / spacing_in)
for i in range(n + 1):
t = (i + 0.5) / max(n + 1, 1)
x = x0 + t*dx + nx*inset_in
y = y0 + t*dy + ny*inset_in
holes.append((x, y))
return holes
Panels are positioned on the tabloid sheet by a simple bin-packer that respects grain direction (leather doesn't stretch evenly across the hide). I put the back/flap piece vertically because it's the longest dimension, then fit the front body, bill divider, and card slot stack into the remaining real estate.
SVG to PDF via rsvg-convert:
rsvg-convert -f pdf -w 1224 -h 1584 pattern.svg > pattern.pdf
# 1224 × 1584 = 17" × 11" at 72 DPI
The "print at actual size" instruction on the cover page matters. Most desktop print dialogs default to "fit to page" which silently scales the pattern. The pattern includes a 1" registration square in a corner; if it doesn't measure 1" after you print, your scale is wrong and you need to reprint with scaling disabled.
What I'd do differently
The stitch-hole spacing should be a derived value, not a knob. Saddle stitching wants the holes on opposing panels to align so the same awl goes through both layers, which means the hole count on the body's shoulder edge has to match the hole count on the flap's shoulder edge. I solved that by computing one edge's count and propagating it, instead of letting both panels independently divide their lengths by spacing. The first version had panels with 23 holes meeting panels with 22, which sounds like nothing until you're trying to thread waxed cord through misaligned holes at 11pm.