Re: [PATCH] Use GdkPixbufLoader for thumbnailer to reduce memory consumption
- From: Christian Neumair <chris gnome-de org>
- To: Alexander Larsson <alexl redhat com>
- Cc: nautilus-list gnome org
- Subject: Re: [PATCH] Use GdkPixbufLoader for thumbnailer to reduce memory consumption
- Date: Wed, 24 May 2006 22:15:11 +0200
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]