app: round layer bounds to global pixel grid when scaling image/group

Add gimp_item_scale_by_factors_with_origin(), which is an extension
of gimp_item_scale_by_factors(), taking the input/output points of
origin for the transformation (both of which are (0, 0) in the case
of gimp_item_scale_by_factors()).  Implement
gimp_item_scale_by_factors() in terms of the new function, and Use
the new function when scaling group layers, instead of manually
calculating the children boundaries, so that the behavior is
uniform across whole-image scaling and group-layer scaling.

The new function rounds all four edges of the boundary to the
image-global pixel grid, instead of only rounding the top/left
edges to the global grid, and the bottom/right edges to the item-
local grid.  This preserves layer-adjacency when scaling.
This commit is contained in:
Ell 2018-03-25 11:20:14 -04:00
parent 139a23451d
commit 5763b50d45
3 changed files with 99 additions and 48 deletions

View File

@ -810,42 +810,30 @@ gimp_group_layer_scale (GimpLayer *layer,
while (list)
{
GimpItem *child = list->data;
gint child_width;
gint child_height;
gint child_offset_x;
gint child_offset_y;
list = g_list_next (list);
if (queue)
gimp_object_queue_pop (queue);
child_width = ROUND (width_factor * gimp_item_get_width (child));
child_height = ROUND (height_factor * gimp_item_get_height (child));
child_offset_x = ROUND (width_factor * (gimp_item_get_offset_x (child) -
old_offset_x));
child_offset_y = ROUND (height_factor * (gimp_item_get_offset_y (child) -
old_offset_y));
child_offset_x += new_offset_x;
child_offset_y += new_offset_y;
if (child_width > 0 && child_height > 0)
if (! gimp_item_scale_by_factors_with_origin (child,
width_factor, height_factor,
old_offset_x, old_offset_y,
new_offset_x, new_offset_y,
interpolation_type,
progress))
{
gimp_item_scale (child,
child_width, child_height,
child_offset_x, child_offset_y,
interpolation_type, progress);
}
else if (gimp_item_is_attached (item))
{
gimp_image_remove_layer (gimp_item_get_image (item),
GIMP_LAYER (child),
TRUE, NULL);
}
else
{
gimp_container_remove (private->children, GIMP_OBJECT (child));
/* new width or height are 0; remove item */
if (gimp_item_is_attached (item))
{
gimp_image_remove_layer (gimp_item_get_image (item),
GIMP_LAYER (child),
TRUE, NULL);
}
else
{
gimp_container_remove (private->children, GIMP_OBJECT (child));
}
}
}

View File

@ -1261,22 +1261,32 @@ gimp_item_check_scaling (GimpItem *item,
gint new_width,
gint new_height)
{
GimpImage *image;
gdouble img_scale_w;
gdouble img_scale_h;
gint new_item_width;
gint new_item_height;
GimpItemPrivate *private;
GimpImage *image;
gdouble img_scale_w;
gdouble img_scale_h;
gint new_item_offset_x;
gint new_item_offset_y;
gint new_item_width;
gint new_item_height;
g_return_val_if_fail (GIMP_IS_ITEM (item), FALSE);
image = gimp_item_get_image (item);
private = GET_PRIVATE (item);
image = gimp_item_get_image (item);
img_scale_w = ((gdouble) new_width /
(gdouble) gimp_image_get_width (image));
img_scale_h = ((gdouble) new_height /
(gdouble) gimp_image_get_height (image));
new_item_width = ROUND (img_scale_w * (gdouble) gimp_item_get_width (item));
new_item_height = ROUND (img_scale_h * (gdouble) gimp_item_get_height (item));
img_scale_w = ((gdouble) new_width /
(gdouble) gimp_image_get_width (image));
img_scale_h = ((gdouble) new_height /
(gdouble) gimp_image_get_height (image));
new_item_offset_x = SIGNED_ROUND (img_scale_w * private->offset_x);
new_item_offset_y = SIGNED_ROUND (img_scale_h * private->offset_y);
new_item_width = SIGNED_ROUND (img_scale_w * (private->offset_x +
gimp_item_get_width (item))) -
new_item_offset_x;
new_item_height = SIGNED_ROUND (img_scale_h * (private->offset_y +
gimp_item_get_height (item))) -
new_item_offset_y;
return (new_item_width > 0 && new_item_height > 0);
}
@ -1359,6 +1369,41 @@ gimp_item_scale_by_factors (GimpItem *item,
gdouble h_factor,
GimpInterpolationType interpolation,
GimpProgress *progress)
{
return gimp_item_scale_by_factors_with_origin (item,
w_factor, h_factor,
0, 0, 0, 0,
interpolation, progress);
}
/**
* gimp_item_scale_by_factors:
* @item: Item to be transformed by explicit width and height factors.
* @w_factor: scale factor to apply to width and horizontal offset
* @h_factor: scale factor to apply to height and vertical offset
* @origin_x: x-coordinate of the transformation input origin
* @origin_y: y-coordinate of the transformation input origin
* @new_origin_x: x-coordinate of the transformation output origin
* @new_origin_y: y-coordinate of the transformation output origin
* @interpolation:
* @progress:
*
* Same as gimp_item_scale_by_factors(), but with the option to specify
* custom input and output points of origin for the transformation.
*
* Returns: #TRUE, if the scaled item has positive dimensions
* #FALSE if the scaled item has at least one zero dimension
**/
gboolean
gimp_item_scale_by_factors_with_origin (GimpItem *item,
gdouble w_factor,
gdouble h_factor,
gint origin_x,
gint origin_y,
gint new_origin_x,
gint new_origin_y,
GimpInterpolationType interpolation,
GimpProgress *progress)
{
GimpItemPrivate *private;
gint new_width, new_height;
@ -1369,18 +1414,26 @@ gimp_item_scale_by_factors (GimpItem *item,
private = GET_PRIVATE (item);
if (w_factor == 0.0 || h_factor == 0.0)
if (w_factor <= 0.0 || h_factor <= 0.0)
{
g_warning ("%s: requested width or height scale equals zero", G_STRFUNC);
g_warning ("%s: requested width or height scale is non-positive",
G_STRFUNC);
return FALSE;
}
new_offset_x = SIGNED_ROUND (w_factor * (gdouble) private->offset_x);
new_offset_y = SIGNED_ROUND (h_factor * (gdouble) private->offset_y);
new_width = ROUND (w_factor * (gdouble) gimp_item_get_width (item));
new_height = ROUND (h_factor * (gdouble) gimp_item_get_height (item));
new_offset_x = SIGNED_ROUND (w_factor * (private->offset_x - origin_x));
new_offset_y = SIGNED_ROUND (h_factor * (private->offset_y - origin_y));
new_width = SIGNED_ROUND (w_factor * (private->offset_x - origin_x +
gimp_item_get_width (item))) -
new_offset_x;
new_height = SIGNED_ROUND (h_factor * (private->offset_y - origin_y +
gimp_item_get_height (item))) -
new_offset_y;
if (new_width != 0 && new_height != 0)
new_offset_x += new_origin_x;
new_offset_y += new_origin_y;
if (new_width > 0 && new_height > 0)
{
gimp_item_scale (item,
new_width, new_height,

View File

@ -236,6 +236,16 @@ gboolean gimp_item_scale_by_factors (GimpItem *item,
gdouble h_factor,
GimpInterpolationType interpolation,
GimpProgress *progress);
gboolean
gimp_item_scale_by_factors_with_origin (GimpItem *item,
gdouble w_factor,
gdouble h_factor,
gint origin_x,
gint origin_y,
gint new_origin_x,
gint new_origin_y,
GimpInterpolationType interpolation,
GimpProgress *progress);
void gimp_item_scale_by_origin (GimpItem *item,
gint new_width,
gint new_height,