[gimp/gimp-2-10] app, libgimpbase: add gimp:offset operation



commit f7a1aec1e9c507fd2a9d64ef2286c0669ed648c7
Author: Ell <ell_se yahoo com>
Date:   Wed Jun 5 17:53:16 2019 -0400

    app, libgimpbase: add gimp:offset operation
    
    Add a new gimp:offset operation, which implements equivalent
    functionality to gimp_drawable_offset(), in preparation for adding
    an interactive offset tool.
    
    To simplify things, add a GIMP_OFFSET_WRAP_AROUND value to the
    GimpOffsetType enum, to avoid the need for a separate wrap-around
    flag.  This makes the gimp-drawable-offset procedure parameters a
    little superfluous, but whatever.
    
    (cherry picked from commit 40fefb6076cfe1938dd72d32aaba209ec7360907)

 app/operations/Makefile.am           |   2 +
 app/operations/gimp-operations.c     |   2 +
 app/operations/gimpoperationoffset.c | 480 +++++++++++++++++++++++++++++++++++
 app/operations/gimpoperationoffset.h |  55 ++++
 libgimpbase/gimpbaseenums.c          |   2 +
 libgimpbase/gimpbaseenums.h          |   4 +-
 pdb/enums.pl                         |   6 +-
 7 files changed, 548 insertions(+), 3 deletions(-)
---
diff --git a/app/operations/Makefile.am b/app/operations/Makefile.am
index e46c944674..dad1ec9ebd 100644
--- a/app/operations/Makefile.am
+++ b/app/operations/Makefile.am
@@ -64,6 +64,8 @@ libappoperations_a_sources = \
        gimpoperationhistogramsink.h            \
        gimpoperationmaskcomponents.cc          \
        gimpoperationmaskcomponents.h           \
+       gimpoperationoffset.c                   \
+       gimpoperationoffset.h                   \
        gimpoperationprofiletransform.c         \
        gimpoperationprofiletransform.h         \
        gimpoperationscalarmultiply.c           \
diff --git a/app/operations/gimp-operations.c b/app/operations/gimp-operations.c
index dd9390bf14..7cb30fd2dd 100644
--- a/app/operations/gimp-operations.c
+++ b/app/operations/gimp-operations.c
@@ -42,6 +42,7 @@
 #include "gimpoperationgrow.h"
 #include "gimpoperationhistogramsink.h"
 #include "gimpoperationmaskcomponents.h"
+#include "gimpoperationoffset.h"
 #include "gimpoperationprofiletransform.h"
 #include "gimpoperationscalarmultiply.h"
 #include "gimpoperationsemiflatten.h"
@@ -136,6 +137,7 @@ gimp_operations_init (Gimp *gimp)
   g_type_class_ref (GIMP_TYPE_OPERATION_GROW);
   g_type_class_ref (GIMP_TYPE_OPERATION_HISTOGRAM_SINK);
   g_type_class_ref (GIMP_TYPE_OPERATION_MASK_COMPONENTS);
+  g_type_class_ref (GIMP_TYPE_OPERATION_OFFSET);
   g_type_class_ref (GIMP_TYPE_OPERATION_PROFILE_TRANSFORM);
   g_type_class_ref (GIMP_TYPE_OPERATION_SCALAR_MULTIPLY);
   g_type_class_ref (GIMP_TYPE_OPERATION_SEMI_FLATTEN);
diff --git a/app/operations/gimpoperationoffset.c b/app/operations/gimpoperationoffset.c
new file mode 100644
index 0000000000..6a6114be03
--- /dev/null
+++ b/app/operations/gimpoperationoffset.c
@@ -0,0 +1,480 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimpoperationoffset.c
+ * Copyright (C) 2019 Ell
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <cairo.h>
+#include <gegl-plugin.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+#include "operations-types.h"
+
+#include "gegl/gimp-gegl-utils.h"
+
+#include "core/gimpcontext.h"
+
+#include "gimpoperationoffset.h"
+
+
+enum
+{
+  PROP_0,
+  PROP_CONTEXT,
+  PROP_TYPE,
+  PROP_X,
+  PROP_Y
+};
+
+
+static void            gimp_operation_offset_dispose                   (GObject              *object);
+static void            gimp_operation_offset_get_property              (GObject              *object,
+                                                                        guint                 property_id,
+                                                                        GValue               *value,
+                                                                        GParamSpec           *pspec);
+static void            gimp_operation_offset_set_property              (GObject              *object,
+                                                                        guint                 property_id,
+                                                                        const GValue         *value,
+                                                                        GParamSpec           *pspec);
+
+static GeglRectangle   gimp_operation_offset_get_required_for_output   (GeglOperation        *operation,
+                                                                        const gchar          *input_pad,
+                                                                        const GeglRectangle  *output_roi);
+static GeglRectangle   gimp_operation_offset_get_invalidated_by_change (GeglOperation        *operation,
+                                                                        const gchar          *input_pad,
+                                                                        const GeglRectangle  *input_roi);
+static void            gimp_operation_offset_prepare                   (GeglOperation        *operation);
+static gboolean        gimp_operation_offset_parent_process            (GeglOperation        *operation,
+                                                                        GeglOperationContext *context,
+                                                                        const gchar          *output_pad,
+                                                                        const GeglRectangle  *result,
+                                                                        gint                  level);
+
+static gboolean        gimp_operation_offset_process                   (GeglOperation        *operation,
+                                                                        GeglBuffer           *input,
+                                                                        GeglBuffer           *output,
+                                                                        const GeglRectangle  *roi,
+                                                                        gint                  level);
+
+static void            gimp_operation_offset_get_offset                (GimpOperationOffset  *offset,
+                                                                        gboolean              invert,
+                                                                        gint                 *x,
+                                                                        gint                 *y);
+static void            gimp_operation_offset_get_rect                  (GimpOperationOffset  *offset,
+                                                                        gboolean              invert,
+                                                                        const GeglRectangle  *roi,
+                                                                        GeglRectangle        *rect);
+
+
+G_DEFINE_TYPE (GimpOperationOffset, gimp_operation_offset,
+               GEGL_TYPE_OPERATION_FILTER)
+
+#define parent_class gimp_operation_offset_parent_class
+
+
+static void
+gimp_operation_offset_class_init (GimpOperationOffsetClass *klass)
+{
+  GObjectClass             *object_class    = G_OBJECT_CLASS (klass);
+  GeglOperationClass       *operation_class = GEGL_OPERATION_CLASS (klass);
+  GeglOperationFilterClass *filter_class    = GEGL_OPERATION_FILTER_CLASS (klass);
+
+  object_class->dispose                      = gimp_operation_offset_dispose;
+  object_class->set_property                 = gimp_operation_offset_set_property;
+  object_class->get_property                 = gimp_operation_offset_get_property;
+
+  operation_class->get_required_for_output   = gimp_operation_offset_get_required_for_output;
+  operation_class->get_invalidated_by_change = gimp_operation_offset_get_invalidated_by_change;
+  operation_class->prepare                   = gimp_operation_offset_prepare;
+  operation_class->process                   = gimp_operation_offset_parent_process;
+
+  operation_class->threaded                  = FALSE;
+  operation_class->cache_policy              = GEGL_CACHE_POLICY_NEVER;
+
+  filter_class->process                      = gimp_operation_offset_process;
+
+  gegl_operation_class_set_keys (operation_class,
+                                 "name",        "gimp:offset",
+                                 "categories",  "gimp",
+                                 "description", "GIMP Offset operation",
+                                 NULL);
+
+  g_object_class_install_property (object_class, PROP_CONTEXT,
+                                   g_param_spec_object ("context",
+                                                        "Context",
+                                                        "A GimpContext",
+                                                        GIMP_TYPE_CONTEXT,
+                                                        G_PARAM_READWRITE |
+                                                        G_PARAM_CONSTRUCT));
+
+  g_object_class_install_property (object_class, PROP_TYPE,
+                                   g_param_spec_enum  ("type",
+                                                       "Type",
+                                                       "Offset type",
+                                                       GIMP_TYPE_OFFSET_TYPE,
+                                                       GIMP_OFFSET_WRAP_AROUND,
+                                                       G_PARAM_READWRITE |
+                                                       G_PARAM_CONSTRUCT));
+
+  g_object_class_install_property (object_class, PROP_X,
+                                   g_param_spec_int ("x",
+                                                     "X Offset",
+                                                     "X offset",
+                                                     G_MININT, G_MAXINT, 0,
+                                                     G_PARAM_READWRITE |
+                                                     G_PARAM_CONSTRUCT));
+
+  g_object_class_install_property (object_class, PROP_Y,
+                                   g_param_spec_int ("y",
+                                                     "Y Offset",
+                                                     "Y offset",
+                                                     G_MININT, G_MAXINT, 0,
+                                                     G_PARAM_READWRITE |
+                                                     G_PARAM_CONSTRUCT));
+}
+
+static void
+gimp_operation_offset_init (GimpOperationOffset *self)
+{
+}
+
+static void
+gimp_operation_offset_dispose (GObject *object)
+{
+  GimpOperationOffset *offset = GIMP_OPERATION_OFFSET (object);
+
+  g_clear_object (&offset->context);
+
+  G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+gimp_operation_offset_get_property (GObject    *object,
+                                    guint       property_id,
+                                    GValue     *value,
+                                    GParamSpec *pspec)
+{
+  GimpOperationOffset *offset = GIMP_OPERATION_OFFSET (object);
+
+  switch (property_id)
+    {
+    case PROP_CONTEXT:
+      g_value_set_object (value, offset->context);
+      break;
+
+    case PROP_TYPE:
+      g_value_set_enum (value, offset->type);
+      break;
+
+    case PROP_X:
+      g_value_set_int (value, offset->x);
+      break;
+
+    case PROP_Y:
+      g_value_set_int (value, offset->y);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+      break;
+    }
+}
+
+static void
+gimp_operation_offset_set_property (GObject      *object,
+                                         guint         property_id,
+                                         const GValue *value,
+                                         GParamSpec   *pspec)
+{
+  GimpOperationOffset *offset = GIMP_OPERATION_OFFSET (object);
+
+  switch (property_id)
+    {
+    case PROP_CONTEXT:
+      g_set_object (&offset->context, g_value_get_object (value));
+      break;
+
+    case PROP_TYPE:
+      offset->type = g_value_get_enum (value);
+      break;
+
+    case PROP_X:
+      offset->x = g_value_get_int (value);
+      break;
+
+    case PROP_Y:
+      offset->y = g_value_get_int (value);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+      break;
+    }
+}
+
+static GeglRectangle
+gimp_operation_offset_get_required_for_output (GeglOperation       *operation,
+                                               const gchar         *input_pad,
+                                               const GeglRectangle *output_roi)
+{
+  GimpOperationOffset *offset = GIMP_OPERATION_OFFSET (operation);
+  GeglRectangle        rect;
+
+  gimp_operation_offset_get_rect (offset, TRUE, output_roi, &rect);
+
+  return rect;
+}
+
+static GeglRectangle
+gimp_operation_offset_get_invalidated_by_change (GeglOperation       *operation,
+                                                 const gchar         *input_pad,
+                                                 const GeglRectangle *input_roi)
+{
+  GimpOperationOffset *offset = GIMP_OPERATION_OFFSET (operation);
+  GeglRectangle        rect;
+
+  gimp_operation_offset_get_rect (offset, FALSE, input_roi, &rect);
+
+  return rect;
+}
+
+static void
+gimp_operation_offset_prepare (GeglOperation *operation)
+{
+  const Babl *format;
+
+  format = gegl_operation_get_source_format (operation, "input");
+
+  if (! format)
+    format = babl_format ("RGBA float");
+
+  gegl_operation_set_format (operation, "input",  format);
+  gegl_operation_set_format (operation, "output", format);
+}
+
+static gboolean
+gimp_operation_offset_parent_process (GeglOperation        *operation,
+                                      GeglOperationContext *context,
+                                      const gchar          *output_pad,
+                                      const GeglRectangle  *result,
+                                      gint                  level)
+{
+  GimpOperationOffset *offset = GIMP_OPERATION_OFFSET (operation);
+  GObject             *input;
+  gint                 x;
+  gint                 y;
+
+  input = gegl_operation_context_get_object (context, "input");
+
+  gimp_operation_offset_get_offset (offset, FALSE, &x, &y);
+
+  if (x == 0 && y == 0)
+    {
+      gegl_operation_context_set_object (context, "output", input);
+
+      return TRUE;
+    }
+  else if (offset->type  == GIMP_OFFSET_TRANSPARENT ||
+           (offset->type == GIMP_OFFSET_BACKGROUND  &&
+            ! offset->context))
+    {
+      GObject *output = NULL;
+
+      if (input)
+        {
+          const GeglRectangle *extent;
+
+          extent = gegl_buffer_get_extent (GEGL_BUFFER (input));
+
+          output = g_object_new (GEGL_TYPE_BUFFER,
+            "source", input,
+            "x",      extent->x,
+            "y",      extent->y,
+            "width",  extent->width,
+            "height", extent->height,
+            "shift-x", -x,
+            "shift-y", -y,
+            NULL);
+
+          if (gegl_object_get_has_forked (input))
+            gegl_object_set_has_forked (output);
+        }
+
+      gegl_operation_context_take_object (context, "output", output);
+
+      return TRUE;
+    }
+
+  return GEGL_OPERATION_CLASS (parent_class)->process (operation, context,
+                                                       output_pad, result,
+                                                       level);
+}
+
+static gboolean
+gimp_operation_offset_process (GeglOperation       *operation,
+                               GeglBuffer          *input,
+                               GeglBuffer          *output,
+                               const GeglRectangle *roi,
+                               gint                 level)
+{
+  GimpOperationOffset *offset = GIMP_OPERATION_OFFSET (operation);
+  GeglColor           *color  = NULL;
+  GeglRectangle        bounds;
+  gint                 x;
+  gint                 y;
+  gint                 i;
+
+  bounds = gegl_operation_get_bounding_box (GEGL_OPERATION (offset));
+
+  gimp_operation_offset_get_offset (offset, FALSE, &x, &y);
+
+  if (offset->type == GIMP_OFFSET_BACKGROUND && offset->context)
+    {
+      GimpRGB bg;
+
+      gimp_context_get_background (offset->context, &bg);
+
+      color = gimp_gegl_color_new (&bg);
+    }
+
+  for (i = 0; i < 4; i++)
+    {
+      GeglRectangle offset_bounds = bounds;
+      gint          offset_x      = x;
+      gint          offset_y      = y;
+
+      if (i & 1)
+        offset_x += x < 0 ? bounds.width  : -bounds.width;
+      if (i & 2)
+        offset_y += y < 0 ? bounds.height : -bounds.height;
+
+      offset_bounds.x += offset_x;
+      offset_bounds.y += offset_y;
+
+      if (gegl_rectangle_intersect (&offset_bounds, &offset_bounds, roi))
+        {
+          if (i == 0 || offset->type == GIMP_OFFSET_WRAP_AROUND)
+            {
+              GeglRectangle offset_roi = offset_bounds;
+
+              offset_roi.x -= offset_x;
+              offset_roi.y -= offset_y;
+
+              gegl_buffer_copy (input,  &offset_roi, GEGL_ABYSS_NONE,
+                                output, &offset_bounds);
+            }
+          else if (color)
+            {
+              gegl_buffer_set_color (output, &offset_bounds, color);
+            }
+        }
+    }
+
+  g_clear_object (&color);
+
+  return TRUE;
+}
+
+static void
+gimp_operation_offset_get_offset (GimpOperationOffset *offset,
+                                  gboolean             invert,
+                                  gint                *x,
+                                  gint                *y)
+{
+  GeglRectangle bounds;
+
+  bounds = gegl_operation_get_bounding_box (GEGL_OPERATION (offset));
+
+  if (gegl_rectangle_is_empty (&bounds))
+    {
+      *x = 0;
+      *y = 0;
+
+      return;
+    }
+
+  *x = offset->x;
+  *y = offset->y;
+
+  if (invert)
+    {
+      *x = -*x;
+      *y = -*y;
+    }
+
+  if (offset->type == GIMP_OFFSET_WRAP_AROUND)
+    {
+      *x %= bounds.width;
+
+      if (*x < 0)
+        *x += bounds.width;
+
+      *y %= bounds.height;
+
+      if (*y < 0)
+        *y += bounds.height;
+    }
+}
+
+static void
+gimp_operation_offset_get_rect (GimpOperationOffset *offset,
+                                gboolean             invert,
+                                const GeglRectangle *roi,
+                                GeglRectangle       *rect)
+{
+  GeglRectangle bounds;
+  gint          x;
+  gint          y;
+
+  bounds = gegl_operation_get_bounding_box (GEGL_OPERATION (offset));
+
+  if (gegl_rectangle_is_empty (&bounds))
+    {
+      rect->x      = 0;
+      rect->y      = 0;
+      rect->width  = 0;
+      rect->height = 0;
+
+      return;
+    }
+
+  gimp_operation_offset_get_offset (offset, invert, &x, &y);
+
+  *rect = *roi;
+
+  rect->x += x;
+  rect->y += y;
+
+  if (offset->type == GIMP_OFFSET_WRAP_AROUND)
+    {
+      if (rect->x + rect->width > bounds.x + bounds.width)
+        {
+          rect->x      = bounds.x;
+          rect->width  = bounds.width;
+        }
+
+      if (rect->y + rect->height > bounds.y + bounds.height)
+        {
+          rect->y      = bounds.y;
+          rect->height = bounds.height;
+        }
+    }
+
+  gegl_rectangle_intersect (rect, rect, &bounds);
+}
diff --git a/app/operations/gimpoperationoffset.h b/app/operations/gimpoperationoffset.h
new file mode 100644
index 0000000000..dcd0e0b320
--- /dev/null
+++ b/app/operations/gimpoperationoffset.h
@@ -0,0 +1,55 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimpoperationoffset.h
+ * Copyright (C) 2019 Ell
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GIMP_OPERATION_OFFSET_H__
+#define __GIMP_OPERATION_OFFSET_H__
+
+
+#define GIMP_TYPE_OPERATION_OFFSET            (gimp_operation_offset_get_type ())
+#define GIMP_OPERATION_OFFSET(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), 
GIMP_TYPE_OPERATION_OFFSET, GimpOperationOffset))
+#define GIMP_OPERATION_OFFSET_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass),  
GIMP_TYPE_OPERATION_OFFSET, GimpOperationOffsetClass))
+#define GIMP_IS_OPERATION_OFFSET(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), 
GIMP_TYPE_OPERATION_OFFSET))
+#define GIMP_IS_OPERATION_OFFSET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),  
GIMP_TYPE_OPERATION_OFFSET))
+#define GIMP_OPERATION_OFFSET_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj),  
GIMP_TYPE_OPERATION_OFFSET, GimpOperationOffsetClass))
+
+
+typedef struct _GimpOperationOffset      GimpOperationOffset;
+typedef struct _GimpOperationOffsetClass GimpOperationOffsetClass;
+
+struct _GimpOperationOffset
+{
+  GeglOperationFilter  parent_instance;
+
+  GimpContext         *context;
+  GimpOffsetType       type;
+  gint                 x;
+  gint                 y;
+};
+
+struct _GimpOperationOffsetClass
+{
+  GeglOperationFilterClass  parent_class;
+};
+
+
+GType   gimp_operation_offset_get_type (void) G_GNUC_CONST;
+
+
+#endif /* __GIMP_OPERATION_OFFSET_H__ */
diff --git a/libgimpbase/gimpbaseenums.c b/libgimpbase/gimpbaseenums.c
index ad87b7523b..186e48e7e7 100644
--- a/libgimpbase/gimpbaseenums.c
+++ b/libgimpbase/gimpbaseenums.c
@@ -1183,6 +1183,7 @@ gimp_offset_type_get_type (void)
   {
     { GIMP_OFFSET_BACKGROUND, "GIMP_OFFSET_BACKGROUND", "background" },
     { GIMP_OFFSET_TRANSPARENT, "GIMP_OFFSET_TRANSPARENT", "transparent" },
+    { GIMP_OFFSET_WRAP_AROUND, "GIMP_OFFSET_WRAP_AROUND", "wrap-around" },
     { 0, NULL, NULL }
   };
 
@@ -1190,6 +1191,7 @@ gimp_offset_type_get_type (void)
   {
     { GIMP_OFFSET_BACKGROUND, "GIMP_OFFSET_BACKGROUND", NULL },
     { GIMP_OFFSET_TRANSPARENT, "GIMP_OFFSET_TRANSPARENT", NULL },
+    { GIMP_OFFSET_WRAP_AROUND, "GIMP_OFFSET_WRAP_AROUND", NULL },
     { 0, NULL, NULL }
   };
 
diff --git a/libgimpbase/gimpbaseenums.h b/libgimpbase/gimpbaseenums.h
index 45bf8da201..4f3d9fafbe 100644
--- a/libgimpbase/gimpbaseenums.h
+++ b/libgimpbase/gimpbaseenums.h
@@ -932,6 +932,7 @@ typedef enum
  * GimpOffsetType:
  * @GIMP_OFFSET_BACKGROUND:  Background
  * @GIMP_OFFSET_TRANSPARENT: Transparent
+ * @GIMP_OFFSET_WRAP_AROUND: Wrap image around
  *
  * Background fill types for the offset operation.
  **/
@@ -942,7 +943,8 @@ GType gimp_offset_type_get_type (void) G_GNUC_CONST;
 typedef enum
 {
   GIMP_OFFSET_BACKGROUND,
-  GIMP_OFFSET_TRANSPARENT
+  GIMP_OFFSET_TRANSPARENT,
+  GIMP_OFFSET_WRAP_AROUND
 } GimpOffsetType;
 
 
diff --git a/pdb/enums.pl b/pdb/enums.pl
index a04d88b62d..e9e11cd829 100644
--- a/pdb/enums.pl
+++ b/pdb/enums.pl
@@ -379,9 +379,11 @@ package Gimp::CodeGen::enums;
     GimpOffsetType =>
        { contig => 1,
          header => 'libgimpbase/gimpbaseenums.h',
-         symbols => [ qw(GIMP_OFFSET_BACKGROUND GIMP_OFFSET_TRANSPARENT) ],
+         symbols => [ qw(GIMP_OFFSET_BACKGROUND GIMP_OFFSET_TRANSPARENT
+                         GIMP_OFFSET_WRAP_AROUND) ],
          mapping => { GIMP_OFFSET_BACKGROUND => '0',
-                      GIMP_OFFSET_TRANSPARENT => '1' }
+                      GIMP_OFFSET_TRANSPARENT => '1',
+                      GIMP_OFFSET_WRAP_AROUND => '2' }
        },
     GimpOrientationType =>
        { contig => 1,


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