/* -------------------------- * p_create_corpus_layer * -------------------------- * create the corpus layer that builds the reference pattern * for the resynthesizer call. The reference pattern is built * as duplicate of the original image reduced to the area around the current selection. * (grown by corpus_border_radius) * Note that the duplicate image has a selection, that includes the gorwn area * around the orignal selection, but EXCLUDES the original selection * (that is the area holding the object that has to be replaced * by pattern of the surrounding area) * returns the layer_id of the reference pattern. */ static gint32 p_create_corpus_layer(gint32 image_id, gint32 drawable_id, TransValues *val_ptr) { gint32 dup_image_id; gint32 channel_id; gint32 channel_2_id; GimpRGB bck_color; GimpRGB white_opaque_color; /* gboolean has_selection; */ gboolean non_empty; gint x1, y1, x2, y2; gint32 active_layer_stackposition; gint32 active_dup_layer_id; active_layer_stackposition = gap_layer_get_stackposition(image_id, drawable_id); dup_image_id = gimp_image_duplicate(image_id); channel_id = gimp_selection_save(dup_image_id); gimp_selection_grow(dup_image_id, val_ptr->corpus_border_radius); gimp_selection_invert(dup_image_id); gimp_context_get_background(&bck_color); channel_2_id = gimp_selection_save(dup_image_id); gimp_image_select_item(dup_image_id, GIMP_CHANNEL_OP_REPLACE, channel_id); gimp_rgba_set_uchar (&white_opaque_color, 255, 255, 255, 255); gimp_context_set_background(&white_opaque_color); gimp_edit_clear(channel_2_id); gimp_context_set_background(&bck_color); /* restore original background color */ gimp_selection_load(channel_2_id); gimp_selection_invert(dup_image_id); /* has_selection = */ gimp_selection_bounds(dup_image_id, &non_empty, &x1, &y1, &x2, &y2); gimp_image_crop(dup_image_id, (x2 - x1), (y2 - y1), x1, y1); gimp_selection_invert(dup_image_id); active_dup_layer_id = gap_layer_get_id_by_stackposition(dup_image_id, active_layer_stackposition); if (1==0) { /* debug code shows the duplicate image by adding a display */ gimp_display_new(dup_image_id); } return (active_dup_layer_id); } /* end p_create_corpus_layer */
void gimp_image_set_quick_mask_state (GimpImage *image, gboolean active) { GimpChannel *selection; GimpChannel *mask; gboolean channel_was_active; g_return_if_fail (GIMP_IS_IMAGE (image)); if (active == gimp_image_get_quick_mask_state (image)) return; /* Keep track of the state so that we can make the right drawable * active again when deactiviting quick mask (see bug #134371). */ if (image->quick_mask_state) channel_was_active = (image->quick_mask_state & CHANNEL_WAS_ACTIVE) != 0; else channel_was_active = gimp_image_get_active_channel (image) != NULL; /* Set image->quick_mask_state early so we can return early when * being called recursively. */ image->quick_mask_state = (active ? TRUE | (channel_was_active ? CHANNEL_WAS_ACTIVE : 0) : FALSE); selection = gimp_image_get_mask (image); mask = gimp_image_get_quick_mask (image); if (active) { if (! mask) { gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_IMAGE_QUICK_MASK, _("Enable Quick Mask")); if (gimp_channel_is_empty (selection)) { /* if no selection */ GimpLayer *floating_sel = gimp_image_floating_sel (image); if (floating_sel) floating_sel_to_layer (floating_sel); mask = gimp_channel_new (image, image->width, image->height, GIMP_IMAGE_QUICK_MASK_NAME, &image->quick_mask_color); /* Clear the mask */ gimp_channel_clear (mask, NULL, FALSE); } else { /* if selection */ mask = GIMP_CHANNEL (gimp_item_duplicate (GIMP_ITEM (selection), GIMP_TYPE_CHANNEL, FALSE)); /* Clear the selection */ gimp_channel_clear (selection, NULL, TRUE); gimp_channel_set_color (mask, &image->quick_mask_color, FALSE); gimp_item_rename (GIMP_ITEM (mask), GIMP_IMAGE_QUICK_MASK_NAME); } if (image->quick_mask_inverted) gimp_channel_invert (mask, FALSE); gimp_image_add_channel (image, mask, 0); gimp_image_undo_group_end (image); } } else { if (mask) { GimpLayer *floating_sel = gimp_image_floating_sel (image); gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_IMAGE_QUICK_MASK, _("Disable Quick Mask")); if (image->quick_mask_inverted) gimp_channel_invert (mask, TRUE); if (floating_sel && floating_sel->fs.drawable == GIMP_DRAWABLE (mask)) floating_sel_anchor (floating_sel); gimp_selection_load (gimp_image_get_mask (image), mask); gimp_image_remove_channel (image, mask); if (! channel_was_active) gimp_image_unset_active_channel (image); gimp_image_undo_group_end (image); } } gimp_image_quick_mask_changed (image); }
/* -------------------------------------------- * gap_fg_from_selection_exec_apply_run * -------------------------------------------- * generate a tri map from the current selection by filling the shrinked * shape with white, the expanded shape with black and the borderline * between shrinked and expanded selection with medium gray. * the trimap is attached as layermask to the input drawable, * and used as input for the foreground selection via alpha matting algorithm, * that creates a resulting layer with trimmed selection. * */ gint gap_fg_from_selection_exec_apply_run (gint32 image_id, gint32 drawable_id , gboolean doProgress, gboolean doFlush , GapFgSelectValues *fsValPtr) { GimpRGB color; gint32 activeSelection; gint32 shrinkedSelection; gint32 trimap; gboolean hadSelection; gint rc; rc = 0; trimap = -1; activeSelection = -1; shrinkedSelection = -1; hadSelection = FALSE; gimp_context_push(); gimp_image_undo_group_start(image_id); if (gimp_selection_is_empty(image_id) == TRUE) { if (gimp_drawable_has_alpha(drawable_id) == FALSE) { /* if the layer has no alpha select all */ gimp_selection_all(image_id); } else { gimp_selection_layer_alpha(drawable_id); } activeSelection = gimp_selection_save(image_id); } else { activeSelection = gimp_selection_save(image_id); hadSelection = TRUE; } trimap = gimp_layer_get_mask(drawable_id); if (trimap < 0) { /* create trimap as new layermask */ trimap = gimp_layer_create_mask(drawable_id, GIMP_ADD_BLACK_MASK); gimp_layer_add_mask(drawable_id, trimap); } else { /* use BLACK color to fill the already existing layermask * (note that gimp_drawable_fill is used to fill the entire mask * regardless to the current selection) */ color.r = 0.0; color.g = 0.0; color.b = 0.0; color.a = 1.0; gimp_context_set_background (&color); gimp_drawable_fill(trimap, GIMP_BACKGROUND_FILL); } gimp_selection_sharpen(image_id); if (fsValPtr->innerRadius > 0) { gimp_selection_shrink(image_id, fsValPtr->innerRadius); } shrinkedSelection = gimp_selection_save(image_id); /* use WHITE color to mark foreground regions */ color.r = 1.0; color.g = 1.0; color.b = 1.0; color.a = 1.0; gimp_context_set_background (&color); gimp_edit_fill(trimap, GIMP_BACKGROUND_FILL); gimp_selection_load(activeSelection); gimp_selection_sharpen(image_id); if (fsValPtr->outerRadius > 0) { gimp_selection_grow(image_id, fsValPtr->outerRadius); } gimp_selection_combine(shrinkedSelection, GIMP_CHANNEL_OP_SUBTRACT); /* use medium GRAY to mark undefined regions */ color.r = 0.5; color.g = 0.5; color.b = 0.5; color.a = 1.0; gimp_context_set_background (&color); gimp_edit_fill(trimap, GIMP_BACKGROUND_FILL); gimp_selection_none(image_id); /* perform the foreground selection (that creates the resulting layer) */ { GapFgExtractValues fgExtractValues; GapFgExtractValues *fgValPtr; fgValPtr = &fgExtractValues; fgValPtr->input_drawable_id = drawable_id; fgValPtr->tri_map_drawable_id = trimap; fgValPtr->create_result = TRUE; fgValPtr->create_layermask = fsValPtr->create_layermask; fgValPtr->lock_color = fsValPtr->lock_color; fgValPtr->colordiff_threshold = fsValPtr->colordiff_threshold; rc = gap_fg_matting_exec_apply_run (image_id, drawable_id , doProgress, doFlush , fgValPtr ); } /* restore original selection */ if (hadSelection == TRUE) { gimp_selection_load(activeSelection); } gimp_image_undo_group_end(image_id); gimp_context_pop(); return (rc); } /* end gap_fg_from_selection_exec_apply_run */