SVG Editor
Fill a vector template with your own images and text
- image1
- image2
- image3
- IMAGE
ComfyUI is ruthlessly pixel-based. Nearly everything in the graph is a raster IMAGE tensor, and the vector world - SVG files, fonts, layout - barely exists. SVG Editor (from stormcenter/ComfyUI-SVGFullfill) is a niche attempt to bridge that. Give it an SVG whose elements have the right ids and it swaps in up to 3 of your generated images and up to 10 text strings, then rasterizes the result to a normal IMAGE that plugs straight into Save Image or anywhere else you'd send pixels.
Why you'd reach for it
Any time you want your output locked inside a fixed frame: a poster template, a certificate, a badge, a comic title card, a label layout. Vector generation is still a corner of this ecosystem (Recraft's SVG output is the outlier everyone name-drops), but hand-written or designer-made SVG templates are everywhere. This node is the glue that puts generated content inside them without leaving the workflow, and - the detail that tells you who wrote it - it ships with a Chinese font (AaYuanWeiTuSi-2.ttf) so CJK text renders correctly out of the box.
How it works
All the work happens server-side in Python. The node parses your SVG with ElementTree, injects a @font-face pointing at the first font it finds in its font/ directory, then walks the DOM:
<text>elements withid="text1"throughid="text10"get their contents replaced and styled with that injected font.<image>elements withid="image1",id="image2",id="image3"get theirhrefreplaced with a base64-encoded PNG of whatever IMAGE you wired in - position and size attributes are preserved.- The result is rendered to PNG with cairosvg and returned as an IMAGE tensor at the SVG's declared width/height (800×800 if the file doesn't set one).
That means your template has to be prepared - the ids are the contract. The README's <text id="text1">Replaceable Text 1</text> is the shape you need. No id, no replacement; the element is simply left alone. This is why "Editor" is a generous name: there are no handles to drag, it's a find-and-replace renderer. But if your mental model is "I have a template and want to fill it in," that's exactly right.
The inputs that matter
svg_text is the required input - raw SVG markup. Wire it from the companion SVG Uploader node, or from any node that outputs SVG as a string if you're generating templates programmatically. Then image1–image3 accept IMAGE tensors straight off any sampler or loader (optional - skip the slots you don't use), and text1–text10 are plain multiline strings; only non-empty ones are applied. The single output is IMAGE, ready for Save Image, a VAE decode, or anything downstream.
Install
ComfyUI Manager, search "ComfyUI-SVGFullfill", or:
cd ComfyUI/custom_nodes
git clone https://github.com/stormcenter/ComfyUI-SVGFullfill
then restart ComfyUI. The repo's requirements.txt pulls in Pillow, numpy and cairosvg. That last one is the dependency to watch - cairosvg needs the cairo graphics library underneath, and on Linux that sometimes means installing a system libcairo2 before the pip package will cooperate. No model downloads. Drop more .ttf/.otf files into the font/ directory and the first one found gets used for replaced text.
Where people get burned
- The limits in the README are hard-coded: 3 image slots, 10 text slots. That's it.
- External images referenced by URL in your SVG won't work - base64-embed them first.
- SVG animations are flattened or ignored; this is a still-image renderer.
- If anything throws, you silently get a 64×64 black image out of the node - an extremely confusing failure mode. The
Error processing SVGtraceback lives in the console, so check there first.
Start troubleshooting with the console, then an id typo, then the font. In that order, you'll find it.
Inputs (14)
| Name | Type | Default | Description |
|---|---|---|---|
| svg_text | STRING | — | |
| image1opt | IMAGE | — | |
| image2opt | IMAGE | — | |
| image3opt | IMAGE | — | |
| text1opt | STRING | — | |
| text2opt | STRING | — | |
| text3opt | STRING | — | |
| text4opt | STRING | — | |
| text5opt | STRING | — | |
| text6opt | STRING | — | |
| text7opt | STRING | — | |
| text8opt | STRING | — | |
| text9opt | STRING | — | |
| text10opt | STRING | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| IMAGE | IMAGE | — |