Skip to content

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

License

Notifications You must be signed in to change notification settings

OutdoorMap/svgager

Repository files navigation

Svgager

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

Features

  • Multiple Output Formats: Convert SVG to PNG, JPG, JPEG, GIF, or WebP
  • Resolution Control: Set output width, height, or both dimensions
  • Aspect Ratio Preservation: Automatically maintains aspect ratio when only one dimension is specified
  • Transparent Backgrounds: PNG format supports transparency by default
  • Configurable Backgrounds: Other formats support custom background colors (hex format)
  • SVG Preprocessing: Replace strings in SVG content before conversion (useful for dynamic color changes)
  • High Performance: Built with Rust for maximum speed and efficiency

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:

  • End users (adding to your app): No Rust needed
  • Contributors (running mix test): Rust required

Supported Platforms (Precompiled Binaries)

Precompiled binaries are provided for:

  • Linux (x86_64, aarch64)
  • macOS (x86_64, aarch64/Apple Silicon)
  • Windows (x86_64)

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:

  • SVGAGER_BUILD=true - Force compilation from source instead of using precompiled binaries
  • RUSTLER_PRECOMPILED_FORCE_BUILD=true - Alternative way to force building from source

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

  • svg_string (String.t) - The SVG content as a string
  • opts (Keyword.t) - Conversion options

Options

  • :format (required) - Output format. One of :png, :jpg, :jpeg, :gif, or :webp
  • :width (optional) - Output width in pixels (integer). If only width is provided, height is calculated to maintain aspect ratio
  • :height (optional) - Output height in pixels (integer). If only height is provided, width is calculated to maintain aspect ratio
  • :background_color (optional) - Background color as hex string (e.g., "FFFFFF" or "#FF0000"). Ignored for PNG format which uses transparency. Defaults to "FFFFFF" (white) for other formats
  • :replacements (optional) - Map of string replacements to apply to SVG before conversion (e.g., %{"#000000" => "#FF0000"})

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

Returns

  • {:ok, binary_data} - Binary image data on success
  • {:error, reason} - Error string on failure

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:

  • Run tests locally
  • Make changes to the Rust code
  • Build the library from source

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:

  • config/dev.exs: Sets force_build_nif: true (builds from source)
  • config/test.exs: Sets force_build_nif: true (builds from source)
  • config/prod.exs: Sets force_build_nif: false (uses precompiled binaries)

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:

  • The Rust NIF compiles in debug mode by default (faster compilation)
  • Use MIX_ENV=prod mix compile to compile in release mode (optimized, slower compilation)
  • The first compilation will take a few minutes (Rust dependencies are cached after that)
  • Subsequent recompiles are much faster

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

  • rustler - Elixir NIF bindings
  • resvg - High-quality SVG rendering
  • usvg - SVG parsing and tree representation
  • tiny-skia - 2D rendering backend
  • image - Multi-format image encoding

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:

  • Setting up your development environment
  • Coding standards and style guides
  • Testing requirements
  • Pull request process
  • Reporting issues

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

  • Report bugs and issues
  • Suggest new features or improvements
  • Improve documentation
  • Submit pull requests
  • Star the project on GitHub

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:

  • Use this library in commercial projects
  • Modify and distribute the code
  • Use it privately
  • Sublicense it

You must:

  • Include the license and copyright notice
  • Acknowledge the original authors

You cannot:

  • Hold the authors liable for damages
  • Claim warranty coverage

Acknowledgments

  • Built with Rustler for Elixir/Rust integration
  • Uses resvg for high-quality SVG rendering
  • Powered by tiny-skia for 2D graphics
  • Image encoding via image-rs

Support

Project Status

  • Production Ready: All core features implemented and tested
  • Well Tested: 106 tests covering all functionality
  • Documented: Comprehensive documentation and examples
  • Precompiled Binaries: Coming soon (requires GitHub releases setup)

Roadmap

Potential future enhancements:

  • Additional image formats (AVIF, TIFF, BMP)
  • SVG animation support
  • Image optimization options
  • Batch conversion utilities
  • CLI tool for command-line usage
  • More preprocessing options (filters, effects)

Suggestions welcome! Open an issue to discuss new features.

About

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

Resources

License

Contributing

Stars

Watchers

Forks

Packages

No packages published

Contributors 2

  •  
  •