Donner SVG is an under-development modern C++20 SVG rendering library which provides full access to the SVG DOM, enabling browser-level functionality without the browser.
Donner is nearing a 0.1 release, which provides core static SVG functionality (without text or filter support). Text, filter, and animation support are on the roadmap.
Why Donner?
Donner supports:
Donner renders with Skia, which provides the same high-quality rendering used by Chromium.
<circle>
<clipPath>
<defs>
<ellipse>
<g>
<image>
<line>
<linearGradient>
<marker>
<mask>
<path>
<pattern>
<polygon>
<polyline>
<radialGradient>
<rect>
<stop>
<style>
<svg>
<use>
Not yet supported: <a>
<filter>
<switch>
<symbol>
<text>
<textPath>
<tspan>
bazel run --run_under="cd $PWD &&" //examples:svg_to_png -- donner_splash.svg
How it works: svg_to_png.cc
// This is the base SVG we are loading, a simple path containing a line
std::string_view svgContents(R"(
<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200" viewBox="0 0 10 10">
<path d="M 1 1 L 4 5" stroke="blue" />
</svg>
)");
// Call ParseSVG to load the SVG file
donner::base::parser::ParseResult<donner::svg::SVGDocument> maybeResult =
donner::svg::parser::SVGParser::ParseSVG(svgContents);
if (maybeResult.hasError()) {
std::cerr << "Parse Error " << maybeResult.error() << "\n"; // Includes line:column and reason
std::abort();
// - or - handle the error per your project's conventions
}
donner::svg::SVGDocument document = std::move(maybeResult.result());
// querySelector supports standard CSS selectors, anything that's valid when defining a CSS rule
// works here too, for example querySelector("svg > path[fill='blue']") is also valid and will
// match the same element.
std::optional<donner::svg::SVGElement> maybePath = document.querySelector("path");
UTILS_RELEASE_ASSERT_MSG(maybePath, "Failed to find path element");
// The result of querySelector is a generic SVGElement, but we know it's a path, so we can cast
// it. If the cast fails, an assertion will be triggered.
donner::svg::SVGPathElement path = maybePath->cast<donner::svg::SVGPathElement>();
if (std::optional<donner::svg::PathSpline> spline = path.computedSpline()) {
std::cout << "Path: " << *spline << "\n";
std::cout << "Length: " << spline->pathLength() << " userspace units\n";
} else {
std::cout << "Path is empty\n";
}
Detailed docs: svg_tree_interaction.cc
using namespace donner::base;
using namespace donner::base::parser;
using namespace donner::svg;
using namespace donner::svg::parser;
std::ifstream file("test.svg");
if (!file) {
std::cerr << "Could not open file\n";
std::abort();
}
std::string fileData;
file.seekg(0, std::ios::end);
const std::streamsize fileLength = file.tellg();
file.seekg(0);
fileData.resize(fileLength);
file.read(fileData.data(), fileLength);
ParseResult<SVGDocument> maybeDocument = SVGParser::ParseSVG(fileData);
if (maybeDocument.hasError()) {
std::cerr << "Parse Error: " << maybeDocument.error() << "\n";
std::abort();
}
RendererSkia renderer;
renderer.draw(maybeDocument.result());
const bool success = renderer.save("output.png");
Detailed docs: svg_to_png.cc
bazel run --run_under="cd $PWD &&" //examples:svg_viewer -- <filename>
This example demonstrates how to create an interactive SVG viewer using ImGui. The viewer allows you to load and display SVG files, and interact with SVG elements using ImGui.
Detailed docs: svg_viewer.cc