diff --git a/app/core/gimpchannel-select.c b/app/core/gimpchannel-select.c index 892dbb203e..6abe01f960 100644 --- a/app/core/gimpchannel-select.c +++ b/app/core/gimpchannel-select.c @@ -516,7 +516,7 @@ gimp_channel_select_fuzzy (GimpChannel *channel, pickable = GIMP_PICKABLE (drawable); add_on = gimp_pickable_contiguous_region_by_seed (pickable, - NULL, + NULL, NULL, NULL, antialias, threshold, select_transparent, diff --git a/app/core/gimpdrawable-bucket-fill.c b/app/core/gimpdrawable-bucket-fill.c index 4aebb63535..7025018ff8 100644 --- a/app/core/gimpdrawable-bucket-fill.c +++ b/app/core/gimpdrawable-bucket-fill.c @@ -50,6 +50,8 @@ void gimp_drawable_bucket_fill (GimpDrawable *drawable, GeglBuffer *line_art, + gfloat *distmap, + gfloat *thickmap, GimpFillOptions *options, gboolean fill_transparent, GimpSelectCriterion fill_criterion, @@ -72,7 +74,8 @@ gimp_drawable_bucket_fill (GimpDrawable *drawable, image = gimp_item_get_image (GIMP_ITEM (drawable)); gimp_set_busy (image->gimp); - buffer = gimp_drawable_get_bucket_fill_buffer (drawable, line_art, options, + buffer = gimp_drawable_get_bucket_fill_buffer (drawable, line_art, + distmap, thickmap, options, fill_transparent, fill_criterion, threshold, sample_merged, diagonal_neighbors, @@ -134,6 +137,8 @@ gimp_drawable_bucket_fill (GimpDrawable *drawable, GeglBuffer * gimp_drawable_get_bucket_fill_buffer (GimpDrawable *drawable, GeglBuffer *line_art, + gfloat *distmap, + gfloat *thickmap, GimpFillOptions *options, gboolean fill_transparent, GimpSelectCriterion fill_criterion, @@ -196,7 +201,7 @@ gimp_drawable_get_bucket_fill_buffer (GimpDrawable *drawable, * contiguous region. */ new_mask = gimp_pickable_contiguous_region_by_seed (pickable, - line_art, + line_art, distmap, thickmap, antialias, threshold, fill_transparent, diff --git a/app/core/gimpdrawable-bucket-fill.h b/app/core/gimpdrawable-bucket-fill.h index 9cb566f699..7b6cae9888 100644 --- a/app/core/gimpdrawable-bucket-fill.h +++ b/app/core/gimpdrawable-bucket-fill.h @@ -21,6 +21,8 @@ void gimp_drawable_bucket_fill (GimpDrawable *drawable, GeglBuffer *line_art, + gfloat *distmap, + gfloat *thickmap, GimpFillOptions *options, gboolean fill_transparent, GimpSelectCriterion fill_criterion, @@ -32,6 +34,8 @@ void gimp_drawable_bucket_fill (GimpDrawable *drawabl gdouble y); GeglBuffer * gimp_drawable_get_bucket_fill_buffer (GimpDrawable *drawable, GeglBuffer *line_art, + gfloat *distmap, + gfloat *thickmap, GimpFillOptions *options, gboolean fill_transparent, GimpSelectCriterion fill_criterion, diff --git a/app/core/gimplineart.c b/app/core/gimplineart.c index 640cb9f7b1..c8373eb87c 100644 --- a/app/core/gimplineart.c +++ b/app/core/gimplineart.c @@ -105,7 +105,8 @@ static GArray * gimp_lineart_line_segment_until_hit (const GeglBuffer Pixel start, GimpVector2 direction, int size); -static gfloat * gimp_lineart_estimate_strokes_radii (GeglBuffer *mask); +static gfloat * gimp_lineart_estimate_strokes_radii (GeglBuffer *mask, + gfloat **lineart_distmap); /* Some callback-type functions. */ @@ -163,7 +164,7 @@ static void gimp_edgelset_next8 (const GeglBuffer *buffer, /** * gimp_lineart_close: - * @line_art: the input #GeglBuffer. + * @buffer: the input #GeglBuffer. * @select_transparent: whether we binarize the alpha channel or the * luminosity. * @stroke_threshold: [0-1] threshold value for detecting stroke pixels @@ -187,8 +188,10 @@ static void gimp_edgelset_next8 (const GeglBuffer *buffer, * @segments_max_length: the maximum length for creating segments * between end points. Unlike splines, segments * are straight lines. + * @lineart_distmap: a distance map of the line art pixels. + * @lineart_radii: a map of estimated radii of line art border pixels. * - * Creates a binarized version of the strokes of @line_art, detected either + * Creates a binarized version of the strokes of @buffer, detected either * with luminosity (light means background) or alpha values depending on * @select_transparent. This binary version of the strokes will have closed * regions allowing adequate selection of "nearly closed regions". @@ -201,24 +204,28 @@ static void gimp_edgelset_next8 (const GeglBuffer *buffer, * Fourey, David Tschumperlé, David Revoy. * * Returns: a new #GeglBuffer of format "Y u8" representing the - * binarized @line_art. A value of + * binarized @line_art. If @lineart_radii and @lineart_distmap + * are not #NULL, newly allocated float buffer are returned, + * which can be used for overflowing created masks later. */ GeglBuffer * -gimp_lineart_close (GeglBuffer *line_art, - gboolean select_transparent, - gfloat stroke_threshold, - gint minimal_lineart_area, - gint normal_estimate_mask_size, - gfloat end_point_rate, - gint spline_max_length, - gfloat spline_max_angle, - gint end_point_connectivity, - gfloat spline_roundness, - gboolean allow_self_intersections, - gint created_regions_significant_area, - gint created_regions_minimum_area, - gboolean small_segments_from_spline_sources, - gint segments_max_length) +gimp_lineart_close (GeglBuffer *buffer, + gboolean select_transparent, + gfloat stroke_threshold, + gint minimal_lineart_area, + gint normal_estimate_mask_size, + gfloat end_point_rate, + gint spline_max_length, + gfloat spline_max_angle, + gint end_point_connectivity, + gfloat spline_roundness, + gboolean allow_self_intersections, + gint created_regions_significant_area, + gint created_regions_minimum_area, + gboolean small_segments_from_spline_sources, + gint segments_max_length, + gfloat **lineart_distmap, + gfloat **lineart_radii) { const Babl *gray_format; gfloat *normals; @@ -236,8 +243,8 @@ gimp_lineart_close (GeglBuffer *line_art, guchar max_value = 0; gfloat threshold; gfloat clamped_threshold; - gint width = gegl_buffer_get_width (line_art); - gint height = gegl_buffer_get_height (line_art); + gint width = gegl_buffer_get_width (buffer); + gint height = gegl_buffer_get_height (buffer); gint i; normals = g_new0 (gfloat, width * height * 2); @@ -252,9 +259,9 @@ gimp_lineart_close (GeglBuffer *line_art, gray_format = babl_format ("Y' u8"); /* Transform the line art from any format to gray. */ - strokes = gegl_buffer_new (gegl_buffer_get_extent (line_art), + strokes = gegl_buffer_new (gegl_buffer_get_extent (buffer), gray_format); - gegl_buffer_copy (line_art, NULL, GEGL_ABYSS_NONE, strokes, NULL); + gegl_buffer_copy (buffer, NULL, GEGL_ABYSS_NONE, strokes, NULL); gegl_buffer_set_format (strokes, babl_format ("Y' u8")); if (! select_transparent) @@ -306,7 +313,7 @@ gimp_lineart_close (GeglBuffer *line_art, smoothed_curvatures, normal_estimate_mask_size); - radii = gimp_lineart_estimate_strokes_radii (strokes); + radii = gimp_lineart_estimate_strokes_radii (strokes, lineart_distmap); threshold = 1.0f - end_point_rate; clamped_threshold = MAX (0.25f, threshold); for (i = 0; i < width; i++) @@ -321,7 +328,10 @@ gimp_lineart_close (GeglBuffer *line_art, curvatures[i + j * width] = 0.0; } } - g_free (radii); + if (lineart_radii) + *lineart_radii = radii; + else + g_free (radii); keypoints = gimp_lineart_curvature_extremums (curvatures, smoothed_curvatures, width, height); @@ -1266,7 +1276,8 @@ gimp_lineart_line_segment_until_hit (const GeglBuffer *mask, } static gfloat * -gimp_lineart_estimate_strokes_radii (GeglBuffer *mask) +gimp_lineart_estimate_strokes_radii (GeglBuffer *mask, + gfloat **lineart_distmap) { GeglBufferIterator *gi; gfloat *dist; @@ -1411,7 +1422,10 @@ gimp_lineart_estimate_strokes_radii (GeglBuffer *mask) } } - g_free (dist); + if (lineart_distmap) + *lineart_distmap = dist; + else + g_free (dist); g_object_unref (distmap); return thickness; diff --git a/app/core/gimplineart.h b/app/core/gimplineart.h index 54ee9e546b..8fa43f78da 100644 --- a/app/core/gimplineart.h +++ b/app/core/gimplineart.h @@ -22,21 +22,23 @@ #define __GIMP_LINEART__ -GeglBuffer * gimp_lineart_close (GeglBuffer *line_art, - gboolean select_transparent, - gfloat stroke_threshold, - gint minimal_lineart_area, - gint normal_estimate_mask_size, - gfloat end_point_rate, - gint spline_max_length, - gfloat spline_max_angle, - gint end_point_connectivity, - gfloat spline_roundness, - gboolean allow_self_intersections, - gint created_regions_significant_area, - gint created_regions_minimum_area, - gboolean small_segments_from_spline_sources, - gint segments_max_length); +GeglBuffer * gimp_lineart_close (GeglBuffer *buffer, + gboolean select_transparent, + gfloat stroke_threshold, + gint minimal_lineart_area, + gint normal_estimate_mask_size, + gfloat end_point_rate, + gint spline_max_length, + gfloat spline_max_angle, + gint end_point_connectivity, + gfloat spline_roundness, + gboolean allow_self_intersections, + gint created_regions_significant_area, + gint created_regions_minimum_area, + gboolean small_segments_from_spline_sources, + gint segments_max_length, + gfloat **lineart_distmap, + gfloat **lineart_radii); #endif /* __GIMP_LINEART__ */ diff --git a/app/core/gimppickable-contiguous-region.c b/app/core/gimppickable-contiguous-region.c index 9149643c8f..396758e03a 100644 --- a/app/core/gimppickable-contiguous-region.c +++ b/app/core/gimppickable-contiguous-region.c @@ -46,6 +46,13 @@ typedef struct gfloat stroke_threshold; } LineArtData; +typedef struct +{ + gint x; + gint y; + gfloat dist; +} BorderPixel; + /* local function prototypes */ @@ -106,10 +113,20 @@ static void find_contiguous_region (GeglBuffer *src_buffer, gint y, const gfloat *col); -static LineArtData * line_art_data_new (GeglBuffer *buffer, - gboolean select_transparent, - gfloat stroke_threshold); -static void line_art_data_free (LineArtData *data); +static LineArtData * line_art_data_new (GeglBuffer *buffer, + gboolean select_transparent, + gfloat stroke_threshold); +static void line_art_data_free (LineArtData *data); +static GimpPickableLineArtAsyncResult * + line_art_result_new (GeglBuffer *line_art, + gfloat *distmap, + gfloat *thickmap); +static void line_art_result_free (GimpPickableLineArtAsyncResult + *data); +static void line_art_queue_pixel (GQueue *queue, + gint x, + gint y, + gfloat dist); /* public functions */ @@ -119,6 +136,8 @@ gimp_pickable_contiguous_region_prepare_line_art_async_func (GimpAsync *async, LineArtData *data) { GeglBuffer *lineart; + gfloat *distmap; + gfloat *thickmap; gboolean has_alpha; gboolean select_transparent = FALSE; @@ -201,23 +220,29 @@ gimp_pickable_contiguous_region_prepare_line_art_async_func (GimpAsync *async, /*small_segments_from_spline_sources,*/ TRUE, /*segments_max_length*/ - 20); + 20, + &distmap, &thickmap); GIMP_TIMER_END("close line-art"); - gimp_async_finish_full (async, lineart, g_object_unref); + gimp_async_finish_full (async, + line_art_result_new (lineart, distmap, thickmap), + (GDestroyNotify) line_art_result_free); line_art_data_free (data); } GeglBuffer * -gimp_pickable_contiguous_region_prepare_line_art (GimpPickable *pickable, - gboolean select_transparent, - gfloat stroke_threshold) +gimp_pickable_contiguous_region_prepare_line_art (GimpPickable *pickable, + gboolean select_transparent, + gfloat stroke_threshold, + gfloat **distmap, + gfloat **thickmap) { - GimpAsync *async; - LineArtData *data; - GeglBuffer *lineart; + GimpAsync *async; + LineArtData *data; + GimpPickableLineArtAsyncResult *result; + GeglBuffer *lineart; g_return_val_if_fail (GIMP_IS_PICKABLE (pickable), NULL); @@ -230,7 +255,13 @@ gimp_pickable_contiguous_region_prepare_line_art (GimpPickable *pickable, gimp_pickable_contiguous_region_prepare_line_art_async_func (async, data); - lineart = g_object_ref (gimp_async_get_result (async)); + result = gimp_async_get_result (async); + + lineart = g_object_ref (result->line_art); + *distmap = result->distmap; + *thickmap = result->thickmap; + result->distmap = NULL; + result->thickmap = NULL; g_object_unref (async); @@ -272,6 +303,8 @@ gimp_pickable_contiguous_region_prepare_line_art_async (GimpPickable *pickable, GeglBuffer * gimp_pickable_contiguous_region_by_seed (GimpPickable *pickable, GeglBuffer *line_art, + gfloat *distmap, + gfloat *thickmap, gboolean antialias, gfloat threshold, gboolean select_transparent, @@ -288,7 +321,6 @@ gimp_pickable_contiguous_region_by_seed (GimpPickable *pickable, gint n_components; gboolean has_alpha; gfloat start_col[MAX_CHANNELS]; - gfloat flag = 2.0; gboolean smart_line_art = FALSE; gboolean free_line_art = FALSE; @@ -296,6 +328,9 @@ gimp_pickable_contiguous_region_by_seed (GimpPickable *pickable, if (select_criterion == GIMP_SELECT_CRITERION_LINE_ART) { + g_return_val_if_fail ((line_art && distmap && thickmap) || + (! line_art && ! distmap && ! thickmap), + NULL); if (line_art == NULL) { /* It is much better experience to pre-compute the line art, @@ -303,7 +338,8 @@ gimp_pickable_contiguous_region_by_seed (GimpPickable *pickable, * selecting/filling through a PDB call). */ line_art = gimp_pickable_contiguous_region_prepare_line_art (pickable, select_transparent, - stroke_threshold); + stroke_threshold, + &distmap, &thickmap); free_line_art = TRUE; } @@ -382,59 +418,198 @@ gimp_pickable_contiguous_region_by_seed (GimpPickable *pickable, /* The last step of the line art algorithm is to make sure that * selections does not leave "holes" between its borders and the * line arts, while not stepping over as well. - * To achieve this, I label differently the selection and the rest - * and leave the stroke pixels unlabelled, then I let these - * unknown pixels be labelled by flooding through watershed. + * I used to run the "gegl:watershed-transform" operation to flood + * the stroke pixels, but for such simple need, this simple code + * is so much faster while producing better results. */ - GeglBufferIterator *gi; - GeglNode *graph; - GeglNode *input; - GeglNode *op; + gfloat *mask; + GQueue *queue = g_queue_new (); + gint width = gegl_buffer_get_width (line_art); + gint height = gegl_buffer_get_height (line_art); + gint nx, ny; GIMP_TIMER_START(); - /* Flag the unselected line art pixels. */ - gi = gegl_buffer_iterator_new (src_buffer, NULL, 0, NULL, - GEGL_ACCESS_READ, GEGL_ABYSS_NONE, 2); - gegl_buffer_iterator_add (gi, mask_buffer, NULL, 0, - babl_format ("Y float"), - GEGL_ACCESS_READWRITE, GEGL_ABYSS_NONE); + mask = g_new (gfloat, width * height); + gegl_buffer_get (mask_buffer, NULL, 1.0, NULL, + mask, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE); - while (gegl_buffer_iterator_next (gi)) + for (y = 0; y < height; y++) + for (x = 0; x < width; x++) + { + gfloat thickness = thickmap[x + y * width]; + + if (thickness > 0.0) + { + if (x > 0) + { + nx = x - 1; + if (y > 0) + { + ny = y - 1; + if (mask[nx + ny * width] != 0.0) + { + line_art_queue_pixel (queue, x, y, thickness); + continue; + } + } + ny = y; + if (mask[nx + ny * width] != 0.0) + { + line_art_queue_pixel (queue, x, y, thickness); + continue; + } + if (y < height - 1) + { + ny = y + 1; + if (mask[nx + ny * width] != 0.0) + { + line_art_queue_pixel (queue, x, y, thickness); + continue; + } + } + } + if (x < width - 1) + { + nx = x + 1; + if (y > 0) + { + ny = y - 1; + if (mask[nx + ny * width] != 0.0) + { + line_art_queue_pixel (queue, x, y, thickness); + continue; + } + } + ny = y; + if (mask[nx + ny * width] != 0.0) + { + line_art_queue_pixel (queue, x, y, thickness); + continue; + } + if (y < height - 1) + { + ny = y + 1; + if (mask[nx + ny * width] != 0.0) + { + line_art_queue_pixel (queue, x, y, thickness); + continue; + } + } + } + nx = x; + if (y > 0) + { + ny = y - 1; + if (mask[nx + ny * width] != 0.0) + { + line_art_queue_pixel (queue, x, y, thickness); + continue; + } + } + if (y < height - 1) + { + ny = y + 1; + if (mask[nx + ny * width] != 0.0) + { + line_art_queue_pixel (queue, x, y, thickness); + continue; + } + } + } + } + + while (! g_queue_is_empty (queue)) { - guchar *lineart = (guchar*) gi->items[0].data; - gfloat *mask = (gfloat*) gi->items[1].data; - gint k; + BorderPixel *c = g_queue_pop_head (queue); - for (k = 0; k < gi->length; k++) + if (mask[c->x + c->y * width] != 1.0) { - if (*lineart && ! *mask) - *mask = flag; - lineart++; - mask++; + mask[c->x + c->y * width] = 1.0; + if (c->x > 0) + { + nx = c->x - 1; + if (c->y > 0) + { + ny = c->y - 1; + if (mask[nx + ny * width] == 0.0 && + distmap[nx + ny * width] > distmap[c->x + c->y * width] && + distmap[nx + ny * width] < c->dist) + line_art_queue_pixel (queue, nx, ny, c->dist); + } + ny = c->y; + if (mask[nx + ny * width] == 0.0 && + distmap[nx + ny * width] > distmap[c->x + c->y * width] && + distmap[nx + ny * width] < c->dist) + line_art_queue_pixel (queue, nx, ny, c->dist); + if (c->y < height - 1) + { + ny = c->y - 1; + if (mask[nx + ny * width] == 0.0 && + distmap[nx + ny * width] > distmap[c->x + c->y * width] && + distmap[nx + ny * width] < c->dist) + line_art_queue_pixel (queue, nx, ny, c->dist); + } + } + if (c->x < width - 1) + { + nx = c->x + 1; + if (c->y > 0) + { + ny = c->y - 1; + if (mask[nx + ny * width] == 0.0 && + distmap[nx + ny * width] > distmap[c->x + c->y * width] && + distmap[nx + ny * width] < c->dist) + line_art_queue_pixel (queue, nx, ny, c->dist); + } + ny = c->y; + if (mask[nx + ny * width] == 0.0 && + distmap[nx + ny * width] > distmap[c->x + c->y * width] && + distmap[nx + ny * width] < c->dist) + line_art_queue_pixel (queue, nx, ny, c->dist); + if (c->y < height - 1) + { + ny = c->y - 1; + if (mask[nx + ny * width] == 0.0 && + distmap[nx + ny * width] > distmap[c->x + c->y * width] && + distmap[nx + ny * width] < c->dist) + line_art_queue_pixel (queue, nx, ny, c->dist); + } + } + nx = c->x; + if (c->y > 0) + { + ny = c->y - 1; + if (mask[nx + ny * width] == 0.0 && + distmap[nx + ny * width] > distmap[c->x + c->y * width] && + distmap[nx + ny * width] < c->dist) + line_art_queue_pixel (queue, nx, ny, c->dist); + } + if (c->y < height - 1) + { + ny = c->y + 1; + if (mask[nx + ny * width] == 0.0 && + distmap[nx + ny * width] > distmap[c->x + c->y * width] && + distmap[nx + ny * width] < c->dist) + line_art_queue_pixel (queue, nx, ny, c->dist); + } } + g_free (c); } - - /* Watershed the line art. */ - graph = gegl_node_new (); - input = gegl_node_new_child (graph, - "operation", "gegl:buffer-source", - "buffer", mask_buffer, - NULL); - op = gegl_node_new_child (graph, - "operation", "gegl:watershed-transform", - "flag-component", 0, - "flag", &flag, - NULL); - gegl_node_connect_to (input, "output", - op, "input"); - gegl_node_blit_buffer (op, mask_buffer, NULL, 0, GEGL_ABYSS_NONE); - g_object_unref (graph); + g_queue_free (queue); + gegl_buffer_set (mask_buffer, gegl_buffer_get_extent (mask_buffer), + 0, NULL, mask, GEGL_AUTO_ROWSTRIDE); + g_free (mask); GIMP_TIMER_END("watershed line art"); + + if (free_line_art) + { + g_object_unref (src_buffer); + g_free (distmap); + g_free (thickmap); + } } - if (free_line_art) - g_object_unref (src_buffer); return mask_buffer; } @@ -1001,3 +1176,43 @@ line_art_data_free (LineArtData *data) g_slice_free (LineArtData, data); } + +static GimpPickableLineArtAsyncResult * +line_art_result_new (GeglBuffer *line_art, + gfloat *distmap, + gfloat *thickmap) +{ + GimpPickableLineArtAsyncResult *data; + + data = g_slice_new (GimpPickableLineArtAsyncResult); + data->line_art = line_art; + data->distmap = distmap; + data->thickmap = thickmap; + + return data; +} + +static void +line_art_result_free (GimpPickableLineArtAsyncResult *data) +{ + g_object_unref (data->line_art); + g_clear_pointer (&data->distmap, g_free); + g_clear_pointer (&data->thickmap, g_free); + + g_slice_free (GimpPickableLineArtAsyncResult, data); +} + +static void +line_art_queue_pixel (GQueue *queue, + gint x, + gint y, + gfloat dist) +{ + BorderPixel *p = g_new (BorderPixel, 1); + + p->x = x; + p->y = y; + p->dist = dist; + + g_queue_push_head (queue, p); +} diff --git a/app/core/gimppickable-contiguous-region.h b/app/core/gimppickable-contiguous-region.h index 95543a59e5..8c2f61e82d 100644 --- a/app/core/gimppickable-contiguous-region.h +++ b/app/core/gimppickable-contiguous-region.h @@ -18,10 +18,18 @@ #ifndef __GIMP_PICKABLE_CONTIGUOUS_REGION_H__ #define __GIMP_PICKABLE_CONTIGUOUS_REGION_H__ +typedef struct +{ + GeglBuffer *line_art; + gfloat *distmap; + gfloat *thickmap; +} GimpPickableLineArtAsyncResult; GeglBuffer * gimp_pickable_contiguous_region_prepare_line_art (GimpPickable *pickable, gboolean select_transparent, - gfloat stroke_threshold); + gfloat stroke_threshold, + gfloat **distmap, + gfloat **thickmap); GimpAsync * gimp_pickable_contiguous_region_prepare_line_art_async (GimpPickable *pickable, gboolean select_transparent, gfloat stroke_threshold, @@ -29,6 +37,8 @@ GimpAsync * gimp_pickable_contiguous_region_prepare_line_art_async (GimpPickabl GeglBuffer * gimp_pickable_contiguous_region_by_seed (GimpPickable *pickable, GeglBuffer *line_art, + gfloat *distmap, + gfloat *thickmap, gboolean antialias, gfloat threshold, gboolean select_transparent, diff --git a/app/pdb/drawable-edit-cmds.c b/app/pdb/drawable-edit-cmds.c index 3c5e307bd7..5a88a1deb4 100644 --- a/app/pdb/drawable-edit-cmds.c +++ b/app/pdb/drawable-edit-cmds.c @@ -165,7 +165,7 @@ drawable_edit_bucket_fill_invoker (GimpProcedure *procedure, if (gimp_fill_options_set_by_fill_type (options, context, fill_type, error)) { - gimp_drawable_bucket_fill (drawable, NULL, options, + gimp_drawable_bucket_fill (drawable, NULL, NULL, NULL, options, GIMP_PDB_CONTEXT (context)->sample_transparent, GIMP_PDB_CONTEXT (context)->sample_criterion, GIMP_PDB_CONTEXT (context)->sample_threshold, diff --git a/app/tools/gimpbucketfilltool.c b/app/tools/gimpbucketfilltool.c index 413f871cbc..b46da842b5 100644 --- a/app/tools/gimpbucketfilltool.c +++ b/app/tools/gimpbucketfilltool.c @@ -61,6 +61,8 @@ struct _GimpBucketFillToolPrivate { GimpAsync *async; GeglBuffer *line_art; + gfloat *distmap; + gfloat *thickmap; GWeakRef cached_image; GWeakRef cached_drawable; @@ -243,6 +245,8 @@ gimp_bucket_fill_tool_finalize (GObject *object) } g_clear_object (&tool->priv->line_art); + g_clear_pointer (&tool->priv->distmap, g_free); + g_clear_pointer (&tool->priv->thickmap, g_free); if (image) { @@ -363,6 +367,8 @@ gimp_bucket_fill_tool_preview (GimpBucketFillTool *tool, { GeglBuffer *fill = NULL; GeglBuffer *line_art = NULL; + gfloat *distmap = NULL; + gfloat *thickmap = NULL; gdouble x = coords->x; gdouble y = coords->y; @@ -377,10 +383,14 @@ gimp_bucket_fill_tool_preview (GimpBucketFillTool *tool, } if (options->fill_criterion == GIMP_SELECT_CRITERION_LINE_ART) - line_art = g_object_ref (tool->priv->line_art); + { + line_art = g_object_ref (tool->priv->line_art); + distmap = tool->priv->distmap; + thickmap = tool->priv->thickmap; + } fill = gimp_drawable_get_bucket_fill_buffer (drawable, - line_art, + line_art, distmap, thickmap, fill_options, options->fill_transparent, options->fill_criterion, @@ -696,7 +706,17 @@ gimp_bucket_fill_compute_line_art_cb (GimpAsync *async, return; if (gimp_async_is_finished (async)) - tool->priv->line_art = g_object_ref (gimp_async_get_result (async)); + { + GimpPickableLineArtAsyncResult *result; + + result = gimp_async_get_result (async); + + tool->priv->line_art = g_object_ref (result->line_art); + tool->priv->distmap = result->distmap; + tool->priv->thickmap = result->thickmap; + result->distmap = NULL; + result->thickmap = NULL; + } g_clear_object (&tool->priv->async); } @@ -719,6 +739,9 @@ gimp_bucket_fill_compute_line_art (GimpBucketFillTool *tool) } g_clear_object (&tool->priv->line_art); + g_clear_pointer (&tool->priv->distmap, g_free); + g_clear_pointer (&tool->priv->thickmap, g_free); + if (options->fill_criterion == GIMP_SELECT_CRITERION_LINE_ART) { GimpPickable *pickable = NULL; @@ -822,6 +845,8 @@ gimp_bucket_fill_tool_image_changed (GimpContext *context, GimpImage *prev_drawable = g_weak_ref_get (&tool->priv->cached_drawable); g_clear_object (&tool->priv->line_art); + g_clear_pointer (&tool->priv->distmap, g_free); + g_clear_pointer (&tool->priv->thickmap, g_free); if (prev_image) { diff --git a/app/tools/gimpfuzzyselecttool.c b/app/tools/gimpfuzzyselecttool.c index 2f43b406c5..e28dc71f47 100644 --- a/app/tools/gimpfuzzyselecttool.c +++ b/app/tools/gimpfuzzyselecttool.c @@ -122,7 +122,7 @@ gimp_fuzzy_select_tool_get_mask (GimpRegionSelectTool *region_select, pickable = GIMP_PICKABLE (image); } - return gimp_pickable_contiguous_region_by_seed (pickable, NULL, + return gimp_pickable_contiguous_region_by_seed (pickable, NULL, NULL, NULL, sel_options->antialias, options->threshold / 255.0, options->select_transparent, diff --git a/pdb/groups/drawable_edit.pdb b/pdb/groups/drawable_edit.pdb index 9687d9989f..193a735ec0 100644 --- a/pdb/groups/drawable_edit.pdb +++ b/pdb/groups/drawable_edit.pdb @@ -169,7 +169,7 @@ HELP if (gimp_fill_options_set_by_fill_type (options, context, fill_type, error)) { - gimp_drawable_bucket_fill (drawable, NULL, options, + gimp_drawable_bucket_fill (drawable, NULL, NULL, NULL, options, GIMP_PDB_CONTEXT (context)->sample_transparent, GIMP_PDB_CONTEXT (context)->sample_criterion, GIMP_PDB_CONTEXT (context)->sample_threshold,