[gimp] app: add a new feature to stroke the line art fill borders.



commit 76699e89ac32455230fe0e7ab30c4d38006b6828
Author: Jehan <jehan girinstud io>
Date:   Mon Feb 28 15:39:52 2022 +0100

    app: add a new feature to stroke the line art fill borders.
    
    Currently the option is quite simple. What should happen to make it more
    usable:
    
    * Right now, it uses the last stroke options (e.g. as used in a
      previously run "Stroke Selection" or "Stroke Path"). We should have
      some dedicated GUI in the bucket fill options.
    * The bucket fill options GUI should really be redesigned. The more we
      add options, the less understandable it is.
    * There is a question whether we want to just use whatever brush size is
      being set or if we want to have it vary and follow the line art width
      (since we have proper distance map, we could use this to tweak the
      stroke per-coords).
    
    As usual, this feature was suggested by Aryeom who was still very
    saddened that despite all the fancy features in this tool, it is not
    able to produce nice rendering. So she proposed that the tool could
    stroke the fill region borders.

 app/core/gimpchannel.c              |  6 ++--
 app/core/gimpdrawable-bucket-fill.c | 68 ++++++++++++++++++++++++++++++++++---
 app/core/gimpdrawable-bucket-fill.h |  1 +
 app/tools/gimpbucketfilloptions.c   | 19 +++++++++++
 app/tools/gimpbucketfilloptions.h   |  1 +
 app/tools/gimpbucketfilltool.c      |  1 +
 6 files changed, 90 insertions(+), 6 deletions(-)
---
diff --git a/app/core/gimpchannel.c b/app/core/gimpchannel.c
index 12bc985cd1..7b6a9851ae 100644
--- a/app/core/gimpchannel.c
+++ b/app/core/gimpchannel.c
@@ -826,7 +826,8 @@ gimp_channel_stroke (GimpItem           *item,
     case GIMP_STROKE_LINE:
       gimp_drawable_stroke_boundary (drawable,
                                      stroke_options,
-                                     segs_in, n_segs_in,
+                                     n_segs_in > 0 ? segs_in   : segs_out,
+                                     n_segs_in > 0 ? n_segs_in : n_segs_out,
                                      offset_x, offset_y,
                                      push_undo);
       retval = TRUE;
@@ -849,7 +850,8 @@ gimp_channel_stroke (GimpItem           *item,
         retval = gimp_paint_core_stroke_boundary (core, drawable,
                                                   paint_options,
                                                   emulate_dynamics,
-                                                  segs_in, n_segs_in,
+                                                  n_segs_in > 0 ? segs_in   : segs_out,
+                                                  n_segs_in > 0 ? n_segs_in : n_segs_out,
                                                   offset_x, offset_y,
                                                   push_undo, error);
 
diff --git a/app/core/gimpdrawable-bucket-fill.c b/app/core/gimpdrawable-bucket-fill.c
index 319887cc82..7af371c6ef 100644
--- a/app/core/gimpdrawable-bucket-fill.c
+++ b/app/core/gimpdrawable-bucket-fill.c
@@ -23,9 +23,12 @@
 
 #include "libgimpbase/gimpbase.h"
 #include "libgimpcolor/gimpcolor.h"
+#include "libgimpconfig/gimpconfig.h"
 
 #include "core-types.h"
 
+#include "config/gimpdialogconfig.h"
+
 #include "gegl/gimp-gegl-apply-operation.h"
 #include "gegl/gimp-gegl-mask.h"
 #include "gegl/gimp-gegl-mask-combine.h"
@@ -38,6 +41,7 @@
 #include "gimpdrawable.h"
 #include "gimpdrawable-bucket-fill.h"
 #include "gimpfilloptions.h"
+#include "gimpstrokeoptions.h"
 #include "gimpimage.h"
 #include "gimplineart.h"
 #include "gimppickable.h"
@@ -325,7 +329,7 @@ gimp_drawable_get_bucket_fill_buffer (GimpDrawable         *drawable,
  *               filling process. Set to NULL if you need a one-time
  *               fill.
  * @mask_x: returned x bound of @mask_buffer.
- * @mask_y: returned x bound of @mask_buffer.
+ * @mask_y: returned y bound of @mask_buffer.
  * @mask_width: returned width bound of @mask_buffer.
  * @mask_height: returned height bound of @mask_buffer.
  *
@@ -333,7 +337,7 @@ gimp_drawable_get_bucket_fill_buffer (GimpDrawable         *drawable,
  * based on @line_art and @options, without actually applying it.
  * If @mask_buffer is not NULL, the intermediate fill mask will also be
  * returned. This fill mask can later be reused in successive calls to
- * gimp_drawable_get_bucket_fill_buffer() for interactive filling.
+ * gimp_drawable_get_line_art_fill_buffer() for interactive filling.
  *
  * The @fill_color_as_line_art option is a special feature where we
  * consider pixels in @drawable already in the fill color as part of the
@@ -351,6 +355,7 @@ gimp_drawable_get_line_art_fill_buffer (GimpDrawable     *drawable,
                                         gboolean          sample_merged,
                                         gboolean          fill_color_as_line_art,
                                         gdouble           fill_color_threshold,
+                                        gboolean          line_art_stroke,
                                         gdouble           seed_x,
                                         gdouble           seed_y,
                                         GeglBuffer      **mask_buffer,
@@ -362,6 +367,7 @@ gimp_drawable_get_line_art_fill_buffer (GimpDrawable     *drawable,
   GimpImage  *image;
   GeglBuffer *buffer;
   GeglBuffer *new_mask;
+  GeglBuffer *stroke_mask;
   GeglBuffer *fill_buffer   = NULL;
   GimpRGB     fill_color;
   gint        fill_offset_x = 0;
@@ -438,7 +444,59 @@ gimp_drawable_get_line_art_fill_buffer (GimpDrawable     *drawable,
   if (mask_buffer)
     *mask_buffer = new_mask;
 
-  gimp_gegl_mask_bounds (new_mask, &x, &y, &width, &height);
+  if (line_art_stroke)
+    {
+      GimpChannel       *channel;
+      GList             *drawables;
+      GimpStrokeOptions *stroke_options;
+      GimpContext       *context = gimp_get_user_context (image->gimp);
+      GError            *error   = NULL;
+      const GimpRGB      white   = {1.0, 1.0, 1.0, 1.0};
+
+      context = gimp_config_duplicate (GIMP_CONFIG (context));
+      /* As we are stroking a mask, we need to set color to white. */
+      gimp_context_set_foreground (GIMP_CONTEXT (context),
+                                   &white);
+
+      /* This initial version uses the stroke option as used in other
+       * stroke features. A future version should allow to set the
+       * stroke directly from bucket fill tool options.
+       */
+      stroke_options = GIMP_DIALOG_CONFIG (image->gimp->config)->stroke_options;
+      stroke_options = gimp_config_duplicate (GIMP_CONFIG (stroke_options));
+
+      channel = gimp_channel_new_from_buffer (image, new_mask, NULL, NULL);
+      gimp_image_add_hidden_item (image, GIMP_ITEM (channel));
+      drawables = g_list_prepend (NULL, channel);
+
+      if (! gimp_item_stroke (GIMP_ITEM (channel), drawables,
+                              context,
+                              stroke_options,
+                              NULL, FALSE, NULL, &error))
+        {
+          g_warning ("%s: stroking failed with: %s\n",
+                     G_STRFUNC, error ? error->message : "no error message");
+          g_clear_error (&error);
+        }
+
+      g_list_free (drawables);
+
+      gimp_pickable_flush (GIMP_PICKABLE (channel));
+      stroke_mask = gimp_drawable_get_buffer (GIMP_DRAWABLE (channel));
+      g_object_ref (stroke_mask);
+
+      gimp_image_remove_hidden_item (image, GIMP_ITEM (channel));
+      g_object_unref (channel);
+
+      g_object_unref (stroke_options);
+      g_object_unref (context);
+    }
+  else
+    {
+      stroke_mask = g_object_ref (new_mask);
+    }
+
+  gimp_gegl_mask_bounds (stroke_mask, &x, &y, &width, &height);
   width  -= x;
   height -= y;
 
@@ -508,7 +566,7 @@ gimp_drawable_get_line_art_fill_buffer (GimpDrawable     *drawable,
                                                             width, height),
                                             -x, -y);
 
-  gimp_gegl_apply_opacity (buffer, NULL, NULL, buffer, new_mask,
+  gimp_gegl_apply_opacity (buffer, NULL, NULL, buffer, stroke_mask,
                            -mask_offset_x, -mask_offset_y, 1.0);
 
   if (gimp_fill_options_get_feather (options, &feather_radius))
@@ -534,6 +592,8 @@ gimp_drawable_get_line_art_fill_buffer (GimpDrawable     *drawable,
   if (! mask_buffer)
     g_object_unref (new_mask);
 
+  g_object_unref (stroke_mask);
+
   gimp_unset_busy (image->gimp);
 
   return buffer;
diff --git a/app/core/gimpdrawable-bucket-fill.h b/app/core/gimpdrawable-bucket-fill.h
index 0339d6c70f..ffbf891c47 100644
--- a/app/core/gimpdrawable-bucket-fill.h
+++ b/app/core/gimpdrawable-bucket-fill.h
@@ -50,6 +50,7 @@ GeglBuffer * gimp_drawable_get_line_art_fill_buffer (GimpDrawable         *drawa
                                                      gboolean              sample_merged,
                                                      gboolean              fill_color_as_line_art,
                                                      gdouble               fill_color_threshold,
+                                                     gboolean              line_art_stroke,
                                                      gdouble               seed_x,
                                                      gdouble               seed_y,
                                                      GeglBuffer          **mask_buffer,
diff --git a/app/tools/gimpbucketfilloptions.c b/app/tools/gimpbucketfilloptions.c
index 0328b59d5f..fd9567d379 100644
--- a/app/tools/gimpbucketfilloptions.c
+++ b/app/tools/gimpbucketfilloptions.c
@@ -59,6 +59,7 @@ enum
   PROP_LINE_ART_SOURCE,
   PROP_LINE_ART_THRESHOLD,
   PROP_LINE_ART_MAX_GROW,
+  PROP_LINE_ART_STROKE,
   PROP_LINE_ART_MAX_GAP_LENGTH,
   PROP_FILL_CRITERION,
   PROP_FILL_COLOR_AS_LINE_ART,
@@ -215,6 +216,14 @@ gimp_bucket_fill_options_class_init (GimpBucketFillOptionsClass *klass)
                         1, 100, 3,
                         GIMP_PARAM_STATIC_STRINGS);
 
+  /* TODO: we should be able to choose which tool to stroke with. */
+  GIMP_CONFIG_PROP_BOOLEAN (object_class, PROP_LINE_ART_STROKE,
+                            "line-art-stroke-border",
+                            _("Stroke borders"),
+                            _("Stroke fill borders with last stroke options"),
+                            FALSE,
+                            GIMP_PARAM_STATIC_STRINGS);
+
   GIMP_CONFIG_PROP_INT (object_class, PROP_LINE_ART_MAX_GAP_LENGTH,
                         "line-art-max-gap-length",
                         _("Maximum gap length"),
@@ -294,6 +303,9 @@ gimp_bucket_fill_options_set_property (GObject      *object,
     case PROP_LINE_ART_MAX_GROW:
       options->line_art_max_grow = g_value_get_int (value);
       break;
+    case PROP_LINE_ART_STROKE:
+      options->line_art_stroke = g_value_get_boolean (value);
+      break;
     case PROP_LINE_ART_MAX_GAP_LENGTH:
       options->line_art_max_gap_length = g_value_get_int (value);
       break;
@@ -359,6 +371,9 @@ gimp_bucket_fill_options_get_property (GObject    *object,
     case PROP_LINE_ART_MAX_GROW:
       g_value_set_int (value, options->line_art_max_grow);
       break;
+    case PROP_LINE_ART_STROKE:
+      g_value_set_boolean (value, options->line_art_stroke);
+      break;
     case PROP_LINE_ART_MAX_GAP_LENGTH:
       g_value_set_int (value, options->line_art_max_gap_length);
       break;
@@ -560,6 +575,10 @@ gimp_bucket_fill_options_gui (GimpToolOptions *tool_options)
                                     1, 5, 0);
   gtk_box_pack_start (GTK_BOX (box2), scale, FALSE, FALSE, 0);
 
+  /*  Line Art: stroke border with paint brush */
+  widget = gimp_prop_check_button_new (config, "line-art-stroke-border", NULL);
+  gtk_box_pack_start (GTK_BOX (box2), widget, FALSE, FALSE, 0);
+
   /*  Line Art: stroke threshold */
   scale = gimp_prop_spin_scale_new (config, "line-art-threshold",
                                     0.05, 0.1, 2);
diff --git a/app/tools/gimpbucketfilloptions.h b/app/tools/gimpbucketfilloptions.h
index 30bb594cbb..84345011f8 100644
--- a/app/tools/gimpbucketfilloptions.h
+++ b/app/tools/gimpbucketfilloptions.h
@@ -52,6 +52,7 @@ struct _GimpBucketFillOptions
   GimpLineArtSource             line_art_source;
   gdouble                       line_art_threshold;
   gint                          line_art_max_grow;
+  gboolean                      line_art_stroke;
   gint                          line_art_max_gap_length;
 
   gboolean                      fill_as_line_art;
diff --git a/app/tools/gimpbucketfilltool.c b/app/tools/gimpbucketfilltool.c
index 40f04e84e1..5478b61538 100644
--- a/app/tools/gimpbucketfilltool.c
+++ b/app/tools/gimpbucketfilltool.c
@@ -457,6 +457,7 @@ gimp_bucket_fill_tool_preview (GimpBucketFillTool *tool,
                                                          GIMP_LINE_ART_SOURCE_SAMPLE_MERGED,
                                                          options->fill_as_line_art,
                                                          options->fill_as_line_art_threshold / 255.0,
+                                                         options->line_art_stroke,
                                                          x, y,
                                                          &tool->priv->fill_mask,
                                                          &x, &y, NULL, NULL);


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