1 /* GIMP - The GNU Image Manipulation Program
2  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "config.h"
19 
20 #include <cairo.h>
21 #define GEGL_ITERATOR2_API
22 #include <gegl.h>
23 #include <gdk-pixbuf/gdk-pixbuf.h>
24 
25 #include "libgimpbase/gimpbase.h"
26 #include "libgimpcolor/gimpcolor.h"
27 
28 #include "core-types.h"
29 
30 #include "gegl/gimp-gegl-apply-operation.h"
31 #include "gegl/gimp-gegl-mask.h"
32 #include "gegl/gimp-gegl-mask-combine.h"
33 #include "gegl/gimp-gegl-utils.h"
34 
35 #include "operations/layer-modes/gimp-layer-modes.h"
36 
37 #include "gimp.h"
38 #include "gimpchannel.h"
39 #include "gimpdrawable.h"
40 #include "gimpdrawable-bucket-fill.h"
41 #include "gimpfilloptions.h"
42 #include "gimpimage.h"
43 #include "gimppickable.h"
44 #include "gimppickable-contiguous-region.h"
45 
46 #include "gimp-intl.h"
47 
48 
49 /*  public functions  */
50 
51 void
gimp_drawable_bucket_fill(GimpDrawable * drawable,GimpFillOptions * options,gboolean fill_transparent,GimpSelectCriterion fill_criterion,gdouble threshold,gboolean sample_merged,gboolean diagonal_neighbors,gdouble seed_x,gdouble seed_y)52 gimp_drawable_bucket_fill (GimpDrawable         *drawable,
53                            GimpFillOptions      *options,
54                            gboolean              fill_transparent,
55                            GimpSelectCriterion   fill_criterion,
56                            gdouble               threshold,
57                            gboolean              sample_merged,
58                            gboolean              diagonal_neighbors,
59                            gdouble               seed_x,
60                            gdouble               seed_y)
61 {
62   GimpImage  *image;
63   GeglBuffer *buffer;
64   gdouble     mask_x;
65   gdouble     mask_y;
66   gint        width, height;
67 
68   g_return_if_fail (GIMP_IS_DRAWABLE (drawable));
69   g_return_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)));
70   g_return_if_fail (GIMP_IS_FILL_OPTIONS (options));
71 
72   image = gimp_item_get_image (GIMP_ITEM (drawable));
73 
74   gimp_set_busy (image->gimp);
75 
76   buffer = gimp_drawable_get_bucket_fill_buffer (drawable, options,
77                                                  fill_transparent, fill_criterion,
78                                                  threshold, FALSE, sample_merged,
79                                                  diagonal_neighbors,
80                                                  seed_x, seed_y, NULL,
81                                                  &mask_x, &mask_y, &width, &height);
82 
83   if (buffer)
84     {
85       /*  Apply it to the image  */
86       gimp_drawable_apply_buffer (drawable, buffer,
87                                   GEGL_RECTANGLE (0, 0, width, height),
88                                   TRUE, C_("undo-type", "Bucket Fill"),
89                                   gimp_context_get_opacity (GIMP_CONTEXT (options)),
90                                   gimp_context_get_paint_mode (GIMP_CONTEXT (options)),
91                                   GIMP_LAYER_COLOR_SPACE_AUTO,
92                                   GIMP_LAYER_COLOR_SPACE_AUTO,
93                                   gimp_layer_mode_get_paint_composite_mode
94                                   (gimp_context_get_paint_mode (GIMP_CONTEXT (options))),
95                                   NULL, (gint) mask_x, mask_y);
96       g_object_unref (buffer);
97 
98       gimp_drawable_update (drawable, mask_x, mask_y, width, height);
99     }
100 
101   gimp_unset_busy (image->gimp);
102 }
103 
104 /**
105  * gimp_drawable_get_bucket_fill_buffer:
106  * @drawable: the #GimpDrawable to edit.
107  * @options:
108  * @fill_transparent:
109  * @fill_criterion:
110  * @threshold:
111  * @show_all:
112  * @sample_merged:
113  * @diagonal_neighbors:
114  * @seed_x: X coordinate to start the fill.
115  * @seed_y: Y coordinate to start the fill.
116  * @mask_buffer: mask of the fill in-progress when in an interactive
117  *               filling process. Set to NULL if you need a one-time
118  *               fill.
119  * @mask_x: returned x bound of @mask_buffer.
120  * @mask_y: returned x bound of @mask_buffer.
121  * @mask_width: returned width bound of @mask_buffer.
122  * @mask_height: returned height bound of @mask_buffer.
123  *
124  * Creates the fill buffer for a bucket fill operation on @drawable,
125  * without actually applying it (if you want to apply it directly as a
126  * one-time operation, use gimp_drawable_bucket_fill() instead). If
127  * @mask_buffer is not NULL, the intermediate fill mask will also be
128  * returned. This fill mask can later be reused in successive calls to
129  * gimp_drawable_get_bucket_fill_buffer() for interactive filling.
130  *
131  * Returns: a fill buffer which can be directly applied to @drawable, or
132  *          used in a drawable filter as preview.
133  */
134 GeglBuffer *
gimp_drawable_get_bucket_fill_buffer(GimpDrawable * drawable,GimpFillOptions * options,gboolean fill_transparent,GimpSelectCriterion fill_criterion,gdouble threshold,gboolean show_all,gboolean sample_merged,gboolean diagonal_neighbors,gdouble seed_x,gdouble seed_y,GeglBuffer ** mask_buffer,gdouble * mask_x,gdouble * mask_y,gint * mask_width,gint * mask_height)135 gimp_drawable_get_bucket_fill_buffer (GimpDrawable         *drawable,
136                                       GimpFillOptions      *options,
137                                       gboolean              fill_transparent,
138                                       GimpSelectCriterion   fill_criterion,
139                                       gdouble               threshold,
140                                       gboolean              show_all,
141                                       gboolean              sample_merged,
142                                       gboolean              diagonal_neighbors,
143                                       gdouble               seed_x,
144                                       gdouble               seed_y,
145                                       GeglBuffer          **mask_buffer,
146                                       gdouble              *mask_x,
147                                       gdouble              *mask_y,
148                                       gint                 *mask_width,
149                                       gint                 *mask_height)
150 {
151   GimpImage    *image;
152   GimpPickable *pickable;
153   GeglBuffer   *buffer;
154   GeglBuffer   *new_mask;
155   gboolean      antialias;
156   gint          x, y, width, height;
157   gint          mask_offset_x = 0;
158   gint          mask_offset_y = 0;
159   gint          sel_x, sel_y, sel_width, sel_height;
160 
161   g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL);
162   g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)), NULL);
163   g_return_val_if_fail (GIMP_IS_FILL_OPTIONS (options), NULL);
164 
165   image = gimp_item_get_image (GIMP_ITEM (drawable));
166 
167   if (! gimp_item_mask_intersect (GIMP_ITEM (drawable),
168                                   &sel_x, &sel_y, &sel_width, &sel_height))
169     return NULL;
170 
171   if (mask_buffer && *mask_buffer && threshold == 0.0)
172     {
173       gfloat pixel;
174 
175       gegl_buffer_sample (*mask_buffer, seed_x, seed_y, NULL, &pixel,
176                           babl_format ("Y float"),
177                           GEGL_SAMPLER_NEAREST, GEGL_ABYSS_NONE);
178 
179       if (pixel != 0.0)
180         /* Already selected. This seed won't change the selection. */
181         return NULL;
182     }
183 
184   gimp_set_busy (image->gimp);
185 
186   if (sample_merged)
187     {
188       if (! show_all)
189         pickable = GIMP_PICKABLE (image);
190       else
191         pickable = GIMP_PICKABLE (gimp_image_get_projection (image));
192     }
193   else
194     {
195       pickable = GIMP_PICKABLE (drawable);
196     }
197 
198   antialias = gimp_fill_options_get_antialias (options);
199 
200   /*  Do a seed bucket fill...To do this, calculate a new
201    *  contiguous region.
202    */
203   new_mask = gimp_pickable_contiguous_region_by_seed (pickable,
204                                                       antialias,
205                                                       threshold,
206                                                       fill_transparent,
207                                                       fill_criterion,
208                                                       diagonal_neighbors,
209                                                       (gint) seed_x,
210                                                       (gint) seed_y);
211   if (mask_buffer && *mask_buffer)
212     {
213       gimp_gegl_mask_combine_buffer (new_mask, *mask_buffer,
214                                      GIMP_CHANNEL_OP_ADD, 0, 0);
215       g_object_unref (*mask_buffer);
216     }
217 
218   if (mask_buffer)
219     *mask_buffer = new_mask;
220 
221   gimp_gegl_mask_bounds (new_mask, &x, &y, &width, &height);
222   width  -= x;
223   height -= y;
224 
225   /*  If there is a selection, intersect the region bounds
226    *  with the selection bounds, to avoid processing areas
227    *  that are going to be masked out anyway.  The actual
228    *  intersection of the fill region with the mask data
229    *  happens when combining the fill buffer, in
230    *  gimp_drawable_apply_buffer().
231    */
232   if (! gimp_channel_is_empty (gimp_image_get_mask (image)))
233     {
234       gint off_x = 0;
235       gint off_y = 0;
236 
237       if (sample_merged)
238         gimp_item_get_offset (GIMP_ITEM (drawable), &off_x, &off_y);
239 
240       if (! gimp_rectangle_intersect (x, y, width, height,
241 
242                                       sel_x + off_x, sel_y + off_y,
243                                       sel_width,     sel_height,
244 
245                                       &x, &y, &width, &height))
246         {
247           /*  The fill region and the selection are disjoint; bail.  */
248 
249           if (! mask_buffer)
250             g_object_unref (new_mask);
251 
252           gimp_unset_busy (image->gimp);
253 
254           return NULL;
255         }
256     }
257 
258   /*  make sure we handle the mask correctly if it was sample-merged  */
259   if (sample_merged)
260     {
261       GimpItem *item = GIMP_ITEM (drawable);
262       gint      off_x, off_y;
263 
264       /*  Limit the channel bounds to the drawable's extents  */
265       gimp_item_get_offset (item, &off_x, &off_y);
266 
267       gimp_rectangle_intersect (x, y, width, height,
268 
269                                 off_x, off_y,
270                                 gimp_item_get_width (item),
271                                 gimp_item_get_height (item),
272 
273                                 &x, &y, &width, &height);
274 
275       mask_offset_x = x;
276       mask_offset_y = y;
277 
278       /*  translate mask bounds to drawable coords  */
279       x -= off_x;
280       y -= off_y;
281     }
282   else
283     {
284       mask_offset_x = x;
285       mask_offset_y = y;
286     }
287 
288   buffer = gimp_fill_options_create_buffer (options, drawable,
289                                             GEGL_RECTANGLE (0, 0,
290                                                             width, height),
291                                             -x, -y);
292 
293   gimp_gegl_apply_opacity (buffer, NULL, NULL, buffer, new_mask,
294                            -mask_offset_x, -mask_offset_y, 1.0);
295 
296   if (mask_x)
297     *mask_x = x;
298   if (mask_y)
299     *mask_y = y;
300   if (mask_width)
301     *mask_width = width;
302   if (mask_height)
303     *mask_height = height;
304 
305   if (! mask_buffer)
306     g_object_unref (new_mask);
307 
308   gimp_unset_busy (image->gimp);
309 
310   return buffer;
311 }
312 
313 /**
314  * gimp_drawable_get_line_art_fill_buffer:
315  * @drawable: the #GimpDrawable to edit.
316  * @line_art: the #GimpLineArt computed as fill source.
317  * @options: the #GimpFillOptions.
318  * @sample_merged:
319  * @seed_x: X coordinate to start the fill.
320  * @seed_y: Y coordinate to start the fill.
321  * @mask_buffer: mask of the fill in-progress when in an interactive
322  *               filling process. Set to NULL if you need a one-time
323  *               fill.
324  * @mask_x: returned x bound of @mask_buffer.
325  * @mask_y: returned x bound of @mask_buffer.
326  * @mask_width: returned width bound of @mask_buffer.
327  * @mask_height: returned height bound of @mask_buffer.
328  *
329  * Creates the fill buffer for a bucket fill operation on @drawable
330  * based on @line_art and @options, without actually applying it.
331  * If @mask_buffer is not NULL, the intermediate fill mask will also be
332  * returned. This fill mask can later be reused in successive calls to
333  * gimp_drawable_get_bucket_fill_buffer() for interactive filling.
334  *
335  * Returns: a fill buffer which can be directly applied to @drawable, or
336  *          used in a drawable filter as preview.
337  */
338 GeglBuffer *
gimp_drawable_get_line_art_fill_buffer(GimpDrawable * drawable,GimpLineArt * line_art,GimpFillOptions * options,gboolean sample_merged,gdouble seed_x,gdouble seed_y,GeglBuffer ** mask_buffer,gdouble * mask_x,gdouble * mask_y,gint * mask_width,gint * mask_height)339 gimp_drawable_get_line_art_fill_buffer (GimpDrawable     *drawable,
340                                         GimpLineArt      *line_art,
341                                         GimpFillOptions  *options,
342                                         gboolean          sample_merged,
343                                         gdouble           seed_x,
344                                         gdouble           seed_y,
345                                         GeglBuffer      **mask_buffer,
346                                         gdouble          *mask_x,
347                                         gdouble          *mask_y,
348                                         gint             *mask_width,
349                                         gint             *mask_height)
350 {
351   GimpImage  *image;
352   GeglBuffer *buffer;
353   GeglBuffer *new_mask;
354   gint        x, y, width, height;
355   gint        mask_offset_x = 0;
356   gint        mask_offset_y = 0;
357   gint        sel_x, sel_y, sel_width, sel_height;
358   gdouble     feather_radius;
359 
360   g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL);
361   g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)), NULL);
362   g_return_val_if_fail (GIMP_IS_FILL_OPTIONS (options), NULL);
363 
364   image = gimp_item_get_image (GIMP_ITEM (drawable));
365 
366   if (! gimp_item_mask_intersect (GIMP_ITEM (drawable),
367                                   &sel_x, &sel_y, &sel_width, &sel_height))
368     return NULL;
369 
370   if (mask_buffer && *mask_buffer)
371     {
372       gfloat pixel;
373 
374       gegl_buffer_sample (*mask_buffer, seed_x, seed_y, NULL, &pixel,
375                           babl_format ("Y float"),
376                           GEGL_SAMPLER_NEAREST, GEGL_ABYSS_NONE);
377 
378       if (pixel != 0.0)
379         /* Already selected. This seed won't change the selection. */
380         return NULL;
381     }
382 
383   gimp_set_busy (image->gimp);
384 
385   /*  Do a seed bucket fill...To do this, calculate a new
386    *  contiguous region.
387    */
388   new_mask = gimp_pickable_contiguous_region_by_line_art (NULL, line_art,
389                                                           (gint) seed_x,
390                                                           (gint) seed_y);
391   if (mask_buffer && *mask_buffer)
392     {
393       gimp_gegl_mask_combine_buffer (new_mask, *mask_buffer,
394                                      GIMP_CHANNEL_OP_ADD, 0, 0);
395       g_object_unref (*mask_buffer);
396     }
397   if (mask_buffer)
398     *mask_buffer = new_mask;
399 
400   gimp_gegl_mask_bounds (new_mask, &x, &y, &width, &height);
401   width  -= x;
402   height -= y;
403 
404   /*  If there is a selection, intersect the region bounds
405    *  with the selection bounds, to avoid processing areas
406    *  that are going to be masked out anyway.  The actual
407    *  intersection of the fill region with the mask data
408    *  happens when combining the fill buffer, in
409    *  gimp_drawable_apply_buffer().
410    */
411   if (! gimp_channel_is_empty (gimp_image_get_mask (image)))
412     {
413       gint off_x = 0;
414       gint off_y = 0;
415 
416       if (sample_merged)
417         gimp_item_get_offset (GIMP_ITEM (drawable), &off_x, &off_y);
418 
419       if (! gimp_rectangle_intersect (x, y, width, height,
420 
421                                       sel_x + off_x, sel_y + off_y,
422                                       sel_width,     sel_height,
423 
424                                       &x, &y, &width, &height))
425         {
426           if (! mask_buffer)
427             g_object_unref (new_mask);
428           /*  The fill region and the selection are disjoint; bail.  */
429           gimp_unset_busy (image->gimp);
430 
431           return NULL;
432         }
433     }
434 
435   /*  make sure we handle the mask correctly if it was sample-merged  */
436   if (sample_merged)
437     {
438       GimpItem *item = GIMP_ITEM (drawable);
439       gint      off_x, off_y;
440 
441       /*  Limit the channel bounds to the drawable's extents  */
442       gimp_item_get_offset (item, &off_x, &off_y);
443 
444       gimp_rectangle_intersect (x, y, width, height,
445 
446                                 off_x, off_y,
447                                 gimp_item_get_width (item),
448                                 gimp_item_get_height (item),
449 
450                                 &x, &y, &width, &height);
451 
452       mask_offset_x = x;
453       mask_offset_y = y;
454 
455       /*  translate mask bounds to drawable coords  */
456       x -= off_x;
457       y -= off_y;
458     }
459   else
460     {
461       mask_offset_x = x;
462       mask_offset_y = y;
463     }
464 
465   buffer = gimp_fill_options_create_buffer (options, drawable,
466                                             GEGL_RECTANGLE (0, 0,
467                                                             width, height),
468                                             -x, -y);
469 
470   gimp_gegl_apply_opacity (buffer, NULL, NULL, buffer, new_mask,
471                            -mask_offset_x, -mask_offset_y, 1.0);
472 
473   if (gimp_fill_options_get_feather (options, &feather_radius))
474     {
475       /* Feathering for the line art algorithm is not applied during
476        * mask creation because we just want to apply it on the borders
477        * of the mask at the end (since the mask can evolve, we don't
478        * want to actually touch it, but only the intermediate results).
479        */
480       gimp_gegl_apply_feather (buffer, NULL, NULL, buffer, NULL,
481                                feather_radius, feather_radius, TRUE);
482     }
483 
484   if (mask_x)
485     *mask_x = x;
486   if (mask_y)
487     *mask_y = y;
488   if (mask_width)
489     *mask_width = width;
490   if (mask_height)
491     *mask_height = height;
492 
493   if (! mask_buffer)
494     g_object_unref (new_mask);
495 
496   gimp_unset_busy (image->gimp);
497 
498   return buffer;
499 }
500