From: Jim Evins Date: Sat, 3 Jul 2010 03:12:32 +0000 (-0400) Subject: Add native support for SVG images. X-Git-Tag: glabels-2_3_1~228 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=3e365e5f9187a12fbf0e29d4d3804cab0261e8e9;p=glabels 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. --- diff --git a/configure.ac b/configure.ac index 4942de82..d3ee342c 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 9dd1ad9f..c19d0095 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 72f8e05b..4ebd3a1c 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 23432d9e..d29d6246 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 59a862b8..25825a81 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 ace188bd..66d8ebf0 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 50c447c1..f4e94f38 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 7b7181ea..46fc49f6 100644 --- a/src/label-image.c +++ b/src/label-image.c @@ -25,6 +25,8 @@ #include #include #include +#include +#include #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 218a2e75..98abc463 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 84fc098e..37e0c6cf 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 aa183369..eccd6088 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 d544c55f..86403712 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 00000000..f1161bd5 --- /dev/null +++ b/src/svg-cache.c @@ -0,0 +1,316 @@ +/* + * svg-cache.c + * Copyright (C) 2003-2009 Jim Evins . + * + * 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 . + */ + +#include + +#include + +#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 00000000..b2f406f6 --- /dev/null +++ b/src/svg-cache.h @@ -0,0 +1,64 @@ +/* + * svg-cache.h + * Copyright (C) 2010 Jim Evins . + * + * 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 . + */ + +#ifndef __SVG_CACHE_H__ +#define __SVG_CACHE_H__ + +#include +#include + +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 001e33ae..09930a4e 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, @@ -904,6 +916,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. */ /*--------------------------------------------------------------------------*/ @@ -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"); @@ -1701,11 +1758,48 @@ 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 31689143..1e276c36 100644 --- a/templates/glabels-2.3.dtd +++ b/templates/glabels-2.3.dtd @@ -81,6 +81,9 @@ + + + @@ -415,7 +418,7 @@ - + @@ -426,6 +429,13 @@ encoding %DATA_ENCODING_TYPE; "Base64" > + + + +