# img2svg
A high-performance image to SVG converter written in Rust. Transform raster images (PNG, JPEG, etc.) into scalable vector graphics with cubic Bézier curves, edge-aware quantization, and advanced path optimization.
[](https://github.com/yingkitw/img2svg)
[](LICENSE)
## Why img2svg?
### The Problem
Converting raster images to vector format is essential for:
- **Scalability**: Vector graphics scale infinitely without quality loss
- **File size optimization**: Simple shapes often result in smaller SVG files than raster counterparts
- **Editability**: Vectors can be modified in design tools (Illustrator, Inkscape, Figma)
- **Web performance**: SVGs are code-based and can be optimized, animated, and styled with CSS
### Why img2svg?
| **Pure Rust** | ✅ | ❌ (C++) | ❌ (C) | ❌ (Web only) |
| **Color Support** | ✅ Full color | ✅ | ❌ B&W only | ✅ |
| **Library API** | ✅ | ❌ CLI only | ❌ CLI only | ❌ Web only |
| **MCP Server** | ✅ | ❌ | ❌ | ❌ |
| **Local Processing** | ✅ | ✅ | ✅ | ❌ (Cloud) |
| **Open Source** | ✅ | ✅ | ✅ | ❌ |
| **Advanced Algorithms** | ✅ | ⚠️ Basic | ⚠️ Basic | ✅ |
### Key Advantages
1. **Cubic Bézier Curves**: Smooth curves via least-squares fitting with Newton-Raphson reparameterization
2. **Edge-Aware Quantization**: K-means++ with perceptual color distance and Sobel edge detection
3. **Sub-pixel Accuracy**: Marching squares contour extraction with corner-aware path splitting
4. **Smart SVG Output**: `L` for lines, `C` for curves, collinear merge, thin stripe fast path
5. **Original Color Recoloring**: Regions recolored from original image for richer photo fidelity
6. **Batch Processing**: Convert entire directories with `img2svg -i dir/ -o out/`
7. **Large Image Safety**: Auto-resize images exceeding `--max-size` to prevent OOM
8. **Fast LUT Bilateral Filter**: Precomputed range-weight LUT with fixed-point arithmetic
9. **Image filter toolkit**: Optional building blocks (Canny, morphology, CLAHE, unsharp mask, thresholding, color ops) for custom preprocessing or experiments
10. **Flexible Usage**: CLI tool, Rust library, and MCP server
## Examples & Quality
See the `examples/` directory for sample conversions demonstrating quality.
### Simple Graphics (8 colors)
|  |  |
**Details:**
- Command: `img2svg -i https://raw.githubusercontent.com/yingkitw/img2svg/main/examples/input/simple.png -o https://raw.githubusercontent.com/yingkitw/img2svg/main/examples/output/simple.svg -c 8 -s 3`
- Input: 50x50 PNG (2KB) - Basic geometric shapes
- Output: SVG with clean vector paths
- Result: Perfect edges, scalable without quality loss
### Gradients (16 colors)
|  |  |
**Details:**
- Command: `img2svg -i https://raw.githubusercontent.com/yingkitw/img2svg/main/examples/input/gradient.png -o https://raw.githubusercontent.com/yingkitw/img2svg/main/examples/output/gradient.svg -c 16 -s 5`
- Input: 100x100 PNG (1KB) - Smooth gradient
- Output: SVG with banding minimized
- Result: Smooth color transitions, vector-friendly
### Medium Complexity (16 colors)
|  |  |
**Details:**
- Command: `img2svg -i https://raw.githubusercontent.com/yingkitw/img2svg/main/examples/input/medium.png -o https://raw.githubusercontent.com/yingkitw/img2svg/main/examples/output/medium.svg -c 16 -s 5`
- Input: 100x100 PNG (2KB)
- Output: SVG with clean regions
- Result: Preserves shapes, smooth curves
### Complex Illustration (16 colors)
|  |  |
**Details:**
- Command: `img2svg -i https://raw.githubusercontent.com/yingkitw/img2svg/main/examples/input/complex.png -o https://raw.githubusercontent.com/yingkitw/img2svg/main/examples/output/complex.svg -c 16 -s 5`
- Input: 200x200 PNG (6KB) - Detailed illustration
- Output: SVG with fine details preserved
- Result: Clean paths, scalable
### Very Complex (32 colors)
|  |  |
**Details:**
- Command: `img2svg -i https://raw.githubusercontent.com/yingkitw/img2svg/main/examples/input/very_complex.png -o https://raw.githubusercontent.com/yingkitw/img2svg/main/examples/output/very_complex.svg -c 32 -s 7`
- Input: 200x200 PNG (13KB) - Highly detailed
- Output: SVG with complex paths
- Result: Details preserved, clean vector output
### Photograph with Preprocessing (Lenna)
Photographs benefit from the `--preprocess` flag which applies edge-preserving smoothing and color reduction.
|  |  |
**Comparison:**
- **Without preprocessing**: 87 KB SVG with heavy color banding
- **With preprocessing**: 28 KB SVG (67% smaller) with cleaner regions
**Details:**
- Command: `img2svg -i https://raw.githubusercontent.com/yingkitw/img2svg/main/examples/input/lenna.png -o https://raw.githubusercontent.com/yingkitw/img2svg/main/examples/output/lenna.svg --preprocess -c 12 -t 0.15 -s 3`
- Input: 512x512 PNG - Standard test photograph
- Output: Vector version with preprocessing applied
- Result: Preprocessing significantly reduces file size and color banding for photographs
**What preprocessing does:**
- **Bilateral filtering**: Smooths flat areas while preserving edges
- **Color reduction**: Reduces color noise before quantization
- **Result**: Cleaner color regions, smaller file size, less posterization
### Comparison with Alternatives
```bash
# ImageMagick trace (often produces jagged edges)
convert input.png svg:output-imagemagick.svg
# img2svg (smooth curves, better color accuracy)
img2svg -i input.png -o img2svg.svg -c 16 -s 5
```
**Quality Differences**:
- img2svg: Smooth curves, accurate colors, compact paths
- ImageMagick: Often produces jagged edges, limited color optimization
- Potrace: B&W only, requires pre-processing for color images
## Installation
### CLI Tool
```bash
# From crates.io
cargo install img2svg
# From source
git clone https://github.com/yingkitw/img2svg.git
cd img2svg
cargo install --path .
```
### Library
Add to your `Cargo.toml`:
```toml
[dependencies]
img2svg = "0.1"
```
### MCP Server
The MCP binary is built from the same crate as the CLI (no separate directory):
```bash
git clone https://github.com/yingkitw/img2svg.git
cd img2svg
cargo install --path .
# installs img2svg and img2svg-mcp
```
## Usage
### CLI Tool
The CLI uses the **enhanced Bézier pipeline** by default (same as the `vectorize_enhanced` API). Pass **`--original`** to use the legacy pipeline (median-cut, RDP, line segments) and to apply `--threshold`, `--smooth`, `--hierarchical`, and `--advanced` as documented below.
**Supported inputs** (via the `image` crate): PNG, JPEG, GIF, BMP, ICO, TIFF, WebP, PNM, TGA, DDS, Farbfeld.
```bash
# Basic conversion
img2svg -i input.png -o output.svg
# Photo with preprocessing (recommended for photographs)
img2svg -i photo.jpg -o photo.svg --preprocess -c 12
# High-quality graphics with more colors
img2svg -i logo.png -o logo.svg -c 32 -s 7
# Simple logo with fewer colors
img2svg -i icon.png -o icon.svg -c 8 -s 2
# Batch convert all images in a directory
img2svg -i images/ -o svgs/
# Limit max dimension for very large images (default: 4096)
img2svg -i huge_photo.jpg -o output.svg --max-size 2048
```
### Options
| `--input` | `-i` | *required* | Input image file or directory (batch mode) |
| `--output` | `-o` | auto | Output SVG file or directory |
| `--max-size` | | 4096 | Auto-resize images exceeding this dimension (prevents OOM) |
| `--preprocess` | `-p` | false | Extra edge-preserving smoothing and color reduction **before** vectorization (recommended for photos) |
| `--colors` | `-c` | 16 | Target palette size for quantization (default pipeline and `--original`) |
| `--threshold` | `-t` | 0.1 | Edge detection threshold (0.0–1.0); **`--original` only** |
| `--smooth` | `-s` | 5 | Path smoothing level (0–10); **`--original` only** |
| `--original` | | false | Legacy pipeline: median-cut, marching squares, RDP, line-segment SVG |
| `--hierarchical` | | false | Hierarchical decomposition; **`--original` only** |
| `--advanced` | `-a` | false | Layered SVG output; **`--original` only** |
The default enhanced pipeline tunes smoothing and edge-aware quantization internally (`EnhancedOptions`); use **`--original`** if you need direct control via `--threshold` and `--smooth`.
### Rust Library
There are two conversion paths:
- **`convert` / `convert_to_svg_string`** — legacy pipeline (`vectorize` + `generate_svg`), controlled by `ConversionOptions` (same behavior as CLI **`--original`**).
- **`vectorize_enhanced` + `write_enhanced_svg` / `generate_enhanced_svg`** — default high-quality pipeline (Bézier fitting, edge-aware quantization); matches the **CLI without `--original`**.
```rust
use img2svg::{
convert, convert_to_svg_string, load_image, ConversionOptions,
vectorize_enhanced, write_enhanced_svg, EnhancedOptions,
};
use std::path::Path;
// Legacy pipeline (CLI equivalent: --original)
let options = ConversionOptions::default();
convert(Path::new("input.png"), Path::new("output.svg"), &options)?;
// Default / enhanced pipeline (CLI default)
let image = load_image(Path::new("input.png"))?;
let opts = EnhancedOptions {
num_colors: 16,
..Default::default()
};
let data = vectorize_enhanced(&image, &opts)?;
write_enhanced_svg(&data, Path::new("output.svg"))?;
// In-memory SVG string (legacy pipeline only)
let svg = convert_to_svg_string(&image, &options)?;
```
#### Image filters (optional)
The `image_filters` module is re-exported at the crate root for preprocessing and experimentation: median filter, Prewitt/Roberts edges, Canny, morphology, Otsu/adaptive thresholding, CLAHE, gamma, unsharp mask, emboss, sepia, and related color helpers. Compose these on `ImageData` before calling `vectorize_enhanced` or `convert`.
### MCP Server
The MCP (Model Context Protocol) server is built into the same codebase and allows AI assistants (like Claude Desktop) to convert images to SVG directly.
**Note:** The MCP tool invokes the library’s **`convert` / `ConversionOptions`** path (legacy pipeline: median-cut, RDP, line-segment SVG)—the same knobs as **`img2svg --original`**. It does **not** currently call the default CLI enhanced Bézier pipeline; use the **`img2svg` binary** for that behavior.
#### Installation
The MCP server binary is built automatically with the main project:
```bash
# Build both CLI and MCP server
cargo build --release
# Or install both binaries
cargo install --path .
```
The binaries will be:
- `img2svg` - CLI tool
- `img2svg-mcp` - MCP server
#### Configuration for Claude Desktop
Add to your Claude Desktop MCP configuration file:
**macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
**Windows**: `%APPDATA%\Claude\claude_desktop_config.json`
```json
{
"mcpServers": {
"img2svg": {
"command": "/path/to/img2svg-mcp",
"args": []
}
}
}
```
Replace `/path/to/img2svg-mcp` with the full path to the installed binary:
- If installed via `cargo install`: Run `which img2svg-mcp` to find the path
- If built locally: Usually at `target/release/img2svg-mcp`
#### Usage
Once configured, restart Claude Desktop and use the tool directly in conversations:
> "Convert the image at /path/to/logo.png to SVG with 8 colors"
The MCP server provides one tool:
- `convert_image_to_svg`: Converts raster images to SVG format
- `input_path` (required): Path to input image
- `output_path` (required): Path for output SVG
- `num_colors` (optional): Number of colors (1-64, default: 16)
- `smooth_level` (optional): Smoothing level (0-10, default: 5)
- `threshold` (optional): Edge detection threshold (0.0-1.0, default: 0.1)
## Algorithm
img2svg uses a sophisticated multi-stage pipeline (default Bézier pipeline):
1. **LUT Bilateral Filter**: Fast edge-preserving blur with precomputed range-weight LUT (two-pass for photos)
2. **Edge Detection**: Sobel gradient for edge-aware quantization boundaries
3. **Color Quantization**: K-means++ initialization + k-means refinement with perceptual color distance
4. **Majority-Vote Smoothing**: Edge-aware smoothing merges thin artifacts (adaptive: 4 passes for graphics, 2 for photos)
5. **Original Recoloring**: Each quantized region recolored with average original pixel color for richer fidelity
6. **Contour Tracing**: Marching squares on per-color binary masks produces sub-pixel-accurate boundaries
7. **Thin Stripe Fast Path**: Contours < 2px → direct SVG rectangles (preserves line patterns)
8. **Corner-Preserving Smoothing**: Gaussian smoothing that preserves sharp corners
9. **Visvalingam-Whyatt Simplification**: Area-based point removal with corner preservation
10. **Edge Snapping + Corner Injection**: Points snapped to image edges; 90° corners injected at edge transitions
11. **Cubic Bézier Fitting**: Least-squares fit with Newton-Raphson reparameterization + G1 continuity
12. **SVG Generation**: `L` for lines, `C` for curves, collinear merge, gap-filling strokes
The original pipeline (`--original`) uses median-cut quantization, RDP simplification, and line-segment SVG paths.
## Performance
img2svg is optimized for speed and memory:
- **Speed**: Typical 1000x1000 image converts in <1 second
- **Memory**: Auto-resize for large images (configurable `--max-size`, default 4096)
- **Parallelization**: Rayon parallel path processing (smooth → simplify → Bézier fit)
- **Batch Mode**: Convert entire directories in one command
Benchmarks (1000x1000px image):
| 8 | 0.3s | 45 KB |
| 16 | 0.5s | 78 KB |
| 32 | 0.8s | 156 KB |
| 64 | 1.4s | 312 KB |
## Tips for Best Results
### For Logos and Icons
- Use fewer colors (8-16)
- Lower smoothing (2-4)
- Higher threshold (0.15-0.2)
- Results: Clean vector shapes, small file size
### For Photos
> **Best results**: Use `--preprocess` flag which applies edge-preserving smoothing and color reduction
```bash
# Recommended for photos
img2svg -i photo.jpg -o photo.svg --preprocess -c 12 -t 0.15 -s 3
```
**What preprocessing does:**
- **Bilateral filtering**: Smooths flat areas while preserving edges
- **Color reduction**: Reduces color noise before quantization
- **Result**: Cleaner regions, smaller file size, less posterization
**Without preprocessing:**
- Use fewer colors (8-12)
- Higher threshold (0.15-0.2)
- Lower smoothing (2-4)
### For Illustrations
- Medium colors (16-32)
- Medium smoothing (4-6)
- Default threshold (0.1)
### For Clip Art
- Fewer colors (4-8)
- Higher smoothing (3-5)
- Higher threshold (0.15-0.25)
## Limitations
- **Best with**: Images with clear color boundaries (logos, icons, flat illustrations)
- **Photos**: Use `--preprocess` flag for better results, but expect some loss of detail
- **Not suitable for**: Highly detailed photorealistic images with complex gradients
- For complex photos, consider keeping the original raster format
## Contributing
Contributions are welcome! Please see [TODO.md](TODO.md) for planned improvements.
## License
Apache License 2.0 - see [LICENSE](LICENSE) for details.
## Acknowledgments
- Median-cut algorithm: Paul Heckbert (1980)
- Marching squares: William E. Lorensen (1987)
- RDP algorithm: Ramer & Douglas & Peucker (1972-1973)