[gegl] map-{absolute,relative}: factor out common code; add scale matrix



commit 7e1ddbb250a17e0ebd37f4fa397025c9d87fe9ee
Author: Ell <ell_se yahoo com>
Date:   Thu Nov 15 14:31:54 2018 -0500

    map-{absolute,relative}: factor out common code; add scale matrix
    
    Factor out the common code of gegl:map-absolute and
    gegl:map-relative to map-common.h, and include it in both
    operations.
    
    When using a non-nearest sampler, use the gradient of the input
    field to construct a scale matrix to pass to the sampler, to reduce
    aliasing when the input is downscaled.

 operations/common/map-absolute.c | 108 +------------
 operations/common/map-common.h   | 319 +++++++++++++++++++++++++++++++++++++++
 operations/common/map-relative.c | 111 +-------------
 3 files changed, 327 insertions(+), 211 deletions(-)
---
diff --git a/operations/common/map-absolute.c b/operations/common/map-absolute.c
index 144b01dd8..c9aecf6bc 100644
--- a/operations/common/map-absolute.c
+++ b/operations/common/map-absolute.c
@@ -39,112 +39,9 @@ property_enum (abyss_policy, _("Abyss policy"),
 #include "gegl-op.h"
 
 
-static void
-prepare (GeglOperation *operation)
-{
-  const Babl *space = gegl_operation_get_source_space (operation, "input");
-  const Babl *format = babl_format_with_space ("RGBA float", space);
-
-  gegl_operation_set_format (operation, "input", format);
-  gegl_operation_set_format (operation, "aux", babl_format_n (babl_type ("float"), 2));
-  gegl_operation_set_format (operation, "output", format);
-}
-
-static GeglRectangle
-get_required_for_output (GeglOperation       *operation,
-                         const gchar         *input_pad,
-                         const GeglRectangle *region)
-{
-  if (! strcmp (input_pad, "input"))
-    return *gegl_operation_source_get_bounding_box (operation, "input");
-  else
-    return *region;
-}
-
-static gboolean
-process (GeglOperation       *operation,
-         GeglBuffer          *input,
-         GeglBuffer          *aux,
-         GeglBuffer          *output,
-         const GeglRectangle *result,
-         gint                 level)
-{
-  GeglProperties       *o = GEGL_PROPERTIES (operation);
-  const Babl           *format_io, *format_coords;
-  GeglSampler          *sampler;
-  GeglBufferIterator   *it;
-  gint                  index_in, index_out, index_coords;
-
-  format_io = gegl_operation_get_format (operation,"output");
-  format_coords = babl_format_n (babl_type ("float"), 2);
+#define MAP_ABSOLUTE
+#include "map-common.h"
 
-  sampler = gegl_buffer_sampler_new_at_level (input, format_io, o->sampler_type,
-                                              level);
-
-  if (aux != NULL)
-    {
-      it = gegl_buffer_iterator_new (output, result, level, format_io,
-                                     GEGL_ACCESS_WRITE, GEGL_ABYSS_NONE, 3);
-      index_out = 0;
-
-      index_coords = gegl_buffer_iterator_add (it, aux, result, level, format_coords,
-                                               GEGL_ACCESS_READ, GEGL_ABYSS_NONE);
-      index_in = gegl_buffer_iterator_add (it, input, result, level, format_io,
-                                           GEGL_ACCESS_READ, o->abyss_policy);
-
-      while (gegl_buffer_iterator_next (it))
-        {
-          gint        w;
-          gint        h;
-          gfloat      x;
-          gfloat      y;
-          gfloat     *in = it->items[index_in].data;
-          gfloat     *out = it->items[index_out].data;
-          gfloat     *coords = it->items[index_coords].data;
-          GeglRectangle *roi = &it->items[0].roi;
-
-          y = roi->y + 0.5; /* initial y coordinate */
-
-          for (h = roi->height; h; h--, y++)
-            {
-              x = roi->x + 0.5; /* initial x coordinate */
-
-              for (w = roi->width; w; w--, x++)
-                {
-                  /* if the coordinate asked is an exact pixel, we fetch it
-                   * directly, to avoid the blur of sampling */
-                  if (coords[0] == x && coords[1] == y)
-                    {
-                      out[0] = in[0];
-                      out[1] = in[1];
-                      out[2] = in[2];
-                      out[3] = in[3];
-                    }
-                  else
-                    {
-                      gegl_sampler_get (sampler, coords[0],
-                                                 coords[1],
-                                                 NULL, out,
-                                                 o->abyss_policy);
-                    }
-
-                  coords += 2;
-                  in += 4;
-                  out += 4;
-                }
-            }
-        }
-    }
-  else
-    {
-      gegl_buffer_copy (input, result, o->abyss_policy,
-                        output, result);
-    }
-
-  g_object_unref (sampler);
-
-  return TRUE;
-}
 
 static void
 gegl_op_class_init (GeglOpClass *klass)
@@ -158,6 +55,7 @@ gegl_op_class_init (GeglOpClass *klass)
   composer_class->process = process;
   operation_class->prepare = prepare;
   operation_class->get_required_for_output = get_required_for_output;
+  operation_class->get_invalidated_by_change = get_invalidated_by_change;
 
   gegl_operation_class_set_keys (operation_class,
     "name",              "gegl:map-absolute",
diff --git a/operations/common/map-common.h b/operations/common/map-common.h
new file mode 100644
index 000000000..1e89b00ae
--- /dev/null
+++ b/operations/common/map-common.h
@@ -0,0 +1,319 @@
+/* This file is an image processing operation for GEGL
+ *
+ * GEGL is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * GEGL 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GEGL; if not, see <https://www.gnu.org/licenses/>.
+ *
+ * Copyright 2011 Michael Muré <batolettre gmail com>
+ *
+ */
+
+
+#include <math.h>
+
+
+#define EPSILON 1e-6
+
+
+static void
+prepare (GeglOperation *operation)
+{
+  const Babl *space = gegl_operation_get_source_space (operation, "input");
+  const Babl *format = babl_format_with_space ("RGBA float", space);
+
+  gegl_operation_set_format (operation, "input", format);
+  gegl_operation_set_format (operation, "aux", babl_format_n (babl_type ("float"), 2));
+  gegl_operation_set_format (operation, "output", format);
+}
+
+static GeglRectangle
+get_required_for_output (GeglOperation       *operation,
+                         const gchar         *input_pad,
+                         const GeglRectangle *region)
+{
+  if (! strcmp (input_pad, "input"))
+    {
+      return *gegl_operation_source_get_bounding_box (operation, "input");
+    }
+  else
+    {
+      GeglRectangle rect = *region;
+
+      rect.x      -= 1;
+      rect.y      -= 1;
+      rect.width  += 2;
+      rect.height += 2;
+
+      return rect;
+    }
+}
+
+static GeglRectangle
+get_invalidated_by_change (GeglOperation       *operation,
+                           const gchar         *input_pad,
+                           const GeglRectangle *region)
+{
+  if (! strcmp (input_pad, "input"))
+    {
+      return gegl_operation_get_bounding_box (operation);
+    }
+  else
+    {
+      GeglRectangle rect = *region;
+
+      rect.x      -= 1;
+      rect.y      -= 1;
+      rect.width  += 2;
+      rect.height += 2;
+
+      return rect;
+    }
+}
+
+static gboolean
+process (GeglOperation       *operation,
+         GeglBuffer          *input,
+         GeglBuffer          *aux,
+         GeglBuffer          *output,
+         const GeglRectangle *result,
+         gint                 level)
+{
+  GeglProperties     *o = GEGL_PROPERTIES (operation);
+  const Babl         *format_io, *format_coords;
+  GeglSampler        *sampler;
+  GeglBufferIterator *it;
+  gint                index_in, index_out, index_coords;
+
+  format_io = gegl_operation_get_format (operation, "output");
+  format_coords = babl_format_n (babl_type ("float"), 2);
+
+  sampler = gegl_buffer_sampler_new_at_level (input, format_io,
+                                              o->sampler_type, level);
+
+  if (aux != NULL
+#ifdef MAP_RELATIVE
+      && fabs (o->scaling) > EPSILON
+#endif
+     )
+    {
+      it = gegl_buffer_iterator_new (output, result, level, format_io,
+                                     GEGL_ACCESS_WRITE, GEGL_ABYSS_NONE, 3);
+      index_out = 0;
+
+      index_coords = gegl_buffer_iterator_add (it, aux, result, level, format_coords,
+                                               GEGL_ACCESS_READ, GEGL_ABYSS_NONE);
+      index_in = gegl_buffer_iterator_add (it, input, result, level, format_io,
+                                           GEGL_ACCESS_READ, o->abyss_policy);
+
+      while (gegl_buffer_iterator_next (it))
+        {
+          gint        c;
+          gint        r;
+          gfloat      x;
+          gfloat      y;
+#ifdef MAP_RELATIVE
+          gdouble     scaling = GEGL_PROPERTIES (operation)->scaling;
+          gdouble     scaling_2 = scaling / 2.0;
+#endif
+          gfloat     *in = it->items[index_in].data;
+          gfloat     *out = it->items[index_out].data;
+          gfloat     *coords = it->items[index_coords].data;
+          GeglRectangle *roi = &it->items[0].roi;
+
+          y = roi->y + 0.5; /* initial y coordinate */
+
+          if (o->sampler_type == GEGL_SAMPLER_NEAREST)
+            {
+              for (r = 0; r < roi->height; r++, y++)
+                {
+                  x = roi->x + 0.5; /* initial x coordinate */
+
+                  for (c = 0; c < roi->width; c++, x++)
+                    {
+                      /* if the coordinate asked is an exact pixel, we
+                       * fetch it directly
+                       */
+#ifdef MAP_RELATIVE
+                      if (coords[0] == 0.0f && coords[1] == 0.0f)
+#else
+                      if (coords[0] == x    && coords[1] == y)
+#endif
+                        {
+                          out[0] = in[0];
+                          out[1] = in[1];
+                          out[2] = in[2];
+                          out[3] = in[3];
+                        }
+                      else
+                        {
+                          gdouble coords_x = coords[0];
+                          gdouble coords_y = coords[1];
+
+#ifdef MAP_RELATIVE
+                          coords_x = x + coords_x * scaling;
+                          coords_y = y + coords_y * scaling;
+#endif
+
+                          gegl_sampler_get (sampler,
+                                            coords_x, coords_y,
+                                            NULL, out,
+                                            o->abyss_policy);
+                        }
+
+                      coords += 2;
+                      in += 4;
+                      out += 4;
+                    }
+                }
+            }
+          else
+            {
+              gint   stride = 2 * roi->width;
+              gfloat coords_top[2 * roi->width];
+              gfloat coords_bottom[2 * roi->width];
+              gfloat coords_left[2 * roi->height];
+              gfloat coords_right[2 * roi->height];
+
+              gegl_buffer_get (aux,
+                               GEGL_RECTANGLE (roi->x, roi->y - 1,
+                                               roi->width, 1),
+                               1.0, format_coords, coords_top,
+                               GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_CLAMP);
+              gegl_buffer_get (aux,
+                               GEGL_RECTANGLE (roi->x, roi->y + roi->height,
+                                               roi->width, 1),
+                               1.0, format_coords, coords_bottom,
+                               GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_CLAMP);
+              gegl_buffer_get (aux,
+                               GEGL_RECTANGLE (roi->x - 1, roi->y,
+                                               1, roi->height),
+                               1.0, format_coords, coords_left,
+                               GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_CLAMP);
+              gegl_buffer_get (aux,
+                               GEGL_RECTANGLE (roi->x + roi->width, roi->y,
+                                               1, roi->height),
+                               1.0, format_coords, coords_right,
+                               GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_CLAMP);
+
+              for (r = 0; r < roi->height; r++, y++)
+                {
+                  x = roi->x + 0.5; /* initial x coordinate */
+
+                  for (c = 0; c < roi->width; c++, x++)
+                    {
+                      GeglBufferMatrix2 scale;
+
+                      if (c < roi->width - 1)
+                        {
+                          scale.coeff[0][0] = coords[2];
+                          scale.coeff[1][0] = coords[3];
+                        }
+                      else
+                        {
+                          scale.coeff[0][0] = coords_right[2 * r + 0];
+                          scale.coeff[1][0] = coords_right[2 * r + 1];
+                        }
+
+                      if (c > 0)
+                        {
+                          scale.coeff[0][0] -= coords[-2];
+                          scale.coeff[1][0] -= coords[-1];
+                        }
+                      else
+                        {
+                          scale.coeff[0][0] -= coords_left[2 * r + 0];
+                          scale.coeff[1][0] -= coords_left[2 * r + 1];
+                        }
+
+                      if (r < roi->height - 1)
+                        {
+                          scale.coeff[0][1] = coords[stride + 0];
+                          scale.coeff[1][1] = coords[stride + 1];
+                        }
+                      else
+                        {
+                          scale.coeff[0][1] = coords_bottom[2 * c + 0];
+                          scale.coeff[1][1] = coords_bottom[2 * c + 1];
+                        }
+
+                      if (r > 0)
+                        {
+                          scale.coeff[0][1] -= coords[-stride + 0];
+                          scale.coeff[1][1] -= coords[-stride + 1];
+                        }
+                      else
+                        {
+                          scale.coeff[0][1] -= coords_top[2 * c + 0];
+                          scale.coeff[1][1] -= coords_top[2 * c + 1];
+                        }
+
+#ifdef MAP_RELATIVE
+                      scale.coeff[0][0] = scale.coeff[0][0] * scaling_2 + 1.0;
+                      scale.coeff[0][1] = scale.coeff[0][1] * scaling_2;
+                      scale.coeff[1][0] = scale.coeff[1][0] * scaling_2;
+                      scale.coeff[1][1] = scale.coeff[1][1] * scaling_2 + 1.0;
+#else
+                      scale.coeff[0][0] /= 2.0;
+                      scale.coeff[0][1] /= 2.0;
+                      scale.coeff[1][0] /= 2.0;
+                      scale.coeff[1][1] /= 2.0;
+#endif
+
+                      /* if the coordinate asked is an exact pixel, we fetch it
+                       * directly, to avoid the blur of sampling
+                       */
+#ifdef MAP_RELATIVE
+                      if (coords[0] == 0.0f && coords[1] == 0.0f &&
+#else
+                      if (coords[0] == x    && coords[1] == y    &&
+#endif
+                          gegl_buffer_matrix2_is_identity (&scale))
+                        {
+                          out[0] = in[0];
+                          out[1] = in[1];
+                          out[2] = in[2];
+                          out[3] = in[3];
+                        }
+                      else
+                        {
+                          gdouble coords_x = coords[0];
+                          gdouble coords_y = coords[1];
+
+#ifdef MAP_RELATIVE
+                          coords_x = x + coords_x * scaling;
+                          coords_y = y + coords_y * scaling;
+#endif
+
+                          gegl_sampler_get (sampler,
+                                            coords_x, coords_y,
+                                            &scale, out,
+                                            o->abyss_policy);
+                        }
+
+                      coords += 2;
+                      in += 4;
+                      out += 4;
+                    }
+                }
+            }
+        }
+    }
+  else
+    {
+      gegl_buffer_copy (input, result, o->abyss_policy,
+                        output, result);
+    }
+
+  g_object_unref (sampler);
+
+  return TRUE;
+}
diff --git a/operations/common/map-relative.c b/operations/common/map-relative.c
index 17c21f723..5ec22a23e 100644
--- a/operations/common/map-relative.c
+++ b/operations/common/map-relative.c
@@ -17,7 +17,6 @@
  *
  */
 
-
 #define GEGL_ITERATOR2_API
 #ifdef GEGL_PROPERTIES
 
@@ -33,6 +32,8 @@ property_enum (abyss_policy, _("Abyss policy"),
                GeglAbyssPolicy, gegl_abyss_policy,
                GEGL_ABYSS_NONE)
 
+property_boolean (box_filter, _("Box filter"), FALSE)
+
 #else
 
 #define GEGL_OP_COMPOSER
@@ -44,112 +45,9 @@ property_enum (abyss_policy, _("Abyss policy"),
 #include "gegl-op.h"
 
 
-static void
-prepare (GeglOperation *operation)
-{
-  const Babl *space = gegl_operation_get_source_space (operation, "input");
-  const Babl *format = babl_format_with_space ("RGBA float", space);
-
-  gegl_operation_set_format (operation, "input", format);
-  gegl_operation_set_format (operation, "aux", babl_format_n (babl_type ("float"), 2));
-  gegl_operation_set_format (operation, "output", format);
-}
+#define MAP_RELATIVE
+#include "map-common.h"
 
-static GeglRectangle
-get_required_for_output (GeglOperation       *operation,
-                         const gchar         *input_pad,
-                         const GeglRectangle *region)
-{
-  if (! strcmp (input_pad, "input"))
-    return *gegl_operation_source_get_bounding_box (operation, "input");
-  else
-    return *region;
-}
-
-static gboolean
-process (GeglOperation       *operation,
-         GeglBuffer          *input,
-         GeglBuffer          *aux,
-         GeglBuffer          *output,
-         const GeglRectangle *result,
-         gint                 level)
-{
-  GeglProperties       *o = GEGL_PROPERTIES (operation);
-  const Babl           *format_io, *format_coords;
-  GeglSampler          *sampler;
-  GeglBufferIterator   *it;
-  gint                  index_in, index_out, index_coords;
-
-  format_io = gegl_operation_get_format (operation, "output");
-  format_coords = babl_format_n (babl_type ("float"), 2);
-
-  sampler = gegl_buffer_sampler_new_at_level (input, format_io, o->sampler_type, level);
-
-  if (aux != NULL && o->scaling != 0.0)
-    {
-      it = gegl_buffer_iterator_new (output, result, level, format_io,
-                                     GEGL_ACCESS_WRITE, GEGL_ABYSS_NONE, 3);
-      index_out = 0;
-
-      index_coords = gegl_buffer_iterator_add (it, aux, result, level, format_coords,
-                                               GEGL_ACCESS_READ, GEGL_ABYSS_NONE);
-      index_in = gegl_buffer_iterator_add (it, input, result, level, format_io,
-                                           GEGL_ACCESS_READ, o->abyss_policy);
-
-      while (gegl_buffer_iterator_next (it))
-        {
-          gint        w;
-          gint        h;
-          gfloat      x;
-          gfloat      y;
-          gfloat      scaling = GEGL_PROPERTIES (operation)->scaling;
-          gfloat     *in = it->items[index_in].data;
-          gfloat     *out = it->items[index_out].data;
-          gfloat     *coords = it->items[index_coords].data;
-          GeglRectangle *roi = &it->items[0].roi;
-
-          y = roi->y + 0.5; /* initial y coordinate */
-
-          for (h = roi->height; h; h--, y++)
-            {
-              x = roi->x + 0.5; /* initial x coordinate */
-
-              for (w = roi->width; w; w--, x++)
-                {
-                  /* if the coordinate asked is an exact pixel, we fetch it
-                   * directly, to avoid the blur of sampling */
-                  if (coords[0] == 0.0f && coords[1] == 0.0f)
-                    {
-                      out[0] = in[0];
-                      out[1] = in[1];
-                      out[2] = in[2];
-                      out[3] = in[3];
-                    }
-                  else
-                    {
-                      gegl_sampler_get (sampler, x + coords[0] * scaling,
-                                                 y + coords[1] * scaling,
-                                                 NULL, out,
-                                                 o->abyss_policy);
-                    }
-
-                  coords += 2;
-                  in += 4;
-                  out += 4;
-                }
-            }
-        }
-    }
-  else
-    {
-      gegl_buffer_copy (input, result, o->abyss_policy,
-                        output, result);
-    }
-
-  g_object_unref (sampler);
-
-  return TRUE;
-}
 
 static void
 gegl_op_class_init (GeglOpClass *klass)
@@ -178,6 +76,7 @@ gegl_op_class_init (GeglOpClass *klass)
   composer_class->process = process;
   operation_class->prepare = prepare;
   operation_class->get_required_for_output = get_required_for_output;
+  operation_class->get_invalidated_by_change = get_invalidated_by_change;
 
   gegl_operation_class_set_keys (operation_class,
     "name",        "gegl:map-relative",


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