[gthumb: 55/129] Added GthImage as a generic container of image data



commit 30e7b30b87cd87138f3b76f803f5b198fdecc6dd
Author: Paolo Bacchilega <paobac src gnome org>
Date:   Thu Apr 21 21:54:17 2011 +0200

    Added GthImage as a generic container of image data
    
    This change will allow to add loaders that create a cairo_surface structure directly
    instead of loading the image in a GdkPixbuf and then converting it to a cairo_surface.

 .../contact_sheet/gth-contact-sheet-creator.c      |   16 +-
 extensions/flicker/dlg-import-from-flickr.c        |   15 +-
 extensions/image_print/gth-load-image-info-task.c  |   21 +-
 extensions/image_viewer/gth-image-viewer-page.c    |   24 +-
 extensions/picasaweb/dlg-import-from-picasaweb.c   |   15 +-
 extensions/raw_files/main.c                        |   68 +++---
 extensions/slideshow/gth-slideshow.c               |   10 +-
 extensions/webalbums/gth-web-exporter.c            |   15 +-
 gthumb/Makefile.am                                 |    2 +
 gthumb/gth-image-loader.c                          |  131 ++++------
 gthumb/gth-image-loader.h                          |   18 +-
 gthumb/gth-image-preloader.c                       |   43 ++--
 gthumb/gth-image-preloader.h                       |    4 +-
 gthumb/gth-image.c                                 |  280 ++++++++++++++++++++
 gthumb/gth-image.h                                 |   86 ++++++
 gthumb/gth-main-default-types.c                    |    5 +-
 gthumb/gth-main.c                                  |   59 +++--
 gthumb/gth-main.h                                  |    7 +-
 gthumb/gth-overwrite-dialog.c                      |   16 +-
 gthumb/gth-thumb-loader.c                          |   87 ++++---
 gthumb/gth-thumb-loader.h                          |    2 +-
 gthumb/pixbuf-io.c                                 |   53 ++--
 gthumb/pixbuf-io.h                                 |    5 +-
 23 files changed, 686 insertions(+), 296 deletions(-)
---
diff --git a/extensions/contact_sheet/gth-contact-sheet-creator.c b/extensions/contact_sheet/gth-contact-sheet-creator.c
index bbfd578..fec4fec 100644
--- a/extensions/contact_sheet/gth-contact-sheet-creator.c
+++ b/extensions/contact_sheet/gth-contact-sheet-creator.c
@@ -933,23 +933,26 @@ image_loader_ready_cb (GObject      *source_object,
 		       gpointer      user_data)
 {
 	GthContactSheetCreator *self = user_data;
+	GthImage               *image;
 	GdkPixbuf              *pixbuf;
 	int                     original_width;
 	int                     original_height;
 	GError                 *error = NULL;
 	ItemData               *item_data;
 
-	if (! gth_image_loader_load_image_finish (GTH_IMAGE_LOADER (source_object),
-						  result,
-						  &pixbuf,
-						  &original_width,
-						  &original_height,
-						  &error))
+	if (! gth_image_loader_load_finish (GTH_IMAGE_LOADER (source_object),
+					    result,
+					    &image,
+					    &original_width,
+					    &original_height,
+					    &error))
 	{
 		gth_task_completed (GTH_TASK (self), error);
 		return;
 	}
 
+	pixbuf = gth_image_get_pixbuf (image);
+
 	item_data = self->priv->current_file->data;
 	if (self->priv->squared_thumbnails)
 		item_data->thumbnail = _gdk_pixbuf_scale_squared (pixbuf, MIN (self->priv->thumb_height, self->priv->thumb_width), GDK_INTERP_BILINEAR);
@@ -959,6 +962,7 @@ image_loader_ready_cb (GObject      *source_object,
 	item_data->original_height = original_height;
 
 	g_object_unref (pixbuf);
+	g_object_unref (image);
 
 	self->priv->current_file = self->priv->current_file->next;
 	load_current_image (self);
diff --git a/extensions/flicker/dlg-import-from-flickr.c b/extensions/flicker/dlg-import-from-flickr.c
index 2b527ed..27954e4 100644
--- a/extensions/flicker/dlg-import-from-flickr.c
+++ b/extensions/flicker/dlg-import-from-flickr.c
@@ -425,7 +425,7 @@ photoset_combobox_changed_cb (GtkComboBox *widget,
 }
 
 
-static GdkPixbufAnimation *
+static GthImage *
 flickr_thumbnail_loader (GthFileData   *file_data,
 			 int            requested_size,
 			 int           *original_width,
@@ -434,10 +434,10 @@ flickr_thumbnail_loader (GthFileData   *file_data,
 			 GCancellable  *cancellable,
 		         GError       **error)
 {
-	GdkPixbufAnimation *animation = NULL;
-	GthThumbLoader     *thumb_loader = user_data;
-	FlickrPhoto        *photo;
-	const char         *uri = NULL;
+	GthImage       *image = NULL;
+	GthThumbLoader *thumb_loader = user_data;
+	FlickrPhoto    *photo;
+	const char     *uri = NULL;
 
 	photo = (FlickrPhoto *) g_file_info_get_attribute_object (file_data->info, "flickr::object");
 	requested_size = gth_thumb_loader_get_requested_size (thumb_loader);
@@ -472,7 +472,8 @@ flickr_thumbnail_loader (GthFileData   *file_data,
 				g_object_unref (pixbuf);
 				pixbuf = rotated;
 
-				animation = gdk_pixbuf_non_anim_new (pixbuf);
+				image = gth_image_new ();
+				gth_image_set_pixbuf (image, pixbuf);
 			}
 
 			g_object_unref (pixbuf);
@@ -484,7 +485,7 @@ flickr_thumbnail_loader (GthFileData   *file_data,
 	else
 		*error = g_error_new_literal (GTH_ERROR, 0, "cannot generate the thumbnail");
 
-	return animation;
+	return image;
 }
 
 
diff --git a/extensions/image_print/gth-load-image-info-task.c b/extensions/image_print/gth-load-image-info-task.c
index 459673d..8446287 100644
--- a/extensions/image_print/gth-load-image-info-task.c
+++ b/extensions/image_print/gth-load-image-info-task.c
@@ -111,33 +111,38 @@ image_loader_ready_cb (GObject      *source_object,
 {
 	GthLoadImageInfoTask *self = user_data;
 	GthImageInfo         *image_info;
-	GdkPixbuf            *pixbuf;
+	GthImage             *image;
 	GError               *error = NULL;
 
-	gth_image_loader_load_image_finish (GTH_IMAGE_LOADER (source_object),
-					    result,
-					    &pixbuf,
-					    NULL,
-					    NULL,
-					    &error);
+	gth_image_loader_load_finish (GTH_IMAGE_LOADER (source_object),
+				      result,
+				      &image,
+				      NULL,
+				      NULL,
+				      &error);
 
 	if (error == NULL)
 		g_cancellable_set_error_if_cancelled (gth_task_get_cancellable (GTH_TASK (self)), &error);
 
 	if (error == NULL) {
+		GdkPixbuf *pixbuf;
+
 		image_info = self->priv->images[self->priv->current];
+		pixbuf = gth_image_get_pixbuf (image);
 		if (pixbuf != NULL) {
 			gth_image_info_set_pixbuf (image_info, pixbuf);
 			g_object_unref (pixbuf);
 		}
 	}
-	else if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+	else if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+		g_object_unref (image);
 		gth_task_completed (GTH_TASK (self), error);
 		return;
 	}
 	else
 		g_clear_error (&error);
 
+	g_object_unref (image);
 	continue_loading_image (self);
 }
 
diff --git a/extensions/image_viewer/gth-image-viewer-page.c b/extensions/image_viewer/gth-image-viewer-page.c
index c0abb10..d44d5a7 100644
--- a/extensions/image_viewer/gth-image-viewer-page.c
+++ b/extensions/image_viewer/gth-image-viewer-page.c
@@ -287,12 +287,14 @@ viewer_key_press_cb (GtkWidget          *widget,
 static void
 image_preloader_requested_ready_cb (GthImagePreloader  *preloader,
 				    GthFileData        *requested,
-				    GdkPixbufAnimation *animation,
+				    GthImage           *image,
 				    int                 original_width,
 				    int                 original_height,
 				    GError             *error,
 				    GthImageViewerPage *self)
 {
+	cairo_surface_t *surface;
+
 	if (! _g_file_equal (requested->file, self->priv->file_data->file))
 		return;
 
@@ -302,10 +304,14 @@ image_preloader_requested_ready_cb (GthImagePreloader  *preloader,
 	}
 
 	gth_viewer_page_focus (GTH_VIEWER_PAGE (self));
-	gth_image_viewer_set_animation (GTH_IMAGE_VIEWER (self->priv->viewer),
-					animation,
-					original_width,
-					original_height);
+
+	surface = gth_image_get_cairo_surface (image);
+	gth_image_viewer_set_image (GTH_IMAGE_VIEWER (self->priv->viewer),
+				    surface,
+				    original_width,
+				    original_height);
+	cairo_surface_destroy (surface);
+
 	if (self->priv->shrink_wrap)
 		gth_image_viewer_page_shrink_wrap (self, TRUE);
 	gth_image_history_clear (self->priv->history);
@@ -784,8 +790,6 @@ gth_image_viewer_page_real_view (GthViewerPage *base,
 	GthFileData        *next_file_data = NULL;
 	GthFileData        *next2_file_data = NULL;
 	GthFileData        *prev_file_data = NULL;
-	int                 window_width;
-	int                 window_height;
 
 	self = (GthImageViewerPage*) base;
 	g_return_if_fail (file_data != NULL);
@@ -825,13 +829,9 @@ gth_image_viewer_page_real_view (GthViewerPage *base,
 			prev_file_data = gth_file_store_get_file (file_store, &iter2);
 	}
 
-	gtk_window_get_size (GTK_WINDOW (self->priv->browser),
-			     &window_width,
-			     &window_height);
-
 	gth_image_preloader_load (self->priv->preloader,
 				  self->priv->file_data,
-				  (gth_image_prelaoder_get_load_policy (self->priv->preloader) == GTH_LOAD_POLICY_TWO_STEPS) ? MAX (window_width, window_height) : -1,
+				  -1,
 				  next_file_data,
 				  next2_file_data,
 				  prev_file_data,
diff --git a/extensions/picasaweb/dlg-import-from-picasaweb.c b/extensions/picasaweb/dlg-import-from-picasaweb.c
index feccd04..29be8fc 100644
--- a/extensions/picasaweb/dlg-import-from-picasaweb.c
+++ b/extensions/picasaweb/dlg-import-from-picasaweb.c
@@ -863,7 +863,7 @@ album_combobox_changed_cb (GtkComboBox *widget,
 }
 
 
-GdkPixbufAnimation *
+GthImage *
 picasa_web_thumbnail_loader (GthFileData   *file_data,
 			     int            requested_size,
 			     int           *original_width,
@@ -872,10 +872,10 @@ picasa_web_thumbnail_loader (GthFileData   *file_data,
 			     GCancellable  *cancellable,
 			     GError       **error)
 {
-	GdkPixbufAnimation *animation = NULL;
-	GthThumbLoader     *thumb_loader = user_data;
-	PicasaWebPhoto     *photo;
-	const char         *uri;
+	GthImage       *image = NULL;
+	GthThumbLoader *thumb_loader = user_data;
+	PicasaWebPhoto *photo;
+	const char     *uri;
 
 	photo = (PicasaWebPhoto *) g_file_info_get_attribute_object (file_data->info, "gphoto::object");
 	requested_size = gth_thumb_loader_get_requested_size (thumb_loader);
@@ -910,7 +910,8 @@ picasa_web_thumbnail_loader (GthFileData   *file_data,
 				g_object_unref (pixbuf);
 				pixbuf = rotated;
 
-				animation = gdk_pixbuf_non_anim_new (pixbuf);
+				image = gth_image_new ();
+				gth_image_set_pixbuf (image, pixbuf);
 			}
 
 			g_object_unref (pixbuf);
@@ -922,7 +923,7 @@ picasa_web_thumbnail_loader (GthFileData   *file_data,
 	else
 		*error = g_error_new_literal (GTH_ERROR, 0, "cannot generate the thumbnail");
 
-	return animation;
+	return image;
 }
 
 
diff --git a/extensions/raw_files/main.c b/extensions/raw_files/main.c
index 74b3e0f..b060627 100644
--- a/extensions/raw_files/main.c
+++ b/extensions/raw_files/main.c
@@ -181,13 +181,13 @@ openraw_get_pixbuf_from_file (GthFileData  *file_data,
 }
 
 
-static GdkPixbufAnimation *
+static GthImage *
 openraw_pixbuf_animation_new_from_file (GthFileData  *file_data,
 					int           requested_size,
 					GError      **error)
 {
-	GdkPixbufAnimation *animation;
-	GdkPixbuf          *pixbuf;
+	GthImage  *image = NULL;
+	GdkPixbuf *pixbuf;
 
 	if (requested_size == 0)
 		pixbuf = openraw_extract_thumbnail_from_file (file_data, requested_size, error);
@@ -195,13 +195,12 @@ openraw_pixbuf_animation_new_from_file (GthFileData  *file_data,
 		pixbuf = openraw_get_pixbuf_from_file (file_data, error);
 
 	if (pixbuf != NULL) {
-		animation = gdk_pixbuf_non_anim_new (pixbuf);
+		image = gth_image_new ();
+		gth_image_set_pixbuf (image, pixbuf);
 		g_object_unref (pixbuf);
 	}
-	else
-		animation = NULL;
 
-	return animation;
+	return image;
 }
 
 
@@ -268,7 +267,7 @@ get_file_mtime (const char *path)
 }
 
 
-static GdkPixbufAnimation *
+static GthImage *
 openraw_pixbuf_animation_new_from_file (GthFileData   *file_data,
 					int            requested_size,
 					int           *original_width,
@@ -277,17 +276,17 @@ openraw_pixbuf_animation_new_from_file (GthFileData   *file_data,
 					GCancellable  *cancellable,
 					GError       **error)
 {
-	GdkPixbufAnimation *animation;
-	GdkPixbuf          *pixbuf;
-	gboolean            is_thumbnail;
-	gboolean            is_raw;
-	gboolean            is_hdr;
-	char               *local_file;
-	char               *local_file_md5;
-	char	           *cache_file;
-	char	           *cache_file_esc;
-	char	           *local_file_esc;
-	char	           *command = NULL;
+	GthImage  *image = NULL;
+	GdkPixbuf *pixbuf;
+	gboolean   is_thumbnail;
+	gboolean   is_raw;
+	gboolean   is_hdr;
+	char      *local_file;
+	char      *local_file_md5;
+	char	  *cache_file;
+	char	  *cache_file_esc;
+	char	  *local_file_esc;
+	char	  *command = NULL;
 
 	is_thumbnail = requested_size > 0;
 	is_raw = _g_mime_type_is_raw (gth_file_data_get_mime_type (file_data));
@@ -424,19 +423,17 @@ openraw_pixbuf_animation_new_from_file (GthFileData   *file_data,
 	}
 
 	if (pixbuf != NULL) {
-		animation = gdk_pixbuf_non_anim_new (pixbuf);
+		image = gth_image_new ();
+		gth_image_set_pixbuf (image, pixbuf);
 		g_object_unref (pixbuf);
 	}
-	else
-		animation = NULL;
-
 
 	g_free (cache_file_esc);
 	g_free (local_file_esc);
 	g_free (cache_file);
 	g_free (local_file);
 
-	return animation;
+	return image;
 }
 
 
@@ -446,17 +443,18 @@ openraw_pixbuf_animation_new_from_file (GthFileData   *file_data,
 G_MODULE_EXPORT void
 gthumb_extension_activate (void)
 {
-	gth_main_register_pixbuf_loader (openraw_pixbuf_animation_new_from_file,
-					 "image/x-adobe-dng",
-					 "image/x-canon-cr2",
-					 "image/x-canon-crw",
-					 "image/x-epson-erf",
-					 "image/x-minolta-mrw",
-					 "image/x-nikon-nef",
-					 "image/x-olympus-orf",
-					 "image/x-pentax-pef",
-					 "image/x-sony-arw",
-					 NULL);
+	gth_main_register_image_loader_func (openraw_pixbuf_animation_new_from_file,
+					     GTH_IMAGE_FORMAT_GDK_PIXBUF,
+					     "image/x-adobe-dng",
+					     "image/x-canon-cr2",
+					     "image/x-canon-crw",
+					     "image/x-epson-erf",
+					     "image/x-minolta-mrw",
+					     "image/x-nikon-nef",
+					     "image/x-olympus-orf",
+					     "image/x-pentax-pef",
+					     "image/x-sony-arw",
+					     NULL);
 }
 
 
diff --git a/extensions/slideshow/gth-slideshow.c b/extensions/slideshow/gth-slideshow.c
index aa1b55f..b875127 100644
--- a/extensions/slideshow/gth-slideshow.c
+++ b/extensions/slideshow/gth-slideshow.c
@@ -232,14 +232,13 @@ view_next_image_automatically (GthSlideshow *self)
 static void
 image_preloader_requested_ready_cb (GthImagePreloader  *preloader,
 				    GthFileData        *requested,
-				    GdkPixbufAnimation *animation,
+				    GthImage           *image,
 				    int                 original_width,
 				    int                 original_height,
 				    GError             *error,
 				    gpointer            user_data)
 {
 	GthSlideshow *self = user_data;
-	GdkPixbuf    *static_image;
 
 	if (error != NULL) {
 		g_clear_error (&error);
@@ -248,12 +247,7 @@ image_preloader_requested_ready_cb (GthImagePreloader  *preloader,
 	}
 
 	_g_object_unref (self->priv->current_pixbuf);
-
-	static_image = gdk_pixbuf_animation_get_static_image (animation);
-	if (static_image != NULL)
-		self->priv->current_pixbuf = gdk_pixbuf_copy (static_image);
-	else
-		self->priv->current_pixbuf = NULL;
+	self->priv->current_pixbuf = gth_image_get_pixbuf (image);
 
 	if (self->priv->current_pixbuf == NULL) {
 		_gth_slideshow_load_next_image (self);
diff --git a/extensions/webalbums/gth-web-exporter.c b/extensions/webalbums/gth-web-exporter.c
index 6f68417..b95ecb5 100644
--- a/extensions/webalbums/gth-web-exporter.c
+++ b/extensions/webalbums/gth-web-exporter.c
@@ -2552,14 +2552,15 @@ image_loader_ready_cb (GObject      *source_object,
 {
 	GthWebExporter *self = user_data;
 	ImageData      *idata;
+	GthImage       *image;
 	GdkPixbuf      *pixbuf;
 
-	if (! gth_image_loader_load_image_finish (GTH_IMAGE_LOADER (source_object),
-						  result,
-						  &pixbuf,
-						  NULL,
-						  NULL,
-						  NULL))
+	if (! gth_image_loader_load_finish (GTH_IMAGE_LOADER (source_object),
+					    result,
+					    &image,
+					    NULL,
+					    NULL,
+					    NULL))
 	{
 		load_next_file (self);
 		return;
@@ -2569,6 +2570,7 @@ image_loader_ready_cb (GObject      *source_object,
 
 	/* image */
 
+	pixbuf = gth_image_get_pixbuf (image);
 	idata->image = g_object_ref (pixbuf);
 	if (self->priv->copy_images && self->priv->resize_images) {
 		int w = gdk_pixbuf_get_width (pixbuf);
@@ -2665,6 +2667,7 @@ image_loader_ready_cb (GObject      *source_object,
 		self->priv->saving_timeout = g_idle_add (save_image_preview, self);
 
 	g_object_unref (pixbuf);
+	g_object_unref (image);
 }
 
 
diff --git a/gthumb/Makefile.am b/gthumb/Makefile.am
index b24c9c6..a1e44a0 100644
--- a/gthumb/Makefile.am
+++ b/gthumb/Makefile.am
@@ -64,6 +64,7 @@ PUBLIC_HEADER_FILES = 					\
 	gth-hook.h					\
 	gth-icon-cache.h				\
 	gth-icon-view.h					\
+	gth-image.h					\
 	gth-image-dragger.h				\
 	gth-image-history.h				\
 	gth-image-loader.h				\
@@ -182,6 +183,7 @@ gthumb_SOURCES = 					\
 	gth-hook.c					\
 	gth-icon-cache.c				\
 	gth-icon-view.c					\
+	gth-image.c					\
 	gth-image-dragger.c				\
 	gth-image-history.c				\
 	gth-image-loader.c				\
diff --git a/gthumb/gth-image-loader.c b/gthumb/gth-image-loader.c
index f650f45..2ef664a 100644
--- a/gthumb/gth-image-loader.c
+++ b/gthumb/gth-image-loader.c
@@ -34,10 +34,11 @@
 
 
 struct _GthImageLoaderPrivate {
-	gboolean     as_animation;  /* Whether to load the image in a
-				     * GdkPixbufAnimation structure. */
-	PixbufLoader loader_func;
-	gpointer     loader_data;
+	gboolean           as_animation;  /* Whether to load the image in a
+				           * GdkPixbufAnimation structure. */
+	GthImageFormat     preferred_format;
+	GthImageLoaderFunc loader_func;
+	gpointer           loader_data;
 };
 
 
@@ -72,6 +73,7 @@ gth_image_loader_init (GthImageLoader *self)
 	self->priv->as_animation = FALSE;
 	self->priv->loader_func = NULL;
 	self->priv->loader_data = NULL;
+	self->priv->preferred_format = GTH_IMAGE_FORMAT_GDK_PIXBUF;
 }
 
 
@@ -104,8 +106,8 @@ gth_image_loader_get_type (void)
 
 
 GthImageLoader *
-gth_image_loader_new (PixbufLoader loader_func,
-		      gpointer     loader_data)
+gth_image_loader_new (GthImageLoaderFunc loader_func,
+		      gpointer           loader_data)
 {
 	GthImageLoader *self;
 
@@ -117,9 +119,9 @@ gth_image_loader_new (PixbufLoader loader_func,
 
 
 void
-gth_image_loader_set_loader_func (GthImageLoader *self,
-				  PixbufLoader    loader_func,
-				  gpointer        loader_data)
+gth_image_loader_set_loader_func (GthImageLoader     *self,
+				  GthImageLoaderFunc  loader_func,
+				  gpointer            loader_data)
 {
 	g_return_if_fail (self != NULL);
 
@@ -128,6 +130,15 @@ gth_image_loader_set_loader_func (GthImageLoader *self,
 }
 
 
+void
+gth_image_loader_set_preferred_format (GthImageLoader *self,
+				       GthImageFormat  preferred_format)
+{
+	g_return_if_fail (self != NULL);
+	self->priv->preferred_format = preferred_format;
+}
+
+
 typedef struct {
 	GthFileData  *file_data;
 	int           requested_size;
@@ -161,17 +172,17 @@ load_data_unref (LoadData *load_data)
 
 
 typedef struct {
-	GdkPixbufAnimation *animation;
-	int                 original_width;
-	int                 original_height;
+	GthImage *image;
+	int       original_width;
+	int       original_height;
 } LoadResult;
 
 
 static void
 load_result_unref (LoadResult *load_result)
 {
-	if (load_result->animation != NULL)
-		g_object_unref (load_result->animation);
+	if (load_result->image != NULL)
+		g_object_unref (load_result->image);
 	g_free (load_result);
 }
 
@@ -245,7 +256,7 @@ load_image_thread (gpointer user_data)
 	GSimpleAsyncResult *result = user_data;
 	LoadData           *load_data;
 	GthImageLoader     *self;
-	GdkPixbufAnimation *animation;
+	GthImage           *image;
 	int                 original_width;
 	int                 original_height;
 	GError             *error = NULL;
@@ -265,37 +276,38 @@ load_image_thread (gpointer user_data)
 	}
 
 	self = (GthImageLoader *) g_async_result_get_source_object (G_ASYNC_RESULT (result));
-	animation = NULL;
+	image = NULL;
 	original_width = -1;
 	original_height = -1;
 
 	if (self->priv->loader_func != NULL) {
-		animation = (*self->priv->loader_func) (load_data->file_data,
-						        load_data->requested_size,
-						        &original_width,
-						        &original_height,
-						        self->priv->loader_data,
-						        load_data->cancellable,
-						        &error);
+		image = (*self->priv->loader_func) (load_data->file_data,
+						    load_data->requested_size,
+						    &original_width,
+						    &original_height,
+						    self->priv->loader_data,
+						    load_data->cancellable,
+						    &error);
 	}
 	else  {
-		PixbufLoader loader_func;
+		GthImageLoaderFunc loader_func;
 
-		loader_func = gth_main_get_pixbuf_loader (gth_file_data_get_mime_type (load_data->file_data));
+		loader_func = gth_main_get_image_loader_func (gth_file_data_get_mime_type (load_data->file_data),
+							      self->priv->preferred_format);
 		if (loader_func != NULL)
-			animation = loader_func (load_data->file_data,
-						 load_data->requested_size,
-						 &original_width,
-						 &original_height,
-						 NULL,
-						 load_data->cancellable,
-						 &error);
+			image = loader_func (load_data->file_data,
+					     load_data->requested_size,
+					     &original_width,
+					     &original_height,
+					     NULL,
+					     load_data->cancellable,
+					     &error);
 		else
 			error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, _("No suitable loader available for this file type"));
 	}
 
 	load_result = g_new0 (LoadResult, 1);
-	load_result->animation = animation;
+	load_result->image = image;
 	load_result->original_width = original_width;
 	load_result->original_height = original_height;
 
@@ -390,12 +402,12 @@ gth_image_loader_load (GthImageLoader      *loader,
 
 
 gboolean
-gth_image_loader_load_animation_finish (GthImageLoader      *loader,
-					GAsyncResult        *result,
-					GdkPixbufAnimation **animation,
-					int                 *original_width,
-					int                 *original_height,
-					GError             **error)
+gth_image_loader_load_finish (GthImageLoader   *loader,
+			      GAsyncResult     *result,
+			      GthImage        **image,
+			      int              *original_width,
+			      int              *original_height,
+			      GError         **error)
 {
 	  GSimpleAsyncResult *simple;
 	  LoadResult         *load_result;
@@ -408,8 +420,8 @@ gth_image_loader_load_animation_finish (GthImageLoader      *loader,
 		  return FALSE;
 
 	  load_result = g_simple_async_result_get_op_res_gpointer (simple);
-	  if (animation != NULL)
-		  *animation = g_object_ref (load_result->animation);
+	  if (image != NULL)
+		  *image = g_object_ref (load_result->image);
 	  if (original_width != NULL)
 	  	  *original_width = load_result->original_width;
 	  if (original_height != NULL)
@@ -417,40 +429,3 @@ gth_image_loader_load_animation_finish (GthImageLoader      *loader,
 
 	  return TRUE;
 }
-
-
-gboolean
-gth_image_loader_load_image_finish (GthImageLoader  *loader,
-				    GAsyncResult    *res,
-				    GdkPixbuf      **pixbuf,
-				    int             *original_width,
-				    int             *original_height,
-				    GError         **error)
-{
-	GdkPixbufAnimation *animation;
-	GdkPixbuf          *static_image;
-
-	if (! gth_image_loader_load_animation_finish (loader,
-						      res,
-						      &animation,
-						      original_width,
-						      original_height,
-						      error))
-	{
-		return FALSE;
-	}
-
-	static_image = gdk_pixbuf_animation_get_static_image (animation);
-	if (static_image != NULL) {
-		*pixbuf = gdk_pixbuf_copy (static_image);
-	}
-	else {
-		*pixbuf = NULL;
-		if (error != NULL)
-			*error = g_error_new_literal (GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_FAILED, "No image");
-	}
-
-	g_object_unref (animation);
-
-	return TRUE;
-}
diff --git a/gthumb/gth-image-loader.h b/gthumb/gth-image-loader.h
index 25d65d0..57252b8 100644
--- a/gthumb/gth-image-loader.h
+++ b/gthumb/gth-image-loader.h
@@ -25,7 +25,7 @@
 #include <glib.h>
 #include <gdk-pixbuf/gdk-pixbuf.h>
 #include "gth-file-data.h"
-#include "pixbuf-io.h"
+#include "gth-image.h"
 
 G_BEGIN_DECLS
 
@@ -50,11 +50,13 @@ struct _GthImageLoaderClass {
 };
 
 GType             gth_image_loader_get_type               (void);
-GthImageLoader *  gth_image_loader_new                    (PixbufLoader          loader_func,
+GthImageLoader *  gth_image_loader_new                    (GthImageLoaderFunc    loader_func,
 							   gpointer              loader_data);
 void              gth_image_loader_set_loader_func        (GthImageLoader       *loader,
-							   PixbufLoader          loader_func,
+							   GthImageLoaderFunc    loader_func,
 						           gpointer              loader_data);
+void              gth_image_loader_set_preferred_format   (GthImageLoader       *loader,
+							   GthImageFormat        preferred_format);
 void              gth_image_loader_load                   (GthImageLoader       *loader,
 							   GthFileData          *file_data,
 							   int                   requested_size,
@@ -62,15 +64,9 @@ void              gth_image_loader_load                   (GthImageLoader
 							   GCancellable         *cancellable,
 							   GAsyncReadyCallback   callback,
 							   gpointer              user_data);
-gboolean          gth_image_loader_load_animation_finish  (GthImageLoader       *loader,
+gboolean          gth_image_loader_load_finish            (GthImageLoader       *loader,
 							   GAsyncResult         *res,
-							   GdkPixbufAnimation  **animation,
-							   int                  *original_width,
-							   int                  *original_height,
-							   GError              **error);
-gboolean          gth_image_loader_load_image_finish      (GthImageLoader       *loader,
-						  	   GAsyncResult         *res,
-							   GdkPixbuf           **pixbuf,
+							   GthImage            **image,
 							   int                  *original_width,
 							   int                  *original_height,
 							   GError              **error);
diff --git a/gthumb/gth-image-preloader.c b/gthumb/gth-image-preloader.c
index 856f102..1f14ba1 100644
--- a/gthumb/gth-image-preloader.c
+++ b/gthumb/gth-image-preloader.c
@@ -49,7 +49,7 @@ typedef struct {
 	gboolean            loaded;
 	gboolean            error;
 	GthImageLoader     *loader;
-	GdkPixbufAnimation *animation;
+	GthImage           *image;
 	int                 original_width;
 	int                 original_height;
 	guint               token;
@@ -99,7 +99,8 @@ preloader_new (GthImagePreloader *self)
 	preloader->loaded = FALSE;
 	preloader->error = FALSE;
 	preloader->loader = gth_image_loader_new (NULL, NULL);
-	preloader->animation = NULL;
+	gth_image_loader_set_preferred_format (preloader->loader, GTH_IMAGE_FORMAT_CAIRO_SURFACE);
+	preloader->image = NULL;
 	preloader->original_width = -1;
 	preloader->original_height = -1;
 
@@ -112,7 +113,7 @@ preloader_free (Preloader *preloader)
 {
 	if (preloader == NULL)
 		return;
-	_g_object_unref (preloader->animation);
+	_g_object_unref (preloader->image);
 	_g_object_unref (preloader->loader);
 	_g_object_unref (preloader->file_data);
 	g_free (preloader);
@@ -145,7 +146,7 @@ preloader_has_valid_content_for_file (Preloader   *preloader,
 	return ((preloader->file_data != NULL)
 		&& preloader->loaded
 		&& ! preloader->error
-		&& (preloader->animation != NULL)
+		&& (preloader->image != NULL)
 	        && g_file_equal (preloader->file_data->file, file_data->file)
 	        && (_g_time_val_cmp (gth_file_data_get_modification_time (file_data),
 	        		     gth_file_data_get_modification_time (preloader->file_data)) == 0));
@@ -172,8 +173,8 @@ preloader_needs_second_step (Preloader *preloader)
 		&& ! preloader->error
 		&& (preloader->requested_size != -1)
 		&& ((preloader->original_width > preloader->requested_size) || (preloader->original_height > preloader->requested_size))
-		&& (preloader->animation != NULL)
-		&& gdk_pixbuf_animation_is_static_image (preloader->animation));
+		&& (preloader->image != NULL)
+		&& ! gth_image_is_animation (preloader->image));
 }
 
 
@@ -396,25 +397,25 @@ image_loader_ready_cb (GObject      *source_object,
 	LoadRequest        *load_request = user_data;
 	Preloader          *preloader = load_request->preloader;
 	GthImagePreloader  *self = preloader->self;
-	GdkPixbufAnimation *animation = NULL;
+	GthImage           *image;
 	int                 original_width;
 	int                 original_height;
 	GError             *error = NULL;
 	gboolean            success;
 	int                 interval;
 
-	success = gth_image_loader_load_animation_finish  (GTH_IMAGE_LOADER (source_object),
-							   result,
-							   &animation,
-							   &original_width,
-							   &original_height,
-							   &error);
+	success = gth_image_loader_load_finish  (GTH_IMAGE_LOADER (source_object),
+						 result,
+						 &image,
+						 &original_width,
+						 &original_height,
+						 &error);
 
 	if (! g_file_equal (load_request->file_data->file, preloader->file_data->file)
 	    || (preloader->token != self->priv->token))
 	{
 		load_request_free (load_request);
-		_g_object_unref (animation);
+		g_object_unref (image);
 		if (error != NULL)
 			g_error_free (error);
 		return;
@@ -422,8 +423,8 @@ image_loader_ready_cb (GObject      *source_object,
 
 	interval = NOT_REQUESTED_INTERVAL;
 
-	_g_object_unref (preloader->animation);
-	preloader->animation = _g_object_ref (animation);
+	_g_object_unref (preloader->image);
+	preloader->image = g_object_ref (image);
 	preloader->original_width = original_width;
 	preloader->original_height = original_height;
 	preloader->loaded = success;
@@ -439,7 +440,7 @@ image_loader_ready_cb (GObject      *source_object,
 			       gth_image_preloader_signals[preloader_signal_to_emit (preloader)],
 			       0,
 			       preloader->file_data,
-			       preloader->animation,
+			       preloader->image,
 			       preloader->original_width,
 			       preloader->original_height,
 			       error);
@@ -461,7 +462,7 @@ image_loader_ready_cb (GObject      *source_object,
 		self->priv->load_id = g_timeout_add (interval, load_next, self);
 
 	load_request_free (load_request);
-	_g_object_unref (animation);
+	g_object_unref (image);
 }
 
 
@@ -524,8 +525,8 @@ start_next_loader (GthImagePreloader *self)
 		}
 #endif
 
-		_g_object_unref (preloader->animation);
-		preloader->animation = NULL;
+		_g_object_unref (preloader->image);
+		preloader->image = NULL;
 
 		load_request = g_new0 (LoadRequest, 1);
 		load_request->preloader = preloader;
@@ -622,7 +623,7 @@ assign_loaders (LoadData *load_data)
 							gth_image_preloader_signals[preloader_signal_to_emit (preloader)],
 							0,
 							preloader->file_data,
-							preloader->animation,
+							preloader->image,
 							preloader->original_width,
 							preloader->original_height,
 							NULL);
diff --git a/gthumb/gth-image-preloader.h b/gthumb/gth-image-preloader.h
index da42106..0278654 100644
--- a/gthumb/gth-image-preloader.h
+++ b/gthumb/gth-image-preloader.h
@@ -56,13 +56,13 @@ struct _GthImagePreloaderClass {
 
 	void  (* requested_ready)      (GthImagePreloader  *preloader,
 					GthFileData        *requested,
-					GdkPixbufAnimation *animation,
+					GthImage           *image,
 					int                 original_width,
 					int                 original_height,
 					GError             *error);
 	void  (* original_size_ready)  (GthImagePreloader  *preloader,
 					GthFileData        *requested,
-					GdkPixbufAnimation *animation,
+					GthImage           *image,
 					int                 original_width,
 					int                 original_height,
 					GError             *error);
diff --git a/gthumb/gth-image.c b/gthumb/gth-image.c
new file mode 100644
index 0000000..717e9ad
--- /dev/null
+++ b/gthumb/gth-image.c
@@ -0,0 +1,280 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ *  GThumb
+ *
+ *  Copyright (C) 2011 The Free Software Foundation, Inc.
+ *
+ *  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, see <http://www.gnu.org/licenses/>.
+ */
+
+#define GDK_PIXBUF_ENABLE_BACKEND 1
+
+#include <glib.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include "cairo-utils.h"
+#include "glib-utils.h"
+#include "gth-image.h"
+#include "pixbuf-utils.h"
+
+
+struct _GthImagePrivate {
+	GthImageFormat format;
+	union {
+		cairo_surface_t    *surface;
+		GdkPixbuf          *pixbuf;
+		GdkPixbufAnimation *pixbuf_animation;
+	} data;
+};
+
+
+static gpointer parent_class = NULL;
+
+
+static void
+_gth_image_free_data (GthImage *self)
+{
+	switch (self->priv->format) {
+	case GTH_IMAGE_FORMAT_CAIRO_SURFACE:
+		cairo_surface_destroy (self->priv->data.surface);
+		self->priv->data.surface = NULL;
+		break;
+
+	case GTH_IMAGE_FORMAT_GDK_PIXBUF:
+		_g_object_unref (self->priv->data.pixbuf);
+		self->priv->data.pixbuf = NULL;
+		break;
+
+	case GTH_IMAGE_FORMAT_GDK_PIXBUF_ANIMATION:
+		_g_object_unref (self->priv->data.pixbuf_animation);
+		self->priv->data.pixbuf_animation = NULL;
+		break;
+
+	default:
+		break;
+	}
+}
+
+
+static void
+gth_image_finalize (GObject *object)
+{
+	g_return_if_fail (object != NULL);
+	g_return_if_fail (GTH_IS_IMAGE (object));
+
+	_gth_image_free_data (GTH_IMAGE (object));
+
+	/* Chain up */
+	G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+
+static void
+gth_image_class_init (GthImageClass *class)
+{
+	GObjectClass *gobject_class;
+
+	parent_class = g_type_class_peek_parent (class);
+	g_type_class_add_private (class, sizeof (GthImagePrivate));
+
+	gobject_class = (GObjectClass*) class;
+	gobject_class->finalize = gth_image_finalize;
+}
+
+
+static void
+gth_image_instance_init (GthImage *self)
+{
+	self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GTH_TYPE_IMAGE, GthImagePrivate);
+	self->priv->format = GTH_IMAGE_FORMAT_CAIRO_SURFACE;
+	self->priv->data.surface = NULL;
+}
+
+
+GType
+gth_image_get_type (void)
+{
+	static GType type = 0;
+
+	if (! type) {
+		GTypeInfo type_info = {
+			sizeof (GthImageClass),
+			NULL,
+			NULL,
+			(GClassInitFunc) gth_image_class_init,
+			NULL,
+			NULL,
+			sizeof (GthImage),
+			0,
+			(GInstanceInitFunc) gth_image_instance_init
+		};
+
+		type = g_type_register_static (G_TYPE_OBJECT,
+					       "GthImage",
+					       &type_info,
+					       0);
+	}
+
+	return type;
+}
+
+
+GthImage *
+gth_image_new (void)
+{
+	return (GthImage *) g_object_new (GTH_TYPE_IMAGE, NULL);
+}
+
+
+void
+gth_image_set_cairo_surface (GthImage        *image,
+			     cairo_surface_t *value)
+{
+	_gth_image_free_data (image);
+	if (value == NULL)
+		return;
+
+	image->priv->format = GTH_IMAGE_FORMAT_CAIRO_SURFACE;
+	image->priv->data.surface = cairo_surface_reference (value);
+}
+
+
+cairo_surface_t *
+gth_image_get_cairo_surface (GthImage *image)
+{
+	cairo_surface_t *result = NULL;
+
+	switch (image->priv->format) {
+	case GTH_IMAGE_FORMAT_CAIRO_SURFACE:
+		result = cairo_surface_reference (image->priv->data.surface);
+		break;
+
+	case GTH_IMAGE_FORMAT_GDK_PIXBUF:
+		result = _cairo_image_surface_create_from_pixbuf (image->priv->data.pixbuf);
+		break;
+
+	case GTH_IMAGE_FORMAT_GDK_PIXBUF_ANIMATION:
+		if (image->priv->data.pixbuf_animation != NULL) {
+			GdkPixbuf *static_image;
+
+			static_image = gdk_pixbuf_animation_get_static_image (image->priv->data.pixbuf_animation);
+			result = _cairo_image_surface_create_from_pixbuf (static_image);
+		}
+		break;
+
+	default:
+		break;
+	}
+
+	return result;
+}
+
+
+void
+gth_image_set_pixbuf (GthImage  *image,
+		      GdkPixbuf *value)
+{
+	_gth_image_free_data (image);
+	if (value == NULL)
+		return;
+
+	image->priv->format = GTH_IMAGE_FORMAT_GDK_PIXBUF;
+	image->priv->data.pixbuf = g_object_ref (value);
+}
+
+
+GdkPixbuf *
+gth_image_get_pixbuf (GthImage *image)
+{
+	GdkPixbuf *result = NULL;
+
+	switch (image->priv->format) {
+	case GTH_IMAGE_FORMAT_CAIRO_SURFACE:
+		result = _gdk_pixbuf_new_from_cairo_surface (image->priv->data.surface);
+		break;
+
+	case GTH_IMAGE_FORMAT_GDK_PIXBUF:
+		result = g_object_ref (image->priv->data.pixbuf);
+		break;
+
+	case GTH_IMAGE_FORMAT_GDK_PIXBUF_ANIMATION:
+		if (image->priv->data.pixbuf_animation != NULL) {
+			GdkPixbuf *static_image;
+
+			static_image = gdk_pixbuf_animation_get_static_image (image->priv->data.pixbuf_animation);
+			if (static_image != NULL)
+				result = gdk_pixbuf_copy (static_image);
+		}
+		break;
+
+	default:
+		break;
+	}
+
+	return result;
+}
+
+
+void
+gth_image_set_pixbuf_animation (GthImage           *image,
+				GdkPixbufAnimation *value)
+{
+	_gth_image_free_data (image);
+	if (value == NULL)
+		return;
+
+	image->priv->format = GTH_IMAGE_FORMAT_GDK_PIXBUF_ANIMATION;
+	image->priv->data.pixbuf_animation = g_object_ref (value);
+}
+
+
+GdkPixbufAnimation *
+gth_image_get_pixbuf_animation (GthImage *image)
+{
+	GdkPixbufAnimation *result = NULL;
+
+	switch (image->priv->format) {
+	case GTH_IMAGE_FORMAT_CAIRO_SURFACE:
+		if (image->priv->data.surface != NULL) {
+			GdkPixbuf *pixbuf;
+
+			pixbuf = _gdk_pixbuf_new_from_cairo_surface (image->priv->data.surface);
+			result = gdk_pixbuf_non_anim_new (pixbuf);
+
+			g_object_unref (pixbuf);
+		}
+		break;
+
+	case GTH_IMAGE_FORMAT_GDK_PIXBUF:
+		result = gdk_pixbuf_non_anim_new (image->priv->data.pixbuf);
+		break;
+
+	case GTH_IMAGE_FORMAT_GDK_PIXBUF_ANIMATION:
+		result = _g_object_ref (image->priv->data.pixbuf);
+		break;
+
+	default:
+		break;
+	}
+
+	return result;
+}
+
+
+gboolean
+gth_image_is_animation (GthImage *image)
+{
+	return ((image->priv->format == GTH_IMAGE_FORMAT_GDK_PIXBUF_ANIMATION)
+	        && (! gdk_pixbuf_animation_is_static_image (image->priv->data.pixbuf_animation)));
+}
diff --git a/gthumb/gth-image.h b/gthumb/gth-image.h
new file mode 100644
index 0000000..9230a3d
--- /dev/null
+++ b/gthumb/gth-image.h
@@ -0,0 +1,86 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ *  GThumb
+ *
+ *  Copyright (C) 2011 The Free Software Foundation, Inc.
+ *
+ *  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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GTH_IMAGE_H
+#define GTH_IMAGE_H
+
+#include <glib.h>
+#include <glib-object.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include "gth-file-data.h"
+
+G_BEGIN_DECLS
+
+typedef enum {
+	GTH_IMAGE_FORMAT_CAIRO_SURFACE,
+	GTH_IMAGE_FORMAT_GDK_PIXBUF,
+	GTH_IMAGE_FORMAT_GDK_PIXBUF_ANIMATION,
+	GTH_IMAGE_N_FORMATS
+} GthImageFormat;
+
+#define GTH_TYPE_IMAGE            (gth_image_get_type ())
+#define GTH_IMAGE(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTH_TYPE_IMAGE, GthImage))
+#define GTH_IMAGE_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GTH_TYPE_IMAGE, GthImageClass))
+#define GTH_IS_IMAGE(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTH_TYPE_IMAGE))
+#define GTH_IS_IMAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTH_TYPE_IMAGE))
+#define GTH_IMAGE_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), GTH_TYPE_IMAGE, GthImageClass))
+
+typedef struct _GthImage         GthImage;
+typedef struct _GthImageClass    GthImageClass;
+typedef struct _GthImagePrivate  GthImagePrivate;
+
+struct _GthImage
+{
+	GObject __parent;
+	GthImagePrivate *priv;
+};
+
+struct _GthImageClass
+{
+	GObjectClass __parent_class;
+};
+
+
+typedef GthImage * (*GthImageLoaderFunc) (GthFileData   *file_data,
+					  int            requested_size,
+					  int           *original_width,
+					  int           *original_height,
+					  gpointer       user_data,
+					  GCancellable  *cancellable,
+					  GError       **error);
+
+
+GType                 gth_image_get_type              (void);
+GthImage *            gth_image_new                   (void);
+void                  gth_image_set_cairo_surface     (GthImage           *image,
+						       cairo_surface_t    *value);
+cairo_surface_t *     gth_image_get_cairo_surface     (GthImage           *image);
+void                  gth_image_set_pixbuf            (GthImage           *image,
+						       GdkPixbuf          *value);
+GdkPixbuf *           gth_image_get_pixbuf            (GthImage           *image);
+void                  gth_image_set_pixbuf_animation  (GthImage           *image,
+						       GdkPixbufAnimation *value);
+GdkPixbufAnimation *  gth_image_get_pixbuf_animation  (GthImage           *image);
+gboolean              gth_image_is_animation          (GthImage           *image);
+
+G_END_DECLS
+
+#endif /* GTH_IMAGE_H */
diff --git a/gthumb/gth-main-default-types.c b/gthumb/gth-main-default-types.c
index 511df17..037b301 100644
--- a/gthumb/gth-main-default-types.c
+++ b/gthumb/gth-main-default-types.c
@@ -44,7 +44,10 @@ gth_main_register_default_file_loader (void)
 
 		mime_types = gdk_pixbuf_format_get_mime_types (format);
 		for (i = 0; mime_types[i] != NULL; i++)
-			gth_main_register_pixbuf_loader (gth_pixbuf_animation_new_from_file, mime_types[i], NULL);
+			gth_main_register_image_loader_func (gth_pixbuf_animation_new_from_file,
+							     (g_content_type_is_a (mime_types[i], "image/gif") ? GTH_IMAGE_FORMAT_GDK_PIXBUF_ANIMATION : GTH_IMAGE_FORMAT_GDK_PIXBUF),
+							     mime_types[i],
+							     NULL);
 
 		g_strfreev (mime_types);
 	}
diff --git a/gthumb/gth-main.c b/gthumb/gth-main.c
index 23db90e..28ea727 100644
--- a/gthumb/gth-main.c
+++ b/gthumb/gth-main.c
@@ -104,7 +104,7 @@ struct _GthMainPrivate
 	GHashTable          *metadata_info_hash;
 	gboolean             metadata_info_sorted;
 	GHashTable          *sort_types;
-	GHashTable          *loaders;
+	GHashTable          *image_loaders;
 	GHashTable          *types;
 	GHashTable          *classes;
 	GHashTable          *objects_order;
@@ -135,8 +135,8 @@ gth_main_finalize (GObject *object)
 
 		if (gth_main->priv->sort_types != NULL)
 			g_hash_table_unref (gth_main->priv->sort_types);
-		if (gth_main->priv->loaders != NULL)
-			g_hash_table_unref (gth_main->priv->loaders);
+		if (gth_main->priv->image_loaders != NULL)
+			g_hash_table_unref (gth_main->priv->image_loaders);
 		if (gth_main->priv->types != NULL)
 			g_hash_table_unref (gth_main->priv->types);
 		if (gth_main->priv->classes != NULL)
@@ -175,11 +175,11 @@ static void
 gth_main_init (GthMain *main)
 {
 	main->priv = g_new0 (GthMainPrivate, 1);
-	main->priv->sort_types = g_hash_table_new_full (g_str_hash,
-							g_str_equal,
-							NULL,
-							NULL);
-	main->priv->loaders = g_hash_table_new (g_str_hash, (GEqualFunc) g_content_type_equals);
+	main->priv->sort_types = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, NULL);
+	main->priv->image_loaders = g_hash_table_new_full (g_str_hash,
+						           (GEqualFunc) g_content_type_equals,
+						           g_free,
+						           NULL);
 	main->priv->metadata_category = g_ptr_array_new ();
 	main->priv->metadata_info = g_ptr_array_new ();
 	main->priv->metadata_info_hash = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, NULL);
@@ -743,9 +743,10 @@ _gth_main_create_type_spec (GType       object_type,
 
 
 void
-gth_main_register_pixbuf_loader (PixbufLoader  loader,
-			         const char   *first_mime_type,
-			         ...)
+gth_main_register_image_loader_func (GthImageLoaderFunc  loader,
+				     GthImageFormat      native_format,
+				     const char         *first_mime_type,
+				     ...)
 {
 	va_list     var_args;
 	const char *mime_type;
@@ -755,7 +756,11 @@ gth_main_register_pixbuf_loader (PixbufLoader  loader,
 	va_start (var_args, first_mime_type);
 	mime_type = first_mime_type;
   	while (mime_type != NULL) {
-		g_hash_table_insert (Main->priv->loaders, (gpointer) get_static_string (g_content_type_from_mime_type (mime_type)), loader);
+  		char *key;
+
+  		key = g_strdup_printf ("%s-%d", mime_type, native_format);
+		g_hash_table_insert (Main->priv->image_loaders, (gpointer) key, loader);
+
 		mime_type = va_arg (var_args, const char *);
   	}
 	va_end (var_args);
@@ -764,13 +769,31 @@ gth_main_register_pixbuf_loader (PixbufLoader  loader,
 }
 
 
-PixbufLoader
-gth_main_get_pixbuf_loader (const char *mime_type)
+GthImageLoaderFunc
+gth_main_get_image_loader_func (const char     *mime_type,
+				GthImageFormat  preferred_format)
 {
-	if (mime_type != NULL)
-		return (PixbufLoader) g_hash_table_lookup (Main->priv->loaders, mime_type);
-	else
-		return NULL;
+	GthImageLoaderFunc  loader;
+	char               *key;
+	int                 format;
+
+	/* give priority to the preferred format */
+
+	key = g_strdup_printf ("%s-%d", mime_type, preferred_format);
+	loader = g_hash_table_lookup (Main->priv->image_loaders, key);
+
+	/* if the preferred format is not available, search another
+	 * format. */
+
+	for (format = 0; (loader == NULL) && (format < GTH_IMAGE_N_FORMATS); format++) {
+		g_free (key);
+		key = g_strdup_printf ("%s-%d", mime_type, format);
+		loader = g_hash_table_lookup (Main->priv->image_loaders, key);
+	}
+
+	g_free (key);
+
+	return loader;
 }
 
 
diff --git a/gthumb/gth-main.h b/gthumb/gth-main.h
index df7458c..00d6a01 100644
--- a/gthumb/gth-main.h
+++ b/gthumb/gth-main.h
@@ -30,6 +30,7 @@
 #include "gth-file-source.h"
 #include "gth-filter-file.h"
 #include "gth-hook.h"
+#include "gth-image.h"
 #include "gth-metadata-provider.h"
 #include "gth-monitor.h"
 #include "gth-pixbuf-saver.h"
@@ -85,10 +86,12 @@ GList *                gth_main_get_all_metadata_info         (void);
 void                   gth_main_register_sort_type            (GthFileDataSort      *sort_type);
 GthFileDataSort *      gth_main_get_sort_type                 (const char           *name);
 GList *                gth_main_get_all_sort_types            (void);
-void                   gth_main_register_pixbuf_loader        (PixbufLoader          loader,
+void                   gth_main_register_image_loader_func    (GthImageLoaderFunc    loader,
+							       GthImageFormat        native_format,
 						               const char           *first_mime_type,
 						               ...);
-PixbufLoader           gth_main_get_pixbuf_loader             (const char           *mime_type);
+GthImageLoaderFunc     gth_main_get_image_loader_func         (const char           *mime_type,
+							       GthImageFormat        preferred_format);
 GthPixbufSaver *       gth_main_get_pixbuf_saver              (const char           *mime_type);
 GthTest *              gth_main_get_general_filter            (void);
 GthTest *              gth_main_add_general_filter            (GthTest              *filter);
diff --git a/gthumb/gth-overwrite-dialog.c b/gthumb/gth-overwrite-dialog.c
index 607a2ac..e34ed37 100644
--- a/gthumb/gth-overwrite-dialog.c
+++ b/gthumb/gth-overwrite-dialog.c
@@ -124,19 +124,22 @@ image_loader_ready_cb (GObject      *source_object,
 {
 	GthOverwriteDialog *self = user_data;
 	GError             *error = NULL;
+	GthImage           *image;
 	GdkPixbuf          *pixbuf;
 	GtkWidget          *viewer;
 
-	if (! gth_image_loader_load_image_finish (GTH_IMAGE_LOADER (source_object),
-						  result,
-						  &pixbuf,
-						  NULL,
-						  NULL,
-						  &error))
+	if (! gth_image_loader_load_finish (GTH_IMAGE_LOADER (source_object),
+					    result,
+					    &image,
+					    NULL,
+					    NULL,
+					    &error))
 	{
 		return;
 	}
 
+	pixbuf = gth_image_get_pixbuf (image);
+
 	if (GTH_IMAGE_LOADER (source_object) == self->priv->old_image_loader)
 		viewer = self->priv->old_image_viewer;
 	else
@@ -144,6 +147,7 @@ image_loader_ready_cb (GObject      *source_object,
 	gth_image_viewer_set_pixbuf (GTH_IMAGE_VIEWER (viewer), pixbuf, -1, -1);
 
 	g_object_unref (pixbuf);
+	g_object_unref (image);
 }
 
 
diff --git a/gthumb/gth-thumb-loader.c b/gthumb/gth-thumb-loader.c
index 350724f..17e2c60 100644
--- a/gthumb/gth-thumb-loader.c
+++ b/gthumb/gth-thumb-loader.c
@@ -139,7 +139,7 @@ gth_thumb_loader_get_type (void)
 }
 
 
-static GdkPixbufAnimation *
+static GthImage *
 generate_thumbnail (GthFileData   *file_data,
 		    int            requested_size,
 		    int           *original_width,
@@ -148,10 +148,10 @@ generate_thumbnail (GthFileData   *file_data,
 		    GCancellable  *cancellable,
 		    GError       **error)
 {
-	GthThumbLoader     *self = user_data;
-	GdkPixbuf          *pixbuf = NULL;
-	GdkPixbufAnimation *animation;
-	char               *uri;
+	GthThumbLoader *self = user_data;
+	GdkPixbuf      *pixbuf = NULL;
+	GthImage       *image;
+	char           *uri;
 
 	if (original_width != NULL)
 		*original_width = -1;
@@ -159,7 +159,7 @@ generate_thumbnail (GthFileData   *file_data,
 	if (original_height != NULL)
 		*original_height = -1;
 
-	animation = NULL;
+	image = NULL;
 	uri = g_file_get_uri (file_data->file);
 	pixbuf = gnome_desktop_thumbnail_factory_generate_no_script (self->priv->thumb_factory,
 								     uri,
@@ -174,17 +174,17 @@ generate_thumbnail (GthFileData   *file_data,
 	}
 
 	if (pixbuf == NULL) {
-		PixbufLoader thumbnailer;
+		GthImageLoaderFunc thumbnailer;
 
-		thumbnailer = gth_main_get_pixbuf_loader (gth_file_data_get_mime_type (file_data));
+		thumbnailer = gth_main_get_image_loader_func (gth_file_data_get_mime_type (file_data), GTH_IMAGE_FORMAT_GDK_PIXBUF);
 		if (thumbnailer != NULL)
-			animation = thumbnailer (file_data,
-						 self->priv->cache_max_size,
-						 original_width,
-						 original_height,
-						 NULL,
-						 cancellable,
-						 error);
+			image = thumbnailer (file_data,
+					     self->priv->cache_max_size,
+					     original_width,
+					     original_height,
+					     NULL,
+					     cancellable,
+					     error);
 	}
 
 	if (pixbuf != NULL) {
@@ -195,21 +195,24 @@ generate_thumbnail (GthFileData   *file_data,
 
 		if (error != NULL)
 			g_clear_error (error);
-		animation = gdk_pixbuf_non_anim_new (pixbuf);
+
+		image = gth_image_new ();
+		gth_image_set_pixbuf (image, pixbuf);
+
 		g_object_unref (pixbuf);
 	}
 
-	if (animation == NULL)
+	if (image == NULL)
 		if (error != NULL)
 			*error = g_error_new_literal (GTH_ERROR, 0, "Cannot generate the thumbnail");
 
 	g_free (uri);
 
-	return animation;
+	return image;
 }
 
 
-static GdkPixbufAnimation *
+static GthImage *
 load_cached_thumbnail (GthFileData   *file_data,
 		       int            requested_size,
 		       int           *original_width,
@@ -218,20 +221,21 @@ load_cached_thumbnail (GthFileData   *file_data,
 		       GCancellable  *cancellable,
 		       GError       **error)
 {
-	GdkPixbufAnimation *animation = NULL;
-	char               *filename;
-	GdkPixbuf          *pixbuf;
+	GthImage  *image = NULL;
+	char      *filename;
+	GdkPixbuf *pixbuf;
 
 	filename = g_file_get_path (file_data->file);
 	pixbuf = gdk_pixbuf_new_from_file (filename, error);
 	if (pixbuf != NULL) {
-		animation = gdk_pixbuf_non_anim_new (pixbuf);
+		image = gth_image_new ();
+		gth_image_set_pixbuf (image, pixbuf);
 		g_object_unref (pixbuf);
 	}
 
 	g_free (filename);
 
-	return animation;
+	return image;
 }
 
 
@@ -258,8 +262,8 @@ gth_thumb_loader_new (int requested_size)
 
 
 void
-gth_thumb_loader_set_loader_func (GthThumbLoader *self,
-			          PixbufLoader    loader_func)
+gth_thumb_loader_set_loader_func (GthThumbLoader     *self,
+				  GthImageLoaderFunc  loader_func)
 {
 	gth_image_loader_set_loader_func (self->priv->tloader,
 					  (loader_func != NULL) ? loader_func : generate_thumbnail,
@@ -426,18 +430,19 @@ cache_image_ready_cb (GObject      *source_object,
 {
 	LoadData       *load_data = user_data;
 	GthThumbLoader *self = load_data->thumb_loader;
+	GthImage       *image;
 	GdkPixbuf      *pixbuf;
 	int             width;
 	int             height;
 	gboolean        modified;
 	LoadResult     *load_result;
 
-	if (! gth_image_loader_load_image_finish (GTH_IMAGE_LOADER (source_object),
-						  res,
-						  &pixbuf,
-						  NULL,
-						  NULL,
-						  NULL))
+	if (! gth_image_loader_load_finish (GTH_IMAGE_LOADER (source_object),
+					    res,
+					    &image,
+					    NULL,
+					    NULL,
+					    NULL))
 	{
 		/* error loading the thumbnail from the cache, try to generate
 		 * the thumbnail loading the original image. */
@@ -456,6 +461,8 @@ cache_image_ready_cb (GObject      *source_object,
 	/* Thumbnail correctly loaded from the cache. Scale if the user wants
 	 * a different size. */
 
+	pixbuf = gth_image_get_pixbuf (image);
+
 	g_return_if_fail (pixbuf != NULL);
 
 	width = gdk_pixbuf_get_width (pixbuf);
@@ -477,6 +484,7 @@ cache_image_ready_cb (GObject      *source_object,
 	g_simple_async_result_complete_in_idle (load_data->simple);
 
 	load_data_unref (load_data);
+	g_object_unref (image);
 }
 
 
@@ -729,15 +737,16 @@ original_image_ready_cb (GObject      *source_object,
 {
 	LoadData       *load_data = user_data;
 	GthThumbLoader *self = load_data->thumb_loader;
+	GthImage       *image;
 	GdkPixbuf      *pixbuf = NULL;
 	GError         *error = NULL;
 
-	if (! gth_image_loader_load_image_finish (GTH_IMAGE_LOADER (source_object),
-						  res,
-						  &pixbuf,
-						  NULL,
-						  NULL,
-						  &error))
+	if (! gth_image_loader_load_finish (GTH_IMAGE_LOADER (source_object),
+					    res,
+					    &image,
+					    NULL,
+					    NULL,
+					    &error))
 	{
 		/* error loading the original image, try with the system
 		 * thumbnailer */
@@ -781,9 +790,11 @@ original_image_ready_cb (GObject      *source_object,
 		return;
 	}
 
+	pixbuf = gth_image_get_pixbuf (image);
 	original_image_loaded_correctly (self, load_data, pixbuf);
 
 	g_object_unref (pixbuf);
+	g_object_unref (image);
 	load_data_unref (load_data);
 }
 
diff --git a/gthumb/gth-thumb-loader.h b/gthumb/gth-thumb-loader.h
index ef40bc7..56f8c21 100644
--- a/gthumb/gth-thumb-loader.h
+++ b/gthumb/gth-thumb-loader.h
@@ -55,7 +55,7 @@ struct _GthThumbLoaderClass
 GType             gth_thumb_loader_get_type             (void);
 GthThumbLoader *  gth_thumb_loader_new                  (int                   requested_size);
 void              gth_thumb_loader_set_loader_func      (GthThumbLoader       *self,
-						         PixbufLoader          loader_func);
+							 GthImageLoaderFunc    loader_func);
 void              gth_thumb_loader_set_requested_size   (GthThumbLoader       *self,
 					                 int                   size);
 int               gth_thumb_loader_get_requested_size   (GthThumbLoader       *self);
diff --git a/gthumb/pixbuf-io.c b/gthumb/pixbuf-io.c
index 5567dae..9610ad0 100644
--- a/gthumb/pixbuf-io.c
+++ b/gthumb/pixbuf-io.c
@@ -334,7 +334,7 @@ pixbuf_loader_size_prepared_cb (GdkPixbufLoader *loader,
 #endif
 
 
-GdkPixbuf *
+GthImage *
 gth_pixbuf_new_from_file (GthFileData   *file_data,
 			  int            requested_size,
 			  int           *original_width,
@@ -344,6 +344,7 @@ gth_pixbuf_new_from_file (GthFileData   *file_data,
 			  GError       **error)
 {
 #ifndef USE_PIXBUF_LOADER
+	GthImage  *image;
 	GdkPixbuf *pixbuf = NULL;
 	char      *path;
 	gboolean   scale_pixbuf;
@@ -402,7 +403,12 @@ gth_pixbuf_new_from_file (GthFileData   *file_data,
 
 	g_free (path);
 
-	return pixbuf;
+	image = gth_image_new ();
+	gth_image_set_pixbuf (image, pixbuf);
+
+	g_object_unref (pixbuf);
+
+	return image;
 
 #else
 
@@ -471,7 +477,7 @@ gth_pixbuf_new_from_file (GthFileData   *file_data,
 }
 
 
-GdkPixbufAnimation *
+GthImage *
 gth_pixbuf_animation_new_from_file (GthFileData   *file_data,
 				    int            requested_size,
 				    int           *original_width,
@@ -480,40 +486,35 @@ gth_pixbuf_animation_new_from_file (GthFileData   *file_data,
 				    GCancellable  *cancellable,
 				    GError       **error)
 {
-	GdkPixbufAnimation *animation = NULL;
-	const char         *mime_type;
+	GthImage   *image = NULL;
+	const char *mime_type;
 
 	mime_type = gth_file_data_get_mime_type (file_data);
 	if (mime_type == NULL)
 		return NULL;
 
 	if (g_content_type_equals (mime_type, "image/gif")) {
-		char *path;
+		GdkPixbufAnimation *animation;
+		char               *path;
 
 		path = g_file_get_path (file_data->file);
 		if (path != NULL)
 			animation = gdk_pixbuf_animation_new_from_file (path, error);
 
-		g_free (path);
+		image = gth_image_new ();
+		gth_image_set_pixbuf_animation (image, animation);
 
-		return animation;
-	}
-	else {
-		GdkPixbuf *pixbuf;
-
-		pixbuf = gth_pixbuf_new_from_file (file_data,
-						   requested_size,
-						   original_width,
-						   original_height,
-						   FALSE,
-						   cancellable,
-						   error);
-
-		if (pixbuf != NULL) {
-			animation = gdk_pixbuf_non_anim_new (pixbuf);
-			g_object_unref (pixbuf);
-		}
+		g_object_unref (animation);
+		g_free (path);
 	}
-
-	return animation;
+	else
+		image = gth_pixbuf_new_from_file (file_data,
+						  requested_size,
+						  original_width,
+						  original_height,
+						  FALSE,
+						  cancellable,
+						  error);
+
+	return image;
 }
diff --git a/gthumb/pixbuf-io.h b/gthumb/pixbuf-io.h
index 8ff6af0..d4bacc6 100644
--- a/gthumb/pixbuf-io.h
+++ b/gthumb/pixbuf-io.h
@@ -63,15 +63,14 @@ void        _gdk_pixbuf_save_async             (GdkPixbuf        *pixbuf,
 						gboolean          replace,
 						GthFileDataFunc   ready_func,
 						gpointer          data);
-GdkPixbuf * gth_pixbuf_new_from_file           (GthFileData      *file,
+GthImage  * gth_pixbuf_new_from_file           (GthFileData      *file,
 						int               requested_size,
 						int              *original_width,
 						int              *original_height,
 						gboolean          scale_to_original,
 						GCancellable     *cancellable,
 						GError          **error);
-GdkPixbufAnimation *
-	    gth_pixbuf_animation_new_from_file (GthFileData      *file_data,
+GthImage *  gth_pixbuf_animation_new_from_file (GthFileData      *file_data,
 						int               requested_size,
 						int              *original_width,
 						int              *original_height,



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