[gimp] app: Add "gimp:flood" GEGL operation



commit c63bee344057343eb5edac23ef996400e23bcafc
Author: Ell <ell_se yahoo com>
Date:   Sun Jan 24 17:08:43 2016 +0000

    app: Add "gimp:flood" GEGL operation
    
    This operation assigns to each pixel the minimum of the
    maxima of all paths from it to the outside, as if the
    input image represents a height map, and the operation
    floods it with water.

 app/gegl/gimp-gegl-apply-operation.c |   22 +++
 app/gegl/gimp-gegl-apply-operation.h |    6 +
 app/operations/Makefile.am           |    2 +
 app/operations/gimp-operations.c     |    2 +
 app/operations/gimpoperationflood.c  |  240 ++++++++++++++++++++++++++++++++++
 app/operations/gimpoperationflood.h  |   53 ++++++++
 6 files changed, 325 insertions(+), 0 deletions(-)
---
diff --git a/app/gegl/gimp-gegl-apply-operation.c b/app/gegl/gimp-gegl-apply-operation.c
index cb38043..cf519be 100644
--- a/app/gegl/gimp-gegl-apply-operation.c
+++ b/app/gegl/gimp-gegl-apply-operation.c
@@ -427,6 +427,28 @@ gimp_gegl_apply_shrink (GeglBuffer          *src_buffer,
 }
 
 void
+gimp_gegl_apply_flood (GeglBuffer          *src_buffer,
+                       GimpProgress        *progress,
+                       const gchar         *undo_desc,
+                       GeglBuffer          *dest_buffer,
+                       const GeglRectangle *dest_rect)
+{
+  GeglNode *node;
+
+  g_return_if_fail (GEGL_IS_BUFFER (src_buffer));
+  g_return_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress));
+  g_return_if_fail (GEGL_IS_BUFFER (dest_buffer));
+
+  node = gegl_node_new_child (NULL,
+                              "operation", "gimp:flood",
+                              NULL);
+
+  gimp_gegl_apply_operation (src_buffer, progress, undo_desc,
+                             node, dest_buffer, dest_rect);
+  g_object_unref (node);
+}
+
+void
 gimp_gegl_apply_gaussian_blur (GeglBuffer          *src_buffer,
                                GimpProgress        *progress,
                                const gchar         *undo_desc,
diff --git a/app/gegl/gimp-gegl-apply-operation.h b/app/gegl/gimp-gegl-apply-operation.h
index 14e5542..ad1fd91 100644
--- a/app/gegl/gimp-gegl-apply-operation.h
+++ b/app/gegl/gimp-gegl-apply-operation.h
@@ -95,6 +95,12 @@ void   gimp_gegl_apply_shrink          (GeglBuffer            *src_buffer,
                                         gint                   radius_y,
                                         gboolean               edge_lock);
 
+void   gimp_gegl_apply_flood           (GeglBuffer            *src_buffer,
+                                        GimpProgress          *progress,
+                                        const gchar           *undo_desc,
+                                        GeglBuffer            *dest_buffer,
+                                        const GeglRectangle   *dest_rect);
+
 void   gimp_gegl_apply_gaussian_blur   (GeglBuffer            *src_buffer,
                                         GimpProgress          *progress,
                                         const gchar           *undo_desc,
diff --git a/app/operations/Makefile.am b/app/operations/Makefile.am
index 4d169f8..82606b7 100644
--- a/app/operations/Makefile.am
+++ b/app/operations/Makefile.am
@@ -48,6 +48,8 @@ libappoperations_generic_a_sources = \
        gimpoperationcagetransform.h            \
        gimpoperationequalize.c                 \
        gimpoperationequalize.h                 \
+       gimpoperationflood.c                    \
+       gimpoperationflood.h                    \
        gimpoperationgrow.c                     \
        gimpoperationgrow.h                     \
        gimpoperationhistogramsink.c            \
diff --git a/app/operations/gimp-operations.c b/app/operations/gimp-operations.c
index e3f322e..afeec94 100644
--- a/app/operations/gimp-operations.c
+++ b/app/operations/gimp-operations.c
@@ -35,6 +35,7 @@
 #include "gimpoperationcagecoefcalc.h"
 #include "gimpoperationcagetransform.h"
 #include "gimpoperationequalize.h"
+#include "gimpoperationflood.h"
 #include "gimpoperationgrow.h"
 #include "gimpoperationhistogramsink.h"
 #include "gimpoperationmaskcomponents.h"
@@ -103,6 +104,7 @@ gimp_operations_init (void)
   g_type_class_ref (GIMP_TYPE_OPERATION_CAGE_COEF_CALC);
   g_type_class_ref (GIMP_TYPE_OPERATION_CAGE_TRANSFORM);
   g_type_class_ref (GIMP_TYPE_OPERATION_EQUALIZE);
+  g_type_class_ref (GIMP_TYPE_OPERATION_FLOOD);
   g_type_class_ref (GIMP_TYPE_OPERATION_GROW);
   g_type_class_ref (GIMP_TYPE_OPERATION_HISTOGRAM_SINK);
   g_type_class_ref (GIMP_TYPE_OPERATION_MASK_COMPONENTS);
diff --git a/app/operations/gimpoperationflood.c b/app/operations/gimpoperationflood.c
new file mode 100644
index 0000000..59d4b93
--- /dev/null
+++ b/app/operations/gimpoperationflood.c
@@ -0,0 +1,240 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimpoperationflood.c
+ * Copyright (C) 2016 Ell
+ *
+ * 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/>.
+ */
+
+#include "config.h"
+
+#include <cairo.h>
+#include <gegl.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+#include "libgimpcolor/gimpcolor.h"
+#include "libgimpmath/gimpmath.h"
+
+#include "operations-types.h"
+
+#include "gimpoperationflood.h"
+
+
+static void          gimp_operation_flood_prepare      (GeglOperation       *operation);
+static GeglRectangle
+          gimp_operation_flood_get_required_for_output (GeglOperation       *self,
+                                                        const gchar         *input_pad,
+                                                        const GeglRectangle *roi);
+static GeglRectangle
+                gimp_operation_flood_get_cached_region (GeglOperation       *self,
+                                                        const GeglRectangle *roi);
+
+static gboolean gimp_operation_flood_process_segment   (const gfloat        *src,
+                                                        gfloat              *dest,
+                                                        gchar               *changed,
+                                                        gint                 size);
+static gboolean gimp_operation_flood_process           (GeglOperation       *operation,
+                                                        GeglBuffer          *input,
+                                                        GeglBuffer          *output,
+                                                        const GeglRectangle *roi,
+                                                        gint                 level);
+
+
+G_DEFINE_TYPE (GimpOperationFlood, gimp_operation_flood,
+               GEGL_TYPE_OPERATION_FILTER)
+
+#define parent_class gimp_operation_flood_parent_class
+
+
+static void
+gimp_operation_flood_class_init (GimpOperationFloodClass *klass)
+{
+  GeglOperationClass       *operation_class = GEGL_OPERATION_CLASS (klass);
+  GeglOperationFilterClass *filter_class    = GEGL_OPERATION_FILTER_CLASS (klass);
+
+  operation_class->want_in_place = FALSE;
+  operation_class->threaded      = FALSE;
+
+  gegl_operation_class_set_keys (operation_class,
+                                 "name",        "gimp:flood",
+                                 "categories",  "gimp",
+                                 "description", "GIMP Flood operation",
+                                 NULL);
+
+  operation_class->prepare                 = gimp_operation_flood_prepare;
+  operation_class->get_required_for_output = gimp_operation_flood_get_required_for_output;
+  operation_class->get_cached_region       = gimp_operation_flood_get_cached_region;
+
+  filter_class->process                    = gimp_operation_flood_process;
+}
+
+static void
+gimp_operation_flood_init (GimpOperationFlood *self)
+{
+}
+
+static void
+gimp_operation_flood_prepare (GeglOperation *operation)
+{
+  gegl_operation_set_format (operation, "input",  babl_format ("Y float"));
+  gegl_operation_set_format (operation, "output", babl_format ("Y float"));
+}
+
+static GeglRectangle
+gimp_operation_flood_get_required_for_output (GeglOperation       *self,
+                                              const gchar         *input_pad,
+                                              const GeglRectangle *roi)
+{
+  return *gegl_operation_source_get_bounding_box (self, "input");
+}
+
+static GeglRectangle
+gimp_operation_flood_get_cached_region (GeglOperation       *self,
+                                        const GeglRectangle *roi)
+{
+  return *gegl_operation_source_get_bounding_box (self, "input");
+}
+
+static gboolean
+gimp_operation_flood_process_segment (const gfloat *src,
+                                      gfloat       *dest,
+                                      gchar        *changed,
+                                      gint          size)
+{
+  gint     dir;
+  gboolean any_changed = FALSE;
+
+  for (dir = 1; dir >= -1; dir -= 2) /*  for dir in [1, -1]: ...  */
+    {
+      gint   i;
+      gfloat level = 0.0;
+
+      for (i = size; i; i--)
+        {
+          if      (*src  > level) { level    = *src;               }
+          if      (*dest < level) { level    = *dest;              }
+          else if (level < *dest) { *dest    = level;
+                                    *changed = any_changed = TRUE; }
+
+          if (i > 1)
+            {
+              src     += dir;
+              dest    += dir;
+              changed += dir;
+            }
+        }
+    }
+
+  return any_changed;
+}
+
+static gboolean
+gimp_operation_flood_process (GeglOperation       *operation,
+                              GeglBuffer          *input,
+                              GeglBuffer          *output,
+                              const GeglRectangle *roi,
+                              gint                 level)
+{
+  const Babl *input_format  = babl_format ("Y float");
+  const Babl *output_format = babl_format ("Y float");
+  gfloat     *src_buffer, *dest_buffer;
+  gchar      *horz_changed, *vert_changed;
+  gboolean    any_changed;
+  gint        forced;
+  gboolean    horz;
+  GeglColor  *color;
+
+  g_return_val_if_fail (input != output, FALSE);
+
+  src_buffer   = g_new (gfloat, MAX (roi->width, roi->height));
+  dest_buffer  = g_new (gfloat, MAX (roi->width, roi->height));
+  horz_changed = g_new (gchar, roi->width);
+  vert_changed = g_new (gchar, roi->height);
+
+  color = gegl_color_new ("#fff");
+  gegl_buffer_set_color (output, roi, color);
+  g_object_unref (color);
+
+  forced = 2; /*  Force at least one horizontal and one vertical iterations.  */
+  horz = TRUE;
+  do
+    {
+      gint           count, size;
+      GeglRectangle  rect = *roi;
+      gint          *coord;
+      gchar         *prev_changed, *curr_changed;
+      gint           i;
+
+      any_changed = FALSE;
+
+      if (horz)
+        {
+          count        = roi->height;
+          size         = roi->width;
+          rect.height  = 1;
+          coord        = &rect.y;
+          prev_changed = vert_changed;
+          curr_changed = horz_changed;
+        }
+      else
+        {
+          count        = roi->width;
+          size         = roi->height;
+          rect.width   = 1;
+          coord        = &rect.x;
+          prev_changed = horz_changed;
+          curr_changed = vert_changed;
+        }
+
+      for (i = 0; i < count; i++, (*coord)++)
+        {
+          gboolean this_changed;
+
+          if (! (forced || prev_changed[i]))
+            continue;
+          prev_changed[i] = FALSE;
+
+          gegl_buffer_get (input, &rect, 1.0, input_format, src_buffer,
+                           GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
+          gegl_buffer_get (output, &rect, 1.0, output_format, dest_buffer,
+                           GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
+
+          this_changed = gimp_operation_flood_process_segment (src_buffer,
+                                                               dest_buffer,
+                                                               curr_changed,
+                                                               size);
+
+          if (this_changed)
+            {
+              gegl_buffer_set (output, &rect, 0, output_format, dest_buffer,
+                               GEGL_AUTO_ROWSTRIDE);
+
+              any_changed = TRUE;
+            }
+        }
+
+      horz = ! horz;
+      if (forced)
+        forced--;
+    }
+  while (forced || any_changed);
+
+  g_free (src_buffer);
+  g_free (dest_buffer);
+  g_free (horz_changed);
+  g_free (vert_changed);
+
+  return TRUE;
+}
diff --git a/app/operations/gimpoperationflood.h b/app/operations/gimpoperationflood.h
new file mode 100644
index 0000000..60787f2
--- /dev/null
+++ b/app/operations/gimpoperationflood.h
@@ -0,0 +1,53 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimpoperationflood.h
+ * Copyright (C) 2016 Ell
+ *
+ * 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/>.
+ */
+
+#ifndef __GIMP_OPERATION_FLOOD_H__
+#define __GIMP_OPERATION_FLOOD_H__
+
+
+#include <gegl-plugin.h>
+
+
+#define GIMP_TYPE_OPERATION_FLOOD            (gimp_operation_flood_get_type ())
+#define GIMP_OPERATION_FLOOD(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_OPERATION_FLOOD, 
GimpOperationFlood))
+#define GIMP_OPERATION_FLOOD_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass),  GIMP_TYPE_OPERATION_FLOOD, 
GimpOperationFloodClass))
+#define GIMP_IS_OPERATION_FLOOD(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_OPERATION_FLOOD))
+#define GIMP_IS_OPERATION_FLOOD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),  GIMP_TYPE_OPERATION_FLOOD))
+#define GIMP_OPERATION_FLOOD_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj),  GIMP_TYPE_OPERATION_FLOOD, 
GimpOperationFloodClass))
+
+
+typedef struct _GimpOperationFlood      GimpOperationFlood;
+typedef struct _GimpOperationFloodClass GimpOperationFloodClass;
+
+struct _GimpOperationFlood
+{
+  GeglOperationFilter  parent_instance;
+};
+
+struct _GimpOperationFloodClass
+{
+  GeglOperationFilterClass  parent_class;
+};
+
+
+GType   gimp_operation_flood_get_type (void) G_GNUC_CONST;
+
+
+#endif /* __GIMP_OPERATION_FLOOD_H__ */


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