Svgager

High-performance SVG to image conversion library for Elixir, powered by Rust via Rustler.

Features

Prerequisites

For End Users (Installing as Dependency)

Elixir 1.19 or later

Note: Rust is NOT required for end users! Svgager uses precompiled NIFs that work out of the box on supported platforms (Linux, macOS, Windows).

For Developers (Contributing/Testing)

Elixir 1.19 or later Rust and Cargo - REQUIRED for running tests and development

Quick Summary:

Supported Platforms (Precompiled Binaries)

Precompiled binaries are provided for:

Building from Source (Optional)

If you need to compile from source, you'll need Rust and Cargo:

# Install Rust
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

# Restart terminal or run:
source $HOME/.cargo/env

# Verify installation
cargo --version
rustc --version

# Force compilation from source
export SVGAGER_BUILD=true
mix deps.compile svgager

Or visit https://rustup.rs/ for other installation methods.

Installation

Add svgager to your list of dependencies in mix.exs:

def deps do
  [
    {:svgager, "~> 0.1.0"}
  ]
end

Then run:

mix deps.get
mix compile

Precompiled Binaries

Svgager uses rustler_precompiled to provide precompiled NIFs for common platforms. When you run mix deps.get, it will automatically download the appropriate precompiled binary for your platform from GitHub releases.

Environment Variables:

For Package Maintainers:

To release precompiled binaries:

# 1. Update version in mix.exs
# 2. Update the base_url in lib/svgager/native.ex with your GitHub repository
# 3. Run the release helper
mix rustler_precompiled.download Svgager.Native --all --print

# 4. Upload the generated .tar.gz files to GitHub releases
# 5. Generate checksums
mix rustler_precompiled.download Svgager.Native --all --print-checksum > checksum-Elixir.Svgager.Native.exs

# 6. Commit the checksum file

Usage

Basic Conversion

# Read an SVG file
svg_content = File.read!("input.svg")

# Convert to PNG with transparency (800px width, height auto-calculated)
{:ok, png_data} = Svgager.convert(svg_content, format: :png, width: 800)
File.write!("output.png", png_data)

JPG with Background Color

# Convert to JPG with red background
{:ok, jpg_data} = Svgager.convert(svg_content,
  format: :jpg,
  width: 1200,
  height: 800,
  background_color: "FF0000"
)
File.write!("output.jpg", jpg_data)

WebP with Custom Resolution

# Convert to WebP maintaining aspect ratio
{:ok, webp_data} = Svgager.convert(svg_content,
  format: :webp,
  width: 1024,
  background_color: "FFFFFF"
)
File.write!("output.webp", webp_data)

SVG Preprocessing

You can replace strings in the SVG before conversion, useful for changing colors dynamically:

# Change colors before conversion
{:ok, png_data} = Svgager.convert(svg_content,
  format: :png,
  width: 800,
  replacements: %{
    "#000000" => "#FF5500",
    "#FFFFFF" => "#00AAFF",
    "blue" => "red"
  }
)

GIF Format

# Convert to GIF with white background
{:ok, gif_data} = Svgager.convert(svg_content,
  format: :gif,
  width: 600,
  height: 400,
  background_color: "FFFFFF"
)
File.write!("output.gif", gif_data)

API Reference

Svgager.convert/2

Converts SVG to the specified image format and returns binary data.

Parameters

Options

When both :width and :height are provided, the output uses exact dimensions (may distort if aspect ratio doesn't match original SVG).

Returns

Error Handling

case Svgager.convert(svg_content, format: :png, width: 800) do
  {:ok, image_data} ->
    File.write!("output.png", image_data)
    IO.puts("Conversion successful!")

  {:error, reason} ->
    IO.puts("Conversion failed: #{reason}")
end

Development

Prerequisites for Development

Important: Rust and Cargo are REQUIRED for development and testing!

While end users don't need Rust (they use precompiled binaries), developers need Rust to:

Install Rust:

# Option 1: Using rustup (recommended)
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source $HOME/.cargo/env

# Option 2: Using mise (if you use mise for version management)
mise install rust@latest
mise use rust@latest

# Verify installation
cargo --version
rustc --version

Setting Up Development Environment

The library automatically builds from source in dev/test mode (configured via config/dev.exs and config/test.exs):

# Clone the repository
git clone <repository-url>
cd svgager

# Install dependencies
mix deps.get

# Compile (automatically builds Rust NIF from source in dev mode)
mix compile

# Run tests
mix test

Build Configuration:

The build behavior is controlled by Mix configs:

You can override this with the SVGAGER_BUILD environment variable:

# Force building from source in any environment
SVGAGER_BUILD=true mix compile

# Or export it for your session
export SVGAGER_BUILD=true
mix compile

Development Tips:

Project Structure

svgager/
├── lib/
│   ├── svgager.ex              # Main public API
│   └── svgager/
│       ├── converter.ex         # High-level conversion logic
│       └── native.ex            # NIF module definition
├── native/
│   └── svgager_native/
│       ├── Cargo.toml           # Rust dependencies
│       └── src/
│           ├── lib.rs           # Rust NIF entry point
│           └── converter.rs     # Rust conversion implementation
├── test/
│   └── svgager_test.exs
└── mix.exs

Technical Details

Rust Dependencies

Performance

Svgager leverages Rust's performance for fast SVG rendering and image encoding. The library uses resvg, which is widely regarded as one of the highest-quality SVG renderers available.

Contributing

We welcome contributions! Please see CONTRIBUTING.md for detailed guidelines on:

Quick Start for Contributors

# Fork and clone the repository
git clone https://github.com/OutdoorMap/svgager.git
cd svgager

# Install dependencies
mix deps.get

# Compile (requires Rust)
mise exec -- mix compile

# Run tests
mise exec -- mix test

# Format code before committing
mix format
cd native/svgager_native && cargo fmt

Ways to Contribute

License

Copyright (c) 2026 OutdoorMap AB

This project is licensed under the MIT License - see the LICENSE file for details.

What This Means

You can:

You must:

You cannot:

Acknowledgments

Support

Project Status

Roadmap

Potential future enhancements:

Suggestions welcome! Open an issue to discuss new features.