From b01ecf80e6f225f8594cdc90aebc7ea87538ace4 Mon Sep 17 00:00:00 2001 From: Jehan Date: Sun, 9 Feb 2025 19:24:41 +0100 Subject: [PATCH] app, libgimp, pdb: allow NULL input drawable to the new crop procedures. Cropping relatively to the full image contents is a common usage (it is in fact the "Crop to Content" feature we have in the Image menu) so I found it a bit frustrating that these 2 functions only allow to crop relatively to a single drawable. Therefore, I make NULL an acceptable input which will default to cropping to the full image content instead. --- app/pdb/image-autocrop-cmds.c | 141 +++++++++++++++++++------------ libgimp/gimpimageautocrop_pdb.c | 10 ++- pdb/groups/image_autocrop.pdb | 143 ++++++++++++++++++++------------ 3 files changed, 186 insertions(+), 108 deletions(-) diff --git a/app/pdb/image-autocrop-cmds.c b/app/pdb/image-autocrop-cmds.c index 40c5e58139..feffc888ce 100644 --- a/app/pdb/image-autocrop-cmds.c +++ b/app/pdb/image-autocrop-cmds.c @@ -63,22 +63,41 @@ image_autocrop_invoker (GimpProcedure *procedure, if (success) { - if (gimp_pdb_item_is_attached (GIMP_ITEM (drawable), NULL, - GIMP_PDB_ITEM_CONTENT, error)) + gint x, y, width, height; + + if (drawable != NULL) { - gint x, y, width, height; - gint off_x, off_y; + if (gimp_pdb_item_is_attached (GIMP_ITEM (drawable), NULL, + GIMP_PDB_ITEM_CONTENT, error)) + { + gint off_x, off_y; - gimp_pickable_auto_shrink (GIMP_PICKABLE (drawable), + gimp_pickable_auto_shrink (GIMP_PICKABLE (drawable), + 0, 0, + gimp_item_get_width (GIMP_ITEM (drawable)), + gimp_item_get_height (GIMP_ITEM (drawable)), + &x, &y, &width, &height); + + gimp_item_get_offset (GIMP_ITEM (drawable), &off_x, &off_y); + x += off_x; + y += off_y; + } + else + { + success = FALSE; + } + } + else + { + gimp_pickable_auto_shrink (GIMP_PICKABLE (image), 0, 0, - gimp_item_get_width (GIMP_ITEM (drawable)), - gimp_item_get_height (GIMP_ITEM (drawable)), + gimp_image_get_width (image), + gimp_image_get_height (image), &x, &y, &width, &height); + } - gimp_item_get_offset (GIMP_ITEM (drawable), &off_x, &off_y); - x += off_x; - y += off_y; - + if (success) + { gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_ITEM_RESIZE, _("Autocrop image")); @@ -101,8 +120,6 @@ image_autocrop_invoker (GimpProcedure *procedure, gimp_image_undo_group_end (image); } - else - success = FALSE; } return gimp_procedure_get_return_values (procedure, success, @@ -126,45 +143,25 @@ image_autocrop_selected_layers_invoker (GimpProcedure *procedure, if (success) { - if (gimp_pdb_item_is_attached (GIMP_ITEM (drawable), NULL, - GIMP_PDB_ITEM_CONTENT, error)) - { - GList *layers = gimp_image_get_selected_layers (image); - GList *iter; - gint x, y, width, height; + GimpAutoShrink shrink; + gint x, y, width, height; - if (layers) + if (drawable != NULL) + { + if (gimp_pdb_item_is_attached (GIMP_ITEM (drawable), NULL, + GIMP_PDB_ITEM_CONTENT, error)) { gint off_x, off_y; + shrink = gimp_pickable_auto_shrink (GIMP_PICKABLE (drawable), + 0, 0, + gimp_item_get_width (GIMP_ITEM (drawable)), + gimp_item_get_height (GIMP_ITEM (drawable)), + &x, &y, &width, &height); + gimp_item_get_offset (GIMP_ITEM (drawable), &off_x, &off_y); - - switch (gimp_pickable_auto_shrink (GIMP_PICKABLE (drawable), - 0, 0, - gimp_item_get_width (GIMP_ITEM (drawable)), - gimp_item_get_height (GIMP_ITEM (drawable)), - &x, &y, &width, &height)) - { - case GIMP_AUTO_SHRINK_SHRINK: - gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_ITEM_RESIZE, - _("Autocrop layer")); - - for (iter = layers; iter; iter = iter->next) - { - gint layer_off_x, layer_off_y; - - gimp_item_get_offset (GIMP_ITEM (iter->data), &layer_off_x, &layer_off_y); - gimp_item_resize (GIMP_ITEM (iter->data), - context, GIMP_FILL_TRANSPARENT, - width, height, layer_off_x - (off_x + x), layer_off_y - (off_y + y)); - } - - gimp_image_undo_group_end (image); - break; - - default: - break; - } + x += off_x; + y += off_y; } else { @@ -173,7 +170,43 @@ image_autocrop_selected_layers_invoker (GimpProcedure *procedure, } else { - success = FALSE; + shrink = gimp_pickable_auto_shrink (GIMP_PICKABLE (image), + 0, 0, + gimp_image_get_width (image), + gimp_image_get_height (image), + &x, &y, &width, &height); + } + + if (success && shrink != GIMP_AUTO_SHRINK_SHRINK) + success = FALSE; + + if (success) + { + GList *layers = gimp_image_get_selected_layers (image); + + if (layers) + { + GList *iter; + + gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_ITEM_RESIZE, + _("Autocrop layer")); + + for (iter = layers; iter; iter = iter->next) + { + gint layer_off_x, layer_off_y; + + gimp_item_get_offset (GIMP_ITEM (iter->data), &layer_off_x, &layer_off_y); + gimp_item_resize (GIMP_ITEM (iter->data), + context, GIMP_FILL_TRANSPARENT, + width, height, layer_off_x - x, layer_off_y - y); + } + + gimp_image_undo_group_end (image); + } + else + { + success = FALSE; + } } } @@ -196,7 +229,8 @@ register_image_autocrop_procs (GimpPDB *pdb) "Remove empty borders from the image", "Remove empty borders from the @image based on empty borders of the input @drawable.\n" "\n" - "The input drawable serves as a base for detecting cropping extents (transparency or background color).", + "The input drawable serves as a base for detecting cropping extents (transparency or background color).\n" + "With a %NULL input drawable, the image itself will serve as a base for detecting cropping extents.", NULL); gimp_procedure_set_static_attribution (procedure, "Spencer Kimball & Peter Mattis", @@ -212,7 +246,7 @@ register_image_autocrop_procs (GimpPDB *pdb) gimp_param_spec_drawable ("drawable", "drawable", "Input drawable", - FALSE, + TRUE, GIMP_PARAM_READWRITE)); gimp_pdb_register_procedure (pdb, procedure); g_object_unref (procedure); @@ -226,7 +260,8 @@ register_image_autocrop_procs (GimpPDB *pdb) gimp_procedure_set_static_help (procedure, "Crop the selected layers based on empty borders of the input drawable", "Crop the selected layers of the input @image based on empty borders of the input @drawable.\n" - "The input drawable serves as a base for detecting cropping extents (transparency or background color), and is not necessarily among the cropped layers (the current selected layers).", + "The input drawable serves as a base for detecting cropping extents (transparency or background color), and is not necessarily among the cropped layers (the current selected layers).\n" + "With a %NULL input drawable, the image itself will serve as a base for detecting cropping extents.", NULL); gimp_procedure_set_static_attribution (procedure, "Spencer Kimball & Peter Mattis", @@ -235,14 +270,14 @@ register_image_autocrop_procs (GimpPDB *pdb) gimp_procedure_add_argument (procedure, gimp_param_spec_image ("image", "image", - "Input image)", + "Input image", FALSE, GIMP_PARAM_READWRITE)); gimp_procedure_add_argument (procedure, gimp_param_spec_drawable ("drawable", "drawable", "Input drawable", - FALSE, + TRUE, GIMP_PARAM_READWRITE)); gimp_pdb_register_procedure (pdb, procedure); g_object_unref (procedure); diff --git a/libgimp/gimpimageautocrop_pdb.c b/libgimp/gimpimageautocrop_pdb.c index c086627ca3..77940b61d5 100644 --- a/libgimp/gimpimageautocrop_pdb.c +++ b/libgimp/gimpimageautocrop_pdb.c @@ -39,7 +39,7 @@ /** * gimp_image_autocrop: * @image: Input image). - * @drawable: Input drawable. + * @drawable: (nullable): Input drawable. * * Remove empty borders from the image * @@ -48,6 +48,8 @@ * * The input drawable serves as a base for detecting cropping extents * (transparency or background color). + * With a %NULL input drawable, the image itself will serve as a base + * for detecting cropping extents. * * Returns: TRUE on success. **/ @@ -78,8 +80,8 @@ gimp_image_autocrop (GimpImage *image, /** * gimp_image_autocrop_selected_layers: - * @image: Input image). - * @drawable: Input drawable. + * @image: Input image. + * @drawable: (nullable): Input drawable. * * Crop the selected layers based on empty borders of the input * drawable @@ -89,6 +91,8 @@ gimp_image_autocrop (GimpImage *image, * The input drawable serves as a base for detecting cropping extents * (transparency or background color), and is not necessarily among the * cropped layers (the current selected layers). + * With a %NULL input drawable, the image itself will serve as a base + * for detecting cropping extents. * * Returns: TRUE on success. **/ diff --git a/pdb/groups/image_autocrop.pdb b/pdb/groups/image_autocrop.pdb index 0d49886891..7b5e0a814b 100644 --- a/pdb/groups/image_autocrop.pdb +++ b/pdb/groups/image_autocrop.pdb @@ -26,6 +26,9 @@ Remove empty borders from the @image based on empty borders of the input @drawab The input drawable serves as a base for detecting cropping extents (transparency or background color). + +With a %NULL input drawable, the image itself will serve as a base for +detecting cropping extents. HELP &std_pdb_misc; @@ -34,29 +37,48 @@ HELP @inargs = ( { name => 'image', type => 'image', desc => 'Input image)' }, - { name => 'drawable', type => 'drawable', + { name => 'drawable', type => 'drawable', none_ok => 1, desc => 'Input drawable' } ); %invoke = ( code => <<'CODE' { - if (gimp_pdb_item_is_attached (GIMP_ITEM (drawable), NULL, - GIMP_PDB_ITEM_CONTENT, error)) + gint x, y, width, height; + + if (drawable != NULL) { - gint x, y, width, height; - gint off_x, off_y; + if (gimp_pdb_item_is_attached (GIMP_ITEM (drawable), NULL, + GIMP_PDB_ITEM_CONTENT, error)) + { + gint off_x, off_y; - gimp_pickable_auto_shrink (GIMP_PICKABLE (drawable), + gimp_pickable_auto_shrink (GIMP_PICKABLE (drawable), + 0, 0, + gimp_item_get_width (GIMP_ITEM (drawable)), + gimp_item_get_height (GIMP_ITEM (drawable)), + &x, &y, &width, &height); + + gimp_item_get_offset (GIMP_ITEM (drawable), &off_x, &off_y); + x += off_x; + y += off_y; + } + else + { + success = FALSE; + } + } + else + { + gimp_pickable_auto_shrink (GIMP_PICKABLE (image), 0, 0, - gimp_item_get_width (GIMP_ITEM (drawable)), - gimp_item_get_height (GIMP_ITEM (drawable)), + gimp_image_get_width (image), + gimp_image_get_height (image), &x, &y, &width, &height); + } - gimp_item_get_offset (GIMP_ITEM (drawable), &off_x, &off_y); - x += off_x; - y += off_y; - + if (success) + { gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_ITEM_RESIZE, _("Autocrop image")); @@ -79,8 +101,6 @@ HELP gimp_image_undo_group_end (image); } - else - success = FALSE; } CODE ); @@ -95,6 +115,9 @@ Crop the selected layers of the input @image based on empty borders of the input The input drawable serves as a base for detecting cropping extents (transparency or background color), and is not necessarily among the cropped layers (the current selected layers). + +With a %NULL input drawable, the image itself will serve as a base for +detecting cropping extents. HELP &std_pdb_misc; @@ -102,54 +125,34 @@ HELP @inargs = ( { name => 'image', type => 'image', - desc => 'Input image)' }, - { name => 'drawable', type => 'drawable', + desc => 'Input image' }, + { name => 'drawable', type => 'drawable', none_ok => 1, desc => 'Input drawable' } ); %invoke = ( code => <<'CODE' { - if (gimp_pdb_item_is_attached (GIMP_ITEM (drawable), NULL, - GIMP_PDB_ITEM_CONTENT, error)) - { - GList *layers = gimp_image_get_selected_layers (image); - GList *iter; - gint x, y, width, height; + GimpAutoShrink shrink; + gint x, y, width, height; - if (layers) + if (drawable != NULL) + { + if (gimp_pdb_item_is_attached (GIMP_ITEM (drawable), NULL, + GIMP_PDB_ITEM_CONTENT, error)) { gint off_x, off_y; + shrink = gimp_pickable_auto_shrink (GIMP_PICKABLE (drawable), + 0, 0, + gimp_item_get_width (GIMP_ITEM (drawable)), + gimp_item_get_height (GIMP_ITEM (drawable)), + &x, &y, &width, &height); + gimp_item_get_offset (GIMP_ITEM (drawable), &off_x, &off_y); - - switch (gimp_pickable_auto_shrink (GIMP_PICKABLE (drawable), - 0, 0, - gimp_item_get_width (GIMP_ITEM (drawable)), - gimp_item_get_height (GIMP_ITEM (drawable)), - &x, &y, &width, &height)) - { - case GIMP_AUTO_SHRINK_SHRINK: - gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_ITEM_RESIZE, - _("Autocrop layer")); - - for (iter = layers; iter; iter = iter->next) - { - gint layer_off_x, layer_off_y; - - gimp_item_get_offset (GIMP_ITEM (iter->data), &layer_off_x, &layer_off_y); - gimp_item_resize (GIMP_ITEM (iter->data), - context, GIMP_FILL_TRANSPARENT, - width, height, layer_off_x - (off_x + x), layer_off_y - (off_y + y)); - } - - gimp_image_undo_group_end (image); - break; - - default: - break; - } - } + x += off_x; + y += off_y; + } else { success = FALSE; @@ -157,7 +160,43 @@ HELP } else { - success = FALSE; + shrink = gimp_pickable_auto_shrink (GIMP_PICKABLE (image), + 0, 0, + gimp_image_get_width (image), + gimp_image_get_height (image), + &x, &y, &width, &height); + } + + if (success && shrink != GIMP_AUTO_SHRINK_SHRINK) + success = FALSE; + + if (success) + { + GList *layers = gimp_image_get_selected_layers (image); + + if (layers) + { + GList *iter; + + gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_ITEM_RESIZE, + _("Autocrop layer")); + + for (iter = layers; iter; iter = iter->next) + { + gint layer_off_x, layer_off_y; + + gimp_item_get_offset (GIMP_ITEM (iter->data), &layer_off_x, &layer_off_y); + gimp_item_resize (GIMP_ITEM (iter->data), + context, GIMP_FILL_TRANSPARENT, + width, height, layer_off_x - x, layer_off_y - y); + } + + gimp_image_undo_group_end (image); + } + else + { + success = FALSE; + } } } CODE