Hi,
I added a new Script-Fu API command to simplify a frequently used operation that was too slow using the existing building blocks.
Previously, to intersect a layer’s alpha with a base layer’s alpha, I used Script-Fu:
;; Clone the base layers alpha to the painting layer
(when trim
(let ((layer-mask (add-mask-to-layer layer ADD-MASK-ALPHA-TRANSFER))
(base-mask (add-mask-to-layer base-layer ADD-MASK-ALPHA-TRANSFER)))
(gimp-channel-combine-masks layer-mask base-mask CHANNEL-OP-INTERSECT 0 0)
(gimp-layer-remove-mask base-layer MASK-APPLY)
(gimp-layer-remove-mask layer MASK-APPLY)))
Now I have a faster shortcut:
(when trim
(gimp-layer-combine-alpha layer base-layer CHANNEL-OP-INTERSECT 0 0))
I hacked together the implementation by borrowing from the gimp-channel-combine-masks logic. It does what I need, but I suspect it’s inefficient. I briefly attempted a direct buffer-level solution but didn’t get far. I’d appreciate feedback.
This function is intended for repeatedly trimming excess paint by intersecting a painting layer’s alpha with another layer’s alpha. The constant creation and restoration of masks feels wasteful. Maybe it’s fine. Maybe it’s not.
Any thoughts?
void
gimp_layer_combine_alpha (GimpLayer *dst_layer,
GimpLayer *src_layer,
GimpChannelOps op,
gint offx,
gint offy)
{
GimpLayerMask *dst_mask, *src_mask;
GeglBuffer *dst_buffer, *src_buffer;
GimpChannelCombineData data;
g_return_if_fail (GIMP_IS_LAYER (dst_layer));
g_return_if_fail (GIMP_IS_LAYER (src_layer));
g_return_if_fail (gimp_drawable_has_alpha (GIMP_DRAWABLE (dst_layer)));
g_return_if_fail (gimp_drawable_has_alpha (GIMP_DRAWABLE (src_layer)));
// Create two masks from the layers alpha, alpha gets removed
dst_mask = gimp_layer_create_mask (dst_layer, GIMP_ADD_MASK_ALPHA_TRANSFER, NULL);
src_mask = gimp_layer_create_mask (src_layer, GIMP_ADD_MASK_ALPHA_TRANSFER, NULL);
// Store as buffers for GEGL op
dst_buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (dst_mask));
src_buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (src_mask));
if (gimp_alpha_combine_start (GIMP_CHANNEL (dst_mask), op,
GEGL_RECTANGLE (
offx + gegl_buffer_get_x (src_buffer),
offy + gegl_buffer_get_y (src_buffer),
gegl_buffer_get_width (src_buffer),
gegl_buffer_get_height (src_buffer)),
FALSE, FALSE, &data))
{
gimp_gegl_mask_combine_buffer (dst_buffer, src_buffer, op, offx, offy);
gimp_alpha_combine_end (GIMP_CHANNEL (dst_mask), &data);
}
// Restore alpha from masks
gimp_layer_add_mask (dst_layer, dst_mask, FALSE, NULL);
gimp_layer_apply_mask (dst_layer, GIMP_MASK_APPLY, FALSE);
gimp_layer_add_mask (src_layer, src_mask, FALSE, NULL);
gimp_layer_apply_mask (src_layer, GIMP_MASK_APPLY, FALSE);
}