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:
@ -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)
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user