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,
|
const gchar *undo_desc,
|
||||||
gboolean cancellable)
|
gboolean cancellable)
|
||||||
{
|
{
|
||||||
GeglRectangle rect;
|
GimpImage *image;
|
||||||
gboolean success = TRUE;
|
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_DRAWABLE (drawable), FALSE);
|
||||||
g_return_val_if_fail (GIMP_IS_FILTER (filter), FALSE);
|
g_return_val_if_fail (GIMP_IS_FILTER (filter), FALSE);
|
||||||
g_return_val_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress), FALSE);
|
g_return_val_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress), FALSE);
|
||||||
|
|
||||||
if (gimp_item_mask_intersect (GIMP_ITEM (drawable),
|
image = gimp_item_get_image (GIMP_ITEM (drawable));
|
||||||
&rect.x, &rect.y,
|
applicator = gimp_filter_get_applicator (filter);
|
||||||
&rect.width, &rect.height))
|
|
||||||
|
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));
|
return TRUE;
|
||||||
GeglBuffer *undo_buffer;
|
}
|
||||||
GeglRectangle undo_rect;
|
|
||||||
GimpApplicator *applicator;
|
|
||||||
GeglBuffer *cache = NULL;
|
|
||||||
GeglRectangle *rects = NULL;
|
|
||||||
gint n_rects = 0;
|
|
||||||
|
|
||||||
gimp_gegl_rectangle_align_to_tile_grid (
|
if (applicator)
|
||||||
&undo_rect,
|
{
|
||||||
&rect,
|
const GeglRectangle *crop_rect;
|
||||||
gimp_drawable_get_buffer (drawable));
|
|
||||||
|
|
||||||
undo_buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0,
|
crop_rect = gimp_applicator_get_crop (applicator);
|
||||||
undo_rect.width,
|
|
||||||
undo_rect.height),
|
|
||||||
gimp_drawable_get_format (drawable));
|
|
||||||
|
|
||||||
gimp_gegl_buffer_copy (gimp_drawable_get_buffer (drawable),
|
if (crop_rect && ! gegl_rectangle_intersect (&rect, &rect, crop_rect))
|
||||||
&undo_rect,
|
return TRUE;
|
||||||
GEGL_ABYSS_NONE,
|
|
||||||
undo_buffer,
|
|
||||||
GEGL_RECTANGLE (0, 0, 0, 0));
|
|
||||||
|
|
||||||
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)
|
gimp_gegl_rectangle_align_to_tile_grid (
|
||||||
{
|
&undo_rect,
|
||||||
/* disable the output crop */
|
&rect,
|
||||||
gimp_applicator_set_crop (applicator, NULL);
|
gimp_drawable_get_buffer (drawable));
|
||||||
|
|
||||||
/* the cache and its valid rectangles are the region that
|
undo_buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0,
|
||||||
* 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_rect.width,
|
undo_rect.width,
|
||||||
undo_rect.height),
|
undo_rect.height),
|
||||||
GEGL_ABYSS_NONE,
|
gimp_drawable_get_format (drawable));
|
||||||
gimp_drawable_get_buffer (drawable),
|
|
||||||
&undo_rect);
|
|
||||||
|
|
||||||
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)
|
if (gimp_gegl_apply_cached_operation (gimp_drawable_get_buffer (drawable),
|
||||||
{
|
progress, undo_desc,
|
||||||
g_object_unref (cache);
|
gimp_filter_get_node (filter),
|
||||||
g_free (rects);
|
gimp_drawable_get_buffer (drawable),
|
||||||
}
|
&rect, FALSE,
|
||||||
|
cache, rects, n_rects,
|
||||||
|
cancellable))
|
||||||
|
{
|
||||||
|
/* finished successfully */
|
||||||
|
|
||||||
gimp_drawable_update (drawable,
|
gimp_drawable_push_undo (drawable, undo_desc, undo_buffer,
|
||||||
rect.x, rect.y,
|
undo_rect.x, undo_rect.y,
|
||||||
rect.width, rect.height);
|
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;
|
return success;
|
||||||
}
|
}
|
||||||
|
@ -65,6 +65,8 @@ struct _GimpDrawableFilter
|
|||||||
gboolean has_input;
|
gboolean has_input;
|
||||||
|
|
||||||
GimpFilterRegion region;
|
GimpFilterRegion region;
|
||||||
|
gboolean crop_enabled;
|
||||||
|
GeglRectangle crop_rect;
|
||||||
gboolean preview_enabled;
|
gboolean preview_enabled;
|
||||||
GimpAlignmentType preview_alignment;
|
GimpAlignmentType preview_alignment;
|
||||||
gdouble preview_position;
|
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_finalize (GObject *object);
|
||||||
|
|
||||||
static void gimp_drawable_filter_sync_region (GimpDrawableFilter *filter);
|
static void gimp_drawable_filter_sync_region (GimpDrawableFilter *filter);
|
||||||
static void gimp_drawable_filter_sync_preview (GimpDrawableFilter *filter,
|
static void gimp_drawable_filter_sync_crop (GimpDrawableFilter *filter,
|
||||||
gboolean old_enabled,
|
gboolean old_crop_enabled,
|
||||||
GimpAlignmentType old_alignment,
|
const GeglRectangle *old_crop_rect,
|
||||||
gdouble old_position);
|
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_opacity (GimpDrawableFilter *filter);
|
||||||
static void gimp_drawable_filter_sync_mode (GimpDrawableFilter *filter);
|
static void gimp_drawable_filter_sync_mode (GimpDrawableFilter *filter);
|
||||||
static void gimp_drawable_filter_sync_affect (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
|
void
|
||||||
gimp_drawable_filter_set_preview (GimpDrawableFilter *filter,
|
gimp_drawable_filter_set_preview (GimpDrawableFilter *filter,
|
||||||
gboolean enabled,
|
gboolean enabled,
|
||||||
@ -318,9 +356,13 @@ gimp_drawable_filter_set_preview (GimpDrawableFilter *filter,
|
|||||||
filter->preview_alignment = alignment;
|
filter->preview_alignment = alignment;
|
||||||
filter->preview_position = position;
|
filter->preview_position = position;
|
||||||
|
|
||||||
gimp_drawable_filter_sync_preview (filter,
|
gimp_drawable_filter_sync_crop (filter,
|
||||||
old_enabled,
|
filter->crop_enabled,
|
||||||
old_alignment, old_position);
|
&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))
|
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,
|
success = gimp_drawable_merge_filter (filter->drawable,
|
||||||
GIMP_FILTER (filter),
|
GIMP_FILTER (filter),
|
||||||
progress,
|
progress,
|
||||||
@ -510,12 +556,14 @@ gimp_drawable_filter_sync_region (GimpDrawableFilter *filter)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static gboolean
|
||||||
gimp_drawable_filter_get_preview_rect (GimpDrawableFilter *filter,
|
gimp_drawable_filter_get_crop_rect (GimpDrawableFilter *filter,
|
||||||
gboolean enabled,
|
gboolean crop_enabled,
|
||||||
GimpAlignmentType alignment,
|
const GeglRectangle *crop_rect,
|
||||||
gdouble position,
|
gboolean preview_enabled,
|
||||||
GeglRectangle *rect)
|
GimpAlignmentType preview_alignment,
|
||||||
|
gdouble preview_position,
|
||||||
|
GeglRectangle *rect)
|
||||||
{
|
{
|
||||||
gint width;
|
gint width;
|
||||||
gint height;
|
gint height;
|
||||||
@ -528,62 +576,71 @@ gimp_drawable_filter_get_preview_rect (GimpDrawableFilter *filter,
|
|||||||
width = rect->width;
|
width = rect->width;
|
||||||
height = rect->height;
|
height = rect->height;
|
||||||
|
|
||||||
if (enabled)
|
if (preview_enabled)
|
||||||
{
|
{
|
||||||
switch (alignment)
|
switch (preview_alignment)
|
||||||
{
|
{
|
||||||
case GIMP_ALIGN_LEFT:
|
case GIMP_ALIGN_LEFT:
|
||||||
rect->width *= position;
|
rect->width *= preview_position;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GIMP_ALIGN_RIGHT:
|
case GIMP_ALIGN_RIGHT:
|
||||||
rect->width *= (1.0 - position);
|
rect->width *= (1.0 - preview_position);
|
||||||
rect->x = width - rect->width;
|
rect->x = width - rect->width;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GIMP_ALIGN_TOP:
|
case GIMP_ALIGN_TOP:
|
||||||
rect->height *= position;
|
rect->height *= preview_position;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GIMP_ALIGN_BOTTOM:
|
case GIMP_ALIGN_BOTTOM:
|
||||||
rect->height *= (1.0 - position);
|
rect->height *= (1.0 - preview_position);
|
||||||
rect->y = height - rect->height;
|
rect->y = height - rect->height;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
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
|
static void
|
||||||
gimp_drawable_filter_sync_preview (GimpDrawableFilter *filter,
|
gimp_drawable_filter_sync_crop (GimpDrawableFilter *filter,
|
||||||
gboolean old_enabled,
|
gboolean old_crop_enabled,
|
||||||
GimpAlignmentType old_alignment,
|
const GeglRectangle *old_crop_rect,
|
||||||
gdouble old_position)
|
gboolean old_preview_enabled,
|
||||||
|
GimpAlignmentType old_preview_alignment,
|
||||||
|
gdouble old_preview_position,
|
||||||
|
gboolean update)
|
||||||
{
|
{
|
||||||
GeglRectangle old_rect;
|
GeglRectangle old_rect;
|
||||||
GeglRectangle new_rect;
|
GeglRectangle new_rect;
|
||||||
|
gboolean enabled;
|
||||||
|
|
||||||
gimp_drawable_filter_get_preview_rect (filter,
|
gimp_drawable_filter_get_crop_rect (filter,
|
||||||
old_enabled,
|
old_crop_enabled,
|
||||||
old_alignment,
|
old_crop_rect,
|
||||||
old_position,
|
old_preview_enabled,
|
||||||
&old_rect);
|
old_preview_alignment,
|
||||||
|
old_preview_position,
|
||||||
|
&old_rect);
|
||||||
|
|
||||||
gimp_drawable_filter_get_preview_rect (filter,
|
enabled = gimp_drawable_filter_get_crop_rect (filter,
|
||||||
filter->preview_enabled,
|
filter->crop_enabled,
|
||||||
filter->preview_alignment,
|
&filter->crop_rect,
|
||||||
filter->preview_position,
|
filter->preview_enabled,
|
||||||
&new_rect);
|
filter->preview_alignment,
|
||||||
|
filter->preview_position,
|
||||||
|
&new_rect);
|
||||||
|
|
||||||
gimp_applicator_set_crop (filter->applicator,
|
gimp_applicator_set_crop (filter->applicator, enabled ? &new_rect : NULL);
|
||||||
filter->preview_enabled ? &new_rect : NULL);
|
|
||||||
|
|
||||||
if (old_rect.x != new_rect.x ||
|
if (update && ! gegl_rectangle_equal (&old_rect, &new_rect))
|
||||||
old_rect.y != new_rect.y ||
|
|
||||||
old_rect.width != new_rect.width ||
|
|
||||||
old_rect.height != new_rect.height)
|
|
||||||
{
|
{
|
||||||
cairo_region_t *region;
|
cairo_region_t *region;
|
||||||
gint n_rects;
|
gint n_rects;
|
||||||
@ -859,10 +916,13 @@ gimp_drawable_filter_add_filter (GimpDrawableFilter *filter)
|
|||||||
|
|
||||||
gimp_drawable_filter_sync_mask (filter);
|
gimp_drawable_filter_sync_mask (filter);
|
||||||
gimp_drawable_filter_sync_region (filter);
|
gimp_drawable_filter_sync_region (filter);
|
||||||
gimp_drawable_filter_sync_preview (filter,
|
gimp_drawable_filter_sync_crop (filter,
|
||||||
filter->preview_enabled,
|
filter->crop_enabled,
|
||||||
filter->preview_alignment,
|
&filter->crop_rect,
|
||||||
filter->preview_position);
|
filter->preview_enabled,
|
||||||
|
filter->preview_alignment,
|
||||||
|
filter->preview_position,
|
||||||
|
TRUE);
|
||||||
gimp_drawable_filter_sync_opacity (filter);
|
gimp_drawable_filter_sync_opacity (filter);
|
||||||
gimp_drawable_filter_sync_mode (filter);
|
gimp_drawable_filter_sync_mode (filter);
|
||||||
gimp_drawable_filter_sync_affect (filter);
|
gimp_drawable_filter_sync_affect (filter);
|
||||||
|
@ -57,6 +57,9 @@ GimpDrawableFilter *
|
|||||||
|
|
||||||
void gimp_drawable_filter_set_region (GimpDrawableFilter *filter,
|
void gimp_drawable_filter_set_region (GimpDrawableFilter *filter,
|
||||||
GimpFilterRegion region);
|
GimpFilterRegion region);
|
||||||
|
void gimp_drawable_filter_set_crop (GimpDrawableFilter *filter,
|
||||||
|
const GeglRectangle *rect,
|
||||||
|
gboolean update);
|
||||||
void gimp_drawable_filter_set_preview (GimpDrawableFilter *filter,
|
void gimp_drawable_filter_set_preview (GimpDrawableFilter *filter,
|
||||||
gboolean enabled,
|
gboolean enabled,
|
||||||
GimpAlignmentType alignment,
|
GimpAlignmentType alignment,
|
||||||
|
Reference in New Issue
Block a user