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 <string.h>
21
22 #include <cairo.h>
23 #include <gegl.h>
24 #include <gdk-pixbuf/gdk-pixbuf.h>
25
26 #include "libgimpbase/gimpbase.h"
27 #include "libgimpmath/gimpmath.h"
28 #include "libgimpcolor/gimpcolor.h"
29
30 #include "core-types.h"
31
32 #include "paint/gimppaintcore-stroke.h"
33 #include "paint/gimppaintoptions.h"
34
35 #include "gegl/gimp-gegl-apply-operation.h"
36 #include "gegl/gimp-gegl-loops.h"
37 #include "gegl/gimp-gegl-mask.h"
38 #include "gegl/gimp-gegl-nodes.h"
39
40 #include "gimp.h"
41 #include "gimp-utils.h"
42 #include "gimpboundary.h"
43 #include "gimpcontainer.h"
44 #include "gimperror.h"
45 #include "gimpimage.h"
46 #include "gimpimage-quick-mask.h"
47 #include "gimpimage-undo.h"
48 #include "gimpimage-undo-push.h"
49 #include "gimpchannel.h"
50 #include "gimpchannel-select.h"
51 #include "gimpcontext.h"
52 #include "gimpdrawable-fill.h"
53 #include "gimpdrawable-stroke.h"
54 #include "gimpmarshal.h"
55 #include "gimppaintinfo.h"
56 #include "gimppickable.h"
57 #include "gimpstrokeoptions.h"
58
59 #include "gimp-intl.h"
60
61
62 #define RGBA_EPSILON 1e-6
63
64 enum
65 {
66 COLOR_CHANGED,
67 LAST_SIGNAL
68 };
69
70
71 static void gimp_channel_pickable_iface_init (GimpPickableInterface *iface);
72
73 static void gimp_channel_finalize (GObject *object);
74
75 static gint64 gimp_channel_get_memsize (GimpObject *object,
76 gint64 *gui_size);
77
78 static gchar * gimp_channel_get_description (GimpViewable *viewable,
79 gchar **tooltip);
80
81 static GeglNode * gimp_channel_get_node (GimpFilter *filter);
82
83 static gboolean gimp_channel_is_attached (GimpItem *item);
84 static GimpItemTree * gimp_channel_get_tree (GimpItem *item);
85 static gboolean gimp_channel_bounds (GimpItem *item,
86 gdouble *x,
87 gdouble *y,
88 gdouble *width,
89 gdouble *height);
90 static GimpItem * gimp_channel_duplicate (GimpItem *item,
91 GType new_type);
92 static void gimp_channel_convert (GimpItem *item,
93 GimpImage *dest_image,
94 GType old_type);
95 static void gimp_channel_translate (GimpItem *item,
96 gdouble off_x,
97 gdouble off_y,
98 gboolean push_undo);
99 static void gimp_channel_scale (GimpItem *item,
100 gint new_width,
101 gint new_height,
102 gint new_offset_x,
103 gint new_offset_y,
104 GimpInterpolationType interp_type,
105 GimpProgress *progress);
106 static void gimp_channel_resize (GimpItem *item,
107 GimpContext *context,
108 GimpFillType fill_type,
109 gint new_width,
110 gint new_height,
111 gint offset_x,
112 gint offset_y);
113 static GimpTransformResize
114 gimp_channel_get_clip (GimpItem *item,
115 GimpTransformResize clip_result);
116 static gboolean gimp_channel_fill (GimpItem *item,
117 GimpDrawable *drawable,
118 GimpFillOptions *fill_options,
119 gboolean push_undo,
120 GimpProgress *progress,
121 GError **error);
122 static gboolean gimp_channel_stroke (GimpItem *item,
123 GimpDrawable *drawable,
124 GimpStrokeOptions *stroke_options,
125 gboolean push_undo,
126 GimpProgress *progress,
127 GError **error);
128 static void gimp_channel_to_selection (GimpItem *item,
129 GimpChannelOps op,
130 gboolean antialias,
131 gboolean feather,
132 gdouble feather_radius_x,
133 gdouble feather_radius_y);
134
135 static void gimp_channel_convert_type (GimpDrawable *drawable,
136 GimpImage *dest_image,
137 const Babl *new_format,
138 GimpColorProfile *dest_profile,
139 GeglDitherMethod layer_dither_type,
140 GeglDitherMethod mask_dither_type,
141 gboolean push_undo,
142 GimpProgress *progress);
143 static void gimp_channel_invalidate_boundary (GimpDrawable *drawable);
144 static void gimp_channel_get_active_components (GimpDrawable *drawable,
145 gboolean *active);
146
147 static void gimp_channel_set_buffer (GimpDrawable *drawable,
148 gboolean push_undo,
149 const gchar *undo_desc,
150 GeglBuffer *buffer,
151 const GeglRectangle *bounds);
152
153 static gdouble gimp_channel_get_opacity_at (GimpPickable *pickable,
154 gint x,
155 gint y);
156
157 static gboolean gimp_channel_real_boundary (GimpChannel *channel,
158 const GimpBoundSeg **segs_in,
159 const GimpBoundSeg **segs_out,
160 gint *num_segs_in,
161 gint *num_segs_out,
162 gint x1,
163 gint y1,
164 gint x2,
165 gint y2);
166 static gboolean gimp_channel_real_is_empty (GimpChannel *channel);
167 static void gimp_channel_real_feather (GimpChannel *channel,
168 gdouble radius_x,
169 gdouble radius_y,
170 gboolean edge_lock,
171 gboolean push_undo);
172 static void gimp_channel_real_sharpen (GimpChannel *channel,
173 gboolean push_undo);
174 static void gimp_channel_real_clear (GimpChannel *channel,
175 const gchar *undo_desc,
176 gboolean push_undo);
177 static void gimp_channel_real_all (GimpChannel *channel,
178 gboolean push_undo);
179 static void gimp_channel_real_invert (GimpChannel *channel,
180 gboolean push_undo);
181 static void gimp_channel_real_border (GimpChannel *channel,
182 gint radius_x,
183 gint radius_y,
184 GimpChannelBorderStyle style,
185 gboolean edge_lock,
186 gboolean push_undo);
187 static void gimp_channel_real_grow (GimpChannel *channel,
188 gint radius_x,
189 gint radius_y,
190 gboolean push_undo);
191 static void gimp_channel_real_shrink (GimpChannel *channel,
192 gint radius_x,
193 gint radius_y,
194 gboolean edge_lock,
195 gboolean push_undo);
196 static void gimp_channel_real_flood (GimpChannel *channel,
197 gboolean push_undo);
198
199
200 static void gimp_channel_buffer_changed (GeglBuffer *buffer,
201 const GeglRectangle *rect,
202 GimpChannel *channel);
203
204
205 G_DEFINE_TYPE_WITH_CODE (GimpChannel, gimp_channel, GIMP_TYPE_DRAWABLE,
206 G_IMPLEMENT_INTERFACE (GIMP_TYPE_PICKABLE,
207 gimp_channel_pickable_iface_init))
208
209 #define parent_class gimp_channel_parent_class
210
211 static guint channel_signals[LAST_SIGNAL] = { 0 };
212
213
214 static void
gimp_channel_class_init(GimpChannelClass * klass)215 gimp_channel_class_init (GimpChannelClass *klass)
216 {
217 GObjectClass *object_class = G_OBJECT_CLASS (klass);
218 GimpObjectClass *gimp_object_class = GIMP_OBJECT_CLASS (klass);
219 GimpViewableClass *viewable_class = GIMP_VIEWABLE_CLASS (klass);
220 GimpFilterClass *filter_class = GIMP_FILTER_CLASS (klass);
221 GimpItemClass *item_class = GIMP_ITEM_CLASS (klass);
222 GimpDrawableClass *drawable_class = GIMP_DRAWABLE_CLASS (klass);
223
224 channel_signals[COLOR_CHANGED] =
225 g_signal_new ("color-changed",
226 G_TYPE_FROM_CLASS (klass),
227 G_SIGNAL_RUN_FIRST,
228 G_STRUCT_OFFSET (GimpChannelClass, color_changed),
229 NULL, NULL,
230 gimp_marshal_VOID__VOID,
231 G_TYPE_NONE, 0);
232
233 object_class->finalize = gimp_channel_finalize;
234
235 gimp_object_class->get_memsize = gimp_channel_get_memsize;
236
237 viewable_class->get_description = gimp_channel_get_description;
238 viewable_class->default_icon_name = "gimp-channel";
239
240 filter_class->get_node = gimp_channel_get_node;
241
242 item_class->is_attached = gimp_channel_is_attached;
243 item_class->get_tree = gimp_channel_get_tree;
244 item_class->bounds = gimp_channel_bounds;
245 item_class->duplicate = gimp_channel_duplicate;
246 item_class->convert = gimp_channel_convert;
247 item_class->translate = gimp_channel_translate;
248 item_class->scale = gimp_channel_scale;
249 item_class->resize = gimp_channel_resize;
250 item_class->get_clip = gimp_channel_get_clip;
251 item_class->fill = gimp_channel_fill;
252 item_class->stroke = gimp_channel_stroke;
253 item_class->to_selection = gimp_channel_to_selection;
254 item_class->default_name = _("Channel");
255 item_class->rename_desc = C_("undo-type", "Rename Channel");
256 item_class->translate_desc = C_("undo-type", "Move Channel");
257 item_class->scale_desc = C_("undo-type", "Scale Channel");
258 item_class->resize_desc = C_("undo-type", "Resize Channel");
259 item_class->flip_desc = C_("undo-type", "Flip Channel");
260 item_class->rotate_desc = C_("undo-type", "Rotate Channel");
261 item_class->transform_desc = C_("undo-type", "Transform Channel");
262 item_class->fill_desc = C_("undo-type", "Fill Channel");
263 item_class->stroke_desc = C_("undo-type", "Stroke Channel");
264 item_class->to_selection_desc = C_("undo-type", "Channel to Selection");
265 item_class->reorder_desc = C_("undo-type", "Reorder Channel");
266 item_class->raise_desc = C_("undo-type", "Raise Channel");
267 item_class->raise_to_top_desc = C_("undo-type", "Raise Channel to Top");
268 item_class->lower_desc = C_("undo-type", "Lower Channel");
269 item_class->lower_to_bottom_desc = C_("undo-type", "Lower Channel to Bottom");
270 item_class->raise_failed = _("Channel cannot be raised higher.");
271 item_class->lower_failed = _("Channel cannot be lowered more.");
272
273 drawable_class->convert_type = gimp_channel_convert_type;
274 drawable_class->invalidate_boundary = gimp_channel_invalidate_boundary;
275 drawable_class->get_active_components = gimp_channel_get_active_components;
276 drawable_class->set_buffer = gimp_channel_set_buffer;
277
278 klass->boundary = gimp_channel_real_boundary;
279 klass->is_empty = gimp_channel_real_is_empty;
280 klass->feather = gimp_channel_real_feather;
281 klass->sharpen = gimp_channel_real_sharpen;
282 klass->clear = gimp_channel_real_clear;
283 klass->all = gimp_channel_real_all;
284 klass->invert = gimp_channel_real_invert;
285 klass->border = gimp_channel_real_border;
286 klass->grow = gimp_channel_real_grow;
287 klass->shrink = gimp_channel_real_shrink;
288 klass->flood = gimp_channel_real_flood;
289
290 klass->feather_desc = C_("undo-type", "Feather Channel");
291 klass->sharpen_desc = C_("undo-type", "Sharpen Channel");
292 klass->clear_desc = C_("undo-type", "Clear Channel");
293 klass->all_desc = C_("undo-type", "Fill Channel");
294 klass->invert_desc = C_("undo-type", "Invert Channel");
295 klass->border_desc = C_("undo-type", "Border Channel");
296 klass->grow_desc = C_("undo-type", "Grow Channel");
297 klass->shrink_desc = C_("undo-type", "Shrink Channel");
298 klass->flood_desc = C_("undo-type", "Flood Channel");
299 }
300
301 static void
gimp_channel_init(GimpChannel * channel)302 gimp_channel_init (GimpChannel *channel)
303 {
304 gimp_rgba_set (&channel->color, 0.0, 0.0, 0.0, GIMP_OPACITY_OPAQUE);
305
306 channel->show_masked = FALSE;
307
308 /* Selection mask variables */
309 channel->boundary_known = FALSE;
310 channel->segs_in = NULL;
311 channel->segs_out = NULL;
312 channel->num_segs_in = 0;
313 channel->num_segs_out = 0;
314 channel->empty = FALSE;
315 channel->bounds_known = FALSE;
316 channel->x1 = 0;
317 channel->y1 = 0;
318 channel->x2 = 0;
319 channel->y2 = 0;
320 }
321
322 static void
gimp_channel_pickable_iface_init(GimpPickableInterface * iface)323 gimp_channel_pickable_iface_init (GimpPickableInterface *iface)
324 {
325 iface->get_opacity_at = gimp_channel_get_opacity_at;
326 }
327
328 static void
gimp_channel_finalize(GObject * object)329 gimp_channel_finalize (GObject *object)
330 {
331 GimpChannel *channel = GIMP_CHANNEL (object);
332
333 g_clear_pointer (&channel->segs_in, g_free);
334 g_clear_pointer (&channel->segs_out, g_free);
335
336 G_OBJECT_CLASS (parent_class)->finalize (object);
337 }
338
339 static gint64
gimp_channel_get_memsize(GimpObject * object,gint64 * gui_size)340 gimp_channel_get_memsize (GimpObject *object,
341 gint64 *gui_size)
342 {
343 GimpChannel *channel = GIMP_CHANNEL (object);
344
345 *gui_size += channel->num_segs_in * sizeof (GimpBoundSeg);
346 *gui_size += channel->num_segs_out * sizeof (GimpBoundSeg);
347
348 return GIMP_OBJECT_CLASS (parent_class)->get_memsize (object, gui_size);
349 }
350
351 static gchar *
gimp_channel_get_description(GimpViewable * viewable,gchar ** tooltip)352 gimp_channel_get_description (GimpViewable *viewable,
353 gchar **tooltip)
354 {
355 if (! strcmp (GIMP_IMAGE_QUICK_MASK_NAME,
356 gimp_object_get_name (viewable)))
357 {
358 return g_strdup (_("Quick Mask"));
359 }
360
361 return GIMP_VIEWABLE_CLASS (parent_class)->get_description (viewable,
362 tooltip);
363 }
364
365 static GeglNode *
gimp_channel_get_node(GimpFilter * filter)366 gimp_channel_get_node (GimpFilter *filter)
367 {
368 GimpDrawable *drawable = GIMP_DRAWABLE (filter);
369 GimpChannel *channel = GIMP_CHANNEL (filter);
370 GeglNode *node;
371 GeglNode *source;
372 GeglNode *mode_node;
373 const Babl *color_format;
374
375 node = GIMP_FILTER_CLASS (parent_class)->get_node (filter);
376
377 source = gimp_drawable_get_source_node (drawable);
378 gegl_node_add_child (node, source);
379
380 g_warn_if_fail (channel->color_node == NULL);
381
382 if (gimp_drawable_get_linear (drawable))
383 color_format = babl_format ("RGBA float");
384 else
385 color_format = babl_format ("R'G'B'A float");
386
387 channel->color_node = gegl_node_new_child (node,
388 "operation", "gegl:color",
389 "format", color_format,
390 NULL);
391 gimp_gegl_node_set_color (channel->color_node,
392 &channel->color);
393
394 g_warn_if_fail (channel->mask_node == NULL);
395
396 channel->mask_node = gegl_node_new_child (node,
397 "operation", "gegl:opacity",
398 NULL);
399 gegl_node_connect_to (channel->color_node, "output",
400 channel->mask_node, "input");
401
402 g_warn_if_fail (channel->invert_node == NULL);
403
404 channel->invert_node = gegl_node_new_child (node,
405 "operation", "gegl:invert-linear",
406 NULL);
407
408 if (channel->show_masked)
409 {
410 gegl_node_connect_to (source, "output",
411 channel->invert_node, "input");
412 gegl_node_connect_to (channel->invert_node, "output",
413 channel->mask_node, "aux");
414 }
415 else
416 {
417 gegl_node_connect_to (source, "output",
418 channel->mask_node, "aux");
419 }
420
421 mode_node = gimp_drawable_get_mode_node (drawable);
422
423 gegl_node_connect_to (channel->mask_node, "output",
424 mode_node, "aux");
425
426 return node;
427 }
428
429 static gboolean
gimp_channel_is_attached(GimpItem * item)430 gimp_channel_is_attached (GimpItem *item)
431 {
432 GimpImage *image = gimp_item_get_image (item);
433
434 return (GIMP_IS_IMAGE (image) &&
435 gimp_container_have (gimp_image_get_channels (image),
436 GIMP_OBJECT (item)));
437 }
438
439 static GimpItemTree *
gimp_channel_get_tree(GimpItem * item)440 gimp_channel_get_tree (GimpItem *item)
441 {
442 if (gimp_item_is_attached (item))
443 {
444 GimpImage *image = gimp_item_get_image (item);
445
446 return gimp_image_get_channel_tree (image);
447 }
448
449 return NULL;
450 }
451
452 static gboolean
gimp_channel_bounds(GimpItem * item,gdouble * x,gdouble * y,gdouble * width,gdouble * height)453 gimp_channel_bounds (GimpItem *item,
454 gdouble *x,
455 gdouble *y,
456 gdouble *width,
457 gdouble *height)
458 {
459 GimpChannel *channel = GIMP_CHANNEL (item);
460
461 if (! channel->bounds_known)
462 {
463 GeglBuffer *buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (channel));
464
465 channel->empty = ! gimp_gegl_mask_bounds (buffer,
466 &channel->x1,
467 &channel->y1,
468 &channel->x2,
469 &channel->y2);
470
471 channel->bounds_known = TRUE;
472 }
473
474 *x = channel->x1;
475 *y = channel->y1;
476 *width = channel->x2 - channel->x1;
477 *height = channel->y2 - channel->y1;
478
479 return ! channel->empty;
480 }
481
482 static GimpItem *
gimp_channel_duplicate(GimpItem * item,GType new_type)483 gimp_channel_duplicate (GimpItem *item,
484 GType new_type)
485 {
486 GimpItem *new_item;
487
488 g_return_val_if_fail (g_type_is_a (new_type, GIMP_TYPE_DRAWABLE), NULL);
489
490 new_item = GIMP_ITEM_CLASS (parent_class)->duplicate (item, new_type);
491
492 if (GIMP_IS_CHANNEL (new_item))
493 {
494 GimpChannel *channel = GIMP_CHANNEL (item);
495 GimpChannel *new_channel = GIMP_CHANNEL (new_item);
496
497 new_channel->color = channel->color;
498 new_channel->show_masked = channel->show_masked;
499
500 /* selection mask variables */
501 new_channel->bounds_known = channel->bounds_known;
502 new_channel->empty = channel->empty;
503 new_channel->x1 = channel->x1;
504 new_channel->y1 = channel->y1;
505 new_channel->x2 = channel->x2;
506 new_channel->y2 = channel->y2;
507
508 if (new_type == GIMP_TYPE_CHANNEL)
509 {
510 /* 8-bit channel hack: make sure pixels between all sorts
511 * of channels of an image is always copied without any
512 * gamma conversion
513 */
514 GimpDrawable *new_drawable = GIMP_DRAWABLE (new_item);
515 GimpImage *image = gimp_item_get_image (item);
516 const Babl *format = gimp_image_get_channel_format (image);
517
518 if (format != gimp_drawable_get_format (new_drawable))
519 {
520 GeglBuffer *new_buffer;
521
522 new_buffer =
523 gegl_buffer_new (GEGL_RECTANGLE (0, 0,
524 gimp_item_get_width (new_item),
525 gimp_item_get_height (new_item)),
526 format);
527
528 gegl_buffer_set_format (new_buffer,
529 gimp_drawable_get_format (new_drawable));
530 gimp_gegl_buffer_copy (gimp_drawable_get_buffer (new_drawable),
531 NULL, GEGL_ABYSS_NONE,
532 new_buffer, NULL);
533 gegl_buffer_set_format (new_buffer, NULL);
534
535 gimp_drawable_set_buffer (new_drawable, FALSE, NULL, new_buffer);
536 g_object_unref (new_buffer);
537 }
538 }
539 }
540
541 return new_item;
542 }
543
544 static void
gimp_channel_convert(GimpItem * item,GimpImage * dest_image,GType old_type)545 gimp_channel_convert (GimpItem *item,
546 GimpImage *dest_image,
547 GType old_type)
548 {
549 GimpChannel *channel = GIMP_CHANNEL (item);
550 GimpDrawable *drawable = GIMP_DRAWABLE (item);
551
552 if (! gimp_drawable_is_gray (drawable))
553 {
554 gimp_drawable_convert_type (drawable, dest_image,
555 GIMP_GRAY,
556 gimp_image_get_precision (dest_image),
557 gimp_drawable_has_alpha (drawable),
558 NULL,
559 GEGL_DITHER_NONE, GEGL_DITHER_NONE,
560 FALSE, NULL);
561 }
562
563 if (gimp_drawable_has_alpha (drawable))
564 {
565 GeglBuffer *new_buffer;
566 const Babl *format;
567 GimpRGB background;
568
569 format = gimp_drawable_get_format_without_alpha (drawable);
570
571 new_buffer =
572 gegl_buffer_new (GEGL_RECTANGLE (0, 0,
573 gimp_item_get_width (item),
574 gimp_item_get_height (item)),
575 format);
576
577 gimp_rgba_set (&background, 0.0, 0.0, 0.0, 0.0);
578
579 gimp_gegl_apply_flatten (gimp_drawable_get_buffer (drawable),
580 NULL, NULL,
581 new_buffer, &background,
582 GIMP_LAYER_COLOR_SPACE_RGB_LINEAR);
583
584 gimp_drawable_set_buffer_full (drawable, FALSE, NULL,
585 new_buffer,
586 GEGL_RECTANGLE (
587 gimp_item_get_offset_x (item),
588 gimp_item_get_offset_y (item),
589 0, 0),
590 TRUE);
591 g_object_unref (new_buffer);
592 }
593
594 if (G_TYPE_FROM_INSTANCE (channel) == GIMP_TYPE_CHANNEL)
595 {
596 gint width = gimp_image_get_width (dest_image);
597 gint height = gimp_image_get_height (dest_image);
598
599 gimp_item_set_offset (item, 0, 0);
600
601 if (gimp_item_get_width (item) != width ||
602 gimp_item_get_height (item) != height)
603 {
604 gimp_item_resize (item, gimp_get_user_context (dest_image->gimp),
605 GIMP_FILL_TRANSPARENT,
606 width, height, 0, 0);
607 }
608 }
609
610 GIMP_ITEM_CLASS (parent_class)->convert (item, dest_image, old_type);
611 }
612
613 static void
gimp_channel_translate(GimpItem * item,gdouble off_x,gdouble off_y,gboolean push_undo)614 gimp_channel_translate (GimpItem *item,
615 gdouble off_x,
616 gdouble off_y,
617 gboolean push_undo)
618 {
619 GimpChannel *channel = GIMP_CHANNEL (item);
620 gint x, y, width, height;
621
622 gimp_item_bounds (GIMP_ITEM (channel), &x, &y, &width, &height);
623
624 /* update the old area */
625 gimp_drawable_update (GIMP_DRAWABLE (item), x, y, width, height);
626
627 if (push_undo)
628 gimp_channel_push_undo (channel, NULL);
629
630 if (gimp_rectangle_intersect (x + SIGNED_ROUND (off_x),
631 y + SIGNED_ROUND (off_y),
632 width, height,
633 0, 0,
634 gimp_item_get_width (GIMP_ITEM (channel)),
635 gimp_item_get_height (GIMP_ITEM (channel)),
636 &x, &y, &width, &height))
637 {
638 /* copy the portion of the mask we will keep to a temporary
639 * buffer
640 */
641 GeglBuffer *tmp_buffer =
642 gegl_buffer_new (GEGL_RECTANGLE (0, 0, width, height),
643 gimp_drawable_get_format (GIMP_DRAWABLE (channel)));
644
645 gimp_gegl_buffer_copy (gimp_drawable_get_buffer (GIMP_DRAWABLE (channel)),
646 GEGL_RECTANGLE (x - SIGNED_ROUND (off_x),
647 y - SIGNED_ROUND (off_y),
648 width, height),
649 GEGL_ABYSS_NONE,
650 tmp_buffer,
651 GEGL_RECTANGLE (0, 0, 0, 0));
652
653 /* clear the mask */
654 gegl_buffer_clear (gimp_drawable_get_buffer (GIMP_DRAWABLE (channel)),
655 NULL);
656
657 /* copy the temp mask back to the mask */
658 gimp_gegl_buffer_copy (tmp_buffer, NULL, GEGL_ABYSS_NONE,
659 gimp_drawable_get_buffer (GIMP_DRAWABLE (channel)),
660 GEGL_RECTANGLE (x, y, 0, 0));
661
662 /* free the temporary mask */
663 g_object_unref (tmp_buffer);
664
665 channel->x1 = x;
666 channel->y1 = y;
667 channel->x2 = x + width;
668 channel->y2 = y + height;
669 }
670 else
671 {
672 /* clear the mask */
673 gegl_buffer_clear (gimp_drawable_get_buffer (GIMP_DRAWABLE (channel)),
674 NULL);
675
676 channel->empty = TRUE;
677 channel->x1 = 0;
678 channel->y1 = 0;
679 channel->x2 = gimp_item_get_width (GIMP_ITEM (channel));
680 channel->y2 = gimp_item_get_height (GIMP_ITEM (channel));
681 }
682
683 /* update the new area */
684 gimp_drawable_update (GIMP_DRAWABLE (item),
685 channel->x1, channel->y1,
686 channel->x2 - channel->x1,
687 channel->y2 - channel->y1);
688 }
689
690 static void
gimp_channel_scale(GimpItem * item,gint new_width,gint new_height,gint new_offset_x,gint new_offset_y,GimpInterpolationType interpolation_type,GimpProgress * progress)691 gimp_channel_scale (GimpItem *item,
692 gint new_width,
693 gint new_height,
694 gint new_offset_x,
695 gint new_offset_y,
696 GimpInterpolationType interpolation_type,
697 GimpProgress *progress)
698 {
699 GimpChannel *channel = GIMP_CHANNEL (item);
700
701 if (G_TYPE_FROM_INSTANCE (item) == GIMP_TYPE_CHANNEL)
702 {
703 new_offset_x = 0;
704 new_offset_y = 0;
705 }
706
707 /* don't waste CPU cycles scaling an empty channel */
708 if (channel->bounds_known && channel->empty)
709 {
710 GimpDrawable *drawable = GIMP_DRAWABLE (item);
711 GeglBuffer *new_buffer;
712
713 new_buffer =
714 gegl_buffer_new (GEGL_RECTANGLE (0, 0, new_width, new_height),
715 gimp_drawable_get_format (drawable));
716
717 gimp_drawable_set_buffer_full (drawable,
718 gimp_item_is_attached (item), NULL,
719 new_buffer,
720 GEGL_RECTANGLE (new_offset_x, new_offset_y,
721 0, 0),
722 TRUE);
723 g_object_unref (new_buffer);
724
725 gimp_channel_clear (GIMP_CHANNEL (item), NULL, FALSE);
726 }
727 else
728 {
729 GIMP_ITEM_CLASS (parent_class)->scale (item, new_width, new_height,
730 new_offset_x, new_offset_y,
731 interpolation_type, progress);
732 }
733 }
734
735 static void
gimp_channel_resize(GimpItem * item,GimpContext * context,GimpFillType fill_type,gint new_width,gint new_height,gint offset_x,gint offset_y)736 gimp_channel_resize (GimpItem *item,
737 GimpContext *context,
738 GimpFillType fill_type,
739 gint new_width,
740 gint new_height,
741 gint offset_x,
742 gint offset_y)
743 {
744 GIMP_ITEM_CLASS (parent_class)->resize (item, context, GIMP_FILL_TRANSPARENT,
745 new_width, new_height,
746 offset_x, offset_y);
747
748 if (G_TYPE_FROM_INSTANCE (item) == GIMP_TYPE_CHANNEL)
749 {
750 gimp_item_set_offset (item, 0, 0);
751 }
752 }
753
754 static GimpTransformResize
gimp_channel_get_clip(GimpItem * item,GimpTransformResize clip_result)755 gimp_channel_get_clip (GimpItem *item,
756 GimpTransformResize clip_result)
757 {
758 return GIMP_TRANSFORM_RESIZE_CLIP;
759 }
760
761 static gboolean
gimp_channel_fill(GimpItem * item,GimpDrawable * drawable,GimpFillOptions * fill_options,gboolean push_undo,GimpProgress * progress,GError ** error)762 gimp_channel_fill (GimpItem *item,
763 GimpDrawable *drawable,
764 GimpFillOptions *fill_options,
765 gboolean push_undo,
766 GimpProgress *progress,
767 GError **error)
768 {
769 GimpChannel *channel = GIMP_CHANNEL (item);
770 const GimpBoundSeg *segs_in;
771 const GimpBoundSeg *segs_out;
772 gint n_segs_in;
773 gint n_segs_out;
774 gint offset_x, offset_y;
775
776 if (! gimp_channel_boundary (channel, &segs_in, &segs_out,
777 &n_segs_in, &n_segs_out,
778 0, 0, 0, 0))
779 {
780 g_set_error_literal (error, GIMP_ERROR, GIMP_FAILED,
781 _("Cannot fill empty channel."));
782 return FALSE;
783 }
784
785 gimp_item_get_offset (item, &offset_x, &offset_y);
786
787 gimp_drawable_fill_boundary (drawable,
788 fill_options,
789 segs_in, n_segs_in,
790 offset_x, offset_y,
791 push_undo);
792
793 return TRUE;
794 }
795
796 static gboolean
gimp_channel_stroke(GimpItem * item,GimpDrawable * drawable,GimpStrokeOptions * stroke_options,gboolean push_undo,GimpProgress * progress,GError ** error)797 gimp_channel_stroke (GimpItem *item,
798 GimpDrawable *drawable,
799 GimpStrokeOptions *stroke_options,
800 gboolean push_undo,
801 GimpProgress *progress,
802 GError **error)
803 {
804 GimpChannel *channel = GIMP_CHANNEL (item);
805 const GimpBoundSeg *segs_in;
806 const GimpBoundSeg *segs_out;
807 gint n_segs_in;
808 gint n_segs_out;
809 gboolean retval = FALSE;
810 gint offset_x, offset_y;
811
812 if (! gimp_channel_boundary (channel, &segs_in, &segs_out,
813 &n_segs_in, &n_segs_out,
814 0, 0, 0, 0))
815 {
816 g_set_error_literal (error, GIMP_ERROR, GIMP_FAILED,
817 _("Cannot stroke empty channel."));
818 return FALSE;
819 }
820
821 gimp_item_get_offset (item, &offset_x, &offset_y);
822
823 switch (gimp_stroke_options_get_method (stroke_options))
824 {
825 case GIMP_STROKE_LINE:
826 gimp_drawable_stroke_boundary (drawable,
827 stroke_options,
828 segs_in, n_segs_in,
829 offset_x, offset_y,
830 push_undo);
831 retval = TRUE;
832 break;
833
834 case GIMP_STROKE_PAINT_METHOD:
835 {
836 GimpPaintInfo *paint_info;
837 GimpPaintCore *core;
838 GimpPaintOptions *paint_options;
839 gboolean emulate_dynamics;
840
841 paint_info = gimp_context_get_paint_info (GIMP_CONTEXT (stroke_options));
842
843 core = g_object_new (paint_info->paint_type, NULL);
844
845 paint_options = gimp_stroke_options_get_paint_options (stroke_options);
846 emulate_dynamics = gimp_stroke_options_get_emulate_dynamics (stroke_options);
847
848 retval = gimp_paint_core_stroke_boundary (core, drawable,
849 paint_options,
850 emulate_dynamics,
851 segs_in, n_segs_in,
852 offset_x, offset_y,
853 push_undo, error);
854
855 g_object_unref (core);
856 }
857 break;
858
859 default:
860 g_return_val_if_reached (FALSE);
861 }
862
863 return retval;
864 }
865
866 static void
gimp_channel_to_selection(GimpItem * item,GimpChannelOps op,gboolean antialias,gboolean feather,gdouble feather_radius_x,gdouble feather_radius_y)867 gimp_channel_to_selection (GimpItem *item,
868 GimpChannelOps op,
869 gboolean antialias,
870 gboolean feather,
871 gdouble feather_radius_x,
872 gdouble feather_radius_y)
873 {
874 GimpChannel *channel = GIMP_CHANNEL (item);
875 GimpImage *image = gimp_item_get_image (item);
876 gint off_x, off_y;
877
878 gimp_item_get_offset (item, &off_x, &off_y);
879
880 gimp_channel_select_channel (gimp_image_get_mask (image),
881 GIMP_ITEM_GET_CLASS (item)->to_selection_desc,
882 channel, off_x, off_y,
883 op,
884 feather, feather_radius_x, feather_radius_x);
885 }
886
887 static void
gimp_channel_convert_type(GimpDrawable * drawable,GimpImage * dest_image,const Babl * new_format,GimpColorProfile * dest_profile,GeglDitherMethod layer_dither_type,GeglDitherMethod mask_dither_type,gboolean push_undo,GimpProgress * progress)888 gimp_channel_convert_type (GimpDrawable *drawable,
889 GimpImage *dest_image,
890 const Babl *new_format,
891 GimpColorProfile *dest_profile,
892 GeglDitherMethod layer_dither_type,
893 GeglDitherMethod mask_dither_type,
894 gboolean push_undo,
895 GimpProgress *progress)
896 {
897 GeglBuffer *dest_buffer;
898
899 dest_buffer =
900 gegl_buffer_new (GEGL_RECTANGLE (0, 0,
901 gimp_item_get_width (GIMP_ITEM (drawable)),
902 gimp_item_get_height (GIMP_ITEM (drawable))),
903 new_format);
904
905 if (mask_dither_type == GEGL_DITHER_NONE)
906 {
907 gimp_gegl_buffer_copy (gimp_drawable_get_buffer (drawable), NULL,
908 GEGL_ABYSS_NONE,
909 dest_buffer, NULL);
910 }
911 else
912 {
913 gint bits;
914
915 bits = (babl_format_get_bytes_per_pixel (new_format) * 8 /
916 babl_format_get_n_components (new_format));
917
918 gimp_gegl_apply_dither (gimp_drawable_get_buffer (drawable),
919 NULL, NULL,
920 dest_buffer, 1 << bits, mask_dither_type);
921 }
922
923 gimp_drawable_set_buffer (drawable, push_undo, NULL, dest_buffer);
924 g_object_unref (dest_buffer);
925 }
926
927 static void
gimp_channel_invalidate_boundary(GimpDrawable * drawable)928 gimp_channel_invalidate_boundary (GimpDrawable *drawable)
929 {
930 GimpChannel *channel = GIMP_CHANNEL (drawable);
931
932 channel->boundary_known = FALSE;
933 channel->bounds_known = FALSE;
934 }
935
936 static void
gimp_channel_get_active_components(GimpDrawable * drawable,gboolean * active)937 gimp_channel_get_active_components (GimpDrawable *drawable,
938 gboolean *active)
939 {
940 /* Make sure that the alpha channel is not valid. */
941 active[GRAY] = TRUE;
942 active[ALPHA_G] = FALSE;
943 }
944
945 static void
gimp_channel_set_buffer(GimpDrawable * drawable,gboolean push_undo,const gchar * undo_desc,GeglBuffer * buffer,const GeglRectangle * bounds)946 gimp_channel_set_buffer (GimpDrawable *drawable,
947 gboolean push_undo,
948 const gchar *undo_desc,
949 GeglBuffer *buffer,
950 const GeglRectangle *bounds)
951 {
952 GimpChannel *channel = GIMP_CHANNEL (drawable);
953 GeglBuffer *old_buffer = gimp_drawable_get_buffer (drawable);
954
955 if (old_buffer)
956 {
957 g_signal_handlers_disconnect_by_func (old_buffer,
958 gimp_channel_buffer_changed,
959 channel);
960 }
961
962 GIMP_DRAWABLE_CLASS (parent_class)->set_buffer (drawable,
963 push_undo, undo_desc,
964 buffer, bounds);
965
966 gegl_buffer_signal_connect (buffer, "changed",
967 G_CALLBACK (gimp_channel_buffer_changed),
968 channel);
969
970 if (gimp_filter_peek_node (GIMP_FILTER (channel)))
971 {
972 const Babl *color_format;
973
974 if (gimp_drawable_get_linear (drawable))
975 color_format = babl_format ("RGBA float");
976 else
977 color_format = babl_format ("R'G'B'A float");
978
979 gegl_node_set (channel->color_node,
980 "format", color_format,
981 NULL);
982 }
983 }
984
985 static gdouble
gimp_channel_get_opacity_at(GimpPickable * pickable,gint x,gint y)986 gimp_channel_get_opacity_at (GimpPickable *pickable,
987 gint x,
988 gint y)
989 {
990 GimpChannel *channel = GIMP_CHANNEL (pickable);
991 gdouble value = GIMP_OPACITY_TRANSPARENT;
992
993 if (x >= 0 && x < gimp_item_get_width (GIMP_ITEM (channel)) &&
994 y >= 0 && y < gimp_item_get_height (GIMP_ITEM (channel)))
995 {
996 if (! channel->bounds_known ||
997 (! channel->empty &&
998 x >= channel->x1 &&
999 x < channel->x2 &&
1000 y >= channel->y1 &&
1001 y < channel->y2))
1002 {
1003 gegl_buffer_sample (gimp_drawable_get_buffer (GIMP_DRAWABLE (channel)),
1004 x, y, NULL, &value, babl_format ("Y double"),
1005 GEGL_SAMPLER_NEAREST, GEGL_ABYSS_NONE);
1006 }
1007 }
1008
1009 return value;
1010 }
1011
1012 static gboolean
gimp_channel_real_boundary(GimpChannel * channel,const GimpBoundSeg ** segs_in,const GimpBoundSeg ** segs_out,gint * num_segs_in,gint * num_segs_out,gint x1,gint y1,gint x2,gint y2)1013 gimp_channel_real_boundary (GimpChannel *channel,
1014 const GimpBoundSeg **segs_in,
1015 const GimpBoundSeg **segs_out,
1016 gint *num_segs_in,
1017 gint *num_segs_out,
1018 gint x1,
1019 gint y1,
1020 gint x2,
1021 gint y2)
1022 {
1023 if (! channel->boundary_known)
1024 {
1025 gint x3, y3, x4, y4;
1026
1027 /* free the out of date boundary segments */
1028 g_free (channel->segs_in);
1029 g_free (channel->segs_out);
1030
1031 if (gimp_item_bounds (GIMP_ITEM (channel), &x3, &y3, &x4, &y4))
1032 {
1033 GeglBuffer *buffer;
1034 GeglRectangle rect = { x3, y3, x4, y4 };
1035
1036 x4 += x3;
1037 y4 += y3;
1038
1039 buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (channel));
1040
1041 channel->segs_out = gimp_boundary_find (buffer, &rect,
1042 babl_format ("Y float"),
1043 GIMP_BOUNDARY_IGNORE_BOUNDS,
1044 x1, y1, x2, y2,
1045 GIMP_BOUNDARY_HALF_WAY,
1046 &channel->num_segs_out);
1047 x1 = MAX (x1, x3);
1048 y1 = MAX (y1, y3);
1049 x2 = MIN (x2, x4);
1050 y2 = MIN (y2, y4);
1051
1052 if (x2 > x1 && y2 > y1)
1053 {
1054 channel->segs_in = gimp_boundary_find (buffer, NULL,
1055 babl_format ("Y float"),
1056 GIMP_BOUNDARY_WITHIN_BOUNDS,
1057 x1, y1, x2, y2,
1058 GIMP_BOUNDARY_HALF_WAY,
1059 &channel->num_segs_in);
1060 }
1061 else
1062 {
1063 channel->segs_in = NULL;
1064 channel->num_segs_in = 0;
1065 }
1066 }
1067 else
1068 {
1069 channel->segs_in = NULL;
1070 channel->segs_out = NULL;
1071 channel->num_segs_in = 0;
1072 channel->num_segs_out = 0;
1073 }
1074
1075 channel->boundary_known = TRUE;
1076 }
1077
1078 *segs_in = channel->segs_in;
1079 *segs_out = channel->segs_out;
1080 *num_segs_in = channel->num_segs_in;
1081 *num_segs_out = channel->num_segs_out;
1082
1083 return (! channel->empty);
1084 }
1085
1086 static gboolean
gimp_channel_real_is_empty(GimpChannel * channel)1087 gimp_channel_real_is_empty (GimpChannel *channel)
1088 {
1089 GeglBuffer *buffer;
1090
1091 if (channel->bounds_known)
1092 return channel->empty;
1093
1094 buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (channel));
1095
1096 if (! gimp_gegl_mask_is_empty (buffer))
1097 return FALSE;
1098
1099 /* The mask is empty, meaning we can set the bounds as known */
1100 g_clear_pointer (&channel->segs_in, g_free);
1101 g_clear_pointer (&channel->segs_out, g_free);
1102
1103 channel->empty = TRUE;
1104 channel->num_segs_in = 0;
1105 channel->num_segs_out = 0;
1106 channel->bounds_known = TRUE;
1107 channel->boundary_known = TRUE;
1108 channel->x1 = 0;
1109 channel->y1 = 0;
1110 channel->x2 = gimp_item_get_width (GIMP_ITEM (channel));
1111 channel->y2 = gimp_item_get_height (GIMP_ITEM (channel));
1112
1113 return TRUE;
1114 }
1115
1116 static void
gimp_channel_real_feather(GimpChannel * channel,gdouble radius_x,gdouble radius_y,gboolean edge_lock,gboolean push_undo)1117 gimp_channel_real_feather (GimpChannel *channel,
1118 gdouble radius_x,
1119 gdouble radius_y,
1120 gboolean edge_lock,
1121 gboolean push_undo)
1122 {
1123 gint x1, y1, x2, y2;
1124
1125 if (radius_x <= 0.0 && radius_y <= 0.0)
1126 return;
1127
1128 if (! gimp_item_bounds (GIMP_ITEM (channel), &x1, &y1, &x2, &y2))
1129 return;
1130
1131 x2 += x1;
1132 y2 += y1;
1133
1134 if (gimp_channel_is_empty (channel))
1135 return;
1136
1137 x1 = MAX (0, x1 - ceil (radius_x));
1138 y1 = MAX (0, y1 - ceil (radius_y));
1139
1140 x2 = MIN (gimp_item_get_width (GIMP_ITEM (channel)), x2 + ceil (radius_x));
1141 y2 = MIN (gimp_item_get_height (GIMP_ITEM (channel)), y2 + ceil (radius_y));
1142
1143 if (push_undo)
1144 gimp_channel_push_undo (channel,
1145 GIMP_CHANNEL_GET_CLASS (channel)->feather_desc);
1146
1147 gimp_gegl_apply_feather (gimp_drawable_get_buffer (GIMP_DRAWABLE (channel)),
1148 NULL, NULL,
1149 gimp_drawable_get_buffer (GIMP_DRAWABLE (channel)),
1150 GEGL_RECTANGLE (x1, y1, x2 - x1, y2 - y1),
1151 radius_x,
1152 radius_y,
1153 edge_lock);
1154
1155 gimp_drawable_update (GIMP_DRAWABLE (channel), 0, 0, -1, -1);
1156 }
1157
1158 static void
gimp_channel_real_sharpen(GimpChannel * channel,gboolean push_undo)1159 gimp_channel_real_sharpen (GimpChannel *channel,
1160 gboolean push_undo)
1161 {
1162 GimpDrawable *drawable = GIMP_DRAWABLE (channel);
1163
1164 if (push_undo)
1165 gimp_channel_push_undo (channel,
1166 GIMP_CHANNEL_GET_CLASS (channel)->sharpen_desc);
1167
1168 gimp_gegl_apply_threshold (gimp_drawable_get_buffer (drawable),
1169 NULL, NULL,
1170 gimp_drawable_get_buffer (drawable),
1171 0.5);
1172
1173 gimp_drawable_update (GIMP_DRAWABLE (channel), 0, 0, -1, -1);
1174 }
1175
1176 static void
gimp_channel_real_clear(GimpChannel * channel,const gchar * undo_desc,gboolean push_undo)1177 gimp_channel_real_clear (GimpChannel *channel,
1178 const gchar *undo_desc,
1179 gboolean push_undo)
1180 {
1181 GeglBuffer *buffer;
1182 GeglRectangle rect;
1183 GeglRectangle aligned_rect;
1184
1185 if (channel->bounds_known && channel->empty)
1186 return;
1187
1188 if (push_undo)
1189 {
1190 if (! undo_desc)
1191 undo_desc = GIMP_CHANNEL_GET_CLASS (channel)->clear_desc;
1192
1193 gimp_channel_push_undo (channel, undo_desc);
1194 }
1195
1196 buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (channel));
1197
1198 if (channel->bounds_known)
1199 {
1200 rect.x = channel->x1;
1201 rect.y = channel->y1;
1202 rect.width = channel->x2 - channel->x1;
1203 rect.height = channel->y2 - channel->y1;
1204 }
1205 else
1206 {
1207 rect.x = 0;
1208 rect.y = 0;
1209 rect.width = gimp_item_get_width (GIMP_ITEM (channel));
1210 rect.height = gimp_item_get_height (GIMP_ITEM (channel));
1211 }
1212
1213 gegl_rectangle_align_to_buffer (&aligned_rect, &rect, buffer,
1214 GEGL_RECTANGLE_ALIGNMENT_SUPERSET);
1215
1216 gegl_buffer_clear (buffer, &aligned_rect);
1217
1218 /* we know the bounds */
1219 channel->bounds_known = TRUE;
1220 channel->empty = TRUE;
1221 channel->x1 = 0;
1222 channel->y1 = 0;
1223 channel->x2 = gimp_item_get_width (GIMP_ITEM (channel));
1224 channel->y2 = gimp_item_get_height (GIMP_ITEM (channel));
1225
1226 gimp_drawable_update (GIMP_DRAWABLE (channel),
1227 rect.x, rect.y, rect.width, rect.height);
1228 }
1229
1230 static void
gimp_channel_real_all(GimpChannel * channel,gboolean push_undo)1231 gimp_channel_real_all (GimpChannel *channel,
1232 gboolean push_undo)
1233 {
1234 GeglColor *color;
1235
1236 if (push_undo)
1237 gimp_channel_push_undo (channel,
1238 GIMP_CHANNEL_GET_CLASS (channel)->all_desc);
1239
1240 /* clear the channel */
1241 color = gegl_color_new ("#fff");
1242 gegl_buffer_set_color (gimp_drawable_get_buffer (GIMP_DRAWABLE (channel)),
1243 NULL, color);
1244 g_object_unref (color);
1245
1246 /* we know the bounds */
1247 channel->bounds_known = TRUE;
1248 channel->empty = FALSE;
1249 channel->x1 = 0;
1250 channel->y1 = 0;
1251 channel->x2 = gimp_item_get_width (GIMP_ITEM (channel));
1252 channel->y2 = gimp_item_get_height (GIMP_ITEM (channel));
1253
1254 gimp_drawable_update (GIMP_DRAWABLE (channel), 0, 0, -1, -1);
1255 }
1256
1257 static void
gimp_channel_real_invert(GimpChannel * channel,gboolean push_undo)1258 gimp_channel_real_invert (GimpChannel *channel,
1259 gboolean push_undo)
1260 {
1261 GimpDrawable *drawable = GIMP_DRAWABLE (channel);
1262
1263 if (push_undo)
1264 gimp_channel_push_undo (channel,
1265 GIMP_CHANNEL_GET_CLASS (channel)->invert_desc);
1266
1267 if (channel->bounds_known && channel->empty)
1268 {
1269 gimp_channel_all (channel, FALSE);
1270 }
1271 else
1272 {
1273 gimp_gegl_apply_invert_linear (gimp_drawable_get_buffer (drawable),
1274 NULL, NULL,
1275 gimp_drawable_get_buffer (drawable));
1276
1277 gimp_drawable_update (GIMP_DRAWABLE (channel), 0, 0, -1, -1);
1278 }
1279 }
1280
1281 static void
gimp_channel_real_border(GimpChannel * channel,gint radius_x,gint radius_y,GimpChannelBorderStyle style,gboolean edge_lock,gboolean push_undo)1282 gimp_channel_real_border (GimpChannel *channel,
1283 gint radius_x,
1284 gint radius_y,
1285 GimpChannelBorderStyle style,
1286 gboolean edge_lock,
1287 gboolean push_undo)
1288 {
1289 gint x1, y1, x2, y2;
1290
1291 if (radius_x == 0 && radius_y == 0)
1292 {
1293 /* The relevant GEGL operations require radius_x and radius_y to be > 0.
1294 * When both are 0 (currently can only be achieved by the user through
1295 * PDB), the effect should be to clear the channel.
1296 */
1297 gimp_channel_clear (channel,
1298 GIMP_CHANNEL_GET_CLASS (channel)->border_desc,
1299 push_undo);
1300 return;
1301 }
1302 else if (radius_x <= 0 || radius_y <= 0)
1303 {
1304 /* FIXME: Implement the case where only one of radius_x and radius_y is 0.
1305 * Currently, should never happen.
1306 */
1307 g_return_if_reached();
1308 }
1309
1310 if (! gimp_item_bounds (GIMP_ITEM (channel), &x1, &y1, &x2, &y2))
1311 return;
1312
1313 x2 += x1;
1314 y2 += y1;
1315
1316 if (gimp_channel_is_empty (channel))
1317 return;
1318
1319 if (x1 - radius_x < 0)
1320 x1 = 0;
1321 else
1322 x1 -= radius_x;
1323
1324 if (x2 + radius_x > gimp_item_get_width (GIMP_ITEM (channel)))
1325 x2 = gimp_item_get_width (GIMP_ITEM (channel));
1326 else
1327 x2 += radius_x;
1328
1329 if (y1 - radius_y < 0)
1330 y1 = 0;
1331 else
1332 y1 -= radius_y;
1333
1334 if (y2 + radius_y > gimp_item_get_height (GIMP_ITEM (channel)))
1335 y2 = gimp_item_get_height (GIMP_ITEM (channel));
1336 else
1337 y2 += radius_y;
1338
1339 if (push_undo)
1340 gimp_channel_push_undo (channel,
1341 GIMP_CHANNEL_GET_CLASS (channel)->border_desc);
1342
1343 gimp_gegl_apply_border (gimp_drawable_get_buffer (GIMP_DRAWABLE (channel)),
1344 NULL, NULL,
1345 gimp_drawable_get_buffer (GIMP_DRAWABLE (channel)),
1346 GEGL_RECTANGLE (x1, y1, x2 - x1, y2 - y1),
1347 radius_x, radius_y, style, edge_lock);
1348
1349 gimp_drawable_update (GIMP_DRAWABLE (channel), 0, 0, -1, -1);
1350 }
1351
1352 static void
gimp_channel_real_grow(GimpChannel * channel,gint radius_x,gint radius_y,gboolean push_undo)1353 gimp_channel_real_grow (GimpChannel *channel,
1354 gint radius_x,
1355 gint radius_y,
1356 gboolean push_undo)
1357 {
1358 gint x1, y1, x2, y2;
1359
1360 if (radius_x == 0 && radius_y == 0)
1361 return;
1362
1363 if (radius_x <= 0 && radius_y <= 0)
1364 {
1365 gimp_channel_shrink (channel, -radius_x, -radius_y, FALSE, push_undo);
1366 return;
1367 }
1368
1369 if (radius_x < 0 || radius_y < 0)
1370 return;
1371
1372 if (! gimp_item_bounds (GIMP_ITEM (channel), &x1, &y1, &x2, &y2))
1373 return;
1374
1375 x2 += x1;
1376 y2 += y1;
1377
1378 if (gimp_channel_is_empty (channel))
1379 return;
1380
1381 if (x1 - radius_x > 0)
1382 x1 = x1 - radius_x;
1383 else
1384 x1 = 0;
1385
1386 if (y1 - radius_y > 0)
1387 y1 = y1 - radius_y;
1388 else
1389 y1 = 0;
1390
1391 if (x2 + radius_x < gimp_item_get_width (GIMP_ITEM (channel)))
1392 x2 = x2 + radius_x;
1393 else
1394 x2 = gimp_item_get_width (GIMP_ITEM (channel));
1395
1396 if (y2 + radius_y < gimp_item_get_height (GIMP_ITEM (channel)))
1397 y2 = y2 + radius_y;
1398 else
1399 y2 = gimp_item_get_height (GIMP_ITEM (channel));
1400
1401 if (push_undo)
1402 gimp_channel_push_undo (channel,
1403 GIMP_CHANNEL_GET_CLASS (channel)->grow_desc);
1404
1405 gimp_gegl_apply_grow (gimp_drawable_get_buffer (GIMP_DRAWABLE (channel)),
1406 NULL, NULL,
1407 gimp_drawable_get_buffer (GIMP_DRAWABLE (channel)),
1408 GEGL_RECTANGLE (x1, y1, x2 - x1, y2 - y1),
1409 radius_x, radius_y);
1410
1411 gimp_drawable_update (GIMP_DRAWABLE (channel), 0, 0, -1, -1);
1412 }
1413
1414 static void
gimp_channel_real_shrink(GimpChannel * channel,gint radius_x,gint radius_y,gboolean edge_lock,gboolean push_undo)1415 gimp_channel_real_shrink (GimpChannel *channel,
1416 gint radius_x,
1417 gint radius_y,
1418 gboolean edge_lock,
1419 gboolean push_undo)
1420 {
1421 gint x1, y1, x2, y2;
1422
1423 if (radius_x == 0 && radius_y == 0)
1424 return;
1425
1426 if (radius_x <= 0 && radius_y <= 0)
1427 {
1428 gimp_channel_grow (channel, -radius_x, -radius_y, push_undo);
1429 return;
1430 }
1431
1432 if (radius_x < 0 || radius_y < 0)
1433 return;
1434
1435 if (! gimp_item_bounds (GIMP_ITEM (channel), &x1, &y1, &x2, &y2))
1436 return;
1437
1438 x2 += x1;
1439 y2 += y1;
1440
1441 if (gimp_channel_is_empty (channel))
1442 return;
1443
1444 if (x1 > 0)
1445 x1--;
1446 if (y1 > 0)
1447 y1--;
1448 if (x2 < gimp_item_get_width (GIMP_ITEM (channel)))
1449 x2++;
1450 if (y2 < gimp_item_get_height (GIMP_ITEM (channel)))
1451 y2++;
1452
1453 if (push_undo)
1454 gimp_channel_push_undo (channel,
1455 GIMP_CHANNEL_GET_CLASS (channel)->shrink_desc);
1456
1457 gimp_gegl_apply_shrink (gimp_drawable_get_buffer (GIMP_DRAWABLE (channel)),
1458 NULL, NULL,
1459 gimp_drawable_get_buffer (GIMP_DRAWABLE (channel)),
1460 GEGL_RECTANGLE (x1, y1, x2 - x1, y2 - y1),
1461 radius_x, radius_y, edge_lock);
1462
1463 gimp_drawable_update (GIMP_DRAWABLE (channel), 0, 0, -1, -1);
1464 }
1465
1466 static void
gimp_channel_real_flood(GimpChannel * channel,gboolean push_undo)1467 gimp_channel_real_flood (GimpChannel *channel,
1468 gboolean push_undo)
1469 {
1470 gint x, y, width, height;
1471
1472 if (! gimp_item_bounds (GIMP_ITEM (channel), &x, &y, &width, &height))
1473 return;
1474
1475 if (gimp_channel_is_empty (channel))
1476 return;
1477
1478 if (push_undo)
1479 gimp_channel_push_undo (channel,
1480 GIMP_CHANNEL_GET_CLASS (channel)->flood_desc);
1481
1482 gimp_gegl_apply_flood (gimp_drawable_get_buffer (GIMP_DRAWABLE (channel)),
1483 NULL, NULL,
1484 gimp_drawable_get_buffer (GIMP_DRAWABLE (channel)),
1485 GEGL_RECTANGLE (x, y, width, height));
1486
1487 gimp_drawable_update (GIMP_DRAWABLE (channel), x, y, width, height);
1488 }
1489
1490 static void
gimp_channel_buffer_changed(GeglBuffer * buffer,const GeglRectangle * rect,GimpChannel * channel)1491 gimp_channel_buffer_changed (GeglBuffer *buffer,
1492 const GeglRectangle *rect,
1493 GimpChannel *channel)
1494 {
1495 gimp_drawable_invalidate_boundary (GIMP_DRAWABLE (channel));
1496 }
1497
1498
1499 /* public functions */
1500
1501 GimpChannel *
gimp_channel_new(GimpImage * image,gint width,gint height,const gchar * name,const GimpRGB * color)1502 gimp_channel_new (GimpImage *image,
1503 gint width,
1504 gint height,
1505 const gchar *name,
1506 const GimpRGB *color)
1507 {
1508 GimpChannel *channel;
1509
1510 g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL);
1511
1512 channel =
1513 GIMP_CHANNEL (gimp_drawable_new (GIMP_TYPE_CHANNEL,
1514 image, name,
1515 0, 0, width, height,
1516 gimp_image_get_channel_format (image)));
1517
1518 if (color)
1519 channel->color = *color;
1520
1521 channel->show_masked = TRUE;
1522
1523 /* selection mask variables */
1524 channel->x2 = width;
1525 channel->y2 = height;
1526
1527 return channel;
1528 }
1529
1530 GimpChannel *
gimp_channel_new_from_buffer(GimpImage * image,GeglBuffer * buffer,const gchar * name,const GimpRGB * color)1531 gimp_channel_new_from_buffer (GimpImage *image,
1532 GeglBuffer *buffer,
1533 const gchar *name,
1534 const GimpRGB *color)
1535 {
1536 GimpChannel *channel;
1537 GeglBuffer *dest;
1538
1539 g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL);
1540 g_return_val_if_fail (GEGL_IS_BUFFER (buffer), NULL);
1541
1542 channel = gimp_channel_new (image,
1543 gegl_buffer_get_width (buffer),
1544 gegl_buffer_get_height (buffer),
1545 name, color);
1546
1547 dest = gimp_drawable_get_buffer (GIMP_DRAWABLE (channel));
1548 gimp_gegl_buffer_copy (buffer, NULL, GEGL_ABYSS_NONE, dest, NULL);
1549
1550 return channel;
1551 }
1552
1553 GimpChannel *
gimp_channel_new_from_alpha(GimpImage * image,GimpDrawable * drawable,const gchar * name,const GimpRGB * color)1554 gimp_channel_new_from_alpha (GimpImage *image,
1555 GimpDrawable *drawable,
1556 const gchar *name,
1557 const GimpRGB *color)
1558 {
1559 GimpChannel *channel;
1560 GeglBuffer *dest_buffer;
1561 gint width;
1562 gint height;
1563
1564 g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL);
1565 g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL);
1566 g_return_val_if_fail (gimp_drawable_has_alpha (drawable), NULL);
1567
1568 width = gimp_item_get_width (GIMP_ITEM (drawable));
1569 height = gimp_item_get_height (GIMP_ITEM (drawable));
1570
1571 channel = gimp_channel_new (image, width, height, name, color);
1572
1573 gimp_channel_clear (channel, NULL, FALSE);
1574
1575 dest_buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (channel));
1576
1577 gegl_buffer_set_format (dest_buffer,
1578 gimp_drawable_get_component_format (drawable,
1579 GIMP_CHANNEL_ALPHA));
1580 gimp_gegl_buffer_copy (gimp_drawable_get_buffer (drawable), NULL,
1581 GEGL_ABYSS_NONE,
1582 dest_buffer, NULL);
1583 gegl_buffer_set_format (dest_buffer, NULL);
1584
1585 return channel;
1586 }
1587
1588 GimpChannel *
gimp_channel_new_from_component(GimpImage * image,GimpChannelType type,const gchar * name,const GimpRGB * color)1589 gimp_channel_new_from_component (GimpImage *image,
1590 GimpChannelType type,
1591 const gchar *name,
1592 const GimpRGB *color)
1593 {
1594 GimpChannel *channel;
1595 GeglBuffer *src_buffer;
1596 GeglBuffer *dest_buffer;
1597 gint width;
1598 gint height;
1599 const Babl *format;
1600
1601 g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL);
1602
1603 format = gimp_image_get_component_format (image, type);
1604
1605 g_return_val_if_fail (format != NULL, NULL);
1606
1607 gimp_pickable_flush (GIMP_PICKABLE (image));
1608
1609 src_buffer = gimp_pickable_get_buffer (GIMP_PICKABLE (image));
1610 width = gegl_buffer_get_width (src_buffer);
1611 height = gegl_buffer_get_height (src_buffer);
1612
1613 channel = gimp_channel_new (image, width, height, name, color);
1614
1615 dest_buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (channel));
1616
1617 gegl_buffer_set_format (dest_buffer, format);
1618 gimp_gegl_buffer_copy (src_buffer, NULL, GEGL_ABYSS_NONE, dest_buffer, NULL);
1619 gegl_buffer_set_format (dest_buffer, NULL);
1620
1621 return channel;
1622 }
1623
1624 GimpChannel *
gimp_channel_get_parent(GimpChannel * channel)1625 gimp_channel_get_parent (GimpChannel *channel)
1626 {
1627 g_return_val_if_fail (GIMP_IS_CHANNEL (channel), NULL);
1628
1629 return GIMP_CHANNEL (gimp_viewable_get_parent (GIMP_VIEWABLE (channel)));
1630 }
1631
1632 void
gimp_channel_set_color(GimpChannel * channel,const GimpRGB * color,gboolean push_undo)1633 gimp_channel_set_color (GimpChannel *channel,
1634 const GimpRGB *color,
1635 gboolean push_undo)
1636 {
1637 g_return_if_fail (GIMP_IS_CHANNEL (channel));
1638 g_return_if_fail (color != NULL);
1639
1640 if (gimp_rgba_distance (&channel->color, color) > RGBA_EPSILON)
1641 {
1642 if (push_undo && gimp_item_is_attached (GIMP_ITEM (channel)))
1643 {
1644 GimpImage *image = gimp_item_get_image (GIMP_ITEM (channel));
1645
1646 gimp_image_undo_push_channel_color (image, C_("undo-type", "Set Channel Color"),
1647 channel);
1648 }
1649
1650 channel->color = *color;
1651
1652 if (gimp_filter_peek_node (GIMP_FILTER (channel)))
1653 {
1654 gimp_gegl_node_set_color (channel->color_node,
1655 &channel->color);
1656 }
1657
1658 gimp_drawable_update (GIMP_DRAWABLE (channel), 0, 0, -1, -1);
1659
1660 g_signal_emit (channel, channel_signals[COLOR_CHANGED], 0);
1661 }
1662 }
1663
1664 void
gimp_channel_get_color(GimpChannel * channel,GimpRGB * color)1665 gimp_channel_get_color (GimpChannel *channel,
1666 GimpRGB *color)
1667 {
1668 g_return_if_fail (GIMP_IS_CHANNEL (channel));
1669 g_return_if_fail (color != NULL);
1670
1671 *color = channel->color;
1672 }
1673
1674 gdouble
gimp_channel_get_opacity(GimpChannel * channel)1675 gimp_channel_get_opacity (GimpChannel *channel)
1676 {
1677 g_return_val_if_fail (GIMP_IS_CHANNEL (channel), GIMP_OPACITY_TRANSPARENT);
1678
1679 return channel->color.a;
1680 }
1681
1682 void
gimp_channel_set_opacity(GimpChannel * channel,gdouble opacity,gboolean push_undo)1683 gimp_channel_set_opacity (GimpChannel *channel,
1684 gdouble opacity,
1685 gboolean push_undo)
1686 {
1687 g_return_if_fail (GIMP_IS_CHANNEL (channel));
1688
1689 opacity = CLAMP (opacity, GIMP_OPACITY_TRANSPARENT, GIMP_OPACITY_OPAQUE);
1690
1691 if (channel->color.a != opacity)
1692 {
1693 if (push_undo && gimp_item_is_attached (GIMP_ITEM (channel)))
1694 {
1695 GimpImage *image = gimp_item_get_image (GIMP_ITEM (channel));
1696
1697 gimp_image_undo_push_channel_color (image, C_("undo-type", "Set Channel Opacity"),
1698 channel);
1699 }
1700
1701 channel->color.a = opacity;
1702
1703 if (gimp_filter_peek_node (GIMP_FILTER (channel)))
1704 {
1705 gimp_gegl_node_set_color (channel->color_node,
1706 &channel->color);
1707 }
1708
1709 gimp_drawable_update (GIMP_DRAWABLE (channel), 0, 0, -1, -1);
1710
1711 g_signal_emit (channel, channel_signals[COLOR_CHANGED], 0);
1712 }
1713 }
1714
1715 gboolean
gimp_channel_get_show_masked(GimpChannel * channel)1716 gimp_channel_get_show_masked (GimpChannel *channel)
1717 {
1718 g_return_val_if_fail (GIMP_IS_CHANNEL (channel), FALSE);
1719
1720 return channel->show_masked;
1721 }
1722
1723 void
gimp_channel_set_show_masked(GimpChannel * channel,gboolean show_masked)1724 gimp_channel_set_show_masked (GimpChannel *channel,
1725 gboolean show_masked)
1726 {
1727 g_return_if_fail (GIMP_IS_CHANNEL (channel));
1728
1729 if (show_masked != channel->show_masked)
1730 {
1731 channel->show_masked = show_masked ? TRUE : FALSE;
1732
1733 if (channel->invert_node)
1734 {
1735 GeglNode *source;
1736
1737 source = gimp_drawable_get_source_node (GIMP_DRAWABLE (channel));
1738
1739 if (channel->show_masked)
1740 {
1741 gegl_node_connect_to (source, "output",
1742 channel->invert_node, "input");
1743 gegl_node_connect_to (channel->invert_node, "output",
1744 channel->mask_node, "aux");
1745 }
1746 else
1747 {
1748 gegl_node_disconnect (channel->invert_node, "input");
1749
1750 gegl_node_connect_to (source, "output",
1751 channel->mask_node, "aux");
1752 }
1753 }
1754
1755 gimp_drawable_update (GIMP_DRAWABLE (channel), 0, 0, -1, -1);
1756 }
1757 }
1758
1759 void
gimp_channel_push_undo(GimpChannel * channel,const gchar * undo_desc)1760 gimp_channel_push_undo (GimpChannel *channel,
1761 const gchar *undo_desc)
1762 {
1763 g_return_if_fail (GIMP_IS_CHANNEL (channel));
1764 g_return_if_fail (gimp_item_is_attached (GIMP_ITEM (channel)));
1765
1766 gimp_image_undo_push_mask (gimp_item_get_image (GIMP_ITEM (channel)),
1767 undo_desc, channel);
1768 }
1769
1770
1771 /******************************/
1772 /* selection mask functions */
1773 /******************************/
1774
1775 GimpChannel *
gimp_channel_new_mask(GimpImage * image,gint width,gint height)1776 gimp_channel_new_mask (GimpImage *image,
1777 gint width,
1778 gint height)
1779 {
1780 GimpChannel *channel;
1781
1782 g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL);
1783
1784 channel =
1785 GIMP_CHANNEL (gimp_drawable_new (GIMP_TYPE_CHANNEL,
1786 image, _("Selection Mask"),
1787 0, 0, width, height,
1788 gimp_image_get_mask_format (image)));
1789
1790 channel->show_masked = TRUE;
1791 channel->x2 = width;
1792 channel->y2 = height;
1793
1794 gegl_buffer_clear (gimp_drawable_get_buffer (GIMP_DRAWABLE (channel)),
1795 NULL);
1796
1797 return channel;
1798 }
1799
1800 gboolean
gimp_channel_boundary(GimpChannel * channel,const GimpBoundSeg ** segs_in,const GimpBoundSeg ** segs_out,gint * num_segs_in,gint * num_segs_out,gint x1,gint y1,gint x2,gint y2)1801 gimp_channel_boundary (GimpChannel *channel,
1802 const GimpBoundSeg **segs_in,
1803 const GimpBoundSeg **segs_out,
1804 gint *num_segs_in,
1805 gint *num_segs_out,
1806 gint x1,
1807 gint y1,
1808 gint x2,
1809 gint y2)
1810 {
1811 g_return_val_if_fail (GIMP_IS_CHANNEL (channel), FALSE);
1812 g_return_val_if_fail (segs_in != NULL, FALSE);
1813 g_return_val_if_fail (segs_out != NULL, FALSE);
1814 g_return_val_if_fail (num_segs_in != NULL, FALSE);
1815 g_return_val_if_fail (num_segs_out != NULL, FALSE);
1816
1817 return GIMP_CHANNEL_GET_CLASS (channel)->boundary (channel,
1818 segs_in, segs_out,
1819 num_segs_in, num_segs_out,
1820 x1, y1,
1821 x2, y2);
1822 }
1823
1824 gboolean
gimp_channel_is_empty(GimpChannel * channel)1825 gimp_channel_is_empty (GimpChannel *channel)
1826 {
1827 g_return_val_if_fail (GIMP_IS_CHANNEL (channel), FALSE);
1828
1829 return GIMP_CHANNEL_GET_CLASS (channel)->is_empty (channel);
1830 }
1831
1832 void
gimp_channel_feather(GimpChannel * channel,gdouble radius_x,gdouble radius_y,gboolean edge_lock,gboolean push_undo)1833 gimp_channel_feather (GimpChannel *channel,
1834 gdouble radius_x,
1835 gdouble radius_y,
1836 gboolean edge_lock,
1837 gboolean push_undo)
1838 {
1839 g_return_if_fail (GIMP_IS_CHANNEL (channel));
1840
1841 if (! gimp_item_is_attached (GIMP_ITEM (channel)))
1842 push_undo = FALSE;
1843
1844 GIMP_CHANNEL_GET_CLASS (channel)->feather (channel, radius_x, radius_y,
1845 edge_lock, push_undo);
1846 }
1847
1848 void
gimp_channel_sharpen(GimpChannel * channel,gboolean push_undo)1849 gimp_channel_sharpen (GimpChannel *channel,
1850 gboolean push_undo)
1851 {
1852 g_return_if_fail (GIMP_IS_CHANNEL (channel));
1853
1854 if (! gimp_item_is_attached (GIMP_ITEM (channel)))
1855 push_undo = FALSE;
1856
1857 GIMP_CHANNEL_GET_CLASS (channel)->sharpen (channel, push_undo);
1858 }
1859
1860 void
gimp_channel_clear(GimpChannel * channel,const gchar * undo_desc,gboolean push_undo)1861 gimp_channel_clear (GimpChannel *channel,
1862 const gchar *undo_desc,
1863 gboolean push_undo)
1864 {
1865 g_return_if_fail (GIMP_IS_CHANNEL (channel));
1866
1867 if (! gimp_item_is_attached (GIMP_ITEM (channel)))
1868 push_undo = FALSE;
1869
1870 GIMP_CHANNEL_GET_CLASS (channel)->clear (channel, undo_desc, push_undo);
1871 }
1872
1873 void
gimp_channel_all(GimpChannel * channel,gboolean push_undo)1874 gimp_channel_all (GimpChannel *channel,
1875 gboolean push_undo)
1876 {
1877 g_return_if_fail (GIMP_IS_CHANNEL (channel));
1878
1879 if (! gimp_item_is_attached (GIMP_ITEM (channel)))
1880 push_undo = FALSE;
1881
1882 GIMP_CHANNEL_GET_CLASS (channel)->all (channel, push_undo);
1883 }
1884
1885 void
gimp_channel_invert(GimpChannel * channel,gboolean push_undo)1886 gimp_channel_invert (GimpChannel *channel,
1887 gboolean push_undo)
1888 {
1889 g_return_if_fail (GIMP_IS_CHANNEL (channel));
1890
1891 if (! gimp_item_is_attached (GIMP_ITEM (channel)))
1892 push_undo = FALSE;
1893
1894 GIMP_CHANNEL_GET_CLASS (channel)->invert (channel, push_undo);
1895 }
1896
1897 void
gimp_channel_border(GimpChannel * channel,gint radius_x,gint radius_y,GimpChannelBorderStyle style,gboolean edge_lock,gboolean push_undo)1898 gimp_channel_border (GimpChannel *channel,
1899 gint radius_x,
1900 gint radius_y,
1901 GimpChannelBorderStyle style,
1902 gboolean edge_lock,
1903 gboolean push_undo)
1904 {
1905 g_return_if_fail (GIMP_IS_CHANNEL (channel));
1906
1907 if (! gimp_item_is_attached (GIMP_ITEM (channel)))
1908 push_undo = FALSE;
1909
1910 GIMP_CHANNEL_GET_CLASS (channel)->border (channel,
1911 radius_x, radius_y, style, edge_lock,
1912 push_undo);
1913 }
1914
1915 void
gimp_channel_grow(GimpChannel * channel,gint radius_x,gint radius_y,gboolean push_undo)1916 gimp_channel_grow (GimpChannel *channel,
1917 gint radius_x,
1918 gint radius_y,
1919 gboolean push_undo)
1920 {
1921 g_return_if_fail (GIMP_IS_CHANNEL (channel));
1922
1923 if (! gimp_item_is_attached (GIMP_ITEM (channel)))
1924 push_undo = FALSE;
1925
1926 GIMP_CHANNEL_GET_CLASS (channel)->grow (channel, radius_x, radius_y,
1927 push_undo);
1928 }
1929
1930 void
gimp_channel_shrink(GimpChannel * channel,gint radius_x,gint radius_y,gboolean edge_lock,gboolean push_undo)1931 gimp_channel_shrink (GimpChannel *channel,
1932 gint radius_x,
1933 gint radius_y,
1934 gboolean edge_lock,
1935 gboolean push_undo)
1936 {
1937 g_return_if_fail (GIMP_IS_CHANNEL (channel));
1938
1939 if (! gimp_item_is_attached (GIMP_ITEM (channel)))
1940 push_undo = FALSE;
1941
1942 GIMP_CHANNEL_GET_CLASS (channel)->shrink (channel, radius_x, radius_y,
1943 edge_lock, push_undo);
1944 }
1945
1946 void
gimp_channel_flood(GimpChannel * channel,gboolean push_undo)1947 gimp_channel_flood (GimpChannel *channel,
1948 gboolean push_undo)
1949 {
1950 g_return_if_fail (GIMP_IS_CHANNEL (channel));
1951
1952 if (! gimp_item_is_attached (GIMP_ITEM (channel)))
1953 push_undo = FALSE;
1954
1955 GIMP_CHANNEL_GET_CLASS (channel)->flood (channel, push_undo);
1956 }
1957