[gimp] app: fix format selection in gimpimage-contiguous-region



commit dd1f731cc9ae518abd7b66df825e3c1a0da8de5a
Author: Michael Natterer <mitch gimp org>
Date:   Mon Apr 8 03:14:06 2013 +0200

    app: fix format selection in gimpimage-contiguous-region
    
    and also re-enable selecting by H, S, V. Doing that sometimes runs
    into an infinite loop though, which I don't think is this code's
    fault...

 app/core/gimpimage-contiguous-region.c |  174 ++++++++++++++++++--------------
 1 files changed, 99 insertions(+), 75 deletions(-)
---
diff --git a/app/core/gimpimage-contiguous-region.c b/app/core/gimpimage-contiguous-region.c
index 64edbbc..554a2b8 100644
--- a/app/core/gimpimage-contiguous-region.c
+++ b/app/core/gimpimage-contiguous-region.c
@@ -38,6 +38,10 @@
 
 /*  local function prototypes  */
 
+static const Babl * choose_format         (GeglBuffer          *buffer,
+                                           GimpSelectCriterion  select_criterion,
+                                           gint                *n_components,
+                                           gboolean            *has_alpha);
 static gfloat   pixel_difference          (const gfloat        *col1,
                                            const gfloat        *col2,
                                            gboolean             antialias,
@@ -64,6 +68,8 @@ static gboolean find_contiguous_segment   (const gfloat        *col,
 static void find_contiguous_region_helper (GeglBuffer          *src_buffer,
                                            GeglBuffer          *mask_buffer,
                                            const Babl          *format,
+                                           gint                 n_components,
+                                           gboolean             has_alpha,
                                            gboolean             select_transparent,
                                            GimpSelectCriterion  select_criterion,
                                            gboolean             antialias,
@@ -90,7 +96,9 @@ gimp_image_contiguous_region_by_seed (GimpImage           *image,
   GeglBuffer   *src_buffer;
   GimpChannel  *mask;
   GeglBuffer   *mask_buffer;
-  const Babl   *src_format;
+  const Babl   *format;
+  gint          n_components;
+  gboolean      has_alpha;
   gfloat        start_col[MAX_CHANNELS];
 
   g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL);
@@ -103,31 +111,18 @@ gimp_image_contiguous_region_by_seed (GimpImage           *image,
 
   gimp_pickable_flush (pickable);
 
-  src_format = gimp_pickable_get_format (pickable);
-  if (babl_format_is_palette (src_format))
-    src_format = babl_format ("RGBA float");
-  else
-    src_format = gimp_babl_format (gimp_babl_format_get_base_type (src_format),
-                                   GIMP_PRECISION_FLOAT,
-                                   babl_format_has_alpha (src_format));
-
   src_buffer = gimp_pickable_get_buffer (pickable);
 
-  mask = gimp_channel_new_mask (image,
-                                gegl_buffer_get_width  (src_buffer),
-                                gegl_buffer_get_height (src_buffer));
-
-  mask_buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (mask));
+  format = choose_format (src_buffer, select_criterion,
+                          &n_components, &has_alpha);
 
-  gegl_buffer_sample (src_buffer, x, y, NULL, start_col, src_format,
+  gegl_buffer_sample (src_buffer, x, y, NULL, start_col, format,
                       GEGL_SAMPLER_NEAREST, GEGL_ABYSS_NONE);
 
-  if (babl_format_has_alpha (src_format))
+  if (has_alpha)
     {
       if (select_transparent)
         {
-          gint n_components = babl_format_get_n_components (src_format);
-
           /*  don't select transparent regions if the start pixel isn't
            *  fully transparent
            */
@@ -140,7 +135,14 @@ gimp_image_contiguous_region_by_seed (GimpImage           *image,
       select_transparent = FALSE;
     }
 
-  find_contiguous_region_helper (src_buffer, mask_buffer, src_format,
+  mask = gimp_channel_new_mask (image,
+                                gegl_buffer_get_width  (src_buffer),
+                                gegl_buffer_get_height (src_buffer));
+
+  mask_buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (mask));
+
+  find_contiguous_region_helper (src_buffer, mask_buffer,
+                                 format, n_components, has_alpha,
                                  select_transparent, select_criterion,
                                  antialias, threshold,
                                  x, y, start_col);
@@ -155,7 +157,7 @@ gimp_image_contiguous_region_by_color (GimpImage            *image,
                                        gboolean              antialias,
                                        gfloat                threshold,
                                        gboolean              select_transparent,
-                                       GimpSelectCriterion  select_criterion,
+                                       GimpSelectCriterion   select_criterion,
                                        const GimpRGB        *color)
 {
   /*  Scan over the image's active layer, finding pixels within the
@@ -169,16 +171,15 @@ gimp_image_contiguous_region_by_color (GimpImage            *image,
   GimpChannel        *mask;
   GeglBuffer         *src_buffer;
   GeglBuffer         *mask_buffer;
-  gint                width, height;
+  const Babl         *format;
+  gint                n_components;
   gboolean            has_alpha;
-  gfloat              col[MAX_CHANNELS];
+  gfloat              start_col[MAX_CHANNELS];
 
   g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL);
   g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL);
   g_return_val_if_fail (color != NULL, NULL);
 
-  gimp_rgba_get_pixel (color, babl_format ("RGBA float"), col);
-
   if (sample_merged)
     pickable = GIMP_PICKABLE (gimp_image_get_projection (image));
   else
@@ -186,15 +187,12 @@ gimp_image_contiguous_region_by_color (GimpImage            *image,
 
   gimp_pickable_flush (pickable);
 
-  has_alpha = babl_format_has_alpha (gimp_pickable_get_format (pickable));
-
   src_buffer = gimp_pickable_get_buffer (pickable);
-  width  = gegl_buffer_get_width (src_buffer);
-  height = gegl_buffer_get_height (src_buffer);
 
-  iter = gegl_buffer_iterator_new (src_buffer,
-                                   NULL, 0, babl_format ("RGBA float"),
-                                   GEGL_BUFFER_READ, GEGL_ABYSS_NONE);
+  format = choose_format (src_buffer, select_criterion,
+                          &n_components, &has_alpha);
+
+  gimp_rgba_get_pixel (color, format, start_col);
 
   if (has_alpha)
     {
@@ -202,7 +200,7 @@ gimp_image_contiguous_region_by_color (GimpImage            *image,
         {
           /*  don't select transparancy if "color" isn't fully transparent
            */
-          if (col[3] > 0.0)
+          if (start_col[n_components - 1] > 0.0)
             select_transparent = FALSE;
         }
     }
@@ -211,10 +209,16 @@ gimp_image_contiguous_region_by_color (GimpImage            *image,
       select_transparent = FALSE;
     }
 
-  mask = gimp_channel_new_mask (image, width, height);
+  mask = gimp_channel_new_mask (image,
+                                gegl_buffer_get_width  (src_buffer),
+                                gegl_buffer_get_height (src_buffer));
 
   mask_buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (mask));
 
+  iter = gegl_buffer_iterator_new (src_buffer,
+                                   NULL, 0, format,
+                                   GEGL_BUFFER_READ, GEGL_ABYSS_NONE);
+
   gegl_buffer_iterator_add (iter, mask_buffer,
                             NULL, 0, babl_format ("Y float"),
                             GEGL_BUFFER_WRITE, GEGL_ABYSS_NONE);
@@ -227,10 +231,10 @@ gimp_image_contiguous_region_by_color (GimpImage            *image,
       while (iter->length--)
         {
           /*  Find how closely the colors match  */
-          *dest = pixel_difference (col, src,
+          *dest = pixel_difference (start_col, src,
                                     antialias,
                                     threshold,
-                                    has_alpha ? 4 : 3,
+                                    n_components,
                                     has_alpha,
                                     select_transparent,
                                     select_criterion);
@@ -246,6 +250,49 @@ gimp_image_contiguous_region_by_color (GimpImage            *image,
 
 /*  private functions  */
 
+static const Babl *
+choose_format (GeglBuffer          *buffer,
+               GimpSelectCriterion  select_criterion,
+               gint                *n_components,
+               gboolean            *has_alpha)
+{
+  const Babl *format = gegl_buffer_get_format (buffer);
+
+  *has_alpha = babl_format_has_alpha (format);
+
+  switch (select_criterion)
+    {
+    case GIMP_SELECT_CRITERION_COMPOSITE:
+      if (babl_format_is_palette (format))
+        format = babl_format ("RGBA float");
+      else
+        format = gimp_babl_format (gimp_babl_format_get_base_type (format),
+                                   GIMP_PRECISION_FLOAT,
+                                   *has_alpha);
+      break;
+
+    case GIMP_SELECT_CRITERION_R:
+    case GIMP_SELECT_CRITERION_G:
+    case GIMP_SELECT_CRITERION_B:
+      format = babl_format ("RGBA float");
+      break;
+
+    case GIMP_SELECT_CRITERION_H:
+    case GIMP_SELECT_CRITERION_S:
+    case GIMP_SELECT_CRITERION_V:
+      format = babl_format ("HSVA float");
+      break;
+
+    default:
+      g_return_val_if_reached (NULL);
+      break;
+    }
+
+  *n_components = babl_format_get_n_components (format);
+
+  return format;
+}
+
 static gfloat
 pixel_difference (const gfloat        *col1,
                   const gfloat        *col2,
@@ -268,8 +315,8 @@ pixel_difference (const gfloat        *col1,
     }
   else
     {
-      gfloat  diff;
-      gint    b;
+      gfloat diff;
+      gint   b;
 
       if (has_alpha)
         n_components--;
@@ -297,21 +344,13 @@ pixel_difference (const gfloat        *col1,
           max = fabs (col1[2] - col2[2]);
           break;
 
-#if 0
         case GIMP_SELECT_CRITERION_H:
-          av0 = (gint) col1[0];
-          av1 = (gint) col1[1];
-          av2 = (gint) col1[2];
-          bv0 = (gint) col2[0];
-          bv1 = (gint) col2[1];
-          bv2 = (gint) col2[2];
-          gimp_rgb_to_hsv_int (&av0, &av1, &av2);
-          gimp_rgb_to_hsv_int (&bv0, &bv1, &bv2);
-          /* wrap around candidates for the actual distance */
           {
-            gint dist1 = abs (av0 - bv0);
-            gint dist2 = abs (av0 - 360 - bv0);
-            gint dist3 = abs (av0 - bv0 + 360);
+            /* wrap around candidates for the actual distance */
+            gfloat dist1 = fabs (col1[0] - col2[0]);
+            gfloat dist2 = fabs (col1[0] - 1.0 - col2[0]);
+            gfloat dist3 = fabs (col1[0] - col2[0] + 1.0);
+
             max = MIN (dist1, dist2);
             if (max > dist3)
               max = dist3;
@@ -319,29 +358,12 @@ pixel_difference (const gfloat        *col1,
           break;
 
         case GIMP_SELECT_CRITERION_S:
-          av0 = (gint) col1[0];
-          av1 = (gint) col1[1];
-          av2 = (gint) col1[2];
-          bv0 = (gint) col2[0];
-          bv1 = (gint) col2[1];
-          bv2 = (gint) col2[2];
-          gimp_rgb_to_hsv_int (&av0, &av1, &av2);
-          gimp_rgb_to_hsv_int (&bv0, &bv1, &bv2);
-          max = abs (av1 - bv1);
+          max = fabs (col1[1] - col2[1]);
           break;
 
         case GIMP_SELECT_CRITERION_V:
-          av0 = (gint) col1[0];
-          av1 = (gint) col1[1];
-          av2 = (gint) col1[2];
-          bv0 = (gint) col2[0];
-          bv1 = (gint) col2[1];
-          bv2 = (gint) col2[2];
-          gimp_rgb_to_hsv_int (&av0, &av1, &av2);
-          gimp_rgb_to_hsv_int (&bv0, &bv1, &bv2);
-          max = abs (av2 - bv2);
+          max = fabs (col1[2] - col2[2]);
           break;
-#endif
         }
     }
 
@@ -369,7 +391,7 @@ static gboolean
 find_contiguous_segment (const gfloat        *col,
                          GeglBuffer          *src_buffer,
                          GeglBuffer          *mask_buffer,
-                         const Babl          *src_format,
+                         const Babl          *format,
                          gint                 n_components,
                          gboolean             has_alpha,
                          gint                 width,
@@ -386,7 +408,7 @@ find_contiguous_segment (const gfloat        *col,
   gfloat mask_row[width];
   gfloat diff;
 
-  gegl_buffer_sample (src_buffer, initial_x, initial_y, NULL, s, src_format,
+  gegl_buffer_sample (src_buffer, initial_x, initial_y, NULL, s, format,
                       GEGL_SAMPLER_NEAREST, GEGL_ABYSS_NONE);
 
   diff = pixel_difference (col, s, antialias, threshold,
@@ -403,7 +425,7 @@ find_contiguous_segment (const gfloat        *col,
 
   while (*start >= 0 && diff)
     {
-      gegl_buffer_sample (src_buffer, *start, initial_y, NULL, s, src_format,
+      gegl_buffer_sample (src_buffer, *start, initial_y, NULL, s, format,
                           GEGL_SAMPLER_NEAREST, GEGL_ABYSS_NONE);
 
       diff = pixel_difference (col, s, antialias, threshold,
@@ -421,7 +443,7 @@ find_contiguous_segment (const gfloat        *col,
 
   while (*end < width && diff)
     {
-      gegl_buffer_sample (src_buffer, *end, initial_y, NULL, s, src_format,
+      gegl_buffer_sample (src_buffer, *end, initial_y, NULL, s, format,
                           GEGL_SAMPLER_NEAREST, GEGL_ABYSS_NONE);
 
       diff = pixel_difference (col, s, antialias, threshold,
@@ -446,6 +468,8 @@ static void
 find_contiguous_region_helper (GeglBuffer          *src_buffer,
                                GeglBuffer          *mask_buffer,
                                const Babl          *format,
+                               gint                 n_components,
+                               gboolean             has_alpha,
                                gboolean             select_transparent,
                                GimpSelectCriterion  select_criterion,
                                gboolean             antialias,
@@ -487,8 +511,8 @@ find_contiguous_region_helper (GeglBuffer          *src_buffer,
 
           if (! find_contiguous_segment (col, src_buffer, mask_buffer,
                                          format,
-                                         babl_format_get_n_components (format),
-                                         babl_format_has_alpha (format),
+                                         n_components,
+                                         has_alpha,
                                          gegl_buffer_get_width (src_buffer),
                                          select_transparent, select_criterion,
                                          antialias, threshold, x, y,


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