[gimp/wip/passthrough] app: adapt gimp_image_merge_layers() to handle pass-through groups ...
- From: N/A <ell src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gimp/wip/passthrough] app: adapt gimp_image_merge_layers() to handle pass-through groups ...
- Date: Mon, 24 Apr 2017 10:12:01 +0000 (UTC)
commit 90d9f0148e210d396e0b64dcaa45d54f19b038e8
Author: Ell <ell_se yahoo com>
Date: Sun Apr 23 17:47:59 2017 -0400
app: adapt gimp_image_merge_layers() to handle pass-through groups ...
... and fix flatten-image along the way. *And* do some cleanup.
Currently, gimp_image_merge_layers() combines the layers on its own,
one by one. This is incompatible with pass-through groups, because
the group's buffer is rendered independently of its backdrop, while
we need to take the backdrop into account when mergeing the group.
Instead, render the subgraph of the parent graph, corresponding to
the set of merged layers, directly into the new layer. Since the
layers we merge are always visible and continuous, we only need a
minor massage to the parent graph. This takes care of pass-through
groups inherently.
This commit also changes the behavior of flatten-image: Currently,
the flattened layers are rendered directly on top of the opaque
background, which can make previously-hidden areas (due to layers
using composite modes other than src-over, or legacy layer modes)
visible. This is almost certainly not desirable.
Instead, construct the graph such that the flattened layers are
combined with the background only after being merged with one
another.
app/core/gimpimage-merge.c | 213 +++++++++++++++++---------------------------
1 files changed, 81 insertions(+), 132 deletions(-)
---
diff --git a/app/core/gimpimage-merge.c b/app/core/gimpimage-merge.c
index bc8ec4b..ce23ca0 100644
--- a/app/core/gimpimage-merge.c
+++ b/app/core/gimpimage-merge.c
@@ -27,9 +27,9 @@
#include "core-types.h"
-#include "gegl/gimpapplicator.h"
#include "gegl/gimp-babl-compat.h"
#include "gegl/gimp-gegl-apply-operation.h"
+#include "gegl/gimp-gegl-nodes.h"
#include "gegl/gimp-gegl-utils.h"
#include "vectors/gimpvectors.h"
@@ -421,35 +421,36 @@ gimp_image_merge_layers (GimpImage *image,
GimpContext *context,
GimpMergeType merge_type)
{
- GList *list;
- GSList *reverse_list = NULL;
+ GimpLayer *parent;
+ gint x1, y1;
+ gint x2, y2;
GSList *layers;
- GimpLayer *merge_layer;
GimpLayer *layer;
+ GimpLayer *top_layer;
GimpLayer *bottom_layer;
- GimpParasiteList *parasites;
- gint count;
- gint x1, y1, x2, y2;
- gint off_x, off_y;
+ GimpLayer *merge_layer;
gint position;
- gchar *name;
- GimpLayer *parent;
+ GeglNode *node;
+ GeglNode *source_node;
+ GeglNode *flatten_node;
+ GeglNode *offset_node;
+ GeglNode *last_node;
+ GeglNode *last_node_source;
+ GimpParasiteList *parasites;
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)
+ x1 = y1 = 0;
+ x2 = y2 = 0;
+ for (layers = merge_list; layers; layers = g_slist_next (layers))
{
- layer = merge_list->data;
+ gint off_x, off_y;
+
+ layer = layers->data;
gimp_item_get_offset (GIMP_ITEM (layer), &off_x, &off_y);
@@ -457,7 +458,7 @@ gimp_image_merge_layers (GimpImage *image,
{
case GIMP_EXPAND_AS_NECESSARY:
case GIMP_CLIP_TO_IMAGE:
- if (! count)
+ if (layers == merge_list)
{
x1 = off_x;
y1 = off_y;
@@ -486,7 +487,7 @@ gimp_image_merge_layers (GimpImage *image,
break;
case GIMP_CLIP_TO_BOTTOM_LAYER:
- if (merge_list->next == NULL)
+ if (layers->next == NULL)
{
x1 = off_x;
y1 = off_y;
@@ -496,7 +497,7 @@ gimp_image_merge_layers (GimpImage *image,
break;
case GIMP_FLATTEN_IMAGE:
- if (merge_list->next == NULL)
+ if (layers->next == NULL)
{
x1 = 0;
y1 = 0;
@@ -505,56 +506,41 @@ gimp_image_merge_layers (GimpImage *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)
- {
- g_slist_free (reverse_list);
+ return NULL;
- return NULL;
- }
-
- /* Start a merge undo group. */
+ top_layer = merge_list->data;
+ bottom_layer = layer;
- name = g_strdup (gimp_object_get_name (layer));
+ flatten_node = NULL;
if (merge_type == GIMP_FLATTEN_IMAGE ||
(gimp_drawable_is_indexed (GIMP_DRAWABLE (layer)) &&
- ! gimp_drawable_has_alpha (GIMP_DRAWABLE (layer))))
+ ! gimp_drawable_has_alpha (GIMP_DRAWABLE (layer))))
{
- GeglColor *color;
- GimpRGB bg;
+ 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_object_get_name (bottom_layer),
GIMP_OPACITY_OPAQUE,
GIMP_LAYER_MODE_NORMAL_LEGACY);
+
if (! merge_layer)
{
g_warning ("%s: could not allocate merge layer", G_STRFUNC);
- g_free (name);
- g_slist_free (reverse_list);
-
return NULL;
}
- gimp_item_set_offset (GIMP_ITEM (merge_layer), x1, y1);
-
/* get the background for compositing */
gimp_context_get_background (context, &bg);
gimp_pickable_srgb_to_image_color (GIMP_PICKABLE (layer),
&bg, &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);
+ flatten_node = gimp_gegl_create_flatten_node (&bg);
position = 0;
}
@@ -567,8 +553,8 @@ gimp_image_merge_layers (GimpImage *image,
merge_layer =
gimp_layer_new (image, (x2 - x1), (y2 - y1),
- gimp_drawable_get_format_with_alpha (GIMP_DRAWABLE (layer)),
- "merged layer",
+ gimp_drawable_get_format_with_alpha (GIMP_DRAWABLE (bottom_layer)),
+ gimp_object_get_name (bottom_layer),
GIMP_OPACITY_OPAQUE,
GIMP_LAYER_MODE_NORMAL_LEGACY);
@@ -576,120 +562,84 @@ gimp_image_merge_layers (GimpImage *image,
{
g_warning ("%s: could not allocate merge layer", G_STRFUNC);
- g_free (name);
- g_slist_free (reverse_list);
-
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));
+ gimp_container_get_child_index (container, GIMP_OBJECT (bottom_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;
- GimpLayerMode mode;
- GimpLayerColorSpace blend_space;
- GimpLayerColorSpace composite_space;
- GimpLayerCompositeMode composite_mode;
+ gimp_item_set_offset (GIMP_ITEM (merge_layer), x1, y1);
- layer = layers->data;
+ /* Build our graph inside the top-layer's parent's node */
+ source_node = gimp_filter_get_node (GIMP_FILTER (top_layer));
- gimp_item_get_offset (GIMP_ITEM (layer), &off_x, &off_y);
+ node = gegl_node_get_parent (source_node);
+ g_assert (node != NULL);
- /* MODE_DISSOLVE 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);
- blend_space = gimp_layer_get_blend_space (layer);
- composite_space = gimp_layer_get_composite_space (layer);
- composite_mode = gimp_layer_get_composite_mode (layer);
+ offset_node = gegl_node_new_child (node,
+ "operation", "gegl:translate",
+ "x", (gdouble) -x1,
+ "y", (gdouble) -y1,
+ NULL);
- if (layer == bottom_layer)
- {
- if (mode != GIMP_LAYER_MODE_DISSOLVE)
- mode = GIMP_LAYER_MODE_NORMAL_LEGACY;
-
- blend_space = GIMP_LAYER_COLOR_SPACE_AUTO;
- composite_space = GIMP_LAYER_COLOR_SPACE_AUTO;
- composite_mode = GIMP_LAYER_COMPOSITE_AUTO;
- }
-
- merge_buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (merge_layer));
- layer_buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (layer));
-
- applicator = gimp_applicator_new (NULL, FALSE, FALSE);
+ if (flatten_node)
+ {
+ gegl_node_add_child (node, flatten_node);
+ g_object_unref (flatten_node);
- if (gimp_layer_get_mask (layer) &&
- gimp_layer_get_apply_mask (layer))
- {
- GeglBuffer *mask_buffer;
+ gegl_node_link_many (source_node, flatten_node, offset_node, NULL);
+ }
+ else
+ {
+ gegl_node_link_many (source_node, offset_node, NULL);
+ }
- mask_buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (layer->mask));
+ /* Disconnect the bottom-layer node's input */
+ last_node = gimp_filter_get_node (GIMP_FILTER (bottom_layer));
+ last_node_source = gegl_node_get_producer (last_node, "input", NULL);
- gimp_applicator_set_mask_buffer (applicator, mask_buffer);
- gimp_applicator_set_mask_offset (applicator,
- - (x1 - off_x),
- - (y1 - off_y));
- }
+ gegl_node_disconnect (last_node, "input");
- gimp_applicator_set_src_buffer (applicator, merge_buffer);
- gimp_applicator_set_dest_buffer (applicator, merge_buffer);
+ /* Render the graph into the merge layer */
+ gegl_node_blit_buffer (offset_node,
+ gimp_drawable_get_buffer (GIMP_DRAWABLE (merge_layer)),
+ NULL, 0, GEGL_ABYSS_NONE);
- gimp_applicator_set_apply_buffer (applicator, layer_buffer);
- gimp_applicator_set_apply_offset (applicator,
- - (x1 - off_x),
- - (y1 - off_y));
+ /* Reconnect the bottom-layer node's input */
+ if (last_node_source)
+ gegl_node_link (last_node_source, last_node);
- gimp_applicator_set_opacity (applicator, gimp_layer_get_opacity (layer));
- gimp_applicator_set_mode (applicator, mode,
- blend_space, composite_space, composite_mode);
+ /* Clean up the graph */
+ gegl_node_remove_child (node, offset_node);
- gimp_applicator_blit (applicator,
- GEGL_RECTANGLE (0, 0,
- gegl_buffer_get_width (merge_buffer),
- gegl_buffer_get_height (merge_buffer)));
+ if (flatten_node)
+ gegl_node_remove_child (node, flatten_node);
- g_object_unref (applicator);
+ /* 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)));
- gimp_image_remove_layer (image, layer, TRUE, NULL);
- }
+ 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);
- g_slist_free (reverse_list);
+ /* Remove the merged layers from the image */
+ for (layers = merge_list; layers; layers = g_slist_next (layers))
+ gimp_image_remove_layer (image, layers->data, TRUE, NULL);
- 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);
+ GList *list = gimp_image_get_layer_iter (image);
+
while (list)
{
layer = list->data;
@@ -704,7 +654,6 @@ gimp_image_merge_layers (GimpImage *image,
else
{
/* Add the layer to the image */
-
gimp_image_add_layer (image, merge_layer, parent,
gimp_container_get_n_children (container) -
position + 1,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]