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



commit 5763b50d452a52ffb7e9fc2ec30dcde7ba9b5957
Author: Ell <ell_se yahoo com>
Date:   Sun Mar 25 11:20:14 2018 -0400

    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.

 app/core/gimpgrouplayer.c |   46 ++++++++--------------
 app/core/gimpitem.c       |   93 +++++++++++++++++++++++++++++++++++----------
 app/core/gimpitem.h       |   10 +++++
 3 files changed, 100 insertions(+), 49 deletions(-)
---
diff --git a/app/core/gimpgrouplayer.c b/app/core/gimpgrouplayer.c
index b78ecee..e81ba8e 100644
--- a/app/core/gimpgrouplayer.c
+++ b/app/core/gimpgrouplayer.c
@@ -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)
-        {
-          gimp_item_scale (child,
-                           child_width, child_height,
-                           child_offset_x, child_offset_y,
-                           interpolation_type, progress);
-        }
-      else if (gimp_item_is_attached (item))
+      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_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));
+            }
         }
     }
 
diff --git a/app/core/gimpitem.c b/app/core/gimpitem.c
index 1fbf375..29dfbcc 100644
--- a/app/core/gimpitem.c
+++ b/app/core/gimpitem.c
@@ -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);
-
-  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));
+  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_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);
 }
@@ -1360,6 +1370,41 @@ gimp_item_scale_by_factors (GimpItem              *item,
                             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;
   gint             new_offset_x, new_offset_y;
@@ -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;
+
+  new_offset_x += new_origin_x;
+  new_offset_y += new_origin_y;
 
-  if (new_width != 0 && new_height != 0)
+  if (new_width > 0 && new_height > 0)
     {
       gimp_item_scale (item,
                        new_width, new_height,
diff --git a/app/core/gimpitem.h b/app/core/gimpitem.h
index b9023cf..783d07a 100644
--- a/app/core/gimpitem.h
+++ b/app/core/gimpitem.h
@@ -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,


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]