Covecto: dual-engine image vectorization in Rust

Covecto: dual-engine image vectorization in Rust

Most image vectorizers pick a lane. Some are great at tracing screenshots and pixel art with pixel-perfect precision. Others smooth photos into Bezier curves. Almost none do both well.

Covecto does both. It ships two engines, picks the right one automatically, and runs fast because it is written in Rust.

Four days ago the repo had zero commits. Today it is at v0.1.1 with a CLI, a REST API, Docker image, and 14 pages of docs. This is an early release post, not a maturity claim. Two stars on GitHub, one contributor (@ajianaz), MIT licensed. If you want to try something new and help shape the direction, this is the window.

The problem with single-engine vectorizers

Here is the before state. You have a folder of app icons that need to be SVG. You run them through a photo-oriented tracer. The output looks soft, edges blurred, 1-pixel details smeared into curves. Then you have a product photo. You run it through a pixel-exact tracer. The output is 400 tiny rectangles and a 2 MB SVG file that renders slowly and looks wrong.

You switch tools depending on input. You write wrapper scripts. You forget which tool handles which case. The batch job fails at 2 AM because a screenshot landed in the photo pipeline.

The after state: one tool that detects what kind of image it is looking at and applies the right algorithm. No manual switching. No wrapper scripts.

Two engines, one binary

Covecto (full name: Cora Vectorizer) has two vectorization engines.

PixelExact is built for icons, pixel art, and screenshots. The pipeline is contiguous-region flood-fill, then boundary tracing, then rectilinear SVG output. Straight edges stay straight. A 16x16 icon becomes a clean, small SVG with exact coordinates.

Spline is built for photos and illustrations. It runs color quantization, then contour tracing, then Bezier spline fitting. This engine uses vtracer 0.6.5. Photos get smooth curves and reasonable file sizes.

Auto mode (the default) uses heuristics based on image characteristics to pick between them. You do not have to think about it.

How it works in practice

Install it three ways:


# One-line install (Linux/macOS/Windows)
curl -fsSL https://codecora.dev/covecto/install | sh

# Cargo
cargo install covecto

# Docker
docker pull ghcr.io/codecoradev/covecto:latest

Basic usage. Auto-detect the best engine:


covecto input.png -o output.svg

Force a specific engine when you know what you want:


# Pixel-exact for icons
covecto icon.png --engine pixel-exact -o icon.svg

# Spline for photos, with optimization
covecto photo.jpg --engine spline --optimize -o photo.svg

Built-in profiles tune multiple parameters at once. There are four: icon, logo, photo, lineart.


covecto logo.png --profile logo -o logo.svg

Batch processing is first-class. Recursive scan, glob patterns, Rayon parallel batch, progress bar, dry-run mode, JSON output for scripting.


# Entire directory
covecto ./icons/ --engine pixel-exact -o ./output/

# Recursive scan with glob
covecto "screenshots/*.png" --recursive -o ./vectorized/

Output formats: SVG (default), PDF, EPS.

REST API for service integration

Covecto also ships an HTTP server built on axum 0.8. Four endpoints:


# Start the server
covecto serve --port 3000

# Vectorize
curl -F "[email protected]" -F "engine=auto" http://localhost:3000/v1/vectorize

# Optimize existing SVG
curl -F "[email protected]" http://localhost:3000/v1/optimize

# Health check
curl http://localhost:3000/v1/health

Full endpoints: /v1/vectorize, /v1/optimize, /v1/health, /v1/metrics. There is an OpenAPI 3.1 spec in the repo. The Docker image runs in API server mode by default, so deployment is one docker run.

What is under the hood

The repo is a Rust workspace with three crates: core (vectorization logic), cli (the binary), and api (the HTTP server). You can use the core library directly:


use covecto_core::{vectorize, VectorizeRequest, Engine, VectorizeConfig};

let img = image::open("input.png").unwrap().to_rgba8();
let request = VectorizeRequest::new(img)
    .with_config(VectorizeConfig {
        engine: Engine::Auto,
        ..Default::default()
    });
let result = vectorize(&request).unwrap();
println!("{} paths in {}ms",
    result.metadata.path_count,
    result.metadata.processing_time_ms);

CI runs on GitHub Actions: check, format, clippy, test, build. The Docker image is a multi-stage build published to GHCR. SVG optimization works both standalone and as a post-vectorize step. VitePress docs cover 14 pages at codecora.dev/covecto/docs.

What is next

This is v0.1.1, released 2026-07-24 (v0.1.0 was the day before). The project is four days old. Things that work today: both engines, auto mode, CLI, REST API, Docker, profiles, batch processing, three output formats. Things that are rough: edge cases in contour tracing, performance on very large images, documentation gaps in advanced config.

The roadmap is open. File issues, send PRs, break things and report what broke.

Try it

Repo: github.com/codecoradev/covecto

Docs: codecora.dev/covecto/docs

Install: curl -fsSL https://codecora.dev/covecto/install | sh

Star it if you find it useful. Open an issue if you do not. Early projects live or die on feedback, and this one is four days into existence.