summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Neumair <cneumair@gnome.org>2008-06-30 13:28:52 +0000
committerChristian Neumair <cneumair@src.gnome.org>2008-06-30 13:28:52 +0000
commita28322e65d0f80cbbab4b0f8d1e0e410f4f01cae (patch)
tree7189262fee7eb5d52aac100c273db01fce343d55
parentc1b01d86d22003aaee7a0f840681cc9c931fe6fb (diff)
downloadnautilus-a28322e65d0f80cbbab4b0f8d1e0e410f4f01cae.tar.gz
Scale down huge pixbufs when loading. Massively speed up loading of
2008-06-30 Christian Neumair <cneumair@gnome.org> * libnautilus-private/nautilus-directory-async.c (thumbnail_done), (thumbnail_loader_size_prepared), (get_pixbuf_for_content), (thumbnail_start): * libnautilus-private/nautilus-file.h: Scale down huge pixbufs when loading. Massively speed up loading of directories where the original image is used as thumbnail. Also try to write the whole file at once rather than writing in chunks. * libnautilus-private/nautilus-file-private.h: * libnautilus-private/nautilus-file.c (nautilus_file_get_icon): Rewrite some flaky parts of thumbnailing. Never scale any thumbnails up. Always compose thumbnail on the fly instead storing it once and scaling it up and down. Add flag to force that thumbnail size matches the output icon size for tree view. * src/file-manager/fm-list-model.c (fm_list_model_get_value): Use this flag. svn path=/branches/gnome-2-22/; revision=14310
-rw-r--r--ChangeLog23
-rw-r--r--libnautilus-private/nautilus-directory-async.c37
-rw-r--r--libnautilus-private/nautilus-file-private.h2
-rw-r--r--libnautilus-private/nautilus-file.c77
-rw-r--r--libnautilus-private/nautilus-file.h4
-rw-r--r--src/file-manager/fm-list-model.c3
6 files changed, 102 insertions, 44 deletions
diff --git a/ChangeLog b/ChangeLog
index 4beee9f13..4f0ff351d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,26 @@
+2008-06-30 Christian Neumair <cneumair@gnome.org>
+
+ * libnautilus-private/nautilus-directory-async.c (thumbnail_done),
+ (thumbnail_loader_size_prepared), (get_pixbuf_for_content),
+ (thumbnail_start):
+ * libnautilus-private/nautilus-file.h:
+ Scale down huge pixbufs when loading. Massively speed up loading of
+ directories where the original image is used as thumbnail.
+ Also try to write the whole file at once rather than writing in chunks.
+
+ * libnautilus-private/nautilus-file-private.h:
+ * libnautilus-private/nautilus-file.c (nautilus_file_get_icon):
+ Rewrite some flaky parts of thumbnailing.
+
+ Never scale any thumbnails up.
+ Always compose thumbnail on the fly instead storing it once and
+ scaling it up and down.
+ Add flag to force that thumbnail size matches
+ the output icon size for tree view.
+
+ * src/file-manager/fm-list-model.c (fm_list_model_get_value):
+ Use this flag.
+
2008-06-29 Cosimo Cecchi <cosimoc@gnome.org>
* src/nautilus-window.c: (nautilus_window_set_status):
diff --git a/libnautilus-private/nautilus-directory-async.c b/libnautilus-private/nautilus-directory-async.c
index 63a74f6dd..267925629 100644
--- a/libnautilus-private/nautilus-directory-async.c
+++ b/libnautilus-private/nautilus-directory-async.c
@@ -3768,7 +3768,6 @@ thumbnail_done (NautilusDirectory *directory,
g_object_unref (file->details->thumbnail);
file->details->thumbnail = NULL;
}
- file->details->thumbnail_size = 0;
if (pixbuf) {
thumb_mtime_str = gdk_pixbuf_get_option (pixbuf, "tEXt::Thumb::MTime");
if (thumb_mtime_str) {
@@ -3838,6 +3837,35 @@ thumbnail_state_free (ThumbnailState *state)
g_free (state);
}
+extern int cached_thumbnail_size;
+
+/* scale very large images down to the max. size we need */
+static void
+thumbnail_loader_size_prepared (GdkPixbufLoader *loader,
+ int width,
+ int height,
+ gpointer user_data)
+{
+ int max_thumbnail_size;
+ double aspect_ratio;
+
+ aspect_ratio = ((double) width) / height;
+
+ /* cf. nautilus_file_get_icon() */
+ max_thumbnail_size = NAUTILUS_ICON_SIZE_LARGEST * cached_thumbnail_size / NAUTILUS_ICON_SIZE_STANDARD;
+ if (MAX (width, height) > max_thumbnail_size) {
+ if (width > height) {
+ width = max_thumbnail_size;
+ height = width / aspect_ratio;
+ } else {
+ height = max_thumbnail_size;
+ width = height * aspect_ratio;
+ }
+
+ gdk_pixbuf_loader_set_size (loader, width, height);
+ }
+}
+
static GdkPixbuf *
get_pixbuf_for_content (goffset file_len,
char *file_contents)
@@ -3849,11 +3877,14 @@ get_pixbuf_for_content (goffset file_len,
pixbuf = NULL;
loader = gdk_pixbuf_loader_new ();
+ g_signal_connect (loader, "size-prepared",
+ G_CALLBACK (thumbnail_loader_size_prepared),
+ NULL);
/* For some reason we have to write in chunks, or gdk-pixbuf fails */
res = TRUE;
while (res && file_len > 0) {
- chunk_len = MIN (32*1024, file_len);
+ chunk_len = file_len;
res = gdk_pixbuf_loader_write (loader, file_contents, chunk_len, NULL);
file_contents += chunk_len;
file_len -= chunk_len;
@@ -3959,7 +3990,7 @@ thumbnail_start (NautilusDirectory *directory,
state->file = file;
state->cancellable = g_cancellable_new ();
- if (file->details->thumbnail_size > 128) {
+ if (file->details->thumbnail_wants_original) {
state->tried_original = TRUE;
state->trying_original = TRUE;
location = nautilus_file_get_location (file);
diff --git a/libnautilus-private/nautilus-file-private.h b/libnautilus-private/nautilus-file-private.h
index 8420a7ef5..ee63b70b5 100644
--- a/libnautilus-private/nautilus-file-private.h
+++ b/libnautilus-private/nautilus-file-private.h
@@ -106,7 +106,6 @@ struct NautilusFileDetails
char *thumbnail_path;
GdkPixbuf *thumbnail;
time_t thumbnail_mtime;
- int thumbnail_size; /* 0 means original unframed thumbnail */
GList *mime_list; /* If this is a directory, the list of MIME types in it. */
char *top_left_text;
@@ -181,6 +180,7 @@ struct NautilusFileDetails
eel_boolean_bit got_custom_activation_location : 1;
eel_boolean_bit thumbnail_is_up_to_date : 1;
+ eel_boolean_bit thumbnail_wants_original : 1;
eel_boolean_bit thumbnail_tried_original : 1;
eel_boolean_bit thumbnailing_failed : 1;
diff --git a/libnautilus-private/nautilus-file.c b/libnautilus-private/nautilus-file.c
index 222b524ff..b9bdc5853 100644
--- a/libnautilus-private/nautilus-file.c
+++ b/libnautilus-private/nautilus-file.c
@@ -3190,7 +3190,7 @@ get_custom_icon (NautilusFile *file)
static int cached_thumbnail_limit;
-static int cached_thumbnail_size;
+int cached_thumbnail_size;
static int show_image_thumbs;
GFilesystemPreviewType
@@ -3349,51 +3349,52 @@ nautilus_file_get_icon (NautilusFile *file,
return icon;
}
- modified_size = size * cached_thumbnail_size / NAUTILUS_ICON_SIZE_STANDARD;
+ if (flags & NAUTILUS_FILE_ICON_FLAGS_FORCE_THUMBNAIL_SIZE) {
+ modified_size = size;
+ } else {
+ modified_size = size * cached_thumbnail_size / NAUTILUS_ICON_SIZE_STANDARD;
+ }
if (flags & NAUTILUS_FILE_ICON_FLAGS_USE_THUMBNAILS &&
nautilus_file_should_show_thumbnail (file)) {
if (file->details->thumbnail) {
- if (file->details->thumbnail_size == modified_size) {
- scaled_pixbuf = g_object_ref (file->details->thumbnail);
- } else {
- int w, h, s;
- double scale;
-
- if (file->details->thumbnail_size == 0) {
- raw_pixbuf = g_object_ref (file->details->thumbnail);
- } else {
- raw_pixbuf = nautilus_thumbnail_unframe_image (file->details->thumbnail);
- }
+ int w, h, s;
+ double scale;
- w = gdk_pixbuf_get_width (raw_pixbuf);
- h = gdk_pixbuf_get_height (raw_pixbuf);
-
- s = MAX (w, h);
-
- scale = (double)modified_size / s;
+ raw_pixbuf = g_object_ref (file->details->thumbnail);
- /* These compensate for the size of the frame which will be added around the raw image */
+ w = gdk_pixbuf_get_width (raw_pixbuf);
+ h = gdk_pixbuf_get_height (raw_pixbuf);
+
+ s = MAX (w, h);
+ scale = (double)modified_size / s;
+
+
+ if (scale > 0.99) {
+ /* never scale any thumbnails up */
+ scaled_pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
+ gdk_pixbuf_get_has_alpha (raw_pixbuf),
+ gdk_pixbuf_get_bits_per_sample (raw_pixbuf),
+ w * scale, h * scale);
+ gdk_pixbuf_fill (scaled_pixbuf, 0xffffff00);
+ gdk_pixbuf_copy_area (raw_pixbuf,
+ 0, 0, w, h,
+ scaled_pixbuf,
+ (gdk_pixbuf_get_width (scaled_pixbuf) - w) / 2,
+ (gdk_pixbuf_get_height (scaled_pixbuf) - h) / 2);
+ } else {
scaled_pixbuf = gdk_pixbuf_scale_simple (raw_pixbuf,
- NAUTILUS_THUMBNAIL_FRAME_LEFT + w * scale + NAUTILUS_THUMBNAIL_FRAME_RIGHT,
- NAUTILUS_THUMBNAIL_FRAME_TOP + h * scale + NAUTILUS_THUMBNAIL_FRAME_BOTTOM,
+ w * scale, h * scale,
GDK_INTERP_BILINEAR);
- nautilus_thumbnail_frame_image (&scaled_pixbuf);
-
- g_object_unref (raw_pixbuf);
-
- if (modified_size > file->details->thumbnail_size) {
- /* Invalidate if we resize upward (and the
- loaded was not the original raw version, w/ size 0).
- */
- if (file->details->thumbnail_size != 0 ||
- (modified_size > 128 && !file->details->thumbnail_tried_original)) {
- nautilus_file_invalidate_attributes (file, NAUTILUS_FILE_ATTRIBUTE_THUMBNAIL);
- }
- file->details->thumbnail_size = modified_size;
- g_object_unref (file->details->thumbnail);
- file->details->thumbnail = g_object_ref (scaled_pixbuf);
- }
+ }
+ nautilus_thumbnail_frame_image (&scaled_pixbuf);
+ g_object_unref (raw_pixbuf);
+
+ if (modified_size > 128 &&
+ !file->details->thumbnail_wants_original) {
+ /* Invalidate if we resize upward */
+ file->details->thumbnail_wants_original = TRUE;
+ nautilus_file_invalidate_attributes (file, NAUTILUS_FILE_ATTRIBUTE_THUMBNAIL);
}
icon = nautilus_icon_info_new_for_pixbuf (scaled_pixbuf);
diff --git a/libnautilus-private/nautilus-file.h b/libnautilus-private/nautilus-file.h
index 99e0aeb98..2ab12df4a 100644
--- a/libnautilus-private/nautilus-file.h
+++ b/libnautilus-private/nautilus-file.h
@@ -77,7 +77,9 @@ typedef enum {
NAUTILUS_FILE_ICON_FLAGS_IGNORE_VISITING = (1<<1),
NAUTILUS_FILE_ICON_FLAGS_EMBEDDING_TEXT = (1<<2),
NAUTILUS_FILE_ICON_FLAGS_FOR_DRAG_ACCEPT = (1<<3),
- NAUTILUS_FILE_ICON_FLAGS_FOR_OPEN_FOLDER = (1<<4)
+ NAUTILUS_FILE_ICON_FLAGS_FOR_OPEN_FOLDER = (1<<4),
+ /* whether the thumbnail size must match the display icon size */
+ NAUTILUS_FILE_ICON_FLAGS_FORCE_THUMBNAIL_SIZE = (1<<5)
} NautilusFileIconFlags;
/* Emblems sometimes displayed for NautilusFiles. Do not localize. */
diff --git a/src/file-manager/fm-list-model.c b/src/file-manager/fm-list-model.c
index 324829f4d..aa37e9849 100644
--- a/src/file-manager/fm-list-model.c
+++ b/src/file-manager/fm-list-model.c
@@ -292,7 +292,8 @@ fm_list_model_get_value (GtkTreeModel *tree_model, GtkTreeIter *iter, int column
zoom_level = fm_list_model_get_zoom_level_from_column_id (column);
icon_size = nautilus_get_icon_size_for_zoom_level (zoom_level);
- flags = NAUTILUS_FILE_ICON_FLAGS_USE_THUMBNAILS;
+ flags = NAUTILUS_FILE_ICON_FLAGS_USE_THUMBNAILS |
+ NAUTILUS_FILE_ICON_FLAGS_FORCE_THUMBNAIL_SIZE;
if (model->details->drag_view != NULL) {
GtkTreePath *path_a, *path_b;