[dia] svg: almost working round-trip with cairo/svg



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, &current_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]