memononen / nanosvg

Simple stupid SVG parser
zlib License
1.71k stars 363 forks source link

support text tags #87

Open technosaurus opened 7 years ago

technosaurus commented 7 years ago

I put together a SVG path-based font to use with nanosvg in lieu of text tags. My paths only use the stroke (no fill) to minimize the path size, but an outlined font effect can be reproduced by duplicating the path and reducing the stroke-width and the 'x' and 'y' offsets can be simulated by prepending "Mx y". Would something like this be the preferred way to add text support, or are there plans to add different type(s) so that the downstream projects can render the text directly such as stb_truetype for nanosvgrast.h or freetype for X11+opengl, etc...?

The font looks like this (amazingly its actually better than my first iterations) and only takes ~20 bytes per character a with the following svg:

<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 360 32">
    <path fill="#000" d="M0 0h999v999h-999z"/>
    <path stroke="#fff" fill="none" d="M0 0m1 1h6-3v11m4-12m2 1v11-4a2 2 0 1 1 4 0v4m2-12m6 10a2 3 0 1 1 0-2h-4m6-8m8 0m6 7a2 3 0 1 0 0 3v5-10m2-5m2 6v4a2 2 0 1 0 4 0v2-6m2-6m4 4v1m0 1v6m4-12m6 7a2 3 0 1 0 0 3m2-10m2 1v11-3l3 -3-2 2 3 4m2-12m8 0m2 7a2 3 0 1 1 0 3v2-11m6-1m2 6v6-4a2 2 0 1 1 4 0m2-8m6 9a2 3 0 1 0 0 .1zm2-9m2 6l1 6 1-4 1 4 1-6m2-6m2 6v6-4a2 2 0 1 1 4 0v4m2-12m8 0m2 12v-6h2-2q0-4 4-4m2-2m6 9a2 3 0 1 0 0 .1zm2-9m2 6l4 6m-4 0l4-6m2-6m8 0m4 4v1m0 1v5q0 2-2 2m6-13m2 6v4a2 2 0 1 0 4 0v2-6m2-6m2 6v6-4a1 2 0 1 1 2 0v4-4a1 2 0 1 1 2 0v4m2-12m2 7a2 3 0 1 1 0 3v5-10m6-5m6 10a2 3 0 1 1 0-2h-4m6-8m6 7a2 3 0 1 0 0 3v2-11m2-1m8 0m6 9a2 3 0 1 0 0 .1zm2-9m2 6l2 5 2-5m2-6m6 10a2 3 0 1 1 0-2h-4m6-8m2 6v6-4a2 2 0 1 1 4 0m2-8m8 0m4 4v8-6h2-4m6-6m2 1v11-4a2 2 0 1 1 4 0v4m2-12m6 10a2 3 0 1 1 0-2h-4m6-8m8 0m4 1v11m4-12m6 7a2 3 0 1 0 0 3v2-7m2-5m2 6h4l-4 6h4m2-12m2 6l2 4l2-4-4 8m6-14m8 0m6 7a2 3 0 1 0 0 3v2-11m2-1m6 9a2 3 0 1 0 0 .1zm2-9m6 7a2 3 0 1 0 0 3v-5 8a2 2 0 0 1 -4 0m6-13m3 12a.5.5 0 0 0-.1-.1zm5-12m-360 16m1 1h6-3v11m4-12m2 1v11-6h4v6-11m2-1m6 12h-4v-11h4m-4 5h3m3-6m8 0m4 1a2 5.5 0 1 0 .1 0zm0 7l3 4m1-12m2 1v9a2 2 0 0 0 4 0v-9m2-1m2 1h4-2v11h2-4m6-12m5.5 3a2 5 0 1 0 0 7m2.5-10m2 1v11-6l5-5-4 4 4 7m1-12m8 0m2 1h1a2 2 0 1 1 0 5h-1h2a2 2 0 1 1 -2 6zm6-1m2 12v-11h1a3 2 0 1 1 0 5h-1 1l4 6m1-12m4 1a2 5.5 0 1 0 .1 0zm4-1m1 1l2 11 1-6 1 6 2-11m1-1m2 12v-11l4 11v-11m2-1m8 0m2 12v-11h4m-4 5h3m3-6m4 1a2 5.5 0 1 0 .1 0zm4-1m2 1l4 11m-4 0l4-11m2-1m8 0m4 1h2v7q0 4-4 4m6-12m2 1v9a2 2 0 0 0 4 0v-9m2-1m1 12v-11l3 6 3-6v11m1-12m2 12v-11h1a3 2 0 1 1 0 5h-1m6-6m6 12h-4v-11h4m-4 5h3m3-6m2 1h1a3 5 0 1 1 0 11h-1zm6-1m8 0m4 1a2 5.5 0 1 0 .1 0zm4-1m2 1l2 11 2-11m2-1m6 12h-4v-11h4m-4 5h3m3-6m2 12v-11h1a3 2 0 1 1 0 5h-1 1l4 6m1-12m8 0m1 1h6-3v11m4-12m2 1v11-6h4v6-11m2-1m6 12h-4v-11h4m-4 5h3m3-6m8 0m2 1v11h4m2-12m1 12l3-10l3 10m-1-4h-4m6-8m6 12h-4l4-11h-4m6-1m2 1l2 6v5-5l2-6m2-1m8 0m2 1h1a3 5 0 1 1 0 11h-1zm6-1m4 1a2 5.5 0 1 0 .1 0zm4-1m6 4a2 5 0 1 0 0 5v-2h-2m4-7m4 1v9m0 1v1m4-12"/>
</svg>
static const char *char_paths[96] = {
/* " " */ "m8 0",
/* "!" */ "m4 1v9m0 1v1m4-12",
/*"\"" */ "m3 2v3m2-3v3m3-5",
/* "#" */ "m2 3v8m4-8v8m-5-2h6m-6-4h6m1-5",
/* "$" */ "m2 11a2 3 0 1 0 2-4a2 3 0 1 1 2-4m-2-2v12m4-15",
/* "%" */ "m2 3a1 1 0 1 1 0 .1zm4-2l-4 11m2-2a1 1 0 1 1 0 .1zm2-14",
/* "&" */ "m7 12l-3-6a2 2.5 0 1 1 .1 0a3 3 0 1 0 3 2m1-8",
/* "'" */ "m4 2v3m4-5",
/* "(" */ "m4 12q-3-6 0-11m4-1",
/* ")" */ "m4 12q3-6 0-11m4-1",
/* "*" */ "m1 6h6m-1 4l-4-8m2 0v8m-2 0l4-8m2-2",
/* "+" */ "m1 6h6m-3-3v6m4-9",
/* "," */ "m5 11q1 1-2 3m5-14",
/* "-" */ "m2 6h4m2-6",
/* "." */ "m3 12a.5.5 0 0 0-.1-.1zm5-12",
/* "/" */ "m2 12l4-11m2-1",
/* "0" */ "m2 5.5a2 4 0 1 1 4 0v2a2 4 0 1 1-4 0zm2 0v2m4-8",
/* "1" */ "m3 3l1-1v10m4-12",
/* "2" */ "m2 3a2 5 30 0 1 0 9h5m1-12",
/* "3" */ "m2 2a2 2 0 1 1 3 4m0 0h-1a3 3 0 1 1-3 4m7-10",
/* "4" */ "m2 1v5h4v6-11m2-1",
/* "5" */ "m2 10a2 4 0 1 0 0-4v-5h4m2-1",
/* "6" */ "m3 6a2 3 0 1 1 -1 1l4-6m2-1",
/* "7" */ "m1 1h5l-4 11m6-12",
/* "8" */ "m3.5 6a2 2.5 0 1 1 1 0a2 3 0 1 1 -1 0zm4.5-6",
/* "9" */ "m2 12l4-6a2.5 3 0 1 0 -1 1m3-7",
/* ":" */ "m3 3a.5.5 0 1 0 0-.1zm0 6a.5.5 0 1 0 0-.1zm5-9",
/* ";" */ "m3 3a.5.5 0 1 0 0-.1zm0 6a.5.5 0 1 0 0-.1zq2 0 -1 2m6-11",
/* "<" */ "m6 12l-4-6 4-5m2-1",
/* "=" */ "m2 5h4m-4 2h4m2-7",
/* ">" */ "m2 12l4-6-4-5m6-1",
/* "?" */ "m2 4a2 2 0 1 1 2 2v2m0 3a.5.5 0 1 0-.1 0zm4-11",
/* "@" */ "m5 8a1 1 0 1 1 0 -1a1 2 0 1 0 2-0a3 5 0 1 0 -2 4m3-11",
/* "A" */ "m1 12l3-10l3 10m-1-4h-4m6-8",
/* "B" */ "m2 1h1a2 2 0 1 1 0 5h-1h2a2 2 0 1 1 -2 6zm6-1",
/* "C" */ "m5.5 3a2 5 0 1 0 0 7m2.5-10",
/* "D" */ "m2 1h1a3 5 0 1 1 0 11h-1zm6-1",
/* "E" */ "m6 12h-4v-11h4m-4 5h3m3-6",
/* "F" */ "m2 12v-11h4m-4 5h3m3-6",
/* "G" */ "m6 4a2 5 0 1 0 0 5v-2h-2m4-7",
/* "H" */ "m2 1v11-6h4v6-11m2-1",
/* "I" */ "m2 1h4-2v11h2-4m6-12",
/* "J" */ "m4 1h2v7q0 4-4 4m6-12",
/* "K" */ "m2 1v11-6l5-5-4 4 4 7m1-12",
/* "L" */ "m2 1v11h4m2-12",
/* "M" */ "m1 12v-11l3 6 3-6v11m1-12",
/* "N" */ "m2 12v-11l4 11v-11m2-1",
/* "O" */ "m4 1a2 5.5 0 1 0 .1 0zm4-1",
/* "P" */ "m2 12v-11h1a3 2 0 1 1 0 5h-1m6-6",
/* "Q" */ "m4 1a2 5.5 0 1 0 .1 0zm0 7l3 4m1-12",
/* "R" */ "m2 12v-11h1a3 2 0 1 1 0 5h-1 1l4 6m1-12",
/* "S" */ "m2 10a2 3 0 1 0 2-4a2 2.5 0 1 1 2-4m2-2",
/* "T" */ "m1 1h6-3v11m4-12",
/* "U" */ "m2 1v9a2 2 0 0 0 4 0v-9m2-1",
/* "V" */ "m2 1l2 11 2-11m2-1",
/* "W" */ "m1 1l2 11 1-6 1 6 2-11m1-1",
/* "X" */ "m2 1l4 11m-4 0l4-11m2-1",
/* "Y" */ "m2 1l2 6v5-5l2-6m2-1",
/* "Z" */ "m6 12h-4l4-11h-4m6-1",
/* "[" */ "m5 12h-2v-11h2m3-1",
/*"\\" */ "m2 1l4 11m2-12",
/* "]" */ "m3 12h2v-11h-2m5-1",
/* "^" */ "m2 4l2-2 2 2m2-4",
/* "_" */ "m1 14h6m1-14",
/* "`" */ "m3 2l2 1m3-3",
/* "a" */ "m6 7a2 3 0 1 0 0 3v2-7m2-5",
/* "b" */ "m2 7a2 3 0 1 1 0 3v2-11m6-1",
/* "c" */ "m6 7a2 3 0 1 0 0 3m2-10",
/* "d" */ "m6 7a2 3 0 1 0 0 3v2-11m2-1",
/* "e" */ "m6 10a2 3 0 1 1 0-2h-4m6-8",
/* "f" */ "m2 12v-6h2-2q0-4 4-4m2-2",
/* "g" */ "m6 7a2 3 0 1 0 0 3v-5 8a2 2 0 0 1 -4 0m6-13",
/* "h" */ "m2 1v11-4a2 2 0 1 1 4 0v4m2-12",
/* "i" */ "m4 4v1m0 1v6m4-12",
/* "j" */ "m4 4v1m0 1v5q0 2-2 2m6-13",
/* "k" */ "m2 1v11-3l3 -3-2 2 3 4m2-12",
/* "l" */ "m4 1v11m4-12",
/* "m" */ "m2 6v6-4a1 2 0 1 1 2 0v4-4a1 2 0 1 1 2 0v4m2-12",
/* "n" */ "m2 6v6-4a2 2 0 1 1 4 0v4m2-12",
/* "o" */ "m6 9a2 3 0 1 0 0 .1zm2-9",
/* "p" */ "m2 7a2 3 0 1 1 0 3v5-10m6-5",
/* "q" */ "m6 7a2 3 0 1 0 0 3v5-10m2-5",
/* "r" */ "m2 6v6-4a2 2 0 1 1 4 0m2-8",
/* "s" */ "m2 10a2 2 0 1 0 2-2h-1a2 1 0 0 1 3-2m2-6",
/* "t" */ "m4 4v8-6h2-4m6-6",
/* "u" */ "m2 6v4a2 2 0 1 0 4 0v2-6m2-6",
/* "v" */ "m2 6l2 5 2-5m2-6",
/* "w" */ "m2 6l1 6 1-4 1 4 1-6m2-6",
/* "x" */ "m2 6l4 6m-4 0l4-6m2-6",
/* "y" */ "m2 6l2 4l2-4-4 8m6-14",
/* "z" */ "m2 6h4l-4 6h4m2-12",
/* "{" */ "m5 13a1 6 0 0 1-1-5l-1-1 1-1a1 6 0 0 1 1-5m3-1",
/* "|" */ "m4 13v-12m4-1",
/* "}" */ "m3 13a1 6 0 0 0 1-5l1-1-1-1a1 6 0 0 0 -1-5m5-1",
/* "~" */ "m2 6q1-1 2 0t2 0m2-6",
/* ??? */ "m1 1h6v14h-6zm7-1",
};

I wrote a simple (public domain) svg generator that uses these "glyphs" to generate nanosvg friendly icons here although it also handles things like newlines and tabs, which aren't necessary/desired for the svg specification.

I could implement this a couple different ways, but I thought I'd query other nanosvg users and devs for feedback first

SergeySlice commented 6 years ago

Very interesting! I need scalable font support for my project https://sourceforge.net/projects/cloverefiboot/ where I already implemented a copy of nanosvg.

zhongjingjogy commented 6 years ago

Is this feature to be supported?

I found some other solutions around GitHub, i.e., SVG2PNG, svg_font_renderer. But such a feature is not well supported. A potential solution is to use the strategy of svg_font_renderer, but extra effort should be devoted to

  1. traversing the tree of svg,
  2. identifying the text tags,
  3. calculating the transform properties
  4. and alternating the text nodes with path.

Is it?

technosaurus commented 6 years ago

My intent here was to convert text tags into a path which nanosvg can already handle. I was hoping to get feedback on how to handle various attributes such as font size (which I assume can just be scaled, and the y-offset recomputed). A prettier or more compact default font is more than welcome - this was just a proof of concept.

It could make a good fallback mode even if someone patches nanosvg to use stb_truetype (i.e. no font found or stbtt disabled by build time configuration)

Matheus-Garbelini commented 4 years ago

is there an update on this? Support for text would be nice to use with imgui.

oehhar commented 4 years ago

AFAIK, there is no font support planned for nanosvg. You can use inkscape to transform your text to a path.

Matheus-Garbelini commented 4 years ago

thanks @oehhar . I'm afraid that would not work for real time svg rendering application. The only alternative is svgpp, but who knows how to use that library :disappointed: .

zcream commented 3 years ago

@zhongjingjogy are you suggesting that svg2png and svg_font_renderer support text properly ?

I found some other solutions around GitHub, i.e., SVG2PNG, svg_font_renderer.

asmwarrior commented 2 years ago

AFAIK, there is no font support planned for nanosvg. You can use inkscape to transform your text to a path.

This method works OK, thanks.

asmwarrior commented 2 years ago

I have made some partial progress on showing the text field. Especially extract the text and font information from the svg file, and draw the text labels by some native(such as wxWidgets DrawText()) function calls.

See here: asmwarrior/SvgPanel: a wxPanel which can show svg image and simple text labels

oneeyeman1 commented 1 year ago

It would be nice to have a font parsing in this library. I hope the maintainer(s) can integrate this.

oneeyeman1 commented 1 year ago

@asmwarrior

I have made some partial progress on showing the text field. Especially extract the text and font information from the svg file, and draw the text labels by some native(such as wxWidgets DrawText()) function calls.

See here: asmwarrior/SvgPanel: a wxPanel which can show svg image and simple text labels

Can this be used for rendering the toolbar button?

asmwarrior commented 1 year ago

@asmwarrior

I have made some partial progress on showing the text field. Especially extract the text and font information from the svg file, and draw the text labels by some native(such as wxWidgets DrawText()) function calls. See here: asmwarrior/SvgPanel: a wxPanel which can show svg image and simple text labels

Can this be used for rendering the toolbar button?

I think the answer is yes. But please note the font field in a svg file is very complex to parse, my improvement of rending the font is very limited.