[gthumb] optimized the interpolation function
- From: Paolo Bacchilega <paobac src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gthumb] optimized the interpolation function
- Date: Sat, 7 Jul 2012 12:59:05 +0000 (UTC)
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]