Commit 23e6984d authored by Ell's avatar Ell

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.
parent 157d70e3
......@@ -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;
......
......@@ -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);
......
......@@ -33,6 +33,8 @@ libapplayermodes_generic_a_sources = \
gimpoperationdissolve.h \
gimpoperationerase.c \
gimpoperationerase.h \
gimpoperationmerge.c \
gimpoperationmerge.h \
gimpoperationnormal.c \
gimpoperationnormal.h \
gimpoperationreplace.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
},
......
......@@ -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 */
......
/* 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;
}
/* 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__ */
......@@ -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 }
......
......@@ -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" >*/
......
......@@ -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;
......
......@@ -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,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment