summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDamjan Jovanovic <damjan.jov@gmail.com>2010-09-13 05:29:00 +0000
committerBastien Nocera <hadess@hadess.net>2014-10-24 15:00:46 +0200
commit59e3b147287679fe214f39822f3918dba61c9e8f (patch)
treeeb001e332210a9091c2db0c5ab19f5d98b9bf730
parent0da968fd5f1c5f8b05f4549be6bf77fe2f1daa62 (diff)
downloadgdk-pixbuf-59e3b147287679fe214f39822f3918dba61c9e8f.tar.gz
icns: Add progressive loading support
This fixes thumbnailing of ICNS files in nautilus. https://bugzilla.gnome.org/show_bug.cgi?id=629474
-rw-r--r--gdk-pixbuf/io-icns.c114
1 files changed, 114 insertions, 0 deletions
diff --git a/gdk-pixbuf/io-icns.c b/gdk-pixbuf/io-icns.c
index ddc88ee1e..a432e463f 100644
--- a/gdk-pixbuf/io-icns.c
+++ b/gdk-pixbuf/io-icns.c
@@ -43,6 +43,17 @@ struct IcnsBlockHeader
};
typedef struct IcnsBlockHeader IcnsBlockHeader;
+typedef struct
+{
+ GdkPixbufModuleSizeFunc size_func;
+ GdkPixbufModulePreparedFunc prepared_func;
+ GdkPixbufModuleUpdatedFunc updated_func;
+ gpointer user_data;
+
+ GByteArray *byte_array;
+ GdkPixbuf *pixbuf; /* Our "target" */
+} IcnsProgressiveState;
+
/*
* load raw icon data from 'icns' resource
*
@@ -366,6 +377,106 @@ icns_image_load (FILE *f, GError ** error)
return pixbuf;
}
+static void
+context_free (IcnsProgressiveState *context)
+{
+ g_byte_array_free (context->byte_array, TRUE);
+ g_clear_object (&context->pixbuf);
+ g_free (context);
+}
+
+static gpointer
+gdk_pixbuf__icns_image_begin_load (GdkPixbufModuleSizeFunc size_func,
+ GdkPixbufModulePreparedFunc prepared_func,
+ GdkPixbufModuleUpdatedFunc updated_func,
+ gpointer user_data,
+ GError **error)
+{
+ IcnsProgressiveState *context;
+
+ context = g_new0 (IcnsProgressiveState, 1);
+ context->size_func = size_func;
+ context->prepared_func = prepared_func;
+ context->updated_func = updated_func;
+ context->user_data = user_data;
+ context->byte_array = g_byte_array_new ();
+
+ return context;
+}
+
+static gboolean
+gdk_pixbuf__icns_image_stop_load (gpointer data,
+ GError **error)
+{
+ IcnsProgressiveState *context = data;
+
+ g_return_val_if_fail (context != NULL, TRUE);
+
+ context_free (context);
+ return TRUE;
+}
+
+static gboolean
+gdk_pixbuf__icns_image_load_increment (gpointer data,
+ const guchar *buf,
+ guint size,
+ GError **error)
+{
+ IcnsProgressiveState *context = data;
+ int i;
+ int filesize;
+ gint w, h;
+
+ context->byte_array = g_byte_array_append (context->byte_array, buf, size);
+
+ if (context->byte_array->len < 8)
+ return TRUE;
+
+ filesize = (context->byte_array->data[4] << 24) |
+ (context->byte_array->data[5] << 16) |
+ (context->byte_array->data[6] << 8) |
+ (context->byte_array->data[7]);
+
+ if (context->byte_array->len < filesize)
+ return TRUE;
+
+ for (i = 0; i < G_N_ELEMENTS(sizes) && !context->pixbuf; i++)
+ context->pixbuf = load_icon (sizes[i],
+ context->byte_array->data,
+ context->byte_array->len);
+
+ if (!context->pixbuf)
+ {
+ g_set_error_literal (error, GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+ _("Could not decode ICNS file"));
+ return FALSE;
+ }
+
+ w = gdk_pixbuf_get_width (context->pixbuf);
+ h = gdk_pixbuf_get_height (context->pixbuf);
+
+ if (context->size_func != NULL)
+ (*context->size_func) (&w,
+ &h,
+ context->user_data);
+
+ if (context->prepared_func != NULL)
+ (*context->prepared_func) (context->pixbuf,
+ NULL,
+ context->user_data);
+
+ if (context->updated_func != NULL)
+ (*context->updated_func) (context->pixbuf,
+ 0,
+ 0,
+ gdk_pixbuf_get_width (context->pixbuf),
+ gdk_pixbuf_get_height (context->pixbuf),
+ context->user_data);
+
+ return TRUE;
+}
+
#ifndef INCLUDE_icns
#define MODULE_ENTRY(function) G_MODULE_EXPORT void function
#else
@@ -375,6 +486,9 @@ icns_image_load (FILE *f, GError ** error)
MODULE_ENTRY (fill_vtable) (GdkPixbufModule * module)
{
module->load = icns_image_load;
+ module->begin_load = gdk_pixbuf__icns_image_begin_load;
+ module->stop_load = gdk_pixbuf__icns_image_stop_load;
+ module->load_increment = gdk_pixbuf__icns_image_load_increment;
}
MODULE_ENTRY (fill_info) (GdkPixbufFormat * info)