[gthumb: 47/129] sharpen tool: operate on a cairo_surface directly instead of converting to/from a GdkPixbuf



commit fb42cc0e47d225f75d1aa495663cf463334ed65a
Author: Paolo Bacchilega <paobac src gnome org>
Date:   Tue Apr 19 15:44:45 2011 +0200

    sharpen tool: operate on a cairo_surface directly instead of converting to/from a GdkPixbuf

 extensions/file_tools/Makefile.am                  |    4 +-
 extensions/file_tools/cairo-blur.c                 |  271 +++++++++++++++++++
 .../file_tools/{gdk-pixbuf-blur.h => cairo-blur.h} |   15 +-
 extensions/file_tools/gdk-pixbuf-blur.c            |  273 --------------------
 .../file_tools/gth-file-tool-adjust-colors.c       |    9 -
 extensions/file_tools/gth-file-tool-sharpen.c      |  204 +++++++++------
 gthumb/cairo-utils.c                               |   36 +++-
 gthumb/cairo-utils.h                               |    5 +
 8 files changed, 442 insertions(+), 375 deletions(-)
---
diff --git a/extensions/file_tools/Makefile.am b/extensions/file_tools/Makefile.am
index 6625eb8..1c01abb 100644
--- a/extensions/file_tools/Makefile.am
+++ b/extensions/file_tools/Makefile.am
@@ -8,7 +8,7 @@ ENUM_TYPES =		\
 	enum-types.c
 
 HEADER_FILES = 				\
-	gdk-pixbuf-blur.h		\
+	cairo-blur.h			\
 	gth-file-tool-adjust-colors.h	\
 	gth-file-tool-crop.h		\
 	gth-file-tool-desaturate.h	\
@@ -56,7 +56,7 @@ libfile_tools_la_SOURCES = 		\
 	$(HEADER_FILES)			\
 	callbacks.c			\
 	callbacks.h			\
-	gdk-pixbuf-blur.c		\
+	cairo-blur.c			\
 	gth-file-tool-adjust-colors.c	\
 	gth-file-tool-crop.c		\
 	gth-file-tool-desaturate.c	\
diff --git a/extensions/file_tools/cairo-blur.c b/extensions/file_tools/cairo-blur.c
new file mode 100644
index 0000000..287a2fd
--- /dev/null
+++ b/extensions/file_tools/cairo-blur.c
@@ -0,0 +1,271 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ *  GThumb
+ *
+ *  Copyright (C) 2011 The Free Software Foundation, Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <math.h>
+#include <string.h>
+#include <gthumb.h>
+#include "cairo-blur.h"
+
+
+
+static void
+_cairo_image_surface_gaussian_blur (cairo_surface_t *source,
+				    int              radius)
+{
+	/* FIXME: to do */
+}
+
+
+static void
+box_blur (cairo_surface_t *source,
+	  cairo_surface_t *destination,
+	  int              radius,
+	  guchar          *div_kernel_size)
+{
+	int     width, height, src_rowstride, dest_rowstride;
+	guchar *p_src, *p_dest, *c1, *c2;
+	int     x, y, i, i1, i2, width_minus_1, height_minus_1, radius_plus_1;
+	int     r, g, b, a;
+	guchar *p_dest_row, *p_dest_col;
+
+	width = cairo_image_surface_get_width (source);
+	height = cairo_image_surface_get_height (source);
+	radius_plus_1 = radius + 1;
+
+	/* horizontal blur */
+
+	p_src = cairo_image_surface_get_data (source);
+	p_dest = cairo_image_surface_get_data (destination);
+	src_rowstride = cairo_image_surface_get_stride (source);
+	dest_rowstride = cairo_image_surface_get_stride (destination);
+	width_minus_1 = width - 1;
+	for (y = 0; y < height; y++) {
+
+		/* calc the initial sums of the kernel */
+
+		r = g = b = a = 0;
+
+		for (i = -radius; i <= radius; i++) {
+			c1 = p_src + (CLAMP (i, 0, width_minus_1) * 4);
+			r += c1[CAIRO_RED];
+			g += c1[CAIRO_GREEN];
+			b += c1[CAIRO_BLUE];
+			/*if (n_channels == 4)
+				a += c1[CAIRO_ALPHA];*/
+		}
+
+		p_dest_row = p_dest;
+		for (x = 0; x < width; x++) {
+			/* set as the mean of the kernel */
+
+			p_dest_row[CAIRO_RED] = div_kernel_size[r];
+			p_dest_row[CAIRO_GREEN] = div_kernel_size[g];
+			p_dest_row[CAIRO_BLUE] = div_kernel_size[b];
+			p_dest_row[CAIRO_ALPHA] = 0xff;
+			/*if (n_channels == 4)
+				p_dest_row[CAIRO_ALPHA] = div_kernel_size[a];*/
+			p_dest_row += 4;
+
+			/* the pixel to add to the kernel */
+
+			i1 = x + radius_plus_1;
+			if (i1 > width_minus_1)
+				i1 = width_minus_1;
+			c1 = p_src + (i1 * 4);
+
+			/* the pixel to remove from the kernel */
+
+			i2 = x - radius;
+			if (i2 < 0)
+				i2 = 0;
+			c2 = p_src + (i2 * 4);
+
+			/* calc the new sums of the kernel */
+
+			r += c1[CAIRO_RED] - c2[CAIRO_RED];
+			g += c1[CAIRO_GREEN] - c2[CAIRO_GREEN];
+			b += c1[CAIRO_BLUE] - c2[CAIRO_BLUE];
+			/*if (n_channels == 4)
+				a += c1[CAIRO_ALPHA] - c2[CAIRO_ALPHA];*/
+		}
+
+		p_src += src_rowstride;
+		p_dest += dest_rowstride;
+	}
+
+	/* vertical blur */
+
+	p_src = cairo_image_surface_get_data (destination);
+	p_dest = cairo_image_surface_get_data (source);
+	src_rowstride = cairo_image_surface_get_stride (destination);
+	dest_rowstride = cairo_image_surface_get_stride (source);
+	height_minus_1 = height - 1;
+	for (x = 0; x < width; x++) {
+
+		/* calc the initial sums of the kernel */
+
+		r = g = b = a = 0;
+
+		for (i = -radius; i <= radius; i++) {
+			c1 = p_src + (CLAMP (i, 0, height_minus_1) * src_rowstride);
+			r += c1[CAIRO_RED];
+			g += c1[CAIRO_GREEN];
+			b += c1[CAIRO_BLUE];
+			/*if (n_channels == 4)
+				a += c1[CAIRO_ALPHA];*/
+		}
+
+		p_dest_col = p_dest;
+		for (y = 0; y < height; y++) {
+			/* set as the mean of the kernel */
+
+			p_dest_col[CAIRO_RED] = div_kernel_size[r];
+			p_dest_col[CAIRO_GREEN] = div_kernel_size[g];
+			p_dest_col[CAIRO_BLUE] = div_kernel_size[b];
+			p_dest_col[CAIRO_ALPHA] = 0xff;
+			/*if (n_channels == 4)
+				p_dest_row[CAIRO_ALPHA] = div_kernel_size[a];*/
+			p_dest_col += dest_rowstride;
+
+			/* the pixel to add to the kernel */
+
+			i1 = y + radius_plus_1;
+			if (i1 > height_minus_1)
+				i1 = height_minus_1;
+			c1 = p_src + (i1 * src_rowstride);
+
+			/* the pixel to remove from the kernel */
+
+			i2 = y - radius;
+			if (i2 < 0)
+				i2 = 0;
+			c2 = p_src + (i2 * src_rowstride);
+
+			/* calc the new sums of the kernel */
+
+			r += c1[CAIRO_RED] - c2[CAIRO_RED];
+			g += c1[CAIRO_GREEN] - c2[CAIRO_GREEN];
+			b += c1[CAIRO_BLUE] - c2[CAIRO_BLUE];
+			/*if (n_channels == 4)
+				a += c1[CAIRO_ALPHA] - c2[CAIRO_ALPHA];*/
+		}
+
+		p_src += 4;
+		p_dest += 4;
+	}
+}
+
+
+static void
+_cairo_image_surface_box_blur (cairo_surface_t *source,
+			       int              radius,
+			       int              iterations)
+{
+	gint64           kernel_size;
+	guchar          *div_kernel_size;
+	int              i;
+	cairo_surface_t *tmp;
+
+	kernel_size = 2 * radius + 1;
+	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);
+
+	tmp = _cairo_image_surface_create_compatible (source);
+	while (iterations-- > 0)
+		box_blur (source, tmp, radius, div_kernel_size);
+
+	cairo_surface_destroy (tmp);
+}
+
+
+void
+_cairo_image_surface_blur (cairo_surface_t *source,
+			   int              radius)
+{
+	if (radius <= 10)
+		_cairo_image_surface_box_blur (source, radius, 3);
+	else
+		_cairo_image_surface_gaussian_blur (source, radius);
+}
+
+
+void
+_cairo_image_surface_sharpen (cairo_surface_t *source,
+			      int              radius,
+			      double           amount,
+			      guchar           threshold)
+{
+	cairo_surface_t *blurred;
+	int              width, height;
+	int              source_rowstride, blurred_rowstride;
+	int              x, y;
+	guchar          *p_src, *p_blurred;
+	guchar          *p_src_row, *p_blurred_row;
+	guchar           r1, g1, b1;
+	guchar           r2, g2, b2;
+
+	blurred = _cairo_image_surface_copy (source);
+	_cairo_image_surface_blur (blurred, radius);
+
+	width = cairo_image_surface_get_width (source);
+	height = cairo_image_surface_get_height (source);
+	source_rowstride = cairo_image_surface_get_stride (source);
+	blurred_rowstride = cairo_image_surface_get_stride (blurred);
+
+	p_src = cairo_image_surface_get_data (source);
+	p_blurred = cairo_image_surface_get_data (blurred);
+
+	for (y = 0; y < height; y++) {
+		p_src_row = p_src;
+		p_blurred_row = p_blurred;
+
+		for (x = 0; x < width; x++) {
+			r1 = p_src_row[CAIRO_RED];
+			g1 = p_src_row[CAIRO_GREEN];
+			b1 = p_src_row[CAIRO_BLUE];
+
+			r2 = p_blurred_row[CAIRO_RED];
+			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);
+
+			p_src_row[CAIRO_RED] = r1;
+			p_src_row[CAIRO_GREEN] = g1;
+			p_src_row[CAIRO_BLUE] = b1;
+
+			p_src_row += 4;
+			p_blurred_row += 4;
+		}
+
+		p_src += source_rowstride;
+		p_blurred += blurred_rowstride;
+	}
+
+	cairo_surface_destroy (blurred);
+}
diff --git a/extensions/file_tools/gdk-pixbuf-blur.h b/extensions/file_tools/cairo-blur.h
similarity index 76%
rename from extensions/file_tools/gdk-pixbuf-blur.h
rename to extensions/file_tools/cairo-blur.h
index 58311b9..bcc61d1 100644
--- a/extensions/file_tools/gdk-pixbuf-blur.h
+++ b/extensions/file_tools/cairo-blur.h
@@ -23,17 +23,16 @@
 #define GDK_PIXBUF_BLUR_H
 
 #include <glib.h>
-#include <gdk/gdk.h>
-#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <cairo.h>
 
 G_BEGIN_DECLS
 
-void _gdk_pixbuf_blur    (GdkPixbuf *src,
-	 	          int        radius);
-void _gdk_pixbuf_sharpen (GdkPixbuf *src,
-			  int        radius,
-			  double     amount,
-			  guchar     threshold);
+void _cairo_image_surface_blur     (cairo_surface_t *source,
+	 	                    int              radius);
+void _cairo_image_surface_sharpen  (cairo_surface_t *source,
+				    int              radius,
+				    double           amount,
+				    guchar           threshold);
 
 G_END_DECLS
 
diff --git a/extensions/file_tools/gth-file-tool-adjust-colors.c b/extensions/file_tools/gth-file-tool-adjust-colors.c
index 2eca2da..8fbf371 100644
--- a/extensions/file_tools/gth-file-tool-adjust-colors.c
+++ b/extensions/file_tools/gth-file-tool-adjust-colors.c
@@ -80,15 +80,6 @@ adjust_colors_before (GthAsyncTask *task,
 
 
 static guchar
-interpolate_value (guchar original,
-		   guchar reference,
-		   double distance)
-{
-	return CLAMP ((distance * reference) + ((1.0 - distance) * original), 0, 255);
-}
-
-
-static guchar
 gamma_correction (guchar original,
 		  double gamma)
 {
diff --git a/extensions/file_tools/gth-file-tool-sharpen.c b/extensions/file_tools/gth-file-tool-sharpen.c
index 012ff5b..b1971f5 100644
--- a/extensions/file_tools/gth-file-tool-sharpen.c
+++ b/extensions/file_tools/gth-file-tool-sharpen.c
@@ -23,7 +23,7 @@
 #include <gthumb.h>
 #include <extensions/image_viewer/gth-image-viewer-page.h>
 #include "gth-file-tool-sharpen.h"
-#include "gdk-pixbuf-blur.h"
+#include "cairo-blur.h"
 
 
 #define GET_WIDGET(x) (_gtk_builder_get_widget (self->priv->builder, (x)))
@@ -37,16 +37,16 @@ static gpointer parent_class = NULL;
 
 
 struct _GthFileToolSharpenPrivate {
-	GdkPixbuf     *src_pixbuf;
-	GdkPixbuf     *dest_pixbuf;
-	GtkBuilder    *builder;
-	GtkAdjustment *radius_adj;
-	GtkAdjustment *amount_adj;
-	GtkAdjustment *threshold_adj;
-	GtkWidget     *preview;
-	GthTask       *pixbuf_task;
-	guint          apply_event;
-	gboolean       show_preview;
+	cairo_surface_t *source;
+	cairo_surface_t *destination;
+	GtkBuilder      *builder;
+	GtkAdjustment   *radius_adj;
+	GtkAdjustment   *amount_adj;
+	GtkAdjustment   *threshold_adj;
+	GtkWidget       *preview;
+	GthTask         *pixbuf_task;
+	guint            apply_event;
+	gboolean         show_preview;
 };
 
 
@@ -65,28 +65,14 @@ gth_file_tool_sharpen_update_sensitivity (GthFileTool *base)
 }
 
 
-static void
-task_completed_cb (GthTask  *task,
-		   GError   *error,
-		   gpointer  user_data)
-{
-	GthFileTool *base = user_data;
-
-	if (error == NULL) {
-		GthPixbufTask *pixbuf_task;
-		GtkWidget     *viewer_page;
-
-		pixbuf_task = GTH_PIXBUF_TASK (task);
-		viewer_page = gth_browser_get_viewer_page (GTH_BROWSER (gth_file_tool_get_window (base)));
-		gth_image_viewer_page_set_pixbuf (GTH_IMAGE_VIEWER_PAGE (viewer_page), pixbuf_task->dest, TRUE);
-	}
-}
-
-
 typedef struct {
-	int    radius;
-	double amount;
-	int    threshold;
+	GthFileToolSharpen *self;
+	cairo_surface_t    *source;
+	cairo_surface_t    *destination;
+	GtkWidget          *viewer_page;
+	int                 radius;
+	double              amount;
+	int                 threshold;
 } SharpenData;
 
 
@@ -95,7 +81,10 @@ sharpen_data_new (GthFileToolSharpen *self)
 {
 	SharpenData *sharpen_data;
 
-	sharpen_data = g_new (SharpenData, 1);
+	sharpen_data = g_new0 (SharpenData, 1);
+	sharpen_data->source = NULL;
+	sharpen_data->destination = NULL;
+	sharpen_data->viewer_page = NULL;
 	sharpen_data->radius = gtk_adjustment_get_value (self->priv->radius_adj);
 	sharpen_data->amount = - gtk_adjustment_get_value (self->priv->amount_adj) / 100.0;
 	sharpen_data->threshold = gtk_adjustment_get_value (self->priv->threshold_adj);
@@ -105,15 +94,53 @@ sharpen_data_new (GthFileToolSharpen *self)
 
 
 static void
-sharpen_step (GthPixbufTask *pixbuf_task)
+sharpen_before (GthAsyncTask *task,
+	        gpointer      user_data)
+{
+	gth_task_progress (GTH_TASK (task), _("Sharpening image"), NULL, TRUE, 0.0);
+}
+
+
+static gpointer
+sharpen_exec (GthAsyncTask *task,
+	      gpointer      user_data)
 {
-	SharpenData *sharpen_data = pixbuf_task->data;
+	SharpenData *sharpen_data = user_data;
+
+	sharpen_data->destination = _cairo_image_surface_copy (sharpen_data->source);
+
+	/* FIXME: set progress info and allow cancellation */
+
+	_cairo_image_surface_sharpen (sharpen_data->destination,
+				      sharpen_data->radius,
+				      sharpen_data->amount,
+				      sharpen_data->threshold);
 
-	pixbuf_task->dest = gdk_pixbuf_copy (pixbuf_task->src);
-	_gdk_pixbuf_sharpen (pixbuf_task->dest,
-			     sharpen_data->radius,
-			     sharpen_data->amount,
-			     sharpen_data->threshold);
+	return NULL;
+}
+
+
+static void
+sharpen_after (GthAsyncTask *task,
+	       GError       *error,
+	       gpointer      user_data)
+{
+	SharpenData *sharpen_data = user_data;
+
+	if (error == NULL)
+		gth_image_viewer_page_set_image (GTH_IMAGE_VIEWER_PAGE (sharpen_data->viewer_page), sharpen_data->destination, TRUE);
+}
+
+
+static void
+sharpen_data_free (gpointer user_data)
+{
+	SharpenData *sharpen_data = user_data;
+
+	_g_object_unref (sharpen_data->viewer_page);
+	cairo_surface_destroy (sharpen_data->destination);
+	cairo_surface_destroy (sharpen_data->source);
+	g_free (sharpen_data);
 }
 
 
@@ -121,19 +148,29 @@ static void
 ok_button_clicked_cb (GtkButton          *button,
 		      GthFileToolSharpen *self)
 {
+	GtkWidget   *window;
+	GtkWidget   *viewer_page;
 	SharpenData *sharpen_data;
 	GthTask     *task;
 
+	if (self->priv->apply_event != 0) {
+		g_source_remove (self->priv->apply_event);
+		self->priv->apply_event = 0;
+	}
+
+	window = gth_file_tool_get_window (GTH_FILE_TOOL (self));
+	viewer_page = gth_browser_get_viewer_page (GTH_BROWSER (window));
+	if (! GTH_IS_IMAGE_VIEWER_PAGE (viewer_page))
+		return;
+
 	sharpen_data = sharpen_data_new (self);
-	task = gth_pixbuf_task_new (_("Sharpening image"),
-				    TRUE,
-				    NULL,
-				    sharpen_step,
-				    NULL,
-				    sharpen_data,
-				    g_free);
-	gth_pixbuf_task_set_source (GTH_PIXBUF_TASK (task), self->priv->src_pixbuf);
-	g_signal_connect (task, "completed", G_CALLBACK (task_completed_cb), self);
+	sharpen_data->viewer_page = g_object_ref (viewer_page);
+	sharpen_data->source = cairo_surface_reference (self->priv->source);
+	task = gth_async_task_new (sharpen_before,
+				   sharpen_exec,
+				   sharpen_after,
+				   sharpen_data,
+				   sharpen_data_free);
 	gth_browser_exec_task (GTH_BROWSER (gth_file_tool_get_window (GTH_FILE_TOOL (self))), task, FALSE);
 
 	g_object_unref (task);
@@ -185,9 +222,10 @@ apply_cb (gpointer user_data)
 
 	preview = GTH_IMAGE_VIEWER (self->priv->preview);
 	if (self->priv->show_preview) {
-		SharpenData *sharpen_data;
-		GdkPixbuf   *preview_subpixbuf;
-		int          x, y, w ,h;
+		SharpenData     *sharpen_data;
+		int              x, y, w ,h;
+		cairo_surface_t *preview_surface;
+		cairo_t         *cr;
 
 		sharpen_data = sharpen_data_new (self);
 		x = gtk_adjustment_get_value (preview->hadj);
@@ -195,20 +233,30 @@ apply_cb (gpointer user_data)
 		w = gtk_adjustment_get_page_size (preview->hadj);
 		h = gtk_adjustment_get_page_size (preview->vadj);
 
-		_g_object_unref (self->priv->dest_pixbuf);
-		self->priv->dest_pixbuf = gdk_pixbuf_copy (self->priv->src_pixbuf);
-		preview_subpixbuf = gdk_pixbuf_new_subpixbuf (self->priv->dest_pixbuf, x, y, w, h);
-		_gdk_pixbuf_sharpen (preview_subpixbuf,
-				     sharpen_data->radius,
-				     sharpen_data->amount,
-				     sharpen_data->threshold);
-		gth_image_viewer_set_pixbuf (preview, self->priv->dest_pixbuf, -1, -1);
-
-		g_object_unref (preview_subpixbuf);
-		g_free (sharpen_data);
+		cairo_surface_destroy (self->priv->destination);
+		self->priv->destination = _cairo_image_surface_copy (self->priv->source);
+
+		/* FIXME: use a cairo sub-surface when cairo 1.10 will be requiered */
+
+		preview_surface = _cairo_image_surface_copy_subsurface (self->priv->destination, x, y, w, h);
+		_cairo_image_surface_sharpen (preview_surface,
+					      sharpen_data->radius,
+					      sharpen_data->amount,
+					      sharpen_data->threshold);
+
+		cr = cairo_create (self->priv->destination);
+		cairo_set_source_surface (cr, preview_surface, x, y);
+		cairo_rectangle (cr, x, y, w, h);
+		cairo_fill (cr);
+		cairo_destroy (cr);
+
+		gth_image_viewer_set_image (preview, self->priv->destination, -1, -1);
+
+		cairo_surface_destroy (preview_surface);
+		sharpen_data_free (sharpen_data);
 	}
 	else
-		gth_image_viewer_set_pixbuf (preview, self->priv->src_pixbuf, -1, -1);
+		gth_image_viewer_set_image (preview, self->priv->source, -1, -1);
 
 	return FALSE;
 }
@@ -256,15 +304,15 @@ gth_file_tool_sharpen_get_options (GthFileTool *base)
 	if (! GTH_IS_IMAGE_VIEWER_PAGE (viewer_page))
 		return NULL;
 
-	_g_object_unref (self->priv->src_pixbuf);
-	_g_object_unref (self->priv->dest_pixbuf);
+	cairo_surface_destroy (self->priv->source);
+	cairo_surface_destroy (self->priv->destination);
 
 	viewer = gth_image_viewer_page_get_image_viewer (GTH_IMAGE_VIEWER_PAGE (viewer_page));
-	self->priv->src_pixbuf = gth_image_viewer_get_current_pixbuf (GTH_IMAGE_VIEWER (viewer));
-	if (self->priv->src_pixbuf == NULL)
+	self->priv->source = cairo_surface_reference (gth_image_viewer_get_current_image (GTH_IMAGE_VIEWER (viewer)));
+	if (self->priv->source == NULL)
 		return NULL;
 
-	self->priv->dest_pixbuf = NULL;
+	self->priv->destination = NULL;
 
 	self->priv->builder = _gtk_builder_new_from_file ("sharpen-options.ui", "file_tools");
 	options = _gtk_builder_get_widget (self->priv->builder, "options");
@@ -276,7 +324,7 @@ gth_file_tool_sharpen_get_options (GthFileTool *base)
 	gth_image_viewer_set_zoom_change (GTH_IMAGE_VIEWER (self->priv->preview), GTH_ZOOM_CHANGE_KEEP_PREV);
 	gth_image_viewer_set_zoom (GTH_IMAGE_VIEWER (self->priv->preview), 1.0);
 	gth_image_viewer_enable_zoom_with_keys (GTH_IMAGE_VIEWER (self->priv->preview), FALSE);
-	gth_image_viewer_set_pixbuf (GTH_IMAGE_VIEWER (self->priv->preview), self->priv->src_pixbuf, -1, -1);
+	gth_image_viewer_set_image (GTH_IMAGE_VIEWER (self->priv->preview), self->priv->source, -1, -1);
 	image_navigator = gth_image_navigator_new (GTH_IMAGE_VIEWER (self->priv->preview));
 	gtk_widget_show_all (image_navigator);
 	gtk_box_pack_start (GTK_BOX (GET_WIDGET ("preview_hbox")), image_navigator, TRUE, TRUE, 0);
@@ -344,11 +392,11 @@ gth_file_tool_sharpen_destroy_options (GthFileTool *base)
 		self->priv->apply_event = 0;
 	}
 
-	_g_object_unref (self->priv->src_pixbuf);
-	_g_object_unref (self->priv->dest_pixbuf);
+	cairo_surface_destroy (self->priv->source);
+	cairo_surface_destroy (self->priv->destination);
 	_g_object_unref (self->priv->builder);
-	self->priv->src_pixbuf = NULL;
-	self->priv->dest_pixbuf = NULL;
+	self->priv->source = NULL;
+	self->priv->destination = NULL;
 	self->priv->builder = NULL;
 }
 
@@ -364,8 +412,8 @@ static void
 gth_file_tool_sharpen_instance_init (GthFileToolSharpen *self)
 {
 	self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GTH_TYPE_FILE_TOOL_SHARPEN, GthFileToolSharpenPrivate);
-	self->priv->src_pixbuf = NULL;
-	self->priv->dest_pixbuf = NULL;
+	self->priv->source = NULL;
+	self->priv->destination = NULL;
 	self->priv->builder = NULL;
 	self->priv->show_preview = TRUE;
 
@@ -383,8 +431,8 @@ gth_file_tool_sharpen_finalize (GObject *object)
 
 	self = (GthFileToolSharpen *) object;
 
-	_g_object_unref (self->priv->src_pixbuf);
-	_g_object_unref (self->priv->dest_pixbuf);
+	cairo_surface_destroy (self->priv->source);
+	cairo_surface_destroy (self->priv->destination);
 	_g_object_unref (self->priv->builder);
 
 	/* Chain up */
diff --git a/gthumb/cairo-utils.c b/gthumb/cairo-utils.c
index 575f9ae..c8f0766 100644
--- a/gthumb/cairo-utils.c
+++ b/gthumb/cairo-utils.c
@@ -99,7 +99,7 @@ _cairo_image_surface_get_has_alpha (cairo_surface_t *surface)
 
 
 cairo_surface_t *
-_cairo_image_surface_copy (cairo_surface_t *surface)
+_cairo_image_surface_copy (cairo_surface_t *source)
 {
 	cairo_surface_t *result;
 	cairo_format_t   format;
@@ -108,13 +108,18 @@ _cairo_image_surface_copy (cairo_surface_t *surface)
 	int              stride;
 	unsigned char   *pixels;
 	cairo_status_t   status;
+	int              source_stride;
+	int              destination_stride;
+	unsigned char   *p_source;
+	unsigned char   *p_destination;
+	int              row_size;
 
-	if (surface == NULL)
+	if (source == NULL)
 		return NULL;
 
-	format = cairo_image_surface_get_format (surface);
-	width = cairo_image_surface_get_width (surface);
-	height = cairo_image_surface_get_height (surface);
+	format = cairo_image_surface_get_format (source);
+	width = cairo_image_surface_get_width (source);
+	height = cairo_image_surface_get_height (source);
 	stride = cairo_format_stride_for_width (format, width);
 	pixels = g_try_malloc (stride * height);
         if (pixels == NULL)
@@ -135,6 +140,18 @@ _cairo_image_surface_copy (cairo_surface_t *surface)
 		return NULL;
 	}
 
+	source_stride = cairo_image_surface_get_stride (source);
+	destination_stride = cairo_image_surface_get_stride (result);
+	p_source = cairo_image_surface_get_data (source);
+	p_destination = cairo_image_surface_get_data (result);
+	row_size = width * 4;
+	while (height-- > 0) {
+		memcpy (p_destination, p_source, row_size);
+
+		p_source += source_stride;
+		p_destination += destination_stride;
+	}
+
 	return result;
 }
 
@@ -258,6 +275,15 @@ _cairo_image_surface_create_from_pixbuf (GdkPixbuf *pixbuf)
 
 
 cairo_surface_t *
+_cairo_image_surface_create_compatible (cairo_surface_t *surface)
+{
+	return cairo_image_surface_create (cairo_image_surface_get_format (surface),
+					   cairo_image_surface_get_width (surface),
+					   cairo_image_surface_get_height (surface));
+}
+
+
+cairo_surface_t *
 _cairo_image_surface_scale_to (cairo_surface_t *surface,
 			       int              width,
 			       int              height,
diff --git a/gthumb/cairo-utils.h b/gthumb/cairo-utils.h
index b97b813..8f01308 100644
--- a/gthumb/cairo-utils.h
+++ b/gthumb/cairo-utils.h
@@ -99,6 +99,10 @@
 		}								\
 	} G_STMT_END
 
+
+#define interpolate_value(original, reference, distance) (CLAMP (((distance) * (reference)) + ((1.0 - (distance)) * (original)), 0, 255))
+
+
 /* types */
 
 typedef struct {
@@ -138,6 +142,7 @@ cairo_surface_t *  _cairo_image_surface_copy_subsurface     (cairo_surface_t   *
 				      	      	      	     int                width,
 				      	      	      	     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,



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