From 768d06614f203bf555bbda1f6186d4730ae2f8b5 Mon Sep 17 00:00:00 2001 From: Alexis Wilhelm Date: Tue, 8 Nov 2016 17:15:16 +0100 Subject: [PATCH] Bug 316479 - The Perspective Tool creates an empy image... ...instead of transforming it Add gimp_matrix3_will_explode() which determines if a transform matrix will blow up something in a rectangle to infinity, and use the function so set both the GIMP and GEGL code paths to clip the transform to the input size. --- app/core/gimpdrawable-transform.c | 4 ++++ app/gegl/gimp-gegl-apply-operation.c | 9 +++++-- app/gegl/gimp-gegl-apply-operation.h | 1 + libgimpmath/gimpmath.def | 1 + libgimpmath/gimpmatrix.c | 36 ++++++++++++++++++++++++++++ libgimpmath/gimpmatrix.h | 6 +++++ 6 files changed, 55 insertions(+), 2 deletions(-) diff --git a/app/core/gimpdrawable-transform.c b/app/core/gimpdrawable-transform.c index a4baa0046d..034603a989 100644 --- a/app/core/gimpdrawable-transform.c +++ b/app/core/gimpdrawable-transform.c @@ -116,6 +116,9 @@ gimp_drawable_transform_buffer_affine (GimpDrawable *drawable, ! babl_format_has_alpha (gegl_buffer_get_format (orig_buffer))) clip_result = GIMP_TRANSFORM_RESIZE_CLIP; + if (gimp_matrix3_will_explode (&m, u1, v1, u2, v2)) + clip_result = GIMP_TRANSFORM_RESIZE_CLIP; + /* Find the bounding coordinates of target */ gimp_transform_resize_boundary (&m, clip_result, u1, v1, u2, v2, @@ -133,6 +136,7 @@ gimp_drawable_transform_buffer_affine (GimpDrawable *drawable, gimp_gegl_apply_transform (orig_buffer, progress, NULL, new_buffer, interpolation_type, + clip_result, &gegl_matrix); *new_offset_x = x1; diff --git a/app/gegl/gimp-gegl-apply-operation.c b/app/gegl/gimp-gegl-apply-operation.c index a86e2defd0..41440d7aa4 100644 --- a/app/gegl/gimp-gegl-apply-operation.c +++ b/app/gegl/gimp-gegl-apply-operation.c @@ -685,17 +685,22 @@ gimp_gegl_apply_transform (GeglBuffer *src_buffer, const gchar *undo_desc, GeglBuffer *dest_buffer, GimpInterpolationType interpolation_type, + GimpTransformResize clip_result, GimpMatrix3 *transform) { GeglNode *node; + gboolean clip_to_input; g_return_if_fail (GEGL_IS_BUFFER (src_buffer)); g_return_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress)); g_return_if_fail (GEGL_IS_BUFFER (dest_buffer)); + clip_to_input = (clip_result == GIMP_TRANSFORM_RESIZE_CLIP); + node = gegl_node_new_child (NULL, - "operation", "gegl:transform", - "sampler", interpolation_type, + "operation", "gegl:transform", + "sampler", interpolation_type, + "clip-to-input", clip_to_input, NULL); gimp_gegl_node_set_matrix (node, transform); diff --git a/app/gegl/gimp-gegl-apply-operation.h b/app/gegl/gimp-gegl-apply-operation.h index acca14bbe0..9039b5b6e3 100644 --- a/app/gegl/gimp-gegl-apply-operation.h +++ b/app/gegl/gimp-gegl-apply-operation.h @@ -153,6 +153,7 @@ void gimp_gegl_apply_transform (GeglBuffer *src_buffer, const gchar *undo_desc, GeglBuffer *dest_buffer, GimpInterpolationType interpolation_type, + GimpTransformResize clip_result, GimpMatrix3 *transform); diff --git a/libgimpmath/gimpmath.def b/libgimpmath/gimpmath.def index 1a489403ac..039a03dec1 100644 --- a/libgimpmath/gimpmath.def +++ b/libgimpmath/gimpmath.def @@ -16,6 +16,7 @@ EXPORTS gimp_matrix3_scale gimp_matrix3_transform_point gimp_matrix3_translate + gimp_matrix3_will_explode gimp_matrix3_xshear gimp_matrix3_yshear gimp_matrix4_to_deg diff --git a/libgimpmath/gimpmatrix.c b/libgimpmath/gimpmatrix.c index 48c2210308..457057d7e6 100644 --- a/libgimpmath/gimpmatrix.c +++ b/libgimpmath/gimpmatrix.c @@ -865,6 +865,42 @@ gimp_matrix3_is_simple (const GimpMatrix3 *matrix) return TRUE; } +/** + * gimp_matrix3_will_explode: + * @m: The matrix that is to be tested. + * @u1: The rectangle's left coordinate. + * @v1: The rectangle's top coordinate. + * @u2: The rectangle's right coordinate. + * @v2: The rectangle's bottom coordinate. + * + * Checks if the given transformation maps a point of the rectangle to + * infinity, or something equally stupid. + * + * Returns: %TRUE if the transformation will fail, %FALSE otherwise + * + * Since: 2.10 + */ +gboolean +gimp_matrix3_will_explode (const GimpMatrix3 *m, + gdouble u1, + gdouble v1, + gdouble u2, + gdouble v2) +{ + const gdouble a = m->coeff[2][0]; + const gdouble b = m->coeff[2][1]; + const gdouble c = m->coeff[2][2]; + const gdouble d1 = a * u1 + b * v1 + c; + const gdouble d2 = a * u1 + b * v2 + c; + const gdouble d3 = a * u2 + b * v1 + c; + const gdouble d4 = a * u2 + b * v2 + c; + + /* We are safe if all 4 corners of the region are on the same side + * of the a.u+b.v+c=0 line, ie. if d1..d4 have the same sign. + */ + return ! (d1 * d2 > 0 && d1 * d3 > 0 && d1 * d4 > 0); +} + /** * gimp_matrix4_to_deg: * @matrix: diff --git a/libgimpmath/gimpmatrix.h b/libgimpmath/gimpmatrix.h index e435d88352..23a75877f9 100644 --- a/libgimpmath/gimpmatrix.h +++ b/libgimpmath/gimpmatrix.h @@ -111,6 +111,12 @@ gboolean gimp_matrix3_is_diagonal (const GimpMatrix3 *matrix); gboolean gimp_matrix3_is_affine (const GimpMatrix3 *matrix); gboolean gimp_matrix3_is_simple (const GimpMatrix3 *matrix); +gboolean gimp_matrix3_will_explode (const GimpMatrix3 *matrix, + gdouble u1, + gdouble v1, + gdouble u2, + gdouble v2); + void gimp_matrix3_transform_point (const GimpMatrix3 *matrix, gdouble x, gdouble y,