[gthumb] image preloader: implemented a smarter cache
- From: Paolo Bacchilega <paobac src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gthumb] image preloader: implemented a smarter cache
- Date: Sat, 9 Nov 2013 19:59:47 +0000 (UTC)
commit 95c31a31f5f2e96f046715c15e5535f305a1c2ce
Author: Paolo Bacchilega <paobac src gnome org>
Date: Wed Oct 2 23:15:56 2013 +0200
image preloader: implemented a smarter cache
extensions/cairo_io/cairo-image-surface-jpeg.c | 3 +
extensions/cairo_io/cairo-image-surface-jpeg.h | 1 +
extensions/cairo_io/cairo-image-surface-png.c | 1 +
extensions/cairo_io/cairo-image-surface-png.h | 1 +
extensions/cairo_io/cairo-image-surface-svg.c | 1 +
extensions/cairo_io/cairo-image-surface-svg.h | 1 +
extensions/cairo_io/cairo-image-surface-webp.c | 1 +
extensions/cairo_io/cairo-image-surface-webp.h | 1 +
extensions/cairo_io/cairo-image-surface-xcf.c | 1 +
extensions/cairo_io/cairo-image-surface-xcf.h | 1 +
.../contact_sheet/gth-contact-sheet-creator.c | 1 +
extensions/facebook/dlg-import-from-facebook.c | 1 +
extensions/flicker_utils/dlg-import-from-flickr.c | 1 +
extensions/image_print/gth-load-image-info-task.c | 1 +
extensions/image_viewer/gth-image-viewer-page.c | 15 +-
extensions/picasaweb/dlg-import-from-picasaweb.c | 1 +
extensions/raw_files/main.c | 6 +
extensions/webalbums/gth-web-exporter.c | 1 +
gthumb/cairo-scale.c | 132 ++++++++-
gthumb/cairo-scale.h | 39 ++-
gthumb/glib-utils.c | 2 +-
gthumb/gth-image-loader.c | 20 +-
gthumb/gth-image-loader.h | 1 +
gthumb/gth-image-preloader.c | 315 +++++++++++++++++---
gthumb/gth-image-preloader.h | 39 ++--
gthumb/gth-image-utils.c | 1 +
gthumb/gth-image.h | 1 +
gthumb/gth-overwrite-dialog.c | 1 +
gthumb/gth-task.c | 57 ++--
gthumb/gth-task.h | 2 +
gthumb/gth-thumb-loader.c | 5 +
gthumb/pixbuf-io.c | 1 +
gthumb/pixbuf-io.h | 1 +
33 files changed, 544 insertions(+), 112 deletions(-)
---
diff --git a/extensions/cairo_io/cairo-image-surface-jpeg.c b/extensions/cairo_io/cairo-image-surface-jpeg.c
index 0fe2a4d..4e6f7c8 100644
--- a/extensions/cairo_io/cairo-image-surface-jpeg.c
+++ b/extensions/cairo_io/cairo-image-surface-jpeg.c
@@ -149,6 +149,7 @@ _cairo_image_surface_create_from_jpeg (GInputStream *istream,
int requested_size,
int *original_width_p,
int *original_height_p,
+ gboolean *loaded_original_p,
gpointer user_data,
GCancellable *cancellable,
GError **error)
@@ -536,6 +537,8 @@ _cairo_image_surface_create_from_jpeg (GInputStream *istream,
*original_width_p = original_width;
if (original_height_p != NULL)
*original_height_p = original_height;
+ if (loaded_original_p != NULL)
+ *loaded_original_p = ! load_scaled;
jpeg_finish_decompress (&srcinfo);
jpeg_destroy_decompress (&srcinfo);
diff --git a/extensions/cairo_io/cairo-image-surface-jpeg.h b/extensions/cairo_io/cairo-image-surface-jpeg.h
index 23244a7..aaa6716 100644
--- a/extensions/cairo_io/cairo-image-surface-jpeg.h
+++ b/extensions/cairo_io/cairo-image-surface-jpeg.h
@@ -32,6 +32,7 @@ GthImage * _cairo_image_surface_create_from_jpeg (GInputStream *istream,
int requested_size,
int *original_width,
int *original_height,
+ gboolean *loaded_original,
gpointer user_data,
GCancellable *cancellable,
GError **error);
diff --git a/extensions/cairo_io/cairo-image-surface-png.c b/extensions/cairo_io/cairo-image-surface-png.c
index 4e4c126..2df3efd 100644
--- a/extensions/cairo_io/cairo-image-surface-png.c
+++ b/extensions/cairo_io/cairo-image-surface-png.c
@@ -136,6 +136,7 @@ _cairo_image_surface_create_from_png (GInputStream *istream,
int requested_size,
int *original_width,
int *original_height,
+ gboolean *loaded_original,
gpointer user_data,
GCancellable *cancellable,
GError **error)
diff --git a/extensions/cairo_io/cairo-image-surface-png.h b/extensions/cairo_io/cairo-image-surface-png.h
index 2ae9993..c11d6a4 100644
--- a/extensions/cairo_io/cairo-image-surface-png.h
+++ b/extensions/cairo_io/cairo-image-surface-png.h
@@ -32,6 +32,7 @@ GthImage * _cairo_image_surface_create_from_png (GInputStream *istream,
int requested_size,
int *original_width,
int *original_height,
+ gboolean *loaded_original,
gpointer user_data,
GCancellable *cancellable,
GError **error);
diff --git a/extensions/cairo_io/cairo-image-surface-svg.c b/extensions/cairo_io/cairo-image-surface-svg.c
index 13f9af8..7cf0a7b 100644
--- a/extensions/cairo_io/cairo-image-surface-svg.c
+++ b/extensions/cairo_io/cairo-image-surface-svg.c
@@ -168,6 +168,7 @@ _cairo_image_surface_create_from_svg (GInputStream *istream,
int requested_size,
int *original_width,
int *original_height,
+ gboolean *loaded_original,
gpointer user_data,
GCancellable *cancellable,
GError **error)
diff --git a/extensions/cairo_io/cairo-image-surface-svg.h b/extensions/cairo_io/cairo-image-surface-svg.h
index dc67431..18f32f7 100644
--- a/extensions/cairo_io/cairo-image-surface-svg.h
+++ b/extensions/cairo_io/cairo-image-surface-svg.h
@@ -32,6 +32,7 @@ GthImage * _cairo_image_surface_create_from_svg (GInputStream *istream,
int requested_size,
int *original_width,
int *original_height,
+ gboolean *loaded_original,
gpointer user_data,
GCancellable *cancellable,
GError **error);
diff --git a/extensions/cairo_io/cairo-image-surface-webp.c b/extensions/cairo_io/cairo-image-surface-webp.c
index c1ebe9d..cfa6e80 100644
--- a/extensions/cairo_io/cairo-image-surface-webp.c
+++ b/extensions/cairo_io/cairo-image-surface-webp.c
@@ -35,6 +35,7 @@ _cairo_image_surface_create_from_webp (GInputStream *istream,
int requested_size,
int *original_width,
int *original_height,
+ gboolean *loaded_original,
gpointer user_data,
GCancellable *cancellable,
GError **error)
diff --git a/extensions/cairo_io/cairo-image-surface-webp.h b/extensions/cairo_io/cairo-image-surface-webp.h
index d9c952b..4cb1725 100644
--- a/extensions/cairo_io/cairo-image-surface-webp.h
+++ b/extensions/cairo_io/cairo-image-surface-webp.h
@@ -32,6 +32,7 @@ GthImage * _cairo_image_surface_create_from_webp (GInputStream *istream,
int requested_size,
int *original_width,
int *original_height,
+ gboolean *loaded_original,
gpointer user_data,
GCancellable *cancellable,
GError **error);
diff --git a/extensions/cairo_io/cairo-image-surface-xcf.c b/extensions/cairo_io/cairo-image-surface-xcf.c
index 5846976..24392c8 100644
--- a/extensions/cairo_io/cairo-image-surface-xcf.c
+++ b/extensions/cairo_io/cairo-image-surface-xcf.c
@@ -954,6 +954,7 @@ _cairo_image_surface_create_from_xcf (GInputStream *istream,
int requested_size,
int *original_width,
int *original_height,
+ gboolean *loaded_original,
gpointer user_data,
GCancellable *cancellable,
GError **error)
diff --git a/extensions/cairo_io/cairo-image-surface-xcf.h b/extensions/cairo_io/cairo-image-surface-xcf.h
index 3d7717e..7f72e78 100644
--- a/extensions/cairo_io/cairo-image-surface-xcf.h
+++ b/extensions/cairo_io/cairo-image-surface-xcf.h
@@ -32,6 +32,7 @@ GthImage * _cairo_image_surface_create_from_xcf (GInputStream *istream,
int requested_size,
int *original_width,
int *original_height,
+ gboolean *loaded_original,
gpointer user_data,
GCancellable *cancellable,
GError **error);
diff --git a/extensions/contact_sheet/gth-contact-sheet-creator.c
b/extensions/contact_sheet/gth-contact-sheet-creator.c
index 9ff69b5..e5d7412 100644
--- a/extensions/contact_sheet/gth-contact-sheet-creator.c
+++ b/extensions/contact_sheet/gth-contact-sheet-creator.c
@@ -933,6 +933,7 @@ image_loader_ready_cb (GObject *source_object,
&image,
&original_width,
&original_height,
+ NULL,
&error))
{
gth_task_completed (GTH_TASK (self), error);
diff --git a/extensions/facebook/dlg-import-from-facebook.c b/extensions/facebook/dlg-import-from-facebook.c
index 7197bfd..a5cb3fd 100644
--- a/extensions/facebook/dlg-import-from-facebook.c
+++ b/extensions/facebook/dlg-import-from-facebook.c
@@ -404,6 +404,7 @@ facebook_thumbnail_loader (GInputStream *istream,
int requested_size,
int *original_width,
int *original_height,
+ gboolean *loaded_original,
gpointer user_data,
GCancellable *cancellable,
GError **error)
diff --git a/extensions/flicker_utils/dlg-import-from-flickr.c
b/extensions/flicker_utils/dlg-import-from-flickr.c
index c80a13e..e685cd7 100644
--- a/extensions/flicker_utils/dlg-import-from-flickr.c
+++ b/extensions/flicker_utils/dlg-import-from-flickr.c
@@ -411,6 +411,7 @@ flickr_thumbnail_loader (GInputStream *istream,
int requested_size,
int *original_width,
int *original_height,
+ gboolean *loaded_original,
gpointer user_data,
GCancellable *cancellable,
GError **error)
diff --git a/extensions/image_print/gth-load-image-info-task.c
b/extensions/image_print/gth-load-image-info-task.c
index 5cdcbda..df353fa 100644
--- a/extensions/image_print/gth-load-image-info-task.c
+++ b/extensions/image_print/gth-load-image-info-task.c
@@ -119,6 +119,7 @@ image_loader_ready_cb (GObject *source_object,
&image,
NULL,
NULL,
+ NULL,
&error);
if (error == NULL)
diff --git a/extensions/image_viewer/gth-image-viewer-page.c b/extensions/image_viewer/gth-image-viewer-page.c
index d43092d..9b5d44e 100644
--- a/extensions/image_viewer/gth-image-viewer-page.c
+++ b/extensions/image_viewer/gth-image-viewer-page.c
@@ -267,7 +267,7 @@ different_quality_ready_cb (GObject *source_object,
return;
}
- if (! _g_file_equal (requested->file, self->priv->file_data->file))
+ if (! (self->priv->image_changed && requested == NULL) && ! _g_file_equal (requested->file,
self->priv->file_data->file))
goto clear_data;
if (image == NULL)
@@ -295,11 +295,14 @@ clear_data:
static void
update_image_quality_if_required (GthImageViewerPage *self)
{
- double zoom;
+ GthFileData *file_data;
+ double zoom;
- if (self->priv->image_changed || self->priv->loading_image)
+ if (self->priv->loading_image)
return;
+ file_data = self->priv->image_changed ? GTH_MODIFIED_IMAGE : self->priv->file_data;
+
zoom = gth_image_viewer_get_zoom (GTH_IMAGE_VIEWER (self->priv->viewer));
if (zoom >= 1.0) {
int requested_size;
@@ -312,7 +315,7 @@ update_image_quality_if_required (GthImageViewerPage *self)
&original_height);
if ((requested_size > 0) && (MAX (original_width, original_height) > requested_size)) {
gth_image_preloader_load (self->priv->preloader,
- self->priv->file_data,
+ file_data,
GTH_ORIGINAL_SIZE,
NULL,
different_quality_ready_cb,
@@ -329,7 +332,7 @@ update_image_quality_if_required (GthImageViewerPage *self)
new_requested_size = _gth_image_preloader_get_requested_size (self);
if (old_requested_size != new_requested_size) {
gth_image_preloader_load (self->priv->preloader,
- self->priv->file_data,
+ file_data,
new_requested_size,
NULL,
different_quality_ready_cb,
@@ -1395,6 +1398,8 @@ _gth_image_viewer_page_set_image (GthImageViewerPage *self,
if (image == NULL)
return;
+ if (requested_size == -1)
+ gth_image_preloader_set_modified_image (self->priv->preloader, image);
gth_image_viewer_set_surface (GTH_IMAGE_VIEWER (self->priv->viewer), image, -1, -1);
gth_image_viewer_set_requested_size (GTH_IMAGE_VIEWER (self->priv->viewer), requested_size);
diff --git a/extensions/picasaweb/dlg-import-from-picasaweb.c
b/extensions/picasaweb/dlg-import-from-picasaweb.c
index 0901bd0..6114fa8 100644
--- a/extensions/picasaweb/dlg-import-from-picasaweb.c
+++ b/extensions/picasaweb/dlg-import-from-picasaweb.c
@@ -337,6 +337,7 @@ picasa_web_thumbnail_loader (GInputStream *istream,
int requested_size,
int *original_width,
int *original_height,
+ gboolean *loaded_original,
gpointer user_data,
GCancellable *cancellable,
GError **error)
diff --git a/extensions/raw_files/main.c b/extensions/raw_files/main.c
index 46cec15..652b28f 100644
--- a/extensions/raw_files/main.c
+++ b/extensions/raw_files/main.c
@@ -97,6 +97,7 @@ _libraw_read_jpeg_data (void *buffer,
NULL,
NULL,
NULL,
+ NULL,
cancellable,
error);
@@ -226,6 +227,7 @@ _cairo_image_surface_create_from_raw (GInputStream *istream,
int requested_size,
int *original_width,
int *original_height,
+ gboolean *loaded_original,
gpointer user_data,
GCancellable *cancellable,
GError **error)
@@ -268,6 +270,9 @@ _cairo_image_surface_create_from_raw (GInputStream *istream,
if (requested_size > 0) {
+ if (loaded_original != NULL)
+ *loaded_original = FALSE;
+
/* read the thumbnail */
result = libraw_unpack_thumb (raw_data);
@@ -464,6 +469,7 @@ dcraw_pixbuf_animation_new_from_file (GInputStream *istream,
int requested_size,
int *original_width,
int *original_height,
+ gboolean *loaded_original,
gpointer user_data,
GCancellable *cancellable,
GError **error)
diff --git a/extensions/webalbums/gth-web-exporter.c b/extensions/webalbums/gth-web-exporter.c
index 6ec409b..bc9c81b 100644
--- a/extensions/webalbums/gth-web-exporter.c
+++ b/extensions/webalbums/gth-web-exporter.c
@@ -2569,6 +2569,7 @@ image_loader_ready_cb (GObject *source_object,
&image,
NULL,
NULL,
+ NULL,
NULL))
{
load_next_file (self);
diff --git a/gthumb/cairo-scale.c b/gthumb/cairo-scale.c
index 65b499b..14dbd38 100644
--- a/gthumb/cairo-scale.c
+++ b/gthumb/cairo-scale.c
@@ -26,6 +26,7 @@
#include "cairo-utils.h"
#include "cairo-scale.h"
#include "gfixed.h"
+#include "glib-utils.h"
#define CLAMP_PIXEL(v) (((v) <= 0) ? 0 : ((v) >= 255) ? 255 : (v));
@@ -503,13 +504,14 @@ _cairo_image_surface_scale (cairo_surface_t *image,
scale_filter_t filter,
GthAsyncTask *task)
{
- int src_width;
- int src_height;
- cairo_surface_t *scaled;
- resize_filter_t *resize_filter;
- ScaleReal x_factor;
- ScaleReal y_factor;
- cairo_surface_t *tmp;
+ int src_width;
+ int src_height;
+ cairo_surface_t *scaled;
+ cairo_surface_metadata_t *metadata;
+ resize_filter_t *resize_filter;
+ ScaleReal x_factor;
+ ScaleReal y_factor;
+ cairo_surface_t *tmp;
src_width = cairo_image_surface_get_width (image);
src_height = cairo_image_surface_get_height (image);
@@ -520,6 +522,10 @@ _cairo_image_surface_scale (cairo_surface_t *image,
scaled = _cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
scaled_width,
scaled_height);
+ metadata = _cairo_image_surface_get_metadata (scaled);
+ metadata->original_width = src_width;
+ metadata->original_height = src_height;
+
if (scaled == NULL)
return NULL;
@@ -905,3 +911,115 @@ _cairo_image_surface_scale_bilinear (cairo_surface_t *image,
return tmp2;
}
+
+
+/* -- _cairo_image_surface_scale_async -- */
+
+
+typedef struct {
+ cairo_surface_t *original;
+ int new_width;
+ int new_height;
+ scale_filter_t quality;
+ cairo_surface_t *scaled;
+ GthTask *task;
+} ScaleData;
+
+
+static ScaleData *
+scale_data_new (cairo_surface_t *image,
+ int new_width,
+ int new_height,
+ scale_filter_t quality,
+ GCancellable *cancellable)
+{
+ ScaleData *scale_data;
+
+ scale_data = g_new0 (ScaleData, 1);
+ scale_data->original = cairo_surface_reference (image);
+ scale_data->new_width = new_width;
+ scale_data->new_height = new_height;
+ scale_data->quality = quality;
+ scale_data->scaled = NULL;
+ scale_data->task = gth_async_task_new (NULL, NULL, NULL, NULL, NULL);
+ gth_task_set_cancellable (scale_data->task, cancellable);
+
+ return scale_data;
+}
+
+
+static void
+scale_data_free (ScaleData *scale_data)
+{
+ _g_object_unref (scale_data->task);
+ cairo_surface_destroy (scale_data->scaled);
+ cairo_surface_destroy (scale_data->original);
+ g_free (scale_data);
+}
+
+
+static void
+scale_image_thread (GSimpleAsyncResult *result,
+ GObject *object,
+ GCancellable *cancellable)
+{
+ ScaleData *scale_data;
+
+ scale_data = g_simple_async_result_get_op_res_gpointer (result);
+ scale_data->scaled = _cairo_image_surface_scale (scale_data->original,
+ scale_data->new_width,
+ scale_data->new_height,
+ scale_data->quality,
+ GTH_ASYNC_TASK (scale_data->task));
+}
+
+
+void
+_cairo_image_surface_scale_async (cairo_surface_t *image,
+ int new_width,
+ int new_height,
+ scale_filter_t quality,
+ GCancellable *cancellable,
+ GAsyncReadyCallback ready_callback,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *result;
+
+ result = g_simple_async_result_new (NULL,
+ ready_callback,
+ user_data,
+ _cairo_image_surface_scale_async);
+ g_simple_async_result_set_op_res_gpointer (result,
+ scale_data_new (image,
+ new_width,
+ new_height,
+ quality,
+ cancellable),
+ (GDestroyNotify) scale_data_free);
+ g_simple_async_result_run_in_thread (result,
+ scale_image_thread,
+ G_PRIORITY_DEFAULT,
+ cancellable);
+
+ g_object_unref (result);
+}
+
+
+cairo_surface_t *
+_cairo_image_surface_scale_finish (GAsyncResult *result,
+ GError **error)
+{
+ GSimpleAsyncResult *simple;
+ ScaleData *scale_data;
+
+ g_return_val_if_fail (g_simple_async_result_is_valid (result, NULL,
_cairo_image_surface_scale_async), NULL);
+
+ simple = G_SIMPLE_ASYNC_RESULT (result);
+
+ if (g_simple_async_result_propagate_error (simple, error))
+ return NULL;
+
+ scale_data = g_simple_async_result_get_op_res_gpointer (simple);
+
+ return cairo_surface_reference (scale_data->scaled);
+}
diff --git a/gthumb/cairo-scale.h b/gthumb/cairo-scale.h
index dd85c0a..a0f58ff 100644
--- a/gthumb/cairo-scale.h
+++ b/gthumb/cairo-scale.h
@@ -47,21 +47,30 @@ typedef enum /*< skip >*/ {
} scale_filter_t;
-cairo_surface_t * _cairo_image_surface_scale_nearest (cairo_surface_t *image,
- int new_width,
- int new_height);
-cairo_surface_t * _cairo_image_surface_scale (cairo_surface_t *image,
- int width,
- int height,
- scale_filter_t quality,
- GthAsyncTask *task);
-cairo_surface_t * _cairo_image_surface_scale_squared (cairo_surface_t *image,
- int size,
- scale_filter_t quality,
- GthAsyncTask *task);
-cairo_surface_t * _cairo_image_surface_scale_bilinear (cairo_surface_t *image,
- int new_width,
- int new_height);
+cairo_surface_t * _cairo_image_surface_scale_nearest (cairo_surface_t *image,
+ int new_width,
+ int new_height);
+cairo_surface_t * _cairo_image_surface_scale (cairo_surface_t *image,
+ int width,
+ int height,
+ scale_filter_t quality,
+ GthAsyncTask *task);
+cairo_surface_t * _cairo_image_surface_scale_squared (cairo_surface_t *image,
+ int size,
+ scale_filter_t quality,
+ GthAsyncTask *task);
+cairo_surface_t * _cairo_image_surface_scale_bilinear (cairo_surface_t *image,
+ int new_width,
+ int new_height);
+void _cairo_image_surface_scale_async (cairo_surface_t *image,
+ int new_width,
+ int new_height,
+ scale_filter_t quality,
+ GCancellable *cancellable,
+ GAsyncReadyCallback ready_callback,
+ gpointer user_data);
+cairo_surface_t * _cairo_image_surface_scale_finish (GAsyncResult *result,
+ GError **error);
G_END_DECLS
diff --git a/gthumb/glib-utils.c b/gthumb/glib-utils.c
index 1191302..45defba 100644
--- a/gthumb/glib-utils.c
+++ b/gthumb/glib-utils.c
@@ -85,7 +85,7 @@ _g_object_list_ref (GList *list)
void
_g_object_list_unref (GList *list)
{
- g_list_foreach (list, (GFunc) g_object_unref, NULL);
+ g_list_foreach (list, (GFunc) _g_object_unref, NULL);
g_list_free (list);
}
diff --git a/gthumb/gth-image-loader.c b/gthumb/gth-image-loader.c
index 7a41894..8593d07 100644
--- a/gthumb/gth-image-loader.c
+++ b/gthumb/gth-image-loader.c
@@ -113,6 +113,7 @@ typedef struct {
GthImage *image;
int original_width;
int original_height;
+ gboolean loaded_original;
} LoadData;
@@ -127,6 +128,7 @@ load_data_new (GthFileData *file_data,
load_data->file_data = _g_object_ref (file_data);
load_data->requested_size = requested_size;
load_data->cancellable = _g_object_ref (cancellable);
+ load_data->loaded_original = TRUE;
return load_data;
}
@@ -143,14 +145,15 @@ load_data_unref (LoadData *load_data)
static void
-load_pixbuf_thread (GSimpleAsyncResult *result,
- GObject *object,
- GCancellable *cancellable)
+load_image_thread (GSimpleAsyncResult *result,
+ GObject *object,
+ GCancellable *cancellable)
{
GthImageLoader *self = GTH_IMAGE_LOADER (object);
LoadData *load_data;
int original_width;
int original_height;
+ gboolean loaded_original;
GInputStream *istream;
GthImage *image = NULL;
GError *error = NULL;
@@ -166,12 +169,15 @@ load_pixbuf_thread (GSimpleAsyncResult *result,
return;
}
+ loaded_original = TRUE;
+
if (self->priv->loader_func != NULL) {
image = (*self->priv->loader_func) (istream,
load_data->file_data,
load_data->requested_size,
&original_width,
&original_height,
+ &loaded_original,
self->priv->loader_data,
cancellable,
&error);
@@ -190,6 +196,7 @@ load_pixbuf_thread (GSimpleAsyncResult *result,
load_data->requested_size,
&original_width,
&original_height,
+ &loaded_original,
NULL,
cancellable,
&error);
@@ -214,6 +221,7 @@ load_pixbuf_thread (GSimpleAsyncResult *result,
load_data->image = image;
load_data->original_width = original_width;
load_data->original_height = original_height;
+ load_data->loaded_original = loaded_original;
}
@@ -238,7 +246,7 @@ gth_image_loader_load (GthImageLoader *loader,
cancellable),
(GDestroyNotify) load_data_unref);
g_simple_async_result_run_in_thread (result,
- load_pixbuf_thread,
+ load_image_thread,
io_priority,
cancellable);
@@ -252,6 +260,7 @@ gth_image_loader_load_finish (GthImageLoader *loader,
GthImage **image,
int *original_width,
int *original_height,
+ gboolean *loaded_original,
GError **error)
{
GSimpleAsyncResult *simple;
@@ -271,6 +280,8 @@ gth_image_loader_load_finish (GthImageLoader *loader,
*original_width = load_data->original_width;
if (original_height != NULL)
*original_height = load_data->original_height;
+ if (loaded_original != NULL)
+ *loaded_original = load_data->loaded_original;
return TRUE;
}
@@ -301,6 +312,7 @@ gth_image_new_from_stream (GInputStream *istream,
&original_width,
&original_height,
NULL,
+ NULL,
cancellable,
&error);
}
diff --git a/gthumb/gth-image-loader.h b/gthumb/gth-image-loader.h
index e1847d7..2db3343 100644
--- a/gthumb/gth-image-loader.h
+++ b/gthumb/gth-image-loader.h
@@ -69,6 +69,7 @@ gboolean gth_image_loader_load_finish (GthImageLoader
GthImage **image,
int *original_width,
int *original_height,
+ gboolean *loaded_original,
GError **error);
GthImage * gth_image_new_from_stream (GInputStream *istream,
int requested_size,
diff --git a/gthumb/gth-image-preloader.c b/gthumb/gth-image-preloader.c
index 4532c35..07cbf86 100644
--- a/gthumb/gth-image-preloader.c
+++ b/gthumb/gth-image-preloader.c
@@ -23,8 +23,11 @@
#include <config.h>
#include <string.h>
#include <glib.h>
+#include "cairo-scale.h"
+#include "cairo-utils.h"
#include "glib-utils.h"
#include "gth-image-preloader.h"
+#include "gth-image-utils.h"
#include "gth-marshal.h"
@@ -121,15 +124,51 @@ cache_data_unref (CacheData *cache_data)
}
+static inline gboolean
+cache_data_file_matches (CacheData *cache_data,
+ GthFileData *file_data)
+{
+ if ((file_data == GTH_MODIFIED_IMAGE) && (cache_data->file_data == GTH_MODIFIED_IMAGE))
+ return TRUE;
+
+ if ((file_data == GTH_MODIFIED_IMAGE) || (cache_data->file_data == GTH_MODIFIED_IMAGE))
+ return FALSE;
+
+ if (g_file_equal (cache_data->file_data->file, file_data->file)
+ && (_g_time_val_cmp (gth_file_data_get_modification_time (file_data),
+ gth_file_data_get_modification_time (cache_data->file_data)) == 0))
+ {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
static gboolean
cache_data_is_valid_for_request (CacheData *cache_data,
GthFileData *file_data,
int requested_size)
{
- return ((cache_data->requested_size == requested_size)
- && g_file_equal (cache_data->file_data->file, file_data->file)
- && (_g_time_val_cmp (gth_file_data_get_modification_time (file_data),
- gth_file_data_get_modification_time (cache_data->file_data)) == 0));
+ if (! cache_data_file_matches (cache_data, file_data))
+ return FALSE;
+
+ return cache_data->requested_size == requested_size;
+}
+
+
+static gboolean
+cache_data_has_better_quality_for_request (CacheData *cache_data,
+ GthFileData *file_data,
+ int requested_size)
+{
+ if (! cache_data_file_matches (cache_data, file_data))
+ return FALSE;
+
+ if (requested_size == GTH_ORIGINAL_SIZE)
+ return FALSE;
+
+ return (cache_data->requested_size > requested_size) || (cache_data->requested_size ==
GTH_ORIGINAL_SIZE);
}
@@ -147,7 +186,7 @@ load_request_new (GthImagePreloader *preloader)
request->preloader = preloader;
request->files = NULL;
request->current_file = NULL;
- request->requested_size = -1;
+ request->requested_size = GTH_ORIGINAL_SIZE;
request->result = NULL;
request->cancellable = NULL;
@@ -248,9 +287,9 @@ gth_image_preloader_new (void)
static CacheData *
-_gth_image_preloader_lookup_request (GthImagePreloader *self,
- GthFileData *requested_file,
- int requested_size)
+_gth_image_preloader_lookup_same_size (GthImagePreloader *self,
+ GthFileData *requested_file,
+ int requested_size)
{
GList *scan;
@@ -264,6 +303,23 @@ _gth_image_preloader_lookup_request (GthImagePreloader *self,
}
+static CacheData *
+_gth_image_preloader_lookup_bigger_size (GthImagePreloader *self,
+ GthFileData *requested_file,
+ int requested_size)
+{
+ GList *scan;
+
+ for (scan = self->priv->cache->head; scan; scan = scan->next) {
+ CacheData *cache_data = scan->data;
+ if (cache_data_has_better_quality_for_request (cache_data, requested_file, requested_size))
+ return cache_data;
+ }
+
+ return NULL;
+}
+
+
static void
_gth_image_preloader_request_finished (GthImagePreloader *self,
LoadRequest *load_request)
@@ -300,13 +356,32 @@ load_current_file (gpointer user_data)
static void
-queue_load_next_file (GthImagePreloader *self,
- LoadRequest *request)
+_gth_image_preloader_request_completed (GthImagePreloader *self,
+ LoadRequest *request,
+ CacheData *cache_data)
{
- CacheData *cache_data;
+ if (request->current_file == request->requested_file) {
+ if (cache_data != NULL) {
+ g_simple_async_result_set_op_res_gpointer (request->result,
+ cache_data_ref (cache_data),
+ (GDestroyNotify) cache_data_unref);
+ g_simple_async_result_complete_in_idle (request->result);
+ }
+ else {
+ GError *error;
+
+ error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_NOT_FOUND, NULL);
+ g_simple_async_result_set_from_error (request->result, error);
+
+ g_error_free (error);
+ }
+ }
+
+ /* queue the next file */
g_return_if_fail (request->current_file != NULL);
+ cache_data = NULL;
do {
GthFileData *requested_file;
@@ -317,9 +392,9 @@ queue_load_next_file (GthImagePreloader *self,
}
requested_file = (GthFileData *) request->current_file->data;
- cache_data = _gth_image_preloader_lookup_request (self,
- requested_file,
- request->requested_size);
+ cache_data = _gth_image_preloader_lookup_same_size (self,
+ requested_file,
+ request->requested_size);
}
while (cache_data != NULL);
@@ -348,22 +423,137 @@ _gth_image_preloader_add_to_cache (GthImagePreloader *self,
}
+typedef struct {
+ LoadRequest *request;
+ gboolean resize_to_requested_size;
+} LoadData;
+
+
+static LoadData *
+load_data_new (LoadRequest *request,
+ gboolean resize_image)
+{
+ LoadData *load_data;
+
+ load_data = g_new0 (LoadData, 1);
+ load_data->request = load_request_ref (request);
+ load_data->resize_to_requested_size = resize_image;
+
+ return load_data;
+}
+
+
+static void
+load_data_free (LoadData *load_data)
+{
+ load_request_unref (load_data->request);
+ g_free (load_data);
+}
+
+
+static void
+image_scale_ready_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ LoadData *load_data = user_data;
+ LoadRequest *request = load_data->request;
+ GthImagePreloader *self = request->preloader;
+ cairo_surface_t *surface;
+ GError *error = NULL;
+ int original_width;
+ int original_height;
+ CacheData *cache_data;
+
+ if (request->finalized) {
+ load_data_free (load_data);
+ return;
+ }
+
+ surface = _cairo_image_surface_scale_finish (result, &error);
+
+ if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)
+ || (self->priv->last_request != request))
+ {
+ load_data_free (load_data);
+ if (error != NULL)
+ g_error_free (error);
+ cairo_surface_destroy (surface);
+ _gth_image_preloader_request_finished (self, request);
+
+ if (self->priv->last_request != NULL)
+ _gth_image_preloader_start_request (self, self->priv->last_request);
+
+ return;
+ }
+
+ if (! _cairo_image_surface_get_original_size (surface, &original_width, &original_height)) {
+ original_width = cairo_image_surface_get_width (surface);
+ original_height = cairo_image_surface_get_height (surface);
+ }
+ cache_data = cache_data_new ();
+ cache_data->file_data = _g_object_ref (request->current_file->data);
+ cache_data->image = (surface != NULL) ? gth_image_new_for_surface (surface) : NULL;
+ cache_data->original_width = (surface != NULL) ? original_width : -1;
+ cache_data->original_height = (surface != NULL) ? original_height : -1;
+ cache_data->requested_size = request->requested_size;
+ cache_data->error = error;
+ _gth_image_preloader_add_to_cache (self, cache_data);
+ _gth_image_preloader_request_completed (self, request, cache_data);
+
+ cairo_surface_destroy (surface);
+ load_data_free (load_data);
+}
+
+
+static void
+_gth_image_preloader_resize_at_requested_size (GthImagePreloader *self,
+ LoadRequest *request,
+ GthImage *image)
+{
+ cairo_surface_t *surface;
+ int new_width;
+ int new_height;
+
+ surface = gth_image_get_cairo_surface (image);
+ new_width = cairo_image_surface_get_width (surface);
+ new_height = cairo_image_surface_get_height (surface);
+ scale_keeping_ratio (&new_width,
+ &new_height,
+ request->requested_size,
+ request->requested_size,
+ FALSE);
+
+ _cairo_image_surface_scale_async (surface,
+ new_width,
+ new_height,
+ SCALE_FILTER_GOOD,
+ request->cancellable,
+ image_scale_ready_cb,
+ load_data_new (request, FALSE));
+
+ cairo_surface_destroy (surface);
+}
+
+
static void
image_loader_ready_cb (GObject *source_object,
GAsyncResult *result,
gpointer user_data)
{
- LoadRequest *request = user_data;
+ LoadData *load_data = user_data;
+ LoadRequest *request = load_data->request;
GthImagePreloader *self = request->preloader;
GthImage *image = NULL;
int original_width;
int original_height;
+ gboolean loaded_original;
GError *error = NULL;
gboolean success;
CacheData *cache_data;
if (request->finalized) {
- load_request_unref (request);
+ load_data_free (load_data);
return;
}
@@ -372,12 +562,13 @@ image_loader_ready_cb (GObject *source_object,
&image,
&original_width,
&original_height,
+ &loaded_original,
&error);
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)
|| (self->priv->last_request != request))
{
- load_request_unref (request);
+ load_data_free (load_data);
if (error != NULL)
g_error_free (error);
_g_object_unref (image);
@@ -398,17 +589,16 @@ image_loader_ready_cb (GObject *source_object,
cache_data->error = error;
_gth_image_preloader_add_to_cache (self, cache_data);
- if (request->current_file == request->requested_file) {
- g_simple_async_result_set_op_res_gpointer (request->result,
- cache_data_ref (cache_data),
- (GDestroyNotify) cache_data_unref);
- g_simple_async_result_complete_in_idle (request->result);
- }
+ if ((request->requested_size > 0) && loaded_original)
+ load_data->resize_to_requested_size = TRUE;
- queue_load_next_file (self, request);
+ if (load_data->resize_to_requested_size)
+ _gth_image_preloader_resize_at_requested_size (self, request, cache_data->image);
+ else
+ _gth_image_preloader_request_completed (self, request, cache_data);
_g_object_unref (image);
- load_request_unref (request);
+ load_data_free (load_data);
}
@@ -418,33 +608,46 @@ _gth_image_preloader_load_current_file (GthImagePreloader *self,
{
GthFileData *requested_file;
CacheData *cache_data;
+ gboolean ignore_requested_size;
g_return_if_fail (request->current_file != NULL);
-
requested_file = (GthFileData *) request->current_file->data;
- cache_data = _gth_image_preloader_lookup_request (self,
- requested_file,
- request->requested_size);
+
+ /* search the file at the requested size */
+
+ cache_data = _gth_image_preloader_lookup_same_size (self,
+ requested_file,
+ request->requested_size);
if (cache_data != NULL) {
- if (request->current_file == request->requested_file) {
- g_simple_async_result_set_op_res_gpointer (request->result,
- cache_data_ref (cache_data),
- (GDestroyNotify) cache_data_unref);
- g_simple_async_result_complete_in_idle (request->result);
- }
- queue_load_next_file (self, request);
+ _gth_image_preloader_request_completed (self, request, cache_data);
+ return;
+ }
+
+ /* search the file at a bigger size */
+ cache_data = _gth_image_preloader_lookup_bigger_size (self,
+ requested_file,
+ request->requested_size);
+ if (cache_data != NULL) {
+ _gth_image_preloader_resize_at_requested_size (self, request, cache_data->image);
return;
}
- load_request_ref (request);
+ /* load the file at the requested size */
+
+ if (requested_file == GTH_MODIFIED_IMAGE) {
+ _gth_image_preloader_request_completed (self, request, NULL);
+ return;
+ }
+
+ ignore_requested_size = (request->requested_size > 0) && ! g_file_is_native (requested_file->file);
gth_image_loader_load (self->priv->loader,
requested_file,
- request->requested_size,
+ ignore_requested_size ? -1 : request->requested_size,
(request->current_file == request->files) ? G_PRIORITY_HIGH :
G_PRIORITY_DEFAULT,
request->cancellable,
image_loader_ready_cb,
- request);
+ load_data_new (request, ignore_requested_size));
}
@@ -573,3 +776,37 @@ gth_image_preloader_load_finish (GthImagePreloader *self,
return TRUE;
}
+
+
+void
+gth_image_preloader_set_modified_image (GthImagePreloader *self,
+ cairo_surface_t *image)
+{
+ GList *scan;
+ CacheData *cache_data;
+
+ /* delete the modified image from the cache */
+
+ for (scan = self->priv->cache->head; scan; /* void */) {
+ GList *next = scan->next;
+
+ cache_data = scan->data;
+ if (cache_data->file_data == GTH_MODIFIED_IMAGE)
+ g_queue_delete_link (self->priv->cache, scan);
+ scan = next;
+ }
+
+ if (image == NULL)
+ return;
+
+ /* add the modified image to the cache */
+
+ cache_data = cache_data_new ();
+ cache_data->file_data = GTH_MODIFIED_IMAGE;
+ cache_data->image = gth_image_new_for_surface (image);
+ cache_data->original_width = -1;
+ cache_data->original_height = -1;
+ cache_data->requested_size = -1;
+ cache_data->error = NULL;
+ _gth_image_preloader_add_to_cache (self, cache_data);
+}
diff --git a/gthumb/gth-image-preloader.h b/gthumb/gth-image-preloader.h
index 0077213..dec9506 100644
--- a/gthumb/gth-image-preloader.h
+++ b/gthumb/gth-image-preloader.h
@@ -27,6 +27,7 @@
#define GTH_ORIGINAL_SIZE -1
#define GTH_NO_PRELOADERS 0
+#define GTH_MODIFIED_IMAGE NULL
#define GTH_TYPE_IMAGE_PRELOADER (gth_image_preloader_get_type ())
#define GTH_IMAGE_PRELOADER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTH_TYPE_IMAGE_PRELOADER,
GthImagePreloader))
@@ -48,23 +49,25 @@ struct _GthImagePreloaderClass {
GObjectClass __parent_class;
};
-GType gth_image_preloader_get_type (void) G_GNUC_CONST;
-GthImagePreloader * gth_image_preloader_new (void);
-void gth_image_preloader_load (GthImagePreloader *self,
- GthFileData *requested,
- int requested_size,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data,
- int n_files,
- ...);
-gboolean gth_image_preloader_load_finish (GthImagePreloader *self,
- GAsyncResult *result,
- GthFileData **requested,
- GthImage **image,
- int *requested_size,
- int *original_width,
- int *original_height,
- GError **error);
+GType gth_image_preloader_get_type (void) G_GNUC_CONST;
+GthImagePreloader * gth_image_preloader_new (void);
+void gth_image_preloader_load (GthImagePreloader *self,
+ GthFileData *requested,
+ int
requested_size,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data,
+ int n_files,
+ ...);
+gboolean gth_image_preloader_load_finish (GthImagePreloader
*self,
+ GAsyncResult *result,
+ GthFileData **requested,
+ GthImage **image,
+ int
*requested_size,
+ int
*original_width,
+ int
*original_height,
+ GError **error);
+void gth_image_preloader_set_modified_image (GthImagePreloader *self,
+ cairo_surface_t *image);
#endif /* GTH_IMAGE_PRELOADER_H */
diff --git a/gthumb/gth-image-utils.c b/gthumb/gth-image-utils.c
index ef14751..045030d 100644
--- a/gthumb/gth-image-utils.c
+++ b/gthumb/gth-image-utils.c
@@ -145,6 +145,7 @@ _g_buffer_resize_image (void *buffer,
&width,
&height,
NULL,
+ NULL,
cancellable,
error);
if (image == NULL) {
diff --git a/gthumb/gth-image.h b/gthumb/gth-image.h
index a4bf01c..49e38d9 100644
--- a/gthumb/gth-image.h
+++ b/gthumb/gth-image.h
@@ -71,6 +71,7 @@ typedef GthImage * (*GthImageLoaderFunc) (GInputStream *istream,
int requested_size,
int *original_width,
int *original_height,
+ gboolean *loaded_original,
gpointer user_data,
GCancellable *cancellable,
GError **error);
diff --git a/gthumb/gth-overwrite-dialog.c b/gthumb/gth-overwrite-dialog.c
index 33809a8..4191e90 100644
--- a/gthumb/gth-overwrite-dialog.c
+++ b/gthumb/gth-overwrite-dialog.c
@@ -103,6 +103,7 @@ image_loader_ready_cb (GObject *source_object,
&image,
NULL,
NULL,
+ NULL,
&error))
{
return;
diff --git a/gthumb/gth-task.c b/gthumb/gth-task.c
index 6136c19..5fe2e66 100644
--- a/gthumb/gth-task.c
+++ b/gthumb/gth-task.c
@@ -214,16 +214,6 @@ gth_task_init (GthTask *self)
}
-static void
-cancellable_cancelled_cb (GCancellable *cancellable,
- gpointer user_data)
-{
- GthTask *task = user_data;
-
- GTH_TASK_GET_CLASS (task)->cancelled (task);
-}
-
-
void
gth_task_exec (GthTask *task,
GCancellable *cancellable)
@@ -231,19 +221,7 @@ gth_task_exec (GthTask *task,
if (task->priv->running)
return;
- if (task->priv->cancellable != NULL) {
- g_cancellable_disconnect (task->priv->cancellable, task->priv->cancellable_cancelled);
- g_object_unref (task->priv->cancellable);
- }
-
- if (cancellable != NULL)
- task->priv->cancellable = _g_object_ref (cancellable);
- else
- task->priv->cancellable = g_cancellable_new ();
- task->priv->cancellable_cancelled = g_cancellable_connect (task->priv->cancellable,
- G_CALLBACK (cancellable_cancelled_cb),
- task,
- NULL);
+ gth_task_set_cancellable (task, cancellable);
if (task->priv->description != NULL)
gth_task_progress (task, task->priv->description, NULL, TRUE, 0.0);
@@ -260,6 +238,16 @@ gth_task_is_running (GthTask *task)
}
+static void
+cancellable_cancelled_cb (GCancellable *cancellable,
+ gpointer user_data)
+{
+ GthTask *task = user_data;
+
+ GTH_TASK_GET_CLASS (task)->cancelled (task);
+}
+
+
void
gth_task_cancel (GthTask *task)
{
@@ -270,6 +258,29 @@ gth_task_cancel (GthTask *task)
}
+void
+gth_task_set_cancellable (GthTask *task,
+ GCancellable *cancellable)
+{
+ if (task->priv->running)
+ return;
+
+ if (task->priv->cancellable != NULL) {
+ g_cancellable_disconnect (task->priv->cancellable, task->priv->cancellable_cancelled);
+ g_object_unref (task->priv->cancellable);
+ }
+
+ if (cancellable != NULL)
+ task->priv->cancellable = _g_object_ref (cancellable);
+ else
+ task->priv->cancellable = g_cancellable_new ();
+ task->priv->cancellable_cancelled = g_cancellable_connect (task->priv->cancellable,
+ G_CALLBACK (cancellable_cancelled_cb),
+ task,
+ NULL);
+}
+
+
GCancellable *
gth_task_get_cancellable (GthTask *task)
{
diff --git a/gthumb/gth-task.h b/gthumb/gth-task.h
index a8973e0..d21bdb3 100644
--- a/gthumb/gth-task.h
+++ b/gthumb/gth-task.h
@@ -81,6 +81,8 @@ void gth_task_exec (GthTask *task,
GCancellable *cancellable);
gboolean gth_task_is_running (GthTask *task);
void gth_task_cancel (GthTask *task);
+void gth_task_set_cancellable (GthTask *task,
+ GCancellable *cancellable);
GCancellable * gth_task_get_cancellable (GthTask *task);
void gth_task_completed (GthTask *task,
GError *error);
diff --git a/gthumb/gth-thumb-loader.c b/gthumb/gth-thumb-loader.c
index a1c688c..36f5aa9 100644
--- a/gthumb/gth-thumb-loader.c
+++ b/gthumb/gth-thumb-loader.c
@@ -119,6 +119,7 @@ generate_thumbnail (GInputStream *istream,
int requested_size,
int *original_width,
int *original_height,
+ gboolean *loaded_original,
gpointer user_data,
GCancellable *cancellable,
GError **error)
@@ -187,6 +188,7 @@ generate_thumbnail (GInputStream *istream,
original_width,
original_height,
NULL,
+ NULL,
cancellable,
error);
}
@@ -206,6 +208,7 @@ load_cached_thumbnail (GInputStream *istream,
int requested_size,
int *original_width,
int *original_height,
+ gboolean *loaded_original,
gpointer user_data,
GCancellable *cancellable,
GError **error)
@@ -443,6 +446,7 @@ cache_image_ready_cb (GObject *source_object,
&image,
NULL,
NULL,
+ NULL,
NULL))
{
/* error loading the thumbnail from the cache, try to generate
@@ -757,6 +761,7 @@ original_image_ready_cb (GObject *source_object,
&image,
&original_width,
&original_height,
+ NULL,
&error))
{
/* error loading the original image, try with the system
diff --git a/gthumb/pixbuf-io.c b/gthumb/pixbuf-io.c
index 8715364..b826748 100644
--- a/gthumb/pixbuf-io.c
+++ b/gthumb/pixbuf-io.c
@@ -205,6 +205,7 @@ gth_pixbuf_animation_new_from_file (GInputStream *istream,
int requested_size,
int *original_width,
int *original_height,
+ gboolean *loaded_original,
gpointer user_data,
GCancellable *cancellable,
GError **error)
diff --git a/gthumb/pixbuf-io.h b/gthumb/pixbuf-io.h
index b0ca8f3..f38468a 100644
--- a/gthumb/pixbuf-io.h
+++ b/gthumb/pixbuf-io.h
@@ -43,6 +43,7 @@ GthImage * gth_pixbuf_animation_new_from_file (GInputStream *istream,
int requested_size,
int *original_width,
int *original_height,
+ gboolean *loaded_original,
gpointer user_data,
GCancellable *cancellable,
GError **error);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]