app: add split layer mode

Subtracts the source layer from the destination, such that
recompositing the result with the source using merge mode
reproduces the original content.
This commit is contained in:
Ell 2017-03-10 18:28:40 -05:00
parent 23e6984d46
commit ed0fda032d
11 changed files with 303 additions and 4 deletions

View File

@ -2466,6 +2466,7 @@ gimp_image_get_xcf_version (GimpImage *image,
case GIMP_LAYER_MODE_ERASE:
case GIMP_LAYER_MODE_MONO_MIX:
case GIMP_LAYER_MODE_MERGE:
case GIMP_LAYER_MODE_SPLIT:
version = MAX (10, version);
break;

View File

@ -91,6 +91,7 @@
#include "layer-modes/gimpoperationmerge.h"
#include "layer-modes/gimpoperationnormal.h"
#include "layer-modes/gimpoperationreplace.h"
#include "layer-modes/gimpoperationsplit.h"
void
@ -149,6 +150,7 @@ gimp_operations_init (void)
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_SPLIT);
g_type_class_ref (GIMP_TYPE_OPERATION_REPLACE);
g_type_class_ref (GIMP_TYPE_OPERATION_ANTI_ERASE);

View File

@ -38,7 +38,9 @@ libapplayermodes_generic_a_sources = \
gimpoperationnormal.c \
gimpoperationnormal.h \
gimpoperationreplace.c \
gimpoperationreplace.h
gimpoperationreplace.h \
gimpoperationsplit.c \
gimpoperationsplit.h
libapplayermodes_sse2_a_sources = \
gimpoperationnormal-sse2.c

View File

@ -51,6 +51,7 @@
#include "gimpoperationmerge.h"
#include "gimpoperationnormal.h"
#include "gimpoperationreplace.h"
#include "gimpoperationsplit.h"
#include "gimp-layer-modes.h"
@ -848,6 +849,18 @@ static const GimpLayerModeInfo layer_mode_infos[] =
.composite_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR
},
{ GIMP_LAYER_MODE_SPLIT,
.op_name = "gimp:split",
.function = gimp_operation_split_process,
.flags = GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE |
GIMP_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE |
GIMP_LAYER_MODE_FLAG_SUBTRACTIVE,
.context = GIMP_LAYER_MODE_CONTEXT_ALL,
.paint_composite_mode = GIMP_LAYER_COMPOSITE_SRC_ATOP,
.composite_mode = GIMP_LAYER_COMPOSITE_SRC_ATOP
},
{ GIMP_LAYER_MODE_REPLACE,
.op_name = "gimp:replace",
@ -881,6 +894,7 @@ static const GimpLayerMode layer_mode_group_default[] =
GIMP_LAYER_MODE_ERASE,
GIMP_LAYER_MODE_ANTI_ERASE,
GIMP_LAYER_MODE_MERGE,
GIMP_LAYER_MODE_SPLIT,
GIMP_LAYER_MODE_SEPARATOR,
@ -1121,6 +1135,10 @@ static const GimpLayerMode layer_mode_groups[][2] =
[GIMP_LAYER_MODE_GROUP_LEGACY ] = -1
},
{ [GIMP_LAYER_MODE_GROUP_DEFAULT] = GIMP_LAYER_MODE_SPLIT,
[GIMP_LAYER_MODE_GROUP_LEGACY ] = -1
},
{ [GIMP_LAYER_MODE_GROUP_DEFAULT] = GIMP_LAYER_MODE_REPLACE,
[GIMP_LAYER_MODE_GROUP_LEGACY ] = -1
},

View File

@ -2344,6 +2344,7 @@ gimp_layer_mode_get_blend_fun (GimpLayerMode mode)
case GIMP_LAYER_MODE_GRAIN_MERGE_LEGACY:
case GIMP_LAYER_MODE_ERASE:
case GIMP_LAYER_MODE_MERGE:
case GIMP_LAYER_MODE_SPLIT:
case GIMP_LAYER_MODE_REPLACE:
case GIMP_LAYER_MODE_ANTI_ERASE:
case GIMP_LAYER_MODE_SEPARATOR: /* to stop GCC from complaining :P */

View File

@ -0,0 +1,206 @@
/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* gimpoperationsplit.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 "gimpoperationsplit.h"
G_DEFINE_TYPE (GimpOperationSplit, gimp_operation_split,
GIMP_TYPE_OPERATION_LAYER_MODE)
static void
gimp_operation_split_class_init (GimpOperationSplitClass *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:split",
"description", "GIMP split mode operation",
NULL);
point_class->process = gimp_operation_split_process;
}
static void
gimp_operation_split_init (GimpOperationSplit *self)
{
}
gboolean
gimp_operation_split_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:
while (samples--)
{
gfloat in_alpha = in[ALPHA];
gfloat layer_alpha = layer[ALPHA] * opacity;
gfloat new_alpha;
gint b;
if (has_mask)
layer_alpha *= *mask;
if (layer_alpha <= in_alpha)
{
new_alpha = in_alpha - layer_alpha;
for (b = RED; b < ALPHA; b++)
{
out[b] = in[b];
}
}
else
{
new_alpha = layer_alpha - in_alpha;
for (b = RED; b < ALPHA; b++)
{
out[b] = layer[b];
}
}
out[ALPHA] = new_alpha;
in += 4;
layer += 4;
out += 4;
if (has_mask)
mask++;
}
break;
case GIMP_LAYER_COMPOSITE_SRC_ATOP:
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;
new_alpha = MAX (in_alpha - layer_alpha, 0.0f);
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_DST_ATOP:
while (samples--)
{
gfloat in_alpha = in[ALPHA];
gfloat layer_alpha = layer[ALPHA] * opacity;
gfloat new_alpha;
gint b;
if (has_mask)
layer_alpha *= *mask;
new_alpha = MAX (layer_alpha - in_alpha, 0.0f);
if (new_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] = new_alpha;
in += 4;
layer += 4;
out += 4;
if (has_mask)
mask++;
}
break;
case GIMP_LAYER_COMPOSITE_SRC_IN:
while (samples--)
{
gint b;
for (b = RED; b < ALPHA; b++)
{
out[b] = in[b];
}
out[ALPHA] = 0.0f;
in += 4;
out += 4;
}
break;
}
return TRUE;
}

View File

@ -0,0 +1,63 @@
/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* gimpoperationsplit.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_SPLIT_H__
#define __GIMP_OPERATION_SPLIT_H__
#include "gimpoperationlayermode.h"
#define GIMP_TYPE_OPERATION_SPLIT (gimp_operation_split_get_type ())
#define GIMP_OPERATION_SPLIT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_OPERATION_SPLIT, GimpOperationSplit))
#define GIMP_OPERATION_SPLIT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_OPERATION_SPLIT, GimpOperationSplitClass))
#define GIMP_IS_OPERATION_SPLIT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_OPERATION_SPLIT))
#define GIMP_IS_OPERATION_SPLIT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_OPERATION_SPLIT))
#define GIMP_OPERATION_SPLIT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_OPERATION_SPLIT, GimpOperationSplitClass))
typedef struct _GimpOperationSplit GimpOperationSplit;
typedef struct _GimpOperationSplitClass GimpOperationSplitClass;
struct _GimpOperationSplit
{
GimpOperationLayerMode parent_instance;
};
struct _GimpOperationSplitClass
{
GimpOperationLayerModeClass parent_class;
};
GType gimp_operation_split_get_type (void) G_GNUC_CONST;
gboolean gimp_operation_split_process (GeglOperation *op,
void *in,
void *layer,
void *mask,
void *out,
glong samples,
const GeglRectangle *roi,
gint level);
#endif /* __GIMP_OPERATION_SPLIT_H__ */

View File

@ -142,6 +142,7 @@ gimp_layer_mode_get_type (void)
{ 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_SPLIT, "GIMP_LAYER_MODE_SPLIT", "split" },
{ GIMP_LAYER_MODE_REPLACE, "GIMP_LAYER_MODE_REPLACE", "replace" },
{ GIMP_LAYER_MODE_ANTI_ERASE, "GIMP_LAYER_MODE_ANTI_ERASE", "anti-erase" },
{ 0, NULL, NULL }
@ -210,6 +211,7 @@ gimp_layer_mode_get_type (void)
{ 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_SPLIT, NC_("layer-mode", "Split"), NULL },
{ GIMP_LAYER_MODE_REPLACE, NC_("layer-mode", "Replace"), NULL },
{ GIMP_LAYER_MODE_ANTI_ERASE, NC_("layer-mode", "Anti erase"), NULL },
{ 0, NULL, NULL }

View File

@ -120,6 +120,7 @@ typedef enum
GIMP_LAYER_MODE_ERASE, /*< desc="Erase" >*/
GIMP_LAYER_MODE_MONO_MIX, /*< desc="Mono mix" >*/
GIMP_LAYER_MODE_MERGE, /*< desc="Merge" >*/
GIMP_LAYER_MODE_SPLIT, /*< desc="Split" >*/
/* Internal modes, not available to the PDB, must be kept at the end */
GIMP_LAYER_MODE_REPLACE, /*< pdb-skip, desc="Replace" >*/

View File

@ -155,7 +155,8 @@ typedef enum
GIMP_LAYER_MODE_COLOR_ERASE,
GIMP_LAYER_MODE_ERASE,
GIMP_LAYER_MODE_MONO_MIX,
GIMP_LAYER_MODE_MERGE
GIMP_LAYER_MODE_MERGE,
GIMP_LAYER_MODE_SPLIT
} GimpLayerMode;

View File

@ -748,7 +748,8 @@ 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_MERGE) ],
GIMP_LAYER_MODE_MONO_MIX GIMP_LAYER_MODE_MERGE
GIMP_LAYER_MODE_SPLIT) ],
mapping => { GIMP_LAYER_MODE_NORMAL_LEGACY => '0',
GIMP_LAYER_MODE_DISSOLVE => '1',
GIMP_LAYER_MODE_BEHIND_LEGACY => '2',
@ -809,7 +810,8 @@ package Gimp::CodeGen::enums;
GIMP_LAYER_MODE_COLOR_ERASE => '57',
GIMP_LAYER_MODE_ERASE => '58',
GIMP_LAYER_MODE_MONO_MIX => '59',
GIMP_LAYER_MODE_MERGE => '60' }
GIMP_LAYER_MODE_MERGE => '60',
GIMP_LAYER_MODE_SPLIT => '61' }
},
GimpConvertDitherType =>
{ contig => 1,