SVG Visual Normalize & Margin
Make Your SVG Actually Fill the Canvas, Not Just Sit in It
- STRING
Every SVG workflow hits the same wall eventually: the vector comes back technically correct but framed like garbage. Tiny in a huge canvas, hugging the top-left corner, or with a giant empty margin you didn't ask for. This node fixes that - and it does it by looking, not by doing math on path coordinates.
Here's the thing about geometric bounding boxes: they lie. Strokes overflow their path bounds, rotated text extends past its box, filters and blurs spill outside everything. For simple shapes a bounding-box calculation works. For the messy output of an LLM generating SVG or a raster-to-vector tracer, it drifts. SVGVisualBoundsNormalize (display name "SVG Visual Normalize & Margin") instead renders your SVG to a temporary raster and measures where the actual opaque pixels are. Then it scales that artwork to fill the canvas, centers it, and applies an optional margin.
How it works
Under the hood it's a short pipeline: CairoSVG rasterizes your svg_string to a temp PNG, Pillow's getbbox() finds the painted-pixel region, and that region is mapped back into SVG units. The node then wraps every child element in one <g> with a single translate(...) scale(...) transform and rewrites the canvas as viewBox="0 0 w h". One transform, no per-element surgery - which means it survives round-tripping through other SVG nodes in your graph. It's also MIT-licensed and one file, so it's easy to read if you want to see exactly what it's doing.
The inputs that matter
svg_string- paste or wire in your SVG code. That's the whole job.margin_percent- margin as a fraction of canvas, applied after fill and center.0.05= a 5% border. Capped at0.499, because past half you're just drawing a rectangle.visual_bbox_padding_percent- expands the detected visual bounds as a safety buffer against clipping. Start at0, bump it only if you see cut-off edges.center_offset_x_percent/center_offset_y_percent- manual nudge when the visual centering doesn't match your eye. Positive X shifts right, positive Y shifts down.output_width/output_height- set the output canvas. Zero means "keep the other side proportional"; both zero means original dimensions. Max 8192.render_scale_for_bbox(advanced) - the internal rasterization scale. Higher = more accurate bounds on very detailed SVGs, slower to run. Leave at1.0unless you're chasing clipped antialiasing.
The single output is a STRING: your normalized SVG. That feeds into whatever renders or previews SVG in your graph.
Installing it
It's a one-node, one-commit pack, so install is the standard drill:
cd ComfyUI/custom_nodes
git clone https://github.com/coulterj/comfyui-svg-visual-normalize
pip install -r requirements.txt # in your ComfyUI environment
It may also show up under "SVG Visual Normalize" in ComfyUI Manager. The real gotcha is the system dependency: CairoSVG needs the Cairo C library, and that's not a pip thing. On Debian/Ubuntu: sudo apt-get install libcairo2-dev libgdk-pixbuf2.0-dev python3-dev. On macOS: brew install cairo libffi pkg-config. Windows is the painful one - you typically need a GTK+ bundle. If the node spits a red [ERROR] The required 'CairoSVG' library is not installed line at startup, that's the missing piece, not your code.
Where people get burned
The node fails safe: if it can't parse your SVG, can't find a visual bbox (e.g. fully transparent input), or Cairo is missing, it returns your string unchanged rather than corrupting it. You'll also see its debug --- SVGVisualBoundsNormalize: Process Start --- output in the ComfyUI console - read that when something looks off; it logs the detected bbox and final transform. One thing to know: output is re-serialized through lxml, so your whitespace and comments get normalized away, and exotic namespaces or <foreignObject> content may not survive the trip. For normal text-to-vector and traced artwork, it just works - and it's the difference between an SVG that needs manual fixing and one that's ready to drop into your pipeline.
Inputs (8)
| Name | Type | Default | Description |
|---|---|---|---|
| svg_string | STRING | — | |
| margin_percent | FLOAT | 0.0000–0.499 | — |
| visual_bbox_padding_percent | FLOAT | 0.0000–0.1 | — |
| center_offset_x_percent | FLOAT | 0.000-0.5–0.5 | — |
| center_offset_y_percent | FLOAT | 0.000-0.5–0.5 | — |
| output_width | INT | 00–8192 | — |
| output_height | INT | 00–8192 | — |
| render_scale_for_bbox | FLOAT | 1.00.5–4 | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| STRING | STRING | — |