mirror of https://github.com/GNOME/gimp.git
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.
This commit is contained in:
parent
7534ae53d6
commit
5c27d14fdf
|
@ -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;
|
||||
|
@ -877,10 +934,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,
|
||||
|
|
Loading…
Reference in New Issue