All formats

NanoSVG

LanguageC (usable from C++)
Licensezlib license
Repositorygithub.com/memononen/nanosvg
DocumentationREADME and comments in nanosvg.h
Depends onnothing (C standard library)
Read / writeread (parse to paths, rasterize flat fills) / no

NanoSVG is 2 header files: nanosvg.h parses SVG into a list of shapes, each a list of paths made of cubic Bézier segments, already transformed and converted to the units you ask for (px, mm, in, …). nanosvgrast.h is an optional rasterizer that renders those shapes to an RGBA buffer.

It handles paths, basic shapes, transforms, solid colors and simple linear and radial gradients. It doesn’t support text, CSS stylesheets, clipping, masks, filters, patterns or <use>. The README states the project is not actively maintained, but it remains widely embedded (Blender, many game engines, plotters and CNC tools) because it’s tiny and has no dependencies. Use it to get geometry or bake simple icons; use librsvg or LunaSVG for general SVG files.

Installation#

Copy src/nanosvg.h (and src/nanosvgrast.h for rasterizing) into your project. In exactly one .c or .cpp file define the implementation macros before including:

C
#include <stdio.h>
#include <string.h>
#include <math.h>
#define NANOSVG_IMPLEMENTATION
#include "nanosvg.h"
#define NANOSVGRAST_IMPLEMENTATION
#include "nanosvgrast.h"

It’s also in vcpkg (vcpkg install nanosvg) and has a CMake package (find_package(NanoSVG), targets NanoSVG::nanosvg and NanoSVG::nanosvgrast).

Basic usage: read shapes and paths#

C
#include <stdio.h>
#include <string.h>
#include <math.h>
#define NANOSVG_IMPLEMENTATION
#include "nanosvg.h"

int main(void) {
    NSVGimage *image = nsvgParseFromFile("in.svg", "px", 96.0f);
    if (!image) {
        fprintf(stderr, "cannot parse in.svg\n");
        return 1;
    }
    printf("size: %.1f x %.1f\n", image->width, image->height);

    for (NSVGshape *shape = image->shapes; shape; shape = shape->next) {
        if (shape->fill.type == NSVG_PAINT_COLOR)
            printf("shape '%s' fill 0x%08x\n", shape->id, shape->fill.color);  // ABGR
        for (NSVGpath *path = shape->paths; path; path = path->next) {
            // pts holds x0,y0 then 3 points (6 floats) per cubic segment
            for (int i = 0; i < path->npts - 1; i += 3) {
                float *p = &path->pts[i * 2];
                printf("  cubic (%g,%g) (%g,%g) (%g,%g) (%g,%g)\n",
                       p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
            }
        }
    }
    nsvgDelete(image);
    return 0;
}

How to rasterize an SVG to RGBA#

C
#define NANOSVGRAST_IMPLEMENTATION
#include "nanosvgrast.h"

NSVGimage *image = nsvgParseFromFile("icon.svg", "px", 96.0f);
float scale = 64.0f / image->width;               // render 64 px wide
int w = (int)(image->width * scale);
int h = (int)(image->height * scale);
unsigned char *rgba = malloc((size_t)w * h * 4);

NSVGrasterizer *rast = nsvgCreateRasterizer();
nsvgRasterize(rast, image, 0, 0, scale, rgba, w, h, w * 4);
// rgba: non-premultiplied RGBA; save with stb_image_write, upload to a texture, ...
nsvgDeleteRasterizer(rast);
nsvgDelete(image);
free(rgba);

How to get coordinates in millimeters#

Pass the unit and DPI: shapes come back converted, which is handy for plotters and laser cutters:

C
NSVGimage *image = nsvgParseFromFile("cut.svg", "mm", 96.0f);
for (NSVGshape *s = image->shapes; s; s = s->next)
    printf("bounds mm: %g %g %g %g\n", s->bounds[0], s->bounds[1], s->bounds[2], s->bounds[3]);

How to parse SVG from memory#

nsvgParse modifies the string, so pass a writable copy:

C
char *copy = strdup(svg_text);
NSVGimage *image = nsvgParse(copy, "px", 96.0f);
free(copy);

Tips#