[solang] Fixed the flip and rotate operations



commit a684e74263669ad16699b61b1b9afc841b19e462
Author: Debarshi Ray <rishi gnu org>
Date:   Sat Feb 20 17:30:12 2010 +0200

    Fixed the flip and rotate operations
    
    Flipping or rotating a photo changes the extent of the GeglBuffer
    associated with the photo, and depending on the kind of filter that was
    used the extent is stretched by a few pixels. To fix this, the photo
    should be translated and cropped after being flipper or rotated. The
    gegl:translate and gegl:crop are almost as quick as gegl:nop, and
    should not be a significant overhead.
    
    IOperation::get_node now takes a BufferPtr to figure out the
    parameters for the gegl:translate and gegl:crop operations.

 src/common/Makefile.am          |    4 ++-
 src/common/i-operation.h        |    3 +-
 src/common/operation.cpp        |    2 +-
 src/common/utils.cpp            |   50 ++++++++++++++++++++++++++++++++++++
 src/common/utils.h              |   41 +++++++++++++++++++++++++++++
 src/editor/flip-operation.cpp   |   54 ++++++++++++++++++++++++++++++++++++---
 src/editor/flip-operation.h     |    3 +-
 src/editor/rotate-operation.cpp |   54 ++++++++++++++++++++++++++++++++++++---
 src/editor/rotate-operation.h   |    3 +-
 9 files changed, 201 insertions(+), 13 deletions(-)
---
diff --git a/src/common/Makefile.am b/src/common/Makefile.am
index 8656280..64763be 100644
--- a/src/common/Makefile.am
+++ b/src/common/Makefile.am
@@ -85,7 +85,9 @@ libcommon_la_SOURCES = \
 	thumbnailer.h \
 	thumbnailer-proxy.cpp \
 	thumbnailer-proxy.h \
-	types.h
+	types.h \
+	utils.cpp \
+	utils.h
 
 AM_CPPFLAGS = \
 	-DPACKAGE_LOCALE_DIR=\""${datadir}/locale"\" \
diff --git a/src/common/i-operation.h b/src/common/i-operation.h
index eec9227..b2f9605 100644
--- a/src/common/i-operation.h
+++ b/src/common/i-operation.h
@@ -62,7 +62,8 @@ class IOperation :
         IOperation() throw();
 
         virtual NodePtr
-        get_node(const NodePtr & root) const throw() = 0;
+        get_node(const BufferPtr & buffer, const NodePtr & root) const
+                 throw() = 0;
 
     private:
 };
diff --git a/src/common/operation.cpp b/src/common/operation.cpp
index 5de003f..d8915b2 100644
--- a/src/common/operation.cpp
+++ b/src/common/operation.cpp
@@ -65,7 +65,7 @@ Operation::apply(const BufferPtr & buffer,
                   "buffer", buffer->gobj(),
                   NULL);
 
-    const NodePtr operation = get_node(root);
+    const NodePtr operation = get_node(buffer, root);
 
     const NodePtr buffer_sink = root->new_child("operation",
                                                 "gegl:buffer-sink");
diff --git a/src/common/utils.cpp b/src/common/utils.cpp
new file mode 100644
index 0000000..824902f
--- /dev/null
+++ b/src/common/utils.cpp
@@ -0,0 +1,50 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
+/*
+ * Copyright (C) 2010 Debarshi Ray <rishi gnu org>
+ *
+ * Solang 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Solang 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/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif // HAVE_CONFIG_H
+
+#include "utils.h"
+
+namespace Solang
+{
+
+/*
+ * Based on code by: Calvin Williamson
+ *
+ * This code was originally written in C as a part of GEGL:
+ * gegl/gegl-utils.c
+ */
+
+const gdouble EPSILON = 1e-5;
+
+bool
+is_zero(gdouble value)
+{
+    return value > -EPSILON && value < EPSILON;
+}
+
+bool
+is_equal(gdouble v1, gdouble v2)
+{
+    const register gdouble diff = v1 - v2;
+    return diff > -EPSILON && diff < EPSILON;
+}
+
+} // namespace Solang
diff --git a/src/common/utils.h b/src/common/utils.h
new file mode 100644
index 0000000..991648f
--- /dev/null
+++ b/src/common/utils.h
@@ -0,0 +1,41 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
+/*
+ * Copyright (C) 2010 Debarshi Ray <rishi gnu org>
+ *
+ * Solang 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Solang 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/>.
+ */
+
+#ifndef SOLANG_UTILS_H
+#define SOLANG_UTILS_H
+
+#include <glibmm.h>
+
+namespace Solang
+{
+
+/*
+ * Based on code by: Calvin Williamson
+ *
+ * This code was originally written in C as a part of GEGL:
+ * gegl/gegl-utils.h
+ */
+
+extern const gdouble EPSILON;
+
+bool is_zero(gdouble value);
+bool is_equal(gdouble v1, gdouble v2);
+
+} // namespace Solang
+
+#endif // SOLANG_UTILS_H
diff --git a/src/editor/flip-operation.cpp b/src/editor/flip-operation.cpp
index 29dfc6a..fbc670b 100644
--- a/src/editor/flip-operation.cpp
+++ b/src/editor/flip-operation.cpp
@@ -21,9 +21,11 @@
 #endif // HAVE_CONFIG_H
 
 #include <geglmm.h>
+#include <geglmm/buffer.h>
 #include <glibmm/i18n.h>
 
 #include "flip-operation.h"
+#include "utils.h"
 
 namespace Solang
 {
@@ -58,11 +60,15 @@ FlipOperation::get_description() const throw()
 }
 
 NodePtr
-FlipOperation::get_node(const NodePtr & root) const throw()
+FlipOperation::get_node(const BufferPtr & buffer,
+                        const NodePtr & root) const throw()
 {
-    const NodePtr operation = root->new_child("operation",
-                                              "gegl:reflect");
-    gegl_node_set(operation->gobj(),
+    const NodePtr operation = Gegl::Node::create();
+    operation->set("format", babl_format("RGB u8"));
+
+    const NodePtr reflect = operation->new_child("operation",
+                                                 "gegl:reflect");
+    gegl_node_set(reflect->gobj(),
                   "origin-x", originX_,
                   "origin-y", originY_,
                   "filter", filter_.c_str(),
@@ -72,6 +78,46 @@ FlipOperation::get_node(const NodePtr & root) const throw()
                   "y", y_,
                   NULL);
 
+    const Gegl::Rectangle & extent = buffer->get_extent();
+    const gint height = extent.gobj()->height;
+    const gint width = extent.gobj()->width;
+
+    gint translate_x;
+    gint translate_y;
+
+    if (is_zero(x_) && !is_zero(y_)) // horizontal
+    {
+        translate_x = width;
+        translate_y = 0;
+    }
+    else if (!is_zero(x_) && is_zero(y_)) // vertical
+    {
+        translate_x = 0;
+        translate_y = height;
+    }
+
+    const NodePtr translate = operation->new_child("operation",
+                                                   "gegl:translate");
+    gegl_node_set(translate->gobj(),
+                  "filter", "nearest",
+                  "x", static_cast<gdouble>(translate_x),
+                  "y", static_cast<gdouble>(translate_y),
+                  NULL);
+
+    const NodePtr crop = operation->new_child("operation",
+                                              "gegl:crop");
+    gegl_node_set(crop->gobj(),
+                  "x", 0.0,
+                  "y", 0.0,
+                  "width", static_cast<gdouble>(width),
+                  "height", static_cast<gdouble>(height),
+                  NULL);
+
+    const NodePtr input = operation->get_input_proxy("input");
+    const NodePtr output = operation->get_output_proxy("output");
+
+    input->link(reflect)->link(translate)->link(crop)->link(output);
+
     return operation;
 }
 
diff --git a/src/editor/flip-operation.h b/src/editor/flip-operation.h
index 67284a9..a034d82 100644
--- a/src/editor/flip-operation.h
+++ b/src/editor/flip-operation.h
@@ -54,7 +54,8 @@ class FlipOperation :
 
     protected:
         virtual NodePtr
-        get_node(const NodePtr & root) const throw();
+        get_node(const BufferPtr & buffer, const NodePtr & root) const
+                 throw();
 
         void
         set_hard_edges(bool hard_edges) throw();
diff --git a/src/editor/rotate-operation.cpp b/src/editor/rotate-operation.cpp
index af60c7f..0bd55fa 100644
--- a/src/editor/rotate-operation.cpp
+++ b/src/editor/rotate-operation.cpp
@@ -21,9 +21,11 @@
 #endif // HAVE_CONFIG_H
 
 #include <geglmm.h>
+#include <geglmm/buffer.h>
 #include <glibmm/i18n.h>
 
 #include "rotate-operation.h"
+#include "utils.h"
 
 namespace Solang
 {
@@ -56,11 +58,15 @@ RotateOperation::get_description() const throw()
 }
 
 NodePtr
-RotateOperation::get_node(const NodePtr & root) const throw()
+RotateOperation::get_node(const BufferPtr & buffer,
+                          const NodePtr & root) const throw()
 {
-    const NodePtr operation = root->new_child("operation",
-                                              "gegl:rotate");
-    gegl_node_set(operation->gobj(),
+    const NodePtr operation = Gegl::Node::create();
+    operation->set("format", babl_format("RGB u8"));
+
+    const NodePtr rotate = root->new_child("operation",
+                                           "gegl:rotate");
+    gegl_node_set(rotate->gobj(),
                   "origin-x", originX_,
                   "origin-y", originY_,
                   "filter", filter_.c_str(),
@@ -69,6 +75,46 @@ RotateOperation::get_node(const NodePtr & root) const throw()
                   "degrees", degrees_,
                   NULL);
 
+    const Gegl::Rectangle & extent = buffer->get_extent();
+    const gint height = extent.gobj()->height;
+    const gint width = extent.gobj()->width;
+
+    gint translate_x;
+    gint translate_y;
+
+    if (is_equal(-90.0, degrees_)) // clockwise
+    {
+        translate_x = height;
+        translate_y = 0;
+    }
+    else if (is_equal(90.0, degrees_)) // counter-clockwise
+    {
+        translate_x = 0;
+        translate_y = width;
+    }
+
+    const NodePtr translate = operation->new_child("operation",
+                                                   "gegl:translate");
+    gegl_node_set(translate->gobj(),
+                  "filter", "nearest",
+                  "x", static_cast<gdouble>(translate_x),
+                  "y", static_cast<gdouble>(translate_y),
+                  NULL);
+
+    const NodePtr crop = operation->new_child("operation",
+                                              "gegl:crop");
+    gegl_node_set(crop->gobj(),
+                  "x", 0.0,
+                  "y", 0.0,
+                  "width", static_cast<gdouble>(height),
+                  "height", static_cast<gdouble>(width),
+                  NULL);
+
+    const NodePtr input = operation->get_input_proxy("input");
+    const NodePtr output = operation->get_output_proxy("output");
+
+    input->link(rotate)->link(translate)->link(crop)->link(output);
+
     return operation;
 }
 
diff --git a/src/editor/rotate-operation.h b/src/editor/rotate-operation.h
index d961bf5..b1c0f63 100644
--- a/src/editor/rotate-operation.h
+++ b/src/editor/rotate-operation.h
@@ -53,7 +53,8 @@ class RotateOperation :
 
     protected:
         virtual NodePtr
-        get_node(const NodePtr & root) const throw();
+        get_node(const BufferPtr & buffer, const NodePtr & root) const
+                 throw();
 
         void
         set_hard_edges(bool hard_edges) throw();



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