From b4299f5173e332864f5538b21012dc587b27a02f Mon Sep 17 00:00:00 2001 From: Thomas Leonard Date: Thu, 11 Nov 2004 14:04:24 +0000 Subject: [PATCH] r3716: Much faster thumbnail generation (Ken Hayber, reported by Anthony DiSante). --- ROX-Filer/Help/Changes | 4 ++ ROX-Filer/src/gtkicontheme.c | 42 ++----------- ROX-Filer/src/gui_support.c | 139 +++++++++++++++++++++++++++++++++++++++++++ ROX-Filer/src/gui_support.h | 5 ++ ROX-Filer/src/pixmaps.c | 6 +- 5 files changed, 156 insertions(+), 40 deletions(-) diff --git a/ROX-Filer/Help/Changes b/ROX-Filer/Help/Changes index 7fa13760..cfc91d0d 100644 --- a/ROX-Filer/Help/Changes +++ b/ROX-Filer/Help/Changes @@ -2,6 +2,10 @@ A RISC OS-like filer for X by Thomas Leonard +11-Nov-2004 +~~~~~~~~~~~ +Much faster thumbnail generation (Ken Hayber, reported by Anthony DiSante). + 08-Nov-2004 ~~~~~~~~~~~ When closing a filer window showing a directory under a user-mounted diff --git a/ROX-Filer/src/gtkicontheme.c b/ROX-Filer/src/gtkicontheme.c index ddfd4d60..07e3b24f 100644 --- a/ROX-Filer/src/gtkicontheme.c +++ b/ROX-Filer/src/gtkicontheme.c @@ -27,6 +27,7 @@ #endif #endif /* G_OS_WIN32 */ +#include "gui_support.h" #include "gtkicontheme.h" #include "gtkiconthemeparser.h" /* #include "gtkintl.h" */ @@ -1405,43 +1406,6 @@ rox_icon_info_free (RoxIconInfo *icon_info) g_free (icon_info); } -static GdkPixbuf * -load_svg_at_size (const gchar *filename, - gint size, - GError **error) -{ - GdkPixbuf *pixbuf = NULL; - GdkPixbufLoader *loader = NULL; - gchar *contents=NULL; - gsize length; - - if (!g_file_get_contents (filename, - &contents, &length, error)) - goto bail; - - loader = gdk_pixbuf_loader_new (); - gdk_pixbuf_loader_set_size (loader, size, size); - - if (!gdk_pixbuf_loader_write (loader, contents, length, error)) - { - gdk_pixbuf_loader_close (loader, NULL); - goto bail; - } - - if (!gdk_pixbuf_loader_close (loader, error)) - goto bail; - - pixbuf = g_object_ref (gdk_pixbuf_loader_get_pixbuf (loader)); - - bail: - if(contents) - g_free(contents); - if (loader) - g_object_unref (loader); - - return pixbuf; -} - /* This function contains the complicatd logic for deciding * on the size at which to load the icon and loading it at * that size. @@ -1475,8 +1439,10 @@ icon_info_ensure_scale_and_pixbuf (RoxIconInfo *icon_info, if (scale_only) return TRUE; - icon_info->pixbuf = load_svg_at_size (icon_info->filename, + icon_info->pixbuf = rox_pixbuf_new_from_file_at_scale(icon_info->filename, + icon_info->desired_size, icon_info->desired_size, + TRUE, &icon_info->load_error); return icon_info->pixbuf != NULL; diff --git a/ROX-Filer/src/gui_support.c b/ROX-Filer/src/gui_support.c index 544af7b7..45bd28d3 100644 --- a/ROX-Filer/src/gui_support.c +++ b/ROX-Filer/src/gui_support.c @@ -1252,3 +1252,142 @@ void keep_below(GdkWindow *window, gboolean setting) } #endif } + +static void +size_prepared_cb (GdkPixbufLoader *loader, + int width, + int height, + gpointer data) +{ + struct { + gint width; + gint height; + gboolean preserve_aspect_ratio; + } *info = data; + + g_return_if_fail (width > 0 && height > 0); + + if(info->preserve_aspect_ratio) { + if ((double)height * (double)info->width > + (double)width * (double)info->height) { + width = 0.5 + (double)width * (double)info->height / (double)height; + height = info->height; + } else { + height = 0.5 + (double)height * (double)info->width / (double)width; + width = info->width; + } + } else { + width = info->width; + height = info->height; + } + + gdk_pixbuf_loader_set_size (loader, width, height); +} + +/** + * rox_pixbuf_new_from_file_at_scale: + * @filename: Name of file to load. + * @width: The width the image should have + * @height: The height the image should have + * @preserve_aspect_ratio: %TRUE to preserve the image's aspect ratio + * @error: Return location for an error + * + * Creates a new pixbuf by loading an image from a file. The file format is + * detected automatically. If %NULL is returned, then @error will be set. + * Possible errors are in the #GDK_PIXBUF_ERROR and #G_FILE_ERROR domains. + * The image will be scaled to fit in the requested size, optionally preserving + * the image's aspect ratio. + * + * Return value: A newly-created pixbuf with a reference count of 1, or %NULL + * if any of several error conditions occurred: the file could not be opened, + * there was no loader for the file's format, there was not enough memory to + * allocate the image buffer, or the image file contained invalid data. + * + * Taken from GTK 2.6. + **/ +GdkPixbuf * +rox_pixbuf_new_from_file_at_scale (const char *filename, + int width, + int height, + gboolean preserve_aspect_ratio, + GError **error) +{ + + GdkPixbufLoader *loader; + GdkPixbuf *pixbuf; + + guchar buffer [4096]; + int length; + FILE *f; + struct { + gint width; + gint height; + gboolean preserve_aspect_ratio; + } info; + + g_return_val_if_fail (filename != NULL, NULL); + g_return_val_if_fail (width > 0 && height > 0, NULL); + + f = fopen (filename, "rb"); + if (!f) { + gchar *utf8_filename = g_filename_to_utf8 (filename, -1, + NULL, NULL, NULL); + g_set_error (error, + G_FILE_ERROR, + g_file_error_from_errno (errno), + _("Failed to open file '%s': %s"), + utf8_filename ? utf8_filename : "???", + g_strerror (errno)); + g_free (utf8_filename); + return NULL; + } + + loader = gdk_pixbuf_loader_new (); + + info.width = width; + info.height = height; + info.preserve_aspect_ratio = preserve_aspect_ratio; + + g_signal_connect (loader, "size-prepared", G_CALLBACK (size_prepared_cb), &info); + + while (!feof (f) && !ferror (f)) { + length = fread (buffer, 1, sizeof (buffer), f); + if (length > 0) + if (!gdk_pixbuf_loader_write (loader, buffer, length, error)) { + gdk_pixbuf_loader_close (loader, NULL); + fclose (f); + g_object_unref (loader); + return NULL; + } + } + + fclose (f); + + if (!gdk_pixbuf_loader_close (loader, error)) { + g_object_unref (loader); + return NULL; + } + + pixbuf = gdk_pixbuf_loader_get_pixbuf (loader); + + if (!pixbuf) { + gchar *utf8_filename = g_filename_to_utf8 (filename, -1, + NULL, NULL, NULL); + + g_object_unref (loader); + + g_set_error (error, + GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_FAILED, + _("Failed to load image '%s': reason not known, probably a corrupt image file"), + utf8_filename ? utf8_filename : "???"); + g_free (utf8_filename); + return NULL; + } + + g_object_ref (pixbuf); + + g_object_unref (loader); + + return pixbuf; +} diff --git a/ROX-Filer/src/gui_support.h b/ROX-Filer/src/gui_support.h index b1457b15..19934cd7 100644 --- a/ROX-Filer/src/gui_support.h +++ b/ROX-Filer/src/gui_support.h @@ -77,6 +77,11 @@ void render_pixbuf(GdkPixbuf *pixbuf, GdkDrawable *target, GdkGC *gc, /* gdk_window_set_keep_below() only exists in GTK >= 2.4 and is broken until * 2.4.6 */ void keep_below(GdkWindow *window, gboolean setting); +GdkPixbuf * rox_pixbuf_new_from_file_at_scale (const char *filename, + int width, + int height, + gboolean preserve_aspect_ratio, + GError **error); #endif /* _GUI_SUPPORT_H */ diff --git a/ROX-Filer/src/pixmaps.c b/ROX-Filer/src/pixmaps.c index f79a62ef..fbc32071 100644 --- a/ROX-Filer/src/pixmaps.c +++ b/ROX-Filer/src/pixmaps.c @@ -315,7 +315,8 @@ void pixmap_background_thumb(const gchar *path, GFunc callback, gpointer data) info1.st_dev == info2.st_dev && info1.st_ino == info2.st_ino) { - pixbuf = gdk_pixbuf_new_from_file(path, NULL); + pixbuf = rox_pixbuf_new_from_file_at_scale(path, + PIXMAP_THUMB_SIZE, PIXMAP_THUMB_SIZE, TRUE, NULL); if (!pixbuf) { g_fscache_insert(pixmap_cache, @@ -540,7 +541,8 @@ static void child_create_thumbnail(const gchar *path) { GdkPixbuf *image; - image = gdk_pixbuf_new_from_file(path, NULL); + image = rox_pixbuf_new_from_file_at_scale(path, + PIXMAP_THUMB_SIZE, PIXMAP_THUMB_SIZE, TRUE, NULL); if (image) save_thumbnail(path, image); -- 2.11.4.GIT