Image to SVG
Convert transparent or solid-background single-color artwork into a genuine SVG containing paths rather than an embedded bitmap.
Automatic tracing approximates the raster boundary. Only the original vector source can provide mathematically exact curves.
Scope
Supported:
- Transparent PNG.
- PNG on a pure-color background, including white, red, green, or other flat colors.
- SVG containing exactly one Base64 or local PNG.
- Single-color logos, stamps, engravings, silhouettes, and detailed line art.
Reject:
- Photos, gradients, textured backgrounds, and multicolor artwork.
- Remote image URLs.
- SVG mixing raster artwork with existing paths.
- Centerline or editable-stroke reconstruction.
For multicolor artwork, recommend VTracer instead of forcing this workflow.
Script Directory
Important: All scripts are located in the scripts/ subdirectory of this skill.
Agent Execution Instructions:
- Determine this SKILL.md file's directory path as
SKILL_DIR. - Set command working directory to
${SKILL_DIR}. - Execute
bun ${SKILL_DIR}/scripts/vectorize.ts. - Replace
${SKILL_DIR}with the absolute path.
| Script | Purpose |
|---|---|
scripts/vectorize.ts |
Extract alpha, scan Potrace candidates, measure error, and deliver the best path-only SVG |
scripts/vectorize.test.ts |
Unit and real-toolchain regression tests |
Dependencies
Detect the runtime once per session:
command -v bun
command -v ffmpeg
command -v ffprobe
command -v potrace
command -v rsvg-convert || command -v inkscape
Required:
- Bun.
- FFmpeg and FFprobe.
- Potrace.
- One SVG renderer:
rsvg-convertfrom librsvg, or Inkscape.
If a dependency is missing, install it directly with the available package manager. Report only when installation fails or no package manager is available.
Common macOS installation:
brew install oven-sh/bun/bun
brew install ffmpeg potrace librsvg
If Homebrew is unavailable, install with the platform package manager. Do not ask before installing missing conversion dependencies.
Workflow
Confirm the input is within scope.
Run the converter:
bun ${SKILL_DIR}/scripts/vectorize.ts "/absolute/path/to/input.svg"Read
<source-slug>.report.json.Confirm:
structure.pathCount >= 1;structure.imageCount === 0;structure.dataImageCount === 0;verified4x === true.backgroundRemoval.applied === trueonly when the input had a solid background.
Inspect the PNG preview, especially fine lines, holes, hatching, and sharp corners.
Report the SVG, preview, selected threshold, MAE, RMSE, and IoU.
Choose the objective explicitly:
- Use default
maefor the closest alpha appearance. - Use
ioufor overlap, contour match, 轮廓重合率, or IoU requests. - Use
rmseonly when large alpha errors matter more than average error.
Never describe the result as lossless. Say “high-fidelity true vector” and include measured error.
Usage
Specify an output parent directory:
bun ${SKILL_DIR}/scripts/vectorize.ts input.png --output-dir ./output
Override the detected color:
bun ${SKILL_DIR}/scripts/vectorize.ts input.svg --color "#0113a8"
Use solid-background PNG directly; do not preprocess manually:
bun ${SKILL_DIR}/scripts/vectorize.ts "logo-on-white.png"
Preserve all threshold candidates for manual comparison:
bun ${SKILL_DIR}/scripts/vectorize.ts input.svg --keep-candidates
Temporary candidates are deleted by default. Keep them only when tuning, comparing versions, or resolving visual review disputes.
Advanced threshold control:
bun ${SKILL_DIR}/scripts/vectorize.ts input.svg \
--threshold-min 120 \
--threshold-max 140 \
--threshold-step 2
Validated defaults are 124..144, step 2, Potrace alphamax=0.2, and optimization tolerance 0.03.
Optimize for binary outline overlap and scan Potrace smoothing:
bun ${SKILL_DIR}/scripts/vectorize.ts input.svg \
--objective iou \
--threshold-min 122 \
--threshold-max 132 \
--threshold-step 1 \
--alphamax 0,0.2 \
--opttolerance 0,0.03
For detailed hard-edge art, alphamax=0 can raise IoU by avoiding curve smoothing. Do not hard-code color during experiments; inherit wrapper fill or use --color.
Output
Single-file runs write directly into the chosen output directory:
<output-dir>/
├── <source-slug>.svg
├── <source-slug>.preview.png
└── <source-slug>.report.json
Default runs do not create candidates/. With --keep-candidates, also write all measured candidates:
<output-dir>/
├── <source-slug>.svg
├── <source-slug>.preview.png
├── <source-slug>.report.json
└── candidates/
├── candidate-t128-a0-o0.svg
├── candidate-t128-a0-o0.png
└── ...
If --output-dir is omitted, create <source-slug>-svg-output/ next to the input. Existing results are never overwritten; repeated runs append a timestamp to the output filename prefix. Do not copy the source file by default; the report records sourcePath.
For multiple input files, create one subdirectory per source under the chosen output parent to avoid collisions:
<output-parent>/
├── first-image/
│ ├── first-image.svg
│ ├── first-image.preview.png
│ └── first-image.report.json
└── second-image/
├── second-image.svg
├── second-image.preview.png
└── second-image.report.json
The report records backgroundRemoval when a pure-color background was converted to alpha. Intermediate PGM files remain temporary; candidate SVG/PNG files are preserved only with --keep-candidates.
Validation
Run:
bun test ${SKILL_DIR}/scripts/vectorize.test.ts
For final delivery, also validate the generated SVG:
xmllint --noout "/path/to/result.svg"
rg -o '<path\b|<image\b|data:image/' "/path/to/result.svg" | sort | uniq -c
The final SVG must contain paths and no raster references.