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.
This commit is contained in:
Jehan 2025-02-09 19:24:41 +01:00
parent d7b6647647
commit b01ecf80e6
3 changed files with 186 additions and 108 deletions

View file

@ -63,22 +63,41 @@ image_autocrop_invoker (GimpProcedure *procedure,
if (success) if (success)
{ {
if (gimp_pdb_item_is_attached (GIMP_ITEM (drawable), NULL, gint x, y, width, height;
GIMP_PDB_ITEM_CONTENT, error))
if (drawable != NULL)
{ {
gint x, y, width, height; if (gimp_pdb_item_is_attached (GIMP_ITEM (drawable), NULL,
gint off_x, off_y; 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, 0, 0,
gimp_item_get_width (GIMP_ITEM (drawable)), gimp_image_get_width (image),
gimp_item_get_height (GIMP_ITEM (drawable)), gimp_image_get_height (image),
&x, &y, &width, &height); &x, &y, &width, &height);
}
gimp_item_get_offset (GIMP_ITEM (drawable), &off_x, &off_y); if (success)
x += off_x; {
y += off_y;
gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_ITEM_RESIZE, gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_ITEM_RESIZE,
_("Autocrop image")); _("Autocrop image"));
@ -101,8 +120,6 @@ image_autocrop_invoker (GimpProcedure *procedure,
gimp_image_undo_group_end (image); gimp_image_undo_group_end (image);
} }
else
success = FALSE;
} }
return gimp_procedure_get_return_values (procedure, success, return gimp_procedure_get_return_values (procedure, success,
@ -126,45 +143,25 @@ image_autocrop_selected_layers_invoker (GimpProcedure *procedure,
if (success) if (success)
{ {
if (gimp_pdb_item_is_attached (GIMP_ITEM (drawable), NULL, GimpAutoShrink shrink;
GIMP_PDB_ITEM_CONTENT, error)) gint x, y, width, height;
{
GList *layers = gimp_image_get_selected_layers (image);
GList *iter;
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; 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); gimp_item_get_offset (GIMP_ITEM (drawable), &off_x, &off_y);
x += off_x;
switch (gimp_pickable_auto_shrink (GIMP_PICKABLE (drawable), y += off_y;
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;
}
} }
else else
{ {
@ -173,7 +170,43 @@ image_autocrop_selected_layers_invoker (GimpProcedure *procedure,
} }
else 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",
"Remove empty borders from the @image based on empty borders of the input @drawable.\n" "Remove empty borders from the @image based on empty borders of the input @drawable.\n"
"\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); NULL);
gimp_procedure_set_static_attribution (procedure, gimp_procedure_set_static_attribution (procedure,
"Spencer Kimball & Peter Mattis", "Spencer Kimball & Peter Mattis",
@ -212,7 +246,7 @@ register_image_autocrop_procs (GimpPDB *pdb)
gimp_param_spec_drawable ("drawable", gimp_param_spec_drawable ("drawable",
"drawable", "drawable",
"Input drawable", "Input drawable",
FALSE, TRUE,
GIMP_PARAM_READWRITE)); GIMP_PARAM_READWRITE));
gimp_pdb_register_procedure (pdb, procedure); gimp_pdb_register_procedure (pdb, procedure);
g_object_unref (procedure); g_object_unref (procedure);
@ -226,7 +260,8 @@ register_image_autocrop_procs (GimpPDB *pdb)
gimp_procedure_set_static_help (procedure, gimp_procedure_set_static_help (procedure,
"Crop the selected layers based on empty borders of the input drawable", "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" "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); NULL);
gimp_procedure_set_static_attribution (procedure, gimp_procedure_set_static_attribution (procedure,
"Spencer Kimball & Peter Mattis", "Spencer Kimball & Peter Mattis",
@ -235,14 +270,14 @@ register_image_autocrop_procs (GimpPDB *pdb)
gimp_procedure_add_argument (procedure, gimp_procedure_add_argument (procedure,
gimp_param_spec_image ("image", gimp_param_spec_image ("image",
"image", "image",
"Input image)", "Input image",
FALSE, FALSE,
GIMP_PARAM_READWRITE)); GIMP_PARAM_READWRITE));
gimp_procedure_add_argument (procedure, gimp_procedure_add_argument (procedure,
gimp_param_spec_drawable ("drawable", gimp_param_spec_drawable ("drawable",
"drawable", "drawable",
"Input drawable", "Input drawable",
FALSE, TRUE,
GIMP_PARAM_READWRITE)); GIMP_PARAM_READWRITE));
gimp_pdb_register_procedure (pdb, procedure); gimp_pdb_register_procedure (pdb, procedure);
g_object_unref (procedure); g_object_unref (procedure);

View file

@ -39,7 +39,7 @@
/** /**
* gimp_image_autocrop: * gimp_image_autocrop:
* @image: Input image). * @image: Input image).
* @drawable: Input drawable. * @drawable: (nullable): Input drawable.
* *
* Remove empty borders from the image * Remove empty borders from the image
* *
@ -48,6 +48,8 @@
* *
* The input drawable serves as a base for detecting cropping extents * The input drawable serves as a base for detecting cropping extents
* (transparency or background color). * (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. * Returns: TRUE on success.
**/ **/
@ -78,8 +80,8 @@ gimp_image_autocrop (GimpImage *image,
/** /**
* gimp_image_autocrop_selected_layers: * gimp_image_autocrop_selected_layers:
* @image: Input image). * @image: Input image.
* @drawable: Input drawable. * @drawable: (nullable): Input drawable.
* *
* Crop the selected layers based on empty borders of the input * Crop the selected layers based on empty borders of the input
* drawable * drawable
@ -89,6 +91,8 @@ gimp_image_autocrop (GimpImage *image,
* The input drawable serves as a base for detecting cropping extents * The input drawable serves as a base for detecting cropping extents
* (transparency or background color), and is not necessarily among the * (transparency or background color), and is not necessarily among the
* cropped layers (the current selected layers). * 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. * Returns: TRUE on success.
**/ **/

View file

@ -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 The input drawable serves as a base for detecting cropping extents
(transparency or background color). (transparency or background color).
With a %NULL input drawable, the image itself will serve as a base for
detecting cropping extents.
HELP HELP
&std_pdb_misc; &std_pdb_misc;
@ -34,29 +37,48 @@ HELP
@inargs = ( @inargs = (
{ name => 'image', type => 'image', { name => 'image', type => 'image',
desc => 'Input image)' }, desc => 'Input image)' },
{ name => 'drawable', type => 'drawable', { name => 'drawable', type => 'drawable', none_ok => 1,
desc => 'Input drawable' } desc => 'Input drawable' }
); );
%invoke = ( %invoke = (
code => <<'CODE' code => <<'CODE'
{ {
if (gimp_pdb_item_is_attached (GIMP_ITEM (drawable), NULL, gint x, y, width, height;
GIMP_PDB_ITEM_CONTENT, error))
if (drawable != NULL)
{ {
gint x, y, width, height; if (gimp_pdb_item_is_attached (GIMP_ITEM (drawable), NULL,
gint off_x, off_y; 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, 0, 0,
gimp_item_get_width (GIMP_ITEM (drawable)), gimp_image_get_width (image),
gimp_item_get_height (GIMP_ITEM (drawable)), gimp_image_get_height (image),
&x, &y, &width, &height); &x, &y, &width, &height);
}
gimp_item_get_offset (GIMP_ITEM (drawable), &off_x, &off_y); if (success)
x += off_x; {
y += off_y;
gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_ITEM_RESIZE, gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_ITEM_RESIZE,
_("Autocrop image")); _("Autocrop image"));
@ -79,8 +101,6 @@ HELP
gimp_image_undo_group_end (image); gimp_image_undo_group_end (image);
} }
else
success = FALSE;
} }
CODE 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 The input drawable serves as a base for detecting cropping extents
(transparency or background color), and is not necessarily among the (transparency or background color), and is not necessarily among the
cropped layers (the current selected layers). cropped layers (the current selected layers).
With a %NULL input drawable, the image itself will serve as a base for
detecting cropping extents.
HELP HELP
&std_pdb_misc; &std_pdb_misc;
@ -102,54 +125,34 @@ HELP
@inargs = ( @inargs = (
{ name => 'image', type => 'image', { name => 'image', type => 'image',
desc => 'Input image)' }, desc => 'Input image' },
{ name => 'drawable', type => 'drawable', { name => 'drawable', type => 'drawable', none_ok => 1,
desc => 'Input drawable' } desc => 'Input drawable' }
); );
%invoke = ( %invoke = (
code => <<'CODE' code => <<'CODE'
{ {
if (gimp_pdb_item_is_attached (GIMP_ITEM (drawable), NULL, GimpAutoShrink shrink;
GIMP_PDB_ITEM_CONTENT, error)) gint x, y, width, height;
{
GList *layers = gimp_image_get_selected_layers (image);
GList *iter;
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; 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); gimp_item_get_offset (GIMP_ITEM (drawable), &off_x, &off_y);
x += off_x;
switch (gimp_pickable_auto_shrink (GIMP_PICKABLE (drawable), y += off_y;
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;
}
}
else else
{ {
success = FALSE; success = FALSE;
@ -157,7 +160,43 @@ HELP
} }
else 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 CODE