[gthumb/ext] added "reg eye removal" tool



commit 58db43a17310609a7bcd6c743a05b4ffd63198a1
Author: Paolo Bacchilega <paobac src gnome org>
Date:   Fri Sep 11 19:56:55 2009 +0200

    added "reg eye removal" tool

 configure.ac                                       |    3 +
 extensions/Makefile.am                             |    1 +
 extensions/comments/gth-comment.c                  |   19 +-
 extensions/red_eye_removal/Makefile.am             |   30 ++
 extensions/red_eye_removal/data/Makefile.am        |    2 +
 extensions/red_eye_removal/data/ui/Makefile.am     |    5 +
 .../data/ui/red-eye-removal-options.ui             |  191 ++++++++
 extensions/red_eye_removal/gth-file-tool-red-eye.c |  502 ++++++++++++++++++++
 extensions/red_eye_removal/gth-file-tool-red-eye.h |   54 +++
 extensions/red_eye_removal/main.c                  |   53 ++
 .../red_eye_removal.extension.in.in                |   11 +
 gthumb/gth-image-selector.c                        |    1 +
 gthumb/gth-image-viewer.c                          |    2 +
 gthumb/gth-sidebar.c                               |    6 +-
 14 files changed, 870 insertions(+), 10 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 3e9481c..e536d0c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -274,6 +274,9 @@ extensions/list_tools/data/ui/Makefile
 extensions/photo_importer/Makefile
 extensions/photo_importer/data/Makefile
 extensions/photo_importer/data/ui/Makefile
+extensions/red_eye_removal/Makefile
+extensions/red_eye_removal/data/Makefile
+extensions/red_eye_removal/data/ui/Makefile
 extensions/rename_series/Makefile
 extensions/rename_series/data/Makefile
 extensions/rename_series/data/ui/Makefile
diff --git a/extensions/Makefile.am b/extensions/Makefile.am
index ada6456..4383bf1 100644
--- a/extensions/Makefile.am
+++ b/extensions/Makefile.am
@@ -9,6 +9,7 @@ SUBDIRS = 		\
 	image_viewer	\
 	list_tools	\
 	photo_importer	\
+	red_eye_removal	\
 	rename_series 	\
 	search		\
 	slideshow
diff --git a/extensions/comments/gth-comment.c b/extensions/comments/gth-comment.c
index 8868f81..5fad0b5 100644
--- a/extensions/comments/gth-comment.c
+++ b/extensions/comments/gth-comment.c
@@ -165,13 +165,18 @@ gth_comment_real_load_from_element (DomDomizable *base,
 			else if (g_strcmp0 (node->tag_name, "Time") == 0) 
 				gth_comment_set_time_from_time_t (self, atol (dom_element_get_inner_text (node)));
 			else if (g_strcmp0 (node->tag_name, "Keywords") == 0) {
-				char **categories;
-				int    i;
-				
-				categories = g_strsplit (dom_element_get_inner_text (node), ",", -1);
-				for (i = 0; categories[i] != NULL; i++)
-					gth_comment_add_category (self, categories[i]);
-				g_strfreev (categories);
+				const char  *text;
+
+				text = dom_element_get_inner_text (node);
+				if (text != NULL) {
+					char **categories;
+					int    i;
+
+					categories = g_strsplit (text, ",", -1);
+					for (i = 0; categories[i] != NULL; i++)
+						gth_comment_add_category (self, categories[i]);
+					g_strfreev (categories);
+				}
 			}
 		}
 	}
diff --git a/extensions/red_eye_removal/Makefile.am b/extensions/red_eye_removal/Makefile.am
new file mode 100644
index 0000000..16bb461
--- /dev/null
+++ b/extensions/red_eye_removal/Makefile.am
@@ -0,0 +1,30 @@
+SUBDIRS = data
+
+extensiondir = $(libdir)/gthumb-2.0/extensions
+extension_LTLIBRARIES = libred_eye_removal.la
+
+libred_eye_removal_la_SOURCES = 	\
+	gth-file-tool-red-eye.c		\
+	gth-file-tool-red-eye.h		\
+	main.c
+
+libred_eye_removal_la_CFLAGS = $(GTHUMB_CFLAGS) $(DISABLE_DEPRECATED) $(WARNINGS) -I$(top_srcdir) -I$(top_builddir)/gthumb 
+libred_eye_removal_la_LDFLAGS = $(EXTENSION_LIBTOOL_FLAGS)
+libred_eye_removal_la_LIBADD = $(GTHUMB_LIBS)
+libred_eye_removal_la_DEPENDENCIES = $(top_builddir)/gthumb/gthumb$(EXEEXT)
+
+extensioninidir = $(extensiondir)
+extensionini_in_files = red_eye_removal.extension.in.in
+extensionini_DATA = $(extensionini_in_files:.extension.in.in=.extension)
+
+%.extension.in: %.extension.in.in $(extension_LTLIBRARIES)
+	sed -e "s|%LIBRARY%|`. ./$(extension_LTLIBRARIES) && echo $$dlname`|" \
+	$< > $@
+
+%.extension: %.extension.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*po) ; LC_ALL=C $(INTLTOOL_MERGE) -d -u -c $(top_builddir)/po/.intltool-merge-cache $(top_srcdir)/po $< $@
+
+EXTRA_DIST = $(extensionini_in_files) 
+
+DISTCLEANFILES = $(extensionini_DATA)
+
+-include $(top_srcdir)/git.mk
diff --git a/extensions/red_eye_removal/data/Makefile.am b/extensions/red_eye_removal/data/Makefile.am
new file mode 100644
index 0000000..4d5385d
--- /dev/null
+++ b/extensions/red_eye_removal/data/Makefile.am
@@ -0,0 +1,2 @@
+SUBDIRS = ui
+-include $(top_srcdir)/git.mk
diff --git a/extensions/red_eye_removal/data/ui/Makefile.am b/extensions/red_eye_removal/data/ui/Makefile.am
new file mode 100644
index 0000000..f34bb05
--- /dev/null
+++ b/extensions/red_eye_removal/data/ui/Makefile.am
@@ -0,0 +1,5 @@
+uidir = $(datadir)/gthumb-2.0/ui
+ui_DATA = red-eye-removal-options.ui
+EXTRA_DIST = $(ui_DATA)
+
+-include $(top_srcdir)/git.mk
diff --git a/extensions/red_eye_removal/data/ui/red-eye-removal-options.ui b/extensions/red_eye_removal/data/ui/red-eye-removal-options.ui
new file mode 100644
index 0000000..f775e6d
--- /dev/null
+++ b/extensions/red_eye_removal/data/ui/red-eye-removal-options.ui
@@ -0,0 +1,191 @@
+<?xml version="1.0"?>
+<interface>
+  <requires lib="gtk+" version="2.16"/>
+  <!-- interface-naming-policy project-wide -->
+  <object class="GtkAlignment" id="options">
+    <property name="visible">True</property>
+    <property name="top_padding">6</property>
+    <child>
+      <object class="GtkVBox" id="vbox2">
+        <property name="visible">True</property>
+        <property name="orientation">vertical</property>
+        <child>
+          <object class="GtkVBox" id="vbox1">
+            <property name="visible">True</property>
+            <property name="orientation">vertical</property>
+            <property name="spacing">12</property>
+            <child>
+              <object class="GtkFrame" id="frame4">
+                <property name="visible">True</property>
+                <property name="label_xalign">0</property>
+                <property name="shadow_type">none</property>
+                <child>
+                  <object class="GtkAlignment" id="alignment12">
+                    <property name="visible">True</property>
+                    <property name="top_padding">6</property>
+                    <property name="left_padding">12</property>
+                    <child>
+                      <object class="GtkVBox" id="vbox10">
+                        <property name="visible">True</property>
+                        <property name="orientation">vertical</property>
+                        <child>
+                          <object class="GtkTable" id="table2">
+                            <property name="visible">True</property>
+                            <property name="n_rows">2</property>
+                            <property name="n_columns">2</property>
+                            <property name="column_spacing">6</property>
+                            <property name="row_spacing">6</property>
+                            <child>
+                              <object class="GtkLabel" id="label3">
+                                <property name="visible">True</property>
+                                <property name="xalign">0</property>
+                                <property name="label" translatable="yes">_X:</property>
+                                <property name="use_underline">True</property>
+                              </object>
+                              <packing>
+                                <property name="x_options">GTK_FILL</property>
+                                <property name="y_options"></property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkLabel" id="label5">
+                                <property name="visible">True</property>
+                                <property name="xalign">0</property>
+                                <property name="label" translatable="yes">_Y:</property>
+                                <property name="use_underline">True</property>
+                              </object>
+                              <packing>
+                                <property name="top_attach">1</property>
+                                <property name="bottom_attach">2</property>
+                                <property name="x_options">GTK_FILL</property>
+                                <property name="y_options"></property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkHBox" id="hbox5">
+                                <property name="visible">True</property>
+                                <child>
+                                  <object class="GtkSpinButton" id="x_spinbutton">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="invisible_char">&#x25CF;</property>
+                                    <property name="adjustment">x_adjustment</property>
+                                    <property name="climb_rate">1</property>
+                                  </object>
+                                  <packing>
+                                    <property name="expand">False</property>
+                                    <property name="position">0</property>
+                                  </packing>
+                                </child>
+                              </object>
+                              <packing>
+                                <property name="left_attach">1</property>
+                                <property name="right_attach">2</property>
+                                <property name="x_options">GTK_FILL</property>
+                                <property name="y_options">GTK_FILL</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkHBox" id="hbox6">
+                                <property name="visible">True</property>
+                                <child>
+                                  <object class="GtkSpinButton" id="y_spinbutton">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="invisible_char">&#x25CF;</property>
+                                    <property name="adjustment">y_adjustment</property>
+                                    <property name="climb_rate">1</property>
+                                  </object>
+                                  <packing>
+                                    <property name="expand">False</property>
+                                    <property name="position">0</property>
+                                  </packing>
+                                </child>
+                              </object>
+                              <packing>
+                                <property name="left_attach">1</property>
+                                <property name="right_attach">2</property>
+                                <property name="top_attach">1</property>
+                                <property name="bottom_attach">2</property>
+                                <property name="x_options">GTK_FILL</property>
+                                <property name="y_options">GTK_FILL</property>
+                              </packing>
+                            </child>
+                          </object>
+                          <packing>
+                            <property name="position">0</property>
+                          </packing>
+                        </child>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+                <child type="label">
+                  <object class="GtkLabel" id="label15">
+                    <property name="visible">True</property>
+                    <property name="label" translatable="yes">&lt;b&gt;Selection&lt;/b&gt;</property>
+                    <property name="use_markup">True</property>
+                  </object>
+                </child>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkHSeparator" id="hseparator1">
+            <property name="visible">True</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="padding">6</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkHButtonBox" id="hbuttonbox1">
+            <property name="visible">True</property>
+            <property name="spacing">12</property>
+            <property name="layout_style">center</property>
+            <child>
+              <object class="GtkButton" id="cancel_button">
+                <property name="label">gtk-cancel</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_stock">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+            <property name="padding">6</property>
+            <property name="position">2</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+  </object>
+  <object class="GtkAdjustment" id="x_adjustment">
+    <property name="upper">10000</property>
+    <property name="step_increment">1</property>
+  </object>
+  <object class="GtkAdjustment" id="y_adjustment">
+    <property name="upper">10000</property>
+    <property name="step_increment">1</property>
+  </object>
+</interface>
diff --git a/extensions/red_eye_removal/gth-file-tool-red-eye.c b/extensions/red_eye_removal/gth-file-tool-red-eye.c
new file mode 100644
index 0000000..a9e5b5c
--- /dev/null
+++ b/extensions/red_eye_removal/gth-file-tool-red-eye.c
@@ -0,0 +1,502 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ *  GThumb
+ *
+ *  Copyright (C) 2009 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, write to the Free Software
+ *  Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ */
+
+#include <config.h>
+#include <gthumb.h>
+#include <extensions/image_viewer/gth-image-viewer-page.h>
+#include "gth-file-tool-red-eye.h"
+
+
+#define GET_WIDGET(x) (_gtk_builder_get_widget (self->priv->builder, (x)))
+#define REGION_SEARCH_SIZE 3
+
+
+static const double RED_FACTOR = 0.5133333;
+static const double GREEN_FACTOR  = 1.0;
+static const double BLUE_FACTOR =  0.1933333;
+static gpointer parent_class = NULL;
+
+
+struct _GthFileToolRedEyePrivate {
+	GdkPixbuf        *src_pixbuf;
+	GtkBuilder       *builder;
+	GthImageSelector *selector;
+	char             *is_red;
+};
+
+
+static void
+gth_file_tool_red_eye_update_sensitivity (GthFileTool *base)
+{
+	GtkWidget *window;
+	GtkWidget *viewer_page;
+
+	window = gth_file_tool_get_window (base);
+	viewer_page = gth_browser_get_viewer_page (GTH_BROWSER (window));
+	if (! GTH_IS_IMAGE_VIEWER_PAGE (viewer_page))
+		gtk_widget_set_sensitive (GTK_WIDGET (base), FALSE);
+	else
+		gtk_widget_set_sensitive (GTK_WIDGET (base), TRUE);
+}
+
+
+static void
+cancel_button_clicked_cb (GtkButton         *button,
+			  GthFileToolRedEye *self)
+{
+	gth_file_tool_hide_options (GTH_FILE_TOOL (self));
+}
+
+
+static int
+find_region (int   row,
+ 	     int   col,
+ 	     int  *rtop,
+ 	     int  *rbot,
+	     int  *rleft,
+	     int  *rright,
+	     char *isred,
+	     int   width,
+	     int   height)
+{
+	int *rows, *cols, list_length = 0;
+	int  mydir;
+	int  total = 1;
+
+	/* a relatively efficient way to find all connected points in a
+	 * region.  It considers points that have isred == 1, sets them to 2
+	 * if they are connected to the starting point.
+	 * row and col are the starting point of the region,
+	 * the next four params define a rectangle our region fits into.
+	 * isred is an array that tells us if pixels are red or not.
+	 */
+
+	*rtop = row;
+	*rbot = row;
+	*rleft = col;
+	*rright = col;
+
+	rows = g_malloc (width * height * sizeof(int));
+	cols = g_malloc (width * height * sizeof(int));
+
+	rows[0] = row;
+	cols[0] = col;
+	list_length = 1;
+
+	do {
+		list_length -= 1;
+		row = rows[list_length];
+		col = cols[list_length];
+		for (mydir = 0; mydir < 8 ; mydir++) {
+			switch (mydir) {
+			case 0:
+				/*  going left */
+				if (col - 1 < 0) break;
+				if (isred[col-1+row*width] == 1) {
+					isred[col-1+row*width] = 2;
+					if (*rleft > col-1) *rleft = col-1;
+					rows[list_length] = row;
+					cols[list_length] = col-1;
+					list_length+=1;
+					total += 1;
+				}
+				break;
+			case 1:
+				/* up and left */
+				if (col - 1 < 0 || row -1 < 0 ) break;
+				if (isred[col-1+(row-1)*width] == 1 ) {
+					isred[col-1+(row-1)*width] = 2;
+					if (*rleft > col -1) *rleft = col-1;
+					if (*rtop > row -1) *rtop = row-1;
+					rows[list_length] = row-1;
+					cols[list_length] = col-1;
+					list_length += 1;
+					total += 1;
+				}
+				break;
+			case 2:
+				/* up */
+				if (row -1 < 0 ) break;
+				if (isred[col + (row-1)*width] == 1) {
+					isred[col + (row-1)*width] = 2;
+					if (*rtop > row-1) *rtop=row-1;
+					rows[list_length] = row-1;
+					cols[list_length] = col;
+					list_length +=1;
+					total += 1;
+				}
+				break;
+			case 3:
+				/*  up and right */
+				if (col + 1 >= width || row -1 < 0 ) break;
+				if (isred[col+1+(row-1)*width] == 1) {
+					isred[col+1+(row-1)*width] = 2;
+					if (*rright < col +1) *rright = col+1;
+					if (*rtop > row -1) *rtop = row-1;
+					rows[list_length] = row-1;
+					cols[list_length] = col+1;
+					list_length += 1;
+					total +=1;
+				}
+				break;
+			case 4:
+				/* going right */
+				if (col + 1 >= width) break;
+				if (isred[col+1+row*width] == 1) {
+					isred[col+1+row*width] = 2;
+					if (*rright < col+1) *rright = col+1;
+					rows[list_length] = row;
+					cols[list_length] = col+1;
+					list_length += 1;
+					total += 1;
+				}
+				break;
+			case 5:
+				/* down and right */
+				if (col + 1 >= width || row +1 >= height ) break;
+				if (isred[col+1+(row+1)*width] ==1) {
+					isred[col+1+(row+1)*width] = 2;
+					if (*rright < col +1) *rright = col+1;
+					if (*rbot < row +1) *rbot = row+1;
+					rows[list_length] = row+1;
+					cols[list_length] = col+1;
+					list_length += 1;
+					total += 1;
+				}
+				break;
+			case 6:
+				/* down */
+				if (row +1 >=  height ) break;
+				if (isred[col + (row+1)*width] == 1) {
+					isred[col + (row+1)*width] = 2;
+					if (*rbot < row+1) *rbot=row+1;
+					rows[list_length] = row+1;
+					cols[list_length] = col;
+					list_length += 1;
+					total += 1;
+				}
+				break;
+			case 7:
+				/* down and left */
+				if (col - 1 < 0  || row +1 >= height ) break;
+				if (isred[col-1+(row+1)*width] == 1) {
+					isred[col-1+(row+1)*width] = 2;
+					if (*rleft  > col -1) *rleft = col-1;
+					if (*rbot < row +1) *rbot = row+1;
+					rows[list_length] = row+1;
+					cols[list_length] = col-1;
+					list_length += 1;
+					total += 1;
+				}
+				break;
+			default:
+				break;
+			}
+		}
+	}
+	while (list_length > 0);  /* stop when we add no more */
+
+	g_free (rows);
+	g_free (cols);
+
+	return total;
+}
+
+
+static void
+init_is_red (GthFileToolRedEye *self,
+	     GdkPixbuf         *pixbuf)
+{
+	int        width, height;
+	int        rowstride, channels;
+	guchar    *pixels;
+	int        i, j;
+	int        ad_red, ad_green, ad_blue;
+	const int  THRESHOLD = 0;
+
+	width = gdk_pixbuf_get_width (pixbuf);
+	height = gdk_pixbuf_get_height (pixbuf);
+	rowstride = gdk_pixbuf_get_rowstride (pixbuf);
+	channels = gdk_pixbuf_get_n_channels (pixbuf);
+	pixels = gdk_pixbuf_get_pixels(pixbuf);
+
+	g_free (self->priv->is_red);
+	self->priv->is_red = g_new0 (char, width * height);
+
+	for (i = 0; i < height; i++)  {
+		for (j = 0; j < width; j++) {
+			int ofs = channels * j + i * rowstride;
+
+      			ad_red = pixels[ofs] * RED_FACTOR;
+			ad_green = pixels[ofs + 1] * GREEN_FACTOR;
+			ad_blue = pixels[ofs + 2] * BLUE_FACTOR;
+
+			//  This test from the gimp redeye plugin.
+
+			if ((ad_red >= ad_green - THRESHOLD) && (ad_red >= ad_blue - THRESHOLD))
+				self->priv->is_red[j + i * width] = 1;
+     		}
+	}
+}
+
+
+/* returns TRUE if the pixbuf has been modified */
+static gboolean
+fix_redeye (GdkPixbuf *pixbuf,
+	    char      *isred,
+	    int        x,
+	    int        y)
+{
+	gboolean  region_fixed = FALSE;
+	int       width;
+	int       height;
+	int       rowstride;
+	int       channels;
+	guchar   *pixels;
+	int       search, i, j, ii, jj;
+	int       ad_red, ad_blue, ad_green;
+	int       rtop, rbot, rleft, rright; /* edges of region */
+	int       num_pix;
+
+	width = gdk_pixbuf_get_width (pixbuf);
+	height = gdk_pixbuf_get_height (pixbuf);
+	rowstride = gdk_pixbuf_get_rowstride (pixbuf);
+	channels = gdk_pixbuf_get_n_channels (pixbuf);
+	pixels = gdk_pixbuf_get_pixels (pixbuf);
+
+	/*
+   	 * if isred is 0, we don't think the point is red, 1 means red, 2 means
+   	 * part of our region already.
+   	 */
+
+	for (search = 0; ! region_fixed && (search < REGION_SEARCH_SIZE); search++)
+    		for (i = MAX (0, y - search); ! region_fixed && (i <= MIN (height - 1, y + search)); i++ )
+      			for (j = MAX (0, x - search); ! region_fixed && (j <= MIN (width - 1, x + search)); j++) {
+				if (isred[j + i * width] == 0)
+					continue;
+
+				isred[j + i * width] = 2;
+
+				num_pix = find_region (i, j, &rtop, &rbot, &rleft, &rright, isred, width, height);
+
+				/* Fix the region. */
+				for (ii = rtop; ii <= rbot; ii++)
+					for (jj = rleft; jj <= rright; jj++)
+						if (isred[jj + ii * width] == 2) { /* Fix the pixel. */
+							int ofs;
+
+							ofs = channels*jj + ii*rowstride;
+							ad_red = pixels[ofs] * RED_FACTOR;
+							ad_green = pixels[ofs + 1] * GREEN_FACTOR;
+							ad_blue = pixels[ofs + 2] * BLUE_FACTOR;
+
+							pixels[ofs] = ((float) (ad_green + ad_blue)) / (2.0 * RED_FACTOR);
+
+							isred[jj + ii * width] = 0;
+						}
+
+				region_fixed = TRUE;
+      			}
+
+	return region_fixed;
+}
+
+
+static void
+selector_selected_cb (GthImageSelector  *selector,
+		      int                x,
+		      int                y,
+		      GthFileToolRedEye *self)
+{
+	GtkWidget *window;
+	GtkWidget *viewer_page;
+	GdkPixbuf *old_pixbuf;
+	GdkPixbuf *new_pixbuf;
+
+	window = gth_file_tool_get_window (GTH_FILE_TOOL (self));
+	viewer_page = gth_browser_get_viewer_page (GTH_BROWSER (window));
+
+	old_pixbuf = gth_image_viewer_page_get_pixbuf (GTH_IMAGE_VIEWER_PAGE (viewer_page));
+	new_pixbuf = gdk_pixbuf_copy (old_pixbuf);
+	init_is_red (self, new_pixbuf);
+	if (fix_redeye (new_pixbuf, self->priv->is_red, x, y)) {
+		gth_image_viewer_page_set_pixbuf (GTH_IMAGE_VIEWER_PAGE (viewer_page), new_pixbuf);
+		gth_file_tool_hide_options (GTH_FILE_TOOL (self));
+	}
+
+	g_object_unref (new_pixbuf);
+}
+
+
+static void
+selector_motion_notify_cb (GthImageSelector  *selector,
+		           int                x,
+		           int                y,
+		           GthFileToolRedEye *self)
+{
+	gtk_spin_button_set_value (GTK_SPIN_BUTTON (GET_WIDGET ("x_spinbutton")), (double) x);
+	gtk_spin_button_set_value (GTK_SPIN_BUTTON (GET_WIDGET ("y_spinbutton")), (double) y);
+}
+
+
+static GtkWidget *
+gth_file_tool_red_eye_get_options (GthFileTool *base)
+{
+	GthFileToolRedEye *self;
+	GtkWidget       *window;
+	GtkWidget       *viewer_page;
+	GtkWidget       *viewer;
+	GtkWidget       *options;
+
+	self = (GthFileToolRedEye *) base;
+
+	window = gth_file_tool_get_window (base);
+	viewer_page = gth_browser_get_viewer_page (GTH_BROWSER (window));
+	if (! GTH_IS_IMAGE_VIEWER_PAGE (viewer_page))
+		return NULL;
+
+	self->priv->builder = _gtk_builder_new_from_file ("red-eye-removal-options.ui", "red_eye_removal");
+	options = _gtk_builder_get_widget (self->priv->builder, "options");
+	gtk_widget_show (options);
+	g_signal_connect (GET_WIDGET ("cancel_button"),
+			  "clicked",
+			  G_CALLBACK (cancel_button_clicked_cb),
+			  self);
+
+	viewer = gth_image_viewer_page_get_image_viewer (GTH_IMAGE_VIEWER_PAGE (viewer_page));
+	self->priv->selector = (GthImageSelector *) gth_image_selector_new (GTH_IMAGE_VIEWER (viewer), GTH_SELECTOR_TYPE_POINT);
+	gth_image_selector_set_mask_visible (self->priv->selector, FALSE);
+	g_signal_connect (self->priv->selector,
+			  "selected",
+			  G_CALLBACK (selector_selected_cb),
+			  self);
+	g_signal_connect (self->priv->selector,
+			  "motion_notify",
+			  G_CALLBACK (selector_motion_notify_cb),
+			  self);
+	gth_image_viewer_set_tool (GTH_IMAGE_VIEWER (viewer), (GthImageViewerTool *) self->priv->selector);
+
+	return options;
+}
+
+
+static void
+gth_file_tool_red_eye_destroy_options (GthFileTool *base)
+{
+	GthFileToolRedEye *self;
+	GtkWidget       *window;
+	GtkWidget       *viewer_page;
+	GtkWidget       *viewer;
+
+	self = (GthFileToolRedEye *) base;
+
+	window = gth_file_tool_get_window (GTH_FILE_TOOL (self));
+	viewer_page = gth_browser_get_viewer_page (GTH_BROWSER (window));
+	viewer = gth_image_viewer_page_get_image_viewer (GTH_IMAGE_VIEWER_PAGE (viewer_page));
+	gth_image_viewer_set_tool (GTH_IMAGE_VIEWER (viewer), NULL);
+
+	_g_object_unref (self->priv->builder);
+	_g_object_unref (self->priv->selector);
+	g_free (self->priv->is_red);
+
+	self->priv->builder = NULL;
+	self->priv->selector = NULL;
+	self->priv->is_red = NULL;
+}
+
+
+static void
+gth_file_tool_red_eye_activate (GthFileTool *base)
+{
+	gth_file_tool_show_options (base);
+}
+
+
+static void
+gth_file_tool_red_eye_instance_init (GthFileToolRedEye *self)
+{
+	self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GTH_TYPE_FILE_TOOL_RED_EYE, GthFileToolRedEyePrivate);
+	self->priv->is_red = NULL;
+	gth_file_tool_construct (GTH_FILE_TOOL (self), GTK_STOCK_EDIT, _("Red Eye Removal"), _("Red Eye Removal"), FALSE);
+	gtk_widget_set_tooltip_text (GTK_WIDGET (self), _("Remove the red eye effect caused by camera flashes"));
+}
+
+
+static void
+gth_file_tool_red_eye_finalize (GObject *object)
+{
+	GthFileToolRedEye *self;
+
+	g_return_if_fail (object != NULL);
+	g_return_if_fail (GTH_IS_FILE_TOOL_RED_EYE (object));
+
+	self = (GthFileToolRedEye *) object;
+
+	g_free (self->priv->is_red);
+	_g_object_unref (self->priv->selector);
+	_g_object_unref (self->priv->builder);
+
+	/* Chain up */
+	G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+
+static void
+gth_file_tool_red_eye_class_init (GthFileToolRedEyeClass *class)
+{
+	GObjectClass     *gobject_class;
+	GthFileToolClass *file_tool_class;
+
+	parent_class = g_type_class_peek_parent (class);
+	g_type_class_add_private (class, sizeof (GthFileToolRedEyePrivate));
+
+	gobject_class = (GObjectClass*) class;
+	gobject_class->finalize = gth_file_tool_red_eye_finalize;
+
+	file_tool_class = (GthFileToolClass *) class;
+	file_tool_class->update_sensitivity = gth_file_tool_red_eye_update_sensitivity;
+	file_tool_class->activate = gth_file_tool_red_eye_activate;
+	file_tool_class->get_options = gth_file_tool_red_eye_get_options;
+	file_tool_class->destroy_options = gth_file_tool_red_eye_destroy_options;
+}
+
+
+GType
+gth_file_tool_red_eye_get_type (void) {
+	static GType type_id = 0;
+	if (type_id == 0) {
+		static const GTypeInfo g_define_type_info = {
+			sizeof (GthFileToolRedEyeClass),
+			(GBaseInitFunc) NULL,
+			(GBaseFinalizeFunc) NULL,
+			(GClassInitFunc) gth_file_tool_red_eye_class_init,
+			(GClassFinalizeFunc) NULL,
+			NULL,
+			sizeof (GthFileToolRedEye),
+			0,
+			(GInstanceInitFunc) gth_file_tool_red_eye_instance_init,
+			NULL
+		};
+		type_id = g_type_register_static (GTH_TYPE_FILE_TOOL, "GthFileToolRedEye", &g_define_type_info, 0);
+	}
+	return type_id;
+}
diff --git a/extensions/red_eye_removal/gth-file-tool-red-eye.h b/extensions/red_eye_removal/gth-file-tool-red-eye.h
new file mode 100644
index 0000000..aa71615
--- /dev/null
+++ b/extensions/red_eye_removal/gth-file-tool-red-eye.h
@@ -0,0 +1,54 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ *  GThumb
+ *
+ *  Copyright (C) 2009 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, write to the Free Software
+ *  Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef GTH_FILE_TOOL_RED_EYE_H
+#define GTH_FILE_TOOL_RED_EYE_H
+
+#include <gthumb.h>
+
+G_BEGIN_DECLS
+
+#define GTH_TYPE_FILE_TOOL_RED_EYE (gth_file_tool_red_eye_get_type ())
+#define GTH_FILE_TOOL_RED_EYE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTH_TYPE_FILE_TOOL_RED_EYE, GthFileToolRedEye))
+#define GTH_FILE_TOOL_RED_EYE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTH_TYPE_FILE_TOOL_RED_EYE, GthFileToolRedEyeClass))
+#define GTH_IS_FILE_TOOL_RED_EYE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTH_TYPE_FILE_TOOL_RED_EYE))
+#define GTH_IS_FILE_TOOL_RED_EYE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTH_TYPE_FILE_TOOL_RED_EYE))
+#define GTH_FILE_TOOL_RED_EYE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTH_TYPE_FILE_TOOL_RED_EYE, GthFileToolRedEyeClass))
+
+typedef struct _GthFileToolRedEye GthFileToolRedEye;
+typedef struct _GthFileToolRedEyeClass GthFileToolRedEyeClass;
+typedef struct _GthFileToolRedEyePrivate GthFileToolRedEyePrivate;
+
+struct _GthFileToolRedEye {
+	GthFileTool parent_instance;
+	GthFileToolRedEyePrivate *priv;
+};
+
+struct _GthFileToolRedEyeClass {
+	GthFileToolClass parent_class;
+};
+
+GType  gth_file_tool_red_eye_get_type  (void);
+
+G_END_DECLS
+
+#endif /* GTH_FILE_TOOL_RED_EYE_H */
diff --git a/extensions/red_eye_removal/main.c b/extensions/red_eye_removal/main.c
new file mode 100644
index 0000000..3ff0fe5
--- /dev/null
+++ b/extensions/red_eye_removal/main.c
@@ -0,0 +1,53 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ *  GThumb
+ *
+ *  Copyright (C) 2009 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, write to the Free Software
+ *  Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ */
+
+
+#include <config.h>
+#include <gtk/gtk.h>
+#include <gthumb.h>
+#include "gth-file-tool-red-eye.h"
+
+
+G_MODULE_EXPORT void
+gthumb_extension_activate (void)
+{
+	gth_main_register_type ("file-tools", GTH_TYPE_FILE_TOOL_RED_EYE);
+}
+
+
+G_MODULE_EXPORT void
+gthumb_extension_deactivate (void)
+{
+}
+
+
+G_MODULE_EXPORT gboolean
+gthumb_extension_is_configurable (void)
+{
+	return FALSE;
+}
+
+
+G_MODULE_EXPORT void
+gthumb_extension_configure (GtkWindow *parent)
+{
+}
diff --git a/extensions/red_eye_removal/red_eye_removal.extension.in.in b/extensions/red_eye_removal/red_eye_removal.extension.in.in
new file mode 100644
index 0000000..d336e6b
--- /dev/null
+++ b/extensions/red_eye_removal/red_eye_removal.extension.in.in
@@ -0,0 +1,11 @@
+[Extension]
+_Name=Red-Eye Removal
+_Description=Tool to remove the red-eye effect from a photo.
+_Authors=gthumb development team
+Copyright=Copyright © 2009 The Free Software Foundation, Inc.
+Version=1.0
+
+[Loader]
+Type=module
+File=%LIBRARY%
+Requires=image_viewer;file_tools
diff --git a/gthumb/gth-image-selector.c b/gthumb/gth-image-selector.c
index 0fe16e0..d913fe0 100644
--- a/gthumb/gth-image-selector.c
+++ b/gthumb/gth-image-selector.c
@@ -1411,6 +1411,7 @@ gth_image_selector_new (GthImageViewer  *viewer,
 
 	selector = g_object_new (GTH_TYPE_IMAGE_SELECTOR, NULL);
 	selector->priv->viewer = viewer;
+	selector->priv->type = type;
 
 	return GTH_IMAGE_VIEWER_TOOL (selector);
 }
diff --git a/gthumb/gth-image-viewer.c b/gthumb/gth-image-viewer.c
index 1a4f97e..c96f81a 100644
--- a/gthumb/gth-image-viewer.c
+++ b/gthumb/gth-image-viewer.c
@@ -2029,6 +2029,8 @@ gth_image_viewer_set_pixbuf (GthImageViewer *viewer,
 	viewer->priv->is_void = (pixbuf == NULL);
 
 	gth_image_loader_set_pixbuf (viewer->priv->loader, pixbuf);
+	gth_image_viewer_tool_image_changed (viewer->priv->tool);
+
 	gth_image_viewer_update_view (viewer);
 }
 
diff --git a/gthumb/gth-sidebar.c b/gthumb/gth-sidebar.c
index 99746ff..3aa966f 100644
--- a/gthumb/gth-sidebar.c
+++ b/gthumb/gth-sidebar.c
@@ -146,7 +146,7 @@ gth_sidebar_set_file (GthSidebar  *sidebar,
 	GList *children;
 	GList *scan;
 
-	gth_toolbox_deactivate_tool (GTH_TOOLBOX (sidebar->priv->toolbox));
+	/*gth_toolbox_deactivate_tool (GTH_TOOLBOX (sidebar->priv->toolbox)); FIXME */
 
 	children = gth_multipage_get_children (GTH_MULTIPAGE (sidebar->priv->properties));
 	for (scan = children; scan; scan = scan->next) {
@@ -165,8 +165,8 @@ gth_sidebar_set_file (GthSidebar  *sidebar,
 void
 gth_sidebar_show_properties (GthSidebar *sidebar)
 {
-	if (gtk_notebook_get_current_page (GTK_NOTEBOOK (sidebar)) == GTH_SIDEBAR_PAGE_TOOLS)
-		gth_toolbox_deactivate_tool (GTH_TOOLBOX (sidebar->priv->toolbox));
+	/*if (gtk_notebook_get_current_page (GTK_NOTEBOOK (sidebar)) == GTH_SIDEBAR_PAGE_TOOLS)
+		gth_toolbox_deactivate_tool (GTH_TOOLBOX (sidebar->priv->toolbox)); FIXME */
 	gtk_notebook_set_current_page (GTK_NOTEBOOK (sidebar), GTH_SIDEBAR_PAGE_PROPERTIES);
 }
 



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