[gimp] app: add gimp_pickable_contiguous_region_prepare_line_art_async() ...
- From: Ell <ell src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gimp] app: add gimp_pickable_contiguous_region_prepare_line_art_async() ...
- Date: Mon, 19 Nov 2018 20:07:48 +0000 (UTC)
commit b4e12fbbbba8d607abdbe353e424c8386d2a3f11
Author: Ell <ell_se yahoo com>
Date: Mon Nov 19 14:48:26 2018 -0500
app: add gimp_pickable_contiguous_region_prepare_line_art_async() ...
... and use in bucket-fill tool
Add gimp_pickable_contiguous_region_prepare_line_art_async(), which
computes a line-art asynchronously, and use it in the bucket-fill
tool, instead of having the tool create the async op.
This allows the async to keep running even after the pickable dies,
since we only need the pickable's buffer, and not the pickable
itself. Previously, we reffed the pickable for the duration of the
async, but we could still segfault when unreffing it, if the
pickable was a drawable, and its parent image had already died.
Furthermore, let the async work on a copy of the pickable's buffer,
rather than the pickable's buffer directly. This avoids some race
conditions when the pickable is the image (i.e., when "sample
merged" is active), since then we're using image projection's
buffer, which is generally unsafe to use in different threads
concurrently.
Also, s/! has_alpha/has_alpha/ when looking for transparent pixels,
and quit early, at least during this stage, if the async in
canceled.
app/core/gimppickable-contiguous-region.c | 140 +++++++++++++++++++++++++-----
app/core/gimppickable-contiguous-region.h | 43 +++++----
app/tools/gimpbucketfilltool.c | 60 +++----------
3 files changed, 155 insertions(+), 88 deletions(-)
---
diff --git a/app/core/gimppickable-contiguous-region.c b/app/core/gimppickable-contiguous-region.c
index 38a0f2ed0a..0187734616 100644
--- a/app/core/gimppickable-contiguous-region.c
+++ b/app/core/gimppickable-contiguous-region.c
@@ -31,12 +31,22 @@
#include "gegl/gimp-babl.h"
+#include "gimp-parallel.h"
#include "gimp-utils.h" /* GIMP_TIMER */
+#include "gimpasync.h"
#include "gimplineart.h"
#include "gimppickable.h"
#include "gimppickable-contiguous-region.h"
+typedef struct
+{
+ GeglBuffer *buffer;
+ gboolean select_transparent;
+ gfloat stroke_threshold;
+} LineArtData;
+
+
/* local function prototypes */
static const Babl * choose_format (GeglBuffer *buffer,
@@ -96,41 +106,52 @@ 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);
+
/* public functions */
-GeglBuffer *
-gimp_pickable_contiguous_region_prepare_line_art (GimpPickable *pickable,
- gboolean select_transparent,
- gfloat stroke_threshold)
+static void
+gimp_pickable_contiguous_region_prepare_line_art_async_func (GimpAsync *async,
+ LineArtData *data)
{
GeglBuffer *lineart;
gboolean has_alpha;
+ gboolean select_transparent = FALSE;
- g_return_val_if_fail (GIMP_IS_PICKABLE (pickable), NULL);
-
- gimp_pickable_flush (pickable);
-
- lineart = gimp_pickable_get_buffer (pickable);
- has_alpha = babl_format_has_alpha (gegl_buffer_get_format (lineart));
+ has_alpha = babl_format_has_alpha (gegl_buffer_get_format (data->buffer));
- if (! has_alpha)
+ if (has_alpha)
{
- if (select_transparent)
+ if (data->select_transparent)
{
/* don't select transparent regions if there are no fully
* transparent pixels.
*/
GeglBufferIterator *gi;
- select_transparent = FALSE;
- gi = gegl_buffer_iterator_new (lineart, NULL, 0, babl_format ("A u8"),
+ gi = gegl_buffer_iterator_new (data->buffer, NULL, 0,
+ babl_format ("A u8"),
GEGL_ACCESS_READ, GEGL_ABYSS_NONE, 3);
while (gegl_buffer_iterator_next (gi))
{
guint8 *p = (guint8*) gi->items[0].data;
gint k;
+ if (gimp_async_is_canceled (async))
+ {
+ gegl_buffer_iterator_stop (gi);
+
+ gimp_async_abort (async);
+
+ line_art_data_free (data);
+
+ return;
+ }
+
for (k = 0; k < gi->length; k++)
{
if (! *p)
@@ -147,10 +168,6 @@ gimp_pickable_contiguous_region_prepare_line_art (GimpPickable *pickable,
gegl_buffer_iterator_stop (gi);
}
}
- else
- {
- select_transparent = FALSE;
- }
/* For smart selection, we generate a binarized image with close
* regions, then run a composite selection with no threshold on
@@ -158,9 +175,9 @@ gimp_pickable_contiguous_region_prepare_line_art (GimpPickable *pickable,
*/
GIMP_TIMER_START();
- lineart = gimp_lineart_close (lineart,
+ lineart = gimp_lineart_close (data->buffer,
select_transparent,
- stroke_threshold,
+ data->stroke_threshold,
/*minimal_lineart_area,*/
5,
/*normal_estimate_mask_size,*/
@@ -188,9 +205,70 @@ gimp_pickable_contiguous_region_prepare_line_art (GimpPickable *pickable,
GIMP_TIMER_END("close line-art");
+ gimp_async_finish_full (async, lineart, g_object_unref);
+
+ line_art_data_free (data);
+}
+
+GeglBuffer *
+gimp_pickable_contiguous_region_prepare_line_art (GimpPickable *pickable,
+ gboolean select_transparent,
+ gfloat stroke_threshold)
+{
+ GimpAsync *async;
+ LineArtData *data;
+ GeglBuffer *lineart;
+
+ g_return_val_if_fail (GIMP_IS_PICKABLE (pickable), NULL);
+
+ gimp_pickable_flush (pickable);
+
+ async = gimp_async_new ();
+ data = line_art_data_new (gimp_pickable_get_buffer (pickable),
+ select_transparent,
+ stroke_threshold);
+
+ gimp_pickable_contiguous_region_prepare_line_art_async_func (async, data);
+
+ lineart = g_object_ref (gimp_async_get_result (async));
+
+ g_object_unref (async);
+
return lineart;
}
+GimpAsync *
+gimp_pickable_contiguous_region_prepare_line_art_async (GimpPickable *pickable,
+ gboolean select_transparent,
+ gfloat stroke_threshold,
+ gint priority)
+{
+ GeglBuffer *buffer;
+ GimpAsync *async;
+ LineArtData *data;
+
+ g_return_val_if_fail (GIMP_IS_PICKABLE (pickable), NULL);
+
+ gimp_pickable_flush (pickable);
+
+ buffer = gegl_buffer_dup (gimp_pickable_get_buffer (pickable));
+
+ data = line_art_data_new (buffer,
+ select_transparent,
+ stroke_threshold);
+
+ g_object_unref (buffer);
+
+ async = gimp_parallel_run_async_full (
+ priority,
+ (GimpParallelRunAsyncFunc)
+ gimp_pickable_contiguous_region_prepare_line_art_async_func,
+ data,
+ (GDestroyNotify) line_art_data_free);
+
+ return async;
+}
+
GeglBuffer *
gimp_pickable_contiguous_region_by_seed (GimpPickable *pickable,
GeglBuffer *line_art,
@@ -926,3 +1004,25 @@ find_contiguous_region (GeglBuffer *src_buffer,
g_free (row);
#endif
}
+
+static LineArtData *
+line_art_data_new (GeglBuffer *buffer,
+ gboolean select_transparent,
+ gfloat stroke_threshold)
+{
+ LineArtData *data = g_slice_new (LineArtData);
+
+ data->buffer = g_object_ref (buffer);
+ data->select_transparent = select_transparent;
+ data->stroke_threshold = stroke_threshold;
+
+ return data;
+}
+
+static void
+line_art_data_free (LineArtData *data)
+{
+ g_object_unref (data->buffer);
+
+ g_slice_free (LineArtData, data);
+}
diff --git a/app/core/gimppickable-contiguous-region.h b/app/core/gimppickable-contiguous-region.h
index b73f9aa1c4..95543a59e5 100644
--- a/app/core/gimppickable-contiguous-region.h
+++ b/app/core/gimppickable-contiguous-region.h
@@ -19,26 +19,31 @@
#define __GIMP_PICKABLE_CONTIGUOUS_REGION_H__
-GeglBuffer * gimp_pickable_contiguous_region_prepare_line_art (GimpPickable *pickable,
- gboolean select_transparent,
- gfloat stroke_threshold);
-GeglBuffer * gimp_pickable_contiguous_region_by_seed (GimpPickable *pickable,
- GeglBuffer *line_art,
- gboolean antialias,
- gfloat threshold,
- gboolean select_transparent,
- GimpSelectCriterion select_criterion,
- gboolean diagonal_neighbors,
- gfloat stroke_threshold,
- gint x,
- gint y);
+GeglBuffer * gimp_pickable_contiguous_region_prepare_line_art (GimpPickable *pickable,
+ gboolean select_transparent,
+ gfloat stroke_threshold);
+GimpAsync * gimp_pickable_contiguous_region_prepare_line_art_async (GimpPickable *pickable,
+ gboolean select_transparent,
+ gfloat stroke_threshold,
+ gint priority);
-GeglBuffer * gimp_pickable_contiguous_region_by_color (GimpPickable *pickable,
- gboolean antialias,
- gfloat threshold,
- gboolean select_transparent,
- GimpSelectCriterion select_criterion,
- const GimpRGB *color);
+GeglBuffer * gimp_pickable_contiguous_region_by_seed (GimpPickable *pickable,
+ GeglBuffer *line_art,
+ gboolean antialias,
+ gfloat threshold,
+ gboolean select_transparent,
+ GimpSelectCriterion select_criterion,
+ gboolean diagonal_neighbors,
+ gfloat stroke_threshold,
+ gint x,
+ gint y);
+
+GeglBuffer * gimp_pickable_contiguous_region_by_color (GimpPickable *pickable,
+ gboolean antialias,
+ gfloat threshold,
+ gboolean select_transparent,
+ GimpSelectCriterion select_criterion,
+ const GimpRGB *color);
#endif /* __GIMP_PICKABLE_CONTIGUOUS_REGION_H__ */
diff --git a/app/tools/gimpbucketfilltool.c b/app/tools/gimpbucketfilltool.c
index 9ce209c714..829cf87412 100644
--- a/app/tools/gimpbucketfilltool.c
+++ b/app/tools/gimpbucketfilltool.c
@@ -35,7 +35,6 @@
#include "core/gimpimage.h"
#include "core/gimpitem.h"
#include "core/gimplineart.h"
-#include "core/gimp-parallel.h"
#include "core/gimppickable.h"
#include "core/gimppickable-contiguous-region.h"
#include "core/gimpprogress.h"
@@ -689,33 +688,6 @@ gimp_bucket_fill_tool_cursor_update (GimpTool *tool,
GIMP_TOOL_CLASS (parent_class)->cursor_update (tool, coords, state, display);
}
-typedef struct
-{
- GimpPickable *pickable;
- gboolean fill_transparent;
- gdouble line_art_threshold;
-} PrecomputeData;
-
-static void
-precompute_data_free (PrecomputeData *data)
-{
- g_object_unref (data->pickable);
- g_slice_free (PrecomputeData, data);
-}
-
-static void
-gimp_bucket_fill_compute_line_art_async (GimpAsync *async,
- PrecomputeData *data)
-{
- GeglBuffer *line_art;
-
- line_art = gimp_pickable_contiguous_region_prepare_line_art (data->pickable,
- data->fill_transparent,
- data->line_art_threshold);
- precompute_data_free (data);
- gimp_async_finish_full (async, line_art, g_object_unref);
-}
-
static void
gimp_bucket_fill_compute_line_art_cb (GimpAsync *async,
GimpBucketFillTool *tool)
@@ -754,36 +726,26 @@ gimp_bucket_fill_compute_line_art (GimpBucketFillTool *tool)
GimpDrawable *drawable = g_weak_ref_get (&tool->priv->cached_drawable);
if (image && options->sample_merged)
- {
- pickable = GIMP_PICKABLE (image);
- g_clear_object (&drawable);
- }
+ pickable = GIMP_PICKABLE (image);
else if (drawable && ! options->sample_merged)
- {
- pickable = GIMP_PICKABLE (drawable);
- g_clear_object (&image);
- }
- else
- {
- g_clear_object (&image);
- g_clear_object (&drawable);
- }
+ pickable = GIMP_PICKABLE (drawable);
if (pickable)
{
- PrecomputeData *data = g_slice_new (PrecomputeData);
+ tool->priv->async =
+ gimp_pickable_contiguous_region_prepare_line_art_async (
+ pickable,
+ options->fill_transparent,
+ options->line_art_threshold,
+ +1);
- data->pickable = pickable;
- data->fill_transparent = options->fill_transparent;
- data->line_art_threshold = options->line_art_threshold;
-
- tool->priv->async = gimp_parallel_run_async_full (1,
- (GimpParallelRunAsyncFunc)
gimp_bucket_fill_compute_line_art_async,
- data, (GDestroyNotify) precompute_data_free);
gimp_async_add_callback (tool->priv->async,
(GimpAsyncCallback) gimp_bucket_fill_compute_line_art_cb,
tool);
}
+
+ g_clear_object (&image);
+ g_clear_object (&drawable);
}
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]