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 \
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 \
--- /dev/null
+/*
+ * (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;
+}
+
--- /dev/null
+/*
+ * (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
+
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;
/****************************************************************************/
(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);
GL_DEBUG_UI,
GL_DEBUG_MEDIA_SELECT,
GL_DEBUG_MINI_PREVIEW,
+ GL_DEBUG_PIXBUF_CACHE,
GL_DEBUG_WDGT,
} glDebugSection;
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__
#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,
{ "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 },
static guint instance = 0;
+static GdkPixbuf *default_pixbuf = NULL;
+
/*========================================================*/
/* Private function prototypes. */
/*========================================================*/
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);
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");
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);
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");
}
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,
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;
+
}
+
+
#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 {
label->private = g_new0 (glLabelPrivate, 1);
label->private->merge = NULL;
+ label->private->pixbuf_cache = gl_pixbuf_cache_new ();
gl_debug (DEBUG_LABEL, "END");
}
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);
}
}
+/****************************************************************************/
+/* Get pixbuf cache. */
+/****************************************************************************/
+GHashTable *
+gl_label_get_pixbuf_cache (glLabel *label)
+{
+ return label->private->pixbuf_cache;
+}
+
/****************************************************************************/
/* Is label modified? */
/****************************************************************************/
#include "merge.h"
#include "template.h"
+#include "pixbuf-cache.h"
G_BEGIN_DECLS
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);
--- /dev/null
+/*
+ * (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");
+}
+
+
--- /dev/null
+/*
+ * (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__ */
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! */
#include <libxml/tree.h>
#include <libxml/parser.h>
+#include <gdk-pixbuf/gdk-pixdata.h>
#include "label.h"
#include "label-object.h"
#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"
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);
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. */
/****************************************************************************/
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) {
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);
}
}
}
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. */
/****************************************************************************/
doc = xml_label_to_doc (label, status);
+ xmlSetDocCompressMode (doc, 9);
xml_ret = xmlSaveFormatFile (filename, doc, TRUE);
xmlFreeDoc (doc);
if (xml_ret == -1) {
g_object_unref (G_OBJECT(merge));
}
+ xml_create_data (doc->xmlRootNode, ns, label);
+
gl_debug (DEBUG_XML, "END");
*status = XML_LABEL_OK;
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");
+}
+