[gegl] operations: add gegl:illusion



commit b410aa5fa19ae2c897da27180a48886c04daa76a
Author: Thomas Manni <thomas manni free fr>
Date:   Mon Dec 1 23:51:19 2014 +0100

    operations: add gegl:illusion

 operations/common/Makefile.am             |    1 +
 operations/common/illusion.c              |  239 +++++++++++++++++++++++++++++
 po/POTFILES.in                            |    1 +
 tests/compositions/Makefile.am            |    1 +
 tests/compositions/illusion.xml           |   15 ++
 tests/compositions/reference/illusion.png |  Bin 0 -> 1096436 bytes
 6 files changed, 257 insertions(+), 0 deletions(-)
---
diff --git a/operations/common/Makefile.am b/operations/common/Makefile.am
index 4402f6e..a6ad566 100644
--- a/operations/common/Makefile.am
+++ b/operations/common/Makefile.am
@@ -53,6 +53,7 @@ op_LTLIBRARIES = \
        grey.la \
        grid.la \
        high-pass.la \
+       illusion.la \
        image-compare.la \
        introspect.la \
        invert-gamma.la \
diff --git a/operations/common/illusion.c b/operations/common/illusion.c
new file mode 100644
index 0000000..ff455e7
--- /dev/null
+++ b/operations/common/illusion.c
@@ -0,0 +1,239 @@
+/* This file is an image processing operation for GEGL
+ *
+ * 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 3 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/>.
+ *
+ * Author: Hirotsuna Mizuno <s1041150 u-aizu ac jp>
+ *
+ * GEGL port: Thomas Manni <thomas manni free fr>
+ *
+ */
+
+#include "config.h"
+#include <glib/gi18n-lib.h>
+
+#ifdef GEGL_PROPERTIES
+
+enum_start (gegl_illusion_type)
+  enum_value (GEGL_ILLUSION_TYPE_1, "type1", N_("Type 1"))
+  enum_value (GEGL_ILLUSION_TYPE_2, "type2", N_("Type 2"))
+enum_end (GeglIllusionType)
+
+property_int  (division, _("Division"), 8)
+  description (_("The number of divisions"))
+  value_range (0, 64)
+  ui_range    (0, 64)
+
+property_enum (illusion_type, _("Illusion type"),
+                GeglIllusionType, gegl_illusion_type,
+                GEGL_ILLUSION_TYPE_1)
+  description (_("Type of illusion"))
+
+#else
+
+#define GEGL_OP_FILTER
+#define GEGL_OP_C_FILE "illusion.c"
+
+#include "gegl-op.h"
+#include <math.h>
+
+static void prepare (GeglOperation *operation)
+{
+  const Babl *format = gegl_operation_get_source_format (operation, "input");
+
+  if (! format || ! babl_format_has_alpha (format))
+    format = babl_format ("R'G'B' float");
+  else
+    format = babl_format ("R'G'B'A float");
+
+  gegl_operation_set_format (operation, "input",  format);
+  gegl_operation_set_format (operation, "output", format);
+}
+
+static GeglRectangle
+get_required_for_output (GeglOperation       *operation,
+                         const gchar         *input_pad,
+                         const GeglRectangle *roi)
+{
+  GeglRectangle result = *gegl_operation_source_get_bounding_box (operation, "input");
+
+  /* Don't request an infinite plane */
+  if (gegl_rectangle_is_infinite_plane (&result))
+    return *roi;
+
+  return result;
+}
+
+static GeglRectangle
+get_cached_region (GeglOperation       *operation,
+                   const GeglRectangle *roi)
+{
+  GeglRectangle result = *gegl_operation_source_get_bounding_box (operation, "input");
+
+  if (gegl_rectangle_is_infinite_plane (&result))
+    return *roi;
+
+  return result;
+}
+
+static gboolean
+process (GeglOperation       *operation,
+         GeglBuffer          *input,
+         GeglBuffer          *output,
+         const GeglRectangle *result,
+         gint                 level)
+{
+  GeglProperties     *o = GEGL_PROPERTIES (operation);
+
+  gfloat   *src;
+  gfloat   *dst;
+  gint     x, y, xx, yy, b;
+  gint     width, height, components;
+  gdouble  radius, cx, cy, angle;
+  gdouble  center_x;
+  gdouble  center_y;
+  gdouble  scale;
+  gdouble  offset;
+  glong    idx1, idx2;
+  gboolean has_alpha;
+  gfloat   alpha, alpha1, alpha2;
+
+  const Babl *format = gegl_operation_get_format (operation, "output");
+  has_alpha  = babl_format_has_alpha (format);
+
+  if (has_alpha)
+    components = 4;
+  else
+    components = 3;
+
+  width = result->width;
+  height = result->height;
+
+  src = g_new0 (gfloat, width * height * components);
+  dst = g_new0 (gfloat, width * height * components);
+
+  gegl_buffer_get (input, result, 1.0, format, src, GEGL_AUTO_ROWSTRIDE,
+                   GEGL_ABYSS_CLAMP);
+
+  center_x = width / 2.0;
+  center_y = height / 2.0;
+  scale = sqrt (width * width + height * height) / 2;
+  offset = (gint) (scale / 2);
+
+  for (y = 0; y < height; y++)
+    for (x = 0; x < width; x++)
+      {
+        cy = ((gdouble) y - center_y) / scale;
+        cx = ((gdouble) x - center_x) / scale;
+
+        angle = floor (atan2 (cy, cx) * o->division / G_PI_2) *
+                      G_PI_2 / o->division + (G_PI / o->division);
+        radius = sqrt ((gdouble) (cx * cx + cy * cy));
+
+        if (o->illusion_type == GEGL_ILLUSION_TYPE_1)
+          {
+            xx = x - offset * cos (angle);
+            yy = y - offset * sin (angle);
+          }
+        else                          /* GEGL_ILLUSION_TYPE_2 */
+          {
+            xx = x - offset * sin (angle);
+            yy = y - offset * cos (angle);
+          }
+
+        xx = CLAMP (xx, 0, width - 1);
+        yy = CLAMP (yy, 0, height - 1);
+
+        idx1 = (y * width + x) * components;
+        idx2 = (yy * width + xx) * components;
+
+        if (has_alpha)
+          {
+            alpha1 = src[idx1 + 3];
+            alpha2 = src[idx2 + 3];
+            alpha  = (1 - radius) * alpha1 + radius * alpha2;
+
+            if ((dst[idx1 + 3] = (alpha / 2)))
+             {
+               for (b = 0; b < 3; b++)
+                 dst[idx1 + b] = ((1 - radius) * src[idx1 + b] * alpha1 +
+                                radius * src[idx2 + b] * alpha2) / alpha;
+             }
+          }
+        else
+          {
+            for (b = 0; b < 3; b++)
+              dst[idx1 + b] = (1 - radius) * src[idx1 + b] + radius * src[idx2 + b];
+          }
+        }
+
+  gegl_buffer_set (output, result, level, format, dst, GEGL_AUTO_ROWSTRIDE);
+
+  g_free (src);
+  g_free (dst);
+
+  return  TRUE;
+}
+
+static gboolean
+operation_process (GeglOperation        *operation,
+                   GeglOperationContext *context,
+                   const gchar          *output_prop,
+                   const GeglRectangle  *result,
+                   gint                  level)
+{
+  GeglOperationClass  *operation_class;
+
+  const GeglRectangle *in_rect =
+    gegl_operation_source_get_bounding_box (operation, "input");
+
+  operation_class = GEGL_OPERATION_CLASS (gegl_op_parent_class);
+
+  if (in_rect && gegl_rectangle_is_infinite_plane (in_rect))
+    {
+      gpointer in = gegl_operation_context_get_object (context, "input");
+      gegl_operation_context_take_object (context, "output",
+                                          g_object_ref (G_OBJECT (in)));
+      return TRUE;
+    }
+
+  return operation_class->process (operation, context, output_prop, result,
+                                   gegl_operation_context_get_level (context));
+}
+
+static void
+gegl_op_class_init (GeglOpClass *klass)
+{
+  GeglOperationClass       *operation_class;
+  GeglOperationFilterClass *filter_class;
+
+  operation_class = GEGL_OPERATION_CLASS (klass);
+  filter_class    = GEGL_OPERATION_FILTER_CLASS (klass);
+
+  filter_class->process                    = process;
+  operation_class->prepare                 = prepare;
+  operation_class->process                 = operation_process;
+  operation_class->get_required_for_output = get_required_for_output;
+  operation_class->get_cached_region       = get_cached_region;
+  operation_class->opencl_support          = FALSE;
+
+  gegl_operation_class_set_keys (operation_class,
+      "name",        "gegl:illusion",
+      "title",       _("Illusion"),
+      "categories",  "map",
+      "license",     "GPL3+",
+      "description", _("Superimpose many altered copies of the image."),
+      NULL);
+}
+
+#endif
diff --git a/po/POTFILES.in b/po/POTFILES.in
index dd92bf7..8c740f9 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -47,6 +47,7 @@ operations/common/gegl-buffer-save-op.c
 operations/common/grey.c
 operations/common/grid.c
 operations/common/high-pass.c
+operations/common/illusion.c
 operations/common/image-compare.c
 operations/common/introspect.c
 operations/common/invert-gamma.c
diff --git a/tests/compositions/Makefile.am b/tests/compositions/Makefile.am
index adb5e99..b85e81d 100644
--- a/tests/compositions/Makefile.am
+++ b/tests/compositions/Makefile.am
@@ -31,6 +31,7 @@ TESTS = \
        gegl.xml                        \
   gamma.xml                       \
   hdr-color.xml                   \
+  illusion.xml                    \
   image-compare.xml               \
   mantiuk06.xml                   \
   noise-cell.xml                                       \
diff --git a/tests/compositions/illusion.xml b/tests/compositions/illusion.xml
new file mode 100644
index 0000000..e1f2abf
--- /dev/null
+++ b/tests/compositions/illusion.xml
@@ -0,0 +1,15 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<gegl>
+  <node operation='gegl:illusion'>
+    <params>
+      <param name='division'>7</param>
+      <param name='illusion-type'>type1</param>
+    </params>
+  </node>
+  <node operation='gegl:load'>
+    <params>
+      <param name='path'>data/car-stack.png</param>
+    </params>
+  </node>
+</gegl>
+
diff --git a/tests/compositions/reference/illusion.png b/tests/compositions/reference/illusion.png
new file mode 100644
index 0000000..decf3be
Binary files /dev/null and b/tests/compositions/reference/illusion.png differ


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