[gimp] app: add gimp_image_transform()
- From: Ell <ell src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gimp] app: add gimp_image_transform()
- Date: Sat, 10 Aug 2019 21:36:04 +0000 (UTC)
commit c45f1b4148d1797a85d4785135444a7ced88da15
Author: Ell <ell_se yahoo com>
Date: Sat Aug 10 18:42:51 2019 +0300
app: add gimp_image_transform()
Add a new gimp_image_transform() function, which transforms the
entire image, including all layers, channels (including selection
mask), vectors, guides, and sample points, according to a
transformation matrix. The canvas is resized according to the
clip_result parameter, the same way drawables are resized during
transformation; the layers are resized using ADJUST mode
regardless.
app/core/Makefile.am | 2 +
app/core/core-enums.c | 2 +
app/core/core-enums.h | 1 +
app/core/gimpimage-transform.c | 338 +++++++++++++++++++++++++++++++++++++++++
app/core/gimpimage-transform.h | 34 +++++
app/core/gimpimage-undo.c | 1 +
6 files changed, 378 insertions(+)
---
diff --git a/app/core/Makefile.am b/app/core/Makefile.am
index a06b289b39..be90e742ed 100644
--- a/app/core/Makefile.am
+++ b/app/core/Makefile.am
@@ -325,6 +325,8 @@ libappcore_a_sources = \
gimpimage-snap.h \
gimpimage-symmetry.c \
gimpimage-symmetry.h \
+ gimpimage-transform.c \
+ gimpimage-transform.h \
gimpimage-undo.c \
gimpimage-undo.h \
gimpimage-undo-push.c \
diff --git a/app/core/core-enums.c b/app/core/core-enums.c
index 90580abdf5..3baf9ee169 100644
--- a/app/core/core-enums.c
+++ b/app/core/core-enums.c
@@ -1096,6 +1096,7 @@ gimp_undo_type_get_type (void)
{ GIMP_UNDO_GROUP_IMAGE_RESIZE, "GIMP_UNDO_GROUP_IMAGE_RESIZE", "group-image-resize" },
{ GIMP_UNDO_GROUP_IMAGE_FLIP, "GIMP_UNDO_GROUP_IMAGE_FLIP", "group-image-flip" },
{ GIMP_UNDO_GROUP_IMAGE_ROTATE, "GIMP_UNDO_GROUP_IMAGE_ROTATE", "group-image-rotate" },
+ { GIMP_UNDO_GROUP_IMAGE_TRANSFORM, "GIMP_UNDO_GROUP_IMAGE_TRANSFORM", "group-image-transform" },
{ GIMP_UNDO_GROUP_IMAGE_CROP, "GIMP_UNDO_GROUP_IMAGE_CROP", "group-image-crop" },
{ GIMP_UNDO_GROUP_IMAGE_CONVERT, "GIMP_UNDO_GROUP_IMAGE_CONVERT", "group-image-convert" },
{ GIMP_UNDO_GROUP_IMAGE_ITEM_REMOVE, "GIMP_UNDO_GROUP_IMAGE_ITEM_REMOVE", "group-image-item-remove" },
@@ -1195,6 +1196,7 @@ gimp_undo_type_get_type (void)
{ GIMP_UNDO_GROUP_IMAGE_RESIZE, NC_("undo-type", "Resize image"), NULL },
{ GIMP_UNDO_GROUP_IMAGE_FLIP, NC_("undo-type", "Flip image"), NULL },
{ GIMP_UNDO_GROUP_IMAGE_ROTATE, NC_("undo-type", "Rotate image"), NULL },
+ { GIMP_UNDO_GROUP_IMAGE_TRANSFORM, NC_("undo-type", "Transform image"), NULL },
{ GIMP_UNDO_GROUP_IMAGE_CROP, NC_("undo-type", "Crop image"), NULL },
{ GIMP_UNDO_GROUP_IMAGE_CONVERT, NC_("undo-type", "Convert image"), NULL },
{ GIMP_UNDO_GROUP_IMAGE_ITEM_REMOVE, NC_("undo-type", "Remove item"), NULL },
diff --git a/app/core/core-enums.h b/app/core/core-enums.h
index 4b6ea7c0ac..7b569c9ffd 100644
--- a/app/core/core-enums.h
+++ b/app/core/core-enums.h
@@ -502,6 +502,7 @@ typedef enum /*< pdb-skip >*/
GIMP_UNDO_GROUP_IMAGE_RESIZE, /*< desc="Resize image" >*/
GIMP_UNDO_GROUP_IMAGE_FLIP, /*< desc="Flip image" >*/
GIMP_UNDO_GROUP_IMAGE_ROTATE, /*< desc="Rotate image" >*/
+ GIMP_UNDO_GROUP_IMAGE_TRANSFORM, /*< desc="Transform image" >*/
GIMP_UNDO_GROUP_IMAGE_CROP, /*< desc="Crop image" >*/
GIMP_UNDO_GROUP_IMAGE_CONVERT, /*< desc="Convert image" >*/
GIMP_UNDO_GROUP_IMAGE_ITEM_REMOVE, /*< desc="Remove item" >*/
diff --git a/app/core/gimpimage-transform.c b/app/core/gimpimage-transform.c
new file mode 100644
index 0000000000..afe4cfc72d
--- /dev/null
+++ b/app/core/gimpimage-transform.c
@@ -0,0 +1,338 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimpimage-transform.c
+ * Copyright (C) 2019 Ell
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <gegl.h>
+
+#include "libgimpmath/gimpmath.h"
+
+#include "core-types.h"
+
+#include "vectors/gimpvectors.h"
+
+#include "gimp.h"
+#include "gimp-transform-resize.h"
+#include "gimp-transform-utils.h"
+#include "gimpchannel.h"
+#include "gimpcontext.h"
+#include "gimpguide.h"
+#include "gimpimage.h"
+#include "gimpimage-guides.h"
+#include "gimpimage-sample-points.h"
+#include "gimpimage-transform.h"
+#include "gimpimage-undo.h"
+#include "gimpimage-undo-push.h"
+#include "gimpitem.h"
+#include "gimpobjectqueue.h"
+#include "gimpprogress.h"
+#include "gimpsamplepoint.h"
+
+
+#define EPSILON 1e-6
+
+
+/* local function prototypes */
+
+static void gimp_image_transform_guides (GimpImage *image,
+ const GimpMatrix3 *matrix,
+ const GeglRectangle *old_bounds);
+static void gimp_image_transform_sample_points (GimpImage *image,
+ const GimpMatrix3 *matrix,
+ const GeglRectangle *old_bounds);
+
+
+/* private functions */
+
+static void
+gimp_image_transform_guides (GimpImage *image,
+ const GimpMatrix3 *matrix,
+ const GeglRectangle *old_bounds)
+{
+ GList *iter;
+
+ for (iter = gimp_image_get_guides (image); iter;)
+ {
+ GimpGuide *guide = iter->data;
+ GimpOrientationType old_orientation = gimp_guide_get_orientation (guide);
+ gint old_position = gimp_guide_get_position (guide);
+ GimpOrientationType new_orientation;
+ gint new_position;
+ GimpVector2 vertices[2];
+ gint n_vertices;
+ GimpVector2 diff;
+
+ iter = g_list_next (iter);
+
+ switch (old_orientation)
+ {
+ case GIMP_ORIENTATION_HORIZONTAL:
+ vertices[0].x = old_bounds->x;
+ vertices[0].y = old_bounds->y + old_position;
+
+ vertices[1].x = old_bounds->x + old_bounds->width / 2.0;
+ vertices[1].y = old_bounds->y + old_position;
+ break;
+
+ case GIMP_ORIENTATION_VERTICAL:
+ vertices[0].x = old_bounds->x + old_position;
+ vertices[0].y = old_bounds->y;
+
+ vertices[1].x = old_bounds->x + old_position;
+ vertices[1].y = old_bounds->y + old_bounds->height / 2.0;
+ break;
+
+ case GIMP_ORIENTATION_UNKNOWN:
+ g_return_if_reached ();
+ }
+
+ gimp_transform_polygon (matrix,
+ vertices, 2, FALSE,
+ vertices, &n_vertices);
+
+ if (n_vertices < 2)
+ {
+ gimp_image_remove_guide (image, guide, TRUE);
+
+ continue;
+ }
+
+ gimp_vector2_sub (&diff, &vertices[1], &vertices[0]);
+
+ if (gimp_vector2_length (&diff) <= EPSILON)
+ {
+ gimp_image_remove_guide (image, guide, TRUE);
+
+ continue;
+ }
+
+ if (fabs (diff.x) >= fabs (diff.y))
+ {
+ new_orientation = GIMP_ORIENTATION_HORIZONTAL;
+ new_position = SIGNED_ROUND (vertices[1].y);
+
+ if (new_position < 0 || new_position > gimp_image_get_height (image))
+ {
+ gimp_image_remove_guide (image, guide, TRUE);
+
+ continue;
+ }
+ }
+ else
+ {
+ new_orientation = GIMP_ORIENTATION_VERTICAL;
+ new_position = SIGNED_ROUND (vertices[1].x);
+
+ if (new_position < 0 || new_position > gimp_image_get_width (image))
+ {
+ gimp_image_remove_guide (image, guide, TRUE);
+
+ continue;
+ }
+ }
+
+ if (new_orientation != old_orientation ||
+ new_position != old_position)
+ {
+ gimp_image_undo_push_guide (image, NULL, guide);
+
+ gimp_guide_set_orientation (guide, new_orientation);
+ gimp_guide_set_position (guide, new_position);
+
+ gimp_image_guide_moved (image, guide);
+ }
+ }
+}
+
+static void
+gimp_image_transform_sample_points (GimpImage *image,
+ const GimpMatrix3 *matrix,
+ const GeglRectangle *old_bounds)
+{
+ GList *iter;
+
+ for (iter = gimp_image_get_sample_points (image); iter;)
+ {
+ GimpSamplePoint *sample_point = iter->data;
+ gint old_x;
+ gint old_y;
+ gint new_x;
+ gint new_y;
+ GimpVector2 vertices[1];
+ gint n_vertices;
+
+ iter = g_list_next (iter);
+
+ gimp_sample_point_get_position (sample_point, &old_x, &old_y);
+
+ vertices[0].x = old_x;
+ vertices[0].y = old_y;
+
+ gimp_transform_polygon (matrix,
+ vertices, 1, FALSE,
+ vertices, &n_vertices);
+
+ if (n_vertices < 1)
+ {
+ gimp_image_remove_sample_point (image, sample_point, TRUE);
+
+ continue;
+ }
+
+ new_x = SIGNED_ROUND (vertices[0].x);
+ new_y = SIGNED_ROUND (vertices[0].y);
+
+ if (new_x < 0 || new_x >= gimp_image_get_width (image) ||
+ new_y < 0 || new_y >= gimp_image_get_height (image))
+ {
+ gimp_image_remove_sample_point (image, sample_point, TRUE);
+
+ continue;
+ }
+
+ if (new_x != old_x || new_y != old_y)
+ gimp_image_move_sample_point (image, sample_point, new_x, new_y, TRUE);
+ }
+}
+
+
+/* public functions */
+
+void
+gimp_image_transform (GimpImage *image,
+ GimpContext *context,
+ const GimpMatrix3 *matrix,
+ GimpTransformDirection direction,
+ GimpInterpolationType interpolation_type,
+ GimpTransformResize clip_result,
+ GimpProgress *progress)
+{
+ GimpObjectQueue *queue;
+ GimpItem *item;
+ GimpMatrix3 transform;
+ GeglRectangle old_bounds;
+ GeglRectangle new_bounds;
+
+ g_return_if_fail (GIMP_IS_IMAGE (image));
+ g_return_if_fail (GIMP_IS_CONTEXT (context));
+ g_return_if_fail (matrix != NULL);
+ g_return_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress));
+
+ gimp_set_busy (image->gimp);
+
+ old_bounds.x = 0;
+ old_bounds.y = 0;
+ old_bounds.width = gimp_image_get_width (image);
+ old_bounds.height = gimp_image_get_height (image);
+
+ transform = *matrix;
+
+ if (direction == GIMP_TRANSFORM_BACKWARD)
+ gimp_matrix3_invert (&transform);
+
+ gimp_transform_resize_boundary (&transform, clip_result,
+
+ old_bounds.x,
+ old_bounds.y,
+ old_bounds.x + old_bounds.width,
+ old_bounds.y + old_bounds.height,
+
+ &new_bounds.x,
+ &new_bounds.y,
+ &new_bounds.width,
+ &new_bounds.height);
+
+ new_bounds.width -= new_bounds.x;
+ new_bounds.height -= new_bounds.y;
+
+ gimp_matrix3_translate (&transform,
+ old_bounds.x - new_bounds.x,
+ old_bounds.y - new_bounds.y);
+
+ queue = gimp_object_queue_new (progress);
+ progress = GIMP_PROGRESS (queue);
+
+ gimp_object_queue_push_container (queue, gimp_image_get_layers (image));
+ gimp_object_queue_push (queue, gimp_image_get_mask (image));
+ gimp_object_queue_push_container (queue, gimp_image_get_channels (image));
+ gimp_object_queue_push_container (queue, gimp_image_get_vectors (image));
+
+ g_object_freeze_notify (G_OBJECT (image));
+
+ gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_IMAGE_TRANSFORM, NULL);
+
+ /* Transform all layers, channels (including selection mask), and vectors */
+ while ((item = gimp_object_queue_pop (queue)))
+ {
+ GimpTransformResize clip = GIMP_TRANSFORM_RESIZE_ADJUST;
+
+ if (GIMP_IS_CHANNEL (item))
+ clip = clip_result;
+
+ gimp_item_transform (item,
+ context,
+ &transform, direction,
+ interpolation_type, clip,
+ progress);
+
+ if (GIMP_IS_VECTORS (item))
+ gimp_item_set_size (item, new_bounds.width, new_bounds.height);
+ }
+
+ /* Resize the image (if needed) */
+ if (! gegl_rectangle_equal (&new_bounds, &old_bounds))
+ {
+ gimp_image_undo_push_image_size (image,
+ NULL,
+ new_bounds.x,
+ new_bounds.y,
+ new_bounds.width,
+ new_bounds.height);
+
+ g_object_set (image,
+ "width", new_bounds.width,
+ "height", new_bounds.height,
+ NULL);
+ }
+
+ /* Transform all Guides */
+ gimp_image_transform_guides (image, &transform, &old_bounds);
+
+ /* Transform all sample points */
+ gimp_image_transform_sample_points (image, &transform, &old_bounds);
+
+ gimp_image_undo_group_end (image);
+
+ g_object_unref (queue);
+
+ if (! gegl_rectangle_equal (&new_bounds, &old_bounds))
+ {
+ gimp_image_size_changed_detailed (image,
+ old_bounds.x - new_bounds.x,
+ old_bounds.y - new_bounds.y,
+ old_bounds.width,
+ old_bounds.height);
+ }
+
+ g_object_thaw_notify (G_OBJECT (image));
+
+ gimp_unset_busy (image->gimp);
+}
diff --git a/app/core/gimpimage-transform.h b/app/core/gimpimage-transform.h
new file mode 100644
index 0000000000..63a851dff9
--- /dev/null
+++ b/app/core/gimpimage-transform.h
@@ -0,0 +1,34 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattisbvf
+ *
+ * gimpimage-transform.h
+ * Copyright (C) 2019 Ell
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GIMP_IMAGE_TRANSFORM_H__
+#define __GIMP_IMAGE_TRANSFORM_H__
+
+
+void gimp_image_transform (GimpImage *image,
+ GimpContext *context,
+ const GimpMatrix3 *matrix,
+ GimpTransformDirection direction,
+ GimpInterpolationType interpolation_type,
+ GimpTransformResize clip_result,
+ GimpProgress *progress);
+
+
+#endif /* __GIMP_IMAGE_TRANSFORM_H__ */
diff --git a/app/core/gimpimage-undo.c b/app/core/gimpimage-undo.c
index 8f3ea4b906..fbf808b650 100644
--- a/app/core/gimpimage-undo.c
+++ b/app/core/gimpimage-undo.c
@@ -614,6 +614,7 @@ gimp_image_undo_dirty_from_type (GimpUndoType undo_type)
case GIMP_UNDO_GROUP_IMAGE_RESIZE:
case GIMP_UNDO_GROUP_IMAGE_FLIP:
case GIMP_UNDO_GROUP_IMAGE_ROTATE:
+ case GIMP_UNDO_GROUP_IMAGE_TRANSFORM:
case GIMP_UNDO_GROUP_IMAGE_CROP:
return GIMP_DIRTY_IMAGE | GIMP_DIRTY_IMAGE_SIZE;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]