From a701032b4ea9e3588aea38de5d447db5091e3ccf Mon Sep 17 00:00:00 2001 From: Ell Date: Wed, 29 May 2019 04:58:17 -0400 Subject: [PATCH] app: fix symmetry transform in Clone/Heal tools when brush is cropped In GimpSourceCore, when applying a symmetry transform to the source content, combine the transform op with translation to the paint- buffer coordinates, so that subclasses (namely, GimpClone and GimpHeal) can use the op to apply the transformation directly from the source buffer to the paint buffer in a single step. This is both more efficient, and avoids incorrect symmetry transforms when the paint buffer is cropped to the bounds of the drawable. --- app/paint/gimpclone.c | 35 ++++++++++++++---------- app/paint/gimpheal.c | 30 ++++++++++----------- app/paint/gimpsourcecore.c | 54 ++++++++++++++++++++++++++++++++++---- 3 files changed, 84 insertions(+), 35 deletions(-) diff --git a/app/paint/gimpclone.c b/app/paint/gimpclone.c index 464a3a4ba4..9c807f43ff 100644 --- a/app/paint/gimpclone.c +++ b/app/paint/gimpclone.c @@ -169,21 +169,28 @@ gimp_clone_motion (GimpSourceCore *source_core, if (gimp_source_core_use_source (source_core, source_options)) { - gimp_gegl_buffer_copy (src_buffer, - GEGL_RECTANGLE (src_rect->x, - src_rect->y, - paint_area_width, - paint_area_height), - GEGL_ABYSS_NONE, - paint_buffer, - GEGL_RECTANGLE (paint_area_offset_x, - paint_area_offset_y, - 0, 0)); - - if (op) + if (! op) { - gimp_gegl_apply_operation (paint_buffer, NULL, NULL, op, - paint_buffer, NULL, FALSE); + gimp_gegl_buffer_copy (src_buffer, + GEGL_RECTANGLE (src_rect->x, + src_rect->y, + paint_area_width, + paint_area_height), + GEGL_ABYSS_NONE, + paint_buffer, + GEGL_RECTANGLE (paint_area_offset_x, + paint_area_offset_y, + 0, 0)); + } + else + { + gimp_gegl_apply_operation (src_buffer, NULL, NULL, op, + paint_buffer, + GEGL_RECTANGLE (paint_area_offset_x, + paint_area_offset_y, + paint_area_width, + paint_area_height), + FALSE); } } else if (options->clone_type == GIMP_CLONE_PATTERN) diff --git a/app/paint/gimpheal.c b/app/paint/gimpheal.c index 2901df3315..8f7451a3b2 100644 --- a/app/paint/gimpheal.c +++ b/app/paint/gimpheal.c @@ -560,16 +560,23 @@ gimp_heal_motion (GimpSourceCore *source_core, } /* heal should work in perceptual space, use R'G'B' instead of RGB */ - src_copy = gegl_buffer_new (GEGL_RECTANGLE (0, 0, + src_copy = gegl_buffer_new (GEGL_RECTANGLE (paint_area_offset_x, + paint_area_offset_y, src_rect->width, src_rect->height), babl_format ("R'G'B'A float")); - gimp_gegl_buffer_copy (src_buffer, src_rect, GEGL_ABYSS_NONE, - src_copy, - GEGL_RECTANGLE (0, 0, - src_rect->width, - src_rect->height)); + if (! op) + { + gimp_gegl_buffer_copy (src_buffer, src_rect, GEGL_ABYSS_NONE, + src_copy, gegl_buffer_get_extent (src_copy)); + } + else + { + gimp_gegl_apply_operation (src_buffer, NULL, NULL, op, + src_copy, gegl_buffer_get_extent (src_copy), + FALSE); + } if (src_options->sample_merged) { @@ -610,16 +617,7 @@ gimp_heal_motion (GimpSourceCore *source_core, mask_off_y = (y < 0) ? -y : 0; } - if (op) - { - gimp_gegl_apply_operation (src_copy, NULL, NULL, op, - src_copy, NULL, FALSE); - } - - gimp_heal (src_copy, - GEGL_RECTANGLE (0, 0, - gegl_buffer_get_width (src_copy), - gegl_buffer_get_height (src_copy)), + gimp_heal (src_copy, gegl_buffer_get_extent (src_copy), paint_buffer, GEGL_RECTANGLE (paint_area_offset_x, paint_area_offset_y, diff --git a/app/paint/gimpsourcecore.c b/app/paint/gimpsourcecore.c index bfa81d20ed..02db2186f6 100644 --- a/app/paint/gimpsourcecore.c +++ b/app/paint/gimpsourcecore.c @@ -480,9 +480,52 @@ gimp_source_core_motion (GimpSourceCore *source_core, /* Set the paint buffer to transparent */ gegl_buffer_clear (paint_buffer, NULL); - op = gimp_symmetry_get_operation (sym, i, - gegl_buffer_get_width (paint_buffer), - gegl_buffer_get_height (paint_buffer)); + op = gimp_symmetry_get_operation (sym, i); + + if (op) + { + GeglNode *node; + GeglNode *input; + GeglNode *translate_before; + GeglNode *translate_after; + GeglNode *output; + + node = gegl_node_new (); + + input = gegl_node_get_input_proxy (node, "input"); + + translate_before = gegl_node_new_child ( + node, + "operation", "gegl:translate", + "x", -(source_core->src_x + 0.5), + "y", -(source_core->src_y + 0.5), + NULL); + + gegl_node_add_child (node, op); + + translate_after = gegl_node_new_child ( + node, + "operation", "gegl:translate", + "x", (source_core->src_x + 0.5) + + (paint_area_offset_x - src_rect.x), + "y", (source_core->src_y + 0.5) + + (paint_area_offset_y - src_rect.y), + NULL); + + output = gegl_node_get_output_proxy (node, "output"); + + gegl_node_link_many (input, + translate_before, + op, + translate_after, + output, + NULL); + + g_object_unref (op); + + op = node; + } + GIMP_SOURCE_CORE_GET_CLASS (source_core)->motion (source_core, drawable, paint_options, @@ -502,8 +545,9 @@ gimp_source_core_motion (GimpSourceCore *source_core, paint_area_width, paint_area_height); - if (src_buffer) - g_object_unref (src_buffer); + g_clear_object (&op); + + g_clear_object (&src_buffer); } }