static void gimp_layer_prop_undo_constructed (GObject *object) { GimpLayerPropUndo *layer_prop_undo = GIMP_LAYER_PROP_UNDO (object); GimpLayer *layer; G_OBJECT_CLASS (parent_class)->constructed (object); g_assert (GIMP_IS_LAYER (GIMP_ITEM_UNDO (object)->item)); layer = GIMP_LAYER (GIMP_ITEM_UNDO (object)->item); switch (GIMP_UNDO (object)->undo_type) { case GIMP_UNDO_LAYER_MODE: layer_prop_undo->mode = gimp_layer_get_mode (layer); break; case GIMP_UNDO_LAYER_OPACITY: layer_prop_undo->opacity = gimp_layer_get_opacity (layer); break; case GIMP_UNDO_LAYER_LOCK_ALPHA: layer_prop_undo->lock_alpha = gimp_layer_get_lock_alpha (layer); break; default: g_assert_not_reached (); } }
static void gimp_layer_prop_undo_pop (GimpUndo *undo, GimpUndoMode undo_mode, GimpUndoAccumulator *accum) { GimpLayerPropUndo *layer_prop_undo = GIMP_LAYER_PROP_UNDO (undo); GimpLayer *layer = GIMP_LAYER (GIMP_ITEM_UNDO (undo)->item); GIMP_UNDO_CLASS (parent_class)->pop (undo, undo_mode, accum); switch (undo->undo_type) { case GIMP_UNDO_LAYER_REPOSITION: { gint position; position = gimp_image_get_layer_index (undo->image, layer); gimp_image_position_layer (undo->image, layer, layer_prop_undo->position, FALSE, NULL); layer_prop_undo->position = position; } break; case GIMP_UNDO_LAYER_MODE: { GimpLayerModeEffects mode; mode = gimp_layer_get_mode (layer); gimp_layer_set_mode (layer, layer_prop_undo->mode, FALSE); layer_prop_undo->mode = mode; } break; case GIMP_UNDO_LAYER_OPACITY: { gdouble opacity; opacity = gimp_layer_get_opacity (layer); gimp_layer_set_opacity (layer, layer_prop_undo->opacity, FALSE); layer_prop_undo->opacity = opacity; } break; case GIMP_UNDO_LAYER_LOCK_ALPHA: { gboolean lock_alpha; lock_alpha = gimp_layer_get_lock_alpha (layer); gimp_layer_set_lock_alpha (layer, layer_prop_undo->lock_alpha, FALSE); layer_prop_undo->lock_alpha = lock_alpha; } break; default: g_assert_not_reached (); } }
/** * gimp_projection_initialize: * @proj: A #GimpProjection. * @x: * @y: * @w: * @h: * * This function determines whether a visible layer with combine mode * Normal provides complete coverage over the specified area. If not, * the projection is initialized to transparent black. */ static void gimp_projection_initialize (GimpProjection *proj, gint x, gint y, gint w, gint h) { GList *list; gint proj_off_x; gint proj_off_y; gboolean coverage = FALSE; gimp_projectable_get_offset (proj->projectable, &proj_off_x, &proj_off_y); for (list = gimp_projectable_get_layers (proj->projectable); list; list = g_list_next (list)) { GimpLayer *layer = list->data; GimpDrawable *drawable = GIMP_DRAWABLE (layer); GimpItem *item = GIMP_ITEM (layer); gint off_x, off_y; gimp_item_get_offset (item, &off_x, &off_y); /* subtract the projectable's offsets because the list of * update areas is in tile-pyramid coordinates, but our * external API is always in terms of image coordinates. */ off_x -= proj_off_x; off_y -= proj_off_y; if (gimp_item_get_visible (item) && ! gimp_drawable_has_alpha (drawable) && ! gimp_layer_get_mask (layer) && gimp_layer_get_mode (layer) == GIMP_NORMAL_MODE && gimp_layer_get_opacity (layer) == GIMP_OPACITY_OPAQUE && off_x <= x && off_y <= y && (off_x + gimp_item_get_width (item)) >= (x + w) && (off_y + gimp_item_get_height (item)) >= (y + h)) { coverage = TRUE; break; } } if (! coverage) { PixelRegion region; pixel_region_init (®ion, gimp_pickable_get_tiles (GIMP_PICKABLE (proj)), x, y, w, h, TRUE); clear_region (®ion); } }
static GObject * gimp_layer_prop_undo_constructor (GType type, guint n_params, GObjectConstructParam *params) { GObject *object; GimpLayerPropUndo *layer_prop_undo; GimpImage *image; GimpLayer *layer; object = G_OBJECT_CLASS (parent_class)->constructor (type, n_params, params); layer_prop_undo = GIMP_LAYER_PROP_UNDO (object); g_assert (GIMP_IS_LAYER (GIMP_ITEM_UNDO (object)->item)); image = GIMP_UNDO (object)->image; layer = GIMP_LAYER (GIMP_ITEM_UNDO (object)->item); switch (GIMP_UNDO (object)->undo_type) { case GIMP_UNDO_LAYER_REPOSITION: layer_prop_undo->position = gimp_image_get_layer_index (image, layer); break; case GIMP_UNDO_LAYER_MODE: layer_prop_undo->mode = gimp_layer_get_mode (layer); break; case GIMP_UNDO_LAYER_OPACITY: layer_prop_undo->opacity = gimp_layer_get_opacity (layer); break; case GIMP_UNDO_LAYER_LOCK_ALPHA: layer_prop_undo->lock_alpha = gimp_layer_get_lock_alpha (layer); break; default: g_assert_not_reached (); } return object; }
/** * gimp_text_layer_from_layer: * @layer: a #GimpLayer object * @text: a #GimpText object * * Converts a standard #GimpLayer and a #GimpText object into a * #GimpTextLayer. The new text layer takes ownership of the @text and * @layer objects. The @layer object is rendered unusable by this * function. Don't even try to use if afterwards! * * This is a gross hack that is needed in order to load text layers * from XCF files in a backwards-compatible way. Please don't use it * for anything else! * * Return value: a newly allocated #GimpTextLayer object **/ static GimpLayer * gimp_text_layer_from_layer (GimpLayer *layer, GimpText *text) { GimpTextLayer *text_layer; GimpDrawable *drawable; g_return_val_if_fail (GIMP_IS_LAYER (layer), NULL); g_return_val_if_fail (GIMP_IS_TEXT (text), NULL); text_layer = g_object_new (GIMP_TYPE_TEXT_LAYER, "image", gimp_item_get_image (GIMP_ITEM (layer)), NULL); gimp_item_replace_item (GIMP_ITEM (text_layer), GIMP_ITEM (layer)); drawable = GIMP_DRAWABLE (text_layer); gimp_drawable_steal_buffer (drawable, GIMP_DRAWABLE (layer)); gimp_layer_set_opacity (GIMP_LAYER (text_layer), gimp_layer_get_opacity (layer), FALSE); gimp_layer_set_mode (GIMP_LAYER (text_layer), gimp_layer_get_mode (layer), FALSE); gimp_layer_set_blend_space (GIMP_LAYER (text_layer), gimp_layer_get_blend_space (layer), FALSE); gimp_layer_set_composite_space (GIMP_LAYER (text_layer), gimp_layer_get_composite_space (layer), FALSE); gimp_layer_set_composite_mode (GIMP_LAYER (text_layer), gimp_layer_get_composite_mode (layer), FALSE); gimp_layer_set_lock_alpha (GIMP_LAYER (text_layer), gimp_layer_get_lock_alpha (layer), FALSE); gimp_text_layer_set_text (text_layer, text); g_object_unref (text); g_object_unref (layer); return GIMP_LAYER (text_layer); }
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 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; }
/* ------------------------------------ * 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 */