[glabels] Add native support for SVG images.



commit 3e365e5f9187a12fbf0e29d4d3804cab0261e8e9
Author: Jim Evins <evins snaught com>
Date:   Fri Jul 2 23:12:32 2010 -0400

    Add native support for SVG images.
    
    Rather than just rasterizing SVG files into GdkPixbufs, use RSVG to handle
    SVG files directly -- preserving the original file as inline data.

 configure.ac              |    2 +
 po/POTFILES.in            |    2 +
 src/Makefile.am           |    4 +
 src/debug.c               |    2 +
 src/debug.h               |   12 +-
 src/file-util.c           |   19 ++
 src/file-util.h           |    3 +
 src/label-image.c         |  696 ++++++++++++++++++++++++++++++++-------------
 src/label-image.h         |   31 ++-
 src/label.c               |   25 ++-
 src/label.h               |    4 +
 src/object-editor.c       |   10 +-
 src/svg-cache.c           |  316 ++++++++++++++++++++
 src/svg-cache.h           |   64 ++++
 src/xml-label.c           |  170 +++++++++---
 templates/glabels-2.3.dtd |   12 +-
 16 files changed, 1111 insertions(+), 261 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 4942de8..d3ee342 100644
--- a/configure.ac
+++ b/configure.ac
@@ -74,6 +74,7 @@ GLIB_REQUIRED=2.24.0
 GTK_REQUIRED=2.20.0
 GCONF_REQUIRED=2.28.0
 LIBXML_REQUIRED=2.7.0
+LIBRSVG_REQUIRED=2.26.0
 
 dnl Optional dependencies
 LIBEBOOK_REQUIRED=2.28.0
@@ -102,6 +103,7 @@ PKG_CHECK_MODULES(GLABELS, [\
 	gtk+-2.0 >= $GTK_REQUIRED \
 	gconf-2.0 >= $GCONF_REQUIRED \
 	libxml-2.0 >= $LIBXML_REQUIRED \
+	librsvg-2.0 > $LIBRSVG_REQUIRED \
 ])
 
 AC_SUBST(GLABELS_CFLAGS)
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 9dd1ad9..c19d009 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -141,6 +141,8 @@ src/stock.c
 src/stock.h
 src/str-util.c
 src/str-util.h
+src/svg-cache.c
+src/svg-cache.h
 src/template-designer.c
 src/template-designer.h
 src/template-history.c
diff --git a/src/Makefile.am b/src/Makefile.am
index 72f8e05..4ebd3a1 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -155,6 +155,8 @@ glabels_3_SOURCES = 			\
 	xml-label-04.h			\
 	pixbuf-cache.c			\
 	pixbuf-cache.h			\
+	svg-cache.c			\
+	svg-cache.h			\
 	merge.c				\
 	merge.h				\
 	merge-init.c			\
@@ -280,6 +282,8 @@ glabels_3_batch_SOURCES = 		\
 	xml-label-04.h			\
 	pixbuf-cache.c			\
 	pixbuf-cache.h			\
+	svg-cache.c			\
+	svg-cache.h			\
 	merge.c				\
 	merge.h				\
 	merge-init.c			\
diff --git a/src/debug.c b/src/debug.c
index 23432d9..d29d624 100644
--- a/src/debug.c
+++ b/src/debug.c
@@ -85,6 +85,8 @@ gl_debug_init (void)
 		debug_flags |= GLABELS_DEBUG_MINI_PREVIEW;
 	if (g_getenv ("GLABELS_DEBUG_PIXBUF_CACHE") != NULL)
 		debug_flags |= GLABELS_DEBUG_PIXBUF_CACHE;
+	if (g_getenv ("GLABELS_DEBUG_SVG_CACHE") != NULL)
+		debug_flags |= GLABELS_DEBUG_SVG_CACHE;
 	if (g_getenv ("GLABELS_DEBUG_EDITOR") != NULL)
 		debug_flags |= GLABELS_DEBUG_EDITOR;
 	if (g_getenv ("GLABELS_DEBUG_WDGT") != NULL)
diff --git a/src/debug.h b/src/debug.h
index 59a862b..25825a8 100644
--- a/src/debug.h
+++ b/src/debug.h
@@ -59,11 +59,12 @@ typedef enum {
 	GLABELS_DEBUG_MEDIA_SELECT = 1 << 16,
 	GLABELS_DEBUG_MINI_PREVIEW = 1 << 17,
 	GLABELS_DEBUG_PIXBUF_CACHE = 1 << 18,
-	GLABELS_DEBUG_EDITOR       = 1 << 19,
-	GLABELS_DEBUG_WDGT         = 1 << 20,
-        GLABELS_DEBUG_PATH         = 1 << 21,
-	GLABELS_DEBUG_FIELD_BUTTON = 1 << 22,
-        GLABELS_DEBUG_BARCODE      = 1 << 23,
+	GLABELS_DEBUG_SVG_CACHE    = 1 << 19,
+	GLABELS_DEBUG_EDITOR       = 1 << 20,
+	GLABELS_DEBUG_WDGT         = 1 << 21,
+        GLABELS_DEBUG_PATH         = 1 << 22,
+	GLABELS_DEBUG_FIELD_BUTTON = 1 << 23,
+        GLABELS_DEBUG_BARCODE      = 1 << 24,
 } glDebugSection;
 
 
@@ -90,6 +91,7 @@ typedef enum {
 #define	DEBUG_MEDIA_SELECT	GLABELS_DEBUG_MEDIA_SELECT,     __FILE__, __LINE__, __FUNCTION__
 #define	DEBUG_MINI_PREVIEW	GLABELS_DEBUG_MINI_PREVIEW,     __FILE__, __LINE__, __FUNCTION__
 #define	DEBUG_PIXBUF_CACHE	GLABELS_DEBUG_PIXBUF_CACHE,     __FILE__, __LINE__, __FUNCTION__
+#define	DEBUG_SVG_CACHE	GLABELS_DEBUG_SVG_CACHE,     __FILE__, __LINE__, __FUNCTION__
 #define	DEBUG_EDITOR	GLABELS_DEBUG_EDITOR, __FILE__, __LINE__, __FUNCTION__
 #define	DEBUG_WDGT	GLABELS_DEBUG_WDGT,   __FILE__, __LINE__, __FUNCTION__
 #define	DEBUG_PATH      GLABELS_DEBUG_PATH,   __FILE__, __LINE__, __FUNCTION__
diff --git a/src/file-util.c b/src/file-util.c
index ace188b..66d8ebf 100644
--- a/src/file-util.c
+++ b/src/file-util.c
@@ -90,6 +90,25 @@ gl_file_util_make_absolute (const gchar *filename)
 }
 
 
+/****************************************************************************/
+/* Test for given extension.                                                */
+/****************************************************************************/
+gboolean
+gl_file_util_is_extension (const gchar       *filename,
+                           const gchar       *ext_test)
+{
+        gchar *ext;
+
+        ext = strrchr (filename, '.');
+        if ( ext != NULL )
+        {
+                return (g_ascii_strcasecmp (ext, ext_test) == 0);
+        }
+
+        return FALSE;
+}
+
+
 
 /*
  * Local Variables:       -- emacs
diff --git a/src/file-util.h b/src/file-util.h
index 50c447c..f4e94f3 100644
--- a/src/file-util.h
+++ b/src/file-util.h
@@ -30,6 +30,9 @@ gchar              *gl_file_util_remove_extension      (const gchar       *orig_
 
 gchar              *gl_file_util_make_absolute         (const gchar       *filename);
 
+gboolean            gl_file_util_is_extension          (const gchar       *filename,
+                                                        const gchar       *ext_test);
+
 G_END_DECLS
 
 #endif /* __FILE_UTIL_H__ */
diff --git a/src/label-image.c b/src/label-image.c
index 7b7181e..46fc49f 100644
--- a/src/label-image.c
+++ b/src/label-image.c
@@ -25,6 +25,8 @@
 #include <glib/gi18n.h>
 #include <glib.h>
 #include <gdk/gdk.h>
+#include <librsvg/rsvg.h>
+#include <librsvg/rsvg-cairo.h>
 
 #include "pixbuf-util.h"
 #include "pixmaps/checkerboard.xpm"
@@ -39,9 +41,21 @@
 /* Private types.                                         */
 /*========================================================*/
 
+typedef enum {
+        FILE_TYPE_NONE,
+        FILE_TYPE_PIXBUF,
+        FILE_TYPE_SVG
+} FileType;
+
+
 struct _glLabelImagePrivate {
-	glTextNode       *filename;
-	GdkPixbuf        *pixbuf;
+
+        glTextNode       *filename;
+
+        FileType          type;
+
+        GdkPixbuf        *pixbuf;
+        RsvgHandle       *svg_handle;
 };
 
 
@@ -59,7 +73,7 @@ static GdkPixbuf *default_pixbuf = NULL;
 static void gl_label_image_finalize      (GObject           *object);
 
 static void copy                         (glLabelObject     *dst_object,
-					  glLabelObject     *src_object);
+                                          glLabelObject     *src_object);
 
 static void set_size                     (glLabelObject     *object,
                                           gdouble            w,
@@ -91,61 +105,79 @@ G_DEFINE_TYPE (glLabelImage, gl_label_image, GL_TYPE_LABEL_OBJECT);
 static void
 gl_label_image_class_init (glLabelImageClass *class)
 {
-	GObjectClass       *object_class       = G_OBJECT_CLASS (class);
-	glLabelObjectClass *label_object_class = GL_LABEL_OBJECT_CLASS (class);
+        GObjectClass       *object_class       = G_OBJECT_CLASS (class);
+        glLabelObjectClass *label_object_class = GL_LABEL_OBJECT_CLASS (class);
+        GdkPixbuf          *pixbuf;
 
-	gl_label_image_parent_class = g_type_class_peek_parent (class);
+        gl_label_image_parent_class = g_type_class_peek_parent (class);
 
-	label_object_class->copy              = copy;
-	label_object_class->set_size          = set_size;
+        label_object_class->copy              = copy;
+        label_object_class->set_size          = set_size;
         label_object_class->draw_object       = draw_object;
         label_object_class->draw_shadow       = draw_shadow;
         label_object_class->object_at         = object_at;
 
-	object_class->finalize = gl_label_image_finalize;
-}
+        object_class->finalize = gl_label_image_finalize;
 
-
-static void
-gl_label_image_init (glLabelImage *limage)
-{
-        GdkPixbuf *pixbuf;
-
-	if ( default_pixbuf == NULL ) {
-		pixbuf = gdk_pixbuf_new_from_xpm_data ((const char **)checkerboard_xpm);
+        if ( default_pixbuf == NULL ) {
+                pixbuf = gdk_pixbuf_new_from_xpm_data ((const char **)checkerboard_xpm);
                 default_pixbuf =
                         gdk_pixbuf_scale_simple (pixbuf, 128, 128, GDK_INTERP_NEAREST);
                 g_object_unref (pixbuf);
-	}
+        }
+}
+
 
-	limage->priv = g_new0 (glLabelImagePrivate, 1);
+static void
+gl_label_image_init (glLabelImage *this)
+{
+        this->priv = g_new0 (glLabelImagePrivate, 1);
 
-	limage->priv->filename = g_new0 (glTextNode, 1);
+        this->priv->filename = g_new0 (glTextNode, 1);
 
-	limage->priv->pixbuf = default_pixbuf;
+        this->priv->type       = FILE_TYPE_NONE;
+        this->priv->pixbuf     = NULL;
+        this->priv->svg_handle = NULL;
 }
 
 
 static void
 gl_label_image_finalize (GObject *object)
 {
-	glLabelObject *lobject = GL_LABEL_OBJECT (object);
-	glLabelImage  *limage  = GL_LABEL_IMAGE (object);
+        glLabelObject *lobject = GL_LABEL_OBJECT (object);
+        glLabelImage  *this  = GL_LABEL_IMAGE (object);
         glLabel       *label;
-	GHashTable    *pixbuf_cache;
+        GHashTable    *cache;
 
-	g_return_if_fail (object && GL_IS_LABEL_IMAGE (object));
+        g_return_if_fail (object && GL_IS_LABEL_IMAGE (object));
 
-	if (!limage->priv->filename->field_flag) {
+        if (!this->priv->filename->field_flag) {
+                
                 label = gl_label_object_get_parent (lobject);
-		pixbuf_cache = gl_label_get_pixbuf_cache (label);
-		gl_pixbuf_cache_remove_pixbuf (pixbuf_cache,
-					       limage->priv->filename->data);
-	}
-	gl_text_node_free (&limage->priv->filename);
-	g_free (limage->priv);
 
-	G_OBJECT_CLASS (gl_label_image_parent_class)->finalize (object);
+                switch ( this->priv->type )
+                {
+
+                case FILE_TYPE_PIXBUF:
+                        cache = gl_label_get_pixbuf_cache (label);
+                        gl_pixbuf_cache_remove_pixbuf (cache, this->priv->filename->data);
+                        break;
+
+                case FILE_TYPE_SVG:
+                        cache = gl_label_get_svg_cache (label);
+                        gl_svg_cache_remove_svg (cache, this->priv->filename->data);
+                        break;
+
+                default:
+                        break;
+
+                }
+
+        }
+        gl_text_node_free (&this->priv->filename);
+        g_free (this->priv);
+
+        G_OBJECT_CLASS (gl_label_image_parent_class)->finalize (object);
 }
 
 
@@ -156,9 +188,9 @@ GObject *
 gl_label_image_new (glLabel *label,
                     gboolean checkpoint)
 {
-	glLabelImage *limage;
+        glLabelImage *this;
 
-	limage = g_object_new (gl_label_image_get_type(), NULL);
+        this = g_object_new (gl_label_image_get_type(), NULL);
 
         if (label != NULL)
         {
@@ -167,11 +199,11 @@ gl_label_image_new (glLabel *label,
                         gl_label_checkpoint (label, _("Create image object"));
                 }
 
-                gl_label_add_object (label, GL_LABEL_OBJECT (limage));
-                gl_label_object_set_parent (GL_LABEL_OBJECT (limage), label);
+                gl_label_add_object (label, GL_LABEL_OBJECT (this));
+                gl_label_object_set_parent (GL_LABEL_OBJECT (this), label);
         }
 
-	return G_OBJECT (limage);
+        return G_OBJECT (this);
 }
 
 
@@ -182,34 +214,58 @@ static void
 copy (glLabelObject *dst_object,
       glLabelObject *src_object)
 {
-	glLabelImage     *limage     = (glLabelImage *)src_object;
-	glLabelImage     *new_limage = (glLabelImage *)dst_object;
-	glTextNode       *filename;
-	GdkPixbuf        *pixbuf;
-        glLabel          *label;
-	GHashTable       *pixbuf_cache;
-
-	gl_debug (DEBUG_LABEL, "START");
-
-	g_return_if_fail (limage && GL_IS_LABEL_IMAGE (limage));
-	g_return_if_fail (new_limage && GL_IS_LABEL_IMAGE (new_limage));
-
-	filename = gl_label_image_get_filename (limage);
-
-	/* Make sure destination label has data suitably cached. */
-	if ( !filename->field_flag && (filename->data != NULL) ) {
-		pixbuf = limage->priv->pixbuf;
-		if ( pixbuf != default_pixbuf ) {
-                        label = gl_label_object_get_parent (dst_object);
-			pixbuf_cache = gl_label_get_pixbuf_cache (label);
-			gl_pixbuf_cache_add_pixbuf (pixbuf_cache, filename->data, pixbuf);
-		}
-	}
+        glLabelImage     *src_limage = (glLabelImage *)src_object;
+        glLabelImage     *new_limage = (glLabelImage *)dst_object;
+        glTextNode       *filename;
+        GdkPixbuf        *pixbuf;
+        gchar            *contents;
+        glLabel          *src_label, *dst_label;
+        GHashTable       *cache;
+
+        gl_debug (DEBUG_LABEL, "START");
 
-	gl_label_image_set_filename (new_limage, filename, FALSE);
-	gl_text_node_free (&filename);
+        g_return_if_fail (src_limage && GL_IS_LABEL_IMAGE (src_limage));
+        g_return_if_fail (new_limage && GL_IS_LABEL_IMAGE (new_limage));
 
-	gl_debug (DEBUG_LABEL, "END");
+        filename = gl_label_image_get_filename (src_limage);
+
+        /* Make sure destination label has data suitably cached. */
+        if ( !filename->field_flag && (src_limage->priv->type != FILE_TYPE_NONE) )
+        {
+                src_label = gl_label_object_get_parent (src_object);
+                dst_label = gl_label_object_get_parent (dst_object);
+
+                switch ( src_limage->priv->type )
+                {
+
+                case FILE_TYPE_PIXBUF:
+                        pixbuf = src_limage->priv->pixbuf;
+                        if ( pixbuf != NULL ) {
+                                cache = gl_label_get_pixbuf_cache (dst_label);
+                                gl_pixbuf_cache_add_pixbuf (cache, filename->data, pixbuf);
+                        }
+                        break;
+
+                case FILE_TYPE_SVG:
+                        cache = gl_label_get_svg_cache (src_label);
+                        contents = gl_svg_cache_get_contents (cache, filename->data);
+                        if ( contents != NULL ) {
+                                cache = gl_label_get_svg_cache (dst_label);
+                                gl_svg_cache_add_svg (cache, filename->data, contents);
+                                g_free (contents);
+                        }
+                        break;
+
+                default:
+                        break;
+
+                }
+        }
+
+        gl_label_image_set_filename (new_limage, filename, FALSE);
+        gl_text_node_free (&filename);
+
+        gl_debug (DEBUG_LABEL, "END");
 }
 
 
@@ -218,11 +274,11 @@ copy (glLabelObject *dst_object,
 /*---------------------------------------------------------------------------*/
 static void
 set_size (glLabelObject *object,
-	  gdouble        w,
-	  gdouble        h,
+          gdouble        w,
+          gdouble        h,
           gboolean       checkpoint)
 {
-	g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
+        g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
 
         if (w < MIN_IMAGE_SIZE)
         {
@@ -234,7 +290,7 @@ set_size (glLabelObject *object,
                 h = MIN_IMAGE_SIZE;
         }
 
-	GL_LABEL_OBJECT_CLASS (gl_label_image_parent_class)->set_size (object, w, h, checkpoint);
+        GL_LABEL_OBJECT_CLASS (gl_label_image_parent_class)->set_size (object, w, h, checkpoint);
 }
 
 
@@ -242,176 +298,378 @@ set_size (glLabelObject *object,
 /* Set object params.                                                        */
 /*****************************************************************************/
 void
-gl_label_image_set_filename (glLabelImage *limage,
-			     glTextNode   *filename,
+gl_label_image_set_filename (glLabelImage *this,
+                             glTextNode   *filename,
                              gboolean      checkpoint)
 {
-	glTextNode  *old_filename;
-        glLabel     *label;
-	GHashTable  *pixbuf_cache;
-	GdkPixbuf   *pixbuf;
-	gdouble      image_w, image_h, aspect_ratio, w, h;
+        glTextNode        *old_filename;
+        glLabel           *label;
+        GHashTable        *pixbuf_cache;
+        GHashTable        *svg_cache;
+        GdkPixbuf         *pixbuf;
+        RsvgHandle        *svg_handle;
+        RsvgDimensionData  svg_dim;
+        gdouble            image_w, image_h, aspect_ratio, w, h;
 
-	gl_debug (DEBUG_LABEL, "START");
+        gl_debug (DEBUG_LABEL, "START");
 
-	g_return_if_fail (limage && GL_IS_LABEL_IMAGE (limage));
-	g_return_if_fail (filename != NULL);
+        g_return_if_fail (this && GL_IS_LABEL_IMAGE (this));
+        g_return_if_fail (filename != NULL);
 
-	old_filename = limage->priv->filename;
+        old_filename = this->priv->filename;
 
-	/* If Unchanged don't do anything */
-	if ( gl_text_node_equal (filename, old_filename ) ) {
-		return;
-	}
+        /* If Unchanged don't do anything */
+        if ( gl_text_node_equal (filename, old_filename ) ) {
+                return;
+        }
 
-        label = gl_label_object_get_parent (GL_LABEL_OBJECT (limage));
+        label = gl_label_object_get_parent (GL_LABEL_OBJECT (this));
+        pixbuf_cache = gl_label_get_pixbuf_cache (label);
+        svg_cache    = gl_label_get_svg_cache (label);
 
         if ( checkpoint )
         {
                 gl_label_checkpoint (label, _("Set image"));
         }
 
-	pixbuf_cache = gl_label_get_pixbuf_cache (label);
+        /* Set new filename. */
+        this->priv->filename = gl_text_node_dup(filename);
 
-	/* Remove reference to previous pixbuf from cache, if needed. */
-	if ( !old_filename->field_flag && (old_filename->data != NULL) ) {
-		gl_pixbuf_cache_remove_pixbuf (pixbuf_cache, old_filename->data);
-	}
+        /* Remove reference to previous item. */
+        switch (this->priv->type)
+        {
 
-	/* Set new filename. */
-	limage->priv->filename = gl_text_node_dup(filename);
-	gl_text_node_free (&old_filename);
+        case FILE_TYPE_PIXBUF:
+                if ( !old_filename->field_flag && (old_filename->data != NULL) ) {
+                        gl_pixbuf_cache_remove_pixbuf (pixbuf_cache, old_filename->data);
+                }
+                break;
 
-	/* Now set the pixbuf. */
-	if ( filename->field_flag || (filename->data == NULL) ) {
+        case FILE_TYPE_SVG:
+                if ( !old_filename->field_flag && (old_filename->data != NULL) ) {
+                        gl_svg_cache_remove_svg (svg_cache, old_filename->data);
+                }
+                break;
 
-		limage->priv->pixbuf = default_pixbuf;
+        default:
+                break;
 
-	} else {
+        }
 
-		pixbuf = gl_pixbuf_cache_get_pixbuf (pixbuf_cache, filename->data);
+        gl_text_node_free (&old_filename);
 
-		if (pixbuf != NULL) {
-			limage->priv->pixbuf = pixbuf;
-		} else {
-			limage->priv->pixbuf = default_pixbuf;
-		}
-	}
 
-	/* Treat current size as a bounding box, scale image to maintain aspect
-	 * ratio while fitting it in this bounding box. */
-	image_w = gdk_pixbuf_get_width (limage->priv->pixbuf);
-	image_h = gdk_pixbuf_get_height (limage->priv->pixbuf);
-	aspect_ratio = image_h / image_w;
-	gl_label_object_get_size (GL_LABEL_OBJECT(limage), &w, &h);
-	if ( h > w*aspect_ratio ) {
-		h = w * aspect_ratio;
-	} else {
-		w = h / aspect_ratio;
-	}
-	gl_label_object_set_size (GL_LABEL_OBJECT(limage), w, h, FALSE);
+        /* Now set the new file type and the pixbuf or svg_handle. */
+        if ( !filename->field_flag && (filename->data != NULL) )
+        {
+
+                if ( gl_file_util_is_extension (filename->data, ".svg") )
+                {
+                        svg_handle = gl_svg_cache_get_handle (svg_cache, filename->data);
+
+                        if (svg_handle != NULL)
+                        {
+                                this->priv->type       = FILE_TYPE_SVG;
+                                this->priv->pixbuf     = NULL;
+                                this->priv->svg_handle = svg_handle;
+                        }
+                        else
+                        {
+                                this->priv->type       = FILE_TYPE_NONE;
+                                this->priv->pixbuf     = NULL;
+                                this->priv->svg_handle = NULL;
+                        }
+
+                }
+                else
+                {
+
+                        pixbuf = gl_pixbuf_cache_get_pixbuf (pixbuf_cache, filename->data);
+
+                        if (pixbuf != NULL)
+                        {
+                                this->priv->type       = FILE_TYPE_PIXBUF;
+                                this->priv->pixbuf     = pixbuf;
+                                this->priv->svg_handle = NULL;
+                        }
+                        else
+                        {
+                                this->priv->type       = FILE_TYPE_NONE;
+                                this->priv->pixbuf     = NULL;
+                                this->priv->svg_handle = NULL;
+                        }
+
+                }
+        }
+        else
+        {
+                this->priv->type       = FILE_TYPE_NONE;
+                this->priv->pixbuf     = NULL;
+                this->priv->svg_handle = NULL;
+        }
+
+
+        /* Treat current size as a bounding box, scale image to maintain aspect
+         * ratio while fitting it in this bounding box. */
+        switch (this->priv->type)
+        {
+
+        case FILE_TYPE_PIXBUF:
+                image_w = gdk_pixbuf_get_width (this->priv->pixbuf);
+                image_h = gdk_pixbuf_get_height (this->priv->pixbuf);
+                break;
+
+        case FILE_TYPE_SVG:
+                rsvg_handle_get_dimensions (this->priv->svg_handle, &svg_dim);
+                image_w = svg_dim.width;
+                image_h = svg_dim.height;
+                break;
+
+        default:
+                image_w = gdk_pixbuf_get_width (default_pixbuf);
+                image_h = gdk_pixbuf_get_height (default_pixbuf);
+                break;
+
+        }
+        aspect_ratio = image_h / image_w;
+        gl_label_object_get_size (GL_LABEL_OBJECT(this), &w, &h);
+        if ( h > w*aspect_ratio ) {
+                h = w * aspect_ratio;
+        } else {
+                w = h / aspect_ratio;
+        }
+        gl_label_object_set_size (GL_LABEL_OBJECT(this), w, h, FALSE);
 
-	gl_label_object_emit_changed (GL_LABEL_OBJECT(limage));
+        gl_label_object_emit_changed (GL_LABEL_OBJECT(this));
 
-	gl_debug (DEBUG_LABEL, "END");
+        gl_debug (DEBUG_LABEL, "END");
 }
 
 
 void
-gl_label_image_set_pixbuf (glLabelImage  *limage,
+gl_label_image_set_pixbuf (glLabelImage  *this,
                            GdkPixbuf     *pixbuf,
                            gboolean       checkpoint)
 {
-	glTextNode  *old_filename;
+        glTextNode  *old_filename;
         glLabel     *label;
-	GHashTable  *pixbuf_cache;
+        GHashTable  *pixbuf_cache;
+        GHashTable  *svg_cache;
+        gchar       *cs;
         gchar       *name;
-	gdouble      image_w, image_h;
+        gdouble      image_w, image_h;
 
-	gl_debug (DEBUG_LABEL, "START");
+        gl_debug (DEBUG_LABEL, "START");
 
-	g_return_if_fail (limage && GL_IS_LABEL_IMAGE (limage));
-	g_return_if_fail (pixbuf && GDK_IS_PIXBUF (pixbuf));
+        g_return_if_fail (this && GL_IS_LABEL_IMAGE (this));
+        g_return_if_fail (pixbuf && GDK_IS_PIXBUF (pixbuf));
 
-	old_filename = limage->priv->filename;
+        old_filename = this->priv->filename;
 
-        label = gl_label_object_get_parent (GL_LABEL_OBJECT (limage));
+        label = gl_label_object_get_parent (GL_LABEL_OBJECT (this));
 
         if ( checkpoint )
         {
                 gl_label_checkpoint (label, _("Set image"));
         }
 
-	pixbuf_cache = gl_label_get_pixbuf_cache (label);
+        pixbuf_cache = gl_label_get_pixbuf_cache (label);
 
-	/* Remove reference to previous pixbuf from cache, if needed. */
-	if ( !old_filename->field_flag && (old_filename->data != NULL) ) {
-		gl_pixbuf_cache_remove_pixbuf (pixbuf_cache, old_filename->data);
-	}
+        /* Remove reference to previous item. */
+        switch (this->priv->type)
+        {
+
+        case FILE_TYPE_PIXBUF:
+                if ( !old_filename->field_flag && (old_filename->data != NULL) ) {
+                        gl_pixbuf_cache_remove_pixbuf (pixbuf_cache, old_filename->data);
+                }
+                break;
+
+        case FILE_TYPE_SVG:
+                if ( !old_filename->field_flag && (old_filename->data != NULL) ) {
+                        gl_svg_cache_remove_svg (svg_cache, old_filename->data);
+                }
+                break;
+
+        default:
+                break;
+
+        }
 
-	/* Set new filename. */
-        name = g_compute_checksum_for_data (G_CHECKSUM_MD5,
-                                            gdk_pixbuf_get_pixels (pixbuf),
-                                            gdk_pixbuf_get_rowstride (pixbuf)*gdk_pixbuf_get_height (pixbuf));
-	limage->priv->filename = gl_text_node_new_from_text(name);
-	gl_text_node_free (&old_filename);
+        /* Set new filename. */
+        cs = g_compute_checksum_for_data (G_CHECKSUM_MD5,
+                                          gdk_pixbuf_get_pixels (pixbuf),
+                                          gdk_pixbuf_get_rowstride (pixbuf)*gdk_pixbuf_get_height (pixbuf));
+        name = g_strdup_printf ("%s.bitmap", cs);
+        this->priv->filename = gl_text_node_new_from_text(name);
+        gl_text_node_free (&old_filename);
 
-        limage->priv->pixbuf = g_object_ref (pixbuf);
+        this->priv->pixbuf = g_object_ref (pixbuf);
         gl_pixbuf_cache_add_pixbuf (pixbuf_cache, name, pixbuf);
 
+        g_free (cs);
         g_free (name);
 
-	image_w = gdk_pixbuf_get_width (limage->priv->pixbuf);
-	image_h = gdk_pixbuf_get_height (limage->priv->pixbuf);
-	gl_label_object_set_size (GL_LABEL_OBJECT(limage), image_w, image_h, FALSE);
+        this->priv->type       = FILE_TYPE_PIXBUF;
+        this->priv->svg_handle = NULL;
+
+        image_w = gdk_pixbuf_get_width (this->priv->pixbuf);
+        image_h = gdk_pixbuf_get_height (this->priv->pixbuf);
+        gl_label_object_set_size (GL_LABEL_OBJECT(this), image_w, image_h, FALSE);
 
-	gl_label_object_emit_changed (GL_LABEL_OBJECT(limage));
+        gl_label_object_emit_changed (GL_LABEL_OBJECT(this));
 
-	gl_debug (DEBUG_LABEL, "END");
+        gl_debug (DEBUG_LABEL, "END");
 }
 
 
 /*****************************************************************************/
 /* Get object params.                                                        */
 /*****************************************************************************/
-glTextNode *
-gl_label_image_get_filename (glLabelImage *limage)
+GdkPixbuf *
+gl_label_image_get_pixbuf (glLabelImage  *this,
+                           glMergeRecord *record)
 {
-	g_return_val_if_fail (limage && GL_IS_LABEL_IMAGE (limage), NULL);
+        g_return_val_if_fail (this && GL_IS_LABEL_IMAGE (this), NULL);
+
+        if ((record != NULL) && this->priv->filename->field_flag)
+        {
 
-	return gl_text_node_dup (limage->priv->filename);
+                GdkPixbuf   *pixbuf = NULL;
+                gchar       *real_filename;
+
+                /* Indirect filename, re-evaluate for given record. */
+
+                real_filename = gl_merge_eval_key (record,
+						   this->priv->filename->data);
+
+                if (real_filename != NULL)
+                {
+                        pixbuf = gdk_pixbuf_new_from_file (real_filename, NULL);
+                }
+                return pixbuf;
+        }
+
+        if ( this->priv->type == FILE_TYPE_PIXBUF )
+        {
+                return g_object_ref (this->priv->pixbuf);
+        }
+        else
+        {
+                return NULL;
+        }
 }
 
 
-const GdkPixbuf *
-gl_label_image_get_pixbuf (glLabelImage  *limage,
-			   glMergeRecord *record)
+RsvgHandle *
+gl_label_image_get_svg_handle (glLabelImage  *this,
+                               glMergeRecord *record)
 {
-	g_return_val_if_fail (limage && GL_IS_LABEL_IMAGE (limage), NULL);
+	g_return_val_if_fail (this && GL_IS_LABEL_IMAGE (this), NULL);
 
-	if ((record != NULL) && limage->priv->filename->field_flag) {
+	if ((record != NULL) && this->priv->filename->field_flag)
+        {
 
-		GdkPixbuf   *pixbuf = NULL;
+		RsvgHandle  *svg_handle = NULL;
 		gchar       *real_filename;
 
 		/* Indirect filename, re-evaluate for given record. */
 
 		real_filename = gl_merge_eval_key (record,
-						   limage->priv->filename->data);
+						   this->priv->filename->data);
 
-		if (real_filename != NULL) {
-			pixbuf = gdk_pixbuf_new_from_file (real_filename, NULL);
-		}
-		if ( pixbuf != NULL ) {
-			return pixbuf;
-		} else {
-			return default_pixbuf;
+		if (real_filename != NULL)
+                {
+                        if ( gl_file_util_is_extension (real_filename, ".svg") )
+                        {
+                                svg_handle = rsvg_handle_new_from_file (real_filename, NULL);
+                        }
 		}
-
+                return svg_handle;
 	}
 
-	return limage->priv->pixbuf;
+        if ( this->priv->type == FILE_TYPE_SVG )
+        {
+                return g_object_ref (this->priv->svg_handle);
+        }
+        else
+        {
+                return NULL;
+        }
+}
+
+
+static FileType
+get_type (glLabelImage  *this,
+          glMergeRecord *record)
+{
+	g_return_val_if_fail (this && GL_IS_LABEL_IMAGE (this), FALSE);
+
+	if ((record != NULL) && this->priv->filename->field_flag)
+        {
+		gchar       *real_filename;
+
+		real_filename = gl_merge_eval_key (record,
+						   this->priv->filename->data);
+
+                if ( gl_file_util_is_extension (real_filename, ".svg") )
+                {
+                        return FILE_TYPE_SVG;
+                }
+                else
+                {
+                        /* Assume a pixbuf compat file.  If not, queries for
+                           pixbufs should return NULL and do the right thing. */
+                        return FILE_TYPE_PIXBUF;
+                }
+        }
+        else
+        {
+                return (this->priv->type);
+        }
+}
+
+
+glTextNode *
+gl_label_image_get_filename (glLabelImage *this)
+{
+        g_return_val_if_fail (this && GL_IS_LABEL_IMAGE (this), NULL);
 
+        return gl_text_node_dup (this->priv->filename);
+}
+
+
+void
+gl_label_image_get_base_size (glLabelImage *this,
+                              gdouble      *w,
+                              gdouble      *h)
+{
+        RsvgDimensionData  svg_dim;
+
+        g_return_if_fail (this && GL_IS_LABEL_IMAGE (this));
+        g_return_if_fail (w != NULL);
+        g_return_if_fail (h != NULL);
+
+        switch (this->priv->type)
+        {
+
+        case FILE_TYPE_PIXBUF:
+                *w = gdk_pixbuf_get_width (this->priv->pixbuf);
+                *h = gdk_pixbuf_get_height (this->priv->pixbuf);
+                break;
+
+        case FILE_TYPE_SVG:
+                rsvg_handle_get_dimensions (this->priv->svg_handle, &svg_dim);
+                *w = svg_dim.width;
+                *h = svg_dim.height;
+                break;
+
+        default:
+                *w = gdk_pixbuf_get_width (default_pixbuf);
+                *h = gdk_pixbuf_get_height (default_pixbuf);
+                break;
+
+        }
 }
 
 
@@ -424,29 +682,60 @@ draw_object (glLabelObject *object,
              gboolean       screen_flag,
              glMergeRecord *record)
 {
-	gdouble          w, h;
-	const GdkPixbuf *pixbuf;
-	gint             image_w, image_h;
+        glLabelImage      *this = GL_LABEL_IMAGE (object);
+        gdouble            w, h;
+        gdouble            image_w, image_h;
+        GdkPixbuf         *pixbuf;
+        RsvgHandle        *svg_handle;
+        RsvgDimensionData  svg_dim;
+
+        gl_debug (DEBUG_LABEL, "START");
+
+        gl_label_object_get_size (object, &w, &h);
 
-	gl_debug (DEBUG_LABEL, "START");
+        cairo_save (cr);
 
-	gl_label_object_get_size (object, &w, &h);
+        switch (get_type (this, record))
+        {
 
-	pixbuf = gl_label_image_get_pixbuf (GL_LABEL_IMAGE (object), record);
-	image_w = gdk_pixbuf_get_width (pixbuf);
-	image_h = gdk_pixbuf_get_height (pixbuf);
+        case FILE_TYPE_PIXBUF:
+                pixbuf = gl_label_image_get_pixbuf (this, record);
+                if ( pixbuf )
+                {
+                        image_w = gdk_pixbuf_get_width (pixbuf);
+                        image_h = gdk_pixbuf_get_height (pixbuf);
+                        cairo_rectangle (cr, 0.0, 0.0, w, h);
+                        cairo_scale (cr, w/image_w, h/image_h);
+                        gdk_cairo_set_source_pixbuf (cr, pixbuf, 0, 0);
+                        cairo_fill (cr);
+                        g_object_unref (pixbuf);
+                }
+                break;
 
-	cairo_save (cr);
+        case FILE_TYPE_SVG:
+                svg_handle = gl_label_image_get_svg_handle (this, record);
+                if ( svg_handle )
+                {
+                        rsvg_handle_get_dimensions (svg_handle, &svg_dim);
+                        cairo_scale (cr, w/svg_dim.width, h/svg_dim.height);
+                        rsvg_handle_render_cairo (svg_handle, cr);
+                }
+                break;
 
-        cairo_rectangle (cr, 0.0, 0.0, w, h);
+        default:
+                cairo_rectangle (cr, 0.0, 0.0, w, h);
+                image_w = gdk_pixbuf_get_width (default_pixbuf);
+                image_h = gdk_pixbuf_get_height (default_pixbuf);
+                cairo_scale (cr, w/image_w, h/image_h);
+                gdk_cairo_set_source_pixbuf (cr, default_pixbuf, 0, 0);
+                cairo_fill (cr);
+                break;
 
-	cairo_scale (cr, w/image_w, h/image_h);
-        gdk_cairo_set_source_pixbuf (cr, (GdkPixbuf *)pixbuf, 0, 0);
-        cairo_fill (cr);
+        }
 
-	cairo_restore (cr);
+        cairo_restore (cr);
 
-	gl_debug (DEBUG_LABEL, "END");
+        gl_debug (DEBUG_LABEL, "END");
 }
 
 
@@ -459,10 +748,11 @@ draw_shadow (glLabelObject *object,
              gboolean       screen_flag,
              glMergeRecord *record)
 {
+        glLabelImage    *this = GL_LABEL_IMAGE (object);
         gdouble          w, h;
-        const GdkPixbuf *pixbuf;
+        GdkPixbuf       *pixbuf;
         GdkPixbuf       *shadow_pixbuf;
-        gint             image_w, image_h;
+        gdouble          image_w, image_h;
         glColorNode     *shadow_color_node;
         guint            shadow_color;
         gdouble          shadow_opacity;
@@ -479,22 +769,44 @@ draw_shadow (glLabelObject *object,
         }
         shadow_opacity = gl_label_object_get_shadow_opacity (object);
 
-        pixbuf = gl_label_image_get_pixbuf (GL_LABEL_IMAGE (object), record);
-        image_w = gdk_pixbuf_get_width (pixbuf);
-        image_h = gdk_pixbuf_get_height (pixbuf);
-        shadow_pixbuf = gl_pixbuf_util_create_shadow_pixbuf (pixbuf, shadow_color, shadow_opacity);
-
         cairo_save (cr);
 
-        cairo_rectangle (cr, 0.0, 0.0, w, h);
+        switch (get_type (this, record))
+        {
+
+        case FILE_TYPE_PIXBUF:
+                pixbuf = gl_label_image_get_pixbuf (this, record);
+                if ( pixbuf )
+                {
+                        image_w = gdk_pixbuf_get_width (pixbuf);
+                        image_h = gdk_pixbuf_get_height (pixbuf);
+
+                        shadow_pixbuf = gl_pixbuf_util_create_shadow_pixbuf (pixbuf,
+                                                                             shadow_color, shadow_opacity);
+                        cairo_rectangle (cr, 0.0, 0.0, w, h);
+                        cairo_scale (cr, w/image_w, h/image_h);
+                        gdk_cairo_set_source_pixbuf (cr, (GdkPixbuf *)shadow_pixbuf, 0, 0);
+                        cairo_fill (cr);
+
+                        g_object_unref (G_OBJECT (shadow_pixbuf));
+                        g_object_unref (G_OBJECT (pixbuf));
+                }
+                break;
 
-        cairo_scale (cr, w/image_w, h/image_h);
-        gdk_cairo_set_source_pixbuf (cr, (GdkPixbuf *)shadow_pixbuf, 0, 0);
-        cairo_fill (cr);
+        case FILE_TYPE_SVG:
+                /* FIXME: no shadow support, yet. */
+                break;
 
-        cairo_restore (cr);
+        default:
+                shadow_color = gl_color_set_opacity (shadow_color, shadow_opacity);
 
-        g_object_unref (G_OBJECT (shadow_pixbuf));
+                cairo_rectangle (cr, 0.0, 0.0, w, h);
+                cairo_set_source_rgba (cr, GL_COLOR_RGBA_ARGS (shadow_color));
+                cairo_fill (cr);
+                break;
+        }
+
+        cairo_restore (cr);
 
         gl_debug (DEBUG_LABEL, "END");
 }
diff --git a/src/label-image.h b/src/label-image.h
index 218a2e7..98abc46 100644
--- a/src/label-image.h
+++ b/src/label-image.h
@@ -50,23 +50,30 @@ struct _glLabelImageClass {
 	glLabelObjectClass    parent_class;
 };
 
-GType            gl_label_image_get_type     (void) G_GNUC_CONST;
+GType            gl_label_image_get_type       (void) G_GNUC_CONST;
 
-GObject         *gl_label_image_new          (glLabel       *label,
-                                              gboolean       checkpoint);
+GObject         *gl_label_image_new            (glLabel       *label,
+                                                gboolean       checkpoint);
 
-void             gl_label_image_set_filename (glLabelImage  *limage,
-					      glTextNode    *filename,
-                                              gboolean       checkpoint);
+void             gl_label_image_set_filename   (glLabelImage  *limage,
+                                                glTextNode    *filename,
+                                                gboolean       checkpoint);
 
-void             gl_label_image_set_pixbuf   (glLabelImage  *limage,
-					      GdkPixbuf     *pixbuf,
-                                              gboolean       checkpoint);
+void             gl_label_image_set_pixbuf     (glLabelImage  *limage,
+                                                GdkPixbuf     *pixbuf,
+                                                gboolean       checkpoint);
 
-glTextNode      *gl_label_image_get_filename (glLabelImage  *limage);
+GdkPixbuf       *gl_label_image_get_pixbuf     (glLabelImage  *limage,
+                                                glMergeRecord *record);
 
-const GdkPixbuf *gl_label_image_get_pixbuf   (glLabelImage  *limage,
-					      glMergeRecord *record);
+RsvgHandle      *gl_label_image_get_svg_handle (glLabelImage  *this,
+                                                glMergeRecord *record);
+
+glTextNode      *gl_label_image_get_filename   (glLabelImage  *limage);
+
+void             gl_label_image_get_base_size  (glLabelImage *this,
+                                                gdouble      *w,
+                                                gdouble      *h);
 
 G_END_DECLS
 
diff --git a/src/label.c b/src/label.c
index 84fc098..37e0c6c 100644
--- a/src/label.c
+++ b/src/label.c
@@ -62,6 +62,7 @@ struct _glLabelPrivate {
 	glMerge     *merge;
 
 	GHashTable  *pixbuf_cache;
+	GHashTable  *svg_cache;
 
         /* Delay changed signals while operating on selections of multiple objects. */
         gboolean     selection_op_flag;
@@ -275,6 +276,7 @@ gl_label_init (glLabel *label)
 
 	label->priv->merge         = NULL;
 	label->priv->pixbuf_cache  = gl_pixbuf_cache_new ();
+	label->priv->svg_cache     = gl_svg_cache_new ();
 
         label->priv->undo_stack    = g_queue_new ();
         label->priv->redo_stack    = g_queue_new ();
@@ -328,6 +330,7 @@ gl_label_finalize (GObject *object)
         g_queue_free (label->priv->redo_stack);
 
 	gl_pixbuf_cache_free (label->priv->pixbuf_cache);
+	gl_svg_cache_free (label->priv->svg_cache);
 
 	g_free (label->priv);
 
@@ -741,6 +744,16 @@ gl_label_get_pixbuf_cache (glLabel       *label)
 }
 
 
+/****************************************************************************/
+/* Get svg cache.                                                           */
+/****************************************************************************/
+GHashTable *
+gl_label_get_svg_cache (glLabel       *label)
+{
+	return label->priv->svg_cache;
+}
+
+
 /*****************************************************************************/
 /* Add object to label.                                                      */
 /*****************************************************************************/
@@ -2392,12 +2405,14 @@ gl_label_copy_selection (glLabel       *label)
                 if ( gl_label_is_selection_atomic (label) &&
                      GL_IS_LABEL_IMAGE (selection_list->data) )
                 {
-                        glLabelImage       *image_object = GL_LABEL_IMAGE (selection_list->data);
-                        const GdkPixbuf    *pixbuf = gl_label_image_get_pixbuf (image_object, NULL);
-
-                        gtk_target_list_add_image_targets (target_list, 2, TRUE);
+                        glLabelImage  *image_object = GL_LABEL_IMAGE (selection_list->data);
+                        GdkPixbuf     *pixbuf = gl_label_image_get_pixbuf (image_object, NULL);
 
-                        data->pixbuf = g_object_ref (G_OBJECT (pixbuf));
+                        if (pixbuf)
+                        {
+                                gtk_target_list_add_image_targets (target_list, 2, TRUE);
+                                data->pixbuf = pixbuf;
+                        }
                 }
 
 
diff --git a/src/label.h b/src/label.h
index aa18336..eccd608 100644
--- a/src/label.h
+++ b/src/label.h
@@ -28,6 +28,7 @@
 #include "merge.h"
 #include "color.h"
 #include "pixbuf-cache.h"
+#include "svg-cache.h"
 
 G_BEGIN_DECLS
 
@@ -133,6 +134,9 @@ glMerge      *gl_label_get_merge               (glLabel       *label);
 GHashTable   *gl_label_get_pixbuf_cache        (glLabel       *label);
 
 
+GHashTable   *gl_label_get_svg_cache           (glLabel       *label);
+
+
 void          gl_label_add_object              (glLabel       *label,
 						glLabelObject *object);
 
diff --git a/src/object-editor.c b/src/object-editor.c
index d544c55..8640371 100644
--- a/src/object-editor.c
+++ b/src/object-editor.c
@@ -742,7 +742,6 @@ object_changed_cb (glLabelObject  *object,
         PangoAlignment   align;
         gdouble          text_line_spacing;
         gboolean         auto_shrink;
-        const GdkPixbuf *pixbuf;
         gdouble          image_w, image_h;
         glTextNode      *filename;
         glTextNode      *bc_data;
@@ -804,11 +803,9 @@ object_changed_cb (glLabelObject  *object,
         {
 
                 gl_label_object_get_size (object, &w, &h);
-                pixbuf   = gl_label_image_get_pixbuf (GL_LABEL_IMAGE(object), NULL);
                 filename = gl_label_image_get_filename (GL_LABEL_IMAGE(object));
 
-                image_w = gdk_pixbuf_get_width (pixbuf);
-                image_h = gdk_pixbuf_get_height (pixbuf);
+                gl_label_image_get_base_size (GL_LABEL_IMAGE(object), &image_w, &image_h);
 
                 gl_object_editor_set_size (editor, w, h);
                 gl_object_editor_set_base_size (editor, image_w, image_h);
@@ -902,7 +899,6 @@ gl_object_editor_changed_cb (glObjectEditor *editor)
         gdouble            text_line_spacing;
         gboolean           auto_shrink;
         glTextNode        *filename;
-        const GdkPixbuf   *pixbuf;
         gdouble            w, h;
         gdouble            image_w, image_h;
         gdouble            new_w, new_h;
@@ -968,9 +964,7 @@ gl_object_editor_changed_cb (glObjectEditor *editor)
                 }
 
                 /* It may also have a new base size. */
-                pixbuf = gl_label_image_get_pixbuf (GL_LABEL_IMAGE(object), NULL);
-                image_w = gdk_pixbuf_get_width (pixbuf);
-                image_h = gdk_pixbuf_get_height (pixbuf);
+                gl_label_image_get_base_size (GL_LABEL_IMAGE(object), &image_w, &image_h);
                 gl_object_editor_set_base_size (editor, image_w, image_h);
 
                 gl_text_node_free (&filename);
diff --git a/src/svg-cache.c b/src/svg-cache.c
new file mode 100644
index 0000000..f1161bd
--- /dev/null
+++ b/src/svg-cache.c
@@ -0,0 +1,316 @@
+/*
+ *  svg-cache.c
+ *  Copyright (C) 2003-2009  Jim Evins <evins snaught com>.
+ *
+ *  This file is part of gLabels.
+ *
+ *  gLabels is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  gLabels is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with gLabels.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+
+#include <string.h>
+
+#include "svg-cache.h"
+
+#include "debug.h"
+
+
+/*========================================================*/
+/* Private types.                                         */
+/*========================================================*/
+
+typedef struct {
+        gchar      *key;
+        guint       references;
+        RsvgHandle *svg_handle;
+        gchar      *contents;
+} CacheRecord;
+
+
+/*========================================================*/
+/* Private globals.                                       */
+/*========================================================*/
+
+
+/*========================================================*/
+/* Private function prototypes.                           */
+/*========================================================*/
+
+static void  record_destroy   (gpointer val);
+
+static void  add_name_to_list (gpointer key,
+                               gpointer val,
+                               gpointer user_data);
+
+
+/*---------------------------------------------------------------------------*/
+/* PRIVATE.  Destroy cache record.                                           */
+/*---------------------------------------------------------------------------*/
+static void
+record_destroy (gpointer val)
+{
+        CacheRecord *record = (CacheRecord *)val;
+
+        g_return_if_fail (record);
+
+        g_free (record->key);
+        g_object_unref (record->svg_handle);
+        g_free (record->contents);
+        g_free (record);
+}
+
+
+/*****************************************************************************/
+/* Create a new hash table to keep track of cached svgs.                     */
+/*****************************************************************************/
+GHashTable *
+gl_svg_cache_new (void)
+{
+        GHashTable *svg_cache;
+
+        gl_debug (DEBUG_SVG_CACHE, "START");
+
+        svg_cache = g_hash_table_new_full (g_str_hash,
+                                              g_str_equal,
+                                              NULL,
+                                              record_destroy);
+
+        gl_debug (DEBUG_SVG_CACHE, "END svg_cache=%p", svg_cache);
+
+        return svg_cache;
+}
+
+
+/*****************************************************************************/
+/* Free up previously allocated hash table and its contents.                 */
+/*****************************************************************************/
+void
+gl_svg_cache_free (GHashTable *svg_cache)
+{
+        gl_debug (DEBUG_SVG_CACHE, "START");
+
+        g_hash_table_destroy (svg_cache);
+
+        gl_debug (DEBUG_SVG_CACHE, "END");
+}
+
+
+/*****************************************************************************/
+/* Add svg to cache explicitly.                                              */
+/*****************************************************************************/
+void
+gl_svg_cache_add_svg (GHashTable  *svg_cache,
+                      gchar       *name,
+                      const gchar *contents)
+{
+        CacheRecord *test_record, *record;
+        RsvgHandle  *svg_handle;
+
+        gl_debug (DEBUG_SVG_CACHE, "START");
+
+        test_record = g_hash_table_lookup (svg_cache, name);
+        if (test_record != NULL) {
+                /* svg is already in the cache. */
+                gl_debug (DEBUG_SVG_CACHE, "END already in cache");
+                return;
+        }
+
+        record = g_new0 (CacheRecord, 1);
+        record->key        = g_strdup (name);
+        record->references = 0; /* No references yet. */
+        record->svg_handle = rsvg_handle_new_from_data (contents, strlen(contents), NULL);
+        record->contents   = g_strdup (contents);
+
+        g_hash_table_insert (svg_cache, record->key, record);
+
+        gl_debug (DEBUG_SVG_CACHE, "END");
+}
+
+
+/*****************************************************************************/
+/* Get svg handle adding a reference.  If not in cache, read it and add.     */
+/*****************************************************************************/
+RsvgHandle *
+gl_svg_cache_get_handle (GHashTable *svg_cache,
+                         gchar      *name)
+{
+        CacheRecord *record;
+        RsvgHandle  *svg_handle = NULL;
+        gchar       *buffer;
+        gsize        length;
+        GFile       *file;
+
+        gl_debug (DEBUG_SVG_CACHE, "START svg_cache=%p", svg_cache);
+
+        record = g_hash_table_lookup (svg_cache, name);
+
+        if (record != NULL)
+        {
+                record->references++;
+                gl_debug (DEBUG_SVG_CACHE, "references=%d", record->references);
+                gl_debug (DEBUG_SVG_CACHE, "END cached");
+                return record->svg_handle;
+        }
+
+
+        file = g_file_new_for_path (name);
+        if ( g_file_load_contents (file, NULL, &buffer, &length, NULL, NULL) )
+        {
+                svg_handle = rsvg_handle_new_from_data (buffer, length, NULL);
+                if ( svg_handle != NULL) {
+                        record = g_new0 (CacheRecord, 1);
+                        record->key        = g_strdup (name);
+                        record->references = 1;
+                        record->svg_handle = svg_handle;
+                        record->contents   = buffer;
+
+                        g_hash_table_insert (svg_cache, record->key, record);
+                }
+        }
+        g_object_unref (file);
+
+        gl_debug (DEBUG_SVG_CACHE, "END");
+
+        return svg_handle;
+}
+
+
+/*****************************************************************************/
+/* Get contents.   Do not add reference.                                     */
+/*****************************************************************************/
+gchar *
+gl_svg_cache_get_contents (GHashTable *svg_cache,
+                           gchar      *name)
+{
+        CacheRecord *record;
+        RsvgHandle  *svg_handle = NULL;
+        GFile       *file;
+
+        gl_debug (DEBUG_SVG_CACHE, "START svg_cache=%p", svg_cache);
+
+        record = g_hash_table_lookup (svg_cache, name);
+
+        if (record != NULL)
+        {
+                gl_debug (DEBUG_SVG_CACHE, "references=%d", record->references);
+                gl_debug (DEBUG_SVG_CACHE, "END cached");
+                return g_strdup (record->contents);
+        }
+
+        gl_debug (DEBUG_SVG_CACHE, "END");
+
+        return NULL;
+}
+
+
+/*****************************************************************************/
+/* Remove svg, but only if no references left.                               */
+/*****************************************************************************/
+void
+gl_svg_cache_remove_svg (GHashTable *svg_cache,
+                         gchar      *name)
+{
+        CacheRecord *record;
+
+        if (name == NULL) return;
+
+        gl_debug (DEBUG_SVG_CACHE, "START");
+
+        record = g_hash_table_lookup (svg_cache, name);
+        if (record == NULL) {
+                gl_debug (DEBUG_SVG_CACHE, "END not in cache");
+                return;
+        }
+
+        record->references--;
+
+        if ( record->references == 0 ) {
+                g_hash_table_remove (svg_cache, name);
+        }
+
+        gl_debug (DEBUG_SVG_CACHE, "END");
+}
+
+
+/*---------------------------------------------------------------------------*/
+/* PRIVATE.  Add a name to a GList while iterating over cache.               */
+/*---------------------------------------------------------------------------*/
+static void
+add_name_to_list (gpointer key,
+                  gpointer val,
+                  gpointer user_data)
+{
+        gchar     *name       = (gchar *)key;
+        GList     **name_list = (GList **)user_data;
+
+        gl_debug (DEBUG_SVG_CACHE, "START");
+
+        gl_debug (DEBUG_SVG_CACHE, "adding name=%s", name);
+
+        *name_list = g_list_append (*name_list, g_strdup(name));
+
+        gl_debug (DEBUG_SVG_CACHE, "END");
+}
+
+
+/*****************************************************************************/
+/* Return a list of names for all svgs in the cache.                         */
+/*****************************************************************************/
+GList *
+gl_svg_cache_get_name_list (GHashTable *svg_cache)
+{
+        GList *name_list = NULL;
+
+        gl_debug (DEBUG_SVG_CACHE, "START");
+
+        g_hash_table_foreach (svg_cache, add_name_to_list, &name_list);
+
+        gl_debug (DEBUG_SVG_CACHE, "END");
+
+        return name_list;
+}
+
+
+/*****************************************************************************/
+/* Free up a list of svg names.                                              */
+/*****************************************************************************/
+void
+gl_svg_cache_free_name_list (GList *name_list)
+{
+        GList *p_name;
+
+        gl_debug (DEBUG_SVG_CACHE, "START");
+
+        for (p_name = name_list; p_name != NULL; p_name = p_name->next) {
+                g_free (p_name->data);
+                p_name->data = NULL;
+        }
+
+        g_list_free (name_list);
+
+        gl_debug (DEBUG_SVG_CACHE, "END");
+}
+
+
+
+
+/*
+ * Local Variables:       -- emacs
+ * mode: C                -- emacs
+ * c-basic-offset: 8      -- emacs
+ * tab-width: 8           -- emacs
+ * indent-tabs-mode: nil  -- emacs
+ * End:                   -- emacs
+ */
diff --git a/src/svg-cache.h b/src/svg-cache.h
new file mode 100644
index 0000000..b2f406f
--- /dev/null
+++ b/src/svg-cache.h
@@ -0,0 +1,64 @@
+/*
+ *  svg-cache.h
+ *  Copyright (C) 2010  Jim Evins <evins snaught com>.
+ *
+ *  This file is part of gLabels.
+ *
+ *  gLabels is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  gLabels is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with gLabels.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __SVG_CACHE_H__
+#define __SVG_CACHE_H__
+
+#include <glib.h>
+#include <librsvg/rsvg.h>
+
+G_BEGIN_DECLS
+
+GHashTable *gl_svg_cache_new            (void);
+
+void        gl_svg_cache_free           (GHashTable  *svg_cache);
+
+void        gl_svg_cache_add_svg        (GHashTable  *svg_cache,
+                                         gchar       *name,
+                                         const gchar *contents);
+
+RsvgHandle *gl_svg_cache_get_handle     (GHashTable  *svg_cache,
+                                         gchar       *name);
+
+gchar      *gl_svg_cache_get_contents   (GHashTable  *svg_cache,
+                                         gchar       *name);
+
+void        gl_svg_cache_remove_svg     (GHashTable  *svg_cache,
+                                         gchar       *name);
+
+GList      *gl_svg_cache_get_name_list  (GHashTable  *svg_cache);
+
+void        gl_svg_cache_free_name_list (GList       *name_list);
+
+G_END_DECLS
+
+#endif /*__SVG_CACHE_H__ */
+
+
+
+
+/*
+ * Local Variables:       -- emacs
+ * mode: C                -- emacs
+ * c-basic-offset: 8      -- emacs
+ * tab-width: 8           -- emacs
+ * indent-tabs-mode: nil  -- emacs
+ * End:                   -- emacs
+ */
diff --git a/src/xml-label.c b/src/xml-label.c
index 001e33a..09930a4 100644
--- a/src/xml-label.c
+++ b/src/xml-label.c
@@ -104,6 +104,9 @@ static void           xml_parse_data           (xmlNodePtr        node,
 static void           xml_parse_pixdata        (xmlNodePtr        node,
 						glLabel          *label);
 
+static void           xml_parse_file_node      (xmlNodePtr        node,
+						glLabel          *label);
+
 static void           xml_parse_toplevel_span  (xmlNodePtr        node,
 						glLabelObject    *object);
 
@@ -116,43 +119,50 @@ static void           xml_parse_shadow_attrs   (xmlNodePtr        node,
 static xmlDocPtr      xml_label_to_doc         (glLabel          *label,
 						glXMLLabelStatus *status);
 
-static void           xml_create_objects       (xmlNodePtr        root,
+static void           xml_create_objects       (xmlNodePtr        parent,
 						xmlNsPtr          ns,
 						glLabel          *label);
 
-static void           xml_create_object_text   (xmlNodePtr        root,
+static void           xml_create_object_text   (xmlNodePtr        parent,
 						xmlNsPtr          ns,
 						glLabelObject    *object);
 
-static void           xml_create_object_box    (xmlNodePtr        root,
+static void           xml_create_object_box    (xmlNodePtr        parent,
 						xmlNsPtr          ns,
 						glLabelObject    *object);
 
-static void           xml_create_object_line   (xmlNodePtr        root,
+static void           xml_create_object_line   (xmlNodePtr        parent,
 						xmlNsPtr          ns,
 						glLabelObject    *object);
 
-static void           xml_create_object_ellipse(xmlNodePtr        root,
+static void           xml_create_object_ellipse(xmlNodePtr        parent,
 						xmlNsPtr          ns,
 						glLabelObject    *object);
 
-static void           xml_create_object_image  (xmlNodePtr        root,
+static void           xml_create_object_image  (xmlNodePtr        parent,
 						xmlNsPtr          ns,
 						glLabelObject    *object);
 
-static void           xml_create_object_barcode(xmlNodePtr        root,
+static void           xml_create_object_barcode(xmlNodePtr        parent,
 						xmlNsPtr          ns,
 						glLabelObject    *object);
 
-static void           xml_create_merge_fields  (xmlNodePtr        root,
+static void           xml_create_merge_fields  (xmlNodePtr        parent,
 						xmlNsPtr          ns,
 						glLabel          *label);
 
-static void           xml_create_data          (xmlNodePtr        root,
+static void           xml_create_data          (xmlDocPtr         doc,
+                                                xmlNodePtr        parent,
 						xmlNsPtr          ns,
 						glLabel          *label);
 
-static void           xml_create_pixdata       (xmlNodePtr        root,
+static void           xml_create_pixdata       (xmlNodePtr        parent,
+						xmlNsPtr          ns,
+						glLabel          *label,
+						gchar            *name);
+
+static void           xml_create_file_svg      (xmlDocPtr         doc,
+                                                xmlNodePtr        parent,
 						xmlNsPtr          ns,
 						glLabel          *label,
 						gchar            *name);
@@ -851,6 +861,8 @@ xml_parse_data (xmlNodePtr  node,
 
 		if (lgl_xml_is_node (child, "Pixdata")) {
 			xml_parse_pixdata (child, label);
+		} else if (lgl_xml_is_node (child, "File")) {
+			xml_parse_file_node (child, label);
 		} else {
 			if (!xmlNodeIsText (child)) {
 				g_message (_("bad node in Data node =  \"%s\""),
@@ -864,7 +876,7 @@ xml_parse_data (xmlNodePtr  node,
 
 
 /*--------------------------------------------------------------------------*/
-/* PRIVATE.  Parse XML pixbuf data tag.                                     */
+/* PRIVATE.  Parse XML embedded Pixdata node.                               */
 /*--------------------------------------------------------------------------*/
 static void
 xml_parse_pixdata (xmlNodePtr  node,
@@ -905,6 +917,40 @@ xml_parse_pixdata (xmlNodePtr  node,
 
 
 /*--------------------------------------------------------------------------*/
+/* PRIVATE.  Parse XML embedded File node.                                  */
+/*--------------------------------------------------------------------------*/
+static void
+xml_parse_file_node (xmlNodePtr  node,
+                     glLabel    *label)
+{
+	gchar      *name, *format;
+        gchar      *content;
+	GHashTable *svg_cache;
+
+	name    = lgl_xml_get_prop_string (node, "name", NULL);
+	format  = lgl_xml_get_prop_string (node, "format", NULL);
+
+        if ( format && (lgl_str_utf8_casecmp (format, "SVG") == 0) )
+        {
+                content = lgl_xml_get_node_content (node);
+
+		svg_cache = gl_label_get_svg_cache (label);
+                gl_svg_cache_add_svg (svg_cache, name, content);
+
+                g_free (content);
+        }
+        else
+        {
+                g_message (_("Unknown embedded file format: \"%s\""), format);
+                
+        }
+
+        g_free (name);
+        g_free (format);
+}
+
+
+/*--------------------------------------------------------------------------*/
 /* PRIVATE.  Parse top-level Span tag.                                      */
 /*--------------------------------------------------------------------------*/
 static void
@@ -1181,7 +1227,7 @@ xml_label_to_doc (glLabel          *label,
 		g_object_unref (G_OBJECT(merge));
 	}
 
-	xml_create_data (doc->xmlRootNode, ns, label);
+	xml_create_data (doc, doc->xmlRootNode, ns, label);
 
 	gl_debug (DEBUG_XML, "END");
 
@@ -1194,7 +1240,7 @@ xml_label_to_doc (glLabel          *label,
 /* PRIVATE.  Add XML Objects Node                                           */
 /*--------------------------------------------------------------------------*/
 static void
-xml_create_objects (xmlNodePtr  root,
+xml_create_objects (xmlNodePtr  parent,
 		    xmlNsPtr    ns,
 		    glLabel    *label)
 {
@@ -1209,7 +1255,7 @@ xml_create_objects (xmlNodePtr  root,
         rotate_flag = gl_label_get_rotate_flag (label);
         object_list = gl_label_get_object_list (label);
 
-	node = xmlNewChild (root, ns, (xmlChar *)"Objects", NULL);
+	node = xmlNewChild (parent, ns, (xmlChar *)"Objects", NULL);
 	lgl_xml_set_prop_string (node, "id", "0");
 	lgl_xml_set_prop_boolean (node, "rotate", rotate_flag);
 
@@ -1243,7 +1289,7 @@ xml_create_objects (xmlNodePtr  root,
 /* PRIVATE.  Add XML Objects->Object-text Node                              */
 /*--------------------------------------------------------------------------*/
 static void
-xml_create_object_text (xmlNodePtr     root,
+xml_create_object_text (xmlNodePtr     parent,
 			xmlNsPtr       ns,
 			glLabelObject *object)
 {
@@ -1255,7 +1301,7 @@ xml_create_object_text (xmlNodePtr     root,
 
 	gl_debug (DEBUG_XML, "START");
 
-	node = xmlNewChild (root, ns, (xmlChar *)"Object-text", NULL);
+	node = xmlNewChild (parent, ns, (xmlChar *)"Object-text", NULL);
 
 	/* position attrs */
 	gl_label_object_get_position (object, &x, &y);
@@ -1292,7 +1338,7 @@ xml_create_object_text (xmlNodePtr     root,
 /* PRIVATE.  Add XML Objects->Object-box Node                               */
 /*--------------------------------------------------------------------------*/
 static void
-xml_create_object_box (xmlNodePtr     root,
+xml_create_object_box (xmlNodePtr     parent,
 		       xmlNsPtr       ns,
 		       glLabelObject *object)
 {
@@ -1305,7 +1351,7 @@ xml_create_object_box (xmlNodePtr     root,
 
 	gl_debug (DEBUG_XML, "START");
 
-	node = xmlNewChild (root, ns, (xmlChar *)"Object-box", NULL);
+	node = xmlNewChild (parent, ns, (xmlChar *)"Object-box", NULL);
 
 	/* position attrs */
 	gl_label_object_get_position (object, &x, &y);
@@ -1358,7 +1404,7 @@ xml_create_object_box (xmlNodePtr     root,
 /* PRIVATE.  Add XML Objects->Object-ellipse Node                           */
 /*--------------------------------------------------------------------------*/
 static void
-xml_create_object_ellipse (xmlNodePtr     root,
+xml_create_object_ellipse (xmlNodePtr     parent,
 			   xmlNsPtr       ns,
 			   glLabelObject *object)
 {
@@ -1371,7 +1417,7 @@ xml_create_object_ellipse (xmlNodePtr     root,
 
 	gl_debug (DEBUG_XML, "START");
 
-	node = xmlNewChild (root, ns, (xmlChar *)"Object-ellipse", NULL);
+	node = xmlNewChild (parent, ns, (xmlChar *)"Object-ellipse", NULL);
 
 	/* position attrs */
 	gl_label_object_get_position (object, &x, &y);
@@ -1425,7 +1471,7 @@ xml_create_object_ellipse (xmlNodePtr     root,
 /* PRIVATE.  Add XML Objects->Object-line Node                              */
 /*--------------------------------------------------------------------------*/
 static void
-xml_create_object_line (xmlNodePtr     root,
+xml_create_object_line (xmlNodePtr     parent,
 			xmlNsPtr       ns,
 			glLabelObject *object)
 {
@@ -1437,7 +1483,7 @@ xml_create_object_line (xmlNodePtr     root,
 
 	gl_debug (DEBUG_XML, "START");
 
-	node = xmlNewChild (root, ns, (xmlChar *)"Object-line", NULL);
+	node = xmlNewChild (parent, ns, (xmlChar *)"Object-line", NULL);
 
 	/* position attrs */
 	gl_label_object_get_position (object, &x, &y);
@@ -1479,7 +1525,7 @@ xml_create_object_line (xmlNodePtr     root,
 /* PRIVATE.  Add XML Objects->Object-image Node                             */
 /*--------------------------------------------------------------------------*/
 static void
-xml_create_object_image (xmlNodePtr     root,
+xml_create_object_image (xmlNodePtr     parent,
 			 xmlNsPtr       ns,
 			 glLabelObject *object)
 {
@@ -1490,7 +1536,7 @@ xml_create_object_image (xmlNodePtr     root,
 
 	gl_debug (DEBUG_XML, "START");
 
-	node = xmlNewChild (root, ns, (xmlChar *)"Object-image", NULL);
+	node = xmlNewChild (parent, ns, (xmlChar *)"Object-image", NULL);
 
 	/* position attrs */
 	gl_label_object_get_position (object, &x, &y);
@@ -1525,7 +1571,7 @@ xml_create_object_image (xmlNodePtr     root,
 /* PRIVATE.  Add XML Objects->Object-barcode Node                           */
 /*--------------------------------------------------------------------------*/
 static void
-xml_create_object_barcode (xmlNodePtr     root,
+xml_create_object_barcode (xmlNodePtr     parent,
 			   xmlNsPtr       ns,
 			   glLabelObject *object)
 {
@@ -1541,7 +1587,7 @@ xml_create_object_barcode (xmlNodePtr     root,
 
 	gl_debug (DEBUG_XML, "START");
 
-	node = xmlNewChild (root, ns, (xmlChar *)"Object-barcode", NULL);
+	node = xmlNewChild (parent, ns, (xmlChar *)"Object-barcode", NULL);
 
 	/* position attrs */
 	gl_label_object_get_position (object, &x, &y);
@@ -1598,7 +1644,7 @@ xml_create_object_barcode (xmlNodePtr     root,
 /* PRIVATE.  Add XML Label Merge Fields Node                                */
 /*--------------------------------------------------------------------------*/
 static void
-xml_create_merge_fields (xmlNodePtr  root,
+xml_create_merge_fields (xmlNodePtr  parent,
 			 xmlNsPtr    ns,
 			 glLabel    *label)
 {
@@ -1610,7 +1656,7 @@ xml_create_merge_fields (xmlNodePtr  root,
 
 	merge = gl_label_get_merge (label);
 
-	node = xmlNewChild (root, ns, (xmlChar *)"Merge", NULL);
+	node = xmlNewChild (parent, ns, (xmlChar *)"Merge", NULL);
 
 	string = gl_merge_get_name (merge);
 	lgl_xml_set_prop_string (node, "type", string);
@@ -1630,20 +1676,21 @@ xml_create_merge_fields (xmlNodePtr  root,
 /* PRIVATE.  Add XML Label Data Node                                        */
 /*--------------------------------------------------------------------------*/
 static void
-xml_create_data (xmlNodePtr  root,
+xml_create_data (xmlDocPtr   doc,
+                 xmlNodePtr  parent,
 		 xmlNsPtr    ns,
 		 glLabel    *label)
 {
 	xmlNodePtr  node;
+	GHashTable *cache;
 	GList      *name_list, *p;
-	GHashTable *pixbuf_cache;
 
 	gl_debug (DEBUG_XML, "START");
 
-	node = xmlNewChild (root, ns, (xmlChar *)"Data", NULL);
+	node = xmlNewChild (parent, ns, (xmlChar *)"Data", NULL);
 
-	pixbuf_cache = gl_label_get_pixbuf_cache (label);
-	name_list = gl_pixbuf_cache_get_name_list (pixbuf_cache);
+	cache = gl_label_get_pixbuf_cache (label);
+	name_list = gl_pixbuf_cache_get_name_list (cache);
 
 	for (p = name_list; p != NULL; p=p->next) {
 		xml_create_pixdata (node, ns, label, p->data);
@@ -1652,15 +1699,25 @@ xml_create_data (xmlNodePtr  root,
 	gl_pixbuf_cache_free_name_list (name_list);
 
 
+	cache = gl_label_get_svg_cache (label);
+	name_list = gl_svg_cache_get_name_list (cache);
+
+	for (p = name_list; p != NULL; p=p->next) {
+		xml_create_file_svg (doc, node, ns, label, p->data);
+	}
+
+	gl_pixbuf_cache_free_name_list (name_list);
+
+
 	gl_debug (DEBUG_XML, "END");
 }
 
 
 /*--------------------------------------------------------------------------*/
-/* PRIVATE.  Add XML Label Data Pixbuf Node                                 */
+/* PRIVATE.  Add XML Label Data embedded Pixdata Node                       */
 /*--------------------------------------------------------------------------*/
 static void
-xml_create_pixdata (xmlNodePtr  root,
+xml_create_pixdata (xmlNodePtr  parent,
 		    xmlNsPtr    ns,
 		    glLabel    *label,
 		    gchar      *name)
@@ -1685,7 +1742,7 @@ xml_create_pixdata (xmlNodePtr  root,
 		stream = gdk_pixdata_serialize (pixdata, &stream_length);
 		base64 = g_base64_encode (stream, stream_length);
 
-		node = xmlNewChild (root, ns, (xmlChar *)"Pixdata", (xmlChar *)base64);
+		node = xmlNewChild (parent, ns, (xmlChar *)"Pixdata", (xmlChar *)base64);
 		lgl_xml_set_prop_string (node, "name", name);
 		lgl_xml_set_prop_string (node, "encoding", "Base64");
 
@@ -1702,10 +1759,47 @@ xml_create_pixdata (xmlNodePtr  root,
 
 
 /*--------------------------------------------------------------------------*/
+/* PRIVATE.  Add XML Label Data embedded SVG file Node                      */
+/*--------------------------------------------------------------------------*/
+static void
+xml_create_file_svg (xmlDocPtr   doc,
+                     xmlNodePtr  parent,
+                     xmlNsPtr    ns,
+                     glLabel    *label,
+                     gchar      *name)
+{
+	xmlNodePtr  node;
+	xmlNodePtr  cdata_section_node;
+	GHashTable *svg_cache;
+        gchar      *svg_data;
+
+	gl_debug (DEBUG_XML, "START");
+
+	svg_cache = gl_label_get_svg_cache (label);
+
+	svg_data = gl_svg_cache_get_contents (svg_cache, name);
+	if ( svg_data != NULL ) {
+
+		node = xmlNewChild (parent, ns, (xmlChar *)"File", NULL);
+		lgl_xml_set_prop_string (node, "name", name);
+		lgl_xml_set_prop_string (node, "format", "SVG");
+
+                cdata_section_node = xmlNewCDataBlock (doc, (xmlChar *)svg_data, strlen (svg_data));
+                xmlAddChild (node, cdata_section_node);
+
+		g_free (svg_data);
+	}
+
+
+	gl_debug (DEBUG_XML, "END");
+}
+
+
+/*--------------------------------------------------------------------------*/
 /* PRIVATE.  Create top-level Span node.                                    */
 /*--------------------------------------------------------------------------*/
 static void
-xml_create_toplevel_span (xmlNodePtr        root,
+xml_create_toplevel_span (xmlNodePtr        parent,
 			  xmlNsPtr          ns,
 			  glLabelText      *object_text)
 {
@@ -1721,7 +1815,7 @@ xml_create_toplevel_span (xmlNodePtr        root,
 	glTextNode       *text_node;
 	xmlNodePtr        child;
 
-	node = xmlNewChild (root, ns, (xmlChar *)"Span", NULL);
+	node = xmlNewChild (parent, ns, (xmlChar *)"Span", NULL);
 
 	/* All span attrs at top level. */
 	font_family = gl_label_object_get_font_family (GL_LABEL_OBJECT(object_text));
diff --git a/templates/glabels-2.3.dtd b/templates/glabels-2.3.dtd
index 3168914..1e276c3 100644
--- a/templates/glabels-2.3.dtd
+++ b/templates/glabels-2.3.dtd
@@ -81,6 +81,9 @@
 <!-- Data encoding method -->
 <!ENTITY % DATA_ENCODING_TYPE "(None | Base64)">
 
+<!-- Inline file format type -->
+<!ENTITY % FILE_FORMAT_TYPE "(SVG)">
+
 <!-- :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: -->
 <!-- :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: -->
 <!-- Top-level glabels paper data base                                    -->
@@ -415,7 +418,7 @@
 <!-- :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: -->
 <!-- Data Section                                                         -->
 <!-- :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: -->
-<!ENTITY % data_element "Pixdata">
+<!ENTITY % data_element "Pixdata | File">
 
 <!ELEMENT Data (%data_element;)*>
 
@@ -426,6 +429,13 @@
                  encoding        %DATA_ENCODING_TYPE;    "Base64"
 >
 
+<!-- Inline File -->
+<!ELEMENT File (#PCDATA)>
+<!ATTLIST File
+                 name            %STRING_TYPE;           #REQUIRED
+                 format          %FILE_FORMAT_TYPE;      "SVG"
+>
+
 
 <!-- :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: -->
 <!-- Text elements                                                        -->



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]