mirror of https://github.com/GNOME/gimp.git
app: merge layers in chunks, and show progress
In gimp_image_merge_layers() -- the internal function used by the various layer-merging/flattenning functions -- process the merged- layer graph in chunks, using gimp_gegl_apply_operation(), instead of in one go, using gegl_node_blit_buffer(). Processing in chunks better utilizes the cache, since it reduces the size of intermediate buffers, reducing the chances of hitting the swap when merging large images (see, for example, issue #3012.) Additionally, this allows us to show progress indication. Have the relevant gimpimage-merge functions take a GimpProgress, and pass it down to gimp_image_merge_layers(). Adapt all callers.
This commit is contained in:
parent
914200f3ad
commit
e83d8ac4f2
|
@ -166,7 +166,8 @@ static void image_merge_layers_callback (GtkWidget *dialog,
|
|||
GimpContext *context,
|
||||
GimpMergeType merge_type,
|
||||
gboolean merge_active_group,
|
||||
gboolean discard_invisible);
|
||||
gboolean discard_invisible,
|
||||
gpointer user_data);
|
||||
|
||||
|
||||
/* private variables */
|
||||
|
@ -900,8 +901,10 @@ image_merge_layers_cmd_callback (GtkAction *action,
|
|||
{
|
||||
GtkWidget *dialog;
|
||||
GimpImage *image;
|
||||
GimpDisplay *display;
|
||||
GtkWidget *widget;
|
||||
return_if_no_image (image, data);
|
||||
return_if_no_display (display, data);
|
||||
return_if_no_widget (widget, data);
|
||||
|
||||
#define MERGE_LAYERS_DIALOG_KEY "gimp-merge-layers-dialog"
|
||||
|
@ -919,7 +922,7 @@ image_merge_layers_cmd_callback (GtkAction *action,
|
|||
config->layer_merge_active_group_only,
|
||||
config->layer_merge_discard_invisible,
|
||||
image_merge_layers_callback,
|
||||
NULL);
|
||||
display);
|
||||
|
||||
dialogs_attach_dialog (G_OBJECT (image), MERGE_LAYERS_DIALOG_KEY, dialog);
|
||||
}
|
||||
|
@ -932,12 +935,15 @@ image_flatten_image_cmd_callback (GtkAction *action,
|
|||
gpointer data)
|
||||
{
|
||||
GimpImage *image;
|
||||
GimpDisplay *display;
|
||||
GtkWidget *widget;
|
||||
GError *error = NULL;
|
||||
return_if_no_image (image, data);
|
||||
return_if_no_display (display, data);
|
||||
return_if_no_widget (widget, data);
|
||||
|
||||
if (! gimp_image_flatten (image, action_data_get_context (data), &error))
|
||||
if (! gimp_image_flatten (image, action_data_get_context (data),
|
||||
GIMP_PROGRESS (display), &error))
|
||||
{
|
||||
gimp_message_literal (image->gimp,
|
||||
G_OBJECT (widget), GIMP_MESSAGE_WARNING,
|
||||
|
@ -1458,9 +1464,11 @@ image_merge_layers_callback (GtkWidget *dialog,
|
|||
GimpContext *context,
|
||||
GimpMergeType merge_type,
|
||||
gboolean merge_active_group,
|
||||
gboolean discard_invisible)
|
||||
gboolean discard_invisible,
|
||||
gpointer user_data)
|
||||
{
|
||||
GimpDialogConfig *config = GIMP_DIALOG_CONFIG (image->gimp->config);
|
||||
GimpDisplay *display = user_data;
|
||||
|
||||
g_object_set (config,
|
||||
"layer-merge-type", merge_type,
|
||||
|
@ -1472,7 +1480,8 @@ image_merge_layers_callback (GtkWidget *dialog,
|
|||
context,
|
||||
config->layer_merge_type,
|
||||
config->layer_merge_active_group_only,
|
||||
config->layer_merge_discard_invisible);
|
||||
config->layer_merge_discard_invisible,
|
||||
GIMP_PROGRESS (display));
|
||||
|
||||
gimp_image_flush (image);
|
||||
|
||||
|
|
|
@ -579,10 +579,13 @@ layers_merge_down_cmd_callback (GtkAction *action,
|
|||
{
|
||||
GimpImage *image;
|
||||
GimpLayer *layer;
|
||||
GimpDisplay *display;
|
||||
return_if_no_layer (image, layer, data);
|
||||
return_if_no_display (display, data);
|
||||
|
||||
gimp_image_merge_down (image, layer, action_data_get_context (data),
|
||||
GIMP_EXPAND_AS_NECESSARY, NULL);
|
||||
GIMP_EXPAND_AS_NECESSARY,
|
||||
GIMP_PROGRESS (display), NULL);
|
||||
gimp_image_flush (image);
|
||||
}
|
||||
|
||||
|
|
|
@ -48,6 +48,7 @@
|
|||
#include "gimpmarshal.h"
|
||||
#include "gimpparasitelist.h"
|
||||
#include "gimppickable.h"
|
||||
#include "gimpprogress.h"
|
||||
#include "gimpprojectable.h"
|
||||
#include "gimpundostack.h"
|
||||
|
||||
|
@ -58,7 +59,9 @@ static GimpLayer * gimp_image_merge_layers (GimpImage *image,
|
|||
GimpContainer *container,
|
||||
GSList *merge_list,
|
||||
GimpContext *context,
|
||||
GimpMergeType merge_type);
|
||||
GimpMergeType merge_type,
|
||||
const gchar *undo_desc,
|
||||
GimpProgress *progress);
|
||||
|
||||
|
||||
/* public functions */
|
||||
|
@ -68,7 +71,8 @@ gimp_image_merge_visible_layers (GimpImage *image,
|
|||
GimpContext *context,
|
||||
GimpMergeType merge_type,
|
||||
gboolean merge_active_group,
|
||||
gboolean discard_invisible)
|
||||
gboolean discard_invisible,
|
||||
GimpProgress *progress)
|
||||
{
|
||||
GimpContainer *container;
|
||||
GList *list;
|
||||
|
@ -77,6 +81,7 @@ gimp_image_merge_visible_layers (GimpImage *image,
|
|||
|
||||
g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL);
|
||||
g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL);
|
||||
g_return_val_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress), NULL);
|
||||
|
||||
if (merge_active_group)
|
||||
{
|
||||
|
@ -127,12 +132,13 @@ gimp_image_merge_visible_layers (GimpImage *image,
|
|||
if (merge_list)
|
||||
{
|
||||
GimpLayer *layer;
|
||||
const gchar *undo_desc = C_("undo-type", "Merge Visible Layers");
|
||||
|
||||
gimp_set_busy (image->gimp);
|
||||
|
||||
gimp_image_undo_group_start (image,
|
||||
GIMP_UNDO_GROUP_IMAGE_LAYERS_MERGE,
|
||||
C_("undo-type", "Merge Visible Layers"));
|
||||
undo_desc);
|
||||
|
||||
/* if there's a floating selection, anchor it */
|
||||
if (gimp_image_get_floating_selection (image))
|
||||
|
@ -140,7 +146,8 @@ gimp_image_merge_visible_layers (GimpImage *image,
|
|||
|
||||
layer = gimp_image_merge_layers (image,
|
||||
container,
|
||||
merge_list, context, merge_type);
|
||||
merge_list, context, merge_type,
|
||||
undo_desc, progress);
|
||||
g_slist_free (merge_list);
|
||||
|
||||
if (invisible_list)
|
||||
|
@ -166,6 +173,7 @@ gimp_image_merge_visible_layers (GimpImage *image,
|
|||
GimpLayer *
|
||||
gimp_image_flatten (GimpImage *image,
|
||||
GimpContext *context,
|
||||
GimpProgress *progress,
|
||||
GError **error)
|
||||
{
|
||||
GList *list;
|
||||
|
@ -174,6 +182,7 @@ gimp_image_flatten (GimpImage *image,
|
|||
|
||||
g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL);
|
||||
g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL);
|
||||
g_return_val_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress), NULL);
|
||||
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
|
||||
|
||||
for (list = gimp_image_get_layer_iter (image);
|
||||
|
@ -191,11 +200,13 @@ gimp_image_flatten (GimpImage *image,
|
|||
|
||||
if (merge_list)
|
||||
{
|
||||
const gchar *undo_desc = C_("undo-type", "Flatten Image");
|
||||
|
||||
gimp_set_busy (image->gimp);
|
||||
|
||||
gimp_image_undo_group_start (image,
|
||||
GIMP_UNDO_GROUP_IMAGE_LAYERS_MERGE,
|
||||
C_("undo-type", "Flatten Image"));
|
||||
undo_desc);
|
||||
|
||||
/* if there's a floating selection, anchor it */
|
||||
if (gimp_image_get_floating_selection (image))
|
||||
|
@ -204,7 +215,8 @@ gimp_image_flatten (GimpImage *image,
|
|||
layer = gimp_image_merge_layers (image,
|
||||
gimp_image_get_layers (image),
|
||||
merge_list, context,
|
||||
GIMP_FLATTEN_IMAGE);
|
||||
GIMP_FLATTEN_IMAGE,
|
||||
undo_desc, progress);
|
||||
g_slist_free (merge_list);
|
||||
|
||||
gimp_image_alpha_changed (image);
|
||||
|
@ -226,17 +238,20 @@ gimp_image_merge_down (GimpImage *image,
|
|||
GimpLayer *current_layer,
|
||||
GimpContext *context,
|
||||
GimpMergeType merge_type,
|
||||
GimpProgress *progress,
|
||||
GError **error)
|
||||
{
|
||||
GimpLayer *layer;
|
||||
GList *list;
|
||||
GList *layer_list = NULL;
|
||||
GSList *merge_list = NULL;
|
||||
const gchar *undo_desc;
|
||||
|
||||
g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL);
|
||||
g_return_val_if_fail (GIMP_IS_LAYER (current_layer), NULL);
|
||||
g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (current_layer)), NULL);
|
||||
g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL);
|
||||
g_return_val_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress), NULL);
|
||||
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
|
||||
|
||||
if (gimp_layer_is_floating_sel (current_layer))
|
||||
|
@ -299,15 +314,18 @@ gimp_image_merge_down (GimpImage *image,
|
|||
|
||||
merge_list = g_slist_prepend (merge_list, current_layer);
|
||||
|
||||
undo_desc = C_("undo-type", "Merge Down");
|
||||
|
||||
gimp_set_busy (image->gimp);
|
||||
|
||||
gimp_image_undo_group_start (image,
|
||||
GIMP_UNDO_GROUP_IMAGE_LAYERS_MERGE,
|
||||
C_("undo-type", "Merge Down"));
|
||||
undo_desc);
|
||||
|
||||
layer = gimp_image_merge_layers (image,
|
||||
gimp_item_get_container (GIMP_ITEM (current_layer)),
|
||||
merge_list, context, merge_type);
|
||||
merge_list, context, merge_type,
|
||||
undo_desc, progress);
|
||||
g_slist_free (merge_list);
|
||||
|
||||
gimp_image_undo_group_end (image);
|
||||
|
@ -457,7 +475,9 @@ gimp_image_merge_layers (GimpImage *image,
|
|||
GimpContainer *container,
|
||||
GSList *merge_list,
|
||||
GimpContext *context,
|
||||
GimpMergeType merge_type)
|
||||
GimpMergeType merge_type,
|
||||
const gchar *undo_desc,
|
||||
GimpProgress *progress)
|
||||
{
|
||||
GimpLayer *parent;
|
||||
gint x1, y1;
|
||||
|
@ -478,6 +498,7 @@ gimp_image_merge_layers (GimpImage *image,
|
|||
|
||||
g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL);
|
||||
g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL);
|
||||
g_return_val_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress), NULL);
|
||||
|
||||
top_layer = merge_list->data;
|
||||
parent = gimp_layer_get_parent (top_layer);
|
||||
|
@ -660,9 +681,10 @@ gimp_image_merge_layers (GimpImage *image,
|
|||
gegl_node_disconnect (last_node, "input");
|
||||
|
||||
/* 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_gegl_apply_operation (NULL, progress, undo_desc, offset_node,
|
||||
gimp_drawable_get_buffer (
|
||||
GIMP_DRAWABLE (merge_layer)),
|
||||
NULL, FALSE);
|
||||
|
||||
/* Reconnect the bottom-layer node's input */
|
||||
if (last_node_source)
|
||||
|
|
|
@ -23,17 +23,20 @@ GimpLayer * gimp_image_merge_visible_layers (GimpImage *image,
|
|||
GimpContext *context,
|
||||
GimpMergeType merge_type,
|
||||
gboolean merge_active_group,
|
||||
gboolean discard_invisible);
|
||||
gboolean discard_invisible,
|
||||
GimpProgress *progress);
|
||||
GimpLayer * gimp_image_merge_down (GimpImage *image,
|
||||
GimpLayer *current_layer,
|
||||
GimpContext *context,
|
||||
GimpMergeType merge_type,
|
||||
GimpProgress *progress,
|
||||
GError **error);
|
||||
GimpLayer * gimp_image_merge_group_layer (GimpImage *image,
|
||||
GimpGroupLayer *group);
|
||||
|
||||
GimpLayer * gimp_image_flatten (GimpImage *image,
|
||||
GimpContext *context,
|
||||
GimpProgress *progress,
|
||||
GError **error);
|
||||
|
||||
GimpVectors * gimp_image_merge_visible_vectors (GimpImage *image,
|
||||
|
|
|
@ -182,7 +182,8 @@ image_merge_layers_dialog_response (GtkWidget *dialog,
|
|||
private->context,
|
||||
private->merge_type,
|
||||
private->merge_active_group,
|
||||
private->discard_invisible);
|
||||
private->discard_invisible,
|
||||
private->user_data);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -24,7 +24,8 @@ typedef void (* GimpMergeLayersCallback) (GtkWidget *dialog,
|
|||
GimpContext *context,
|
||||
GimpMergeType merge_type,
|
||||
gboolean merge_active_group,
|
||||
gboolean discard_invisible);
|
||||
gboolean discard_invisible,
|
||||
gpointer user_data);
|
||||
|
||||
|
||||
GtkWidget *
|
||||
|
|
|
@ -634,7 +634,8 @@ file_open_layers (Gimp *gimp,
|
|||
|
||||
layer = gimp_image_merge_visible_layers (new_image, context,
|
||||
GIMP_CLIP_TO_IMAGE,
|
||||
FALSE, FALSE);
|
||||
FALSE, FALSE,
|
||||
NULL);
|
||||
|
||||
layers = g_list_prepend (NULL, layer);
|
||||
}
|
||||
|
|
|
@ -1365,7 +1365,8 @@ image_flatten_invoker (GimpProcedure *procedure,
|
|||
|
||||
if (success)
|
||||
{
|
||||
layer = gimp_image_flatten (image, context, error);
|
||||
layer = gimp_image_flatten (image, context,
|
||||
progress, error);
|
||||
|
||||
if (! layer)
|
||||
success = FALSE;
|
||||
|
@ -1400,7 +1401,8 @@ image_merge_visible_layers_invoker (GimpProcedure *procedure,
|
|||
if (success)
|
||||
{
|
||||
layer = gimp_image_merge_visible_layers (image, context, merge_type,
|
||||
FALSE, FALSE);
|
||||
FALSE, FALSE,
|
||||
progress);
|
||||
|
||||
if (! layer)
|
||||
success = FALSE;
|
||||
|
@ -1439,7 +1441,7 @@ image_merge_down_invoker (GimpProcedure *procedure,
|
|||
if (gimp_pdb_item_is_attached (GIMP_ITEM (merge_layer), image, 0, error))
|
||||
{
|
||||
layer = gimp_image_merge_down (image, merge_layer, context, merge_type,
|
||||
error);
|
||||
progress, error);
|
||||
|
||||
if (! layer)
|
||||
success = FALSE;
|
||||
|
|
|
@ -740,7 +740,8 @@ HELP
|
|||
code => <<'CODE'
|
||||
{
|
||||
layer = gimp_image_merge_visible_layers (image, context, merge_type,
|
||||
FALSE, FALSE);
|
||||
FALSE, FALSE,
|
||||
progress);
|
||||
|
||||
if (! layer)
|
||||
success = FALSE;
|
||||
|
@ -786,7 +787,7 @@ HELP
|
|||
if (gimp_pdb_item_is_attached (GIMP_ITEM (merge_layer), image, 0, error))
|
||||
{
|
||||
layer = gimp_image_merge_down (image, merge_layer, context, merge_type,
|
||||
error);
|
||||
progress, error);
|
||||
|
||||
if (! layer)
|
||||
success = FALSE;
|
||||
|
@ -825,7 +826,8 @@ HELP
|
|||
headers => [ qw("core/gimpimage-merge.h") ],
|
||||
code => <<'CODE'
|
||||
{
|
||||
layer = gimp_image_flatten (image, context, error);
|
||||
layer = gimp_image_flatten (image, context,
|
||||
progress, error);
|
||||
|
||||
if (! layer)
|
||||
success = FALSE;
|
||||
|
|
Loading…
Reference in New Issue