Re: [PATCH] Use GdkPixbufLoader for thumbnailer to reduce memory consumption



Am Donnerstag, den 11.05.2006, 16:50 +0200 schrieb Alexander Larsson:
> On Sun, 2006-04-30 at 13:13 +0200, Christian Neumair wrote:
> > > The framing logic isn't the same as before. There are certain images
> > > that get a frame now that didn't before and vice versa. Totem thumbnails
> > > at low zoom levels didn't get one before but do now. Some images in
> > > ~/backgrounds don't get a frame anymore at low zoom now, but did before.
> > > I think the size comparison in
> > > 
> > > > +if ((is_thumbnail || size > NAUTILUS_ICON_SIZE_THUMBNAIL) && !
> > > > gdk_pixbuf_get_has_alpha (pixbuf)) {
> > > 
> > > doesn't do the same as it did before because the pixmap has already been
> > > scaled at that point now.
> > 
> > To be honest I don't understand why we're adding frames to pixbufs that
> > don't come from ~/.thumbnails at all.
> 
> Why should how we implement thumbnailing of image files affect how they
> are shown? That is just an implementation detail. The difference between
> thumbnail-as-itself and real thumbnail very non-obvious to users.

I see. I added code to correctly compare the original image size instead
of the pixbuf size against NAUTILUS_ICON_SIZE_THUMBNAIL.

-- 
Christian Neumair <chris gnome-de org>
Index: libnautilus-private/nautilus-icon-factory.c
===================================================================
RCS file: /cvs/gnome/nautilus/libnautilus-private/nautilus-icon-factory.c,v
retrieving revision 1.326
diff -u -p -r1.326 nautilus-icon-factory.c
--- libnautilus-private/nautilus-icon-factory.c	18 Apr 2006 16:54:31 -0000	1.326
+++ libnautilus-private/nautilus-icon-factory.c	24 May 2006 20:12:26 -0000
@@ -1122,30 +1122,6 @@ path_represents_svg_image (const char *p
 }
 
 static GdkPixbuf *
-scale_icon (GdkPixbuf *pixbuf,
-	    double *scale)
-{
-	guint width, height;
-
-	width = gdk_pixbuf_get_width (pixbuf);
-	height = gdk_pixbuf_get_height (pixbuf);
-
-	if ((int) (width * *scale) > NAUTILUS_ICON_MAXIMUM_SIZE ||
-	    (int) (height * *scale) > NAUTILUS_ICON_MAXIMUM_SIZE) {
-		*scale = MIN ((double) NAUTILUS_ICON_MAXIMUM_SIZE / width,
-			      (double) NAUTILUS_ICON_MAXIMUM_SIZE / height);
-	}
-
-	width = floor (width * *scale + 0.5);
-	height = floor (height * *scale + 0.5);
-	
-	return gdk_pixbuf_scale_simple (pixbuf,
-					width == 0 ? 1 : width,
-					height == 0 ? 1 : height,
-					GDK_INTERP_BILINEAR);
-}
-
-static GdkPixbuf *
 load_icon_file (const char    *filename,
 		guint          base_size,
 		guint          nominal_size,
@@ -1153,11 +1129,10 @@ load_icon_file (const char    *filename,
 		double        *scale_x,
 		double        *scale_y)
 {
-	GdkPixbuf *pixbuf, *scaled_pixbuf;
-	int width, height, size;
-	double scale;
-	gboolean is_thumbnail;
-        gboolean add_frame = FALSE;
+	GdkPixbuf *pixbuf;
+	gboolean add_frame;
+
+	add_frame = FALSE;
 
 	*scale_x = 1.0;
 	*scale_y = 1.0;
@@ -1168,59 +1143,36 @@ load_icon_file (const char    *filename,
 					  force_nominal ? 0 : base_size,
 					  scale_x, scale_y);
 	} else {
-		is_thumbnail = strstr (filename, "/.thumbnails/")  != NULL;
+		int original_size;
+		gboolean is_thumbnail;
 
 		/* FIXME: Maybe we shouldn't have to load the file each time
 		 * Not sure if that is important */
-		if (is_thumbnail) {
-			pixbuf = nautilus_thumbnail_load_framed_image (filename);
-		} else {
-			pixbuf = gdk_pixbuf_new_from_file (filename, NULL);
-		}
+		pixbuf = nautilus_thumbnail_load_image (filename,
+							base_size,
+							nominal_size,
+							force_nominal,
+							scale_x,
+							scale_y);
 
 		if (pixbuf == NULL) {
 			return NULL;
 		}
-		
-		if (force_nominal) {
-			width = gdk_pixbuf_get_width (pixbuf); 
-			height = gdk_pixbuf_get_height (pixbuf);
-			base_size = MAX (width, height);                        
-		} else if (base_size == 0) {
-			if (is_thumbnail) {
-				base_size = 128 * NAUTILUS_ICON_SIZE_STANDARD / NAUTILUS_ICON_SIZE_THUMBNAIL;
-			} else {
-				width = gdk_pixbuf_get_width (pixbuf); 
-				height = gdk_pixbuf_get_height (pixbuf);
-				size = MAX (width, height);
-                                if (size > NAUTILUS_ICON_SIZE_THUMBNAIL && !gdk_pixbuf_get_has_alpha(pixbuf)) {
-                                        add_frame=TRUE;
-                                }
-                                if (size >  nominal_size * NAUTILUS_ICON_SIZE_THUMBNAIL / NAUTILUS_ICON_SIZE_STANDARD) {
-                                        base_size = size * NAUTILUS_ICON_SIZE_STANDARD / NAUTILUS_ICON_SIZE_THUMBNAIL;
-                                }
-                                else if (size > NAUTILUS_ICON_SIZE_STANDARD) {
-					base_size = nominal_size;
-				} else {
-					/* Don't scale up small icons */
-					base_size = NAUTILUS_ICON_SIZE_STANDARD;
-				}
-			}
-		}
-		
-		if (base_size != nominal_size) {
-			scale = (double)nominal_size/base_size;
-			scaled_pixbuf = scale_icon (pixbuf, &scale);
-			*scale_x = scale;
-			*scale_y = scale;
-			g_object_unref (pixbuf);
-			pixbuf = scaled_pixbuf;
+
+		is_thumbnail = strstr (filename, "/.thumbnails/") != NULL;
+
+		original_size = ceil (MAX (gdk_pixbuf_get_width (pixbuf) / *scale_x, gdk_pixbuf_get_height (pixbuf) / *scale_y));
+
+		if ((is_thumbnail || (!force_nominal && base_size == 0 && original_size > NAUTILUS_ICON_SIZE_THUMBNAIL))
+		     && !gdk_pixbuf_get_has_alpha (pixbuf)) {
+			add_frame = TRUE;
 		}
 	}
 
-        if (add_frame){
-                nautilus_thumbnail_frame_image(&pixbuf);
-        }
+	if (add_frame) {
+		nautilus_thumbnail_frame_image(&pixbuf);
+	}
+
 	return pixbuf;
 }
 
Index: libnautilus-private/nautilus-thumbnails.c
===================================================================
RCS file: /cvs/gnome/nautilus/libnautilus-private/nautilus-thumbnails.c,v
retrieving revision 1.56
diff -u -p -r1.56 nautilus-thumbnails.c
--- libnautilus-private/nautilus-thumbnails.c	23 Nov 2005 13:29:34 -0000	1.56
+++ libnautilus-private/nautilus-thumbnails.c	24 May 2006 20:12:27 -0000
@@ -30,6 +30,7 @@
 #include "nautilus-global-preferences.h"
 #include "nautilus-icon-factory-private.h"
 #include "nautilus-icon-factory.h"
+#include <math.h>
 #include <eel/eel-gdk-pixbuf-extensions.h>
 #include <eel/eel-graphic-effects.h>
 #include <eel/eel-string.h>
@@ -263,22 +264,145 @@ nautilus_thumbnail_frame_image (GdkPixbu
 	*pixbuf=pixbuf_with_frame;
 }
 
-/* routine to load an image from the passed-in path, and then embed it in
- * a frame if necessary
+typedef struct {
+	gboolean is_thumbnail;
+	guint base_size;
+	guint nominal_size;
+	gboolean force_nominal;
+	int original_height;
+	int original_width;
+	double *scale_x_out;
+	double *scale_y_out;
+} ThumbnailLoadArgs;
+
+static void
+thumbnail_loader_size_prepared (GdkPixbufLoader *loader,
+				int width,
+				int height,
+				ThumbnailLoadArgs *args)
+{
+	int size = MAX (width, height);
+
+	args->original_width = width;
+	args->original_height = height;
+
+	if (args->force_nominal) {
+		args->base_size = MAX (width, height);                        
+	} else if (args->base_size == 0) {
+		if (args->is_thumbnail) {
+			args->base_size = 128 * NAUTILUS_ICON_SIZE_STANDARD / NAUTILUS_ICON_SIZE_THUMBNAIL;
+		} else {
+			if (size > args->nominal_size * NAUTILUS_ICON_SIZE_THUMBNAIL / NAUTILUS_ICON_SIZE_STANDARD) {
+				args->base_size = size * NAUTILUS_ICON_SIZE_STANDARD / NAUTILUS_ICON_SIZE_THUMBNAIL;
+			} else if (size > NAUTILUS_ICON_SIZE_STANDARD) {
+				args->base_size = args->nominal_size;
+			} else {
+				/* Don't scale up small icons */
+				args->base_size = NAUTILUS_ICON_SIZE_STANDARD;
+			}
+		}
+	}
+
+	if (args->base_size != args->nominal_size) {
+		double scale;
+
+		scale = (double) args->nominal_size / args->base_size;
+
+		if ((int) (width * scale) > NAUTILUS_ICON_MAXIMUM_SIZE ||
+		    (int) (height * scale) > NAUTILUS_ICON_MAXIMUM_SIZE) {
+			scale = MIN ((double) NAUTILUS_ICON_MAXIMUM_SIZE / width,
+				     (double) NAUTILUS_ICON_MAXIMUM_SIZE / height);
+		}
+
+		width = MAX (1, floor (width * scale + 0.5));
+		height = MAX (1, floor (height * scale + 0.5));
+
+		gdk_pixbuf_loader_set_size (loader, width, height);
+	}
+
+}
+
+static void
+thumbnail_loader_area_prepared (GdkPixbufLoader *loader,
+				ThumbnailLoadArgs *args)
+{
+	GdkPixbuf *pixbuf;
+
+	pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
+
+	*args->scale_x_out = (double) gdk_pixbuf_get_width (pixbuf) / args->original_width;
+	*args->scale_y_out = (double) gdk_pixbuf_get_height (pixbuf) / args->original_height;
+}
+
+/* routine to load an image from the passed-in path
  */
 GdkPixbuf *
-nautilus_thumbnail_load_framed_image (const char *path)
+nautilus_thumbnail_load_image (const char *path,
+			       guint base_size,
+			       guint nominal_size,
+			       gboolean force_nominal,
+			       double *scale_x_out,
+			       double *scale_y_out)
 {
+	guchar *buffer;
+	GdkPixbufLoader *loader;
 	GdkPixbuf *pixbuf;
-	
-	pixbuf = gdk_pixbuf_new_from_file (path, NULL);
-	if (pixbuf == NULL) {
+	GError *error;
+	gsize buflen;
+	ThumbnailLoadArgs args;
+
+	error = NULL;
+
+	if (!g_file_get_contents (path, (gchar **) &buffer, &buflen, &error)) {
+		g_message ("Failed to load %s into memory: %s", path, error->message);
+
+		g_error_free (error);
+
 		return NULL;
 	}
-	if (!gdk_pixbuf_get_has_alpha (pixbuf)) {
-		nautilus_thumbnail_frame_image (&pixbuf);
+
+	loader = gdk_pixbuf_loader_new ();
+	g_signal_connect (loader, "size-prepared",
+			  G_CALLBACK (thumbnail_loader_size_prepared),
+			  &args);
+	g_signal_connect (loader, "area-prepared",
+			  G_CALLBACK (thumbnail_loader_area_prepared),
+			  &args);
+
+	args.is_thumbnail = strstr (path, "/.thumbnails/") != NULL;
+	args.base_size = base_size;
+	args.nominal_size = nominal_size;
+	args.force_nominal = force_nominal;
+	args.scale_x_out = scale_x_out;
+	args.scale_y_out = scale_y_out;
+
+	if (!gdk_pixbuf_loader_write (loader, buffer, buflen, &error)) {
+		g_message ("Failed to write %s to thumbnail pixbuf loader: %s", path, error->message);
+
+		gdk_pixbuf_loader_close (loader, NULL);
+		g_object_unref (G_OBJECT (loader));
+		g_error_free (error);
+		g_free (buffer);
+
+		return NULL;
+	}
+
+	if (!gdk_pixbuf_loader_close (loader, &error)) {
+		g_message ("Failed to close thumbnail pixbuf loader for %s: %s", path, error->message);
+
+		g_object_unref (G_OBJECT (loader));
+		g_error_free (error);
+		g_free (buffer);
+
+		return NULL;
 	}
-        return pixbuf;
+
+	pixbuf = g_object_ref (gdk_pixbuf_loader_get_pixbuf (loader));
+
+	g_object_unref (G_OBJECT (loader));
+	g_free (buffer);
+
+	return pixbuf;
 }
 
 void
Index: libnautilus-private/nautilus-thumbnails.h
===================================================================
RCS file: /cvs/gnome/nautilus/libnautilus-private/nautilus-thumbnails.h,v
retrieving revision 1.12
diff -u -p -r1.12 nautilus-thumbnails.h
--- libnautilus-private/nautilus-thumbnails.h	19 Sep 2005 13:51:16 -0000	1.12
+++ libnautilus-private/nautilus-thumbnails.h	24 May 2006 20:12:27 -0000
@@ -31,7 +31,12 @@
 /* Returns NULL if there's no thumbnail yet. */
 void       nautilus_create_thumbnail                (NautilusFile *file);
 void       nautilus_thumbnail_frame_image           (GdkPixbuf **pixbuf);
-GdkPixbuf *nautilus_thumbnail_load_framed_image     (const char   *path);
+GdkPixbuf *nautilus_thumbnail_load_image            (const char *path,
+						     guint       base_size,
+						     guint       nominal_size,
+						     gboolean    force_nominal,
+						     double     *scale_x_out,
+						     double     *scale_y_out);
 void       nautilus_update_thumbnail_file_copied    (const char   *source_file_uri,
 						     const char   *destination_file_uri);
 void       nautilus_update_thumbnail_file_renamed   (const char   *source_file_uri,


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