app: add gimp_drawable_filter_set_crop()
Add gimp_drawable_filter_set_crop(), which allows setting an output
crop rectangle for the filter; anything outside the rectangle
doesn't get filtered. The crop area is combined with the preview
area to determine the filtered area during preview, however, unlike
the preview area, the crop area remains in effect while committing
the filter.
Consequently, when merging a drawable filter, if the filter has a
crop, only process the cropped area.
(cherry picked from commit 5c27d14fdf
)
This commit is contained in:
@ -111,98 +111,104 @@ gimp_drawable_merge_filter (GimpDrawable *drawable,
|
||||
const gchar *undo_desc,
|
||||
gboolean cancellable)
|
||||
{
|
||||
GeglRectangle rect;
|
||||
gboolean success = TRUE;
|
||||
GimpImage *image;
|
||||
GimpApplicator *applicator;
|
||||
GeglBuffer *undo_buffer;
|
||||
GeglRectangle undo_rect;
|
||||
GeglBuffer *cache = NULL;
|
||||
GeglRectangle *rects = NULL;
|
||||
gint n_rects = 0;
|
||||
GeglRectangle rect;
|
||||
gboolean success = TRUE;
|
||||
|
||||
g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), FALSE);
|
||||
g_return_val_if_fail (GIMP_IS_FILTER (filter), FALSE);
|
||||
g_return_val_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress), FALSE);
|
||||
|
||||
if (gimp_item_mask_intersect (GIMP_ITEM (drawable),
|
||||
&rect.x, &rect.y,
|
||||
&rect.width, &rect.height))
|
||||
image = gimp_item_get_image (GIMP_ITEM (drawable));
|
||||
applicator = gimp_filter_get_applicator (filter);
|
||||
|
||||
if (! gimp_item_mask_intersect (GIMP_ITEM (drawable),
|
||||
&rect.x, &rect.y,
|
||||
&rect.width, &rect.height))
|
||||
{
|
||||
GimpImage *image = gimp_item_get_image (GIMP_ITEM (drawable));
|
||||
GeglBuffer *undo_buffer;
|
||||
GeglRectangle undo_rect;
|
||||
GimpApplicator *applicator;
|
||||
GeglBuffer *cache = NULL;
|
||||
GeglRectangle *rects = NULL;
|
||||
gint n_rects = 0;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gimp_gegl_rectangle_align_to_tile_grid (
|
||||
&undo_rect,
|
||||
&rect,
|
||||
gimp_drawable_get_buffer (drawable));
|
||||
if (applicator)
|
||||
{
|
||||
const GeglRectangle *crop_rect;
|
||||
|
||||
undo_buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0,
|
||||
undo_rect.width,
|
||||
undo_rect.height),
|
||||
gimp_drawable_get_format (drawable));
|
||||
crop_rect = gimp_applicator_get_crop (applicator);
|
||||
|
||||
gimp_gegl_buffer_copy (gimp_drawable_get_buffer (drawable),
|
||||
&undo_rect,
|
||||
GEGL_ABYSS_NONE,
|
||||
undo_buffer,
|
||||
GEGL_RECTANGLE (0, 0, 0, 0));
|
||||
if (crop_rect && ! gegl_rectangle_intersect (&rect, &rect, crop_rect))
|
||||
return TRUE;
|
||||
|
||||
applicator = gimp_filter_get_applicator (filter);
|
||||
/* the cache and its valid rectangles are the region that
|
||||
* has already been processed by this applicator.
|
||||
*/
|
||||
cache = gimp_applicator_get_cache_buffer (applicator,
|
||||
&rects, &n_rects);
|
||||
}
|
||||
|
||||
if (applicator)
|
||||
{
|
||||
/* disable the output crop */
|
||||
gimp_applicator_set_crop (applicator, NULL);
|
||||
gimp_gegl_rectangle_align_to_tile_grid (
|
||||
&undo_rect,
|
||||
&rect,
|
||||
gimp_drawable_get_buffer (drawable));
|
||||
|
||||
/* the cache and its valid rectangles are the region that
|
||||
* has already been processed by this applicator.
|
||||
*/
|
||||
cache = gimp_applicator_get_cache_buffer (applicator,
|
||||
&rects, &n_rects);
|
||||
}
|
||||
|
||||
gimp_projection_stop_rendering (gimp_image_get_projection (image));
|
||||
|
||||
if (gimp_gegl_apply_cached_operation (gimp_drawable_get_buffer (drawable),
|
||||
progress, undo_desc,
|
||||
gimp_filter_get_node (filter),
|
||||
gimp_drawable_get_buffer (drawable),
|
||||
&rect, FALSE,
|
||||
cache, rects, n_rects,
|
||||
cancellable))
|
||||
{
|
||||
/* finished successfully */
|
||||
|
||||
gimp_drawable_push_undo (drawable, undo_desc, undo_buffer,
|
||||
undo_rect.x, undo_rect.y,
|
||||
undo_rect.width, undo_rect.height);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* canceled by the user */
|
||||
|
||||
gimp_gegl_buffer_copy (undo_buffer,
|
||||
GEGL_RECTANGLE (0, 0,
|
||||
undo_buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0,
|
||||
undo_rect.width,
|
||||
undo_rect.height),
|
||||
GEGL_ABYSS_NONE,
|
||||
gimp_drawable_get_buffer (drawable),
|
||||
&undo_rect);
|
||||
gimp_drawable_get_format (drawable));
|
||||
|
||||
success = FALSE;
|
||||
}
|
||||
gimp_gegl_buffer_copy (gimp_drawable_get_buffer (drawable),
|
||||
&undo_rect,
|
||||
GEGL_ABYSS_NONE,
|
||||
undo_buffer,
|
||||
GEGL_RECTANGLE (0, 0, 0, 0));
|
||||
|
||||
g_object_unref (undo_buffer);
|
||||
gimp_projection_stop_rendering (gimp_image_get_projection (image));
|
||||
|
||||
if (cache)
|
||||
{
|
||||
g_object_unref (cache);
|
||||
g_free (rects);
|
||||
}
|
||||
if (gimp_gegl_apply_cached_operation (gimp_drawable_get_buffer (drawable),
|
||||
progress, undo_desc,
|
||||
gimp_filter_get_node (filter),
|
||||
gimp_drawable_get_buffer (drawable),
|
||||
&rect, FALSE,
|
||||
cache, rects, n_rects,
|
||||
cancellable))
|
||||
{
|
||||
/* finished successfully */
|
||||
|
||||
gimp_drawable_update (drawable,
|
||||
rect.x, rect.y,
|
||||
rect.width, rect.height);
|
||||
gimp_drawable_push_undo (drawable, undo_desc, undo_buffer,
|
||||
undo_rect.x, undo_rect.y,
|
||||
undo_rect.width, undo_rect.height);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* canceled by the user */
|
||||
|
||||
gimp_gegl_buffer_copy (undo_buffer,
|
||||
GEGL_RECTANGLE (0, 0,
|
||||
undo_rect.width,
|
||||
undo_rect.height),
|
||||
GEGL_ABYSS_NONE,
|
||||
gimp_drawable_get_buffer (drawable),
|
||||
&undo_rect);
|
||||
|
||||
success = FALSE;
|
||||
}
|
||||
|
||||
g_object_unref (undo_buffer);
|
||||
|
||||
if (cache)
|
||||
{
|
||||
g_object_unref (cache);
|
||||
g_free (rects);
|
||||
}
|
||||
|
||||
gimp_drawable_update (drawable,
|
||||
rect.x, rect.y,
|
||||
rect.width, rect.height);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
@ -65,6 +65,8 @@ struct _GimpDrawableFilter
|
||||
gboolean has_input;
|
||||
|
||||
GimpFilterRegion region;
|
||||
gboolean crop_enabled;
|
||||
GeglRectangle crop_rect;
|
||||
gboolean preview_enabled;
|
||||
GimpAlignmentType preview_alignment;
|
||||
gdouble preview_position;
|
||||
@ -93,10 +95,13 @@ static void gimp_drawable_filter_dispose (GObject *ob
|
||||
static void gimp_drawable_filter_finalize (GObject *object);
|
||||
|
||||
static void gimp_drawable_filter_sync_region (GimpDrawableFilter *filter);
|
||||
static void gimp_drawable_filter_sync_preview (GimpDrawableFilter *filter,
|
||||
gboolean old_enabled,
|
||||
GimpAlignmentType old_alignment,
|
||||
gdouble old_position);
|
||||
static void gimp_drawable_filter_sync_crop (GimpDrawableFilter *filter,
|
||||
gboolean old_crop_enabled,
|
||||
const GeglRectangle *old_crop_rect,
|
||||
gboolean old_preview_enabled,
|
||||
GimpAlignmentType old_preview_alignment,
|
||||
gdouble old_preview_position,
|
||||
gboolean update);
|
||||
static void gimp_drawable_filter_sync_opacity (GimpDrawableFilter *filter);
|
||||
static void gimp_drawable_filter_sync_mode (GimpDrawableFilter *filter);
|
||||
static void gimp_drawable_filter_sync_affect (GimpDrawableFilter *filter);
|
||||
@ -292,6 +297,39 @@ gimp_drawable_filter_set_region (GimpDrawableFilter *filter,
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gimp_drawable_filter_set_crop (GimpDrawableFilter *filter,
|
||||
const GeglRectangle *rect,
|
||||
gboolean update)
|
||||
{
|
||||
g_return_if_fail (GIMP_IS_DRAWABLE_FILTER (filter));
|
||||
|
||||
if ((rect != NULL) != filter->crop_enabled ||
|
||||
(rect && ! gegl_rectangle_equal (rect, &filter->crop_rect)))
|
||||
{
|
||||
gboolean old_enabled = filter->crop_enabled;
|
||||
GeglRectangle old_rect = filter->crop_rect;
|
||||
|
||||
if (rect)
|
||||
{
|
||||
filter->crop_enabled = TRUE;
|
||||
filter->crop_rect = *rect;
|
||||
}
|
||||
else
|
||||
{
|
||||
filter->crop_enabled = FALSE;
|
||||
}
|
||||
|
||||
gimp_drawable_filter_sync_crop (filter,
|
||||
old_enabled,
|
||||
&old_rect,
|
||||
filter->preview_enabled,
|
||||
filter->preview_alignment,
|
||||
filter->preview_position,
|
||||
update);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gimp_drawable_filter_set_preview (GimpDrawableFilter *filter,
|
||||
gboolean enabled,
|
||||
@ -318,9 +356,13 @@ gimp_drawable_filter_set_preview (GimpDrawableFilter *filter,
|
||||
filter->preview_alignment = alignment;
|
||||
filter->preview_position = position;
|
||||
|
||||
gimp_drawable_filter_sync_preview (filter,
|
||||
old_enabled,
|
||||
old_alignment, old_position);
|
||||
gimp_drawable_filter_sync_crop (filter,
|
||||
filter->crop_enabled,
|
||||
&filter->crop_rect,
|
||||
old_enabled,
|
||||
old_alignment,
|
||||
old_position,
|
||||
TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
@ -427,6 +469,10 @@ gimp_drawable_filter_commit (GimpDrawableFilter *filter,
|
||||
|
||||
if (gimp_drawable_filter_is_filtering (filter))
|
||||
{
|
||||
gimp_drawable_filter_set_preview (filter, FALSE,
|
||||
filter->preview_alignment,
|
||||
filter->preview_position);
|
||||
|
||||
success = gimp_drawable_merge_filter (filter->drawable,
|
||||
GIMP_FILTER (filter),
|
||||
progress,
|
||||
@ -510,12 +556,14 @@ gimp_drawable_filter_sync_region (GimpDrawableFilter *filter)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gimp_drawable_filter_get_preview_rect (GimpDrawableFilter *filter,
|
||||
gboolean enabled,
|
||||
GimpAlignmentType alignment,
|
||||
gdouble position,
|
||||
GeglRectangle *rect)
|
||||
static gboolean
|
||||
gimp_drawable_filter_get_crop_rect (GimpDrawableFilter *filter,
|
||||
gboolean crop_enabled,
|
||||
const GeglRectangle *crop_rect,
|
||||
gboolean preview_enabled,
|
||||
GimpAlignmentType preview_alignment,
|
||||
gdouble preview_position,
|
||||
GeglRectangle *rect)
|
||||
{
|
||||
gint width;
|
||||
gint height;
|
||||
@ -528,62 +576,71 @@ gimp_drawable_filter_get_preview_rect (GimpDrawableFilter *filter,
|
||||
width = rect->width;
|
||||
height = rect->height;
|
||||
|
||||
if (enabled)
|
||||
if (preview_enabled)
|
||||
{
|
||||
switch (alignment)
|
||||
switch (preview_alignment)
|
||||
{
|
||||
case GIMP_ALIGN_LEFT:
|
||||
rect->width *= position;
|
||||
rect->width *= preview_position;
|
||||
break;
|
||||
|
||||
case GIMP_ALIGN_RIGHT:
|
||||
rect->width *= (1.0 - position);
|
||||
rect->width *= (1.0 - preview_position);
|
||||
rect->x = width - rect->width;
|
||||
break;
|
||||
|
||||
case GIMP_ALIGN_TOP:
|
||||
rect->height *= position;
|
||||
rect->height *= preview_position;
|
||||
break;
|
||||
|
||||
case GIMP_ALIGN_BOTTOM:
|
||||
rect->height *= (1.0 - position);
|
||||
rect->height *= (1.0 - preview_position);
|
||||
rect->y = height - rect->height;
|
||||
break;
|
||||
|
||||
default:
|
||||
g_return_if_reached ();
|
||||
g_return_val_if_reached (FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
if (crop_enabled)
|
||||
gegl_rectangle_intersect (rect, rect, crop_rect);
|
||||
|
||||
return ! gegl_rectangle_equal_coords (rect, 0, 0, width, height);
|
||||
}
|
||||
|
||||
static void
|
||||
gimp_drawable_filter_sync_preview (GimpDrawableFilter *filter,
|
||||
gboolean old_enabled,
|
||||
GimpAlignmentType old_alignment,
|
||||
gdouble old_position)
|
||||
gimp_drawable_filter_sync_crop (GimpDrawableFilter *filter,
|
||||
gboolean old_crop_enabled,
|
||||
const GeglRectangle *old_crop_rect,
|
||||
gboolean old_preview_enabled,
|
||||
GimpAlignmentType old_preview_alignment,
|
||||
gdouble old_preview_position,
|
||||
gboolean update)
|
||||
{
|
||||
GeglRectangle old_rect;
|
||||
GeglRectangle new_rect;
|
||||
gboolean enabled;
|
||||
|
||||
gimp_drawable_filter_get_preview_rect (filter,
|
||||
old_enabled,
|
||||
old_alignment,
|
||||
old_position,
|
||||
&old_rect);
|
||||
gimp_drawable_filter_get_crop_rect (filter,
|
||||
old_crop_enabled,
|
||||
old_crop_rect,
|
||||
old_preview_enabled,
|
||||
old_preview_alignment,
|
||||
old_preview_position,
|
||||
&old_rect);
|
||||
|
||||
gimp_drawable_filter_get_preview_rect (filter,
|
||||
filter->preview_enabled,
|
||||
filter->preview_alignment,
|
||||
filter->preview_position,
|
||||
&new_rect);
|
||||
enabled = gimp_drawable_filter_get_crop_rect (filter,
|
||||
filter->crop_enabled,
|
||||
&filter->crop_rect,
|
||||
filter->preview_enabled,
|
||||
filter->preview_alignment,
|
||||
filter->preview_position,
|
||||
&new_rect);
|
||||
|
||||
gimp_applicator_set_crop (filter->applicator,
|
||||
filter->preview_enabled ? &new_rect : NULL);
|
||||
gimp_applicator_set_crop (filter->applicator, enabled ? &new_rect : NULL);
|
||||
|
||||
if (old_rect.x != new_rect.x ||
|
||||
old_rect.y != new_rect.y ||
|
||||
old_rect.width != new_rect.width ||
|
||||
old_rect.height != new_rect.height)
|
||||
if (update && ! gegl_rectangle_equal (&old_rect, &new_rect))
|
||||
{
|
||||
cairo_region_t *region;
|
||||
gint n_rects;
|
||||
@ -859,10 +916,13 @@ gimp_drawable_filter_add_filter (GimpDrawableFilter *filter)
|
||||
|
||||
gimp_drawable_filter_sync_mask (filter);
|
||||
gimp_drawable_filter_sync_region (filter);
|
||||
gimp_drawable_filter_sync_preview (filter,
|
||||
filter->preview_enabled,
|
||||
filter->preview_alignment,
|
||||
filter->preview_position);
|
||||
gimp_drawable_filter_sync_crop (filter,
|
||||
filter->crop_enabled,
|
||||
&filter->crop_rect,
|
||||
filter->preview_enabled,
|
||||
filter->preview_alignment,
|
||||
filter->preview_position,
|
||||
TRUE);
|
||||
gimp_drawable_filter_sync_opacity (filter);
|
||||
gimp_drawable_filter_sync_mode (filter);
|
||||
gimp_drawable_filter_sync_affect (filter);
|
||||
|
@ -57,6 +57,9 @@ GimpDrawableFilter *
|
||||
|
||||
void gimp_drawable_filter_set_region (GimpDrawableFilter *filter,
|
||||
GimpFilterRegion region);
|
||||
void gimp_drawable_filter_set_crop (GimpDrawableFilter *filter,
|
||||
const GeglRectangle *rect,
|
||||
gboolean update);
|
||||
void gimp_drawable_filter_set_preview (GimpDrawableFilter *filter,
|
||||
gboolean enabled,
|
||||
GimpAlignmentType alignment,
|
||||
|
Reference in New Issue
Block a user