[gthumb] optimized the interpolation function



commit e5f295500a0462e48c1bd94eb91168370a05d348
Author: Paolo Bacchilega <paobac src gnome org>
Date:   Wed Jul 4 17:10:26 2012 +0200

    optimized the interpolation function
    
    removed CLAMP from the interpolate_value function otherwise the
    interpolation is calculated twice.

 extensions/file_tools/cairo-blur.c                 |   28 +++--
 extensions/file_tools/cairo-rotate.c               |  131 ++++++++++++--------
 .../file_tools/gth-file-tool-adjust-colors.c       |   28 +++--
 gthumb/cairo-utils.h                               |    2 +-
 gthumb/glib-utils.h                                |    7 +-
 gthumb/gth-image-navigator.c                       |    3 +-
 6 files changed, 127 insertions(+), 72 deletions(-)
---
diff --git a/extensions/file_tools/cairo-blur.c b/extensions/file_tools/cairo-blur.c
index 287a2fd..8afde57 100644
--- a/extensions/file_tools/cairo-blur.c
+++ b/extensions/file_tools/cairo-blur.c
@@ -60,7 +60,7 @@ box_blur (cairo_surface_t *source,
 	width_minus_1 = width - 1;
 	for (y = 0; y < height; y++) {
 
-		/* calc the initial sums of the kernel */
+		/* calculate the initial sums of the kernel */
 
 		r = g = b = a = 0;
 
@@ -99,7 +99,7 @@ box_blur (cairo_surface_t *source,
 				i2 = 0;
 			c2 = p_src + (i2 * 4);
 
-			/* calc the new sums of the kernel */
+			/* calculate the new sums of the kernel */
 
 			r += c1[CAIRO_RED] - c2[CAIRO_RED];
 			g += c1[CAIRO_GREEN] - c2[CAIRO_GREEN];
@@ -121,7 +121,7 @@ box_blur (cairo_surface_t *source,
 	height_minus_1 = height - 1;
 	for (x = 0; x < width; x++) {
 
-		/* calc the initial sums of the kernel */
+		/* calculate the initial sums of the kernel */
 
 		r = g = b = a = 0;
 
@@ -160,7 +160,7 @@ box_blur (cairo_surface_t *source,
 				i2 = 0;
 			c2 = p_src + (i2 * src_rowstride);
 
-			/* calc the new sums of the kernel */
+			/* calculate the new sums of the kernel */
 
 			r += c1[CAIRO_RED] - c2[CAIRO_RED];
 			g += c1[CAIRO_GREEN] - c2[CAIRO_GREEN];
@@ -186,6 +186,8 @@ _cairo_image_surface_box_blur (cairo_surface_t *source,
 	cairo_surface_t *tmp;
 
 	kernel_size = 2 * radius + 1;
+
+	/* optimization to avoid divisions: div_kernel_size[x] == x / kernel_size */
 	div_kernel_size = g_new (guchar, 256 * kernel_size);
 	for (i = 0; i < 256 * kernel_size; i++)
 		div_kernel_size[i] = (guchar) (i / kernel_size);
@@ -223,6 +225,7 @@ _cairo_image_surface_sharpen (cairo_surface_t *source,
 	guchar          *p_src_row, *p_blurred_row;
 	guchar           r1, g1, b1;
 	guchar           r2, g2, b2;
+	int              tmp;
 
 	blurred = _cairo_image_surface_copy (source);
 	_cairo_image_surface_blur (blurred, radius);
@@ -235,6 +238,12 @@ _cairo_image_surface_sharpen (cairo_surface_t *source,
 	p_src = cairo_image_surface_get_data (source);
 	p_blurred = cairo_image_surface_get_data (blurred);
 
+#define ASSIGN_INTERPOLATED_VALUE(x1, x2)			\
+	if (ABS (x1 - x2) >= threshold) {			\
+		tmp = interpolate_value (x1, x2, amount);	\
+		x1 = CLAMP (tmp, 0, 255);			\
+	}
+
 	for (y = 0; y < height; y++) {
 		p_src_row = p_src;
 		p_blurred_row = p_blurred;
@@ -248,12 +257,9 @@ _cairo_image_surface_sharpen (cairo_surface_t *source,
 			g2 = p_blurred_row[CAIRO_GREEN];
 			b2 = p_blurred_row[CAIRO_BLUE];
 
-			if (ABS (r1 - r2) >= threshold)
-				r1 = interpolate_value (r1, r2, amount);
-			if (ABS (g1 - g2) >= threshold)
-				g1 = interpolate_value (g1, g2, amount);
-			if (ABS (b1 - b2) >= threshold)
-				b1 = interpolate_value (b1, b2, amount);
+			ASSIGN_INTERPOLATED_VALUE (r1, r2)
+			ASSIGN_INTERPOLATED_VALUE (g1, g2)
+			ASSIGN_INTERPOLATED_VALUE (b1, b2)
 
 			p_src_row[CAIRO_RED] = r1;
 			p_src_row[CAIRO_GREEN] = g1;
@@ -267,5 +273,7 @@ _cairo_image_surface_sharpen (cairo_surface_t *source,
 		p_blurred += blurred_rowstride;
 	}
 
+#undef ASSIGN_INTERPOLATED_VALUE
+
 	cairo_surface_destroy (blurred);
 }
diff --git a/extensions/file_tools/cairo-rotate.c b/extensions/file_tools/cairo-rotate.c
index ee2f0c5..5830e4b 100644
--- a/extensions/file_tools/cairo-rotate.c
+++ b/extensions/file_tools/cairo-rotate.c
@@ -24,26 +24,6 @@
 #include "cairo-rotate.h"
 
 
-#define ROUND(x) ((int) floor ((x) + 0.5))
-
-#define INTERPOLATE(v00, v10, v01, v11, fx, fy) ((v00) + ((v10) - (v00)) * (fx) + ((v01) - (v00)) * (fy) + ((v00) - (v10) - (v01) + (v11)) * (fx) * (fy))
-
-#define GET_VALUES(r, g, b, a, x, y) \
-			if (x >= 0 && x < src_width && y >= 0 && y < src_height) { \
-				p_src2 = p_src + src_rowstride * y + 4 * x; \
-				r = p_src2[CAIRO_RED]; \
-				g = p_src2[CAIRO_GREEN]; \
-				b = p_src2[CAIRO_BLUE]; \
-				a = p_src2[CAIRO_ALPHA]; \
-			} \
-			else { \
-				r = r0; \
-				g = g0; \
-				b = b0; \
-				a = a0; \
-			}
-
-
 void
 _cairo_image_surface_rotate_get_cropping_parameters (cairo_surface_t *image,
 						     double           angle,
@@ -138,11 +118,11 @@ _cairo_image_surface_rotate_get_cropping_region (cairo_surface_t       *image,
 		xx2 = new_width - xx2;
 	}
 
-	region->x = ROUND (MIN (xx1, xx2));
-	region->y = ROUND (MIN (yy1, yy2));
+	region->x = GDOUBLE_ROUND_TO_INT (MIN (xx1, xx2));
+	region->y = GDOUBLE_ROUND_TO_INT (MIN (yy1, yy2));
 
-	region->width  = ROUND (MAX (xx1, xx2)) - region->x + 1;
-	region->height = ROUND (MAX (yy1, yy2)) - region->y + 1;
+	region->width  = GDOUBLE_ROUND_TO_INT (MAX (xx1, xx2)) - region->x + 1;
+	region->height = GDOUBLE_ROUND_TO_INT (MAX (yy1, yy2)) - region->y + 1;
 }
 
 
@@ -173,7 +153,7 @@ _cairo_image_surface_rotate_get_align_angle (gboolean  vertical,
 	}
 
 	angle = angle * 180.0 / G_PI;
-	angle = ROUND (angle * 10.0) / 10.0;
+	angle = GDOUBLE_ROUND_TO_INT (angle * 10.0) / 10.0;
 
 	return angle;
 }
@@ -207,6 +187,11 @@ rotate (cairo_surface_t *image,
 	guchar           g00, g01, g10, g11;
 	guchar           b00, b01, b10, b11;
 	guchar           a00, a01, a10, a11;
+	double           half_new_width;
+	double           half_new_height;
+	double           half_src_width;
+	double           half_src_height;
+	int              tmp;
 	guchar           r, g, b, a;
 	guint32          pixel;
 
@@ -214,10 +199,10 @@ rotate (cairo_surface_t *image,
 	angle_rad = angle / 180.0 * G_PI;
 	cos_angle = cos (angle_rad);
 	sin_angle = sin (angle_rad);
-	src_width  = cairo_image_surface_get_width  (image) - 1;
-	src_height = cairo_image_surface_get_height (image) - 1;
-	new_width  = ROUND (      cos_angle  * src_width + fabs(sin_angle) * src_height);
-	new_height = ROUND (fabs (sin_angle) * src_width +      cos_angle  * src_height);
+	src_width  = cairo_image_surface_get_width  (image);
+	src_height = cairo_image_surface_get_height (image);
+	new_width  = GDOUBLE_ROUND_TO_INT (      cos_angle  * src_width + fabs(sin_angle) * src_height);
+	new_height = GDOUBLE_ROUND_TO_INT (fabs (sin_angle) * src_width +      cos_angle  * src_height);
 
 	if (a0 == 0xff) {
 		/* pre-multiply the background color */
@@ -260,38 +245,76 @@ rotate (cairo_surface_t *image,
 	src_rowstride = cairo_image_surface_get_stride (image_with_background);
 	new_rowstride = cairo_image_surface_get_stride (rotated);
 
+/*
+ * bilinear interpolation
+ *            fx
+ *    v00------------v01
+ *    |        |      |
+ * fy |--------v      |
+ *    |               |
+ *    |               |
+ *    |               |
+ *    v10------------v11
+ */
+#define INTERPOLATE(v, v00, v01, v10, v11, fx, fy) \
+	tmp = (1.0 - (fy)) * \
+	      ((1.0 - (fx)) * (v00) + (fx) * (v01)) \
+              + \
+              (fy) * \
+              ((1.0 - (fx)) * (v10) + (fx) * (v11)); \
+	v = CLAMP (tmp, 0, 255);
+
+#define GET_VALUES(r, g, b, a, x, y) \
+	if (x >= 0 && x < src_width && y >= 0 && y < src_height) { \
+		p_src2 = p_src + src_rowstride * y + 4 * x; \
+		r = p_src2[CAIRO_RED]; \
+		g = p_src2[CAIRO_GREEN]; \
+		b = p_src2[CAIRO_BLUE]; \
+		a = p_src2[CAIRO_ALPHA]; \
+	} \
+	else { \
+		r = r0; \
+		g = g0; \
+		b = b0; \
+		a = a0; \
+	}
+
+	half_new_width = new_width / 2.0;
+	half_new_height = new_height / 2.0;
+	half_src_width = src_width / 2.0;
+	half_src_height = src_height / 2.0;
+
 	cairo_surface_flush (rotated);
+
+	y = - half_new_height;
 	for (yi = 0; yi < new_height; yi++) {
 		p_new2 = p_new;
-		y = yi - new_height / 2.0;
 
+		x = - half_new_width;
 		for (xi = 0; xi < new_width; xi++) {
-			x = xi - new_width / 2.0;
-
-			x2 = cos_angle * x - sin_angle * y + src_width  / 2.0;
-			y2 = sin_angle * x + cos_angle * y + src_height / 2.0;
+			x2 = cos_angle * x - sin_angle * y + half_src_width;
+			y2 = sin_angle * x + cos_angle * y + half_src_height;
 
 			if (high_quality) {
-				/* Bilinear interpolation. FIXME: use a gaussian interpolation here */
-
-				x2min = (int) floor (x2);
-				y2min = (int) floor (y2);
+				/* Bilinear interpolation. */
 
+				x2min = (int) x2;
+				y2min = (int) y2;
 				x2max = x2min + 1;
 				y2max = y2min + 1;
 
-				fx = x2 - x2min;
-				fy = y2 - y2min;
-
 				GET_VALUES (r00, g00, b00, a00, x2min, y2min);
 				GET_VALUES (r01, g01, b01, a01, x2max, y2min);
 				GET_VALUES (r10, g10, b10, a10, x2min, y2max);
 				GET_VALUES (r11, g11, b11, a11, x2max, y2max);
 
-				r = CLAMP (INTERPOLATE (r00, r01, r10, r11, fx, fy), 0, 255);
-				g = CLAMP (INTERPOLATE (g00, g01, g10, g11, fx, fy), 0, 255);
-				b = CLAMP (INTERPOLATE (b00, b01, b10, b11, fx, fy), 0, 255);
-				a = CLAMP (INTERPOLATE (a00, a01, a10, a11, fx, fy), 0, 255);
+				fx = x2 - x2min;
+				fy = y2 - y2min;
+
+				INTERPOLATE (r, r00, r01, r10, r11, fx, fy);
+				INTERPOLATE (g, g00, g01, g10, g11, fx, fy);
+				INTERPOLATE (b, b00, b01, b10, b11, fx, fy);
+				INTERPOLATE (a, a00, a01, a10, a11, fx, fy);
 
 				pixel = CAIRO_RGBA_TO_UINT32 (r, g, b, a);
 				memcpy (p_new2, &pixel, sizeof (guint32));
@@ -299,21 +322,31 @@ rotate (cairo_surface_t *image,
 			else {
 				/* Nearest neighbor */
 
-				x2min = ROUND (x2);
-				y2min = ROUND (y2);
+				x2min = GDOUBLE_ROUND_TO_INT (x2);
+				y2min = GDOUBLE_ROUND_TO_INT (y2);
 
-				GET_VALUES (p_new2[CAIRO_RED], p_new2[CAIRO_GREEN], p_new2[CAIRO_BLUE], p_new2[CAIRO_ALPHA], x2min, y2min);
+				GET_VALUES (p_new2[CAIRO_RED],
+					    p_new2[CAIRO_GREEN],
+					    p_new2[CAIRO_BLUE],
+					    p_new2[CAIRO_ALPHA],
+					    x2min,
+					    y2min);
 			}
 
 			p_new2 += 4;
+			x += 1.0;
 		}
 
 		p_new += new_rowstride;
+		y += 1.0;
 	}
-	cairo_surface_mark_dirty (rotated);
 
+	cairo_surface_mark_dirty (rotated);
 	cairo_surface_destroy (image_with_background);
 
+#undef INTERPOLATE
+#undef GET_VALUES
+
 	return rotated;
 }
 
diff --git a/extensions/file_tools/gth-file-tool-adjust-colors.c b/extensions/file_tools/gth-file-tool-adjust-colors.c
index fff831f..5e75c50 100644
--- a/extensions/file_tools/gth-file-tool-adjust-colors.c
+++ b/extensions/file_tools/gth-file-tool-adjust-colors.c
@@ -149,22 +149,24 @@ adjust_colors_exec (GthAsyncTask *task,
 				value = values[channel];
 
 				if (! pixbuf_cache_get (adjust_data->cache, channel + 1, &value)) {
-					int i;
+					int tmp;
 
 					value = gamma_correction (value, adjust_data->gamma);
 
 					if (adjust_data->brightness > 0)
-						value = interpolate_value (value, 0, adjust_data->brightness);
+						tmp = interpolate_value (value, 0, adjust_data->brightness);
 					else
-						value = interpolate_value (value, 255, - adjust_data->brightness);
+						tmp = interpolate_value (value, 255, - adjust_data->brightness);
+					value = CLAMP (tmp, 0, 255);
 
 					if (adjust_data->contrast < 0)
-						value = interpolate_value (value, 127, tan (adjust_data->contrast * G_PI_2));
+						tmp = interpolate_value (value, 127, tan (adjust_data->contrast * G_PI_2));
 					else
-						value = interpolate_value (value, 127, adjust_data->contrast);
+						tmp = interpolate_value (value, 127, adjust_data->contrast);
+					value = CLAMP (tmp, 0, 255);
 
-					i = value + adjust_data->color_level[channel] * adjust_data->midtone_distance[value];
-					value = CLAMP (i, 0, 255);
+					tmp = value + adjust_data->color_level[channel] * adjust_data->midtone_distance[value];
+					value = CLAMP (tmp, 0, 255);
 
 					pixbuf_cache_set (adjust_data->cache, channel + 1, values[channel], value);
 				}
@@ -177,6 +179,7 @@ adjust_colors_exec (GthAsyncTask *task,
 			if (adjust_data->saturation != 0.0) {
 				guchar min, max, lightness;
 				double saturation;
+				int    tmp;
 
 				max = MAX (MAX (values[0], values[1]), values[2]);
 				min = MIN (MIN (values[0], values[1]), values[2]);
@@ -187,9 +190,14 @@ adjust_colors_exec (GthAsyncTask *task,
 				else
 					saturation = adjust_data->saturation;
 
-				values[0] = interpolate_value (values[0], lightness, saturation);
-				values[1] = interpolate_value (values[1], lightness, saturation);
-				values[2] = interpolate_value (values[2], lightness, saturation);
+				tmp = interpolate_value (values[0], lightness, saturation);
+				values[0] = CLAMP (tmp, 0, 255);
+
+				tmp = interpolate_value (values[1], lightness, saturation);
+				values[1] = CLAMP (tmp, 0, 255);
+
+				tmp = interpolate_value (values[2], lightness, saturation);
+				values[2] = CLAMP (tmp, 0, 255);
 			}
 
 			CAIRO_SET_RGBA (p_destination, values[0], values[1], values[2], values[3]);
diff --git a/gthumb/cairo-utils.h b/gthumb/cairo-utils.h
index e38fba2..2da4e63 100644
--- a/gthumb/cairo-utils.h
+++ b/gthumb/cairo-utils.h
@@ -105,7 +105,7 @@
 	(((alpha) << 24) | ((red) << 16) | ((green) << 8) | (blue))
 
 #define interpolate_value(original, reference, distance) 			\
-	(CLAMP (((distance) * (reference)) + ((1.0 - (distance)) * (original)), 0, 255))
+	(((distance) * (reference)) + ((1.0 - (distance)) * (original)))
 
 
 /* types */
diff --git a/gthumb/glib-utils.h b/gthumb/glib-utils.h
index b15babc..d195363 100644
--- a/gthumb/glib-utils.h
+++ b/gthumb/glib-utils.h
@@ -29,7 +29,12 @@
 
 G_BEGIN_DECLS
 
-#define SQR(x) ((x) * (x))
+/* Math */
+
+#define GDOUBLE_ROUND_TO_INT(x)  ((int) floor ((x) + 0.5))
+#define SQR(x)                   ((x) * (x))
+
+/* GFile attributes */
 
 #define GFILE_NAME_TYPE_ATTRIBUTES "standard::name,standard::type"
 #define GFILE_DISPLAY_ATTRIBUTES "standard::display-name,standard::icon"
diff --git a/gthumb/gth-image-navigator.c b/gthumb/gth-image-navigator.c
index 47e4e26..2065971 100644
--- a/gthumb/gth-image-navigator.c
+++ b/gthumb/gth-image-navigator.c
@@ -272,7 +272,8 @@ gth_image_navigator_forall (GtkContainer *container,
 {
 	GthImageNavigator *self = GTH_IMAGE_NAVIGATOR (container);
 
-	(* callback) (GTK_WIDGET (self->priv->viewer), callback_data);
+	if (self->priv->viewer != NULL)
+		(* callback) (GTK_WIDGET (self->priv->viewer), callback_data);
 	if (include_internals) {
 		(* callback) (self->priv->hscrollbar, callback_data);
 		(* callback) (self->priv->vscrollbar, callback_data);



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