mirror of https://github.com/GNOME/gimp.git
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:
parent
23e6984d46
commit
ed0fda032d
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
},
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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__ */
|
|
@ -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 }
|
||||
|
|
|
@ -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" >*/
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue