nanosvg icon indicating copy to clipboard operation
nanosvg copied to clipboard

Adds basic text parsing

Open jamislike opened this issue 7 years ago • 11 comments

Began work on basic text parsing, would you consider adding an improved version of this to NanoSVG..

jamislike avatar Jun 25 '17 01:06 jamislike

Tabs replaced by spaces, formatting garbled. Tabs are annoying )

lieff avatar Oct 02 '17 07:10 lieff

@lieff editor was set spaces, removed! Thanks!

jamislike avatar Oct 02 '17 11:10 jamislike

Good work, If it could parse the Text field, we can extract the those information, and draw the text in some native API. For example, all the non Text elements can be rendered by the current implementation, and the text element can be drawn by the DrawText function from the wxWidgets library.

asmwarrior avatar Apr 05 '22 03:04 asmwarrior

@jamislike can you merge the work in year 2017 with the current head maser?

It looks like some code and structure are changed from the years.

Thanks.

asmwarrior avatar Apr 05 '22 08:04 asmwarrior

2022-04-05.zip I have manually merged your work with the recent master, but I'm not sure this is OK, can you have a look at this patch file(in the attachment zip file)? Thanks.

asmwarrior avatar Apr 05 '22 08:04 asmwarrior

In the patch file, I have add a comment:

@@ -1019,12 +1095,18 @@ static void nsvg__addShape(NSVGparser* p)
 	// Set flags
 	shape->flags = (attr->visible ? NSVG_FLAGS_VISIBLE : 0x00);
 
+// should to be fixed!!!
 	// Add to tail
-	if (p->image->shapes == NULL)
+	prev = NULL;
+	cur = p->image->shapes;
+	while (cur != NULL) {
+		prev = cur;
+		cur = cur->next;
+	}
+	if (prev == NULL)
 		p->image->shapes = shape;
 	else
-		p->shapesTail->next = shape;
-	p->shapesTail = shape;
+		prev->next = shape;
 
 	return;
 

I'm not sure what does the shapesTail used for, since in your work, this is not used, I think this should be fixed.

asmwarrior avatar Apr 05 '22 08:04 asmwarrior

I got a shape like below: (I show this from the GDB debugger command line)

$2 = {id = "text35", '\000' <repeats 249 times>, fill = {type = 1 '\001', {color = 4278190080, gradient = 0xff000000}}, stroke = {type = 0 '\000', {color = 0, gradient = 0x0}}, opacity = 1, strokeWidth = 0.999998748, strokeDashOffset = 0, strokeDashArray = {0, 0, 0, 0, 0, 0, 0, 0}, strokeDashCount = 0 '\000', strokeLineJoin = 0 '\000', strokeLineCap = 0 '\000', miterLimit = 4, fillRule = 0 '\000', flags = 1 '\001', bounds = {0, 0, 0, 0}, paths = 0x0, group = 0x6a37b40, next = 0x0, fontFamily = "sans-serif", '\000' <repeats 53 times>, fontWeight = "sans-serif", '\000' <repeats 53 times>, fontSize = 13.2292004, isText = 1 '\001', textData = "abc", '\000' <repeats 252 times>}

When I try to parse a text field in svg file like below:

    <text
       xml:space="preserve"
       style="font-style:normal;font-weight:normal;font-size:13.2292px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
       x="74.839287"
       y="66.523811"
       id="text35"><tspan
         sodipodi:role="line"
         id="tspan33"
         x="74.839287"
         y="66.523811"
         style="stroke-width:0.264583px">abc</tspan></text>

The svg file is generated by inkscape software.

It looks like the "x" and "y" coordinates is missing from the shape, are there any way to record them? Thanks.

asmwarrior avatar Apr 06 '22 05:04 asmwarrior

I debugged this code for a while, and I see that in this function:

static void nsvg__parseText(NSVGparser* p, const char** attr)
{
	float x = 0.0f;
	float y = 0.0f;
	float r = 0.0f;
	float xform[6];

	int i;

	for (i = 0; attr[i]; i += 2) {
		if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) {
			if (strcmp(attr[i], "x") == 0) x = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigX(p), nsvg__actualWidth(p));
			if (strcmp(attr[i], "y") == 0) y = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigY(p), nsvg__actualHeight(p));
			if (strcmp(attr[i], "transform") == 0)
			{
				nsvg__parseTransform(xform, attr[i+1]);
				x = nsvg__parseCoordinate(p, attr[i+1], xform[4], 0);
				y = nsvg__parseCoordinate(p, attr[i+1], xform[5], 0);
			}
			if (strcmp(attr[i], "font-size") == 0)  r = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualLength(p)) );

		}
	}
	p->isText = 1;

	nsvg__addShape(p);
}

The x and y value are correctly get, but those two variables are local variables, and I see there is no code to use them. So, they never get saved in the shape structure.

asmwarrior avatar Apr 06 '22 06:04 asmwarrior

I have see a pull request here:

Push/pop attributes for SVG element. Add support for x and y attributes. by mindbrix · Pull Request #131 · memononen/nanosvg

With the commits in the pull request, it has to handle the x and 'y` in the attribute. And when adding the shape, it has such result:

[debug]> p shape->bounds
[debug]$1 = {74.8392868, 66.5238113, 74.8392868, 66.5238113}

So, the x,y coordinates of the text elements were stored in the bounds field, so we may later to use this information to draw the text on the screen(use our own API, not the rasterization function in nanosvg, but some DrawText like function in wxWidgets library.).

asmwarrior avatar Apr 06 '22 07:04 asmwarrior

Here is the result of my research, I extract the text elements by the nanosvg and this pull request, and draw the text elements on the rendered image. See the image below. With a comparing of the original svg image in Inkscape tool and the svg viewer window by wxWidgets.

show_text_by_wx_dc_DrawText

asmwarrior avatar Apr 06 '22 09:04 asmwarrior

FYI: I create a very simple project which uses wxWidgets to draw the text, see here: asmwarrior/SvgPanel: a wxPanel which can show svg image and simple text labels

asmwarrior avatar Apr 15 '22 07:04 asmwarrior