[gimp] app: allow setting line art spline and segment length to 0.



commit 0a2d0661689ef48a21fbaa2e0713a5a86a43e968
Author: Jehan <jehan girinstud io>
Date:   Mon Dec 17 15:38:15 2018 +0100

    app: allow setting line art spline and segment length to 0.
    
    Practically it means that the algorithm won't close line art anymore
    with both settings at 0. This can nevertheless still be a very useful
    tool when you have a drawing style with well-closed lines. In such a
    case, you will still profit from the color flooding under the line art
    part of the algorithm.
    Moreover with such well-closed zones from start, you don't get the
    over-segmentation anymore and the threaded processing will be faster
    obviously.

 app/core/gimplineart.c            | 310 ++++++++++++++++++++------------------
 app/tools/gimpbucketfilloptions.c |   4 +-
 2 files changed, 165 insertions(+), 149 deletions(-)
---
diff --git a/app/core/gimplineart.c b/app/core/gimplineart.c
index ae0027ee6e..a2ca6f6c7f 100644
--- a/app/core/gimplineart.c
+++ b/app/core/gimplineart.c
@@ -308,14 +308,14 @@ gimp_line_art_class_init (GimpLineArtClass *klass)
                                    g_param_spec_int ("spline-max-length",
                                                      _("Maximum curved closing length"),
                                                      _("Maximum curved length (in pixels) to close the line 
art"),
-                                                     1, 1000, 60,
+                                                     0, 1000, 60,
                                                      G_PARAM_CONSTRUCT | GIMP_PARAM_READWRITE));
 
   g_object_class_install_property (object_class, PROP_SEGMENT_MAX_LEN,
                                    g_param_spec_int ("segment-max-length",
                                                      _("Maximum straight closing length"),
                                                      _("Maximum straight length (in pixels) to close the 
line art"),
-                                                     1, 1000, 20,
+                                                     0, 1000, 20,
                                                      G_PARAM_CONSTRUCT | GIMP_PARAM_READWRITE));
 }
 
@@ -830,29 +830,14 @@ gimp_line_art_close (GeglBuffer  *buffer,
                      gfloat     **closed_distmap)
 {
   const Babl         *gray_format;
-  gfloat             *normals;
-  gfloat             *curvatures;
-  gfloat             *smoothed_curvatures;
-  gfloat             *radii;
   GeglBufferIterator *gi;
   GeglBuffer         *closed;
   GeglBuffer         *strokes;
-  GHashTable         *visited;
-  GArray             *keypoints;
-  Pixel              *point;
-  GList              *candidates;
-  SplineCandidate    *candidate;
   guchar              max_value = 0;
-  gfloat              threshold;
-  gfloat              clamped_threshold;
   gint                width  = gegl_buffer_get_width (buffer);
   gint                height = gegl_buffer_get_height (buffer);
   gint                i;
 
-  normals             = g_new0 (gfloat, width * height * 2);
-  curvatures          = g_new0 (gfloat, width * height);
-  smoothed_curvatures = g_new0 (gfloat, width * height);
-
   if (select_transparent)
     /* Keep alpha channel as gray levels */
     gray_format = babl_format ("A u8");
@@ -910,150 +895,189 @@ gimp_line_art_close (GeglBuffer  *buffer,
   /* Denoise (remove small connected components) */
   gimp_lineart_denoise (strokes, minimal_lineart_area);
 
-  /* Estimate normals & curvature */
-  gimp_lineart_compute_normals_curvatures (strokes, normals, curvatures,
-                                           smoothed_curvatures,
-                                           normal_estimate_mask_size);
+  closed = strokes;
 
-  radii = gimp_lineart_estimate_strokes_radii (strokes);
-  threshold = 1.0f - end_point_rate;
-  clamped_threshold = MAX (0.25f, threshold);
-  for (i = 0; i < width; i++)
+  if (spline_max_length > 0 || segment_max_length > 0)
     {
-      gint j;
-      for (j = 0; j < height; j++)
+      GArray     *keypoints;
+      GHashTable *visited;
+      gfloat     *radii;
+      gfloat     *normals;
+      gfloat     *curvatures;
+      gfloat     *smoothed_curvatures;
+      gfloat      threshold;
+      gfloat      clamped_threshold;
+
+      normals             = g_new0 (gfloat, width * height * 2);
+      curvatures          = g_new0 (gfloat, width * height);
+      smoothed_curvatures = g_new0 (gfloat, width * height);
+
+      /* Estimate normals & curvature */
+      gimp_lineart_compute_normals_curvatures (strokes, normals, curvatures,
+                                               smoothed_curvatures,
+                                               normal_estimate_mask_size);
+
+      radii = gimp_lineart_estimate_strokes_radii (strokes);
+      threshold = 1.0f - end_point_rate;
+      clamped_threshold = MAX (0.25f, threshold);
+      for (i = 0; i < width; i++)
         {
-          if (smoothed_curvatures[i + j * width] >= (threshold / MAX (1.0f, radii[i + j * width])) ||
-              curvatures[i + j * width] >= clamped_threshold)
-            curvatures[i + j * width] = 1.0;
-          else
-            curvatures[i + j * width] = 0.0;
+          gint j;
+          for (j = 0; j < height; j++)
+            {
+              if (smoothed_curvatures[i + j * width] >= (threshold / MAX (1.0f, radii[i + j * width])) ||
+                  curvatures[i + j * width] >= clamped_threshold)
+                curvatures[i + j * width] = 1.0;
+              else
+                curvatures[i + j * width] = 0.0;
+            }
         }
-    }
-  g_free (radii);
-
-  keypoints = gimp_lineart_curvature_extremums (curvatures, smoothed_curvatures,
-                                                width, height);
-  candidates = gimp_lineart_find_spline_candidates (keypoints, normals, width,
-                                                    spline_max_length,
-                                                    spline_max_angle);
-  closed = gegl_buffer_dup (strokes);
-
-  /* Draw splines */
-  visited = g_hash_table_new_full ((GHashFunc) visited_hash_fun,
-                                   (GEqualFunc) visited_equal_fun,
-                                   (GDestroyNotify) g_free, NULL);
-  while (candidates)
-    {
-      Pixel    *p1 = g_new (Pixel, 1);
-      Pixel    *p2 = g_new (Pixel, 1);
-      gboolean  inserted = FALSE;
-
-      candidate = (SplineCandidate *) candidates->data;
-      p1->x = candidate->p1.x;
-      p1->y = candidate->p1.y;
-      p2->x = candidate->p2.x;
-      p2->y = candidate->p2.y;
-
-      g_free (candidate);
-      candidates = g_list_delete_link (candidates, candidates);
-
-      if ((! g_hash_table_contains (visited, p1) ||
-           GPOINTER_TO_INT (g_hash_table_lookup (visited, p1)) < end_point_connectivity) &&
-          (! g_hash_table_contains (visited, p2) ||
-           GPOINTER_TO_INT (g_hash_table_lookup (visited, p2)) < end_point_connectivity))
+      g_free (radii);
+
+      keypoints = gimp_lineart_curvature_extremums (curvatures, smoothed_curvatures,
+                                                    width, height);
+      visited = g_hash_table_new_full ((GHashFunc) visited_hash_fun,
+                                       (GEqualFunc) visited_equal_fun,
+                                       (GDestroyNotify) g_free, NULL);
+
+      if (spline_max_length > 0)
         {
-          GArray      *discrete_curve;
-          GimpVector2  vect1 = pair2normal (*p1, normals, width);
-          GimpVector2  vect2 = pair2normal (*p2, normals, width);
-          gfloat       distance = gimp_vector2_length_val (gimp_vector2_sub_val (*p1, *p2));
-          gint         transitions;
-
-          gimp_vector2_mul (&vect1, distance);
-          gimp_vector2_mul (&vect1, spline_roundness);
-          gimp_vector2_mul (&vect2, distance);
-          gimp_vector2_mul (&vect2, spline_roundness);
-
-          discrete_curve = gimp_lineart_discrete_spline (*p1, vect1, *p2, vect2);
-
-          transitions = allow_self_intersections ?
-                          gimp_number_of_transitions (discrete_curve, strokes) :
-                          gimp_number_of_transitions (discrete_curve, closed);
-
-          if (transitions == 2 &&
-              ! gimp_lineart_curve_creates_region (closed, discrete_curve,
-                                                   created_regions_significant_area,
-                                                   created_regions_minimum_area - 1))
+          GList           *candidates;
+          SplineCandidate *candidate;
+
+          candidates = gimp_lineart_find_spline_candidates (keypoints, normals, width,
+                                                            spline_max_length,
+                                                            spline_max_angle);
+          closed = gegl_buffer_dup (strokes);
+
+          /* Draw splines */
+          while (candidates)
             {
-              for (i = 0; i < discrete_curve->len; i++)
+              Pixel    *p1 = g_new (Pixel, 1);
+              Pixel    *p2 = g_new (Pixel, 1);
+              gboolean  inserted = FALSE;
+
+              candidate = (SplineCandidate *) candidates->data;
+              p1->x = candidate->p1.x;
+              p1->y = candidate->p1.y;
+              p2->x = candidate->p2.x;
+              p2->y = candidate->p2.y;
+
+              g_free (candidate);
+              candidates = g_list_delete_link (candidates, candidates);
+
+              if ((! g_hash_table_contains (visited, p1) ||
+                   GPOINTER_TO_INT (g_hash_table_lookup (visited, p1)) < end_point_connectivity) &&
+                  (! g_hash_table_contains (visited, p2) ||
+                   GPOINTER_TO_INT (g_hash_table_lookup (visited, p2)) < end_point_connectivity))
                 {
-                  Pixel p = g_array_index (discrete_curve, Pixel, i);
-
-                  if (p.x >= 0 && p.x < gegl_buffer_get_width (closed) &&
-                      p.y >= 0 && p.y < gegl_buffer_get_height (closed))
+                  GArray      *discrete_curve;
+                  GimpVector2  vect1 = pair2normal (*p1, normals, width);
+                  GimpVector2  vect2 = pair2normal (*p2, normals, width);
+                  gfloat       distance = gimp_vector2_length_val (gimp_vector2_sub_val (*p1, *p2));
+                  gint         transitions;
+
+                  gimp_vector2_mul (&vect1, distance);
+                  gimp_vector2_mul (&vect1, spline_roundness);
+                  gimp_vector2_mul (&vect2, distance);
+                  gimp_vector2_mul (&vect2, spline_roundness);
+
+                  discrete_curve = gimp_lineart_discrete_spline (*p1, vect1, *p2, vect2);
+
+                  transitions = allow_self_intersections ?
+                    gimp_number_of_transitions (discrete_curve, strokes) :
+                    gimp_number_of_transitions (discrete_curve, closed);
+
+                  if (transitions == 2 &&
+                      ! gimp_lineart_curve_creates_region (closed, discrete_curve,
+                                                           created_regions_significant_area,
+                                                           created_regions_minimum_area - 1))
                     {
-                      guchar val = 1;
+                      for (i = 0; i < discrete_curve->len; i++)
+                        {
+                          Pixel p = g_array_index (discrete_curve, Pixel, i);
+
+                          if (p.x >= 0 && p.x < gegl_buffer_get_width (closed) &&
+                              p.y >= 0 && p.y < gegl_buffer_get_height (closed))
+                            {
+                              guchar val = 1;
 
-                      gegl_buffer_set (closed, GEGL_RECTANGLE ((gint) p.x, (gint) p.y, 1, 1), 0,
-                                       NULL, &val, GEGL_AUTO_ROWSTRIDE);
+                              gegl_buffer_set (closed, GEGL_RECTANGLE ((gint) p.x, (gint) p.y, 1, 1), 0,
+                                               NULL, &val, GEGL_AUTO_ROWSTRIDE);
+                            }
+                        }
+                      g_hash_table_replace (visited, p1,
+                                            GINT_TO_POINTER (GPOINTER_TO_INT (g_hash_table_lookup (visited, 
p1)) + 1));
+                      g_hash_table_replace (visited, p2,
+                                            GINT_TO_POINTER (GPOINTER_TO_INT (g_hash_table_lookup (visited, 
p2)) + 1));
+                      inserted = TRUE;
                     }
+                  g_array_free (discrete_curve, TRUE);
+                }
+              if (! inserted)
+                {
+                  g_free (p1);
+                  g_free (p2);
                 }
-              g_hash_table_replace (visited, p1,
-                                    GINT_TO_POINTER (GPOINTER_TO_INT (g_hash_table_lookup (visited, p1)) + 
1));
-              g_hash_table_replace (visited, p2,
-                                    GINT_TO_POINTER (GPOINTER_TO_INT (g_hash_table_lookup (visited, p2)) + 
1));
-              inserted = TRUE;
             }
-          g_array_free (discrete_curve, TRUE);
-        }
-      if (! inserted)
-        {
-          g_free (p1);
-          g_free (p2);
-        }
-    }
-
-  /* Draw straight line segments */
-  point = (Pixel *) keypoints->data;
-  for (i = 0; i < keypoints->len; i++)
-    {
-      Pixel    *p = g_new (Pixel, 1);
-      gboolean  inserted = FALSE;
 
-      *p = *point;
+          g_list_free_full (candidates, g_free);
+          g_object_unref (strokes);
+        }
 
-      if (! g_hash_table_contains (visited, p) ||
-          (small_segments_from_spline_sources &&
-           GPOINTER_TO_INT (g_hash_table_lookup (visited, p)) < end_point_connectivity))
+      /* Draw straight line segments */
+      if (segment_max_length > 0)
         {
-          GArray *segment = gimp_lineart_line_segment_until_hit (closed, *point,
-                                                                 pair2normal (*point, normals, width),
-                                                                 segment_max_length);
-
-          if (segment->len &&
-              ! gimp_lineart_curve_creates_region (closed, segment,
-                                                   created_regions_significant_area,
-                                                   created_regions_minimum_area - 1))
+          Pixel *point;
+
+          point = (Pixel *) keypoints->data;
+          for (i = 0; i < keypoints->len; i++)
             {
-              gint j;
+              Pixel    *p = g_new (Pixel, 1);
+              gboolean  inserted = FALSE;
 
-              for (j = 0; j < segment->len; j++)
+              *p = *point;
+
+              if (! g_hash_table_contains (visited, p) ||
+                  (small_segments_from_spline_sources &&
+                   GPOINTER_TO_INT (g_hash_table_lookup (visited, p)) < end_point_connectivity))
                 {
-                  Pixel  p2 = g_array_index (segment, Pixel, j);
-                  guchar val = 1;
+                  GArray *segment = gimp_lineart_line_segment_until_hit (closed, *point,
+                                                                         pair2normal (*point, normals, 
width),
+                                                                         segment_max_length);
+
+                  if (segment->len &&
+                      ! gimp_lineart_curve_creates_region (closed, segment,
+                                                           created_regions_significant_area,
+                                                           created_regions_minimum_area - 1))
+                    {
+                      gint j;
 
-                  gegl_buffer_set (closed, GEGL_RECTANGLE ((gint) p2.x, (gint) p2.y, 1, 1), 0,
-                                   NULL, &val, GEGL_AUTO_ROWSTRIDE);
+                      for (j = 0; j < segment->len; j++)
+                        {
+                          Pixel  p2 = g_array_index (segment, Pixel, j);
+                          guchar val = 1;
+
+                          gegl_buffer_set (closed, GEGL_RECTANGLE ((gint) p2.x, (gint) p2.y, 1, 1), 0,
+                                           NULL, &val, GEGL_AUTO_ROWSTRIDE);
+                        }
+                      g_hash_table_replace (visited, p,
+                                            GINT_TO_POINTER (GPOINTER_TO_INT (g_hash_table_lookup (visited, 
p)) + 1));
+                      inserted = TRUE;
+                    }
+                  g_array_free (segment, TRUE);
                 }
-              g_hash_table_replace (visited, p,
-                                    GINT_TO_POINTER (GPOINTER_TO_INT (g_hash_table_lookup (visited, p)) + 
1));
-              inserted = TRUE;
+              if (! inserted)
+                g_free (p);
+              point++;
             }
-          g_array_free (segment, TRUE);
         }
-      if (! inserted)
-        g_free (p);
-      point++;
+
+      g_free (normals);
+      g_free (curvatures);
+      g_free (smoothed_curvatures);
+      g_array_free (keypoints, TRUE);
+      g_hash_table_destroy (visited);
     }
 
   if (closed_distmap)
@@ -1083,14 +1107,6 @@ gimp_line_art_close (GeglBuffer  *buffer,
       g_object_unref (graph);
     }
 
-  g_hash_table_destroy (visited);
-  g_array_free (keypoints, TRUE);
-  g_object_unref (strokes);
-  g_free (normals);
-  g_free (curvatures);
-  g_free (smoothed_curvatures);
-  g_list_free_full (candidates, g_free);
-
   return closed;
 }
 
diff --git a/app/tools/gimpbucketfilloptions.c b/app/tools/gimpbucketfilloptions.c
index b58e88a169..634e341586 100644
--- a/app/tools/gimpbucketfilloptions.c
+++ b/app/tools/gimpbucketfilloptions.c
@@ -177,14 +177,14 @@ gimp_bucket_fill_options_class_init (GimpBucketFillOptionsClass *klass)
                         "line-art-spline-max-len",
                         _("Maximum curved closing length"),
                         _("Maximum curved length (in pixels) to close the line art"),
-                        1, 1000, 60,
+                        0, 1000, 60,
                         GIMP_PARAM_STATIC_STRINGS);
 
   GIMP_CONFIG_PROP_INT (object_class, PROP_LINE_ART_SEGMENT_MAX_LEN,
                         "line-art-segment-max-len",
                         _("Maximum straight closing length"),
                         _("Maximum straight length (in pixels) to close the line art"),
-                        1, 1000, 20,
+                        0, 1000, 20,
                         GIMP_PARAM_STATIC_STRINGS);
 
   GIMP_CONFIG_PROP_ENUM (object_class, PROP_FILL_CRITERION,


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