All formats

LunaSVG

LanguageC++ (C++17)
LicenseMIT
Repositorygithub.com/sammycage/lunasvg
DocumentationREADME and comments in lunasvg.h
Depends onplutovg (bundled as a git submodule)
Read / writeread (renders to RGBA bitmaps, writes PNG) / no

LunaSVG parses SVG and renders it with plutovg, a small 2D vector rasterizer by the same author. It supports nearly all static features of SVG 1.1 and SVG Tiny 1.2: shapes, paths, gradients, patterns, clipping, masks, markers, <use>, <style> CSS and text. It doesn’t support filters, animation or scripts. Dear ImGui, RmlUi, OpenSiv3D and node-canvas use it.

Beyond rendering it has a small DOM: find elements by id or CSS selector, read and set attributes, get bounding boxes and find the element under a point.

Installation#

Build and install with CMake (the submodule is fetched with --recursive):

Shell
git clone --recursive https://github.com/sammycage/lunasvg.git
cd lunasvg
cmake -B build .
cmake --build build
cmake --install build

It’s also in vcpkg (vcpkg install lunasvg) and Conan. Use it from CMake:

cmake
find_package(lunasvg REQUIRED)
target_link_libraries(myapp PRIVATE lunasvg::lunasvg)

Or without installing, with FetchContent:

cmake
include(FetchContent)
FetchContent_Declare(lunasvg GIT_REPOSITORY https://github.com/sammycage/lunasvg.git GIT_TAG master)
FetchContent_MakeAvailable(lunasvg)
target_link_libraries(myapp PRIVATE lunasvg::lunasvg)

Basic usage: convert SVG to PNG#

C++
#include <lunasvg.h>
#include <iostream>

using namespace lunasvg;

int main() {
    auto document = Document::loadFromFile("in.svg");
    if (!document) {
        std::cerr << "cannot load in.svg\n";
        return 1;
    }
    std::cout << document->width() << " x " << document->height() << "\n";

    Bitmap bitmap = document->renderToBitmap();  // intrinsic size, transparent background
    if (bitmap.isNull()) {
        std::cerr << "render failed\n";
        return 1;
    }
    bitmap.writeToPng("out.png");
    return 0;
}

How to render SVG at a given size or with a background#

renderToBitmap(width, height, backgroundColor): pass -1 for one dimension to keep the aspect ratio. The color is 0xRRGGBBAA:

C++
Bitmap icon = document->renderToBitmap(256, -1);               // 256 px wide
Bitmap opaque = document->renderToBitmap(512, 512, 0xFFFFFFFF); // white background
opaque.writeToPng("icon-512.png");

How to get raw RGBA pixels#

Bitmaps hold premultiplied ARGB32 (the Cairo layout). Convert in place before passing them to code that expects plain RGBA:

C++
Bitmap bitmap = document->renderToBitmap(128, 128);
bitmap.convertToRGBA();
const uint8_t* pixels = bitmap.data();  // R, G, B, A per pixel
int stride = bitmap.stride();           // bytes per row
// upload to a texture, etc.

To draw into your own buffer, wrap it with Bitmap(data, width, height, stride) and call document->render(bitmap, Matrix::scaled(2, 2)).

How to recolor an SVG with CSS#

C++
auto document = Document::loadFromFile("icon.svg");
document->applyStyleSheet("path { fill: #d33; }");
document->renderToBitmap(64, 64).writeToPng("icon-red.png");

How to change attributes and find elements#

C++
auto document = Document::loadFromFile("in.svg");

if (Element logo = document->getElementById("logo")) {
    logo.setAttribute("fill", "green");
    Box box = logo.getBoundingBox();
    std::cout << "logo at " << box.x << "," << box.y << " size " << box.w << "x" << box.h << "\n";
}

for (Element circle : document->querySelectorAll("circle")) {
    circle.setAttribute("stroke", "black");
}

if (Element hit = document->elementFromPoint(30, 30)) {
    std::cout << "clicked: " << hit.getAttribute("id") << "\n";
}
document->renderToBitmap().writeToPng("modified.png");

Tips#