[gimp] app: add GimpPickable::get_pixel_average() vfunc



commit b98a04aadc91ada5f6b460023d41f2b84ac4da73
Author: Ell <ell_se yahoo com>
Date:   Fri May 18 14:54:15 2018 -0400

    app: add GimpPickable::get_pixel_average() vfunc
    
    ... which calculates the average color of the pickable over a given
    area.  Use this function in gimp_pickable_pick_color() when
    sample_average is TRUE, and provide a default implementation which
    calculates the average color using GimpPickable::get_pixel_at(), as
    gimp_pickable_pick_color() did before.
    
    The default implementation is rather slow; classes that implement
    the GimpPickable interface can provide a faster specialized version
    (see the next commit).

 app/core/gimppickable.c |  116 +++++++++++++++++++++++++++++++++++----------
 app/core/gimppickable.h |  120 +++++++++++++++++++++++++----------------------
 2 files changed, 155 insertions(+), 81 deletions(-)
---
diff --git a/app/core/gimppickable.c b/app/core/gimppickable.c
index ffe91b7..7f568b0 100644
--- a/app/core/gimppickable.c
+++ b/app/core/gimppickable.c
@@ -33,6 +33,7 @@
 #include <gdk-pixbuf/gdk-pixbuf.h>
 
 #include "libgimpcolor/gimpcolor.h"
+#include "libgimpmath/gimpmath.h"
 
 #include "core-types.h"
 
@@ -41,7 +42,17 @@
 #include "gimppickable.h"
 
 
-static void   gimp_pickable_interface_base_init (GimpPickableInterface *iface);
+/*  local function prototypes  */
+
+static void   gimp_pickable_interface_base_init    (GimpPickableInterface *iface);
+
+static void   gimp_pickable_real_get_pixel_average (GimpPickable          *pickable,
+                                                    const GeglRectangle   *rect,
+                                                    const Babl            *format,
+                                                    gpointer               pixel);
+
+
+/*  private functions  */
 
 
 GType
@@ -84,8 +95,54 @@ gimp_pickable_interface_base_init (GimpPickableInterface *iface)
 
       initialized = TRUE;
     }
+
+  if (! iface->get_pixel_average)
+    iface->get_pixel_average = gimp_pickable_real_get_pixel_average;
+}
+
+static void
+gimp_pickable_real_get_pixel_average (GimpPickable        *pickable,
+                                      const GeglRectangle *rect,
+                                      const Babl          *format,
+                                      gpointer             pixel)
+{
+  const Babl *average_format = babl_format ("RaGaBaA double");
+  gdouble     average[4]     = {};
+  gint        n              = 0;
+  gint        x;
+  gint        y;
+  gint        c;
+
+  for (y = rect->y; y < rect->y + rect->height; y++)
+    {
+      for (x = rect->x; x < rect->x + rect->width; x++)
+        {
+          gdouble sample[4];
+
+          if (gimp_pickable_get_pixel_at (pickable,
+                                          x, y, average_format, sample))
+            {
+              for (c = 0; c < 4; c++)
+                average[c] += sample[c];
+
+              n++;
+            }
+        }
+    }
+
+  if (n > 0)
+    {
+      for (c = 0; c < 4; c++)
+        average[c] /= n;
+    }
+
+  babl_process (babl_fish (average_format, format), average, pixel, 1);
 }
 
+
+/*  public functions  */
+
+
 void
 gimp_pickable_flush (GimpPickable *pickable)
 {
@@ -182,6 +239,29 @@ gimp_pickable_get_pixel_at (GimpPickable *pickable,
   return FALSE;
 }
 
+void
+gimp_pickable_get_pixel_average (GimpPickable        *pickable,
+                                 const GeglRectangle *rect,
+                                 const Babl          *format,
+                                 gpointer             pixel)
+{
+  GimpPickableInterface *pickable_iface;
+
+  g_return_if_fail (GIMP_IS_PICKABLE (pickable));
+  g_return_if_fail (rect != NULL);
+  g_return_if_fail (pixel != NULL);
+
+  if (! format)
+    format = gimp_pickable_get_format (pickable);
+
+  pickable_iface = GIMP_PICKABLE_GET_INTERFACE (pickable);
+
+  if (pickable_iface->get_pixel_average)
+    pickable_iface->get_pixel_average (pickable, rect, format, pixel);
+  else
+    memset (pixel, 0, babl_format_get_bytes_per_pixel (format));
+}
+
 gboolean
 gimp_pickable_get_color_at (GimpPickable *pickable,
                             gint          x,
@@ -300,45 +380,31 @@ gimp_pickable_pick_color (GimpPickable *pickable,
   gdouble     sample[4];
 
   g_return_val_if_fail (GIMP_IS_PICKABLE (pickable), FALSE);
+  g_return_val_if_fail (color != NULL, FALSE);
 
   format = gimp_pickable_get_format (pickable);
 
   if (! gimp_pickable_get_pixel_at (pickable, x, y, format, sample))
     return FALSE;
 
-  gimp_pickable_pixel_to_srgb (pickable, format, sample, color);
-
   if (pixel)
     memcpy (pixel, sample, babl_format_get_bytes_per_pixel (format));
 
   if (sample_average)
     {
-      gint    count        = 0;
-      gdouble color_avg[4] = { 0.0, 0.0, 0.0, 0.0 };
-      gint    radius       = (gint) average_radius;
-      gint    i, j;
+      gint radius = floor (average_radius);
 
       format = babl_format ("RaGaBaA double");
 
-      for (i = x - radius; i <= x + radius; i++)
-        for (j = y - radius; j <= y + radius; j++)
-          if (gimp_pickable_get_pixel_at (pickable, i, j, format, sample))
-            {
-              count++;
-
-              color_avg[RED]   += sample[RED];
-              color_avg[GREEN] += sample[GREEN];
-              color_avg[BLUE]  += sample[BLUE];
-              color_avg[ALPHA] += sample[ALPHA];
-            }
-
-      sample[RED]   = color_avg[RED]   / count;
-      sample[GREEN] = color_avg[GREEN] / count;
-      sample[BLUE]  = color_avg[BLUE]  / count;
-      sample[ALPHA] = color_avg[ALPHA] / count;
-
-      gimp_pickable_pixel_to_srgb (pickable, format, sample, color);
+      gimp_pickable_get_pixel_average (pickable,
+                                       GEGL_RECTANGLE (x - radius,
+                                                       y - radius,
+                                                       2 * radius + 1,
+                                                       2 * radius + 1),
+                                       format, sample);
     }
 
+  gimp_pickable_pixel_to_srgb (pickable, format, sample, color);
+
   return TRUE;
 }
diff --git a/app/core/gimppickable.h b/app/core/gimppickable.h
index 5e52aa5..f59c223 100644
--- a/app/core/gimppickable.h
+++ b/app/core/gimppickable.h
@@ -35,68 +35,76 @@ struct _GimpPickableInterface
   GTypeInterface base_iface;
 
   /*  virtual functions  */
-  void            (* flush)                 (GimpPickable  *pickable);
-  GimpImage     * (* get_image)             (GimpPickable  *pickable);
-  const Babl    * (* get_format)            (GimpPickable  *pickable);
-  const Babl    * (* get_format_with_alpha) (GimpPickable  *pickable);
-  GeglBuffer    * (* get_buffer)            (GimpPickable  *pickable);
-  gboolean        (* get_pixel_at)          (GimpPickable  *pickable,
-                                             gint           x,
-                                             gint           y,
-                                             const Babl    *format,
-                                             gpointer       pixel);
-  gdouble         (* get_opacity_at)        (GimpPickable  *pickable,
-                                             gint           x,
-                                             gint           y);
-  void            (* pixel_to_srgb)         (GimpPickable  *pickable,
-                                             const Babl    *format,
-                                             gpointer       pixel,
-                                             GimpRGB       *color);
-  void            (* srgb_to_pixel)         (GimpPickable  *pickable,
-                                             const GimpRGB *color,
-                                             const Babl    *format,
-                                             gpointer       pixel);
+  void            (* flush)                 (GimpPickable        *pickable);
+  GimpImage     * (* get_image)             (GimpPickable        *pickable);
+  const Babl    * (* get_format)            (GimpPickable        *pickable);
+  const Babl    * (* get_format_with_alpha) (GimpPickable        *pickable);
+  GeglBuffer    * (* get_buffer)            (GimpPickable        *pickable);
+  gboolean        (* get_pixel_at)          (GimpPickable        *pickable,
+                                             gint                 x,
+                                             gint                 y,
+                                             const Babl          *format,
+                                             gpointer             pixel);
+  gdouble         (* get_opacity_at)        (GimpPickable        *pickable,
+                                             gint                 x,
+                                             gint                 y);
+  void            (* get_pixel_average)     (GimpPickable        *pickable,
+                                             const GeglRectangle *rect,
+                                             const Babl          *format,
+                                             gpointer             pixel);
+  void            (* pixel_to_srgb)         (GimpPickable        *pickable,
+                                             const Babl          *format,
+                                             gpointer             pixel,
+                                             GimpRGB             *color);
+  void            (* srgb_to_pixel)         (GimpPickable        *pickable,
+                                             const GimpRGB       *color,
+                                             const Babl          *format,
+                                             gpointer             pixel);
 };
 
 
 GType           gimp_pickable_interface_get_type    (void) G_GNUC_CONST;
 
-void            gimp_pickable_flush                 (GimpPickable  *pickable);
-GimpImage     * gimp_pickable_get_image             (GimpPickable  *pickable);
-const Babl    * gimp_pickable_get_format            (GimpPickable  *pickable);
-const Babl    * gimp_pickable_get_format_with_alpha (GimpPickable  *pickable);
-GeglBuffer    * gimp_pickable_get_buffer            (GimpPickable  *pickable);
-gboolean        gimp_pickable_get_pixel_at          (GimpPickable  *pickable,
-                                                     gint           x,
-                                                     gint           y,
-                                                     const Babl    *format,
-                                                     gpointer       pixel);
-gboolean        gimp_pickable_get_color_at          (GimpPickable  *pickable,
-                                                     gint           x,
-                                                     gint           y,
-                                                     GimpRGB       *color);
-gdouble         gimp_pickable_get_opacity_at        (GimpPickable  *pickable,
-                                                     gint           x,
-                                                     gint           y);
-void            gimp_pickable_pixel_to_srgb         (GimpPickable  *pickable,
-                                                     const Babl    *format,
-                                                     gpointer       pixel,
-                                                     GimpRGB       *color);
-void            gimp_pickable_srgb_to_pixel         (GimpPickable  *pickable,
-                                                     const GimpRGB *color,
-                                                     const Babl    *format,
-                                                     gpointer       pixel);
-void            gimp_pickable_srgb_to_image_color   (GimpPickable  *pickable,
-                                                     const GimpRGB *color,
-                                                     GimpRGB       *image_color);
+void            gimp_pickable_flush                 (GimpPickable        *pickable);
+GimpImage     * gimp_pickable_get_image             (GimpPickable        *pickable);
+const Babl    * gimp_pickable_get_format            (GimpPickable        *pickable);
+const Babl    * gimp_pickable_get_format_with_alpha (GimpPickable        *pickable);
+GeglBuffer    * gimp_pickable_get_buffer            (GimpPickable        *pickable);
+gboolean        gimp_pickable_get_pixel_at          (GimpPickable        *pickable,
+                                                     gint                 x,
+                                                     gint                 y,
+                                                     const Babl          *format,
+                                                     gpointer             pixel);
+gboolean        gimp_pickable_get_color_at          (GimpPickable        *pickable,
+                                                     gint                 x,
+                                                     gint                 y,
+                                                     GimpRGB             *color);
+gdouble         gimp_pickable_get_opacity_at        (GimpPickable        *pickable,
+                                                     gint                 x,
+                                                     gint                 y);
+void            gimp_pickable_get_pixel_average     (GimpPickable        *pickable,
+                                                     const GeglRectangle *rect,
+                                                     const Babl          *format,
+                                                     gpointer             pixel);
+void            gimp_pickable_pixel_to_srgb         (GimpPickable        *pickable,
+                                                     const Babl          *format,
+                                                     gpointer             pixel,
+                                                     GimpRGB             *color);
+void            gimp_pickable_srgb_to_pixel         (GimpPickable        *pickable,
+                                                     const GimpRGB       *color,
+                                                     const Babl          *format,
+                                                     gpointer             pixel);
+void            gimp_pickable_srgb_to_image_color   (GimpPickable        *pickable,
+                                                     const GimpRGB       *color,
+                                                     GimpRGB             *image_color);
 
-gboolean        gimp_pickable_pick_color            (GimpPickable  *pickable,
-                                                     gint           x,
-                                                     gint           y,
-                                                     gboolean       sample_average,
-                                                     gdouble        average_radius,
-                                                     gpointer       pixel,
-                                                     GimpRGB       *color);
+gboolean        gimp_pickable_pick_color            (GimpPickable        *pickable,
+                                                     gint                 x,
+                                                     gint                 y,
+                                                     gboolean             sample_average,
+                                                     gdouble              average_radius,
+                                                     gpointer             pixel,
+                                                     GimpRGB             *color);
 
 
 #endif  /* __GIMP_PICKABLE_H__ */


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