[gthumb] cairo scale: moved cairo-scale.[ch] in gthumb



commit 3d073ff3056b2dbd2c3865221eb6ea74119965d7
Author: Paolo Bacchilega <paobac src gnome org>
Date:   Fri Aug 17 18:05:51 2012 +0200

    cairo scale: moved cairo-scale.[ch] in gthumb
    
    and use it instead of _cairo_image_curface_scale_to that uses the cairo
    bilinear filter.

 extensions/cairo_io/cairo-io-jpeg.c             |    2 +-
 extensions/file_tools/Makefile.am               |    2 -
 extensions/file_tools/gth-file-tool-resize.c    |    4 +-
 extensions/file_tools/gth-image-line-tool.c     |    2 +-
 extensions/file_tools/gth-image-rotator.c       |    2 +-
 gthumb/Makefile.am                              |    2 +
 {extensions/file_tools => gthumb}/cairo-scale.c |  194 ++++++++++++++---------
 {extensions/file_tools => gthumb}/cairo-scale.h |   31 +++-
 gthumb/cairo-utils.c                            |   23 ---
 gthumb/cairo-utils.h                            |    6 +-
 gthumb/gth-image-navigator.c                    |   11 +-
 11 files changed, 157 insertions(+), 122 deletions(-)
---
diff --git a/extensions/cairo_io/cairo-io-jpeg.c b/extensions/cairo_io/cairo-io-jpeg.c
index acf15fa..a23e2cc 100644
--- a/extensions/cairo_io/cairo-io-jpeg.c
+++ b/extensions/cairo_io/cairo-io-jpeg.c
@@ -497,7 +497,7 @@ _cairo_image_surface_create_from_jpeg (GthFileData   *file_data,
 			width = destination_width;
 			height = destination_height;
 			scale_keeping_ratio (&width, &height, requested_size, requested_size, TRUE);
-			scaled = _cairo_image_surface_scale_to (surface, width, height, CAIRO_FILTER_BILINEAR);
+			scaled = _cairo_image_surface_scale (surface, width, height, SCALE_FILTER_BEST, NULL);
 
 			cairo_surface_destroy (surface);
 			surface = scaled;
diff --git a/extensions/file_tools/Makefile.am b/extensions/file_tools/Makefile.am
index 0c60238..feab2a1 100644
--- a/extensions/file_tools/Makefile.am
+++ b/extensions/file_tools/Makefile.am
@@ -10,7 +10,6 @@ ENUM_TYPES =		\
 HEADER_FILES = 				\
 	cairo-blur.h			\
 	cairo-rotate.h			\
-	cairo-scale.h			\
 	gth-file-tool-adjust-colors.h	\
 	gth-file-tool-crop.h		\
 	gth-file-tool-desaturate.h	\
@@ -59,7 +58,6 @@ libfile_tools_la_SOURCES = 		\
 	callbacks.h			\
 	cairo-blur.c			\
 	cairo-rotate.c			\
-	cairo-scale.c			\
 	gth-file-tool-adjust-colors.c	\
 	gth-file-tool-crop.c		\
 	gth-file-tool-desaturate.c	\
diff --git a/extensions/file_tools/gth-file-tool-resize.c b/extensions/file_tools/gth-file-tool-resize.c
index f7bec9c..369e197 100644
--- a/extensions/file_tools/gth-file-tool-resize.c
+++ b/extensions/file_tools/gth-file-tool-resize.c
@@ -24,7 +24,6 @@
 #include <gthumb.h>
 #include <extensions/image_viewer/gth-image-viewer-page.h>
 #include <extensions/image_viewer/preferences.h>
-#include "cairo-scale.h"
 #include "gth-file-tool-resize.h"
 #include "preferences.h"
 
@@ -128,7 +127,8 @@ update_pixbuf_size (GthFileToolResize *self)
 	self->priv->new_image = _cairo_image_surface_scale (self->priv->original_image,
 							    self->priv->new_width,
 							    self->priv->new_height,
-							    self->priv->high_quality);
+							    (self->priv->high_quality ? SCALE_FILTER_BEST : SCALE_FILTER_FAST),
+							    NULL);
 	window = gth_file_tool_get_window (GTH_FILE_TOOL (self));
 	viewer_page = gth_browser_get_viewer_page (GTH_BROWSER (window));
 	gth_image_viewer_page_set_image (GTH_IMAGE_VIEWER_PAGE (viewer_page), self->priv->new_image, FALSE);
diff --git a/extensions/file_tools/gth-image-line-tool.c b/extensions/file_tools/gth-image-line-tool.c
index 6a77052..09f532f 100644
--- a/extensions/file_tools/gth-image-line-tool.c
+++ b/extensions/file_tools/gth-image-line-tool.c
@@ -147,7 +147,7 @@ update_image_surface (GthImageLineTool *self)
 	gtk_widget_get_allocation (GTK_WIDGET (self->priv->viewer), &allocation);
 	max_size = MAX (allocation.width, allocation.height) / G_SQRT2 + 2;
 	if (scale_keeping_ratio (&width, &height, max_size, max_size, FALSE))
-		preview_image = _cairo_image_surface_scale_to (image, width, height, CAIRO_FILTER_BILINEAR);
+		preview_image = _cairo_image_surface_scale (image, width, height, SCALE_FILTER_BEST, NULL);
 	else
 		preview_image = cairo_surface_reference (image);
 
diff --git a/extensions/file_tools/gth-image-rotator.c b/extensions/file_tools/gth-image-rotator.c
index 4fdc78b..0d9c752 100644
--- a/extensions/file_tools/gth-image-rotator.c
+++ b/extensions/file_tools/gth-image-rotator.c
@@ -239,7 +239,7 @@ update_image_surface (GthImageRotator *self)
 	gtk_widget_get_allocation (GTK_WIDGET (self->priv->viewer), &allocation);
 	max_size = MAX (allocation.width, allocation.height) / G_SQRT2 + 2;
 	if (scale_keeping_ratio (&width, &height, max_size, max_size, FALSE))
-		preview_image = _cairo_image_surface_scale_to (image, width, height, CAIRO_FILTER_BILINEAR);
+		preview_image = _cairo_image_surface_scale (image, width, height, SCALE_FILTER_BEST, NULL);
 	else
 		preview_image = cairo_surface_reference (image);
 
diff --git a/gthumb/Makefile.am b/gthumb/Makefile.am
index 4e279f0..213ca02 100644
--- a/gthumb/Makefile.am
+++ b/gthumb/Makefile.am
@@ -24,6 +24,7 @@ PUBLIC_BUILT_HEADER_FILES =				\
 
 PUBLIC_HEADER_FILES = 					\
 	$(PUBLIC_BUILT_HEADER_FILES)			\
+	cairo-scale.h					\
 	cairo-utils.h					\
 	dom.h						\
 	egg-macros.h					\
@@ -146,6 +147,7 @@ gthumb_SOURCES = 					\
 	$(EXTERNAL)					\
 	$(PUBLIC_HEADER_FILES)				\
 	$(PRIVATE_HEADER_FILES)				\
+	cairo-scale.c					\
 	cairo-utils.c					\
 	dlg-location.c					\
 	dlg-personalize-filters.c			\
diff --git a/extensions/file_tools/cairo-scale.c b/gthumb/cairo-scale.c
similarity index 70%
rename from extensions/file_tools/cairo-scale.c
rename to gthumb/cairo-scale.c
index 566a085..3ca59f0 100644
--- a/extensions/file_tools/cairo-scale.c
+++ b/gthumb/cairo-scale.c
@@ -19,14 +19,14 @@
  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <config.h>
+#include <string.h>
 #include <math.h>
-#include <gthumb.h>
+#include <cairo.h>
+#include "cairo-utils.h"
 #include "cairo-scale.h"
 
 
-/* -- _cairo_image_surface_scale_nearest -- */
-
-
 typedef long gfixed;
 #define GINT_TO_FIXED(x)         ((gfixed) ((x) << 16))
 #define GDOUBLE_TO_FIXED(x)      ((gfixed) ((x) * (1 << 16) + 0.5))
@@ -40,7 +40,13 @@ typedef long gfixed;
 #define gfixed_div(x, y)         (((x) << 16) / (y))
 
 
-cairo_surface_t *
+#if 0
+
+
+/* -- _cairo_image_surface_scale_nearest -- */
+
+
+static cairo_surface_t *
 _cairo_image_surface_scale_nearest (cairo_surface_t *image,
 				    int              new_width,
 				    int              new_height)
@@ -110,7 +116,14 @@ _cairo_image_surface_scale_nearest (cairo_surface_t *image,
 }
 
 
-/* -- _cairo_image_surface_scale_filter -- */
+#endif
+
+
+/* -- _cairo_image_surface_scale_filter --
+ *
+ * Based on code from ImageMagick/magick/resize.c
+ *
+ * */
 
 
 #define EPSILON ((double) 1.0e-16)
@@ -119,15 +132,6 @@ _cairo_image_surface_scale_nearest (cairo_surface_t *image,
 typedef double (*weight_func_t) (double distance);
 
 
-typedef enum {
-	FILTER_POINT = 0,
-	FILTER_BOX,
-	FILTER_TRIANGLE,
-	FILTER_QUADRATIC,
-	N_FILTERS
-} filter_type_t;
-
-
 static double
 box (double x)
 {
@@ -143,16 +147,35 @@ triangle (double x)
 
 
 static double
-quadratic (double x)
+sinc_fast (double x)
 {
-	/*
-	 * 2rd order (quadratic) B-Spline approximation of Gaussian.
-	 */
-	if (x < 0.5)
-		return 0.75 - x * x;
-	if (x < 1.5)
-		return 0.5 * (x - 1.5) * (x - 1.5);
-	return 0.0;
+	if (x > 4.0) {
+		const double alpha = G_PI * x;
+		return sin (alpha) / alpha;
+	}
+
+	{
+		/*
+		 * The approximations only depend on x^2 (sinc is an even function).
+		 */
+
+		const double xx = x*x;
+
+		/*
+		 * Maximum absolute relative error 6.3e-6 < 1/2^17.
+		 */
+		const double c0 = 0.173610016489197553621906385078711564924e-2L;
+		const double c1 = -0.384186115075660162081071290162149315834e-3L;
+		const double c2 = 0.393684603287860108352720146121813443561e-4L;
+		const double c3 = -0.248947210682259168029030370205389323899e-5L;
+		const double c4 = 0.107791837839662283066379987646635416692e-6L;
+		const double c5 = -0.324874073895735800961260474028013982211e-8L;
+		const double c6 = 0.628155216606695311524920882748052490116e-10L;
+		const double c7 = -0.586110644039348333520104379959307242711e-12L;
+		const double p = c0+xx*(c1+xx*(c2+xx*(c3+xx*(c4+xx*(c5+xx*(c6+xx*c7))))));
+
+		return (xx-1.0)*(xx-4.0)*(xx-9.0)*(xx-16.0)*p;
+	}
 }
 
 
@@ -160,11 +183,11 @@ static struct {
 	weight_func_t weight_func;
 	double        support;
 }
-const filters[N_FILTERS] = {
+const filters[N_SCALE_FILTERS] = {
 	{ box,		 .0 },
 	{ box,		 .5 },
 	{ triangle,	1.0 },
-	{ quadratic,	1.5 }
+	{ sinc_fast,	3.0 }
 };
 
 
@@ -172,19 +195,28 @@ const filters[N_FILTERS] = {
 
 
 typedef struct {
-	weight_func_t weight_func;
-	double        support;
+	weight_func_t  weight_func;
+	double         support;
+	GthAsyncTask  *task;
+	gulong         total_lines;
+	gulong         processed_lines;
+	gboolean       cancelled;
 } resize_filter_t;
 
 
 static resize_filter_t *
-resize_filter_create (filter_type_t filter)
+resize_filter_create (scale_filter_t  filter_type,
+		      GthAsyncTask   *task)
 {
 	resize_filter_t *resize_filter;
 
 	resize_filter = g_slice_new (resize_filter_t);
-	resize_filter->weight_func = filters[filter].weight_func;
-	resize_filter->support = filters[filter].support;
+	resize_filter->weight_func = filters[filter_type].weight_func;
+	resize_filter->support = filters[filter_type].support;
+	resize_filter->task = task;
+	resize_filter->total_lines = 0;
+	resize_filter->processed_lines = 0;
+	resize_filter->cancelled = FALSE;
 
 	return resize_filter;
 }
@@ -201,7 +233,12 @@ static double inline
 resize_filter_get_weight (resize_filter_t *resize_filter,
 			  double           distance)
 {
-	return resize_filter->weight_func (fabs (distance));
+	double scale = 1.0;
+
+	if (resize_filter->weight_func == sinc_fast)
+		scale = resize_filter->weight_func (fabs (distance));
+
+	return scale * resize_filter->weight_func (fabs (distance));
 }
 
 
@@ -229,15 +266,18 @@ horizontal_scale_transpose (cairo_surface_t *image,
 			    double           scale_factor,
 			    resize_filter_t *resize_filter)
 {
-	double  scale;
-	double  support;
-	int     y;
-	guchar *p_src;
-        guchar *p_dest;
-        int     src_rowstride;
-        int     dest_rowstride;
-        double *weights;
-        gfixed *fixed_weights;
+	double    scale;
+	double    support;
+	int       y;
+	guchar   *p_src;
+        guchar   *p_dest;
+        int       src_rowstride;
+        int       dest_rowstride;
+        double   *weights;
+        gfixed   *fixed_weights;
+
+	if (resize_filter->cancelled)
+		return;
 
         cairo_surface_flush (scaled);
 
@@ -256,7 +296,7 @@ horizontal_scale_transpose (cairo_surface_t *image,
 	fixed_weights = g_new (gfixed, 2.0 * support + 3.0);
 
 	scale = reciprocal (scale);
-	for (y = 0; y < cairo_image_surface_get_height (scaled); y++) {
+	for (y = 0; ! resize_filter->cancelled && (y < cairo_image_surface_get_height (scaled)); y++) {
 	        guchar *p_src_row;
 	        guchar *p_dest_pixel;
 		double  bisect;
@@ -267,6 +307,11 @@ horizontal_scale_transpose (cairo_surface_t *image,
 		int     x;
 		int     i;
 
+		if (resize_filter->task != NULL) {
+			double progress = (double) resize_filter->processed_lines++ / resize_filter->total_lines;
+			gth_async_task_set_data (resize_filter->task, NULL, NULL, &progress);
+		}
+
 		bisect = (y + 0.5) / scale_factor + EPSILON;
 		start = MAX (bisect - support + 0.5, 0.0);
 		stop = MIN (bisect + support + 0.5, cairo_image_surface_get_width (image));
@@ -278,8 +323,10 @@ horizontal_scale_transpose (cairo_surface_t *image,
 		}
 
 		density = reciprocal (density);
-		for (i = 0; i < n; i++)
-			fixed_weights[i] = GDOUBLE_TO_FIXED (weights[i] * density);
+		for (i = 0; i < n; i++) {
+			double w = weights[i] * density;
+			fixed_weights[i] = GDOUBLE_TO_FIXED (w);
+		}
 
 		p_src_row = p_src;
 		p_dest_pixel = p_dest + (y * dest_rowstride);
@@ -288,6 +335,12 @@ horizontal_scale_transpose (cairo_surface_t *image,
 			gfixed  r, g, b, a;
 			gfixed  w;
 
+			if (resize_filter->task != NULL) {
+				gth_async_task_get_data (resize_filter->task, NULL, &resize_filter->cancelled, NULL);
+				if (resize_filter->cancelled)
+					break;
+			}
+
 			p_src_pixel = p_src_row + (start * 4);
 			r = g = b = a = GFIXED_0;
 
@@ -323,11 +376,12 @@ horizontal_scale_transpose (cairo_surface_t *image,
 }
 
 
-cairo_surface_t *
+static cairo_surface_t *
 _cairo_image_surface_scale_filter (cairo_surface_t *image,
 				   int              new_width,
 				   int              new_height,
-				   filter_type_t    filter)
+				   scale_filter_t   filter,
+				   GthAsyncTask    *task)
 {
 	int              src_width;
 	int              src_height;
@@ -350,7 +404,10 @@ _cairo_image_surface_scale_filter (cairo_surface_t *image,
 	if (scaled == NULL)
 		return NULL;
 
-	resize_filter = resize_filter_create (filter);
+	resize_filter = resize_filter_create (filter, task);
+	resize_filter->total_lines = new_width + new_height;
+	resize_filter->processed_lines = 0;
+
 	x_factor = (double) new_width / src_width;
 	y_factor = (double) new_height / src_height;
 	tmp = cairo_surface_create_similar_image (image,
@@ -360,6 +417,12 @@ _cairo_image_surface_scale_filter (cairo_surface_t *image,
 	horizontal_scale_transpose (image, tmp, x_factor, resize_filter);
 	horizontal_scale_transpose (tmp, scaled, y_factor, resize_filter);
 
+	/* FIXME
+	if (resize_filter->task != NULL) {
+		gboolean terminated = TRUE;
+		gth_async_task_set_data (resize_filter->task, &terminated, NULL, NULL);
+	}*/
+
 	resize_filter_destroy (resize_filter);
 	cairo_surface_destroy (tmp);
 
@@ -368,32 +431,15 @@ _cairo_image_surface_scale_filter (cairo_surface_t *image,
 
 
 cairo_surface_t *
-_cairo_image_surface_scale (cairo_surface_t *image,
-			    int              scaled_width,
-			    int              scaled_height,
-			    gboolean         high_quality)
+_cairo_image_surface_scale (cairo_surface_t  *image,
+			    int               scaled_width,
+			    int               scaled_height,
+			    scale_filter_t    filter,
+			    GthAsyncTask     *task)
 {
-#if 0
-
-	GdkPixbuf       *p;
-	GdkPixbuf       *scaled_p;
-	cairo_surface_t *scaled;
-
-	p = _gdk_pixbuf_new_from_cairo_surface (image);
-	scaled_p = _gdk_pixbuf_scale_simple_safe (p, scaled_width, scaled_height, high_quality ? GDK_INTERP_BILINEAR : GDK_INTERP_NEAREST);
-	scaled = _cairo_image_surface_create_from_pixbuf (scaled_p);
-
-	g_object_unref (scaled_p);
-	g_object_unref (p);
-
-	return scaled;
-
-#else
-
-	if (high_quality)
-		return _cairo_image_surface_scale_filter (image, scaled_width, scaled_height, FILTER_TRIANGLE);
-	else
-		return _cairo_image_surface_scale_nearest (image, scaled_width, scaled_height);
-
-#endif
+	return _cairo_image_surface_scale_filter (image,
+						  scaled_width,
+						  scaled_height,
+						  filter,
+						  task);
 }
diff --git a/extensions/file_tools/cairo-scale.h b/gthumb/cairo-scale.h
similarity index 64%
rename from extensions/file_tools/cairo-scale.h
rename to gthumb/cairo-scale.h
index 3e6563c..e8fa062 100644
--- a/extensions/file_tools/cairo-scale.h
+++ b/gthumb/cairo-scale.h
@@ -19,19 +19,34 @@
  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#ifndef CAIRO_ROTATE_H
-#define CAIRO_ROTATE_H
+#ifndef CAIRO_SCALE_H
+#define CAIRO_SCALE_H
 
 #include <glib.h>
-#include <gdk/gdk.h>
+#include "gth-async-task.h"
 
 G_BEGIN_DECLS
 
-cairo_surface_t *  _cairo_image_surface_scale  (cairo_surface_t *image,
-						int              width,
-						int              height,
-						gboolean         high_quality);
+
+typedef enum /*< skip >*/ {
+	SCALE_FILTER_POINT = 0,
+	SCALE_FILTER_BOX,
+	SCALE_FILTER_TRIANGLE,
+	SCALE_FILTER_LANCZOS,
+	N_SCALE_FILTERS,
+
+	SCALE_FILTER_FAST = SCALE_FILTER_POINT,
+	SCALE_FILTER_GOOD = SCALE_FILTER_BOX,
+	SCALE_FILTER_BEST = SCALE_FILTER_LANCZOS
+} scale_filter_t;
+
+
+cairo_surface_t *  _cairo_image_surface_scale  (cairo_surface_t  *image,
+						int               width,
+						int               height,
+						scale_filter_t    quality,
+						GthAsyncTask     *task);
 
 G_END_DECLS
 
-#endif /* CAIRO_ROTATE_H */
+#endif /* CAIRO_SCALE_H */
diff --git a/gthumb/cairo-utils.c b/gthumb/cairo-utils.c
index d5ec6c5..9aa7360 100644
--- a/gthumb/cairo-utils.c
+++ b/gthumb/cairo-utils.c
@@ -340,29 +340,6 @@ _cairo_image_surface_create_compatible (cairo_surface_t *surface)
 }
 
 
-cairo_surface_t *
-_cairo_image_surface_scale_to (cairo_surface_t *surface,
-			       int              width,
-			       int              height,
-			       cairo_filter_t   filter)
-{
-	cairo_surface_t *scaled;
-	cairo_t         *cr;
-
-	scaled = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
-	cr = cairo_create (scaled);
-	cairo_scale (cr, (double) width / cairo_image_surface_get_width (surface), (double) height / cairo_image_surface_get_height (surface));
-	cairo_set_source_surface (cr, surface, 0, 0);
-	cairo_pattern_set_filter (cairo_get_source (cr), filter);
-	cairo_rectangle (cr, 0, 0, cairo_image_surface_get_width (surface), cairo_image_surface_get_height (surface));
-	cairo_fill (cr);
-
-	cairo_destroy (cr);
-
-	return scaled;
-}
-
-
 void
 _cairo_image_surface_transform_get_steps (cairo_format_t  format,
 					  int             width,
diff --git a/gthumb/cairo-utils.h b/gthumb/cairo-utils.h
index 2da4e63..0acbc1f 100644
--- a/gthumb/cairo-utils.h
+++ b/gthumb/cairo-utils.h
@@ -160,10 +160,6 @@ cairo_surface_t *  _cairo_image_surface_copy_subsurface     (cairo_surface_t
 				      	      	      	     int                    height);
 cairo_surface_t *  _cairo_image_surface_create_from_pixbuf  (GdkPixbuf             *pixbuf);
 cairo_surface_t *  _cairo_image_surface_create_compatible   (cairo_surface_t       *surface);
-cairo_surface_t *  _cairo_image_surface_scale_to            (cairo_surface_t       *surface,
-							     int                    width,
-							     int                    height,
-							     cairo_filter_t         filter);
 void               _cairo_image_surface_transform_get_steps (cairo_format_t         format,
 							     int                    width,
 							     int                    height,
@@ -210,7 +206,7 @@ void              _cairo_draw_slide                         (cairo_t
 		   	   	   	   	 	     double                 image_height,
 		   	   	   	   	 	     GdkColor              *frame_color,
 		   	   	   	   	 	     gboolean               draw_inner_border);
-void              _cairo_paint_grid                          (cairo_t              *cr,
+void              _cairo_paint_grid                         (cairo_t               *cr,
 							     cairo_rectangle_int_t *rectangle,
 							     GthGridType            grid_type);
 
diff --git a/gthumb/gth-image-navigator.c b/gthumb/gth-image-navigator.c
index 2065971..01fedab 100644
--- a/gthumb/gth-image-navigator.c
+++ b/gthumb/gth-image-navigator.c
@@ -22,7 +22,7 @@
 #include <config.h>
 #include <math.h>
 #include <gdk/gdkkeysyms.h>
-#include "cairo-utils.h"
+#include "cairo-scale.h"
 #include "gth-image-navigator.h"
 #include "gth-image-viewer.h"
 #include "gtk-utils.h"
@@ -393,10 +393,11 @@ update_popup_geometry (NavigatorPopup *nav_popup)
 	nav_popup->popup_height = MAX ((int) floor (nav_popup->zoom_factor * zoomed_height + 0.5), 1);
 
 	cairo_surface_destroy (nav_popup->image);
-	nav_popup->image = _cairo_image_surface_scale_to (gth_image_viewer_get_current_image (nav_popup->viewer),
-							  nav_popup->popup_width,
-							  nav_popup->popup_height,
-							  CAIRO_FILTER_GOOD);
+	nav_popup->image = _cairo_image_surface_scale (gth_image_viewer_get_current_image (nav_popup->viewer),
+						       nav_popup->popup_width,
+						       nav_popup->popup_height,
+						       SCALE_FILTER_GOOD,
+						       NULL);
 
 	/* visible area size */
 



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