app: fix layer filter copying.

Copying filters over from one image to a partial copy was broken on
multiple level by doing it on an additional loop, and assuming that the
originally selected layers and the newly created ones had the same
structure:

1. First the actually copied layers may be more numerous. For instance,
   we'd also copy parent layers. Typically copying a layer under a layer
   group, both the layer and its parent layer group would be in the clip
   image.
2. Second, because this structure may change, the assumptions made so
   that filters were not copied to the right image.
3. And as a last consequence, sometimes we could have crashes, assuming
   the same structure and therefore directly dereferencing a NULL
   pointer. I had such a crash when copy-pasting a layer group, while
   also selecting its children layers (though this crash also got hidden
   by my previous commit, but just by chance).

Instead just copy filters in the same time as layers are copied, so that
we can easily associate the filter from the correct original layer we
copied from.
This commit is contained in:
Jehan 2024-08-22 20:49:59 +02:00
parent 408c22dd70
commit 690391b985
3 changed files with 61 additions and 95 deletions

View File

@ -33,8 +33,6 @@
#include "core/gimpcontainer.h"
#include "core/gimpdrawable.h"
#include "core/gimpdrawable-edit.h"
#include "core/gimpdrawable-filters.h"
#include "core/gimpdrawablefilter.h"
#include "core/gimpfilloptions.h"
#include "core/gimplayer.h"
#include "core/gimplayer-new.h"
@ -722,55 +720,6 @@ edit_paste (GimpDisplay *display,
{
gimp_image_set_selected_layers (image, pasted_layers);
/* Copy over layer effects */
if (GIMP_IS_IMAGE (paste))
{
GList *old_layers_list;
GList *new_layers_list;
old_layers_list = gimp_image_get_layer_iter (GIMP_IMAGE (paste));
for (new_layers_list = pasted_layers; new_layers_list;
new_layers_list = g_list_next (new_layers_list))
{
GimpLayer *layer = old_layers_list->data;
GimpLayer *new_layer = new_layers_list->data;
if (gimp_drawable_has_filters (GIMP_DRAWABLE (layer)))
{
GList *filter_list;
GimpContainer *filters;
filters = gimp_drawable_get_filters (GIMP_DRAWABLE (layer));
for (filter_list = GIMP_LIST (filters)->queue->tail;
filter_list;
filter_list = g_list_previous (filter_list))
{
if (GIMP_IS_DRAWABLE_FILTER (filter_list->data))
{
GimpDrawableFilter *old_filter = filter_list->data;
GimpDrawableFilter *filter;
filter =
gimp_drawable_filter_duplicate (GIMP_DRAWABLE (new_layer),
old_filter);
if (filter != NULL)
{
gimp_drawable_filter_apply (filter, NULL);
gimp_drawable_filter_commit (filter, TRUE, NULL, FALSE);
gimp_drawable_filter_layer_mask_freeze (filter);
g_object_unref (filter);
}
}
}
}
old_layers_list = g_list_next (old_layers_list);
}
}
g_list_free (pasted_layers);
gimp_image_flush (image);
}

View File

@ -31,6 +31,8 @@
#include "gimpbuffer.h"
#include "gimpcontext.h"
#include "gimpdrawable-edit.h"
#include "gimpdrawable-filters.h"
#include "gimpdrawablefilter.h"
#include "gimperror.h"
#include "gimpgrouplayer.h"
#include "gimpimage.h"
@ -493,6 +495,36 @@ gimp_edit_paste_get_tagged_layers (GimpImage *image,
{
layer = GIMP_LAYER (gimp_item_convert (GIMP_ITEM (iter->data),
image, layer_type));
if (gimp_drawable_has_filters (GIMP_DRAWABLE (iter->data)))
{
GList *filter_list;
GimpContainer *filters;
filters = gimp_drawable_get_filters (GIMP_DRAWABLE (iter->data));
for (filter_list = GIMP_LIST (filters)->queue->tail;
filter_list;
filter_list = g_list_previous (filter_list))
{
if (GIMP_IS_DRAWABLE_FILTER (filter_list->data))
{
GimpDrawableFilter *old_filter = filter_list->data;
GimpDrawableFilter *filter;
filter = gimp_drawable_filter_duplicate (GIMP_DRAWABLE (layer), old_filter);
if (filter != NULL)
{
gimp_drawable_filter_apply (filter, NULL);
gimp_drawable_filter_commit (filter, TRUE, NULL, FALSE);
gimp_drawable_filter_layer_mask_freeze (filter);
g_object_unref (filter);
}
}
}
}
returned_layers = g_list_prepend (returned_layers, layer);
switch (paste_type)

View File

@ -388,6 +388,35 @@ gimp_image_new_copy_drawables (GimpImage *image,
if (gimp_layer_can_lock_alpha (new_layer))
gimp_layer_set_lock_alpha (new_layer, FALSE, FALSE);
if (gimp_drawable_has_filters (GIMP_DRAWABLE (iter->data)))
{
GList *filter_list;
GimpContainer *filters;
filters = gimp_drawable_get_filters (GIMP_DRAWABLE (iter->data));
for (filter_list = GIMP_LIST (filters)->queue->tail; filter_list;
filter_list = g_list_previous (filter_list))
{
if (GIMP_IS_DRAWABLE_FILTER (filter_list->data))
{
GimpDrawableFilter *old_filter = filter_list->data;
GimpDrawableFilter *filter;
filter = gimp_drawable_filter_duplicate (GIMP_DRAWABLE (new_layer), old_filter);
if (filter != NULL)
{
gimp_drawable_filter_apply (filter, NULL);
gimp_drawable_filter_commit (filter, TRUE, NULL, FALSE);
gimp_drawable_filter_layer_mask_freeze (filter);
g_object_unref (filter);
}
}
}
}
gimp_image_add_layer (new_image, new_layer, new_parent, index++, TRUE);
/* If a group, loop through children. */
@ -419,8 +448,6 @@ gimp_image_new_from_drawables (Gimp *gimp,
gdouble xres;
gdouble yres;
GimpColorProfile *profile = NULL;
GList *old_layers_list;
GList *new_layers_list;
g_return_val_if_fail (GIMP_IS_GIMP (gimp), NULL);
g_return_val_if_fail (drawables != NULL, NULL);
@ -478,48 +505,6 @@ gimp_image_new_from_drawables (Gimp *gimp,
gimp_image_new_copy_drawables (image, drawables, new_image, tag_copies, NULL, NULL, NULL, NULL);
/* Copy any attached layer effects */
old_layers_list = drawables;
for (new_layers_list = gimp_image_get_layer_iter (new_image);
new_layers_list; new_layers_list = g_list_next (new_layers_list))
{
GimpLayer *layer = old_layers_list->data;
GimpLayer *new_layer = new_layers_list->data;
if (gimp_drawable_has_filters (GIMP_DRAWABLE (layer)))
{
GList *filter_list;
GimpContainer *filters;
filters = gimp_drawable_get_filters (GIMP_DRAWABLE (layer));
for (filter_list = GIMP_LIST (filters)->queue->tail; filter_list;
filter_list = g_list_previous (filter_list))
{
if (GIMP_IS_DRAWABLE_FILTER (filter_list->data))
{
GimpDrawableFilter *old_filter = filter_list->data;
GimpDrawableFilter *filter;
filter =
gimp_drawable_filter_duplicate (GIMP_DRAWABLE (new_layer),
old_filter);
if (filter != NULL)
{
gimp_drawable_filter_apply (filter, NULL);
gimp_drawable_filter_commit (filter, TRUE, NULL, FALSE);
gimp_drawable_filter_layer_mask_freeze (filter);
g_object_unref (filter);
}
}
}
}
old_layers_list = g_list_next (old_layers_list);
}
gimp_image_undo_enable (new_image);
return new_image;