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