/* ------------------------------------ * gap_image_merge_to_specified_layer * ------------------------------------ * remove all other layers from the image except the specified layer_id * (by removing other layers, make ref_layer_id visible and perform merging) */ gint32 gap_image_merge_to_specified_layer(gint32 ref_layer_id, GimpMergeType mergemode) { gint32 l_image_id; l_image_id = gimp_item_get_image(ref_layer_id); if(l_image_id >= 0) { gint32 l_idx; gint l_nlayers; gint32 *l_layers_list; l_layers_list = gimp_image_get_layers(l_image_id, &l_nlayers); if(l_layers_list != NULL) { for(l_idx = 0; l_idx < l_nlayers; l_idx++) { if (l_layers_list[l_idx] == ref_layer_id) { gimp_item_set_visible(l_layers_list[l_idx], TRUE); } else { gimp_image_remove_layer(l_image_id, l_layers_list[l_idx]); } } g_free (l_layers_list); return (gap_image_merge_visible_layers(l_image_id, mergemode)); } } return (-1); } /* end gap_image_merge_to_specified_layer */
void floating_sel_remove (GimpLayer *layer) { GimpImage *image; g_return_if_fail (GIMP_IS_LAYER (layer)); g_return_if_fail (gimp_layer_is_floating_sel (layer)); image = gimp_item_get_image (GIMP_ITEM (layer->fs.drawable)); gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_FS_REMOVE, _("Remove Floating Selection")); /* store the affected area from the drawable in the backing store */ floating_sel_relax (layer, TRUE); /* Invalidate the preview of the obscured drawable. We do this here * because it will not be done until the floating selection is removed, * at which point the obscured drawable's preview will not be declared * invalid. */ gimp_viewable_invalidate_preview (GIMP_VIEWABLE (layer)); /* remove the layer from the image */ gimp_image_remove_layer (image, layer); gimp_image_undo_group_end (image); }
GimpLayer * gimp_image_merge_group_layer (GimpImage *image, GimpGroupLayer *group) { GimpLayer *parent; GimpLayer *layer; gint index; g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL); g_return_val_if_fail (GIMP_IS_GROUP_LAYER (group), NULL); g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (group)), NULL); g_return_val_if_fail (gimp_item_get_image (GIMP_ITEM (group)) == image, NULL); gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_IMAGE_LAYERS_MERGE, C_("undo-type", "Merge Layer Group")); parent = gimp_layer_get_parent (GIMP_LAYER (group)); index = gimp_item_get_index (GIMP_ITEM (group)); layer = GIMP_LAYER (gimp_item_duplicate (GIMP_ITEM (group), GIMP_TYPE_LAYER)); gimp_object_set_name (GIMP_OBJECT (layer), gimp_object_get_name (group)); gimp_image_remove_layer (image, GIMP_LAYER (group), TRUE, NULL); gimp_image_add_layer (image, layer, parent, index, TRUE); gimp_image_undo_group_end (image); return layer; }
static GValueArray * floating_sel_remove_invoker (GimpProcedure *procedure, Gimp *gimp, GimpContext *context, GimpProgress *progress, const GValueArray *args, GError **error) { gboolean success = TRUE; GimpLayer *floating_sel; floating_sel = gimp_value_get_layer (&args->values[0], gimp); if (success) { if (gimp_layer_is_floating_sel (floating_sel)) { gimp_image_remove_layer (gimp_item_get_image (GIMP_ITEM (floating_sel)), floating_sel, TRUE, NULL); } else { g_set_error_literal (error, GIMP_PDB_ERROR, GIMP_PDB_ERROR_INVALID_ARGUMENT, _("Cannot remove this layer because " "it is not a floating selection.")); success = FALSE; } } return gimp_procedure_get_return_values (procedure, success, error ? *error : NULL); }
void floating_sel_anchor (GimpLayer *layer) { GimpImage *image; GimpDrawable *drawable; GimpFilter *filter = NULL; gint off_x, off_y; gint dr_off_x, dr_off_y; g_return_if_fail (GIMP_IS_LAYER (layer)); g_return_if_fail (gimp_layer_is_floating_sel (layer)); /* Don't let gimp_image_remove_layer free the layer while we still need it */ g_object_ref (layer); image = gimp_item_get_image (GIMP_ITEM (layer)); gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_FS_ANCHOR, C_("undo-type", "Anchor Floating Selection")); drawable = gimp_layer_get_floating_sel_drawable (layer); gimp_item_get_offset (GIMP_ITEM (layer), &off_x, &off_y); gimp_item_get_offset (GIMP_ITEM (drawable), &dr_off_x, &dr_off_y); if (gimp_item_get_visible (GIMP_ITEM (layer)) && gimp_rectangle_intersect (off_x, off_y, gimp_item_get_width (GIMP_ITEM (layer)), gimp_item_get_height (GIMP_ITEM (layer)), dr_off_x, dr_off_y, gimp_item_get_width (GIMP_ITEM (drawable)), gimp_item_get_height (GIMP_ITEM (drawable)), NULL, NULL, NULL, NULL)) { filter = gimp_drawable_get_floating_sel_filter (drawable); g_object_ref (filter); } /* first remove the filter, then merge it, or we will get warnings * about already connected nodes */ gimp_image_remove_layer (image, layer, TRUE, NULL); if (filter) { gimp_drawable_merge_filter (drawable, filter, NULL, NULL); g_object_unref (filter); } gimp_image_undo_group_end (image); /* invalidate the boundaries */ gimp_drawable_invalidate_boundary (GIMP_DRAWABLE (gimp_image_get_mask (image))); g_object_unref (layer); }
GimpObject * gimp_edit_cut (GimpImage *image, GimpDrawable *drawable, GimpContext *context, GError **error) { g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL); g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL); g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)), NULL); g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); if (GIMP_IS_LAYER (drawable) && gimp_channel_is_empty (gimp_image_get_mask (image))) { GimpImage *clip_image; clip_image = gimp_image_new_from_drawable (image->gimp, drawable); gimp_container_remove (image->gimp->images, GIMP_OBJECT (clip_image)); gimp_set_clipboard_image (image->gimp, clip_image); g_object_unref (clip_image); gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_EDIT_CUT, C_("undo-type", "Cut Layer")); gimp_image_remove_layer (image, GIMP_LAYER (drawable), TRUE, NULL); gimp_image_undo_group_end (image); return GIMP_OBJECT (gimp_get_clipboard_image (image->gimp)); } else { GimpBuffer *buffer; buffer = gimp_edit_extract (image, GIMP_PICKABLE (drawable), context, TRUE, error); if (buffer) { gimp_set_clipboard_buffer (image->gimp, buffer); g_object_unref (buffer); return GIMP_OBJECT (gimp_get_clipboard_buffer (image->gimp)); } } return NULL; }
void floating_sel_anchor (GimpLayer *layer) { GimpImage *image; GimpDrawable *drawable; g_return_if_fail (GIMP_IS_LAYER (layer)); g_return_if_fail (gimp_layer_is_floating_sel (layer)); image = gimp_item_get_image (GIMP_ITEM (layer)); if (! gimp_layer_is_floating_sel (layer)) { gimp_message (image->gimp, NULL, GIMP_MESSAGE_WARNING, _("Cannot anchor this layer because " "it is not a floating selection.")); return; } /* Start a floating selection anchoring undo */ gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_FS_ANCHOR, _("Anchor Floating Selection")); /* Invalidate the previews of the layer that will be composited * with the floating section. */ gimp_viewable_invalidate_preview (GIMP_VIEWABLE (layer->fs.drawable)); /* Relax the floating selection */ floating_sel_relax (layer, TRUE); /* Composite the floating selection contents */ floating_sel_composite (layer, GIMP_ITEM (layer)->offset_x, GIMP_ITEM (layer)->offset_y, GIMP_ITEM (layer)->width, GIMP_ITEM (layer)->height, TRUE); drawable = layer->fs.drawable; /* remove the floating selection */ gimp_image_remove_layer (image, layer); /* end the group undo */ gimp_image_undo_group_end (image); /* invalidate the boundaries */ gimp_drawable_invalidate_boundary (GIMP_DRAWABLE (gimp_image_get_mask (image))); }
/* ----------------------------- * gap_image_reorder_layer * ----------------------------- * move the specified layer to another position within the same image. * (done by removing and then re-inserting the layer) * new_groupname * Name of a group or group/subgroup where the specified layer_id shall be moved to. * Note that the string new_groupname uses the delimiter string * to split nested group/sugrup names. * use new_groupname = NULL to move the specified layer_id to image toplevel. * enableGroupCreation * TRUE: * in case the group layer with new_groupname does not exist * it will be created automatically. * FALSE: * in case the group layer with new_groupname does not exist * -1 is returned and the reorder operation is not performed. * new_position * the desired new stackposition within the specified new_groupname * or toplevel image (when new_groupname is NULL or empty) * returns -1 on error */ gint32 gap_image_reorder_layer(gint32 image_id, gint32 layer_id, gint32 new_position, char *new_groupname, char *delimiter, gboolean enableGroupCreation, char *new_layername) { gint32 l_parent_id; gint32 l_dup_layer_id; gchar *l_name; l_parent_id = gap_image_find_or_create_group_layer(image_id , new_groupname , delimiter , 0 /* stackposition for the group in case it is created at toplevel */ , enableGroupCreation ); if (l_parent_id < 0) { return (-1); } l_dup_layer_id = gimp_layer_copy(layer_id); l_name = NULL; if (new_layername != NULL) { if (*new_layername != '\0') { l_name = g_strdup(new_layername); } } if (l_name == NULL) { l_name = gimp_item_get_name(layer_id); } gimp_image_remove_layer(image_id, layer_id); gimp_image_insert_layer(image_id, l_dup_layer_id, l_parent_id, new_position); gimp_item_set_name(l_dup_layer_id, l_name); g_free(l_name); return (0); /* OK */ } /* end gap_image_reorder_layer */
void removeAllLayersExceptMain(void) { gint *pnLayers = NULL; gint numLayers = 0 ; gint nIndex = 0 ; gimp_image_set_active_layer(local_vals.image_ID, drawableBeginActiveLayer); pnLayers = gimp_image_get_layers(local_vals.image_ID, &numLayers); for (nIndex=0;nIndex< numLayers;nIndex++) { if (pnLayers[nIndex] != drawableBeginActiveLayer) { if (gimp_layer_is_floating_sel(pnLayers[nIndex])) { gimp_floating_sel_remove(pnLayers[nIndex]); } else { gimp_image_remove_layer(local_vals.image_ID, pnLayers[nIndex]); } } } gimp_drawable_set_visible(drawableBeginActiveLayer, TRUE); }
/* --------------------------------------- * gap_image_remove_invisble_layers * --------------------------------------- */ void gap_image_remove_invisble_layers(gint32 image_id) { gint l_nlayers; gint32 *l_layers_list; l_layers_list = gimp_image_get_layers(image_id, &l_nlayers); if(l_layers_list != NULL) { int ii; for(ii=0; ii < l_nlayers; ii++) { if (gimp_item_get_visible(l_layers_list[ii]) != TRUE) { gimp_image_remove_layer(image_id, l_layers_list[ii]); } } g_free (l_layers_list); } } /* end gap_image_remove_invisble_layers */
void destroy_preview (void) { if (prev_p && !prev_p->abort_me) { guint id = prev_p->source_id; prev_p->abort_me = TRUE; /* signal the background save to stop */ background_jpeg_save (prev_p); g_source_remove (id); } if (gimp_image_is_valid (preview_image_ID) && gimp_item_is_valid (preview_layer_ID)) { /* assuming that reference counting is working correctly, we do not need to delete the layer, removing it from the image should be sufficient */ gimp_image_remove_layer (preview_image_ID, preview_layer_ID); preview_layer_ID = -1; } }
/* --------------------------------------- * gap_image_limit_layers * --------------------------------------- * keepTopLayers number of layers to keep on top of the layerstack (Foreground). * keepBgLayers number of layers to keep on bottom of the layerstack (Background). * * Note that gimp-2.7 or later versions supports layer groups. * this procedure does only check for toplevel layers * and ignores layers that are nested in groups. * A top level group counts as one single layer * no matter how many layers und subgroups are in the toplevel group. * */ void gap_image_limit_layers(gint32 image_id, gint keepTopLayers, gint keepBgLayers) { gint l_nlayers; gint32 *l_layers_list; l_layers_list = gimp_image_get_layers(image_id, &l_nlayers); if(l_layers_list != NULL) { int ii; for(ii=0; ii < l_nlayers; ii++) { if ((ii >= keepTopLayers) && ((l_nlayers -ii) > keepBgLayers)) { gimp_image_remove_layer(image_id, l_layers_list[ii]); } } g_free (l_layers_list); } } /* end gap_image_limit_layers */
static void export_merge (gint32 image_ID, gint32 *drawable_ID) { gint32 nlayers; gint32 nvisible = 0; gint32 i; gint32 *layers; gint32 merged; gint32 transp; layers = gimp_image_get_layers (image_ID, &nlayers); for (i = 0; i < nlayers; i++) { if (gimp_item_get_visible (layers[i])) nvisible++; } if (nvisible <= 1) { /* if there is only one (or zero) visible layer, add a new transparent layer that has the same size as the canvas. The merge that follows will ensure that the offset, opacity and size are correct */ transp = gimp_layer_new (image_ID, "-", gimp_image_width (image_ID), gimp_image_height (image_ID), gimp_drawable_type (*drawable_ID) | 1, 100.0, GIMP_NORMAL_MODE); gimp_image_insert_layer (image_ID, transp, -1, 1); gimp_selection_none (image_ID); gimp_edit_clear (transp); nvisible++; } if (nvisible > 1) { g_free (layers); merged = gimp_image_merge_visible_layers (image_ID, GIMP_CLIP_TO_IMAGE); if (merged != -1) *drawable_ID = merged; else return; /* shouldn't happen */ layers = gimp_image_get_layers (image_ID, &nlayers); /* make sure that the merged drawable matches the image size */ if (gimp_drawable_width (merged) != gimp_image_width (image_ID) || gimp_drawable_height (merged) != gimp_image_height (image_ID)) { gint off_x, off_y; gimp_drawable_offsets (merged, &off_x, &off_y); gimp_layer_resize (merged, gimp_image_width (image_ID), gimp_image_height (image_ID), off_x, off_y); } } /* remove any remaining (invisible) layers */ for (i = 0; i < nlayers; i++) { if (layers[i] != *drawable_ID) gimp_image_remove_layer (image_ID, layers[i]); } g_free (layers); }
GimpLayer * gimp_image_merge_visible_layers (GimpImage *image, GimpContext *context, GimpMergeType merge_type, gboolean discard_invisible) { GList *list; GSList *merge_list = NULL; GSList *invisible_list = NULL; gboolean had_floating_sel = FALSE; GimpLayer *layer = NULL; g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL); g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL); /* if there's a floating selection, anchor it */ if (gimp_image_floating_sel (image)) { floating_sel_anchor (image->floating_sel); had_floating_sel = TRUE; } for (list = GIMP_LIST (image->layers)->list; list; list = g_list_next (list)) { layer = list->data; if (gimp_item_get_visible (GIMP_ITEM (layer))) { merge_list = g_slist_append (merge_list, layer); } else if (discard_invisible) { invisible_list = g_slist_append (invisible_list, layer); } } if (merge_list) { const gchar *undo_desc = _("Merge Visible Layers"); gimp_set_busy (image->gimp); if (invisible_list) { gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_IMAGE_LAYERS_MERGE, undo_desc); } layer = gimp_image_merge_layers (image, merge_list, context, merge_type, _("Merge Visible Layers")); g_slist_free (merge_list); if (invisible_list) { GSList *list; for (list = invisible_list; list; list = g_slist_next (list)) gimp_image_remove_layer (image, list->data); gimp_image_undo_group_end (image); g_slist_free (invisible_list); } gimp_unset_busy (image->gimp); return layer; } return gimp_image_get_active_layer (image); }
static GimpLayer * gimp_image_merge_layers (GimpImage *image, GSList *merge_list, GimpContext *context, GimpMergeType merge_type, const gchar *undo_desc) { GList *list; GSList *reverse_list = NULL; PixelRegion src1PR, src2PR, maskPR; PixelRegion *mask; GimpLayer *merge_layer; GimpLayer *layer; GimpLayer *bottom_layer; GimpImageType type; gint count; gint x1, y1, x2, y2; gint x3, y3, x4, y4; CombinationMode operation; gint position; gboolean active[MAX_CHANNELS] = { TRUE, TRUE, TRUE, TRUE }; gint off_x, off_y; gchar *name; g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL); g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL); layer = NULL; type = GIMP_RGBA_IMAGE; x1 = y1 = 0; x2 = y2 = 0; bottom_layer = NULL; /* Get the layer extents */ count = 0; while (merge_list) { layer = merge_list->data; gimp_item_offsets (GIMP_ITEM (layer), &off_x, &off_y); switch (merge_type) { case GIMP_EXPAND_AS_NECESSARY: case GIMP_CLIP_TO_IMAGE: if (! count) { x1 = off_x; y1 = off_y; x2 = off_x + gimp_item_width (GIMP_ITEM (layer)); y2 = off_y + gimp_item_height (GIMP_ITEM (layer)); } else { if (off_x < x1) x1 = off_x; if (off_y < y1) y1 = off_y; if ((off_x + gimp_item_width (GIMP_ITEM (layer))) > x2) x2 = (off_x + gimp_item_width (GIMP_ITEM (layer))); if ((off_y + gimp_item_height (GIMP_ITEM (layer))) > y2) y2 = (off_y + gimp_item_height (GIMP_ITEM (layer))); } if (merge_type == GIMP_CLIP_TO_IMAGE) { x1 = CLAMP (x1, 0, gimp_image_get_width (image)); y1 = CLAMP (y1, 0, gimp_image_get_height (image)); x2 = CLAMP (x2, 0, gimp_image_get_width (image)); y2 = CLAMP (y2, 0, gimp_image_get_height (image)); } break; case GIMP_CLIP_TO_BOTTOM_LAYER: if (merge_list->next == NULL) { x1 = off_x; y1 = off_y; x2 = off_x + gimp_item_width (GIMP_ITEM (layer)); y2 = off_y + gimp_item_height (GIMP_ITEM (layer)); } break; case GIMP_FLATTEN_IMAGE: if (merge_list->next == NULL) { x1 = 0; y1 = 0; x2 = gimp_image_get_width (image); y2 = gimp_image_get_height (image); } break; } count ++; reverse_list = g_slist_prepend (reverse_list, layer); merge_list = g_slist_next (merge_list); } if ((x2 - x1) == 0 || (y2 - y1) == 0) return NULL; /* Start a merge undo group. */ gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_IMAGE_LAYERS_MERGE, undo_desc); name = g_strdup (gimp_object_get_name (GIMP_OBJECT (layer))); if (merge_type == GIMP_FLATTEN_IMAGE || gimp_drawable_type (GIMP_DRAWABLE (layer)) == GIMP_INDEXED_IMAGE) { guchar bg[4] = { 0, 0, 0, 0 }; type = GIMP_IMAGE_TYPE_FROM_BASE_TYPE (gimp_image_base_type (image)); merge_layer = gimp_layer_new (image, (x2 - x1), (y2 - y1), type, gimp_object_get_name (GIMP_OBJECT (layer)), GIMP_OPACITY_OPAQUE, GIMP_NORMAL_MODE); if (! merge_layer) { g_warning ("%s: could not allocate merge layer.", G_STRFUNC); return NULL; } GIMP_ITEM (merge_layer)->offset_x = x1; GIMP_ITEM (merge_layer)->offset_y = y1; /* get the background for compositing */ gimp_image_get_background (image, context, gimp_drawable_type (GIMP_DRAWABLE (merge_layer)), bg); /* init the pixel region */ pixel_region_init (&src1PR, gimp_drawable_get_tiles (GIMP_DRAWABLE (merge_layer)), 0, 0, (x2 - x1), (y2 - y1), TRUE); /* set the region to the background color */ color_region (&src1PR, bg); position = 0; } else { /* The final merged layer inherits the name of the bottom most layer * and the resulting layer has an alpha channel whether or not the * original did. Opacity is set to 100% and the MODE is set to normal. */ merge_layer = gimp_layer_new (image, (x2 - x1), (y2 - y1), gimp_drawable_type_with_alpha (GIMP_DRAWABLE (layer)), "merged layer", GIMP_OPACITY_OPAQUE, GIMP_NORMAL_MODE); if (!merge_layer) { g_warning ("%s: could not allocate merge layer", G_STRFUNC); return NULL; } GIMP_ITEM (merge_layer)->offset_x = x1; GIMP_ITEM (merge_layer)->offset_y = y1; /* clear the layer */ pixel_region_init (&src1PR, gimp_drawable_get_tiles (GIMP_DRAWABLE (merge_layer)), 0, 0, (x2 - x1), (y2 - y1), TRUE); clear_region (&src1PR); /* Find the index in the layer list of the bottom layer--we need this * in order to add the final, merged layer to the layer list correctly */ layer = reverse_list->data; position = gimp_container_num_children (image->layers) - gimp_container_get_child_index (image->layers, GIMP_OBJECT (layer)); } bottom_layer = layer; /* Copy the tattoo and parasites of the bottom layer to the new layer */ gimp_item_set_tattoo (GIMP_ITEM (merge_layer), gimp_item_get_tattoo (GIMP_ITEM (bottom_layer))); g_object_unref (GIMP_ITEM (merge_layer)->parasites); GIMP_ITEM (merge_layer)->parasites = gimp_parasite_list_copy (GIMP_ITEM (bottom_layer)->parasites); while (reverse_list) { GimpLayerModeEffects mode; layer = reverse_list->data; /* determine what sort of operation is being attempted and * if it's actually legal... */ operation = gimp_image_merge_layers_get_operation (merge_layer, layer); if (operation == -1) { gimp_layer_add_alpha (layer); /* try again ... */ operation = gimp_image_merge_layers_get_operation (merge_layer, layer); } if (operation == -1) { g_warning ("%s: attempting to merge incompatible layers.", G_STRFUNC); return NULL; } gimp_item_offsets (GIMP_ITEM (layer), &off_x, &off_y); x3 = CLAMP (off_x, x1, x2); y3 = CLAMP (off_y, y1, y2); x4 = CLAMP (off_x + gimp_item_width (GIMP_ITEM (layer)), x1, x2); y4 = CLAMP (off_y + gimp_item_height (GIMP_ITEM (layer)), y1, y2); /* configure the pixel regions */ pixel_region_init (&src1PR, gimp_drawable_get_tiles (GIMP_DRAWABLE (merge_layer)), (x3 - x1), (y3 - y1), (x4 - x3), (y4 - y3), TRUE); pixel_region_init (&src2PR, gimp_drawable_get_tiles (GIMP_DRAWABLE (layer)), (x3 - off_x), (y3 - off_y), (x4 - x3), (y4 - y3), FALSE); if (gimp_layer_get_mask (layer) && gimp_layer_mask_get_apply (layer->mask)) { TileManager *tiles; tiles = gimp_drawable_get_tiles (GIMP_DRAWABLE (layer->mask)); pixel_region_init (&maskPR, tiles, (x3 - off_x), (y3 - off_y), (x4 - x3), (y4 - y3), FALSE); mask = &maskPR; } else { mask = NULL; } /* DISSOLVE_MODE is special since it is the only mode that does not * work on the projection with the lower layer, but only locally on * the layers alpha channel. */ mode = gimp_layer_get_mode (layer); if (layer == bottom_layer && mode != GIMP_DISSOLVE_MODE) mode = GIMP_NORMAL_MODE; combine_regions (&src1PR, &src2PR, &src1PR, mask, NULL, gimp_layer_get_opacity (layer) * 255.999, mode, active, operation); gimp_image_remove_layer (image, layer); reverse_list = g_slist_next (reverse_list); } g_slist_free (reverse_list); /* if the type is flatten, remove all the remaining layers */ if (merge_type == GIMP_FLATTEN_IMAGE) { list = GIMP_LIST (image->layers)->list; while (list) { layer = list->data; list = g_list_next (list); gimp_image_remove_layer (image, layer); } gimp_image_add_layer (image, merge_layer, position); } else { /* Add the layer to the image */ gimp_image_add_layer (image, merge_layer, gimp_container_num_children (image->layers) - position + 1); } /* set the name after the original layers have been removed so we * don't end up with #2 appended to the name */ gimp_object_take_name (GIMP_OBJECT (merge_layer), name); gimp_item_set_visible (GIMP_ITEM (merge_layer), TRUE, TRUE); /* End the merge undo group */ gimp_image_undo_group_end (image); gimp_drawable_update (GIMP_DRAWABLE (merge_layer), 0, 0, gimp_item_width (GIMP_ITEM (merge_layer)), gimp_item_height (GIMP_ITEM (merge_layer))); return merge_layer; }
static gboolean webx_pipeline_check_update (WebxPipeline *pipeline) { gint *layers; gint num_layers; gint i; g_return_val_if_fail (WEBX_IS_PIPELINE (pipeline), FALSE); if (pipeline->rgb_image != -1) { gimp_image_delete (pipeline->rgb_image); pipeline->rgb_image = -1; } if (pipeline->indexed_image != -1) { gimp_image_delete (pipeline->indexed_image); pipeline->indexed_image = -1; } if (pipeline->background) { g_object_unref (pipeline->background); pipeline->background = NULL; } pipeline->rgb_image = gimp_image_duplicate (pipeline->user_image); gimp_image_undo_disable (pipeline->rgb_image); pipeline->rgb_layer = gimp_image_merge_visible_layers (pipeline->rgb_image, GIMP_CLIP_TO_IMAGE); /* make sure there is only one layer, where all visible layers were merged */ layers = gimp_image_get_layers (pipeline->rgb_image, &num_layers); for (i = 0; i < num_layers; i++) { if (layers[i] != pipeline->rgb_layer) gimp_image_remove_layer (pipeline->rgb_image, layers[i]); } g_free (layers); /* we don't want layer to be smaller than image */ gimp_layer_resize_to_image_size (pipeline->rgb_layer); gimp_image_scale (pipeline->rgb_image, pipeline->resize_width, pipeline->resize_height); webx_pipeline_create_background (pipeline); pipeline->crop_offsx *= pipeline->crop_scale_x; pipeline->crop_offsy *= pipeline->crop_scale_y; pipeline->crop_width *= pipeline->crop_scale_x; pipeline->crop_height *= pipeline->crop_scale_y; pipeline->crop_scale_x = 1.0; pipeline->crop_scale_y = 1.0; webx_pipeline_crop_clip (pipeline); if (pipeline->crop_width != pipeline->resize_width || pipeline->crop_height != pipeline->resize_height ) { gimp_image_crop (pipeline->rgb_image, pipeline->crop_width, pipeline->crop_height, pipeline->crop_offsx, pipeline->crop_offsy); } if (gimp_drawable_is_indexed (pipeline->rgb_layer)) { pipeline->indexed_image = gimp_image_duplicate (pipeline->rgb_image); gimp_image_undo_disable (pipeline->indexed_image); pipeline->indexed_layer = gimp_image_merge_visible_layers (pipeline->indexed_image, GIMP_CLIP_TO_IMAGE); } else { pipeline->indexed_image = -1; pipeline->indexed_layer = -1; } if ( ! gimp_drawable_is_rgb (pipeline->rgb_layer)) gimp_image_convert_rgb (pipeline->rgb_image); return TRUE; }
GimpLayer * gimp_image_merge_visible_layers (GimpImage *image, GimpContext *context, GimpMergeType merge_type, gboolean merge_active_group, gboolean discard_invisible) { GimpContainer *container; GList *list; GSList *merge_list = NULL; GSList *invisible_list = NULL; g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL); g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL); if (merge_active_group) { GimpLayer *active_layer = gimp_image_get_active_layer (image); /* if the active layer is the floating selection, get the * underlying drawable, but only if it is a layer */ if (active_layer && gimp_layer_is_floating_sel (active_layer)) { GimpDrawable *fs_drawable; fs_drawable = gimp_layer_get_floating_sel_drawable (active_layer); if (GIMP_IS_LAYER (fs_drawable)) active_layer = GIMP_LAYER (fs_drawable); } if (active_layer) container = gimp_item_get_container (GIMP_ITEM (active_layer)); else container = gimp_image_get_layers (image); } else { container = gimp_image_get_layers (image); } for (list = gimp_item_stack_get_item_iter (GIMP_ITEM_STACK (container)); list; list = g_list_next (list)) { GimpLayer *layer = list->data; if (gimp_layer_is_floating_sel (layer)) continue; if (gimp_item_get_visible (GIMP_ITEM (layer))) { merge_list = g_slist_append (merge_list, layer); } else if (discard_invisible) { invisible_list = g_slist_append (invisible_list, layer); } } if (merge_list) { GimpLayer *layer; gimp_set_busy (image->gimp); gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_IMAGE_LAYERS_MERGE, C_("undo-type", "Merge Visible Layers")); /* if there's a floating selection, anchor it */ if (gimp_image_get_floating_selection (image)) floating_sel_anchor (gimp_image_get_floating_selection (image)); layer = gimp_image_merge_layers (image, container, merge_list, context, merge_type); g_slist_free (merge_list); if (invisible_list) { GSList *list; for (list = invisible_list; list; list = g_slist_next (list)) gimp_image_remove_layer (image, list->data, TRUE, NULL); g_slist_free (invisible_list); } gimp_image_undo_group_end (image); gimp_unset_busy (image->gimp); return layer; } return gimp_image_get_active_layer (image); }
static GimpLayer * gimp_image_merge_layers (GimpImage *image, GimpContainer *container, GSList *merge_list, GimpContext *context, GimpMergeType merge_type) { GList *list; GSList *reverse_list = NULL; GSList *layers; GimpLayer *merge_layer; GimpLayer *layer; GimpLayer *bottom_layer; GimpParasiteList *parasites; gint count; gint x1, y1, x2, y2; gint off_x, off_y; gint position; gchar *name; GimpLayer *parent; g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL); g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL); layer = NULL; x1 = y1 = 0; x2 = y2 = 0; bottom_layer = NULL; parent = gimp_layer_get_parent (merge_list->data); /* Get the layer extents */ count = 0; while (merge_list) { layer = merge_list->data; gimp_item_get_offset (GIMP_ITEM (layer), &off_x, &off_y); switch (merge_type) { case GIMP_EXPAND_AS_NECESSARY: case GIMP_CLIP_TO_IMAGE: if (! count) { x1 = off_x; y1 = off_y; x2 = off_x + gimp_item_get_width (GIMP_ITEM (layer)); y2 = off_y + gimp_item_get_height (GIMP_ITEM (layer)); } else { if (off_x < x1) x1 = off_x; if (off_y < y1) y1 = off_y; if ((off_x + gimp_item_get_width (GIMP_ITEM (layer))) > x2) x2 = (off_x + gimp_item_get_width (GIMP_ITEM (layer))); if ((off_y + gimp_item_get_height (GIMP_ITEM (layer))) > y2) y2 = (off_y + gimp_item_get_height (GIMP_ITEM (layer))); } if (merge_type == GIMP_CLIP_TO_IMAGE) { x1 = CLAMP (x1, 0, gimp_image_get_width (image)); y1 = CLAMP (y1, 0, gimp_image_get_height (image)); x2 = CLAMP (x2, 0, gimp_image_get_width (image)); y2 = CLAMP (y2, 0, gimp_image_get_height (image)); } break; case GIMP_CLIP_TO_BOTTOM_LAYER: if (merge_list->next == NULL) { x1 = off_x; y1 = off_y; x2 = off_x + gimp_item_get_width (GIMP_ITEM (layer)); y2 = off_y + gimp_item_get_height (GIMP_ITEM (layer)); } break; case GIMP_FLATTEN_IMAGE: if (merge_list->next == NULL) { x1 = 0; y1 = 0; x2 = gimp_image_get_width (image); y2 = gimp_image_get_height (image); } break; } count ++; reverse_list = g_slist_prepend (reverse_list, layer); merge_list = g_slist_next (merge_list); } if ((x2 - x1) == 0 || (y2 - y1) == 0) return NULL; /* Start a merge undo group. */ name = g_strdup (gimp_object_get_name (layer)); if (merge_type == GIMP_FLATTEN_IMAGE || (gimp_drawable_is_indexed (GIMP_DRAWABLE (layer)) && ! gimp_drawable_has_alpha (GIMP_DRAWABLE (layer)))) { GeglColor *color; GimpRGB bg; merge_layer = gimp_layer_new (image, (x2 - x1), (y2 - y1), gimp_image_get_layer_format (image, FALSE), gimp_object_get_name (layer), GIMP_OPACITY_OPAQUE, GIMP_NORMAL_MODE); if (! merge_layer) { g_warning ("%s: could not allocate merge layer.", G_STRFUNC); return NULL; } gimp_item_set_offset (GIMP_ITEM (merge_layer), x1, y1); /* get the background for compositing */ gimp_context_get_background (context, &bg); color = gimp_gegl_color_new (&bg); gegl_buffer_set_color (gimp_drawable_get_buffer (GIMP_DRAWABLE (merge_layer)), GEGL_RECTANGLE(0,0,x2-x1,y2-y1), color); g_object_unref (color); position = 0; } else { /* The final merged layer inherits the name of the bottom most layer * and the resulting layer has an alpha channel whether or not the * original did. Opacity is set to 100% and the MODE is set to normal. */ merge_layer = gimp_layer_new (image, (x2 - x1), (y2 - y1), gimp_drawable_get_format_with_alpha (GIMP_DRAWABLE (layer)), "merged layer", GIMP_OPACITY_OPAQUE, GIMP_NORMAL_MODE); if (!merge_layer) { g_warning ("%s: could not allocate merge layer", G_STRFUNC); return NULL; } gimp_item_set_offset (GIMP_ITEM (merge_layer), x1, y1); /* clear the layer */ gegl_buffer_clear (gimp_drawable_get_buffer (GIMP_DRAWABLE (merge_layer)), NULL); /* Find the index in the layer list of the bottom layer--we need this * in order to add the final, merged layer to the layer list correctly */ layer = reverse_list->data; position = gimp_container_get_n_children (container) - gimp_container_get_child_index (container, GIMP_OBJECT (layer)); } bottom_layer = layer; /* Copy the tattoo and parasites of the bottom layer to the new layer */ gimp_item_set_tattoo (GIMP_ITEM (merge_layer), gimp_item_get_tattoo (GIMP_ITEM (bottom_layer))); parasites = gimp_item_get_parasites (GIMP_ITEM (bottom_layer)); parasites = gimp_parasite_list_copy (parasites); gimp_item_set_parasites (GIMP_ITEM (merge_layer), parasites); g_object_unref (parasites); for (layers = reverse_list; layers; layers = g_slist_next (layers)) { GeglBuffer *merge_buffer; GeglBuffer *layer_buffer; GimpApplicator *applicator; GimpLayerModeEffects mode; layer = layers->data; gimp_item_get_offset (GIMP_ITEM (layer), &off_x, &off_y); /* DISSOLVE_MODE is special since it is the only mode that does not * work on the projection with the lower layer, but only locally on * the layers alpha channel. */ mode = gimp_layer_get_mode (layer); if (layer == bottom_layer && mode != GIMP_DISSOLVE_MODE) mode = GIMP_NORMAL_MODE; merge_buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (merge_layer)); layer_buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (layer)); applicator = gimp_applicator_new (NULL, gimp_drawable_get_linear (GIMP_DRAWABLE (layer)), FALSE, FALSE); if (gimp_layer_get_mask (layer) && gimp_layer_get_apply_mask (layer)) { GeglBuffer *mask_buffer; mask_buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (layer->mask)); gimp_applicator_set_mask_buffer (applicator, mask_buffer); gimp_applicator_set_mask_offset (applicator, - (x1 - off_x), - (y1 - off_y)); } gimp_applicator_set_src_buffer (applicator, merge_buffer); gimp_applicator_set_dest_buffer (applicator, merge_buffer); gimp_applicator_set_apply_buffer (applicator, layer_buffer); gimp_applicator_set_apply_offset (applicator, - (x1 - off_x), - (y1 - off_y)); gimp_applicator_set_mode (applicator, gimp_layer_get_opacity (layer), mode); gimp_applicator_blit (applicator, GEGL_RECTANGLE (0, 0, gegl_buffer_get_width (merge_buffer), gegl_buffer_get_height (merge_buffer))); g_object_unref (applicator); gimp_image_remove_layer (image, layer, TRUE, NULL); } g_slist_free (reverse_list); gimp_object_take_name (GIMP_OBJECT (merge_layer), name); gimp_item_set_visible (GIMP_ITEM (merge_layer), TRUE, FALSE); /* if the type is flatten, remove all the remaining layers */ if (merge_type == GIMP_FLATTEN_IMAGE) { list = gimp_image_get_layer_iter (image); while (list) { layer = list->data; list = g_list_next (list); gimp_image_remove_layer (image, layer, TRUE, NULL); } gimp_image_add_layer (image, merge_layer, parent, position, TRUE); } else { /* Add the layer to the image */ gimp_image_add_layer (image, merge_layer, parent, gimp_container_get_n_children (container) - position + 1, TRUE); } gimp_drawable_update (GIMP_DRAWABLE (merge_layer), 0, 0, gimp_item_get_width (GIMP_ITEM (merge_layer)), gimp_item_get_height (GIMP_ITEM (merge_layer))); return merge_layer; }
static void dog (gint32 image_ID, GimpDrawable *drawable, gdouble inner, gdouble outer, gboolean show_progress) { GimpDrawable *drawable1; GimpDrawable *drawable2; gint32 drawable_id = drawable->drawable_id; gint32 layer1; gint32 layer2; gint width, height; gint x1, y1, x2, y2; guchar maxval = 255; gimp_drawable_mask_bounds (drawable_id, &x1, &y1, &x2, &y2); width = (x2 - x1); height = (y2 - y1); gimp_drawable_flush (drawable); layer1 = gimp_layer_copy (drawable_id); gimp_item_set_visible (layer1, FALSE); gimp_item_set_name (layer1, "dog_scratch_layer1"); gimp_image_insert_layer (image_ID, layer1, gimp_item_get_parent (drawable_id), 0); layer2 = gimp_layer_copy (drawable_id); gimp_item_set_visible (layer2, FALSE); gimp_item_set_name (layer2, "dog_scratch_layer2"); gimp_image_insert_layer (image_ID, layer2, gimp_item_get_parent (drawable_id), 0); drawable1 = gimp_drawable_get (layer1); drawable2 = gimp_drawable_get (layer2); gauss_rle (drawable1, inner, 0, show_progress); gauss_rle (drawable2, outer, 1, show_progress); compute_difference (drawable, drawable1, drawable2, &maxval); gimp_drawable_detach (drawable1); gimp_drawable_detach (drawable2); gimp_image_remove_layer (image_ID, layer1); gimp_image_remove_layer (image_ID, layer2); gimp_drawable_flush (drawable); gimp_drawable_merge_shadow (drawable_id, TRUE); gimp_drawable_update (drawable_id, x1, y1, width, height); if (dogvals.normalize || dogvals.invert) /* gimp_invert doesn't work properly with previews due to shadow handling * so reimplement it here - see Bug 557380 */ { normalize_invert (drawable, dogvals.normalize, maxval, dogvals.invert); gimp_drawable_flush (drawable); gimp_drawable_merge_shadow (drawable_id, TRUE); gimp_drawable_update (drawable_id, x1, y1, width, height); } }
/* ------------------------------------ * gap_image_merge_group_layer * ------------------------------------ * merge the specified group layer and return the id of the resulting layer. * * The merge strategy * o) create a temporary image of same size/type (l_tmp_img_id) * o) copy the specified grouplayer to the temporary image (l_tmp_img_id) * o) call gimp_image_merge_visible_layers on the temporary image (l_tmp_img_id, mode) * o) copy the merged layer back to the original image * to the same group at the position of the original layergroup * o) remove the temporary image * o) remove original layergroup * o) rename the resuling merged layer. * * returns 0 if all done OK * (or -1 on error) */ gint32 gap_image_merge_group_layer(gint32 image_id, gint32 group_layer_id, gint merge_mode) { gint32 l_tmp_img_id; gint32 l_new_layer_id; gint32 l_merged_layer_id; gint32 l_parent_id; gint32 l_position; gint l_src_offset_x; gint l_src_offset_y; gboolean l_visible; char *l_name; if (!gimp_item_is_group(group_layer_id)) { /* the specified group_layer_id is not a group * -- no merge is done, return its id as result -- */ return(group_layer_id); } l_visible = gimp_item_get_visible(group_layer_id); l_name = gimp_item_get_name(group_layer_id); /* create a temporary image */ l_tmp_img_id = gap_image_new_of_samesize(image_id); /* copy the grouplayer to the temporary image */ l_new_layer_id = gap_layer_copy_to_dest_image(l_tmp_img_id, group_layer_id, 100.0, /* full opacity */ 0, /* NORMAL paintmode */ &l_src_offset_x, &l_src_offset_y ); gimp_image_insert_layer (l_tmp_img_id, l_new_layer_id, 0, 0); gimp_layer_set_offsets(l_new_layer_id, l_src_offset_x, l_src_offset_y); gimp_item_set_visible(l_new_layer_id, TRUE); /* merge visible layers in the temporary image */ l_merged_layer_id = gimp_image_merge_visible_layers (l_tmp_img_id, merge_mode); l_new_layer_id = gap_layer_copy_to_dest_image(image_id, l_merged_layer_id, gimp_layer_get_opacity(group_layer_id), gimp_layer_get_mode(group_layer_id), &l_src_offset_x, &l_src_offset_y ); l_position = gimp_image_get_item_position (image_id, group_layer_id); l_parent_id = gimp_item_get_parent(group_layer_id); if (l_parent_id < 0) { l_parent_id = 0; } gimp_image_insert_layer (image_id, l_new_layer_id, l_parent_id, l_position); gimp_layer_set_offsets(l_new_layer_id, l_src_offset_x, l_src_offset_y); /* remove the original group layer from the original image */ gimp_image_remove_layer(image_id, group_layer_id); /* restore the original layer name */ if (l_name != NULL) { gimp_item_set_name(l_new_layer_id, l_name); g_free(l_name); } gimp_item_set_visible(l_new_layer_id, l_visible); /* remove the temporary image */ gap_image_delete_immediate(l_tmp_img_id); return(l_new_layer_id); } /* end gap_image_merge_group_layer */
/* ----------------------------- * gap_fg_matting_exec_apply_run * ----------------------------- * handle undo, progress init and * apply the processing functions */ gint32 gap_fg_matting_exec_apply_run (gint32 image_id, gint32 drawable_id , gboolean doProgress, gboolean doFlush , GapFgExtractValues *fgValPtr) { gint32 retLayerId; gint32 oldLayerMaskId; gint32 triMapOrig; gint32 triMapRelevant; gint32 dummyLayerId; GimpDrawable *maskDrawable; GimpDrawable *activeDrawable; /* dont operate on other drawables than layers */ g_return_val_if_fail (gimp_drawable_is_layer(drawable_id), -1); globalDoProgress = doProgress; triMapOrig = fgValPtr->tri_map_drawable_id; /* try to use layermask as tri-mask * in case negative id was specified by the caller */ oldLayerMaskId = gimp_layer_get_mask(drawable_id); if (fgValPtr->tri_map_drawable_id < 0) { fgValPtr->tri_map_drawable_id = oldLayerMaskId; } gimp_image_undo_group_start (image_id); if (doProgress) { gimp_progress_init (_("Foreground Extract")); } activeDrawable = gimp_drawable_get (drawable_id); triMapRelevant = p_tri_map_preprocessing (activeDrawable, fgValPtr, &dummyLayerId); maskDrawable = gimp_drawable_get(triMapRelevant); if (maskDrawable == NULL) { gimp_image_undo_group_end (image_id); gimp_drawable_detach (activeDrawable); printf("ERROR: no valid tri-mask was specified\n"); return (-1); } if(gap_debug) { printf("gap_fg_matting_exec_apply_run START: drawableID:%d triMapOrig:%d tri_map_drawable_id:%d triMapRelevant:%d\n" " create_layermask:%d lock_color:%d " " create_result:%d colordiff_threshold:%.5f" "\n" , (int)drawable_id , (int)triMapOrig , (int)fgValPtr->tri_map_drawable_id , (int)triMapRelevant , (int)fgValPtr->create_layermask , (int)fgValPtr->lock_color , (int)fgValPtr->create_result , (float)fgValPtr->colordiff_threshold ); } retLayerId = gap_drawable_foreground_extract (activeDrawable, maskDrawable, fgValPtr); gimp_drawable_detach (maskDrawable); if(dummyLayerId >= 0) { if(gap_debug) { printf("removing dummy layer:%d\n" ,(int) dummyLayerId ); } gimp_image_remove_layer(image_id, dummyLayerId); } if (doProgress) { gimp_progress_update(1.0); } gimp_image_undo_group_end (image_id); if(gap_debug) { printf("gap_fg_matting_exec_apply_run DONE: retLayerId:%d\n" , (int)retLayerId ); } if (doFlush != FALSE) { gimp_drawable_flush (activeDrawable); } gimp_drawable_detach (activeDrawable); return (retLayerId); } /* end gap_fg_matting_exec_apply_run */
void gimp_image_crop (GimpImage *image, GimpContext *context, GimpFillType fill_type, gint x, gint y, gint width, gint height, gboolean crop_layers) { GList *list; gint previous_width; gint previous_height; g_return_if_fail (GIMP_IS_IMAGE (image)); g_return_if_fail (GIMP_IS_CONTEXT (context)); previous_width = gimp_image_get_width (image); previous_height = gimp_image_get_height (image); /* Make sure new width and height are non-zero */ if (width < 1 || height < 1) return; gimp_set_busy (image->gimp); g_object_freeze_notify (G_OBJECT (image)); if (crop_layers) gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_IMAGE_CROP, C_("undo-type", "Crop Image")); else gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_IMAGE_RESIZE, C_("undo-type", "Resize Image")); /* Push the image size to the stack */ gimp_image_undo_push_image_size (image, NULL, x, y, width, height); /* Set the new width and height */ g_object_set (image, "width", width, "height", height, NULL); /* Resize all channels */ for (list = gimp_image_get_channel_iter (image); list; list = g_list_next (list)) { GimpItem *item = list->data; gimp_item_resize (item, context, GIMP_FILL_TRANSPARENT, width, height, -x, -y); } /* Resize all vectors */ for (list = gimp_image_get_vectors_iter (image); list; list = g_list_next (list)) { GimpItem *item = list->data; gimp_item_resize (item, context, GIMP_FILL_TRANSPARENT, width, height, -x, -y); } /* Don't forget the selection mask! */ gimp_item_resize (GIMP_ITEM (gimp_image_get_mask (image)), context, GIMP_FILL_TRANSPARENT, width, height, -x, -y); /* crop all layers */ list = gimp_image_get_layer_iter (image); while (list) { GimpItem *item = list->data; list = g_list_next (list); gimp_item_translate (item, -x, -y, TRUE); if (crop_layers) { gint off_x, off_y; gint lx1, ly1, lx2, ly2; gimp_item_get_offset (item, &off_x, &off_y); lx1 = CLAMP (off_x, 0, gimp_image_get_width (image)); ly1 = CLAMP (off_y, 0, gimp_image_get_height (image)); lx2 = CLAMP (gimp_item_get_width (item) + off_x, 0, gimp_image_get_width (image)); ly2 = CLAMP (gimp_item_get_height (item) + off_y, 0, gimp_image_get_height (image)); width = lx2 - lx1; height = ly2 - ly1; if (width > 0 && height > 0) { gimp_item_resize (item, context, fill_type, width, height, -(lx1 - off_x), -(ly1 - off_y)); } else { gimp_image_remove_layer (image, GIMP_LAYER (item), TRUE, NULL); } } } /* Reposition or remove guides */ list = gimp_image_get_guides (image); while (list) { GimpGuide *guide = list->data; gboolean remove_guide = FALSE; gint position = gimp_guide_get_position (guide); list = g_list_next (list); switch (gimp_guide_get_orientation (guide)) { case GIMP_ORIENTATION_HORIZONTAL: position -= y; if ((position < 0) || (position > height)) remove_guide = TRUE; break; case GIMP_ORIENTATION_VERTICAL: position -= x; if ((position < 0) || (position > width)) remove_guide = TRUE; break; default: break; } if (remove_guide) gimp_image_remove_guide (image, guide, TRUE); else if (position != gimp_guide_get_position (guide)) gimp_image_move_guide (image, guide, position, TRUE); } /* Reposition or remove sample points */ list = gimp_image_get_sample_points (image); while (list) { GimpSamplePoint *sample_point = list->data; gboolean remove_sample_point = FALSE; gint old_x; gint old_y; gint new_x; gint new_y; list = g_list_next (list); gimp_sample_point_get_position (sample_point, &old_x, &old_y); new_x = old_x; new_y = old_y; new_y -= y; if ((new_y < 0) || (new_y > height)) remove_sample_point = TRUE; new_x -= x; if ((new_x < 0) || (new_x > width)) remove_sample_point = TRUE; if (remove_sample_point) gimp_image_remove_sample_point (image, sample_point, TRUE); else if (new_x != old_x || new_y != old_y) gimp_image_move_sample_point (image, sample_point, new_x, new_y, TRUE); } gimp_image_undo_group_end (image); gimp_image_size_changed_detailed (image, -x, -y, previous_width, previous_height); g_object_thaw_notify (G_OBJECT (image)); gimp_unset_busy (image->gimp); }
void gimp_image_scale (GimpImage *image, gint new_width, gint new_height, GimpInterpolationType interpolation_type, GimpProgress *progress) { GimpProgress *sub_progress; GList *all_layers; GList *all_channels; GList *all_vectors; GList *list; gint old_width; gint old_height; gint offset_x; gint offset_y; gdouble img_scale_w = 1.0; gdouble img_scale_h = 1.0; gint progress_steps; gint progress_current = 0; g_return_if_fail (GIMP_IS_IMAGE (image)); g_return_if_fail (new_width > 0 && new_height > 0); g_return_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress)); gimp_set_busy (image->gimp); sub_progress = gimp_sub_progress_new (progress); all_layers = gimp_image_get_layer_list (image); all_channels = gimp_image_get_channel_list (image); all_vectors = gimp_image_get_vectors_list (image); progress_steps = (g_list_length (all_layers) + g_list_length (all_channels) + g_list_length (all_vectors) + 1 /* selection */); g_object_freeze_notify (G_OBJECT (image)); gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_IMAGE_SCALE, C_("undo-type", "Scale Image")); old_width = gimp_image_get_width (image); old_height = gimp_image_get_height (image); img_scale_w = (gdouble) new_width / (gdouble) old_width; img_scale_h = (gdouble) new_height / (gdouble) old_height; offset_x = (old_width - new_width) / 2; offset_y = (old_height - new_height) / 2; /* Push the image size to the stack */ gimp_image_undo_push_image_size (image, NULL, offset_x, offset_y, new_width, new_height); /* Set the new width and height early, so below image item setters * (esp. guides and sample points) don't choke about moving stuff * out of the image */ g_object_set (image, "width", new_width, "height", new_height, NULL); /* Scale all channels */ for (list = all_channels; list; list = g_list_next (list)) { GimpItem *item = list->data; gimp_sub_progress_set_step (GIMP_SUB_PROGRESS (sub_progress), progress_current++, progress_steps); gimp_item_scale (item, new_width, new_height, 0, 0, interpolation_type, sub_progress); } /* Scale all vectors */ for (list = all_vectors; list; list = g_list_next (list)) { GimpItem *item = list->data; gimp_sub_progress_set_step (GIMP_SUB_PROGRESS (sub_progress), progress_current++, progress_steps); gimp_item_scale (item, new_width, new_height, 0, 0, interpolation_type, sub_progress); } /* Don't forget the selection mask! */ gimp_sub_progress_set_step (GIMP_SUB_PROGRESS (sub_progress), progress_current++, progress_steps); gimp_item_scale (GIMP_ITEM (gimp_image_get_mask (image)), new_width, new_height, 0, 0, interpolation_type, sub_progress); /* Scale all layers */ for (list = all_layers; list; list = g_list_next (list)) { GimpItem *item = list->data; gimp_sub_progress_set_step (GIMP_SUB_PROGRESS (sub_progress), progress_current++, progress_steps); /* group layers are updated automatically */ if (gimp_viewable_get_children (GIMP_VIEWABLE (item))) { gimp_group_layer_suspend_resize (GIMP_GROUP_LAYER (item), FALSE); continue; } if (! gimp_item_scale_by_factors (item, img_scale_w, img_scale_h, interpolation_type, sub_progress)) { /* Since 0 < img_scale_w, img_scale_h, failure due to one or more * vanishing scaled layer dimensions. Implicit delete implemented * here. Upstream warning implemented in resize_check_layer_scaling(), * which offers the user the chance to bail out. */ gimp_image_remove_layer (image, GIMP_LAYER (item), TRUE, NULL); } } for (list = all_layers; list; list = g_list_next (list)) if (gimp_viewable_get_children (list->data)) gimp_group_layer_resume_resize (list->data, FALSE); /* Scale all Guides */ for (list = gimp_image_get_guides (image); list; list = g_list_next (list)) { GimpGuide *guide = list->data; gint position = gimp_guide_get_position (guide); switch (gimp_guide_get_orientation (guide)) { case GIMP_ORIENTATION_HORIZONTAL: gimp_image_move_guide (image, guide, (position * new_height) / old_height, TRUE); break; case GIMP_ORIENTATION_VERTICAL: gimp_image_move_guide (image, guide, (position * new_width) / old_width, TRUE); break; default: break; } } /* Scale all sample points */ for (list = gimp_image_get_sample_points (image); list; list = g_list_next (list)) { GimpSamplePoint *sample_point = list->data; gimp_image_move_sample_point (image, sample_point, sample_point->x * new_width / old_width, sample_point->y * new_height / old_height, TRUE); } gimp_image_undo_group_end (image); g_list_free (all_layers); g_list_free (all_channels); g_list_free (all_vectors); g_object_unref (sub_progress); gimp_image_size_changed_detailed (image, -offset_x, -offset_y, old_width, old_height); g_object_thaw_notify (G_OBJECT (image)); gimp_unset_busy (image->gimp); }
static void dog (gint32 image_ID, GimpDrawable *drawable, gdouble inner, gdouble outer, gboolean show_progress) { GimpDrawable *drawable1; GimpDrawable *drawable2; gint32 drawable_id = drawable->drawable_id; gint32 layer1; gint32 layer2; gint width, height; gint x1, y1, x2, y2; guchar maxval = 255; gimp_drawable_mask_bounds (drawable_id, &x1, &y1, &x2, &y2); width = (x2 - x1); height = (y2 - y1); gimp_drawable_flush (drawable); layer1 = gimp_layer_copy (drawable_id); gimp_drawable_set_visible (layer1, FALSE); gimp_drawable_set_name (layer1, "dog_scratch_layer1"); gimp_image_add_layer (image_ID, layer1, 0); layer2 = gimp_layer_copy (drawable_id); gimp_drawable_set_visible (layer2, FALSE); gimp_drawable_set_name (layer2, "dog_scratch_layer2"); gimp_image_add_layer (image_ID, layer2, 0); drawable1 = gimp_drawable_get (layer1); drawable2 = gimp_drawable_get (layer2); gauss_rle (drawable1, inner, 0, show_progress); gauss_rle (drawable2, outer, 1, show_progress); compute_difference (drawable, drawable1, drawable2, &maxval); gimp_drawable_detach (drawable1); gimp_drawable_detach (drawable2); gimp_image_remove_layer (image_ID, layer1); gimp_image_remove_layer (image_ID, layer2); gimp_drawable_flush (drawable); gimp_drawable_merge_shadow (drawable_id, TRUE); gimp_drawable_update (drawable_id, x1, y1, width, height); if (dogvals.normalize) { normalize (drawable, maxval); gimp_drawable_flush (drawable); gimp_drawable_merge_shadow (drawable_id, TRUE); gimp_drawable_update (drawable_id, x1, y1, width, height); } if (dogvals.invert) gimp_invert (drawable_id); }
void gimp_image_crop (GimpImage *image, GimpContext *context, gint x1, gint y1, gint x2, gint y2, gboolean active_layer_only, gboolean crop_layers) { gint width, height; gint previous_width, previous_height; g_return_if_fail (GIMP_IS_IMAGE (image)); g_return_if_fail (GIMP_IS_CONTEXT (context)); previous_width = gimp_image_get_width (image); previous_height = gimp_image_get_height (image); width = x2 - x1; height = y2 - y1; /* Make sure new width and height are non-zero */ if (width < 1 || height < 1) return; gimp_set_busy (image->gimp); if (active_layer_only) { GimpLayer *layer; gint off_x, off_y; layer = gimp_image_get_active_layer (image); gimp_item_offsets (GIMP_ITEM (layer), &off_x, &off_y); off_x -= x1; off_y -= y1; gimp_item_resize (GIMP_ITEM (layer), context, width, height, off_x, off_y); } else { GimpItem *item; GList *list; g_object_freeze_notify (G_OBJECT (image)); if (crop_layers) gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_IMAGE_CROP, C_("command", "Crop Image")); else gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_IMAGE_RESIZE, _("Resize Image")); /* Push the image size to the stack */ gimp_image_undo_push_image_size (image, NULL, x1, y1, width, height); /* Set the new width and height */ g_object_set (image, "width", width, "height", height, NULL); /* Resize all channels */ for (list = GIMP_LIST (image->channels)->list; list; list = g_list_next (list)) { item = (GimpItem *) list->data; gimp_item_resize (item, context, width, height, -x1, -y1); } /* Resize all vectors */ for (list = GIMP_LIST (image->vectors)->list; list; list = g_list_next (list)) { item = (GimpItem *) list->data; gimp_item_resize (item, context, width, height, -x1, -y1); } /* Don't forget the selection mask! */ gimp_item_resize (GIMP_ITEM (gimp_image_get_mask (image)), context, width, height, -x1, -y1); /* crop all layers */ list = GIMP_LIST (image->layers)->list; while (list) { item = (GimpItem *) list->data; list = g_list_next (list); gimp_item_translate (item, -x1, -y1, TRUE); if (crop_layers) { gint off_x, off_y; gint lx1, ly1, lx2, ly2; gimp_item_offsets (item, &off_x, &off_y); lx1 = CLAMP (off_x, 0, gimp_image_get_width (image)); ly1 = CLAMP (off_y, 0, gimp_image_get_height (image)); lx2 = CLAMP (gimp_item_width (item) + off_x, 0, gimp_image_get_width (image)); ly2 = CLAMP (gimp_item_height (item) + off_y, 0, gimp_image_get_height (image)); width = lx2 - lx1; height = ly2 - ly1; if (width > 0 && height > 0) gimp_item_resize (item, context, width, height, -(lx1 - off_x), -(ly1 - off_y)); else gimp_image_remove_layer (image, GIMP_LAYER (item)); } } /* Reposition or remove all guides */ list = gimp_image_get_guides (image); while (list) { GimpGuide *guide = list->data; gboolean remove_guide = FALSE; gint position = gimp_guide_get_position (guide); list = g_list_next (list); switch (gimp_guide_get_orientation (guide)) { case GIMP_ORIENTATION_HORIZONTAL: if ((position < y1) || (position > y2)) remove_guide = TRUE; else position -= y1; break; case GIMP_ORIENTATION_VERTICAL: if ((position < x1) || (position > x2)) remove_guide = TRUE; else position -= x1; break; default: break; } if (remove_guide) gimp_image_remove_guide (image, guide, TRUE); else if (position != gimp_guide_get_position (guide)) gimp_image_move_guide (image, guide, position, TRUE); } /* Reposition or remove sample points */ list = gimp_image_get_sample_points (image); while (list) { GimpSamplePoint *sample_point = list->data; gboolean remove_sample_point = FALSE; gint new_x = sample_point->x; gint new_y = sample_point->y; list = g_list_next (list); new_y -= y1; if ((sample_point->y < y1) || (sample_point->y > y2)) remove_sample_point = TRUE; new_x -= x1; if ((sample_point->x < x1) || (sample_point->x > x2)) remove_sample_point = TRUE; if (remove_sample_point) gimp_image_remove_sample_point (image, sample_point, TRUE); else if (new_x != sample_point->x || new_y != sample_point->y) gimp_image_move_sample_point (image, sample_point, new_x, new_y, TRUE); } gimp_image_undo_group_end (image); gimp_image_update (image, 0, 0, gimp_image_get_width (image), gimp_image_get_height (image)); gimp_image_size_changed_detailed (image, -x1, -y1, previous_width, previous_height); g_object_thaw_notify (G_OBJECT (image)); } gimp_unset_busy (image->gimp); }