mirror of https://github.com/GNOME/gimp.git
app: improve alpha to selection with multiple items.
I created a new function gimp_channel_combine_items() which combines a list of items with a channel. The list of items is first combined together as an union set, then only combined with the channel with the desired operation (this is important for operations such as intersect which was broken in my previous commit because all items would be intersected with each other and the selection, whereas we actually want the union of all items to be intersected with the selection). This new function is now used for "Alpha to Selection". Also similarly to copy or color-pick on multi-layers, alpha to selection will now use the composited result of the multi-layers as visible. In particular it means that opacity, modes and visible properties on the layers are taken into account. Alpha to selection on a single layer though still works as previously, only taking the non-composited layer data into account. I am actually struggling if alpha to selection on uncomposited layers (just an union on alpha to selection result for each layer) would not make sense to on some workflows. To be experimented. Finally it is to be noted that this function should also work on channels and vectors (both single or multiple; and of course in such cases, compositing does not matter) though I haven't tested yet. It could even work with a source mix of layers, channels and vectors, though our GUI does not allow such action currently.
This commit is contained in:
parent
a90f59d961
commit
32740ac0de
|
@ -35,6 +35,7 @@
|
|||
|
||||
#include "core/gimp.h"
|
||||
#include "core/gimpchannel.h"
|
||||
#include "core/gimpchannel-combine.h"
|
||||
#include "core/gimpcontainer.h"
|
||||
#include "core/gimpcontext.h"
|
||||
#include "core/gimpdrawable-fill.h"
|
||||
|
@ -1556,22 +1557,15 @@ layers_alpha_to_selection_cmd_callback (GimpAction *action,
|
|||
{
|
||||
GimpImage *image;
|
||||
GList *layers;
|
||||
GList *iter;
|
||||
GimpChannelOps operation;
|
||||
return_if_no_layers (image, layers, data);
|
||||
|
||||
operation = (GimpChannelOps) g_variant_get_int32 (value);
|
||||
|
||||
for (iter = layers; iter; iter = iter->next)
|
||||
{
|
||||
if (operation != GIMP_CHANNEL_OP_REPLACE || iter == layers)
|
||||
gimp_item_to_selection (GIMP_ITEM (iter->data), operation,
|
||||
TRUE, FALSE, 0.0, 0.0);
|
||||
else
|
||||
gimp_item_to_selection (GIMP_ITEM (iter->data),
|
||||
GIMP_CHANNEL_OP_ADD,
|
||||
TRUE, FALSE, 0.0, 0.0);
|
||||
}
|
||||
gimp_channel_push_undo (gimp_image_get_mask (image),
|
||||
C_("undo-type", "Alpha to Selection"));
|
||||
gimp_channel_combine_items (gimp_image_get_mask (image),
|
||||
layers, operation);
|
||||
gimp_image_flush (image);
|
||||
}
|
||||
|
||||
|
|
|
@ -29,8 +29,15 @@
|
|||
|
||||
#include "gegl/gimp-gegl-mask-combine.h"
|
||||
|
||||
#include "gimp.h"
|
||||
#include "gimpchannel.h"
|
||||
#include "gimpchannel-combine.h"
|
||||
#include "gimpimage.h"
|
||||
#include "gimpimage-merge.h"
|
||||
#include "gimpimage-new.h"
|
||||
#include "gimplayer.h"
|
||||
|
||||
#include "vectors/gimpvectors.h"
|
||||
|
||||
|
||||
typedef struct
|
||||
|
@ -469,3 +476,106 @@ gimp_channel_combine_buffer (GimpChannel *mask,
|
|||
|
||||
gimp_channel_combine_end (mask, &data);
|
||||
}
|
||||
|
||||
/**
|
||||
* gimp_channel_combine_items:
|
||||
* @channel:
|
||||
* @items:
|
||||
* @op:
|
||||
*
|
||||
* Edit @channel with the given @items, according to the boolean @op.
|
||||
* @items need to belong to the same image, but it doesn't have to be
|
||||
* the owner image of @channel.
|
||||
* If @items contain a single layer, it will be used as-is, without
|
||||
* caring about opacity, mode or visibility.
|
||||
* If @items contain several layers, they will be used composited using
|
||||
* their opacity, mode, visibility, etc. properties within the image
|
||||
* (similar as if a "merge visible" had been applied to the image then
|
||||
* the resulting layer used alone).
|
||||
* If @items contain channels or vectors, they will be added as a set
|
||||
* (i.e. as a single item which is an union of other items). E.g. an
|
||||
* combine in GIMP_CHANNEL_OP_INTERSECT mode does not intersect all
|
||||
* @items with each other and @channel. It first adds-alike all @items
|
||||
* together, then intersects the result with @channel.
|
||||
*/
|
||||
void
|
||||
gimp_channel_combine_items (GimpChannel *mask,
|
||||
GList *items,
|
||||
GimpChannelOps op)
|
||||
{
|
||||
GimpImage *image;
|
||||
GimpImage *items_image = NULL;
|
||||
GimpImage *temp_image = NULL;
|
||||
|
||||
GimpChannel *channel = NULL;
|
||||
GList *layers = NULL;
|
||||
GList *iter;
|
||||
|
||||
g_return_if_fail (GIMP_IS_CHANNEL (mask));
|
||||
g_return_if_fail (g_list_length (items) > 0);
|
||||
|
||||
for (iter = items; iter; iter = iter->next)
|
||||
{
|
||||
g_return_if_fail (GIMP_IS_LAYER (iter->data) ||
|
||||
GIMP_IS_CHANNEL (iter->data) ||
|
||||
GIMP_IS_VECTORS (iter->data));
|
||||
|
||||
if (items_image == NULL)
|
||||
items_image = gimp_item_get_image (iter->data);
|
||||
else
|
||||
g_return_if_fail (items_image == gimp_item_get_image (iter->data));
|
||||
|
||||
if (GIMP_IS_LAYER (iter->data))
|
||||
layers = g_list_prepend (layers, iter->data);
|
||||
}
|
||||
|
||||
image = gimp_item_get_image (GIMP_ITEM (mask));
|
||||
if (g_list_length (layers) > 1)
|
||||
{
|
||||
GList *merged_layers;
|
||||
|
||||
temp_image = gimp_image_new_from_drawables (image->gimp, items, FALSE);
|
||||
merged_layers = gimp_image_merge_visible_layers (temp_image,
|
||||
gimp_get_user_context (temp_image->gimp),
|
||||
GIMP_CLIP_TO_IMAGE,
|
||||
FALSE, TRUE, NULL);
|
||||
g_return_if_fail (g_list_length (merged_layers) == 1);
|
||||
gimp_item_to_selection (GIMP_ITEM (merged_layers->data),
|
||||
GIMP_CHANNEL_OP_REPLACE,
|
||||
TRUE, FALSE, 0.0, 0.0);
|
||||
channel = gimp_image_get_mask (temp_image);
|
||||
}
|
||||
|
||||
if (! channel)
|
||||
{
|
||||
channel = gimp_channel_new (image,
|
||||
gimp_image_get_width (image),
|
||||
gimp_image_get_height (image),
|
||||
NULL, NULL);
|
||||
gimp_channel_clear (channel, NULL, FALSE);
|
||||
|
||||
if (g_list_length (layers) == 1)
|
||||
gimp_channel_combine_buffer (channel,
|
||||
gimp_drawable_get_buffer (GIMP_DRAWABLE (layers->data)),
|
||||
GIMP_CHANNEL_OP_REPLACE, 0, 0);
|
||||
}
|
||||
|
||||
for (iter = items; iter; iter = iter->next)
|
||||
{
|
||||
if (! GIMP_IS_LAYER (iter->data))
|
||||
gimp_channel_combine_buffer (channel,
|
||||
gimp_drawable_get_buffer (GIMP_DRAWABLE (iter->data)),
|
||||
GIMP_CHANNEL_OP_ADD, 0, 0);
|
||||
}
|
||||
|
||||
gimp_channel_combine_buffer (mask,
|
||||
gimp_drawable_get_buffer (GIMP_DRAWABLE (channel)),
|
||||
op, 0, 0);
|
||||
|
||||
if (temp_image)
|
||||
g_object_unref (temp_image);
|
||||
else
|
||||
g_object_unref (channel);
|
||||
|
||||
g_list_free (layers);
|
||||
}
|
||||
|
|
|
@ -52,5 +52,9 @@ void gimp_channel_combine_buffer (GimpChannel *mask,
|
|||
gint off_x,
|
||||
gint off_y);
|
||||
|
||||
void gimp_channel_combine_items (GimpChannel *mask,
|
||||
GList *items,
|
||||
GimpChannelOps op);
|
||||
|
||||
|
||||
#endif /* __GIMP_CHANNEL_COMBINE_H__ */
|
||||
|
|
Loading…
Reference in New Issue