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.
This commit is contained in:
Ell
2019-05-29 04:58:17 -04:00
parent 60a3965020
commit a701032b4e
3 changed files with 84 additions and 35 deletions

View File

@ -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)

View File

@ -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,

View File

@ -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);
}
}