[dia] svg: almost working round-trip with cairo/svg
- From: Hans Breuer <hans src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [dia] svg: almost working round-trip with cairo/svg
- Date: Wed, 3 Oct 2012 20:02:30 +0000 (UTC)
commit 1c40554e6b7059987576689b5034f640cf291762
Author: Hans Breuer <hans breuer org>
Date: Sun Sep 30 23:36:53 2012 +0200
svg: almost working round-trip with cairo/svg
- support for colors as percent values
- improved dash-array interpretation
- svg-import.c(use_position) : better positioning
- svg-import.c(apply_style) : matrix scaled line-width and dash-array
lib/dia_svg.c | 95 ++++++++++++++++++++++++++++++++++++++------
plug-ins/svg/svg-import.c | 63 +++++++++++++++++++++++------
2 files changed, 132 insertions(+), 26 deletions(-)
---
diff --git a/lib/dia_svg.c b/lib/dia_svg.c
index ba9d503..fa3236b 100644
--- a/lib/dia_svg.c
+++ b/lib/dia_svg.c
@@ -104,11 +104,22 @@ _parse_color(gint32 *color, const char *str)
*color = DIA_SVG_COLOUR_TEXT;
else if (0 == strncmp(str, "rgb(", 4)) {
int r = 0, g = 0, b = 0;
- if (3 == sscanf (str+4, "%d,%d,%d", &r, &g, &b))
+ real dr, dg, db;
+ if (3 == sscanf (str+4, "%d,%d,%d", &r, &g, &b)) {
/* Set alpha to 1.0 */
*color = ((0xFF<<24) & 0xFF000000) | ((r<<16) & 0xFF0000) | ((g<<8) & 0xFF00) | (b & 0xFF);
- else
+ } else if (strchr (str+4, '%')) {
+ /* e.g. cairo uses percent values */
+ gchar **vals = g_strsplit (str+4, "%,", -1);
+ int i;
+
+ *color = 0xFF000000;
+ for (i = 0; vals[i] && i < 3; ++i)
+ *color |= ((int)(((255 * g_ascii_strtod(vals[i], NULL)) / 100))<<(16-(8*i)));
+ g_strfreev (vals);
+ } else {
return FALSE;
+ }
} else if (0 == strncmp(str, "rgba(", 5)) {
int r = 0, g = 0, b = 0, a = 0;
if (4 == sscanf (str+4, "%d,%d,%d,%d", &r, &g, &b, &a))
@@ -158,6 +169,59 @@ enum
FONT_NAME_LENGTH_MAX = 40
};
+static void
+_parse_dasharray (DiaSvgStyle *s, real user_scale, gchar *str, gchar **end)
+{
+ gchar *ptr;
+ gchar **dashes = g_strsplit ((gchar *)str, ",", -1);
+ int n = 0;
+ real dl;
+
+ s->dashlength = g_ascii_strtod(str, &ptr);
+ if (s->dashlength <= 0.0) /* e.g. "none" */
+ s->linestyle = LINESTYLE_SOLID;
+ else if (user_scale > 0)
+ s->dashlength /= user_scale;
+
+ while (dashes[n])
+ ++n; /* Dia can not do arbitrary length, the number of dashes gives the style */
+ if (n > 0)
+ s->dashlength = g_ascii_strtod (dashes[0], NULL);
+ if (user_scale > 0)
+ s->dashlength /= user_scale;
+ switch (n) {
+ case 0 :
+ s->linestyle = LINESTYLE_SOLID;
+ break;
+ case 1 :
+ s->linestyle = LINESTYLE_DASHED;
+ break;
+ case 2 :
+ dl = g_ascii_strtod (dashes[0], NULL);
+ if (user_scale > 0)
+ dl /= user_scale;
+ if (dl < s->line_width || dl > s->dashlength) { /* the difference is arbitrary */
+ s->linestyle = LINESTYLE_DOTTED;
+ s->dashlength *= 10.0; /* dot = 10% of len */
+ } else {
+ s->linestyle = LINESTYLE_DASHED;
+ }
+ break;
+ case 4 :
+ s->linestyle = LINESTYLE_DASH_DOT;
+ break;
+ case 6 : s->linestyle = LINESTYLE_DASH_DOT_DOT;
+ break;
+ default :
+ s->linestyle = LINESTYLE_DOTTED; /* not correct */
+ break;
+ }
+ g_strfreev (dashes);
+
+ if (end)
+ *end = ptr;
+}
+
/** This function not only parses the style attribute of the given node
* it also extracts some of the style properties directly.
* @param node An XML node to parse a style from.
@@ -338,10 +402,6 @@ dia_svg_parse_style(xmlNodePtr node, DiaSvgStyle *s, real user_scale)
s->dashlength /= user_scale;
}
} else if (!strncmp("stroke-dasharray:", ptr, 17)) {
- /* FIXME? do we need to read an array here (not clear from
- * Dia's usage); do we need to set the linestyle depending
- * on the array's size ? --hb
- */
s->linestyle = LINESTYLE_DASHED;
ptr += 17;
while (ptr[0] != '\0' && g_ascii_isspace(ptr[0])) ptr++;
@@ -349,13 +409,8 @@ dia_svg_parse_style(xmlNodePtr node, DiaSvgStyle *s, real user_scale)
if (!strncmp(ptr, "default", 7))
s->dashlength = 1.0;
- else {
- s->dashlength = g_ascii_strtod(ptr, &ptr);
- if (s->dashlength <= 0.0) /* e.g. "none" */
- s->linestyle = LINESTYLE_SOLID;
- else if (user_scale > 0)
- s->dashlength /= user_scale;
- }
+ else
+ _parse_dasharray (s, user_scale, ptr, &ptr);
}
/* skip up to the next attribute */
@@ -395,6 +450,20 @@ dia_svg_parse_style(xmlNodePtr node, DiaSvgStyle *s, real user_scale)
if (user_scale > 0)
s->line_width /= user_scale;
}
+ str = xmlGetProp(node, (const xmlChar *)"stroke-dasharray");
+ if (str) {
+ _parse_dasharray (s, user_scale, str, NULL);
+ xmlFree(str);
+ }
+ /* text-props, again ;( */
+ str = xmlGetProp(node, (const xmlChar *)"font-size");
+ if (str) {
+ s->font_height = g_ascii_strtod((gchar *)str, NULL);
+ if (user_scale > 0)
+ s->font_height /= user_scale;
+ xmlFree(str);
+ }
+
if (family || style || weight) {
if (s->font)
diff --git a/plug-ins/svg/svg-import.c b/plug-ins/svg/svg-import.c
index e6e1753..bb43920 100644
--- a/plug-ins/svg/svg-import.c
+++ b/plug-ins/svg/svg-import.c
@@ -190,6 +190,7 @@ use_position (DiaObject *obj, xmlNodePtr node)
{
Point pos = {0, 0};
xmlChar *str;
+ Point delta = obj->position;
str = xmlGetProp(node, (const xmlChar *)"x");
if (str) {
@@ -202,7 +203,9 @@ use_position (DiaObject *obj, xmlNodePtr node)
pos.y = get_value_as_cm((char *) str, NULL);
xmlFree(str);
}
- /* assuming the original is at 0,0 */
+ /* not assuming the original is at 0,0 */
+ pos.x += delta.x;
+ pos.y += delta.y;
obj->ops->move(obj, &pos);
str = xmlGetProp(node, (const xmlChar *)"transform");
@@ -215,16 +218,25 @@ use_position (DiaObject *obj, xmlNodePtr node)
RealProperty *pr;
prop_list_add_point (props, "obj_pos", &pos);
- prop_list_add_real (props, "width", 1.0);
- prop_list_add_real (props, "height", 1.0);
+ prop_list_add_point (props, "elem_corner", &pos);
+ prop_list_add_real (props, "elem_width", 1.0);
+ prop_list_add_real (props, "elem_height", 1.0);
+ prop_list_add_real (props, PROP_STDNAME_LINE_WIDTH, 0.1);
obj->ops->get_props (obj, props);
/* try to transform the object without the full matrix */
pp = g_ptr_array_index (props, 0);
pp->point_data.x += m->x0;
- pp->point_data.y += m->x0;
- pr = g_ptr_array_index (props, 1);
- pr->real_data *= m->xx;
+ pp->point_data.y += m->y0;
+ /* set position a second time, now for non-elements */
+ pp = g_ptr_array_index (props, 1);
+ pp->point_data.x += m->x0;
+ pp->point_data.y += m->y0;
+
pr = g_ptr_array_index (props, 2);
+ pr->real_data *= m->xx;
+ pr = g_ptr_array_index (props, 3);
+ pr->real_data *= m->yy;
+ pr = g_ptr_array_index (props, 4);
pr->real_data *= m->yy;
obj->ops->set_props (obj, props);
@@ -245,7 +257,17 @@ apply_style(DiaObject *obj, xmlNodePtr node, DiaSvgStyle *parent_style)
ColorProperty *cprop;
RealProperty *rprop;
BoolProperty *bprop;
-
+ real scale = 1.0;
+
+ xmlChar *str = xmlGetProp(node, (const xmlChar *)"transform");
+ if (str) {
+ DiaMatrix *m = dia_svg_parse_transform ((char *)str, user_scale);
+ if (m) {
+ scale = m->xx;
+ g_free (m);
+ }
+ xmlFree(str);
+ }
gs = g_new0(DiaSvgStyle, 1);
/* SVG defaults */
dia_svg_style_init (gs, parent_style);
@@ -265,11 +287,11 @@ apply_style(DiaObject *obj, xmlNodePtr node, DiaSvgStyle *parent_style)
}
}
rprop = g_ptr_array_index(props,1);
- rprop->real_data = gs->line_width;
+ rprop->real_data = gs->line_width * scale;
lsprop = g_ptr_array_index(props,2);
lsprop->style = gs->linestyle != DIA_SVG_LINESTYLE_DEFAULT ? gs->linestyle : LINESTYLE_SOLID;
- lsprop->dash = gs->dashlength;
+ lsprop->dash = gs->dashlength * scale;
cprop = g_ptr_array_index(props,3);
cprop->color_data = get_colour(gs->fill, gs->fill_opacity);
@@ -318,6 +340,17 @@ read_path_svg(xmlNodePtr node, DiaSvgStyle *parent_style, GList *list, DiaContex
do {
bezpoints = dia_svg_parse_path (pathdata, &unparsed, &closed, ¤t_point);
+ if (!closed) {
+ /* expensive way to possibly close the path */
+ DiaSvgStyle *gs = g_new0(DiaSvgStyle, 1);
+
+ dia_svg_style_init (gs, NULL);
+ dia_svg_parse_style(node, gs, user_scale);
+ if (gs->font)
+ dia_font_unref (gs->font);
+ closed = (gs->fill != DIA_SVG_COLOUR_NONE);
+ g_free(gs);
+ }
if (bezpoints && bezpoints->len > 0) {
if (g_array_index(bezpoints, BezPoint, 0).type != BEZ_MOVE_TO) {
dia_context_add_message(ctx, _("Invalid path data.\n"
@@ -439,6 +472,8 @@ read_text_svg(xmlNodePtr node, DiaSvgStyle *parent_style, GList *list)
xmlChar *line = xmlNodeGetContent(tspan);
if (any_tspan) /* every other line needs separation */
g_string_append(paragraph, "\n");
+ else /* only first time */
+ dia_svg_parse_style(tspan, gs, user_scale);
g_string_append(paragraph, (gchar*)line);
xmlFree(line);
any_tspan = TRUE;
@@ -995,10 +1030,10 @@ read_items (xmlNodePtr startnode,
GList *moreitems = read_items (node->xmlChildrenNode, parent_gs, defs_ht, filename_svg, ctx);
/* only one object or create a group */
- if (g_list_length (moreitems))
+ if (g_list_length (moreitems) > 1)
obj = group_create (moreitems);
- else
- obj = g_list_last(items)->data;
+ else if (moreitems)
+ obj = g_list_last(moreitems)->data;
} else if (!xmlStrcmp(node->name, (const xmlChar *)"rect")) {
items = read_rect_svg(node, parent_gs, items);
if (items)
@@ -1109,6 +1144,8 @@ read_items (xmlNodePtr startnode,
xmlFree (href);
}
/* remember some additional stuff of the current object */
+ if (g_list_find (items, obj) && g_list_length (g_list_find (items, obj)) > 1)
+ g_print ("Todo: group or set props ...\n");
if (obj) {
xmlChar *val = xmlGetProp (node, (const xmlChar *)"id");
if (val) {
@@ -1230,7 +1267,7 @@ import_svg(const gchar *filename, DiagramData *dia, DiaContext *ctx, void* user_
/* new_layer() is taking ownership of the name */
Layer *layer = new_layer (g_strdup (name), dia);
- /* layer_add_objects() is taking ownership of the list */
+ /* layer_add_objects() is taking ownersip of the list */
layer_add_objects (layer, g_list_copy (group_objects (group)));
data_add_layer (dia, layer);
group_destroy_shallow (group);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]