ipolypad turns an image or SVG into a small, normalized
polygon hull (16–32 points) ideal for CSS shape-outside and
HTML/canvas text-wrap engines. Two implementations share one spec.
What it does
image / SVG → rasterize → silhouette mask → pad (dilate/erode) →
potrace → pick outer shell → convex hull →
simplify (RDP) → normalize → JSON / CSS
The output is intentionally low-fidelity: text-wrap algorithms don’t need a precise outline, they need a small polygon that hugs the visible shape with a sensible visual gap. ~32 vertices is the sweet spot.
Padding is real geometry, not a clipped inset trick. If the padded silhouette
extends outside the source image rectangle, the emitted polygon can contain
negative percentages or values above 100%.
Negative padding erodes the silhouette for tighter wraps.
Pick your language
- Python — reference. Smart input
handling (colour-distance background detection, auto-contrast, adaptive
thresholding), CLI via
uvx ipolypad, emitsjson/css/svg/png/html. - JavaScript — browser-first.
Strict subset, small bundle, assumes alpha-bearing input, emits
json/css.
For the full algorithmic contract see the specification.
Try it
The interactive demo lets you drop in an SVG
or PNG, runs ipolypad-js in the browser, and reflows a passage of text
around the resulting polygon via pretext-flow.
Output
Default JSON:
{
"src": "dragon.svg",
"raster": { "width": 200, "height": 200, "pad": 6 },
"max_points": 32,
"n_points": 18,
"points": [[0.500000, 0.020000], ...]
}
CSS:
.figure {
shape-outside: polygon(-1.28% 55.64%, 50.00% -8.20%, 103.52% 61.10%, /* ... */);
clip-path: polygon(-1.28% 55.64%, 50.00% -8.20%, 103.52% 61.10%, /* ... */);
}
Asymmetric by design
The Python package is the smart one — colour analysis, auto-contrast, batch, multi-format output. The JavaScript package is intentionally a strict subset so it stays small enough to ship to a browser. They agree byte-for-byte on the overlapping parity surface; everything else is one-sided on purpose.
License
Apache-2.0. See the GitHub repo.