The OpenD Programming Language

arsd.svg

NanoVega.SVG is a simple stupid SVG parser. The output of the parser is a list of drawing commands.

The library suits well for anything from rendering scalable icons in your editor application to prototyping a game.

NanoVega.SVG supports a wide range of SVG features, but several are be missing. Among the most notable known missing features: <use>, <text>, <def> for shapes (it does work for gradients), <script>, <style> (minimal inline style attributes work, but style blocks do not), and animations. Note that <clipPath> is new and may be buggy (but anything in here may be buggy!) and the css support is fairly rudimentary.

More...

Members

Enums

NSVGDefaults
enum NSVGDefaults

Functions

kill
void kill(NSVG* image)
kill
void kill(NSVGrasterizer r)
nsvgCreateRasterizer
NSVGrasterizer nsvgCreateRasterizer()
nsvgParse
NSVG* nsvgParse(const(char)[] input, const(char)[] units, float dpi, int canvaswdt, int canvashgt)
nsvgParseFromFile
NSVG* nsvgParseFromFile(const(char)[] filename, const(char)[] units, float dpi, int canvaswdt, int canvashgt)
nsvgParseFromFile
NSVG* nsvgParseFromFile(ST fi, const(char)[] units, float dpi, int canvaswdt, int canvashgt)
nsvg__curveBounds
void nsvg__curveBounds(float* bounds, const(float)* curve)
nsvg__evalBezier
double nsvg__evalBezier(double t, double p0, double p1, double p2, double p3)
nsvg__ptInBounds
int nsvg__ptInBounds(const(float)* pt, const(float)* bounds)
nsvg__xformIdentity
void nsvg__xformIdentity(float* t)
nsvg__xformInverse
void nsvg__xformInverse(float* inv, const(float)* t)
nsvg__xformMultiply
void nsvg__xformMultiply(float* t, const(float)* s)
nsvg__xformPoint
void nsvg__xformPoint(float* dx, float* dy, float x, float y, const(float)* t)
nsvg__xformPremultiply
void nsvg__xformPremultiply(float* t, const(float)* s)
nsvg__xformSetRotation
void nsvg__xformSetRotation(float* t, float a)
nsvg__xformSetScale
void nsvg__xformSetScale(float* t, float sx, float sy)
nsvg__xformSetSkewX
void nsvg__xformSetSkewX(float* t, float a)
nsvg__xformSetSkewY
void nsvg__xformSetSkewY(float* t, float a)
nsvg__xformSetTranslation
void nsvg__xformSetTranslation(float* t, float tx, float ty)
nsvg__xformVec
void nsvg__xformVec(float* dx, float* dy, float x, float y, const(float)* t)
rasterize
void rasterize(NSVGrasterizer r, const(NSVG)* image, float tx, float ty, float scale, ubyte* dst, int w, int h, int stride)

Rasterizes SVG image, returns RGBA image (non-premultiplied alpha).

Manifest constants

NSVG_EPSILON
enum NSVG_EPSILON;
NSVG_PI
enum NSVG_PI;

Structs

NSVG
struct NSVG

Detailed Description

The shapes in the SVG images are transformed by the viewBox and converted to specified units. That is, you should get the same looking data as your designed in your favorite app.

NanoVega.SVG can return the paths in few different units. For example if you want to render an image, you may choose to get the paths in pixels, or if you are feeding the data into a CNC-cutter, you may want to use millimeters.

The units passed to NanoVega.SVG should be one of: 'px', 'pt', 'pc', 'mm', 'cm', 'in'. DPI (dots-per-inch) controls how the unit conversion is done.

If you don't know or care about the units stuff, "px" and 96 should get you going.

Example Usage:

The easiest way to use it is to rasterize a SVG to a arsd.color.TrueColorImage, and from there you can work with it same as any other memory image. For example, to turn a SVG into a png:

import arsd.svg;
import arsd.png;

void main() {
    // Load
    NSVG* image = nsvgParseFromFile("test.svg", "px", 96);

    int w = cast(int) image.width;
    int h = cast(int) image.height;

    NSVGrasterizer rast = nsvgCreateRasterizer();
    // Allocate memory for image
    auto img = new TrueColorImage(w, h);
    // Rasterize
    rasterize(rast, image, 0, 0, 1, img.imageData.bytes.ptr, w, h, w*4);

    // Delete
    image.kill();

    writePng("test.png", img);


}

You can also dig into the individual commands of the svg without rasterizing it. Note that this is fairly complicated - svgs have a lot of settings, and even this example only does the basics.

1 import core.stdc.stdio;
2 import core.stdc.stdlib;
3 import arsd.svg;
4 import arsd.nanovega;
5 
6 void main() {
7 
8     // we'll create a NanoVega window to display the image
9     int w = 800;
10     int h = 600;
11     auto window = new NVGWindow(w, h, "SVG Test");
12 
13     // Load the file and can look at its info
14     NSVG* image = nsvgParseFromFile("/home/me/svgs/arsd.svg", "px", 96);
15     printf("size: %f x %f\n", image.width, image.height);
16 
17     // and then use the data when the window asks us to redraw
18     // note that is is far from complete; svgs can have shapes, clips, caps, joins...
19     // we're only doing the bare minimum here.
20     window.redrawNVGScene = delegate(nvg) {
21 
22         // clear the screen with white so we can see the images on top of it
23         nvg.beginPath();
24         nvg.fillColor = NVGColor.white;
25         nvg.rect(0, 0, window.width, window.height);
26         nvg.fill();
27         nvg.closePath();
28 
29         image.forEachShape((in ref NSVG.Shape shape) {
30             if (!shape.visible) return;
31 
32             nvg.beginPath();
33 
34             // load the stroke
35             nvg.strokeWidth = shape.strokeWidth;
36             debug import std.stdio;
37 
38             final switch(shape.stroke.type) {
39                 case NSVG.PaintType.None:
40                     // no stroke
41                 break;
42                 case NSVG.PaintType.Color:
43                     with(shape.stroke)
44                         nvg.strokeColor = NVGColor(r, g, b, a);
45                     debug writefln("%08x", shape.fill.color);
46                     break;
47                 case NSVG.PaintType.LinearGradient:
48                 case NSVG.PaintType.RadialGradient:
49                     // FIXME: set the nvg stroke paint to shape.stroke.gradient
50             }
51 
52             // load the fill
53             final switch(shape.fill.type) {
54                 case NSVG.PaintType.None:
55                     // no fill set
56                 break;
57                 case NSVG.PaintType.Color:
58                     with(shape.fill)
59                         nvg.fillColor = NVGColor(r, g, b, a);
60                     break;
61                 case NSVG.PaintType.LinearGradient:
62                 case NSVG.PaintType.RadialGradient:
63                     // FIXME: set the nvg fill paint to shape.stroke.gradient
64             }
65 
66             shape.forEachPath((in ref NSVG.Path path) {
67                 // this will issue final `LineTo` for closed pathes
68                 path.forEachCommand!true(delegate (NSVG.Command cmd, const(float)[] args) nothrow @trusted @nogc {
69                     debug writeln(cmd, args);
70                     final switch (cmd) {
71                         case NSVG.Command.MoveTo: nvg.moveTo(args); break;
72                         case NSVG.Command.LineTo: nvg.lineTo(args); break;
73                         case NSVG.Command.QuadTo: nvg.quadTo(args); break;
74                         case NSVG.Command.BezierTo: nvg.bezierTo(args); break;
75                     }
76                 });
77             });
78 
79             nvg.fill();
80             nvg.stroke();
81 
82             nvg.closePath();
83         });
84     };
85 
86     window.eventLoop(0);
87 
88     // Delete the image
89     image.kill();
90 }

TODO: maybe merge https://github.com/memononen/nanosvg/pull/94 too

Meta