]> git.sur5r.net Git - glabels/commitdiff
Added pixbuf cache and base64 modules.
authorJim Evins <evins@snaught.com>
Mon, 6 Jan 2003 05:53:19 +0000 (05:53 +0000)
committerJim Evins <evins@snaught.com>
Mon, 6 Jan 2003 05:53:19 +0000 (05:53 +0000)
Pixbufs are now saved in a glabels file as a base64 encoded version of the serialized pixdata.
Files are now compressed.

git-svn-id: https://glabels.svn.sourceforge.net/svnroot/glabels/trunk@237 f5e0f49d-192f-0410-a22d-a8d8700d0965

13 files changed:
glabels2/src/Makefile.am
glabels2/src/base64.c [new file with mode: 0644]
glabels2/src/base64.h [new file with mode: 0644]
glabels2/src/debug.c
glabels2/src/debug.h
glabels2/src/glabels.c
glabels2/src/label-image.c
glabels2/src/label.c
glabels2/src/label.h
glabels2/src/pixbuf-cache.c [new file with mode: 0644]
glabels2/src/pixbuf-cache.h [new file with mode: 0644]
glabels2/src/view.c
glabels2/src/xml-label.c

index 513761fb5cfcded61cf079267122da9d1f716b7f..4f06b4ded729d39bada8e0cfcc6cb5128f758247 100644 (file)
@@ -118,6 +118,10 @@ glabels_SOURCES =                  \
        xml-label.h                     \
        xml-label-04.c                  \
        xml-label-04.h                  \
+       pixbuf-cache.c                  \
+       pixbuf-cache.h                  \
+       base64.c                        \
+       base64.h                        \
        merge.c                         \
        merge.h                         \
        merge-init.c                    \
@@ -208,6 +212,10 @@ glabels_batch_SOURCES =            \
        xml-label.h                     \
        xml-label-04.c                  \
        xml-label-04.h                  \
+       pixbuf-cache.c                  \
+       pixbuf-cache.h                  \
+       base64.c                        \
+       base64.h                        \
        merge.c                         \
        merge.h                         \
        merge-init.c                    \
diff --git a/glabels2/src/base64.c b/glabels2/src/base64.c
new file mode 100644 (file)
index 0000000..957b46a
--- /dev/null
@@ -0,0 +1,201 @@
+/*
+ *  (GLABELS) Label and Business Card Creation program for GNOME
+ *
+ *  base64.c:  GLabels base64 encode/decode module
+ *
+ *  Copyright (C)  2003  Jim Evins <evins@snaught.com>
+ *
+ *  This module is based on base64.c from fetchmail:
+ *
+ *  Copyright (C)2002 by Eric S. Raymond.
+ *  Portions are copyrighted by Carl E. Harris and George M. Sipe.
+ *
+ *  This program 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 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program 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 this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+/*
+ * This base 64 encoding is defined in RFC2045 section 6.8.
+ */
+#include <config.h>
+
+#include <glib.h>
+#include <string.h>
+
+#include "base64.h"
+
+/*========================================================*/
+/* Private macros and constants.                          */
+/*========================================================*/
+
+#define LINE_LENGTH 76 /* Must be <= 76 and must be a multiple of 4 */
+#define BAD    -1
+
+#define DECODE64(c)  (isascii(c) ? base64val[c] : BAD)
+
+/*========================================================*/
+/* Private types.                                         */
+/*========================================================*/
+
+/*========================================================*/
+/* Private globals.                                       */
+/*========================================================*/
+
+static const gchar base64digits[] =
+   "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+static const gchar base64val[] = {
+    BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD,
+    BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD,
+    BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD, 62, BAD,BAD,BAD, 63,
+     52, 53, 54, 55,  56, 57, 58, 59,  60, 61,BAD,BAD, BAD,BAD,BAD,BAD,
+    BAD,  0,  1,  2,   3,  4,  5,  6,   7,  8,  9, 10,  11, 12, 13, 14,
+     15, 16, 17, 18,  19, 20, 21, 22,  23, 24, 25,BAD, BAD,BAD,BAD,BAD,
+    BAD, 26, 27, 28,  29, 30, 31, 32,  33, 34, 35, 36,  37, 38, 39, 40,
+     41, 42, 43, 44,  45, 46, 47, 48,  49, 50, 51,BAD, BAD,BAD,BAD,BAD
+};
+
+/*========================================================*/
+/* Private function prototypes.                           */
+/*========================================================*/
+
+\f
+/*****************************************************************************/
+/* Encode to Base64 string.                                                  */
+/*****************************************************************************/
+gchar *
+gl_base64_encode (const guchar *in, guint inlen)
+{
+       gchar *out, *p_out;
+       gint   buf_size;
+       gint   i;
+
+        /* Calculate output buffer size */
+       buf_size  = 4*((inlen+2)/3);            /* Encoded characters */
+       buf_size += buf_size / LINE_LENGTH + 2; /* Line breaks */
+       buf_size += 1;                          /* null termination */
+       
+       /* Allocate output buffer */
+       out = g_new0 (gchar, buf_size);
+       p_out=out;
+
+       /* Now do the encoding */
+       *p_out++ = '\n';
+       for ( i=0; inlen >= 3; inlen-=3 ) {
+
+               *p_out++ = base64digits[in[0] >> 2];
+               *p_out++ = base64digits[((in[0] << 4) & 0x30) | (in[1] >> 4)];
+               *p_out++ = base64digits[((in[1] << 2) & 0x3c) | (in[2] >> 6)];
+               *p_out++ = base64digits[in[2] & 0x3f];
+               in += 3;
+
+               i += 4;
+               if ( (i % LINE_LENGTH) == 0 ) {
+                       *p_out++ = '\n';
+               }
+
+       }
+       if (inlen > 0) {
+               guchar fragment;
+    
+               *p_out++ = base64digits[in[0] >> 2];
+               fragment = (in[0] << 4) & 0x30;
+               if (inlen > 1)
+                       fragment |= in[1] >> 4;
+               *p_out++ = base64digits[fragment];
+               *p_out++ = (inlen < 2) ? '=' : base64digits[(in[1] << 2) & 0x3c];
+               *p_out++ = '=';
+
+               *p_out++ = '\n';
+       }
+       *p_out++ = '\0';
+
+       return out;
+}
+
+/*****************************************************************************/
+/* Decode from a Base64 string.                                              */
+/*****************************************************************************/
+guchar *
+gl_base64_decode (const gchar *in, guint *outlen)
+{
+       gchar           *out, *p_out;
+       gint             buf_size;
+       register guchar  digit1, digit2, digit3, digit4;
+
+        /* Calculate output buffer size */
+       buf_size = strlen (in) * 3 / 4;
+
+       /* Allocate output buffer */
+       out = g_new0 (gchar, buf_size);
+
+       *outlen = 0;
+       p_out = out;
+
+       /* Skip non-printable characters */
+       while ( (*in == '\n') || (*in == '\r') || (*in == ' ') ) {
+               in ++;
+       }
+       if (!*in) {
+               g_free (out);
+               return NULL;
+       }
+
+       /* Now do the decoding */
+       do {
+               digit1 = in[0];
+               if (DECODE64(digit1) == BAD) {
+                       g_free (out);
+                       return NULL;
+               }
+               digit2 = in[1];
+               if (DECODE64(digit2) == BAD) {
+                       g_free (out);
+                       return NULL;
+               }
+               digit3 = in[2];
+               if (digit3 != '=' && DECODE64(digit3) == BAD) {
+                       g_free (out);
+                       return NULL;
+               }
+               digit4 = in[3];
+               if (digit4 != '=' && DECODE64(digit4) == BAD) {
+                       g_free (out);
+                       return NULL;
+               }
+               in += 4;
+
+               *p_out++ = (DECODE64(digit1)<<2) | (DECODE64(digit2) >> 4);
+               (*outlen)++;
+               if (digit3 != '=')
+               {
+                       *p_out++ = ((DECODE64(digit2)<<4)&0xf0) | (DECODE64(digit3)>>2);
+                       (*outlen)++;
+                       if (digit4 != '=')
+                       {
+                               *p_out++ = ((DECODE64(digit3)<<6)&0xc0) | DECODE64(digit4);
+                               (*outlen)++;
+                       }
+               }
+
+               /* Skip non-printable characters */
+               while ( (*in == '\n') || (*in == '\r') || (*in == ' ') ) {
+                       in ++;
+               }
+
+       } while (*in && digit4 != '=');
+
+       return out;
+}
+
diff --git a/glabels2/src/base64.h b/glabels2/src/base64.h
new file mode 100644 (file)
index 0000000..a686949
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ *  (GLABELS) Label and Business Card Creation program for GNOME
+ *
+ *  base64.h:  GLabels base64 encode/decode module
+ *
+ *  Copyright (C)  2003  Jim Evins <evins@snaught.com>
+ *
+ *  This module is based on base64.c from fetchmail:
+ *
+ *  Copyright (C)2002 by Eric S. Raymond.
+ *  Portions are copyrighted by Carl E. Harris and George M. Sipe.
+ *
+ *  This program 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 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program 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 this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+#ifndef __BASE64_H__
+#define __BASE64_H__
+
+G_BEGIN_DECLS
+
+gchar  *gl_base64_encode (const guchar *in,
+                         guint         inlen);
+
+guchar *gl_base64_decode (const gchar  *in,
+                         guint        *outlen);
+
+G_END_DECLS
+
+#endif
+
index ddf0677b5c357a973136fba965f57ee362b2831f..20bf930927ed88bb98a3825d996a98af421edc1b 100644 (file)
@@ -49,6 +49,7 @@ gint gl_debug_window = 0;
 gint gl_debug_ui = 0;
 gint gl_debug_media_select = 0;
 gint gl_debug_mini_preview = 0;
+gint gl_debug_pixbuf_cache = 0;
 gint gl_debug_wdgt = 0;
 
 /****************************************************************************/
@@ -88,6 +89,7 @@ gl_debug (gint   section,
            (gl_debug_ui           && section == GL_DEBUG_UI)             ||
            (gl_debug_media_select && section == GL_DEBUG_MEDIA_SELECT)   ||
            (gl_debug_mini_preview && section == GL_DEBUG_MINI_PREVIEW)   ||
+           (gl_debug_pixbuf_cache && section == GL_DEBUG_PIXBUF_CACHE)   ||
            (gl_debug_wdgt         && section == GL_DEBUG_WDGT) )
                g_print ("%s:%d (%s) %s\n", file, line, function, msg);
        
index 485b54bfc08c2c863ab937739dae20498395ce4a..e2ac135898718efe9566a37f30c08480d831e9a4 100644 (file)
@@ -49,6 +49,7 @@ typedef enum {
        GL_DEBUG_UI,
        GL_DEBUG_MEDIA_SELECT,
        GL_DEBUG_MINI_PREVIEW,
+       GL_DEBUG_PIXBUF_CACHE,
        GL_DEBUG_WDGT,
 } glDebugSection;
 
@@ -69,6 +70,7 @@ extern gint gl_debug_window;
 extern gint gl_debug_ui;
 extern gint gl_debug_media_select;
 extern gint gl_debug_mini_preview;
+extern gint gl_debug_pixbuf_cache;
 extern gint gl_debug_wdgt;
 
 #ifndef __GNUC__
@@ -91,6 +93,7 @@ extern gint gl_debug_wdgt;
 #define        DEBUG_UI        GL_DEBUG_UI,      __FILE__, __LINE__, __FUNCTION__
 #define        DEBUG_MEDIA_SELECT      GL_DEBUG_MEDIA_SELECT,     __FILE__, __LINE__, __FUNCTION__
 #define        DEBUG_MINI_PREVIEW      GL_DEBUG_MINI_PREVIEW,     __FILE__, __LINE__, __FUNCTION__
+#define        DEBUG_PIXBUF_CACHE      GL_DEBUG_PIXBUF_CACHE,     __FILE__, __LINE__, __FUNCTION__
 #define        DEBUG_WDGT      GL_DEBUG_WDGT,    __FILE__, __LINE__, __FUNCTION__
 
 void gl_debug (gint section, gchar *file,
index d64a80532cabe885f15369ba045df1a30eec14e8..150a3f8e03dbbb17ec3c40d729f989f99e5a2bc8 100644 (file)
@@ -95,6 +95,9 @@ static const struct poptOption options [] =
        { "debug-mini-preview", '\0', POPT_ARG_NONE, &gl_debug_mini_preview, 0,
          N_("Show mini preview widget debugging messages."), NULL },
 
+       { "debug-pixbuf-cache", '\0', POPT_ARG_NONE, &gl_debug_pixbuf_cache, 0,
+         N_("Show pixbuf cache debugging messages."), NULL },
+
        { "debug-wdgt", '\0', POPT_ARG_NONE, &gl_debug_wdgt, 0,
          N_("Show widget debugging messages."), NULL },
 
index 8c43f82ac145513f861a6e04a268af6e4cceaf79..1ab49aa47747ea47ac2c55249e1452374d13bc42 100644 (file)
@@ -45,6 +45,8 @@ static GObjectClass *parent_class = NULL;
 
 static guint instance = 0;
 
+static GdkPixbuf *default_pixbuf = NULL;
+
 /*========================================================*/
 /* Private function prototypes.                           */
 /*========================================================*/
@@ -101,25 +103,36 @@ gl_label_image_class_init (glLabelImageClass *klass)
 static void
 gl_label_image_instance_init (glLabelImage *limage)
 {
+       if ( default_pixbuf == NULL ) {
+               default_pixbuf =
+                       gdk_pixbuf_new_from_xpm_data ((const char **)checkerboard_xpm);
+       }
+
        limage->private = g_new0 (glLabelImagePrivate, 1);
 
        limage->private->filename = g_new0 (glTextNode, 1);
 
-       limage->private->pixbuf =
-               gdk_pixbuf_new_from_xpm_data ((const char **)checkerboard_xpm);
+       limage->private->pixbuf = default_pixbuf;
 }
 
 static void
 gl_label_image_finalize (GObject *object)
 {
-       glLabelImage *limage;
+       glLabelObject *lobject;
+       glLabelImage  *limage;
+       GHashTable    *pixbuf_cache;
 
        g_return_if_fail (object && GL_IS_LABEL_IMAGE (object));
 
-       limage = GL_LABEL_IMAGE (object);
+       lobject = GL_LABEL_OBJECT (object);
+       limage  = GL_LABEL_IMAGE (object);
 
+       if (!limage->private->filename->field_flag) {
+               pixbuf_cache = gl_label_get_pixbuf_cache (lobject->parent);
+               gl_pixbuf_cache_remove_pixbuf (pixbuf_cache,
+                                              limage->private->filename->data);
+       }
        gl_text_node_free (&limage->private->filename);
-       g_object_unref (G_OBJECT(limage->private->pixbuf));
        g_free (limage->private);
 
        G_OBJECT_CLASS (parent_class)->finalize (object);
@@ -147,9 +160,11 @@ static void
 copy (glLabelObject *dst_object,
       glLabelObject *src_object)
 {
-       glLabelImage *limage     = (glLabelImage *)src_object;
-       glLabelImage *new_limage = (glLabelImage *)dst_object;
-       glTextNode   *filename;
+       glLabelImage     *limage     = (glLabelImage *)src_object;
+       glLabelImage     *new_limage = (glLabelImage *)dst_object;
+       glTextNode       *filename;
+       GdkPixbuf        *pixbuf;
+       GHashTable       *pixbuf_cache;
 
        gl_debug (DEBUG_LABEL, "START");
 
@@ -157,6 +172,16 @@ copy (glLabelObject *dst_object,
        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->private->pixbuf;
+               if ( pixbuf != default_pixbuf ) {
+                       pixbuf_cache = gl_label_get_pixbuf_cache (dst_object->parent);
+                       gl_pixbuf_cache_add_pixbuf (pixbuf_cache, filename->data, pixbuf);
+               }
+       }
+
        gl_label_image_set_filename (new_limage, filename);
        gl_text_node_free (&filename);
 
@@ -171,62 +196,54 @@ void
 gl_label_image_set_filename (glLabelImage *limage,
                             glTextNode   *filename)
 {
-       GdkPixbuf *pixbuf;
+       glTextNode  *old_filename;
+       GHashTable  *pixbuf_cache;
+       GdkPixbuf   *pixbuf;
 
        gl_debug (DEBUG_LABEL, "START");
 
        g_return_if_fail (limage && GL_IS_LABEL_IMAGE (limage));
+       g_return_if_fail (filename != NULL);
 
-       if ( (filename == NULL) || filename->field_flag || (filename->data == NULL) ) {
+       old_filename = limage->private->filename;
 
-               gl_text_node_free (&limage->private->filename);
-               limage->private->filename = gl_text_node_dup(filename);
-
-               g_object_unref (limage->private->pixbuf);
-               limage->private->pixbuf =
-                       gdk_pixbuf_new_from_xpm_data ((const char **)
-                                                     checkerboard_xpm);
-
-               gl_label_object_emit_changed (GL_LABEL_OBJECT(limage));
-       } else {
+       /* If Unchanged don't do anything */
+       if ( (filename->field_flag == old_filename->field_flag) &&
+            old_filename->data != NULL && filename->data != NULL &&
+            !strcmp(filename->data, old_filename->data) )
+       {
+               return;
+       }
 
-               if ( limage->private->filename == NULL) {
+       pixbuf_cache = gl_label_get_pixbuf_cache (GL_LABEL_OBJECT(limage)->parent);
 
-                       limage->private->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);
+       }
 
-                       pixbuf = gdk_pixbuf_new_from_file (filename->data, NULL);
-                       g_object_unref (limage->private->pixbuf);
-                       if ( pixbuf != NULL ) {
-                               limage->private->pixbuf = pixbuf;
-                       } else {
-                               limage->private->pixbuf =
-                                       gdk_pixbuf_new_from_xpm_data ((const char **)
-                                                                     checkerboard_xpm);
-                       }
+       /* Set new filename. */
+       limage->private->filename = gl_text_node_dup(filename);
+       gl_text_node_free (&old_filename);
 
-                       gl_label_object_emit_changed (GL_LABEL_OBJECT(limage));
+       /* Now set the pixbuf. */
+       if ( filename->field_flag || (filename->data == NULL) ) {
 
-               } else if ( (limage->private->filename->data == NULL) ||
-                           strcmp (limage->private->filename->data, filename->data) != 0) {
+               limage->private->pixbuf = default_pixbuf;
 
-                       gl_text_node_free (&limage->private->filename);
-                       limage->private->filename = gl_text_node_dup (filename);
+       } else {
 
-                       pixbuf = gdk_pixbuf_new_from_file (filename->data, NULL);
-                       g_object_unref (limage->private->pixbuf);
-                       if ( pixbuf != NULL ) {
-                               limage->private->pixbuf = pixbuf;
-                       } else {
-                               limage->private->pixbuf =
-                                       gdk_pixbuf_new_from_xpm_data ((const char **)
-                                                                     checkerboard_xpm);
-                       }
+               pixbuf = gl_pixbuf_cache_get_pixbuf (pixbuf_cache, filename->data);
 
-                       gl_label_object_emit_changed (GL_LABEL_OBJECT(limage));
+               if (pixbuf != NULL) {
+                       limage->private->pixbuf = pixbuf;
+               } else {
+                       limage->private->pixbuf = default_pixbuf;
                }
-
        }
 
+       gl_label_object_emit_changed (GL_LABEL_OBJECT(limage));
+
        gl_debug (DEBUG_LABEL, "END");
 }
 
@@ -246,13 +263,13 @@ const GdkPixbuf *
 gl_label_image_get_pixbuf (glLabelImage  *limage,
                           glMergeRecord *record)
 {
-       GdkPixbuf *pixbuf = NULL;
-       gchar     *real_filename;
-
        g_return_val_if_fail (limage && GL_IS_LABEL_IMAGE (limage), NULL);
 
        if ((record != NULL) && limage->private->filename->field_flag) {
-               
+
+               GdkPixbuf   *pixbuf = NULL;
+               gchar       *real_filename;
+
                /* Indirect filename, re-evaluate for given record. */
 
                real_filename = gl_merge_eval_key (record,
@@ -261,17 +278,17 @@ gl_label_image_get_pixbuf (glLabelImage  *limage,
                if (real_filename != NULL) {
                        pixbuf = gdk_pixbuf_new_from_file (real_filename, NULL);
                }
-               g_object_unref (limage->private->pixbuf);
                if ( pixbuf != NULL ) {
-                       limage->private->pixbuf = pixbuf;
+                       return pixbuf;
                } else {
-                       limage->private->pixbuf =
-                               gdk_pixbuf_new_from_xpm_data ((const char **)
-                                                             checkerboard_xpm);
+                       return default_pixbuf;
                }
 
        }
 
        return limage->private->pixbuf;
+
 }
 
+
+
index f4db0f4bb470999a4b8366b990197d9cc2b2d0d8..8d4a16f779d7020de362646adbc5c415fa26f9f8 100644 (file)
 
 #include "label.h"
 #include "label-object.h"
-#include "label-text.h"
-#include "label-box.h"
-#include "label-line.h"
-#include "label-ellipse.h"
-#include "label-image.h"
-#include "label-barcode.h"
-#include "template.h"
 #include "marshal.h"
 #include "util.h"
 
 
 struct _glLabelPrivate {
 
-        glTemplate *template;
-        gboolean rotate_flag;
+        glTemplate  *template;
+        gboolean     rotate_flag;
 
-       gchar *filename;
-       gboolean modified_flag;
-       gint untitled_instance;
+       gchar       *filename;
+       gboolean     modified_flag;
+       gint         untitled_instance;
 
-       glMerge *merge;
+       glMerge     *merge;
+
+       GHashTable  *pixbuf_cache;
 };
 
 enum {
@@ -179,6 +174,7 @@ gl_label_instance_init (glLabel *label)
 
        label->private = g_new0 (glLabelPrivate, 1);
        label->private->merge = NULL;
+       label->private->pixbuf_cache = gl_pixbuf_cache_new ();
 
        gl_debug (DEBUG_LABEL, "END");
 }
@@ -206,6 +202,8 @@ gl_label_finalize (GObject *object)
                g_object_unref (G_OBJECT(label->private->merge));
        }
 
+       gl_pixbuf_cache_free (label->private->pixbuf_cache);
+
        g_free (label->private);
 
        G_OBJECT_CLASS (parent_class)->finalize (object);
@@ -555,6 +553,15 @@ gl_label_get_short_name (glLabel *label)
        }
 }
 
+/****************************************************************************/
+/* Get pixbuf cache.                                                        */
+/****************************************************************************/
+GHashTable *
+gl_label_get_pixbuf_cache (glLabel       *label)
+{
+       return label->private->pixbuf_cache;
+}
+
 /****************************************************************************/
 /* Is label modified?                                                       */
 /****************************************************************************/
index fbf4688c74f51b395f6f017cd90739565d2c1718..6d639e102bbd7da94dffe021fa106db849f726d8 100644 (file)
@@ -26,6 +26,7 @@
 
 #include "merge.h"
 #include "template.h"
+#include "pixbuf-cache.h"
 
 G_BEGIN_DECLS
 
@@ -107,6 +108,8 @@ gchar        *gl_label_get_filename            (glLabel       *label);
 
 gchar        *gl_label_get_short_name          (glLabel       *label);
 
+GHashTable   *gl_label_get_pixbuf_cache        (glLabel       *label);
+
 gboolean      gl_label_is_modified             (glLabel       *label);
 
 gboolean      gl_label_is_untitled             (glLabel       *label);
diff --git a/glabels2/src/pixbuf-cache.c b/glabels2/src/pixbuf-cache.c
new file mode 100644 (file)
index 0000000..cc2f08e
--- /dev/null
@@ -0,0 +1,250 @@
+/*
+ *  (GLABELS) Label and Business Card Creation program for GNOME
+ *
+ *  pixbuf-cache.c:  GLabels pixbuf cache module
+ *
+ *  Copyright (C) 2003  Jim Evins <evins@snaught.com>.
+ *
+ *  This program 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 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program 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 this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+#include <config.h>
+
+#include "pixbuf-cache.h"
+
+#include "debug.h"
+
+/*========================================================*/
+/* Private types.                                         */
+/*========================================================*/
+
+typedef struct {
+       gchar     *key;
+       guint      references;
+       GdkPixbuf *pixbuf;
+} 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);
+
+\f
+/*---------------------------------------------------------------------------*/
+/* 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->pixbuf);
+       g_free (record);
+}
+
+/*****************************************************************************/
+/* Create a new hash table to keep track of cached pixbufs.                  */
+/*****************************************************************************/
+GHashTable *
+gl_pixbuf_cache_new (void)
+{
+       GHashTable *pixbuf_cache;
+
+       gl_debug (DEBUG_PIXBUF_CACHE, "START");
+
+       pixbuf_cache = g_hash_table_new_full (g_str_hash,
+                                             g_str_equal,
+                                             NULL,
+                                             record_destroy);
+
+       gl_debug (DEBUG_PIXBUF_CACHE, "END pixbuf_cache=%p", pixbuf_cache);
+
+       return pixbuf_cache;
+}
+
+/*****************************************************************************/
+/* Free up previously allocated hash table and its contents.                 */
+/*****************************************************************************/
+void
+gl_pixbuf_cache_free (GHashTable *pixbuf_cache)
+{
+       gl_debug (DEBUG_PIXBUF_CACHE, "START");
+
+       g_hash_table_destroy (pixbuf_cache);
+
+       gl_debug (DEBUG_PIXBUF_CACHE, "END");
+}
+
+/*****************************************************************************/
+/* Add pixbuf to cache explicitly.                                           */
+/*****************************************************************************/
+void
+gl_pixbuf_cache_add_pixbuf (GHashTable *pixbuf_cache,
+                           gchar      *name,
+                           GdkPixbuf  *pixbuf)
+{
+       CacheRecord *test_record, *record;
+       gchar       *key;
+
+       gl_debug (DEBUG_PIXBUF_CACHE, "START");
+
+       test_record = g_hash_table_lookup (pixbuf_cache, name);
+       if (test_record != NULL) {
+               /* pixbuf is already in the cache. */
+               gl_debug (DEBUG_PIXBUF_CACHE, "END already in cache");
+               return;
+       }
+
+       record = g_new0 (CacheRecord, 1);
+       record->key        = g_strdup (name);
+       record->references = 0;
+       record->pixbuf     = pixbuf;
+
+       g_hash_table_insert (pixbuf_cache, record->key, record);
+
+       gl_debug (DEBUG_PIXBUF_CACHE, "END");
+}
+
+/*****************************************************************************/
+/* Get pixbuf.  If not in cache, read it and add to cache.                   */
+/*****************************************************************************/
+GdkPixbuf *
+gl_pixbuf_cache_get_pixbuf (GHashTable *pixbuf_cache,
+                           gchar      *name)
+{
+       CacheRecord *record;
+       GdkPixbuf   *pixbuf;
+
+       gl_debug (DEBUG_PIXBUF_CACHE, "START pixbuf_cache=%p", pixbuf_cache);
+
+       record = g_hash_table_lookup (pixbuf_cache, name);
+
+       if (record != NULL) {
+               gl_debug (DEBUG_PIXBUF_CACHE, "END cached");
+               record->references++;
+               return record->pixbuf;
+       }
+
+
+       pixbuf = gdk_pixbuf_new_from_file (name, NULL);
+       if ( pixbuf != NULL) {
+               record = g_new0 (CacheRecord, 1);
+               record->key        = g_strdup (name);
+               record->references = 1;
+               record->pixbuf     = pixbuf;
+
+               g_hash_table_insert (pixbuf_cache, record->key, record);
+       }
+
+       gl_debug (DEBUG_PIXBUF_CACHE, "END");
+
+       return pixbuf;
+}
+
+/*****************************************************************************/
+/* Remove pixbuf, but only if no references left.                            */
+/*****************************************************************************/
+void
+gl_pixbuf_cache_remove_pixbuf (GHashTable *pixbuf_cache,
+                              gchar      *name)
+{
+       CacheRecord *record;
+
+       gl_debug (DEBUG_PIXBUF_CACHE, "START");
+
+       record = g_hash_table_lookup (pixbuf_cache, name);
+       if (record == NULL) {
+               gl_debug (DEBUG_PIXBUF_CACHE, "END not in cache");
+               return;
+       }
+
+       record->references--;
+
+       if ( record->references == 0 ) {
+               g_hash_table_remove (pixbuf_cache, name);
+       }
+
+       gl_debug (DEBUG_PIXBUF_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_PIXBUF_CACHE, "START");
+
+       gl_debug (DEBUG_PIXBUF_CACHE, "adding name=%s", name);
+
+       *name_list = g_list_append (*name_list, g_strdup(name));
+
+       gl_debug (DEBUG_PIXBUF_CACHE, "END");
+}
+
+/*****************************************************************************/
+/* Return a list of names for all pixbufs in the cache.                      */
+/*****************************************************************************/
+GList *
+gl_pixbuf_cache_get_name_list (GHashTable *pixbuf_cache)
+{
+       GList *name_list = NULL;
+
+       gl_debug (DEBUG_PIXBUF_CACHE, "START");
+
+       g_hash_table_foreach (pixbuf_cache, add_name_to_list, &name_list);
+
+       gl_debug (DEBUG_PIXBUF_CACHE, "END");
+
+       return name_list;
+}
+
+/*****************************************************************************/
+/* Free up a list of pixbuf names.                                           */
+/*****************************************************************************/
+void
+gl_pixbuf_cache_free_name_list (GList *name_list)
+{
+       GList *p_name;
+
+       gl_debug (DEBUG_PIXBUF_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_PIXBUF_CACHE, "END");
+}
+
+
diff --git a/glabels2/src/pixbuf-cache.h b/glabels2/src/pixbuf-cache.h
new file mode 100644 (file)
index 0000000..33d7673
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ *  (GLABELS) Label and Business Card Creation program for GNOME
+ *
+ *  pixbuf-cache.h:  GLabels pixbuf cache module
+ *
+ *  Copyright (C) 2003  Jim Evins <evins@snaught.com>.
+ *
+ *  This program 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 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program 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 this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+#ifndef __PIXBUF_CACHE_H__
+#define __PIXBUF_CACHE_H__
+
+#include <glib.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+G_BEGIN_DECLS
+
+GHashTable *gl_pixbuf_cache_new            (void);
+
+void        gl_pixbuf_cache_free           (GHashTable *pixbuf_cache);
+
+void        gl_pixbuf_cache_add_pixbuf     (GHashTable *pixbuf_cache,
+                                           gchar      *name,
+                                           GdkPixbuf  *pixbuf);
+
+GdkPixbuf  *gl_pixbuf_cache_get_pixbuf     (GHashTable *pixbuf_cache,
+                                           gchar      *name);
+
+void        gl_pixbuf_cache_remove_pixbuf  (GHashTable *pixbuf_cache,
+                                           gchar      *name);
+
+GList      *gl_pixbuf_cache_get_name_list  (GHashTable *pixbuf_cache);
+
+void        gl_pixbuf_cache_free_name_list (GList      *name_list);
+
+G_END_DECLS
+
+#endif /*__PIXBUF_CACHE_H__ */
index f502a01905cdb89fd93f6cc996a0832c082a0877..13e563882d6353b357161bf26aa33d0fccf434be 100644 (file)
@@ -3246,27 +3246,27 @@ selection_received_cb (GtkWidget        *widget,
                p_next = p->next;
 
                object = (glLabelObject *) p->data;
-               gl_label_object_set_parent (object, view->label);
+               newobject = gl_label_object_dup (object, view->label);
 
                gl_debug (DEBUG_VIEW, "object pasted");
 
-               if (GL_IS_LABEL_BOX (object)) {
-                       view_object = gl_view_box_new (GL_LABEL_BOX(object),
+               if (GL_IS_LABEL_BOX (newobject)) {
+                       view_object = gl_view_box_new (GL_LABEL_BOX(newobject),
                                                       view);
-               } else if (GL_IS_LABEL_ELLIPSE (object)) {
-                       view_object = gl_view_ellipse_new (GL_LABEL_ELLIPSE(object),
+               } else if (GL_IS_LABEL_ELLIPSE (newobject)) {
+                       view_object = gl_view_ellipse_new (GL_LABEL_ELLIPSE(newobject),
                                                           view);
-               } else if (GL_IS_LABEL_LINE (object)) {
-                       view_object = gl_view_line_new (GL_LABEL_LINE(object),
+               } else if (GL_IS_LABEL_LINE (newobject)) {
+                       view_object = gl_view_line_new (GL_LABEL_LINE(newobject),
                                                        view);
-               } else if (GL_IS_LABEL_IMAGE (object)) {
-                       view_object = gl_view_image_new (GL_LABEL_IMAGE(object),
+               } else if (GL_IS_LABEL_IMAGE (newobject)) {
+                       view_object = gl_view_image_new (GL_LABEL_IMAGE(newobject),
                                                         view);
-               } else if (GL_IS_LABEL_TEXT (object)) {
-                       view_object = gl_view_text_new (GL_LABEL_TEXT(object),
+               } else if (GL_IS_LABEL_TEXT (newobject)) {
+                       view_object = gl_view_text_new (GL_LABEL_TEXT(newobject),
                                                        view);
-               } else if (GL_IS_LABEL_BARCODE (object)) {
-                       view_object = gl_view_barcode_new (GL_LABEL_BARCODE(object),
+               } else if (GL_IS_LABEL_BARCODE (newobject)) {
+                       view_object = gl_view_barcode_new (GL_LABEL_BARCODE(newobject),
                                                           view);
                } else {
                        /* Should not happen! */
index 5aa7b6f04a4ca79d3b0018dca930c722f5bb44f1..293425d88ae92d523cfaaafd0b4dfcc8349ebf3a 100644 (file)
@@ -26,6 +26,7 @@
 
 #include <libxml/tree.h>
 #include <libxml/parser.h>
+#include <gdk-pixbuf/gdk-pixdata.h>
 
 #include "label.h"
 #include "label-object.h"
@@ -36,6 +37,7 @@
 #include "label-image.h"
 #include "label-barcode.h"
 #include "template.h"
+#include "base64.h"
 #include "xml-label.h"
 #include "xml-label-04.h"
 #include "util.h"
@@ -94,6 +96,12 @@ static glLabelObject *xml_parse_barcode_props  (xmlNodePtr        node,
 static void           xml_parse_merge_fields   (xmlNodePtr        node,
                                                glLabel          *label);
 
+static void           xml_parse_data           (xmlNodePtr        node,
+                                               glLabel          *label);
+
+static void           xml_parse_pixdata        (xmlNodePtr        node,
+                                               glLabel          *label);
+
 
 static xmlDocPtr      xml_label_to_doc         (glLabel          *label,
                                                glXMLLabelStatus *status);
@@ -134,6 +142,16 @@ static void           xml_create_merge_fields  (xmlNodePtr        root,
                                                xmlNsPtr          ns,
                                                glLabel          *label);
 
+static void           xml_create_data          (xmlNodePtr        root,
+                                               xmlNsPtr          ns,
+                                               glLabel          *label);
+
+static void           xml_create_pixdata       (xmlNodePtr        root,
+                                               xmlNsPtr          ns,
+                                               glLabel          *label,
+                                               gchar            *name);
+
+
 /****************************************************************************/
 /* Open and read label from xml file.                                       */
 /****************************************************************************/
@@ -272,6 +290,14 @@ xml_parse_label (xmlNodePtr        root,
 
        label = GL_LABEL(gl_label_new ());
 
+       /* Pass 1, extract data nodes to pre-load cache. */
+       for (node = root->xmlChildrenNode; node != NULL; node = node->next) {
+               if (g_strcasecmp (node->name, "Data") == 0) {
+                       xml_parse_data (node, label);
+               }
+       }
+
+       /* Pass 2, now extract everything else. */
        for (node = root->xmlChildrenNode; node != NULL; node = node->next) {
 
                if (g_strcasecmp (node->name, "Sheet") == 0) {
@@ -286,9 +312,12 @@ xml_parse_label (xmlNodePtr        root,
                        xml_parse_objects (node, label);
                } else if (g_strcasecmp (node->name, "Merge_Fields") == 0) {
                        xml_parse_merge_fields (node, label);
+               } else if (g_strcasecmp (node->name, "Data") == 0) {
+                       /* Handled in pass 1. */
                } else {
                        if (!xmlNodeIsText (node)) {
-                               g_warning (_("bad node =  \"%s\""), node->name);
+                               g_warning (_("bad node in Document node =  \"%s\""),
+                                          node->name);
                        }
                }
        }
@@ -682,6 +711,71 @@ xml_parse_merge_fields (xmlNodePtr  node,
        gl_debug (DEBUG_XML, "END");
 }
 
+/*--------------------------------------------------------------------------*/
+/* PRIVATE.  Parse XML data tag.                                            */
+/*--------------------------------------------------------------------------*/
+static void
+xml_parse_data (xmlNodePtr  node,
+               glLabel    *label)
+{
+       xmlNodePtr  child;
+
+       gl_debug (DEBUG_XML, "START");
+
+       for (child = node->xmlChildrenNode; child != NULL; child = child->next) {
+
+               if (g_strcasecmp (child->name, "Pixdata") == 0) {
+                       xml_parse_pixdata (child, label);
+               } else {
+                       if (!xmlNodeIsText (child)) {
+                               g_warning (_("bad node in Data node =  \"%s\""),
+                                          child->name);
+                       }
+               }
+       }
+
+       gl_debug (DEBUG_XML, "END");
+}
+
+/*--------------------------------------------------------------------------*/
+/* PRIVATE.  Parse XML pixbuf data tag.                                     */
+/*--------------------------------------------------------------------------*/
+static void
+xml_parse_pixdata (xmlNodePtr  node,
+                  glLabel    *label)
+{
+       gchar      *name, *base64;
+       guchar     *stream;
+       guint       stream_length;
+       gboolean    ret;
+       GdkPixdata *pixdata;
+       GdkPixbuf  *pixbuf;
+       GHashTable *pixbuf_cache;
+
+       gl_debug (DEBUG_XML, "START");
+
+       name = xmlGetProp (node, "name");
+       base64 = xmlNodeGetContent (node);
+
+       stream = gl_base64_decode (base64, &stream_length);
+       pixdata = g_new0 (GdkPixdata, 1);
+       ret = gdk_pixdata_deserialize (pixdata, stream_length, stream, NULL);
+
+       if (ret) {
+               pixbuf = gdk_pixbuf_from_pixdata (pixdata, TRUE, NULL);
+
+               pixbuf_cache = gl_label_get_pixbuf_cache (label);
+               gl_pixbuf_cache_add_pixbuf (pixbuf_cache, name, pixbuf);
+       }
+
+       g_free (name);
+       g_free (base64);
+       g_free (stream);
+       g_free (pixdata);
+
+       gl_debug (DEBUG_XML, "END");
+}
+
 /****************************************************************************/
 /* Save label to xml label file.                                            */
 /****************************************************************************/
@@ -697,6 +791,7 @@ gl_xml_label_save (glLabel          *label,
 
        doc = xml_label_to_doc (label, status);
 
+       xmlSetDocCompressMode (doc, 9);
        xml_ret = xmlSaveFormatFile (filename, doc, TRUE);
        xmlFreeDoc (doc);
        if (xml_ret == -1) {
@@ -773,6 +868,8 @@ xml_label_to_doc (glLabel          *label,
                g_object_unref (G_OBJECT(merge));
        }
 
+       xml_create_data (doc->xmlRootNode, ns, label);
+
        gl_debug (DEBUG_XML, "END");
 
        *status = XML_LABEL_OK;
@@ -1188,3 +1285,77 @@ xml_create_merge_fields (xmlNodePtr  root,
        gl_debug (DEBUG_XML, "END");
 }
 
+/*--------------------------------------------------------------------------*/
+/* PRIVATE.  Add XML Label Data Node                                        */
+/*--------------------------------------------------------------------------*/
+static void
+xml_create_data (xmlNodePtr  root,
+                xmlNsPtr    ns,
+                glLabel    *label)
+{
+       xmlNodePtr  node;
+       GList      *name_list, *p;
+       GHashTable *pixbuf_cache;
+
+       gl_debug (DEBUG_XML, "START");
+
+       node = xmlNewChild (root, ns, "Data", NULL);
+
+       pixbuf_cache = gl_label_get_pixbuf_cache (label);
+       name_list = gl_pixbuf_cache_get_name_list (pixbuf_cache);
+
+       for (p = name_list; p != NULL; p=p->next) {
+               xml_create_pixdata (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                                 */
+/*--------------------------------------------------------------------------*/
+static void
+xml_create_pixdata (xmlNodePtr  root,
+                   xmlNsPtr    ns,
+                   glLabel    *label,
+                   gchar      *name)
+{
+       xmlNodePtr  node;
+       GHashTable *pixbuf_cache;
+       GdkPixbuf  *pixbuf;
+       GdkPixdata *pixdata;
+       guchar     *stream;
+       guint       stream_length;
+       gchar      *base64;
+
+       gl_debug (DEBUG_XML, "START");
+
+       pixbuf_cache = gl_label_get_pixbuf_cache (label);
+
+       pixbuf = gl_pixbuf_cache_get_pixbuf (pixbuf_cache, name);
+       if ( pixbuf != NULL ) {
+
+               pixdata = g_new0 (GdkPixdata, 1);
+               gdk_pixdata_from_pixbuf (pixdata, pixbuf, TRUE);
+               stream = gdk_pixdata_serialize (pixdata, &stream_length);
+               base64 = gl_base64_encode (stream, stream_length);
+
+               node = xmlNewChild (root, ns, "Pixdata", base64);
+               xmlSetProp (node, "name", name);
+               xmlSetProp (node, "encoding", "base64");
+
+               gl_pixbuf_cache_remove_pixbuf (pixbuf_cache, name);
+
+               g_free (pixdata->pixel_data);
+               g_free (pixdata);
+               g_free (stream);
+               g_free (base64);
+       }
+
+
+       gl_debug (DEBUG_XML, "END");
+}
+