svg-renderer converts SVG documents to raster images (raw RGBA, PNG, JPEG, WebP) with automatic backend selection. It prefers Vulkan GPU acceleration when available and gracefully falls back to CPU rendering.
This crate was developed with Vibe Coding using GPT-5.5.
Why svg-renderer?
| Need | Solution |
|---|---|
| Quick SVG → PNG/JPEG/WebP in a CLI tool | Free-standing functions or SvgRenderer |
| Batch-rendering thousands of SVGs | SvgPipelineRenderer with N worker threads |
| Always CPU, no GPU dependency | CpuSvgRenderer / CpuSvgPipelineRenderer |
| Explicit GPU-only path | VulkanSvgRenderer / VulkanSvgPipelineRenderer (with vulkan-backend) |
| SVG references external fonts / images | set_resource_search_dirs(…) on any renderer |
| Fine-grained output format control | JpegOptions, WebpOptions structs |
Installation
[]
= "1.0.2"
Default features enable the Vulkan backend. For CPU-only:
[]
= { = "1.0.2", = false }
Feature flags
| Feature | Default | Description |
|---|---|---|
vulkan-backend |
✅ | Vulkan GPU rendering via ash + Skia Vulkan integration |
| (none) | — | CPU rendering only (always available) |
Requirements
- A Rust toolchain compatible with Edition 2024
- Skia build / runtime dependencies (via
skia-safe) - Vulkan drivers + runtime — only if using the Vulkan backend
skia-bindings binary download proxy
skia-safe builds through skia-bindings, which tries to download a prebuilt Skia binary during compilation. If that download fails because GitHub or the binary host is unreachable, configure a curl proxy and run the build again.
For a one-off build:
$env:HTTPS_PROXY = "http://127.0.0.1:7890"
$env:HTTP_PROXY = "http://127.0.0.1:7890"
cargo build
To set the proxy in PowerShell for the current terminal and permanently add user-level proxy environment variables:
$proxy = "http://127.0.0.1:7890"
$env:HTTP_PROXY = $proxy
$env:HTTPS_PROXY = $proxy
[Environment]::SetEnvironmentVariable("HTTP_PROXY", $proxy, "User")
[Environment]::SetEnvironmentVariable("HTTPS_PROXY", $proxy, "User")
Write-Host "Proxy has been set to $proxy."
Write-Host "The current terminal can use it immediately; new terminals will inherit it."
If you prefer CMD, save and run this batch script:
@echo off
set "PROXY=http://127.0.0.1:7890"
rem Apply to the current terminal session immediately.
set HTTP_PROXY=%PROXY%
set HTTPS_PROXY=%PROXY%
rem Persist for new terminal sessions.
setx HTTP_PROXY "http://127.0.0.1:7890"
setx HTTPS_PROXY "http://127.0.0.1:7890"
echo Proxy has been set to %PROXY%.
echo The current terminal can use it immediately; new terminals will inherit it.
pause
For a global curl proxy, create or edit the curl configuration file:
- Windows:
%USERPROFILE%\.curlrc - Linux / macOS:
~/.curlrc
proxy = "http://127.0.0.1:7890"
Use your own proxy address and port. Remove the setting after the build if you do not want all curl requests to use that proxy.
Quick start
One-liner free functions
use ;
let png = render_svg_to_png?;
write?;
Using SvgRenderer (auto-detect backend)
use ;
let mut renderer = new?;
let image = renderer.render_svg?;
println!;
Check which backend was selected:
let mut renderer = new?;
println!; // Cpu or Vulkan
Output formats
PNG
use ;
let mut renderer = new?;
let png = renderer.render_svg_to_png?;
JPEG
use ;
let options = new?;
let jpeg_opts = JpegOptions ;
let mut renderer = new?;
let jpeg = renderer.render_svg_to_jpeg?;
| JpegDownsample | Behavior |
|---|---|
BothDirections |
4:2:0 chroma subsampling (default) |
Horizontal |
4:2:2 |
No |
4:4:4 (best quality, largest file) |
| JpegAlphaOption | Behavior |
|---|---|
Ignore |
Discard alpha |
BlendOnBlack |
Composite over black before encoding |
WebP
use ;
let options = new?;
let webp_opts = WebpOptions ;
let mut renderer = new?;
let webp = renderer.render_svg_to_webp?;
| WebpCompression | Description |
|---|---|
Lossy |
VP8 (default) |
Lossless |
VP8L |
Backend selection
| Type | Feature | Behavior |
|---|---|---|
SvgRenderer |
(any) | Try Vulkan → fallback to CPU |
CpuSvgRenderer |
(always) | CPU raster, no fallback needed |
VulkanSvgRenderer |
vulkan-backend |
GPU only, errors on Vulkan failure |
CPU renderer — no GPU dependency, identical API:
use CpuSvgRenderer;
let mut renderer = new?;
let png = renderer.render_svg_to_png?;
Vulkan renderer — explicit GPU path:
use VulkanSvgRenderer; // requires "vulkan-backend"
let mut renderer = new?;
let png = renderer.render_svg_to_png?;
Pipeline rendering (batch workloads)
SvgPipelineRenderer spawns a pool of dedicated worker threads and dispatches jobs via round-robin. Each worker owns its own renderer — ideal for rendering many SVGs concurrently.
use ;
let renderer = new?; // 4 workers
let options = new?;
let svg = b"<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 320'/>";
// All pipeline methods are async
let image = renderer.render_svg.await?;
let png = renderer.render_svg_to_png.await?;
let jpeg = renderer.render_svg_to_jpeg.await?;
let webp = renderer.render_svg_to_webp.await?;
Pipeline variants mirror the single-shot renderers:
| Pipeline type | Backend |
|---|---|
SvgPipelineRenderer |
Auto-select (Vulkan → CPU) |
CpuSvgPipelineRenderer |
CPU only |
VulkanSvgPipelineRenderer |
Vulkan only (requires vulkan-backend) |
External resources
SVG files may reference external fonts, images, or other assets. Set one or more search directories on any renderer:
let mut renderer = new?;
renderer.set_resource_search_dirs;
The renderer probes:
- Local search directories (in order)
- HTTP(S) fallback via
ureq(built into Skia's resource provider)
Absolute paths in SVG references resolve directly. URL-like references skip local lookup and fall back to HTTP(S).
Image data
Error handling
All public APIs return Result<_, SvgRenderError>.
Examples
All examples can be found in the examples/ directory.
render_svg
Basic single-shot rendering to multiple output formats.
Output in target/example-output/:
sample.rgba— raw RGBA datasample.pngsample.jpgsample.webp
render_pipeline
Async pipeline rendering with 4 worker threads using SvgPipelineRenderer.
Writes target/example-output/pipeline-sample.png.
render_perf
Benchmark all available backends (CPU, Vulkan, pipeline) and reports throughput. Accepts optional arguments:
# 100 iterations, 4 pipeline workers (defaults)
# Custom parameters
Reports: average/median/min/max latency, FPS throughput.
License
Licensed under the MIT License.