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 #include <gdk-pixbuf/gdk-pixbuf.h>
22 #include <gegl.h>
23
24 #include "libgimpcolor/gimpcolor.h"
25
26 #include "core-types.h"
27
28 #include "gegl/gimp-babl.h"
29 #include "gegl/gimp-gegl-apply-operation.h"
30 #include "gegl/gimp-gegl-loops.h"
31
32 #include "gimp.h"
33 #include "gimpcontext.h"
34 #include "gimpdrawable-edit.h"
35 #include "gimpdrawable-private.h"
36 #include "gimperror.h"
37 #include "gimpimage.h"
38 #include "gimpimage-undo.h"
39 #include "gimpimage-undo-push.h"
40 #include "gimplayer.h"
41 #include "gimplayer-new.h"
42 #include "gimplayermask.h"
43 #include "gimplayer-floating-selection.h"
44 #include "gimppickable.h"
45 #include "gimpselection.h"
46
47 #include "gimp-intl.h"
48
49
50 static gboolean gimp_selection_is_attached (GimpItem *item);
51 static GimpItemTree * gimp_selection_get_tree (GimpItem *item);
52 static void gimp_selection_translate (GimpItem *item,
53 gdouble offset_x,
54 gdouble offset_y,
55 gboolean push_undo);
56 static void gimp_selection_scale (GimpItem *item,
57 gint new_width,
58 gint new_height,
59 gint new_offset_x,
60 gint new_offset_y,
61 GimpInterpolationType interp_type,
62 GimpProgress *progress);
63 static void gimp_selection_resize (GimpItem *item,
64 GimpContext *context,
65 GimpFillType fill_type,
66 gint new_width,
67 gint new_height,
68 gint offset_x,
69 gint offset_y);
70 static void gimp_selection_flip (GimpItem *item,
71 GimpContext *context,
72 GimpOrientationType flip_type,
73 gdouble axis,
74 gboolean clip_result);
75 static void gimp_selection_rotate (GimpItem *item,
76 GimpContext *context,
77 GimpRotationType rotation_type,
78 gdouble center_x,
79 gdouble center_y,
80 gboolean clip_result);
81 static gboolean gimp_selection_fill (GimpItem *item,
82 GimpDrawable *drawable,
83 GimpFillOptions *fill_options,
84 gboolean push_undo,
85 GimpProgress *progress,
86 GError **error);
87 static gboolean gimp_selection_stroke (GimpItem *item,
88 GimpDrawable *drawable,
89 GimpStrokeOptions *stroke_options,
90 gboolean push_undo,
91 GimpProgress *progress,
92 GError **error);
93 static void gimp_selection_convert_type (GimpDrawable *drawable,
94 GimpImage *dest_image,
95 const Babl *new_format,
96 GimpColorProfile *dest_profile,
97 GeglDitherMethod layer_dither_type,
98 GeglDitherMethod mask_dither_type,
99 gboolean push_undo,
100 GimpProgress *progress);
101 static void gimp_selection_invalidate_boundary (GimpDrawable *drawable);
102
103 static gboolean gimp_selection_boundary (GimpChannel *channel,
104 const GimpBoundSeg **segs_in,
105 const GimpBoundSeg **segs_out,
106 gint *num_segs_in,
107 gint *num_segs_out,
108 gint x1,
109 gint y1,
110 gint x2,
111 gint y2);
112 static gboolean gimp_selection_is_empty (GimpChannel *channel);
113 static void gimp_selection_feather (GimpChannel *channel,
114 gdouble radius_x,
115 gdouble radius_y,
116 gboolean edge_lock,
117 gboolean push_undo);
118 static void gimp_selection_sharpen (GimpChannel *channel,
119 gboolean push_undo);
120 static void gimp_selection_clear (GimpChannel *channel,
121 const gchar *undo_desc,
122 gboolean push_undo);
123 static void gimp_selection_all (GimpChannel *channel,
124 gboolean push_undo);
125 static void gimp_selection_invert (GimpChannel *channel,
126 gboolean push_undo);
127 static void gimp_selection_border (GimpChannel *channel,
128 gint radius_x,
129 gint radius_y,
130 GimpChannelBorderStyle style,
131 gboolean edge_lock,
132 gboolean push_undo);
133 static void gimp_selection_grow (GimpChannel *channel,
134 gint radius_x,
135 gint radius_y,
136 gboolean push_undo);
137 static void gimp_selection_shrink (GimpChannel *channel,
138 gint radius_x,
139 gint radius_y,
140 gboolean edge_lock,
141 gboolean push_undo);
142 static void gimp_selection_flood (GimpChannel *channel,
143 gboolean push_undo);
144
145
G_DEFINE_TYPE(GimpSelection,gimp_selection,GIMP_TYPE_CHANNEL)146 G_DEFINE_TYPE (GimpSelection, gimp_selection, GIMP_TYPE_CHANNEL)
147
148 #define parent_class gimp_selection_parent_class
149
150
151 static void
152 gimp_selection_class_init (GimpSelectionClass *klass)
153 {
154 GimpViewableClass *viewable_class = GIMP_VIEWABLE_CLASS (klass);
155 GimpItemClass *item_class = GIMP_ITEM_CLASS (klass);
156 GimpDrawableClass *drawable_class = GIMP_DRAWABLE_CLASS (klass);
157 GimpChannelClass *channel_class = GIMP_CHANNEL_CLASS (klass);
158
159 viewable_class->default_icon_name = "gimp-selection";
160
161 item_class->is_attached = gimp_selection_is_attached;
162 item_class->get_tree = gimp_selection_get_tree;
163 item_class->translate = gimp_selection_translate;
164 item_class->scale = gimp_selection_scale;
165 item_class->resize = gimp_selection_resize;
166 item_class->flip = gimp_selection_flip;
167 item_class->rotate = gimp_selection_rotate;
168 item_class->fill = gimp_selection_fill;
169 item_class->stroke = gimp_selection_stroke;
170 item_class->default_name = _("Selection Mask");
171 item_class->translate_desc = C_("undo-type", "Move Selection");
172 item_class->fill_desc = C_("undo-type", "Fill Selection");
173 item_class->stroke_desc = C_("undo-type", "Stroke Selection");
174
175 drawable_class->convert_type = gimp_selection_convert_type;
176 drawable_class->invalidate_boundary = gimp_selection_invalidate_boundary;
177
178 channel_class->boundary = gimp_selection_boundary;
179 channel_class->is_empty = gimp_selection_is_empty;
180 channel_class->feather = gimp_selection_feather;
181 channel_class->sharpen = gimp_selection_sharpen;
182 channel_class->clear = gimp_selection_clear;
183 channel_class->all = gimp_selection_all;
184 channel_class->invert = gimp_selection_invert;
185 channel_class->border = gimp_selection_border;
186 channel_class->grow = gimp_selection_grow;
187 channel_class->shrink = gimp_selection_shrink;
188 channel_class->flood = gimp_selection_flood;
189
190 channel_class->feather_desc = C_("undo-type", "Feather Selection");
191 channel_class->sharpen_desc = C_("undo-type", "Sharpen Selection");
192 channel_class->clear_desc = C_("undo-type", "Select None");
193 channel_class->all_desc = C_("undo-type", "Select All");
194 channel_class->invert_desc = C_("undo-type", "Invert Selection");
195 channel_class->border_desc = C_("undo-type", "Border Selection");
196 channel_class->grow_desc = C_("undo-type", "Grow Selection");
197 channel_class->shrink_desc = C_("undo-type", "Shrink Selection");
198 channel_class->flood_desc = C_("undo-type", "Remove Holes");
199 }
200
201 static void
gimp_selection_init(GimpSelection * selection)202 gimp_selection_init (GimpSelection *selection)
203 {
204 }
205
206 static gboolean
gimp_selection_is_attached(GimpItem * item)207 gimp_selection_is_attached (GimpItem *item)
208 {
209 return (GIMP_IS_IMAGE (gimp_item_get_image (item)) &&
210 gimp_image_get_mask (gimp_item_get_image (item)) ==
211 GIMP_CHANNEL (item));
212 }
213
214 static GimpItemTree *
gimp_selection_get_tree(GimpItem * item)215 gimp_selection_get_tree (GimpItem *item)
216 {
217 return NULL;
218 }
219
220 static void
gimp_selection_translate(GimpItem * item,gdouble offset_x,gdouble offset_y,gboolean push_undo)221 gimp_selection_translate (GimpItem *item,
222 gdouble offset_x,
223 gdouble offset_y,
224 gboolean push_undo)
225 {
226 GIMP_ITEM_CLASS (parent_class)->translate (item, offset_x, offset_y,
227 push_undo);
228 }
229
230 static void
gimp_selection_scale(GimpItem * item,gint new_width,gint new_height,gint new_offset_x,gint new_offset_y,GimpInterpolationType interp_type,GimpProgress * progress)231 gimp_selection_scale (GimpItem *item,
232 gint new_width,
233 gint new_height,
234 gint new_offset_x,
235 gint new_offset_y,
236 GimpInterpolationType interp_type,
237 GimpProgress *progress)
238 {
239 GIMP_ITEM_CLASS (parent_class)->scale (item, new_width, new_height,
240 new_offset_x, new_offset_y,
241 interp_type, progress);
242
243 gimp_item_set_offset (item, 0, 0);
244 }
245
246 static void
gimp_selection_resize(GimpItem * item,GimpContext * context,GimpFillType fill_type,gint new_width,gint new_height,gint offset_x,gint offset_y)247 gimp_selection_resize (GimpItem *item,
248 GimpContext *context,
249 GimpFillType fill_type,
250 gint new_width,
251 gint new_height,
252 gint offset_x,
253 gint offset_y)
254 {
255 GIMP_ITEM_CLASS (parent_class)->resize (item, context, GIMP_FILL_TRANSPARENT,
256 new_width, new_height,
257 offset_x, offset_y);
258
259 gimp_item_set_offset (item, 0, 0);
260 }
261
262 static void
gimp_selection_flip(GimpItem * item,GimpContext * context,GimpOrientationType flip_type,gdouble axis,gboolean clip_result)263 gimp_selection_flip (GimpItem *item,
264 GimpContext *context,
265 GimpOrientationType flip_type,
266 gdouble axis,
267 gboolean clip_result)
268 {
269 GIMP_ITEM_CLASS (parent_class)->flip (item, context, flip_type, axis, TRUE);
270 }
271
272 static void
gimp_selection_rotate(GimpItem * item,GimpContext * context,GimpRotationType rotation_type,gdouble center_x,gdouble center_y,gboolean clip_result)273 gimp_selection_rotate (GimpItem *item,
274 GimpContext *context,
275 GimpRotationType rotation_type,
276 gdouble center_x,
277 gdouble center_y,
278 gboolean clip_result)
279 {
280 GIMP_ITEM_CLASS (parent_class)->rotate (item, context, rotation_type,
281 center_x, center_y,
282 clip_result);
283 }
284
285 static gboolean
gimp_selection_fill(GimpItem * item,GimpDrawable * drawable,GimpFillOptions * fill_options,gboolean push_undo,GimpProgress * progress,GError ** error)286 gimp_selection_fill (GimpItem *item,
287 GimpDrawable *drawable,
288 GimpFillOptions *fill_options,
289 gboolean push_undo,
290 GimpProgress *progress,
291 GError **error)
292 {
293 GimpSelection *selection = GIMP_SELECTION (item);
294 const GimpBoundSeg *dummy_in;
295 const GimpBoundSeg *dummy_out;
296 gint num_dummy_in;
297 gint num_dummy_out;
298 gboolean retval;
299
300 if (! gimp_channel_boundary (GIMP_CHANNEL (selection),
301 &dummy_in, &dummy_out,
302 &num_dummy_in, &num_dummy_out,
303 0, 0, 0, 0))
304 {
305 g_set_error_literal (error, GIMP_ERROR, GIMP_FAILED,
306 _("There is no selection to fill."));
307 return FALSE;
308 }
309
310 gimp_selection_suspend (selection);
311
312 retval = GIMP_ITEM_CLASS (parent_class)->fill (item, drawable,
313 fill_options,
314 push_undo, progress, error);
315
316 gimp_selection_resume (selection);
317
318 return retval;
319 }
320
321 static gboolean
gimp_selection_stroke(GimpItem * item,GimpDrawable * drawable,GimpStrokeOptions * stroke_options,gboolean push_undo,GimpProgress * progress,GError ** error)322 gimp_selection_stroke (GimpItem *item,
323 GimpDrawable *drawable,
324 GimpStrokeOptions *stroke_options,
325 gboolean push_undo,
326 GimpProgress *progress,
327 GError **error)
328 {
329 GimpSelection *selection = GIMP_SELECTION (item);
330 const GimpBoundSeg *dummy_in;
331 const GimpBoundSeg *dummy_out;
332 gint num_dummy_in;
333 gint num_dummy_out;
334 gboolean retval;
335
336 if (! gimp_channel_boundary (GIMP_CHANNEL (selection),
337 &dummy_in, &dummy_out,
338 &num_dummy_in, &num_dummy_out,
339 0, 0, 0, 0))
340 {
341 g_set_error_literal (error, GIMP_ERROR, GIMP_FAILED,
342 _("There is no selection to stroke."));
343 return FALSE;
344 }
345
346 gimp_selection_suspend (selection);
347
348 retval = GIMP_ITEM_CLASS (parent_class)->stroke (item, drawable,
349 stroke_options,
350 push_undo, progress, error);
351
352 gimp_selection_resume (selection);
353
354 return retval;
355 }
356
357 static void
gimp_selection_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)358 gimp_selection_convert_type (GimpDrawable *drawable,
359 GimpImage *dest_image,
360 const Babl *new_format,
361 GimpColorProfile *dest_profile,
362 GeglDitherMethod layer_dither_type,
363 GeglDitherMethod mask_dither_type,
364 gboolean push_undo,
365 GimpProgress *progress)
366 {
367 new_format =
368 gimp_babl_mask_format (gimp_babl_format_get_precision (new_format));
369
370 GIMP_DRAWABLE_CLASS (parent_class)->convert_type (drawable, dest_image,
371 new_format,
372 dest_profile,
373 layer_dither_type,
374 mask_dither_type,
375 push_undo,
376 progress);
377 }
378
379 static void
gimp_selection_invalidate_boundary(GimpDrawable * drawable)380 gimp_selection_invalidate_boundary (GimpDrawable *drawable)
381 {
382 GimpImage *image = gimp_item_get_image (GIMP_ITEM (drawable));
383 GimpLayer *layer;
384
385 /* Turn the current selection off */
386 gimp_image_selection_invalidate (image);
387
388 GIMP_DRAWABLE_CLASS (parent_class)->invalidate_boundary (drawable);
389
390 /* If there is a floating selection, update it's area...
391 * we need to do this since this selection mask can act as an additional
392 * mask in the composition of the floating selection
393 */
394 layer = gimp_image_get_active_layer (image);
395
396 if (layer && gimp_layer_is_floating_sel (layer))
397 {
398 gimp_drawable_update (GIMP_DRAWABLE (layer), 0, 0, -1, -1);
399 }
400
401 #if 0
402 /* invalidate the preview */
403 drawable->private->preview_valid = FALSE;
404 #endif
405 }
406
407 static gboolean
gimp_selection_boundary(GimpChannel * channel,const GimpBoundSeg ** segs_in,const GimpBoundSeg ** segs_out,gint * num_segs_in,gint * num_segs_out,gint unused1,gint unused2,gint unused3,gint unused4)408 gimp_selection_boundary (GimpChannel *channel,
409 const GimpBoundSeg **segs_in,
410 const GimpBoundSeg **segs_out,
411 gint *num_segs_in,
412 gint *num_segs_out,
413 gint unused1,
414 gint unused2,
415 gint unused3,
416 gint unused4)
417 {
418 GimpImage *image = gimp_item_get_image (GIMP_ITEM (channel));
419 GimpDrawable *drawable;
420 GimpLayer *layer;
421
422 if ((layer = gimp_image_get_floating_selection (image)))
423 {
424 /* If there is a floating selection, then
425 * we need to do some slightly different boundaries.
426 * Instead of inside and outside boundaries being defined
427 * by the extents of the layer, the inside boundary (the one
428 * that actually marches and is black/white) is the boundary of
429 * the floating selection. The outside boundary (doesn't move,
430 * is black/gray) is defined as the normal selection mask
431 */
432
433 /* Find the selection mask boundary */
434 GIMP_CHANNEL_CLASS (parent_class)->boundary (channel,
435 segs_in, segs_out,
436 num_segs_in, num_segs_out,
437 0, 0, 0, 0);
438
439 /* Find the floating selection boundary */
440 *segs_in = floating_sel_boundary (layer, num_segs_in);
441
442 return TRUE;
443 }
444 else if ((drawable = gimp_image_get_active_drawable (image)) &&
445 GIMP_IS_CHANNEL (drawable))
446 {
447 /* Otherwise, return the boundary...if a channel is active */
448
449 return GIMP_CHANNEL_CLASS (parent_class)->boundary (channel,
450 segs_in, segs_out,
451 num_segs_in,
452 num_segs_out,
453 0, 0,
454 gimp_image_get_width (image),
455 gimp_image_get_height (image));
456 }
457 else if ((layer = gimp_image_get_active_layer (image)))
458 {
459 /* If a layer is active, we return multiple boundaries based
460 * on the extents
461 */
462
463 gint x1, y1;
464 gint x2, y2;
465 gint offset_x;
466 gint offset_y;
467
468 gimp_item_get_offset (GIMP_ITEM (layer), &offset_x, &offset_y);
469
470 x1 = CLAMP (offset_x, 0, gimp_image_get_width (image));
471 y1 = CLAMP (offset_y, 0, gimp_image_get_height (image));
472 x2 = CLAMP (offset_x + gimp_item_get_width (GIMP_ITEM (layer)),
473 0, gimp_image_get_width (image));
474 y2 = CLAMP (offset_y + gimp_item_get_height (GIMP_ITEM (layer)),
475 0, gimp_image_get_height (image));
476
477 return GIMP_CHANNEL_CLASS (parent_class)->boundary (channel,
478 segs_in, segs_out,
479 num_segs_in,
480 num_segs_out,
481 x1, y1, x2, y2);
482 }
483
484 *segs_in = NULL;
485 *segs_out = NULL;
486 *num_segs_in = 0;
487 *num_segs_out = 0;
488
489 return FALSE;
490 }
491
492 static gboolean
gimp_selection_is_empty(GimpChannel * channel)493 gimp_selection_is_empty (GimpChannel *channel)
494 {
495 GimpSelection *selection = GIMP_SELECTION (channel);
496
497 /* in order to allow stroking of selections, we need to pretend here
498 * that the selection mask is empty so that it doesn't mask the paint
499 * during the stroke operation.
500 */
501 if (selection->suspend_count > 0)
502 return TRUE;
503
504 return GIMP_CHANNEL_CLASS (parent_class)->is_empty (channel);
505 }
506
507 static void
gimp_selection_feather(GimpChannel * channel,gdouble radius_x,gdouble radius_y,gboolean edge_lock,gboolean push_undo)508 gimp_selection_feather (GimpChannel *channel,
509 gdouble radius_x,
510 gdouble radius_y,
511 gboolean edge_lock,
512 gboolean push_undo)
513 {
514 GIMP_CHANNEL_CLASS (parent_class)->feather (channel, radius_x, radius_y,
515 edge_lock, push_undo);
516 }
517
518 static void
gimp_selection_sharpen(GimpChannel * channel,gboolean push_undo)519 gimp_selection_sharpen (GimpChannel *channel,
520 gboolean push_undo)
521 {
522 GIMP_CHANNEL_CLASS (parent_class)->sharpen (channel, push_undo);
523 }
524
525 static void
gimp_selection_clear(GimpChannel * channel,const gchar * undo_desc,gboolean push_undo)526 gimp_selection_clear (GimpChannel *channel,
527 const gchar *undo_desc,
528 gboolean push_undo)
529 {
530 GIMP_CHANNEL_CLASS (parent_class)->clear (channel, undo_desc, push_undo);
531 }
532
533 static void
gimp_selection_all(GimpChannel * channel,gboolean push_undo)534 gimp_selection_all (GimpChannel *channel,
535 gboolean push_undo)
536 {
537 GIMP_CHANNEL_CLASS (parent_class)->all (channel, push_undo);
538 }
539
540 static void
gimp_selection_invert(GimpChannel * channel,gboolean push_undo)541 gimp_selection_invert (GimpChannel *channel,
542 gboolean push_undo)
543 {
544 GIMP_CHANNEL_CLASS (parent_class)->invert (channel, push_undo);
545 }
546
547 static void
gimp_selection_border(GimpChannel * channel,gint radius_x,gint radius_y,GimpChannelBorderStyle style,gboolean edge_lock,gboolean push_undo)548 gimp_selection_border (GimpChannel *channel,
549 gint radius_x,
550 gint radius_y,
551 GimpChannelBorderStyle style,
552 gboolean edge_lock,
553 gboolean push_undo)
554 {
555 GIMP_CHANNEL_CLASS (parent_class)->border (channel,
556 radius_x, radius_y,
557 style, edge_lock,
558 push_undo);
559 }
560
561 static void
gimp_selection_grow(GimpChannel * channel,gint radius_x,gint radius_y,gboolean push_undo)562 gimp_selection_grow (GimpChannel *channel,
563 gint radius_x,
564 gint radius_y,
565 gboolean push_undo)
566 {
567 GIMP_CHANNEL_CLASS (parent_class)->grow (channel,
568 radius_x, radius_y,
569 push_undo);
570 }
571
572 static void
gimp_selection_shrink(GimpChannel * channel,gint radius_x,gint radius_y,gboolean edge_lock,gboolean push_undo)573 gimp_selection_shrink (GimpChannel *channel,
574 gint radius_x,
575 gint radius_y,
576 gboolean edge_lock,
577 gboolean push_undo)
578 {
579 GIMP_CHANNEL_CLASS (parent_class)->shrink (channel,
580 radius_x, radius_y, edge_lock,
581 push_undo);
582 }
583
584 static void
gimp_selection_flood(GimpChannel * channel,gboolean push_undo)585 gimp_selection_flood (GimpChannel *channel,
586 gboolean push_undo)
587 {
588 GIMP_CHANNEL_CLASS (parent_class)->flood (channel, push_undo);
589 }
590
591
592 /* public functions */
593
594 GimpChannel *
gimp_selection_new(GimpImage * image,gint width,gint height)595 gimp_selection_new (GimpImage *image,
596 gint width,
597 gint height)
598 {
599 GimpRGB black = { 0.0, 0.0, 0.0, 0.5 };
600 GimpChannel *channel;
601
602 g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL);
603 g_return_val_if_fail (width > 0 && height > 0, NULL);
604
605 channel = GIMP_CHANNEL (gimp_drawable_new (GIMP_TYPE_SELECTION,
606 image, NULL,
607 0, 0, width, height,
608 gimp_image_get_mask_format (image)));
609
610 gimp_channel_set_color (channel, &black, FALSE);
611 gimp_channel_set_show_masked (channel, TRUE);
612
613 channel->x2 = width;
614 channel->y2 = height;
615
616 return channel;
617 }
618
619 gint
gimp_selection_suspend(GimpSelection * selection)620 gimp_selection_suspend (GimpSelection *selection)
621 {
622 g_return_val_if_fail (GIMP_IS_SELECTION (selection), 0);
623
624 selection->suspend_count++;
625
626 return selection->suspend_count;
627 }
628
629 gint
gimp_selection_resume(GimpSelection * selection)630 gimp_selection_resume (GimpSelection *selection)
631 {
632 g_return_val_if_fail (GIMP_IS_SELECTION (selection), 0);
633 g_return_val_if_fail (selection->suspend_count > 0, 0);
634
635 selection->suspend_count--;
636
637 return selection->suspend_count;
638 }
639
640 GeglBuffer *
gimp_selection_extract(GimpSelection * selection,GimpPickable * pickable,GimpContext * context,gboolean cut_image,gboolean keep_indexed,gboolean add_alpha,gint * offset_x,gint * offset_y,GError ** error)641 gimp_selection_extract (GimpSelection *selection,
642 GimpPickable *pickable,
643 GimpContext *context,
644 gboolean cut_image,
645 gboolean keep_indexed,
646 gboolean add_alpha,
647 gint *offset_x,
648 gint *offset_y,
649 GError **error)
650 {
651 GimpImage *image;
652 GeglBuffer *src_buffer;
653 GeglBuffer *dest_buffer;
654 const Babl *src_format;
655 const Babl *dest_format;
656 gint x1, y1, x2, y2;
657 gboolean non_empty;
658 gint off_x, off_y;
659
660 g_return_val_if_fail (GIMP_IS_SELECTION (selection), NULL);
661 g_return_val_if_fail (GIMP_IS_PICKABLE (pickable), NULL);
662 if (GIMP_IS_ITEM (pickable))
663 g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (pickable)), NULL);
664 g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL);
665 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
666
667 image = gimp_pickable_get_image (pickable);
668
669 /* If there are no bounds, then just extract the entire image
670 * This may not be the correct behavior, but after getting rid
671 * of floating selections, it's still tempting to "cut" or "copy"
672 * a small layer and expect it to work, even though there is no
673 * actual selection mask
674 */
675 if (GIMP_IS_DRAWABLE (pickable))
676 {
677 non_empty = gimp_item_mask_bounds (GIMP_ITEM (pickable),
678 &x1, &y1, &x2, &y2);
679
680 gimp_item_get_offset (GIMP_ITEM (pickable), &off_x, &off_y);
681 }
682 else
683 {
684 non_empty = gimp_item_bounds (GIMP_ITEM (selection),
685 &x1, &y1, &x2, &y2);
686 x2 += x1;
687 y2 += y1;
688
689 off_x = 0;
690 off_y = 0;
691
692 /* can't cut from non-drawables, fall back to copy */
693 cut_image = FALSE;
694 }
695
696 if (non_empty && ((x1 == x2) || (y1 == y2)))
697 {
698 g_set_error_literal (error, GIMP_ERROR, GIMP_FAILED,
699 _("Unable to cut or copy because the "
700 "selected region is empty."));
701 return NULL;
702 }
703
704 /* If there is a selection, we must add alpha because the selection
705 * could have any shape.
706 */
707 if (non_empty)
708 add_alpha = TRUE;
709
710 src_format = gimp_pickable_get_format (pickable);
711
712 /* How many bytes in the temp buffer? */
713 if (babl_format_is_palette (src_format) && ! keep_indexed)
714 {
715 dest_format = gimp_image_get_format (image, GIMP_RGB,
716 gimp_image_get_precision (image),
717 add_alpha ||
718 babl_format_has_alpha (src_format));
719 }
720 else
721 {
722 if (add_alpha)
723 dest_format = gimp_pickable_get_format_with_alpha (pickable);
724 else
725 dest_format = src_format;
726 }
727
728 gimp_pickable_flush (pickable);
729
730 src_buffer = gimp_pickable_get_buffer (pickable);
731
732 /* Allocate the temp buffer */
733 dest_buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0, x2 - x1, y2 - y1),
734 dest_format);
735
736 /* First, copy the pixels, possibly doing INDEXED->RGB and adding alpha */
737 gimp_gegl_buffer_copy (src_buffer, GEGL_RECTANGLE (x1, y1, x2 - x1, y2 - y1),
738 GEGL_ABYSS_NONE,
739 dest_buffer, GEGL_RECTANGLE (0, 0, 0, 0));
740
741 if (non_empty)
742 {
743 /* If there is a selection, mask the dest_buffer with it */
744
745 GeglBuffer *mask_buffer;
746
747 mask_buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (selection));
748
749 gimp_gegl_apply_opacity (dest_buffer, NULL, NULL, dest_buffer,
750 mask_buffer,
751 - (off_x + x1),
752 - (off_y + y1),
753 1.0);
754
755 if (cut_image)
756 {
757 gimp_drawable_edit_clear (GIMP_DRAWABLE (pickable), context);
758 }
759 }
760 else if (cut_image)
761 {
762 /* If we're cutting without selection, remove either the layer
763 * (or floating selection), the layer mask, or the channel
764 */
765 if (GIMP_IS_LAYER (pickable))
766 {
767 gimp_image_remove_layer (image, GIMP_LAYER (pickable),
768 TRUE, NULL);
769 }
770 else if (GIMP_IS_LAYER_MASK (pickable))
771 {
772 gimp_layer_apply_mask (gimp_layer_mask_get_layer (GIMP_LAYER_MASK (pickable)),
773 GIMP_MASK_DISCARD, TRUE);
774 }
775 else if (GIMP_IS_CHANNEL (pickable))
776 {
777 gimp_image_remove_channel (image, GIMP_CHANNEL (pickable),
778 TRUE, NULL);
779 }
780 }
781
782 *offset_x = x1 + off_x;
783 *offset_y = y1 + off_y;
784
785 return dest_buffer;
786 }
787
788 GimpLayer *
gimp_selection_float(GimpSelection * selection,GimpDrawable * drawable,GimpContext * context,gboolean cut_image,gint off_x,gint off_y,GError ** error)789 gimp_selection_float (GimpSelection *selection,
790 GimpDrawable *drawable,
791 GimpContext *context,
792 gboolean cut_image,
793 gint off_x,
794 gint off_y,
795 GError **error)
796 {
797 GimpImage *image;
798 GimpLayer *layer;
799 GeglBuffer *buffer;
800 GimpColorProfile *profile;
801 gint x1, y1;
802 gint x2, y2;
803
804 g_return_val_if_fail (GIMP_IS_SELECTION (selection), NULL);
805 g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL);
806 g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)), NULL);
807 g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL);
808 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
809
810 image = gimp_item_get_image (GIMP_ITEM (selection));
811
812 /* Make sure there is a region to float... */
813 if (! gimp_item_mask_bounds (GIMP_ITEM (drawable), &x1, &y1, &x2, &y2) ||
814 (x1 == x2 || y1 == y2))
815 {
816 g_set_error_literal (error, GIMP_ERROR, GIMP_FAILED,
817 _("Cannot float selection because the selected "
818 "region is empty."));
819 return NULL;
820 }
821
822 /* Start an undo group */
823 gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_FS_FLOAT,
824 C_("undo-type", "Float Selection"));
825
826 /* Cut or copy the selected region */
827 buffer = gimp_selection_extract (selection, GIMP_PICKABLE (drawable), context,
828 cut_image, FALSE, TRUE,
829 &x1, &y1, NULL);
830
831 profile = gimp_color_managed_get_color_profile (GIMP_COLOR_MANAGED (drawable));
832
833 /* Clear the selection */
834 gimp_channel_clear (GIMP_CHANNEL (selection), NULL, TRUE);
835
836 /* Create a new layer from the buffer, using the drawable's type
837 * because it may be different from the image's type if we cut from
838 * a channel or layer mask
839 */
840 layer = gimp_layer_new_from_gegl_buffer (buffer, image,
841 gimp_drawable_get_format_with_alpha (drawable),
842 _("Floated Layer"),
843 GIMP_OPACITY_OPAQUE,
844 gimp_image_get_default_new_layer_mode (image),
845 profile);
846
847 /* Set the offsets */
848 gimp_item_set_offset (GIMP_ITEM (layer), x1 + off_x, y1 + off_y);
849
850 /* Free the temp buffer */
851 g_object_unref (buffer);
852
853 /* Add the floating layer to the image */
854 floating_sel_attach (layer, drawable);
855
856 /* End an undo group */
857 gimp_image_undo_group_end (image);
858
859 /* invalidate the image's boundary variables */
860 GIMP_CHANNEL (selection)->boundary_known = FALSE;
861
862 return layer;
863 }
864