[gthumb: 27/40] check the thumbnail validity without loading the pixbuf



commit dc71ddb3cb4e0d325d980f7f7c256c6ce8d1272e
Author: Paolo Bacchilega <paobac src gnome org>
Date:   Thu Sep 9 16:14:26 2010 +0200

    check the thumbnail validity without loading the pixbuf

 configure.ac                     |    1 +
 gthumb/gnome-desktop-thumbnail.c |  261 ++++++++++++++++++++++++--------------
 gthumb/gnome-desktop-thumbnail.h |    2 +-
 gthumb/gth-thumb-loader.c        |   75 +++++++++--
 gthumb/gth-thumb-loader.h        |    4 +
 5 files changed, 236 insertions(+), 107 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 609ad1c..a5a1b1f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -135,6 +135,7 @@ PKG_CHECK_MODULES(GTHUMB, [
 	gtk+-2.0 		>= $GTK_REQUIRED
 	gconf-2.0 		>= $GCONF_REQUIRED
 	unique-1.0		>= $UNIQUE_REQUIRED
+	libpng
 ])
 AC_SUBST(GTHUMB_LIBS)
 AC_SUBST(GTHUMB_CFLAGS)
diff --git a/gthumb/gnome-desktop-thumbnail.c b/gthumb/gnome-desktop-thumbnail.c
index 83ab309..50d2e18 100644
--- a/gthumb/gnome-desktop-thumbnail.c
+++ b/gthumb/gnome-desktop-thumbnail.c
@@ -55,6 +55,7 @@
 #include <string.h>
 #include <glib.h>
 #include <stdio.h>
+#include <png.h>
 #define GDK_PIXBUF_ENABLE_BACKEND
 #include <gdk-pixbuf/gdk-pixbuf.h>
 #include <gconf/gconf.h>
@@ -524,50 +525,38 @@ gnome_desktop_thumbnail_factory_new (GnomeDesktopThumbnailSize size)
  **/
 char *
 gnome_desktop_thumbnail_factory_lookup (GnomeDesktopThumbnailFactory *factory,
-					const char            *uri,
-					time_t                 mtime)
+					const char                   *uri,
+					time_t                        mtime)
 {
-  GnomeDesktopThumbnailFactoryPrivate *priv = factory->priv;
-  char *path, *file;
-  GChecksum *checksum;
-  guint8 digest[16];
-  gsize digest_len = sizeof (digest);
-  GdkPixbuf *pixbuf;
-  gboolean res;
-
-  g_return_val_if_fail (uri != NULL, NULL);
-
-  res = FALSE;
-
-  checksum = g_checksum_new (G_CHECKSUM_MD5);
-  g_checksum_update (checksum, (const guchar *) uri, strlen (uri));
+	GChecksum *checksum;
+	guint8     digest[16];
+	gsize      digest_len = sizeof (digest);
+	char      *file;
+	char      *path;
 
-  g_checksum_get_digest (checksum, digest, &digest_len);
-  g_assert (digest_len == 16);
+	g_return_val_if_fail (uri != NULL, NULL);
 
-  file = g_strconcat (g_checksum_get_string (checksum), ".png", NULL);
+	checksum = g_checksum_new (G_CHECKSUM_MD5);
+	g_checksum_update (checksum, (const guchar *) uri, strlen (uri));
+	g_checksum_get_digest (checksum, digest, &digest_len);
+	g_assert (digest_len == 16);
 
-  path = g_build_filename (g_get_home_dir (),
-			   ".thumbnails",
-			   (priv->size == GNOME_DESKTOP_THUMBNAIL_SIZE_NORMAL)?"normal":"large",
-			   file,
-			   NULL);
-  g_free (file);
-
-  pixbuf = gdk_pixbuf_new_from_file (path, NULL);
-  if (pixbuf != NULL)
-    {
-      res = gnome_desktop_thumbnail_is_valid (pixbuf, uri, mtime);
-      g_object_unref (pixbuf);
-    }
+	file = g_strconcat (g_checksum_get_string (checksum), ".png", NULL);
+	path = g_build_filename (g_get_home_dir (),
+				 ".thumbnails",
+				 (factory->priv->size == GNOME_DESKTOP_THUMBNAIL_SIZE_NORMAL)?"normal":"large",
+				 file,
+				 NULL);
 
-  g_checksum_free (checksum);
+	if (! gnome_desktop_thumbnail_is_valid (path, uri, mtime)) {
+		g_free (path);
+		path = NULL;
+	}
 
-  if (res)
-    return path;
+	g_free (file);
+	g_checksum_free (checksum);
 
-  g_free (path);
-  return FALSE;
+	return path;
 }
 
 /**
@@ -588,45 +577,34 @@ gnome_desktop_thumbnail_factory_lookup (GnomeDesktopThumbnailFactory *factory,
  **/
 gboolean
 gnome_desktop_thumbnail_factory_has_valid_failed_thumbnail (GnomeDesktopThumbnailFactory *factory,
-							    const char            *uri,
-							    time_t                 mtime)
+							    const char                   *uri,
+							    time_t                        mtime)
 {
-  char *path, *file;
-  GdkPixbuf *pixbuf;
-  gboolean res;
-  GChecksum *checksum;
-  guint8 digest[16];
-  gsize digest_len = sizeof (digest);
-
-  checksum = g_checksum_new (G_CHECKSUM_MD5);
-  g_checksum_update (checksum, (const guchar *) uri, strlen (uri));
-
-  g_checksum_get_digest (checksum, digest, &digest_len);
-  g_assert (digest_len == 16);
-
-  res = FALSE;
-
-  file = g_strconcat (g_checksum_get_string (checksum), ".png", NULL);
-
-  path = g_build_filename (g_get_home_dir (),
-			   ".thumbnails/fail",
-			   appname,
-			   file,
-			   NULL);
-  g_free (file);
-
-  pixbuf = gdk_pixbuf_new_from_file (path, NULL);
-  g_free (path);
-
-  if (pixbuf)
-    {
-      res = gnome_desktop_thumbnail_is_valid (pixbuf, uri, mtime);
-      g_object_unref (pixbuf);
-    }
+	GChecksum *checksum;
+	guint8     digest[16];
+	gsize      digest_len = sizeof (digest);
+	char      *path;
+	char      *file;
+	gboolean   res;
+
+	checksum = g_checksum_new (G_CHECKSUM_MD5);
+	g_checksum_update (checksum, (const guchar *) uri, strlen (uri));
+	g_checksum_get_digest (checksum, digest, &digest_len);
+	g_assert (digest_len == 16);
+
+	file = g_strconcat (g_checksum_get_string (checksum), ".png", NULL);
+	path = g_build_filename (g_get_home_dir (),
+				 ".thumbnails/fail",
+				 appname,
+				 file,
+				 NULL);
+	res = gnome_desktop_thumbnail_is_valid (path, uri, mtime);
 
-  g_checksum_free (checksum);
+	g_free (path);
+	g_free (file);
+	g_checksum_free (checksum);
 
-  return res;
+	return res;
 }
 
 static char *
@@ -1200,9 +1178,104 @@ gnome_desktop_thumbnail_path_for_uri (const char         *uri,
 }
 
 
+/* This function taken from gdk-pixbuf:
+ *
+ * Copyright (C) 1999 Mark Crichton
+ * Copyright (C) 1999 The Free Software Foundation
+ *
+ * Authors: Mark Crichton <crichton gimp org>
+ *          Federico Mena-Quintero <federico gimp org>
+ *
+ * Released under the LGPL version 2 of the License,
+ * or (at your option) any later version.
+ *
+ **/
+static gboolean
+png_text_to_pixbuf_option (png_text   text_ptr,
+                           gchar    **key,
+                           gchar    **value)
+{
+        gboolean is_ascii = TRUE;
+        int i;
+
+        /* Avoid loading iconv if the text is plain ASCII */
+        for (i = 0; i < text_ptr.text_length; i++)
+                if (text_ptr.text[i] & 0x80) {
+                        is_ascii = FALSE;
+                        break;
+                }
+
+        if (is_ascii) {
+                *value = g_strdup (text_ptr.text);
+        } else {
+                *value = g_convert (text_ptr.text, -1,
+                                     "UTF-8", "ISO-8859-1",
+                                     NULL, NULL, NULL);
+        }
+
+        if (*value) {
+                *key = g_strconcat ("tEXt::", text_ptr.key, NULL);
+                return TRUE;
+        } else {
+                g_warning ("Couldn't convert text chunk value to UTF-8.");
+                *key = NULL;
+                return FALSE;
+        }
+}
+
+
+static GHashTable *
+read_png_options (const char *thumbnail_filename)
+{
+	GHashTable  *options;
+	png_structp  png_ptr;
+        png_infop    info_ptr;
+        FILE        *f;
+        png_textp    text_ptr;
+	int          num_texts;
+
+	options = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+
+	png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+	if (png_ptr == NULL)
+		return options;
+
+	info_ptr = png_create_info_struct (png_ptr);
+	if (info_ptr == NULL) {
+		png_destroy_read_struct (&png_ptr, NULL, NULL);
+		return options;
+	}
+
+	f = fopen (thumbnail_filename, "r");
+	if (f == NULL) {
+		png_destroy_read_struct (&png_ptr, NULL, NULL);
+		return options;
+	}
+
+	png_init_io (png_ptr, f);
+	png_read_info (png_ptr, info_ptr);
+
+	if (png_get_text (png_ptr, info_ptr, &text_ptr, &num_texts)) {
+		int i;
+		for (i = 0; i < num_texts; i++) {
+			char *key;
+			char *value;
+
+			if (png_text_to_pixbuf_option (text_ptr[i], &key, &value))
+				g_hash_table_insert (options, key, value);
+		}
+	}
+
+	png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
+	fclose (f);
+
+	return options;
+}
+
+
 /**
  * gnome_desktop_thumbnail_is_valid:
- * @pixbuf: an loaded thumbnail #GdkPixbuf
+ * @thumbnail_filename: the png file that contains the thumbnail
  * @uri: a uri
  * @mtime: the mtime
  *
@@ -1214,25 +1287,25 @@ gnome_desktop_thumbnail_path_for_uri (const char         *uri,
  * Since: 2.2
  **/
 gboolean
-gnome_desktop_thumbnail_is_valid (GdkPixbuf          *pixbuf,
-				  const char         *uri,
-				  time_t              mtime)
+gnome_desktop_thumbnail_is_valid (const char *thumbnail_filename,
+				  const char *uri,
+				  time_t      mtime)
 {
-  const char *thumb_uri, *thumb_mtime_str;
-  time_t thumb_mtime;
-
-  thumb_uri = gdk_pixbuf_get_option (pixbuf, "tEXt::Thumb::URI");
-  if (!thumb_uri)
-    return FALSE;
-  if (strcmp (uri, thumb_uri) != 0)
-    return FALSE;
-
-  thumb_mtime_str = gdk_pixbuf_get_option (pixbuf, "tEXt::Thumb::MTime");
-  if (!thumb_mtime_str)
-    return FALSE;
-  thumb_mtime = atol (thumb_mtime_str);
-  if (mtime != thumb_mtime)
-    return FALSE;
-
-  return TRUE;
+	gboolean    is_valid = FALSE;
+	GHashTable *png_options;
+	const char *thumb_uri;
+
+	png_options = read_png_options (thumbnail_filename);
+	thumb_uri = g_hash_table_lookup (png_options, "tEXt::Thumb::URI");
+	if (g_strcmp0 (uri, thumb_uri) == 0) {
+		const char *thumb_mtime_str;
+
+		thumb_mtime_str = g_hash_table_lookup (png_options, "tEXt::Thumb::MTime");
+		if ((thumb_mtime_str != NULL) && (mtime == atol (thumb_mtime_str)))
+			is_valid = TRUE;
+	}
+
+	g_hash_table_unref (png_options);
+
+	return is_valid;
 }
diff --git a/gthumb/gnome-desktop-thumbnail.h b/gthumb/gnome-desktop-thumbnail.h
index b1b096b..c86f187 100644
--- a/gthumb/gnome-desktop-thumbnail.h
+++ b/gthumb/gnome-desktop-thumbnail.h
@@ -108,7 +108,7 @@ void                   gnome_desktop_thumbnail_factory_create_failed_thumbnail (
 										time_t                 mtime);
 
 /* Thumbnailing utils: */
-gboolean   gnome_desktop_thumbnail_is_valid          (GdkPixbuf          *pixbuf,
+gboolean   gnome_desktop_thumbnail_is_valid          (const char         *thumbnail_filename,
 						      const char         *uri,
 						      time_t              mtime);
 char *     gnome_desktop_thumbnail_md5               (const char         *uri);
diff --git a/gthumb/gth-thumb-loader.c b/gthumb/gth-thumb-loader.c
index 5e36e39..a9ddb8c 100644
--- a/gthumb/gth-thumb-loader.c
+++ b/gthumb/gth-thumb-loader.c
@@ -428,6 +428,8 @@ cache_image_ready_cb (GObject      *source_object,
 	load_result->pixbuf = pixbuf;
 	g_simple_async_result_set_op_res_gpointer (load_data->simple, load_result, (GDestroyNotify) load_result_unref);
 	g_simple_async_result_complete_in_idle (load_data->simple);
+
+	load_data_unref (load_data);
 }
 
 
@@ -691,8 +693,10 @@ original_image_ready_cb (GObject      *source_object,
 								      check_cancellable_cb,
 								      load_data);
 		}
-		else
+		else {
 			failed_to_load_original_image (self, load_data);
+			load_data_unref (load_data);
+		}
 
 		g_free (uri);
 
@@ -700,7 +704,9 @@ original_image_ready_cb (GObject      *source_object,
 	}
 
 	original_image_loaded_correctly (self, load_data, pixbuf);
+
 	g_object_unref (pixbuf);
+	load_data_unref (load_data);
 }
 
 
@@ -746,6 +752,21 @@ gth_thumb_loader_load (GthThumbLoader      *self,
 		g_free (uri);
 	}
 
+	if ((cache_path == NULL)
+	    && (self->priv->max_file_size > 0)
+	    && (g_file_info_get_size (file_data->info) > self->priv->max_file_size))
+	{
+		GError *error;
+
+		error = g_error_new_literal (GTH_ERROR, 0, "file too big to generate the thumbnail");
+		g_simple_async_result_set_from_error (simple, error);
+		g_simple_async_result_complete_in_idle (simple);
+
+		g_error_free (error);
+
+		return;
+	}
+
 	load_data = load_data_new (file_data, self->priv->requested_size);
 	load_data->thumb_loader = g_object_ref (self);
 	load_data->cancellable = _g_object_ref (cancellable);
@@ -769,17 +790,6 @@ gth_thumb_loader_load (GthThumbLoader      *self,
 		g_object_unref (cache_file);
 		g_free (cache_path);
 	}
-	else if ((self->priv->max_file_size > 0) && (g_file_info_get_size (file_data->info) > self->priv->max_file_size)) {
-		GError *error;
-
-		load_data_unref (load_data);
-
-		error = g_error_new_literal (GTH_ERROR, 0, "file too big to generate the thumbnail");
-		g_simple_async_result_set_from_error (simple, error);
-		g_simple_async_result_complete_in_idle (simple);
-
-		g_error_free (error);
-	}
 	else
 		gth_image_loader_load (self->priv->tloader,
 				       file_data,
@@ -812,3 +822,44 @@ gth_thumb_loader_load_finish (GthThumbLoader  *self,
 
 	return TRUE;
 }
+
+
+gboolean
+gth_thumb_loader_has_valid_thumbnail (GthThumbLoader *self,
+				      GthFileData    *file_data)
+{
+	gboolean  valid_thumbnail = FALSE;
+	char     *uri;
+	time_t    mtime;
+	char     *thumbnail_path;
+
+	uri = g_file_get_uri (file_data->file);
+	mtime = gth_file_data_get_mtime (file_data);
+	thumbnail_path = gnome_desktop_thumbnail_factory_lookup (self->priv->thumb_factory, uri, mtime);
+	if (thumbnail_path != NULL) {
+		valid_thumbnail = TRUE;
+		g_free (thumbnail_path);
+	}
+
+	g_free (uri);
+
+	return valid_thumbnail;
+}
+
+
+gboolean
+gth_thumb_loader_has_failed_thumbnail (GthThumbLoader *self,
+				       GthFileData    *file_data)
+{
+	char     *uri;
+	time_t    mtime;
+	gboolean  valid_thumbnail;
+
+	uri = g_file_get_uri (file_data->file);
+	mtime = gth_file_data_get_mtime (file_data);
+	valid_thumbnail = gnome_desktop_thumbnail_factory_has_valid_failed_thumbnail (self->priv->thumb_factory, uri, mtime);
+
+	g_free (uri);
+
+	return valid_thumbnail;
+}
diff --git a/gthumb/gth-thumb-loader.h b/gthumb/gth-thumb-loader.h
index a441130..ef40bc7 100644
--- a/gthumb/gth-thumb-loader.h
+++ b/gthumb/gth-thumb-loader.h
@@ -74,6 +74,10 @@ gboolean          gth_thumb_loader_load_finish          (GthThumbLoader       *s
 						  	 GAsyncResult         *res,
 							 GdkPixbuf           **pixbuf,
 							 GError              **error);
+gboolean          gth_thumb_loader_has_valid_thumbnail  (GthThumbLoader       *self,
+				      	      	         GthFileData          *file_data);
+gboolean          gth_thumb_loader_has_failed_thumbnail (GthThumbLoader       *self,
+				      	      	         GthFileData          *file_data);
 
 G_END_DECLS
 



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