Nodes/Inkvec/Inkvec Trace (raster to SVG)
ComfyUI Node

Inkvec Trace (raster to SVG)

Turning a generated logo into an SVG file you can actually ship

By logolabs·Created 27 days ago·Updated 25 days ago· 2
Inkvec Trace (raster to SVG)
  • image
  • mask
  • svg
  • preview
  • mask
◄precision0.10►
◄min_area2.0►
◄colors64►
◄merge0.035►
◄max_dim2048►
◄time_budget0.0►
◄margin0.00►
◄cutoutauto►
◄no_backgroundfalse►
◄minifyfalse►
◄lossyauto►
◄harmonizetrue►
◄harmonize_threshold0.92►
◄native_alphatrue►
◄content_unitsfalse►
◄timeout_sec300►
◄extra_args►

"Flux is terrific for quickly generating logos" is a true sentence right up until somebody asks for the file. On the thread where that was posted, the comment that stuck was a guy who'd generated a logo he wanted to use for his company, then realised it needed to be a vector - "then it was on to illustrator." That's the gap Inkvec Trace closes: Recraft is the one commercial generator that emits SVG natively, so everywhere else, ComfyUI included, you generate a raster and convert afterwards.

What it actually is

Inkvec Trace is a thin ComfyUI wrapper around Inkvec, LogoLabs' raster-to-SVG tracer. Not a diffusion model doing something that looks like tracing - a purpose-built vectoriser for flat artwork: logos, icons, diagrams, stickers, UI graphics. Photographs are outside its design scope, and one test run shows you why: banding, hundreds of near-identical paths, a file bigger than the PNG.

Under the hood it shells out to the native inkvec Rust binary, so the tracer's behaviour is the binary's behaviour.

How it works

The tracer reduces your image to a palette of at most colors inks, merging any two colours closer than merge in OKLab - the "these are the same colour" knob, and why a JPEG-ish gradient collapses into a handful of flat fills instead of a mess. Then it fits geometry to each ink region.

precision is where the real dial is. It sets the MDL cost of a coordinate, lambda = ln(extent / precision): smaller keeps more detail with more points. Despite the name it does not control output decimals - coordinates are always written with two. min_area throws away specks below that many square pixels, your despeckle for noisy input.

Defaults are the CLI's own, and the node passes every numeric widget explicitly, so what you see is what runs.

Inputs that matter

  • image - the raster. Anything over max_dim (2048) on its long side is traced at 2048 while the SVG is still written at the original size. Nice default, but a 6K scan is then fitted from a downscaled view; raise max_dim if hairlines vanish.
  • mask - transparency, LoadImage's convention (1 = transparent). Connect LoadImage's MASK and holes survive into the SVG. A segmentation mask is the other way round: run Invert Mask first.
  • lossy - noise-aware intake for compressed input. The trap: the CLI's auto sniffs the file type, but ComfyUI hands the node decoded pixels, written as PNG, so auto behaves like a PNG here. Set it on for JPEG/WebP sources and anything from Inkvec Denoise.

native_alpha (on, inkvec 0.1.4+) traces transparency properly - inks carry opacity, holes stay holes, so white artwork on transparency survives. Leave it on. no_background drops the face covering the whole canvas, which is how you get artwork on transparency. content_units is the one to watch: it scales fit tolerances to the raster, which is great for parameter count and will absolutely turn a small square into a circle. timeout_sec (300) is the node's own; extra_args appends raw CLI flags last, overriding the widgets.

Outputs

svg is a STRING and a list - one string per image in the batch, so downstream nodes run once per image. Wire it straight into Inkvec Save SVG.

preview is the traced SVG rendered back to pixels and mask is that render's transparency (1 = transparent), so preview + mask through Join Image with Alpha gives you RGBA. Both need resvg-py or cairosvg; with no renderer installed the node passes the input image through and logs a note instead of failing.

Install

ComfyUI Manager: search "Inkvec" (publisher logolabs-org) and install, then restart. Manually:

cd ComfyUI/custom_nodes
git clone https://github.com/logolabs/inkvec-comfyui.git
pip install -r inkvec-comfyui/requirements.txt

On the Windows portable build, use python_embeded\python.exe -m pip install -r inkvec-comfyui\requirements.txt. The requirements are resvg-py, onnxruntime, huggingface_hub and einops; torch, numpy and Pillow already ship with ComfyUI.

The first trace downloads the inkvec binary for your platform from the project's GitHub releases (about 2 MB), verifies it against the release SHA256SUMS, health-checks it with inkvec --version, and caches it in ComfyUI/models/inkvec/<version>/. It is not updated automatically - delete that folder to pull a newer release. Offline, grab the archive yourself and point INKVEC_BIN at the executable.

Where people get burned

A big image times out and looks like a hang. Trace cost grows with pixel count. The node errors after timeout_sec, and the fix menu is in that message: raise timeout_sec, lower max_dim, or set time_budget - a budget expiry still gives a correct, slightly rougher trace rather than nothing.

A proxy or antivirus eats the binary. Downloading and running an executable on first use is the one part of this pack that security software objects to. If it fails, the error tells you to fetch the file by hand and point INKVEC_BIN at it.

The widgets and the binary disagree. native_alpha and content_units need inkvec 0.1.4; flip one on an older cached release and the CLI reports an unknown option. Re-download the binary (INKVEC_VERSION=0.1.4 pins it if you want it locked).

Text is traced as outlines, never as <text> - fine for a logo, surprising if you wanted selectable type. And if the source is a photograph, stop: vectorisation wants flat art, and no amount of dial-turning changes that.

CategoryInkvec

Inputs (19)

NameTypeDefaultDescription
imageIMAGE—
precisionFLOAT0.100.01–10Sets the MDL cost of a coordinate: lambda = ln(extent / precision). Smaller keeps more detail with more points. It does not set the digits the emitter writes; output coordinates are fixed at 2 decimals. CLI --precision.
min_areaFLOAT2.00–10000Discard features below this area, in px^2. CLI --min-area.
colorsINT641–4096Maximum palette size. CLI --colors.
mergeFLOAT0.0350–0.5OKLab distance below which two colours are one ink. CLI --merge.
max_dimINT20480–16384Inputs larger than this on their longer side are traced at this size and the SVG is written at the original size. Trace time grows with the pixel count. 0 means no cap. CLI --max-dim.
time_budgetFLOAT0.00–3600Advisory wall-clock budget in seconds. When it runs out the output is still a correct trace, with more fills or a less polished outline. 0 means no budget. CLI --time-budget.
marginFLOAT0.000–0.5Transparent margin around the output, as a fraction of the larger side; the viewBox grows, the geometry does not move. CLI --margin.
cutoutCOMBOautoCarry the input's transparency into the SVG: transparent areas stay holes, a shape drawn at one opacity keeps fill-opacity, and white artwork on a transparent ground survives. auto = on when the image or the mask input has any transparency, off for opaque images. Inkvec 0.1.4 traces transparency natively (native_alpha), which already carries it out, so there this only matters with native_alpha off; on 0.1.3 and older it is what keeps the holes, which is why auto passes it for any transparent image. CLI --cutout.
no_backgroundBOOLEANfalseKnock the background out: the face that covers the whole canvas is not painted, so the artwork sits on transparency. CLI --no-background.
minifyBOOLEANfalseNo ids or groups, no trailing zeros. Same geometry, typically about a tenth smaller. CLI --minify.
lossyCOMBOautoNoise-aware intake for compressed input. The CLI's auto reads the file type, but ComfyUI hands the node decoded pixels (written as PNG), so auto behaves like a PNG here. Set on for JPEG/WebP sources and for images from Inkvec Denoise (inkvec --restore does the same). CLI --lossy.
harmonizeBOOLEANtrueShape harmonization (the CLI default: on). Marks that repeat across the drawing are matched by outline similarity and redrawn from one consensus geometry per cluster, which saves parameters on repetitive art. A mark takes the consensus only where that stays within 0.1 px of the boundary traced for it and costs fewer parameters; a face another face is drawn against, and a fitted circle or rounded rectangle, is never moved. Turn it off to skip the pass. CLI --harmonize.
harmonize_thresholdFLOAT0.920–1Shape-equivalence IoU threshold for harmonization. CLI --harmonize-threshold.
native_alphaBOOLEANtrueTrace transparency natively: each ink carries an opacity and the transparent ground is an ink of its own -- holes stay holes, glows and shadows stay translucent, and white artwork on a transparent ground traces. An opaque image traces the same either way, so leave it on. Off composites onto a matte first, as inkvec releases up to 0.1.3 did. Needs inkvec 0.1.4; an older binary reports --no-native-alpha as an unknown option. CLI --native-alpha.
content_unitsBOOLEANfalseScale the fit tolerances with the raster, so a large, simple drawing gets the parameter count of a small one. Trades fidelity for parsimony: small squares can come back as circles and thin rings broken. Needs inkvec 0.1.4. CLI --content-units.
timeout_secINT3005–7200The node stops the tracer after this many seconds and reports an error.
maskoptMASKTransparency, as LoadImage outputs it (1 = transparent). A mask where 1 marks the subject must be inverted first (InvertMask).
extra_argsoptSTRINGFurther inkvec flags, appended last so they override the widgets, e.g. --strokes or --layers. A flag the installed binary does not know is reported as an error. -o/--output/--help/--version are not allowed.

Outputs (3)

NameTypeDescription
svgSTRINGThe SVG source, one string per image in the batch.
previewIMAGEThe SVG rendered back to pixels (needs resvg-py or cairosvg; otherwise the input image).
maskMASKTransparency of the rendered SVG, 1 = transparent (LoadImage's convention).