[gimp/gimp-2-10] app: allow setting line art spline and segment length to 0.
- From: Jehan <jehanp src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gimp/gimp-2-10] app: allow setting line art spline and segment length to 0.
- Date: Wed, 19 Dec 2018 15:46:10 +0000 (UTC)
commit ef12064655b879a28f0aaaeb7068d76d5bac1354
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.
(cherry picked from commit 0a2d0661689ef48a21fbaa2e0713a5a86a43e968)
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]