[gimp] app: add merge layer mode



commit 23e6984d46e75c77edad6e164d94dc392f386084
Author: Ell <ell_se yahoo com>
Date:   Fri Mar 10 17:59:17 2017 -0500

    app: add merge layer mode
    
    Merge mode lays the source layer on top of the destination, same as
    normal mode, however, it assumes the source and destination are two
    parts of an original whole, and are therefore mutually exclusive.
    
    This is useful for blending cut & pasted content without artifacts,
    or for replacing erased content in general.

 app/core/gimpimage.c                               |    1 +
 app/operations/gimp-operations.c                   |    4 +-
 app/operations/layer-modes/Makefile.am             |    2 +
 app/operations/layer-modes/gimp-layer-modes.c      |   17 ++
 .../layer-modes/gimpoperationlayermode.c           |    1 +
 app/operations/layer-modes/gimpoperationmerge.c    |  236 ++++++++++++++++++++
 app/operations/layer-modes/gimpoperationmerge.h    |   63 ++++++
 app/operations/operations-enums.c                  |    2 +
 app/operations/operations-enums.h                  |    1 +
 libgimp/gimpenums.h                                |    3 +-
 tools/pdbgen/enums.pl                              |    5 +-
 11 files changed, 331 insertions(+), 4 deletions(-)
---
diff --git a/app/core/gimpimage.c b/app/core/gimpimage.c
index cd2e487..167a314 100644
--- a/app/core/gimpimage.c
+++ b/app/core/gimpimage.c
@@ -2465,6 +2465,7 @@ gimp_image_get_xcf_version (GimpImage    *image,
         case GIMP_LAYER_MODE_COLOR_ERASE:
         case GIMP_LAYER_MODE_ERASE:
         case GIMP_LAYER_MODE_MONO_MIX:
+        case GIMP_LAYER_MODE_MERGE:
           version = MAX (10, version);
           break;
 
diff --git a/app/operations/gimp-operations.c b/app/operations/gimp-operations.c
index 93c7be2..79121d3 100644
--- a/app/operations/gimp-operations.c
+++ b/app/operations/gimp-operations.c
@@ -86,8 +86,9 @@
 #include "layer-modes/gimp-layer-modes.h"
 #include "layer-modes/gimpoperationantierase.h"
 #include "layer-modes/gimpoperationbehind.h"
-#include "layer-modes/gimpoperationerase.h"
 #include "layer-modes/gimpoperationdissolve.h"
+#include "layer-modes/gimpoperationerase.h"
+#include "layer-modes/gimpoperationmerge.h"
 #include "layer-modes/gimpoperationnormal.h"
 #include "layer-modes/gimpoperationreplace.h"
 
@@ -147,6 +148,7 @@ gimp_operations_init (void)
   g_type_class_ref (GIMP_TYPE_OPERATION_GRAIN_EXTRACT_LEGACY);
   g_type_class_ref (GIMP_TYPE_OPERATION_GRAIN_MERGE_LEGACY);
   g_type_class_ref (GIMP_TYPE_OPERATION_ERASE);
+  g_type_class_ref (GIMP_TYPE_OPERATION_MERGE);
   g_type_class_ref (GIMP_TYPE_OPERATION_REPLACE);
   g_type_class_ref (GIMP_TYPE_OPERATION_ANTI_ERASE);
 
diff --git a/app/operations/layer-modes/Makefile.am b/app/operations/layer-modes/Makefile.am
index f0852e7..cd0c80a 100644
--- a/app/operations/layer-modes/Makefile.am
+++ b/app/operations/layer-modes/Makefile.am
@@ -33,6 +33,8 @@ libapplayermodes_generic_a_sources = \
        gimpoperationdissolve.h         \
        gimpoperationerase.c            \
        gimpoperationerase.h            \
+       gimpoperationmerge.c            \
+       gimpoperationmerge.h            \
        gimpoperationnormal.c           \
        gimpoperationnormal.h           \
        gimpoperationreplace.c          \
diff --git a/app/operations/layer-modes/gimp-layer-modes.c b/app/operations/layer-modes/gimp-layer-modes.c
index 1a61e50..51861c6 100644
--- a/app/operations/layer-modes/gimp-layer-modes.c
+++ b/app/operations/layer-modes/gimp-layer-modes.c
@@ -48,6 +48,7 @@
 #include "gimpoperationbehind.h"
 #include "gimpoperationdissolve.h"
 #include "gimpoperationerase.h"
+#include "gimpoperationmerge.h"
 #include "gimpoperationnormal.h"
 #include "gimpoperationreplace.h"
 
@@ -836,6 +837,17 @@ static const GimpLayerModeInfo layer_mode_infos[] =
     .blend_space          = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR
   },
 
+  { GIMP_LAYER_MODE_MERGE,
+
+    .op_name              = "gimp:merge",
+    .function             = gimp_operation_merge_process,
+    .flags                = GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE,
+    .context              = GIMP_LAYER_MODE_CONTEXT_ALL,
+    .paint_composite_mode = GIMP_LAYER_COMPOSITE_SRC_OVER,
+    .composite_mode       = GIMP_LAYER_COMPOSITE_SRC_OVER,
+    .composite_space      = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR
+  },
+
   { GIMP_LAYER_MODE_REPLACE,
 
     .op_name              = "gimp:replace",
@@ -868,6 +880,7 @@ static const GimpLayerMode layer_mode_group_default[] =
   GIMP_LAYER_MODE_COLOR_ERASE,
   GIMP_LAYER_MODE_ERASE,
   GIMP_LAYER_MODE_ANTI_ERASE,
+  GIMP_LAYER_MODE_MERGE,
 
   GIMP_LAYER_MODE_SEPARATOR,
 
@@ -1104,6 +1117,10 @@ static const GimpLayerMode layer_mode_groups[][2] =
     [GIMP_LAYER_MODE_GROUP_LEGACY ] = -1
   },
 
+  { [GIMP_LAYER_MODE_GROUP_DEFAULT] = GIMP_LAYER_MODE_MERGE,
+    [GIMP_LAYER_MODE_GROUP_LEGACY ] = -1
+  },
+
   { [GIMP_LAYER_MODE_GROUP_DEFAULT] = GIMP_LAYER_MODE_REPLACE,
     [GIMP_LAYER_MODE_GROUP_LEGACY ] = -1
   },
diff --git a/app/operations/layer-modes/gimpoperationlayermode.c 
b/app/operations/layer-modes/gimpoperationlayermode.c
index dd3b863..0434380 100644
--- a/app/operations/layer-modes/gimpoperationlayermode.c
+++ b/app/operations/layer-modes/gimpoperationlayermode.c
@@ -2343,6 +2343,7 @@ gimp_layer_mode_get_blend_fun (GimpLayerMode mode)
     case GIMP_LAYER_MODE_GRAIN_EXTRACT_LEGACY:
     case GIMP_LAYER_MODE_GRAIN_MERGE_LEGACY:
     case GIMP_LAYER_MODE_ERASE:
+    case GIMP_LAYER_MODE_MERGE:
     case GIMP_LAYER_MODE_REPLACE:
     case GIMP_LAYER_MODE_ANTI_ERASE:
     case GIMP_LAYER_MODE_SEPARATOR: /* to stop GCC from complaining :P */
diff --git a/app/operations/layer-modes/gimpoperationmerge.c b/app/operations/layer-modes/gimpoperationmerge.c
new file mode 100644
index 0000000..d13e231
--- /dev/null
+++ b/app/operations/layer-modes/gimpoperationmerge.c
@@ -0,0 +1,236 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimpoperationmerge.c
+ * Copyright (C) 2008 Michael Natterer <mitch gimp org>
+ *               2017 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <gegl-plugin.h>
+
+#include "../operations-types.h"
+
+#include "gimpoperationmerge.h"
+
+
+G_DEFINE_TYPE (GimpOperationMerge, gimp_operation_merge,
+               GIMP_TYPE_OPERATION_LAYER_MODE)
+
+
+static void
+gimp_operation_merge_class_init (GimpOperationMergeClass *klass)
+{
+  GeglOperationClass               *operation_class;
+  GeglOperationPointComposer3Class *point_class;
+
+  operation_class = GEGL_OPERATION_CLASS (klass);
+  point_class     = GEGL_OPERATION_POINT_COMPOSER3_CLASS (klass);
+
+  gegl_operation_class_set_keys (operation_class,
+                                 "name",        "gimp:merge",
+                                 "description", "GIMP merge mode operation",
+                                 NULL);
+
+  point_class->process = gimp_operation_merge_process;
+}
+
+static void
+gimp_operation_merge_init (GimpOperationMerge *self)
+{
+}
+
+gboolean
+gimp_operation_merge_process (GeglOperation       *op,
+                              void                *in_p,
+                              void                *layer_p,
+                              void                *mask_p,
+                              void                *out_p,
+                              glong                samples,
+                              const GeglRectangle *roi,
+                              gint                 level)
+{
+  GimpOperationLayerMode *layer_mode = (gpointer) op;
+  gfloat                 *in         = in_p;
+  gfloat                 *out        = out_p;
+  gfloat                 *layer      = layer_p;
+  gfloat                 *mask       = mask_p;
+  gfloat                  opacity    = layer_mode->opacity;
+  const gboolean          has_mask   = mask != NULL;
+
+  switch (layer_mode->composite_mode)
+    {
+    case GIMP_LAYER_COMPOSITE_SRC_OVER:
+    case GIMP_LAYER_COMPOSITE_AUTO:
+      while (samples--)
+        {
+          gfloat in_alpha    = in[ALPHA];
+          gfloat layer_alpha = layer[ALPHA] * opacity;
+          gfloat new_alpha;
+          gint   b;
+
+          if (has_mask)
+            layer_alpha *= *mask;
+
+          in_alpha = MIN (in_alpha, 1.0f - layer_alpha);
+          new_alpha  = in_alpha + layer_alpha;
+
+          if (new_alpha)
+            {
+              gfloat ratio = layer_alpha / new_alpha;
+
+              for (b = RED; b < ALPHA; b++)
+                {
+                  out[b] = in[b] + (layer[b] - in[b]) * ratio;
+                }
+            }
+          else
+            {
+              for (b = RED; b < ALPHA; b++)
+                {
+                  out[b] = in[b];
+                }
+            }
+
+          out[ALPHA] = new_alpha;
+
+          in    += 4;
+          layer += 4;
+          out   += 4;
+
+          if (has_mask)
+            mask++;
+        }
+      break;
+
+    case GIMP_LAYER_COMPOSITE_SRC_ATOP:
+      while (samples--)
+        {
+          gfloat in_alpha    = in[ALPHA];
+          gfloat layer_alpha = layer[ALPHA] * opacity;
+          gint   b;
+
+          if (has_mask)
+            layer_alpha *= *mask;
+
+          layer_alpha -= 1.0f - in_alpha;
+
+          if (layer_alpha > 0.0f)
+            {
+              gfloat ratio = layer_alpha / in_alpha;
+
+              for (b = RED; b < ALPHA; b++)
+                {
+                  out[b] = in[b] + (layer[b] - in[b]) * ratio;
+                }
+            }
+          else
+            {
+              for (b = RED; b < ALPHA; b++)
+                {
+                  out[b] = in[b];
+                }
+            }
+
+          out[ALPHA] = in_alpha;
+
+          in    += 4;
+          layer += 4;
+          out   += 4;
+
+          if (has_mask)
+            mask++;
+        }
+      break;
+
+    case GIMP_LAYER_COMPOSITE_DST_ATOP:
+      while (samples--)
+        {
+          gfloat layer_alpha = layer[ALPHA] * opacity;
+          gint   b;
+
+          if (has_mask)
+            layer_alpha *= *mask;
+
+          if (layer_alpha != 0.0f)
+            {
+              for (b = RED; b < ALPHA; b++)
+                {
+                  out[b] = layer[b];
+                }
+            }
+          else
+            {
+              for (b = RED; b < ALPHA; b++)
+                {
+                  out[b] = in[b];
+                }
+            }
+
+          out[ALPHA] = layer_alpha;
+
+          in    += 4;
+          layer += 4;
+          out   += 4;
+
+          if (has_mask)
+            mask++;
+        }
+      break;
+
+    case GIMP_LAYER_COMPOSITE_SRC_IN:
+      while (samples--)
+        {
+          gfloat in_alpha    = in[ALPHA];
+          gfloat layer_alpha = layer[ALPHA] * opacity;
+          gint   b;
+
+          if (has_mask)
+            layer_alpha *= *mask;
+
+          layer_alpha -= 1.0f - in_alpha;
+          layer_alpha = MAX (layer_alpha, 0.0f);
+
+          if (layer_alpha != 0.0f)
+            {
+              for (b = RED; b < ALPHA; b++)
+                {
+                  out[b] = layer[b];
+                }
+            }
+          else
+            {
+              for (b = RED; b < ALPHA; b++)
+                {
+                  out[b] = in[b];
+                }
+            }
+
+          out[ALPHA] = layer_alpha;
+
+          in    += 4;
+          layer += 4;
+          out   += 4;
+
+          if (has_mask)
+            mask++;
+        }
+      break;
+    }
+
+  return TRUE;
+}
diff --git a/app/operations/layer-modes/gimpoperationmerge.h b/app/operations/layer-modes/gimpoperationmerge.h
new file mode 100644
index 0000000..8734e8c
--- /dev/null
+++ b/app/operations/layer-modes/gimpoperationmerge.h
@@ -0,0 +1,63 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimpoperationmerge.h
+ * Copyright (C) 2008 Michael Natterer <mitch gimp org>
+ *               2017 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 <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GIMP_OPERATION_MERGE_H__
+#define __GIMP_OPERATION_MERGE_H__
+
+
+#include "gimpoperationlayermode.h"
+
+
+#define GIMP_TYPE_OPERATION_MERGE            (gimp_operation_merge_get_type ())
+#define GIMP_OPERATION_MERGE(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_OPERATION_MERGE, 
GimpOperationMerge))
+#define GIMP_OPERATION_MERGE_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass),  GIMP_TYPE_OPERATION_MERGE, 
GimpOperationMergeClass))
+#define GIMP_IS_OPERATION_MERGE(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_OPERATION_MERGE))
+#define GIMP_IS_OPERATION_MERGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),  GIMP_TYPE_OPERATION_MERGE))
+#define GIMP_OPERATION_MERGE_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj),  GIMP_TYPE_OPERATION_MERGE, 
GimpOperationMergeClass))
+
+
+typedef struct _GimpOperationMerge      GimpOperationMerge;
+typedef struct _GimpOperationMergeClass GimpOperationMergeClass;
+
+struct _GimpOperationMerge
+{
+  GimpOperationLayerMode  parent_instance;
+};
+
+struct _GimpOperationMergeClass
+{
+  GimpOperationLayerModeClass  parent_class;
+};
+
+
+GType    gimp_operation_merge_get_type (void) G_GNUC_CONST;
+
+gboolean gimp_operation_merge_process  (GeglOperation       *op,
+                                        void                *in,
+                                        void                *layer,
+                                        void                *mask,
+                                        void                *out,
+                                        glong                samples,
+                                        const GeglRectangle *roi,
+                                        gint                 level);
+
+
+#endif /* __GIMP_OPERATION_MERGE_H__ */
diff --git a/app/operations/operations-enums.c b/app/operations/operations-enums.c
index 75fb2b2..989c4bd 100644
--- a/app/operations/operations-enums.c
+++ b/app/operations/operations-enums.c
@@ -141,6 +141,7 @@ gimp_layer_mode_get_type (void)
     { GIMP_LAYER_MODE_COLOR_ERASE, "GIMP_LAYER_MODE_COLOR_ERASE", "color-erase" },
     { GIMP_LAYER_MODE_ERASE, "GIMP_LAYER_MODE_ERASE", "erase" },
     { GIMP_LAYER_MODE_MONO_MIX, "GIMP_LAYER_MODE_MONO_MIX", "mono-mix" },
+    { GIMP_LAYER_MODE_MERGE, "GIMP_LAYER_MODE_MERGE", "merge" },
     { GIMP_LAYER_MODE_REPLACE, "GIMP_LAYER_MODE_REPLACE", "replace" },
     { GIMP_LAYER_MODE_ANTI_ERASE, "GIMP_LAYER_MODE_ANTI_ERASE", "anti-erase" },
     { 0, NULL, NULL }
@@ -208,6 +209,7 @@ gimp_layer_mode_get_type (void)
     { GIMP_LAYER_MODE_COLOR_ERASE, NC_("layer-mode", "Color erase"), NULL },
     { GIMP_LAYER_MODE_ERASE, NC_("layer-mode", "Erase"), NULL },
     { GIMP_LAYER_MODE_MONO_MIX, NC_("layer-mode", "Mono mix"), NULL },
+    { GIMP_LAYER_MODE_MERGE, NC_("layer-mode", "Merge"), NULL },
     { GIMP_LAYER_MODE_REPLACE, NC_("layer-mode", "Replace"), NULL },
     { GIMP_LAYER_MODE_ANTI_ERASE, NC_("layer-mode", "Anti erase"), NULL },
     { 0, NULL, NULL }
diff --git a/app/operations/operations-enums.h b/app/operations/operations-enums.h
index ef863b2..2ac6736 100644
--- a/app/operations/operations-enums.h
+++ b/app/operations/operations-enums.h
@@ -119,6 +119,7 @@ typedef enum
   GIMP_LAYER_MODE_COLOR_ERASE,           /*< desc="Color erase"              >*/
   GIMP_LAYER_MODE_ERASE,                 /*< desc="Erase"                    >*/
   GIMP_LAYER_MODE_MONO_MIX,              /*< desc="Mono mix"                 >*/
+  GIMP_LAYER_MODE_MERGE,                 /*< desc="Merge"                    >*/
 
   /*  Internal modes, not available to the PDB, must be kept at the end  */
   GIMP_LAYER_MODE_REPLACE,               /*< pdb-skip, desc="Replace"        >*/
diff --git a/libgimp/gimpenums.h b/libgimp/gimpenums.h
index 8a4c105..3a3b8a4 100644
--- a/libgimp/gimpenums.h
+++ b/libgimp/gimpenums.h
@@ -154,7 +154,8 @@ typedef enum
   GIMP_LAYER_MODE_LUMINANCE,
   GIMP_LAYER_MODE_COLOR_ERASE,
   GIMP_LAYER_MODE_ERASE,
-  GIMP_LAYER_MODE_MONO_MIX
+  GIMP_LAYER_MODE_MONO_MIX,
+  GIMP_LAYER_MODE_MERGE
 } GimpLayerMode;
 
 
diff --git a/tools/pdbgen/enums.pl b/tools/pdbgen/enums.pl
index 93512e1..8bd16e2 100644
--- a/tools/pdbgen/enums.pl
+++ b/tools/pdbgen/enums.pl
@@ -748,7 +748,7 @@ package Gimp::CodeGen::enums;
                          GIMP_LAYER_MODE_LUMA_LIGHTEN_ONLY
                          GIMP_LAYER_MODE_LUMINANCE
                          GIMP_LAYER_MODE_COLOR_ERASE GIMP_LAYER_MODE_ERASE
-                         GIMP_LAYER_MODE_MONO_MIX) ],
+                         GIMP_LAYER_MODE_MONO_MIX GIMP_LAYER_MODE_MERGE) ],
          mapping => { GIMP_LAYER_MODE_NORMAL_LEGACY => '0',
                       GIMP_LAYER_MODE_DISSOLVE => '1',
                       GIMP_LAYER_MODE_BEHIND_LEGACY => '2',
@@ -808,7 +808,8 @@ package Gimp::CodeGen::enums;
                       GIMP_LAYER_MODE_LUMINANCE => '56',
                       GIMP_LAYER_MODE_COLOR_ERASE => '57',
                       GIMP_LAYER_MODE_ERASE => '58',
-                      GIMP_LAYER_MODE_MONO_MIX => '59' }
+                      GIMP_LAYER_MODE_MONO_MIX => '59',
+                      GIMP_LAYER_MODE_MERGE => '60' }
        },
     GimpConvertDitherType =>
        { contig => 1,


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