[gimp] app: add gimp_drawable_filter_set_crop()



commit 5c27d14fdfd151f26b8aab4ddd77e10376278c1e
Author: Ell <ell_se yahoo com>
Date:   Sun Dec 30 04:46:10 2018 -0500

    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.

 app/core/gimpdrawable-filters.c | 164 +++++++++++++++++++++-------------------
 app/core/gimpdrawablefilter.c   | 156 ++++++++++++++++++++++++++------------
 app/core/gimpdrawablefilter.h   |   3 +
 3 files changed, 196 insertions(+), 127 deletions(-)
---
diff --git a/app/core/gimpdrawable-filters.c b/app/core/gimpdrawable-filters.c
index 2dad613110..8c0421cf76 100644
--- a/app/core/gimpdrawable-filters.c
+++ b/app/core/gimpdrawable-filters.c
@@ -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;
-
-      gimp_gegl_rectangle_align_to_tile_grid (
-        &undo_rect,
-        &rect,
-        gimp_drawable_get_buffer (drawable));
-
-      undo_buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0,
-                                                     undo_rect.width,
-                                                     undo_rect.height),
-                                     gimp_drawable_get_format (drawable));
-
-      gimp_gegl_buffer_copy (gimp_drawable_get_buffer (drawable),
-                             &undo_rect,
-                             GEGL_ABYSS_NONE,
-                             undo_buffer,
-                             GEGL_RECTANGLE (0, 0, 0, 0));
-
-      applicator = gimp_filter_get_applicator (filter);
-
-      if (applicator)
-        {
-          /*  disable the output crop  */
-          gimp_applicator_set_crop (applicator, NULL);
-
-          /*  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,
+      return TRUE;
+    }
+
+  if (applicator)
+    {
+      const GeglRectangle *crop_rect;
+
+      crop_rect = gimp_applicator_get_crop (applicator);
+
+      if (crop_rect && ! gegl_rectangle_intersect (&rect, &rect, crop_rect))
+        return TRUE;
+
+      /*  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_gegl_rectangle_align_to_tile_grid (
+    &undo_rect,
+    &rect,
+    gimp_drawable_get_buffer (drawable));
+
+  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));
+
+  gimp_gegl_buffer_copy (gimp_drawable_get_buffer (drawable),
+                         &undo_rect,
+                         GEGL_ABYSS_NONE,
+                         undo_buffer,
+                         GEGL_RECTANGLE (0, 0, 0, 0));
+
+  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  */
 
-          success = FALSE;
-        }
+      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);
 
-      g_object_unref (undo_buffer);
+      success = FALSE;
+    }
 
-      if (cache)
-        {
-          g_object_unref (cache);
-          g_free (rects);
-        }
+  g_object_unref (undo_buffer);
 
-      gimp_drawable_update (drawable,
-                            rect.x, rect.y,
-                            rect.width, rect.height);
+  if (cache)
+    {
+      g_object_unref (cache);
+      g_free (rects);
     }
 
+  gimp_drawable_update (drawable,
+                        rect.x, rect.y,
+                        rect.width, rect.height);
+
   return success;
 }
diff --git a/app/core/gimpdrawablefilter.c b/app/core/gimpdrawablefilter.c
index 02fefe0a11..5b27996b48 100644
--- a/app/core/gimpdrawablefilter.c
+++ b/app/core/gimpdrawablefilter.c
@@ -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;
-
-  gimp_drawable_filter_get_preview_rect (filter,
-                                         old_enabled,
-                                         old_alignment,
-                                         old_position,
-                                         &old_rect);
-
-  gimp_drawable_filter_get_preview_rect (filter,
-                                         filter->preview_enabled,
-                                         filter->preview_alignment,
-                                         filter->preview_position,
-                                         &new_rect);
-
-  gimp_applicator_set_crop (filter->applicator,
-                            filter->preview_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)
+  gboolean      enabled;
+
+  gimp_drawable_filter_get_crop_rect (filter,
+                                      old_crop_enabled,
+                                      old_crop_rect,
+                                      old_preview_enabled,
+                                      old_preview_alignment,
+                                      old_preview_position,
+                                      &old_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, enabled ? &new_rect : NULL);
+
+  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);
diff --git a/app/core/gimpdrawablefilter.h b/app/core/gimpdrawablefilter.h
index bb633322b4..cc3db76b43 100644
--- a/app/core/gimpdrawablefilter.h
+++ b/app/core/gimpdrawablefilter.h
@@ -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,


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]