app: further fix merging a pass-through group when opacity < 1.0.

Just using the output of the group is not enough since the pass-through
mode cannot be reused for the normal layer (and anyway all below layers
will have been removed). This still works out with a full-opacity
pass-through, but for lesser opacity, what we want is to replace with
not just the group's render, but in fact the render after the
compositing node.

As far as my tests go, we should now have exactly the same render before
and after merging a pass-through group, whatever the group opacity.
This commit is contained in:
Jehan 2025-03-11 14:17:48 +01:00
parent 7013fad34d
commit 388e346a5c

View file

@ -410,10 +410,11 @@ GimpLayer *
gimp_image_merge_group_layer (GimpImage *image,
GimpGroupLayer *group)
{
GimpLayer *parent;
GimpLayer *layer;
gboolean is_pass_through = FALSE;
gint index;
GimpLayer *parent;
GimpLayer *layer;
GeglBuffer *pass_through_buffer = NULL;
gboolean is_pass_through = FALSE;
gint index;
g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL);
g_return_val_if_fail (GIMP_IS_GROUP_LAYER (group), NULL);
@ -428,6 +429,16 @@ gimp_image_merge_group_layer (GimpImage *image,
is_pass_through = (gimp_layer_get_mode (GIMP_LAYER (group)) == GIMP_LAYER_MODE_PASS_THROUGH &&
gimp_item_get_visible (GIMP_ITEM (group)));
if (is_pass_through && gimp_layer_get_opacity (GIMP_LAYER (group)) < 1.0)
{
GimpDrawable *drawable = GIMP_DRAWABLE (group);
GeglNode *mode_node = gimp_drawable_get_mode_node (drawable);
GeglRectangle rect;
rect = gegl_node_get_bounding_box (mode_node);
pass_through_buffer = gegl_buffer_new (&rect, gimp_drawable_get_format (drawable));
gegl_node_blit_buffer (mode_node, pass_through_buffer, NULL, 0, GEGL_ABYSS_NONE);
}
/* Merge down filter effects */
gimp_drawable_merge_filters (GIMP_DRAWABLE (group));
@ -441,6 +452,20 @@ gimp_image_merge_group_layer (GimpImage *image,
gimp_image_remove_layer (image, GIMP_LAYER (group), TRUE, NULL);
gimp_image_add_layer (image, layer, parent, index, TRUE);
/* Pass-through groups are a very special case. The duplicate works
* out if the original was at full opacity. But with lower opacity,
* what we want is in fact the output of the "gimp:pass-through" mode
* (similar to "gimp:replace") because we can't reproduce the same
* render otherwise.
* This works well, since anyway the merged layer is ensured to be the
* bottomest one on its own level.
*/
if (pass_through_buffer)
{
gimp_drawable_set_buffer (GIMP_DRAWABLE (layer), FALSE, NULL, pass_through_buffer);
g_object_unref (pass_through_buffer);
}
/* For pass-through group layers, we must remove all "big sister"
* layers, i.e. all layers on the same level below the newly merged
* layer, because their render is already integrated in the merged