Initial checkin of Pika from heckimp
This commit is contained in:
29
app/operations/layer-modes-legacy/meson.build
Normal file
29
app/operations/layer-modes-legacy/meson.build
Normal file
@ -0,0 +1,29 @@
|
||||
libapplayermodeslegacy_sources = [
|
||||
'pikaoperationadditionlegacy.c',
|
||||
'pikaoperationburnlegacy.c',
|
||||
'pikaoperationdarkenonlylegacy.c',
|
||||
'pikaoperationdifferencelegacy.c',
|
||||
'pikaoperationdividelegacy.c',
|
||||
'pikaoperationdodgelegacy.c',
|
||||
'pikaoperationgrainextractlegacy.c',
|
||||
'pikaoperationgrainmergelegacy.c',
|
||||
'pikaoperationhardlightlegacy.c',
|
||||
'pikaoperationhslcolorlegacy.c',
|
||||
'pikaoperationhsvhuelegacy.c',
|
||||
'pikaoperationhsvsaturationlegacy.c',
|
||||
'pikaoperationhsvvaluelegacy.c',
|
||||
'pikaoperationlightenonlylegacy.c',
|
||||
'pikaoperationmultiplylegacy.c',
|
||||
'pikaoperationscreenlegacy.c',
|
||||
'pikaoperationsoftlightlegacy.c',
|
||||
'pikaoperationsubtractlegacy.c',
|
||||
]
|
||||
|
||||
libapplayermodeslegacy = static_library('applayermodeslegacy',
|
||||
libapplayermodeslegacy_sources,
|
||||
include_directories: [ rootInclude, rootAppInclude, ],
|
||||
c_args: '-DG_LOG_DOMAIN="Pika-Layer-Modes-Legacy"',
|
||||
dependencies: [
|
||||
cairo, gegl, gdk_pixbuf,
|
||||
],
|
||||
)
|
||||
130
app/operations/layer-modes-legacy/pikaoperationadditionlegacy.c
Normal file
130
app/operations/layer-modes-legacy/pikaoperationadditionlegacy.c
Normal file
@ -0,0 +1,130 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationadditionmode.c
|
||||
* Copyright (C) 2008 Michael Natterer <mitch@gimp.org>
|
||||
* 2012 Ville Sokk <ville.sokk@gmail.com>
|
||||
*
|
||||
* 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 <gegl-plugin.h>
|
||||
|
||||
#include "../operations-types.h"
|
||||
|
||||
#include "pikaoperationadditionlegacy.h"
|
||||
|
||||
|
||||
static gboolean pika_operation_addition_legacy_process (GeglOperation *op,
|
||||
void *in,
|
||||
void *layer,
|
||||
void *mask,
|
||||
void *out,
|
||||
glong samples,
|
||||
const GeglRectangle *roi,
|
||||
gint level);
|
||||
|
||||
|
||||
G_DEFINE_TYPE (PikaOperationAdditionLegacy, pika_operation_addition_legacy,
|
||||
PIKA_TYPE_OPERATION_LAYER_MODE)
|
||||
|
||||
|
||||
static void
|
||||
pika_operation_addition_legacy_class_init (PikaOperationAdditionLegacyClass *klass)
|
||||
{
|
||||
GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass);
|
||||
PikaOperationLayerModeClass *layer_mode_class = PIKA_OPERATION_LAYER_MODE_CLASS (klass);
|
||||
|
||||
gegl_operation_class_set_keys (operation_class,
|
||||
"name", "pika:addition-legacy",
|
||||
"description", "PIKA addition mode operation",
|
||||
NULL);
|
||||
|
||||
layer_mode_class->process = pika_operation_addition_legacy_process;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_operation_addition_legacy_init (PikaOperationAdditionLegacy *self)
|
||||
{
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_operation_addition_legacy_process (GeglOperation *op,
|
||||
void *in_p,
|
||||
void *layer_p,
|
||||
void *mask_p,
|
||||
void *out_p,
|
||||
glong samples,
|
||||
const GeglRectangle *roi,
|
||||
gint level)
|
||||
{
|
||||
PikaOperationLayerMode *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;
|
||||
|
||||
while (samples--)
|
||||
{
|
||||
gfloat comp_alpha, new_alpha;
|
||||
|
||||
comp_alpha = MIN (in[ALPHA], layer[ALPHA]) * opacity;
|
||||
if (has_mask)
|
||||
comp_alpha *= *mask;
|
||||
|
||||
new_alpha = in[ALPHA] + (1.0f - in[ALPHA]) * comp_alpha;
|
||||
|
||||
if (comp_alpha && new_alpha)
|
||||
{
|
||||
gfloat ratio = comp_alpha / new_alpha;
|
||||
gint b;
|
||||
|
||||
for (b = RED; b < ALPHA; b++)
|
||||
{
|
||||
gfloat comp = in[b] + layer[b];
|
||||
comp = CLAMP (comp, 0.0f, 1.0f);
|
||||
|
||||
out[b] = comp * ratio + in[b] * (1.0f - ratio);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
gint b;
|
||||
|
||||
for (b = RED; b < ALPHA; b++)
|
||||
{
|
||||
out[b] = in[b];
|
||||
}
|
||||
}
|
||||
|
||||
out[ALPHA] = in[ALPHA];
|
||||
|
||||
in += 4;
|
||||
layer += 4;
|
||||
out += 4;
|
||||
|
||||
if (has_mask)
|
||||
mask++;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@ -0,0 +1,57 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationadditionlegacy.h
|
||||
* Copyright (C) 2008 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* 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 __PIKA_OPERATION_ADDITION_LEGACY_H__
|
||||
#define __PIKA_OPERATION_ADDITION_LEGACY_H__
|
||||
|
||||
|
||||
#include "operations/layer-modes/pikaoperationlayermode.h"
|
||||
|
||||
|
||||
#define PIKA_TYPE_OPERATION_ADDITION_LEGACY (pika_operation_addition_legacy_get_type ())
|
||||
#define PIKA_OPERATION_ADDITION_LEGACY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_OPERATION_ADDITION_LEGACY, PikaOperationAdditionLegacy))
|
||||
#define PIKA_OPERATION_ADDITION_LEGACY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_OPERATION_ADDITION_LEGACY, PikaOperationAdditionLegacyClass))
|
||||
#define PIKA_IS_OPERATION_ADDITION_LEGACY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_OPERATION_ADDITION_LEGACY))
|
||||
#define PIKA_IS_OPERATION_ADDITION_LEGACY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_OPERATION_ADDITION_LEGACY))
|
||||
#define PIKA_OPERATION_ADDITION_LEGACY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_OPERATION_ADDITION_LEGACY, PikaOperationAdditionLegacyClass))
|
||||
|
||||
|
||||
typedef struct _PikaOperationAdditionLegacy PikaOperationAdditionLegacy;
|
||||
typedef struct _PikaOperationAdditionLegacyClass PikaOperationAdditionLegacyClass;
|
||||
|
||||
struct _PikaOperationAdditionLegacy
|
||||
{
|
||||
PikaOperationLayerMode parent_instance;
|
||||
};
|
||||
|
||||
struct _PikaOperationAdditionLegacyClass
|
||||
{
|
||||
PikaOperationLayerModeClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType pika_operation_addition_legacy_get_type (void) G_GNUC_CONST;
|
||||
|
||||
|
||||
#endif /* __PIKA_OPERATION_ADDITION_LEGACY_H__ */
|
||||
132
app/operations/layer-modes-legacy/pikaoperationburnlegacy.c
Normal file
132
app/operations/layer-modes-legacy/pikaoperationburnlegacy.c
Normal file
@ -0,0 +1,132 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationburnmode.c
|
||||
* Copyright (C) 2008 Michael Natterer <mitch@gimp.org>
|
||||
* 2012 Ville Sokk <ville.sokk@gmail.com>
|
||||
*
|
||||
* 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 <gegl-plugin.h>
|
||||
|
||||
#include "../operations-types.h"
|
||||
|
||||
#include "pikaoperationburnlegacy.h"
|
||||
|
||||
|
||||
static gboolean pika_operation_burn_legacy_process (GeglOperation *op,
|
||||
void *in,
|
||||
void *layer,
|
||||
void *mask,
|
||||
void *out,
|
||||
glong samples,
|
||||
const GeglRectangle *roi,
|
||||
gint level);
|
||||
|
||||
|
||||
G_DEFINE_TYPE (PikaOperationBurnLegacy, pika_operation_burn_legacy,
|
||||
PIKA_TYPE_OPERATION_LAYER_MODE)
|
||||
|
||||
|
||||
static void
|
||||
pika_operation_burn_legacy_class_init (PikaOperationBurnLegacyClass *klass)
|
||||
{
|
||||
GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass);
|
||||
PikaOperationLayerModeClass *layer_mode_class = PIKA_OPERATION_LAYER_MODE_CLASS (klass);
|
||||
|
||||
gegl_operation_class_set_keys (operation_class,
|
||||
"name", "pika:burn-legacy",
|
||||
"description", "PIKA burn mode operation",
|
||||
NULL);
|
||||
|
||||
layer_mode_class->process = pika_operation_burn_legacy_process;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_operation_burn_legacy_init (PikaOperationBurnLegacy *self)
|
||||
{
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_operation_burn_legacy_process (GeglOperation *op,
|
||||
void *in_p,
|
||||
void *layer_p,
|
||||
void *mask_p,
|
||||
void *out_p,
|
||||
glong samples,
|
||||
const GeglRectangle *roi,
|
||||
gint level)
|
||||
{
|
||||
PikaOperationLayerMode *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;
|
||||
|
||||
while (samples--)
|
||||
{
|
||||
gfloat comp_alpha, new_alpha;
|
||||
|
||||
comp_alpha = MIN (in[ALPHA], layer[ALPHA]) * opacity;
|
||||
if (mask)
|
||||
comp_alpha *= *mask;
|
||||
|
||||
new_alpha = in[ALPHA] + (1.0f - in[ALPHA]) * comp_alpha;
|
||||
|
||||
if (comp_alpha && new_alpha)
|
||||
{
|
||||
gfloat ratio = comp_alpha / new_alpha;
|
||||
gint b;
|
||||
|
||||
for (b = RED; b < ALPHA; b++)
|
||||
{
|
||||
gfloat comp = 1.0f - (1.0f - in[b]) / layer[b];
|
||||
/* The CLAMP macro is deliberately inlined and
|
||||
* written to map comp == NAN (0 / 0) -> 1
|
||||
*/
|
||||
comp = comp < 0.0f ? 0.0f : comp < 1.0f ? comp : 1.0f;
|
||||
|
||||
out[b] = comp * ratio + in[b] * (1.0f - ratio);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
gint b;
|
||||
|
||||
for (b = RED; b < ALPHA; b++)
|
||||
{
|
||||
out[b] = in[b];
|
||||
}
|
||||
}
|
||||
|
||||
out[ALPHA] = in[ALPHA];
|
||||
|
||||
in += 4;
|
||||
layer += 4;
|
||||
out += 4;
|
||||
|
||||
if (mask)
|
||||
mask++;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
57
app/operations/layer-modes-legacy/pikaoperationburnlegacy.h
Normal file
57
app/operations/layer-modes-legacy/pikaoperationburnlegacy.h
Normal file
@ -0,0 +1,57 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationburnlegacy.h
|
||||
* Copyright (C) 2008 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* 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 __PIKA_OPERATION_BURN_LEGACY_H__
|
||||
#define __PIKA_OPERATION_BURN_LEGACY_H__
|
||||
|
||||
|
||||
#include "operations/layer-modes/pikaoperationlayermode.h"
|
||||
|
||||
|
||||
#define PIKA_TYPE_OPERATION_BURN_LEGACY (pika_operation_burn_legacy_get_type ())
|
||||
#define PIKA_OPERATION_BURN_LEGACY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_OPERATION_BURN_LEGACY, PikaOperationBurnLegacy))
|
||||
#define PIKA_OPERATION_BURN_LEGACY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_OPERATION_BURN_LEGACY, PikaOperationBurnLegacyClass))
|
||||
#define PIKA_IS_OPERATION_BURN_LEGACY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_OPERATION_BURN_LEGACY))
|
||||
#define PIKA_IS_OPERATION_BURN_LEGACY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_OPERATION_BURN_LEGACY))
|
||||
#define PIKA_OPERATION_BURN_LEGACY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_OPERATION_BURN_LEGACY, PikaOperationBurnLegacyClass))
|
||||
|
||||
|
||||
typedef struct _PikaOperationBurnLegacy PikaOperationBurnLegacy;
|
||||
typedef struct _PikaOperationBurnLegacyClass PikaOperationBurnLegacyClass;
|
||||
|
||||
struct _PikaOperationBurnLegacy
|
||||
{
|
||||
PikaOperationLayerMode parent_instance;
|
||||
};
|
||||
|
||||
struct _PikaOperationBurnLegacyClass
|
||||
{
|
||||
PikaOperationLayerModeClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType pika_operation_burn_legacy_get_type (void) G_GNUC_CONST;
|
||||
|
||||
|
||||
#endif /* __PIKA_OPERATION_BURN_LEGACY_H__ */
|
||||
@ -0,0 +1,128 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationdarkenonlymode.c
|
||||
* Copyright (C) 2008 Michael Natterer <mitch@gimp.org>
|
||||
* 2012 Ville Sokk <ville.sokk@gmail.com>
|
||||
*
|
||||
* 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 <gegl-plugin.h>
|
||||
|
||||
#include "../operations-types.h"
|
||||
|
||||
#include "pikaoperationdarkenonlylegacy.h"
|
||||
|
||||
|
||||
static gboolean pika_operation_darken_only_legacy_process (GeglOperation *op,
|
||||
void *in,
|
||||
void *layer,
|
||||
void *mask,
|
||||
void *out,
|
||||
glong samples,
|
||||
const GeglRectangle *roi,
|
||||
gint level);
|
||||
|
||||
|
||||
G_DEFINE_TYPE (PikaOperationDarkenOnlyLegacy, pika_operation_darken_only_legacy,
|
||||
PIKA_TYPE_OPERATION_LAYER_MODE)
|
||||
|
||||
|
||||
static void
|
||||
pika_operation_darken_only_legacy_class_init (PikaOperationDarkenOnlyLegacyClass *klass)
|
||||
{
|
||||
GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass);
|
||||
PikaOperationLayerModeClass *layer_mode_class = PIKA_OPERATION_LAYER_MODE_CLASS (klass);
|
||||
|
||||
gegl_operation_class_set_keys (operation_class,
|
||||
"name", "pika:darken-only-legacy",
|
||||
"description", "PIKA darken only mode operation",
|
||||
NULL);
|
||||
|
||||
layer_mode_class->process = pika_operation_darken_only_legacy_process;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_operation_darken_only_legacy_init (PikaOperationDarkenOnlyLegacy *self)
|
||||
{
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_operation_darken_only_legacy_process (GeglOperation *op,
|
||||
void *in_p,
|
||||
void *layer_p,
|
||||
void *mask_p,
|
||||
void *out_p,
|
||||
glong samples,
|
||||
const GeglRectangle *roi,
|
||||
gint level)
|
||||
{
|
||||
PikaOperationLayerMode *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;
|
||||
|
||||
while (samples--)
|
||||
{
|
||||
gfloat comp_alpha, new_alpha;
|
||||
|
||||
comp_alpha = MIN (in[ALPHA], layer[ALPHA]) * opacity;
|
||||
if (mask)
|
||||
comp_alpha *= *mask;
|
||||
|
||||
new_alpha = in[ALPHA] + (1.0f - in[ALPHA]) * comp_alpha;
|
||||
|
||||
if (new_alpha && comp_alpha)
|
||||
{
|
||||
gint b;
|
||||
gfloat ratio = comp_alpha / new_alpha;
|
||||
|
||||
for (b = RED; b < ALPHA; b++)
|
||||
{
|
||||
gfloat comp = MIN (in[b], layer[b]);
|
||||
|
||||
out[b] = comp * ratio + in[b] * (1.0f - ratio);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
gint b;
|
||||
|
||||
for (b = RED; b < ALPHA; b++)
|
||||
{
|
||||
out[b] = in[b];
|
||||
}
|
||||
}
|
||||
|
||||
out[ALPHA] = in[ALPHA];
|
||||
|
||||
in += 4;
|
||||
layer += 4;
|
||||
out += 4;
|
||||
|
||||
if (mask)
|
||||
mask++;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@ -0,0 +1,57 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationdarkenonlylegacy.h
|
||||
* Copyright (C) 2008 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* 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 __PIKA_OPERATION_DARKEN_ONLY_LEGACY_H__
|
||||
#define __PIKA_OPERATION_DARKEN_ONLY_LEGACY_H__
|
||||
|
||||
|
||||
#include "operations/layer-modes/pikaoperationlayermode.h"
|
||||
|
||||
|
||||
#define PIKA_TYPE_OPERATION_DARKEN_ONLY_LEGACY (pika_operation_darken_only_legacy_get_type ())
|
||||
#define PIKA_OPERATION_DARKEN_ONLY_LEGACY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_OPERATION_DARKEN_ONLY_MODE, PikaOperationDarkenOnlyLegacy))
|
||||
#define PIKA_OPERATION_DARKEN_ONLY_LEGACY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_OPERATION_DARKEN_ONLY_MODE, PikaOperationDarkenOnlyLegacyClass))
|
||||
#define PIKA_IS_OPERATION_DARKEN_ONLY_LEGACY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_OPERATION_DARKEN_ONLY_MODE))
|
||||
#define PIKA_IS_OPERATION_DARKEN_ONLY_LEGACY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_OPERATION_DARKEN_ONLY_MODE))
|
||||
#define PIKA_OPERATION_DARKEN_ONLY_LEGACY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_OPERATION_DARKEN_ONLY_MODE, PikaOperationDarkenOnlyLegacyClass))
|
||||
|
||||
|
||||
typedef struct _PikaOperationDarkenOnlyLegacy PikaOperationDarkenOnlyLegacy;
|
||||
typedef struct _PikaOperationDarkenOnlyLegacyClass PikaOperationDarkenOnlyLegacyClass;
|
||||
|
||||
struct _PikaOperationDarkenOnlyLegacy
|
||||
{
|
||||
PikaOperationLayerMode parent_instance;
|
||||
};
|
||||
|
||||
struct _PikaOperationDarkenOnlyLegacyClass
|
||||
{
|
||||
PikaOperationLayerModeClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType pika_operation_darken_only_legacy_get_type (void) G_GNUC_CONST;
|
||||
|
||||
|
||||
#endif /* __PIKA_OPERATION_DARKEN_ONLY_LEGACY_H__ */
|
||||
@ -0,0 +1,130 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationdifferencemode.c
|
||||
* Copyright (C) 2008 Michael Natterer <mitch@gimp.org>
|
||||
* 2012 Ville Sokk <ville.sokk@gmail.com>
|
||||
*
|
||||
* 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 <gegl-plugin.h>
|
||||
|
||||
#include "../operations-types.h"
|
||||
|
||||
#include "pikaoperationdifferencelegacy.h"
|
||||
|
||||
|
||||
static gboolean pika_operation_difference_legacy_process (GeglOperation *op,
|
||||
void *in,
|
||||
void *layer,
|
||||
void *mask,
|
||||
void *out,
|
||||
glong samples,
|
||||
const GeglRectangle *roi,
|
||||
gint level);
|
||||
|
||||
|
||||
G_DEFINE_TYPE (PikaOperationDifferenceLegacy, pika_operation_difference_legacy,
|
||||
PIKA_TYPE_OPERATION_LAYER_MODE)
|
||||
|
||||
|
||||
static void
|
||||
pika_operation_difference_legacy_class_init (PikaOperationDifferenceLegacyClass *klass)
|
||||
{
|
||||
GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass);
|
||||
PikaOperationLayerModeClass *layer_mode_class = PIKA_OPERATION_LAYER_MODE_CLASS (klass);
|
||||
|
||||
gegl_operation_class_set_keys (operation_class,
|
||||
"name", "pika:difference-legacy",
|
||||
"description", "PIKA difference mode operation",
|
||||
NULL);
|
||||
|
||||
layer_mode_class->process = pika_operation_difference_legacy_process;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_operation_difference_legacy_init (PikaOperationDifferenceLegacy *self)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
static gboolean
|
||||
pika_operation_difference_legacy_process (GeglOperation *op,
|
||||
void *in_p,
|
||||
void *layer_p,
|
||||
void *mask_p,
|
||||
void *out_p,
|
||||
glong samples,
|
||||
const GeglRectangle *roi,
|
||||
gint level)
|
||||
{
|
||||
PikaOperationLayerMode *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;
|
||||
|
||||
while (samples--)
|
||||
{
|
||||
gfloat comp_alpha, new_alpha;
|
||||
|
||||
comp_alpha = MIN (in[ALPHA], layer[ALPHA]) * opacity;
|
||||
if (mask)
|
||||
comp_alpha *= *mask;
|
||||
|
||||
new_alpha = in[ALPHA] + (1.0f - in[ALPHA]) * comp_alpha;
|
||||
|
||||
if (comp_alpha && new_alpha)
|
||||
{
|
||||
gfloat ratio = comp_alpha / new_alpha;
|
||||
gint b;
|
||||
|
||||
for (b = RED; b < ALPHA; b++)
|
||||
{
|
||||
gfloat comp = in[b] - layer[b];
|
||||
comp = (comp < 0.0f) ? -comp : comp;
|
||||
|
||||
out[b] = comp * ratio + in[b] * (1.0f - ratio);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
gint b;
|
||||
|
||||
for (b = RED; b < ALPHA; b++)
|
||||
{
|
||||
out[b] = in[b];
|
||||
}
|
||||
}
|
||||
|
||||
out[ALPHA] = in[ALPHA];
|
||||
|
||||
in += 4;
|
||||
layer += 4;
|
||||
out += 4;
|
||||
|
||||
if (mask)
|
||||
mask++;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@ -0,0 +1,57 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationdifferencelegacy.h
|
||||
* Copyright (C) 2008 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* 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 __PIKA_OPERATION_DIFFERENCE_LEGACY_H__
|
||||
#define __PIKA_OPERATION_DIFFERENCE_LEGACY_H__
|
||||
|
||||
|
||||
#include "operations/layer-modes/pikaoperationlayermode.h"
|
||||
|
||||
|
||||
#define PIKA_TYPE_OPERATION_DIFFERENCE_LEGACY (pika_operation_difference_legacy_get_type ())
|
||||
#define PIKA_OPERATION_DIFFERENCE_LEGACY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_OPERATION_DIFFERENCE_LEGACY, PikaOperationDifferenceLegacy))
|
||||
#define PIKA_OPERATION_DIFFERENCE_LEGACY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_OPERATION_DIFFERENCE_LEGACY, PikaOperationDifferenceLegacyClass))
|
||||
#define PIKA_IS_OPERATION_DIFFERENCE_LEGACY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_OPERATION_DIFFERENCE_LEGACY))
|
||||
#define PIKA_IS_OPERATION_DIFFERENCE_LEGACY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_OPERATION_DIFFERENCE_LEGACY))
|
||||
#define PIKA_OPERATION_DIFFERENCE_LEGACY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_OPERATION_DIFFERENCE_LEGACY, PikaOperationDifferenceLegacyClass))
|
||||
|
||||
|
||||
typedef struct _PikaOperationDifferenceLegacy PikaOperationDifferenceLegacy;
|
||||
typedef struct _PikaOperationDifferenceLegacyClass PikaOperationDifferenceLegacyClass;
|
||||
|
||||
struct _PikaOperationDifferenceLegacy
|
||||
{
|
||||
PikaOperationLayerMode parent_instance;
|
||||
};
|
||||
|
||||
struct _PikaOperationDifferenceLegacyClass
|
||||
{
|
||||
PikaOperationLayerModeClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType pika_operation_difference_legacy_get_type (void) G_GNUC_CONST;
|
||||
|
||||
|
||||
#endif /* __PIKA_OPERATION_DIFFERENCE_LEGACY_H__ */
|
||||
131
app/operations/layer-modes-legacy/pikaoperationdividelegacy.c
Normal file
131
app/operations/layer-modes-legacy/pikaoperationdividelegacy.c
Normal file
@ -0,0 +1,131 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationdividemode.c
|
||||
* Copyright (C) 2008 Michael Natterer <mitch@gimp.org>
|
||||
* 2012 Ville Sokk <ville.sokk@gmail.com>
|
||||
*
|
||||
* 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 <gegl-plugin.h>
|
||||
|
||||
#include "libpikamath/pikamath.h"
|
||||
|
||||
#include "../operations-types.h"
|
||||
|
||||
#include "pikaoperationdividelegacy.h"
|
||||
|
||||
|
||||
static gboolean pika_operation_divide_legacy_process (GeglOperation *op,
|
||||
void *in,
|
||||
void *layer,
|
||||
void *mask,
|
||||
void *out,
|
||||
glong samples,
|
||||
const GeglRectangle *roi,
|
||||
gint level);
|
||||
|
||||
|
||||
G_DEFINE_TYPE (PikaOperationDivideLegacy, pika_operation_divide_legacy,
|
||||
PIKA_TYPE_OPERATION_LAYER_MODE)
|
||||
|
||||
|
||||
static void
|
||||
pika_operation_divide_legacy_class_init (PikaOperationDivideLegacyClass *klass)
|
||||
{
|
||||
GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass);
|
||||
PikaOperationLayerModeClass *layer_mode_class = PIKA_OPERATION_LAYER_MODE_CLASS (klass);
|
||||
|
||||
gegl_operation_class_set_keys (operation_class,
|
||||
"name", "pika:divide-legacy",
|
||||
"description", "PIKA divide mode operation",
|
||||
NULL);
|
||||
|
||||
layer_mode_class->process = pika_operation_divide_legacy_process;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_operation_divide_legacy_init (PikaOperationDivideLegacy *self)
|
||||
{
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_operation_divide_legacy_process (GeglOperation *op,
|
||||
void *in_p,
|
||||
void *layer_p,
|
||||
void *mask_p,
|
||||
void *out_p,
|
||||
glong samples,
|
||||
const GeglRectangle *roi,
|
||||
gint level)
|
||||
{
|
||||
PikaOperationLayerMode *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;
|
||||
|
||||
while (samples--)
|
||||
{
|
||||
gfloat comp_alpha, new_alpha;
|
||||
|
||||
comp_alpha = MIN (in[ALPHA], layer[ALPHA]) * opacity;
|
||||
if (mask)
|
||||
comp_alpha *= *mask;
|
||||
|
||||
new_alpha = in[ALPHA] + (1.0f - in[ALPHA]) * comp_alpha;
|
||||
|
||||
if (comp_alpha && new_alpha)
|
||||
{
|
||||
gint b;
|
||||
gfloat ratio = comp_alpha / new_alpha;
|
||||
|
||||
for (b = RED; b < ALPHA; b++)
|
||||
{
|
||||
gfloat comp = in[b] / layer[b];
|
||||
comp = SAFE_CLAMP (comp, 0.0f, 1.0f);
|
||||
|
||||
out[b] = comp * ratio + in[b] * (1.0f - ratio);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
gint b;
|
||||
|
||||
for (b = RED; b < ALPHA; b++)
|
||||
{
|
||||
out[b] = in[b];
|
||||
}
|
||||
}
|
||||
|
||||
out[ALPHA] = in[ALPHA];
|
||||
|
||||
in += 4;
|
||||
layer += 4;
|
||||
out += 4;
|
||||
|
||||
if (mask)
|
||||
mask++;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@ -0,0 +1,57 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationdividelegacy.h
|
||||
* Copyright (C) 2008 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* 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 __PIKA_OPERATION_DIVIDE_LEGACY_H__
|
||||
#define __PIKA_OPERATION_DIVIDE_LEGACY_H__
|
||||
|
||||
|
||||
#include "operations/layer-modes/pikaoperationlayermode.h"
|
||||
|
||||
|
||||
#define PIKA_TYPE_OPERATION_DIVIDE_LEGACY (pika_operation_divide_legacy_get_type ())
|
||||
#define PIKA_OPERATION_DIVIDE_LEGACY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_OPERATION_DIVIDE_LEGACY, PikaOperationDivideLegacy))
|
||||
#define PIKA_OPERATION_DIVIDE_LEGACY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_OPERATION_DIVIDE_LEGACY, PikaOperationDivideLegacyClass))
|
||||
#define PIKA_IS_OPERATION_DIVIDE_LEGACY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_OPERATION_DIVIDE_LEGACY))
|
||||
#define PIKA_IS_OPERATION_DIVIDE_LEGACY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_OPERATION_DIVIDE_LEGACY))
|
||||
#define PIKA_OPERATION_DIVIDE_LEGACY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_OPERATION_DIVIDE_LEGACY, PikaOperationDivideLegacyClass))
|
||||
|
||||
|
||||
typedef struct _PikaOperationDivideLegacy PikaOperationDivideLegacy;
|
||||
typedef struct _PikaOperationDivideLegacyClass PikaOperationDivideLegacyClass;
|
||||
|
||||
struct _PikaOperationDivideLegacy
|
||||
{
|
||||
PikaOperationLayerMode parent_instance;
|
||||
};
|
||||
|
||||
struct _PikaOperationDivideLegacyClass
|
||||
{
|
||||
PikaOperationLayerModeClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType pika_operation_divide_legacy_get_type (void) G_GNUC_CONST;
|
||||
|
||||
|
||||
#endif /* __PIKA_OPERATION_DIVIDE_LEGACY_H__ */
|
||||
131
app/operations/layer-modes-legacy/pikaoperationdodgelegacy.c
Normal file
131
app/operations/layer-modes-legacy/pikaoperationdodgelegacy.c
Normal file
@ -0,0 +1,131 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationdodgelegacy.c
|
||||
* Copyright (C) 2008 Michael Natterer <mitch@gimp.org>
|
||||
* 2012 Ville Sokk <ville.sokk@gmail.com>
|
||||
*
|
||||
* 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 <gegl-plugin.h>
|
||||
|
||||
#include "libpikamath/pikamath.h"
|
||||
|
||||
#include "../operations-types.h"
|
||||
|
||||
#include "pikaoperationdodgelegacy.h"
|
||||
|
||||
|
||||
static gboolean pika_operation_dodge_legacy_process (GeglOperation *op,
|
||||
void *in,
|
||||
void *layer,
|
||||
void *mask,
|
||||
void *out,
|
||||
glong samples,
|
||||
const GeglRectangle *roi,
|
||||
gint level);
|
||||
|
||||
|
||||
G_DEFINE_TYPE (PikaOperationDodgeLegacy, pika_operation_dodge_legacy,
|
||||
PIKA_TYPE_OPERATION_LAYER_MODE)
|
||||
|
||||
|
||||
static void
|
||||
pika_operation_dodge_legacy_class_init (PikaOperationDodgeLegacyClass *klass)
|
||||
{
|
||||
GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass);
|
||||
PikaOperationLayerModeClass *layer_mode_class = PIKA_OPERATION_LAYER_MODE_CLASS (klass);
|
||||
|
||||
gegl_operation_class_set_keys (operation_class,
|
||||
"name", "pika:dodge-legacy",
|
||||
"description", "PIKA dodge mode operation",
|
||||
NULL);
|
||||
|
||||
layer_mode_class->process = pika_operation_dodge_legacy_process;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_operation_dodge_legacy_init (PikaOperationDodgeLegacy *self)
|
||||
{
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_operation_dodge_legacy_process (GeglOperation *op,
|
||||
void *in_p,
|
||||
void *layer_p,
|
||||
void *mask_p,
|
||||
void *out_p,
|
||||
glong samples,
|
||||
const GeglRectangle *roi,
|
||||
gint level)
|
||||
{
|
||||
PikaOperationLayerMode *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;
|
||||
|
||||
while (samples--)
|
||||
{
|
||||
gfloat comp_alpha, new_alpha;
|
||||
|
||||
comp_alpha = MIN (in[ALPHA], layer[ALPHA]) * opacity;
|
||||
if (mask)
|
||||
comp_alpha *= *mask;
|
||||
|
||||
new_alpha = in[ALPHA] + (1.0f - in[ALPHA]) * comp_alpha;
|
||||
|
||||
if (comp_alpha && new_alpha)
|
||||
{
|
||||
gint b;
|
||||
gfloat ratio = comp_alpha / new_alpha;
|
||||
|
||||
for (b = RED; b < ALPHA; b++)
|
||||
{
|
||||
gfloat comp = in[b] / (1.0f - layer[b]);
|
||||
comp = SAFE_CLAMP (comp, 0.0f, 1.0f);
|
||||
|
||||
out[b] = comp * ratio + in[b] * (1.0f - ratio);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
gint b;
|
||||
|
||||
for (b = RED; b < ALPHA; b++)
|
||||
{
|
||||
out[b] = in[b];
|
||||
}
|
||||
}
|
||||
|
||||
out[ALPHA] = in[ALPHA];
|
||||
|
||||
in += 4;
|
||||
layer += 4;
|
||||
out += 4;
|
||||
|
||||
if (mask)
|
||||
mask++;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
57
app/operations/layer-modes-legacy/pikaoperationdodgelegacy.h
Normal file
57
app/operations/layer-modes-legacy/pikaoperationdodgelegacy.h
Normal file
@ -0,0 +1,57 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationdodgelegacy.h
|
||||
* Copyright (C) 2008 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* 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 __PIKA_OPERATION_DODGE_LEGACY_H__
|
||||
#define __PIKA_OPERATION_DODGE_LEGACY_H__
|
||||
|
||||
|
||||
#include "operations/layer-modes/pikaoperationlayermode.h"
|
||||
|
||||
|
||||
#define PIKA_TYPE_OPERATION_DODGE_LEGACY (pika_operation_dodge_legacy_get_type ())
|
||||
#define PIKA_OPERATION_DODGE_LEGACY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_OPERATION_DODGE_LEGACY, PikaOperationDodgeLegacy))
|
||||
#define PIKA_OPERATION_DODGE_LEGACY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_OPERATION_DODGE_LEGACY, PikaOperationDodgeLegacyClass))
|
||||
#define PIKA_IS_OPERATION_DODGE_LEGACY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_OPERATION_DODGE_LEGACY))
|
||||
#define PIKA_IS_OPERATION_DODGE_LEGACY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_OPERATION_DODGE_LEGACY))
|
||||
#define PIKA_OPERATION_DODGE_LEGACY_GET_CLASS(obj)(G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_OPERATION_DODGE_LEGACY, PikaOperationDodgeLegacyClass))
|
||||
|
||||
|
||||
typedef struct _PikaOperationDodgeLegacy PikaOperationDodgeLegacy;
|
||||
typedef struct _PikaOperationDodgeLegacyClass PikaOperationDodgeLegacyClass;
|
||||
|
||||
struct _PikaOperationDodgeLegacy
|
||||
{
|
||||
PikaOperationLayerMode parent_instance;
|
||||
};
|
||||
|
||||
struct _PikaOperationDodgeLegacyClass
|
||||
{
|
||||
PikaOperationLayerModeClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType pika_operation_dodge_legacy_get_type (void) G_GNUC_CONST;
|
||||
|
||||
|
||||
#endif /* __PIKA_OPERATION_DODGE_LEGACY_H__ */
|
||||
@ -0,0 +1,129 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationgrainextractmode.c
|
||||
* Copyright (C) 2008 Michael Natterer <mitch@gimp.org>
|
||||
* 2012 Ville Sokk <ville.sokk@gmail.com>
|
||||
*
|
||||
* 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 <gegl-plugin.h>
|
||||
|
||||
#include "../operations-types.h"
|
||||
|
||||
#include "pikaoperationgrainextractlegacy.h"
|
||||
|
||||
|
||||
static gboolean pika_operation_grain_extract_legacy_process (GeglOperation *op,
|
||||
void *in,
|
||||
void *layer,
|
||||
void *mask,
|
||||
void *out,
|
||||
glong samples,
|
||||
const GeglRectangle *roi,
|
||||
gint level);
|
||||
|
||||
|
||||
G_DEFINE_TYPE (PikaOperationGrainExtractLegacy, pika_operation_grain_extract_legacy,
|
||||
PIKA_TYPE_OPERATION_LAYER_MODE)
|
||||
|
||||
|
||||
static void
|
||||
pika_operation_grain_extract_legacy_class_init (PikaOperationGrainExtractLegacyClass *klass)
|
||||
{
|
||||
GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass);
|
||||
PikaOperationLayerModeClass *layer_mode_class = PIKA_OPERATION_LAYER_MODE_CLASS (klass);
|
||||
|
||||
gegl_operation_class_set_keys (operation_class,
|
||||
"name", "pika:grain-extract-legacy",
|
||||
"description", "PIKA grain extract mode operation",
|
||||
NULL);
|
||||
|
||||
layer_mode_class->process = pika_operation_grain_extract_legacy_process;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_operation_grain_extract_legacy_init (PikaOperationGrainExtractLegacy *self)
|
||||
{
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_operation_grain_extract_legacy_process (GeglOperation *op,
|
||||
void *in_p,
|
||||
void *layer_p,
|
||||
void *mask_p,
|
||||
void *out_p,
|
||||
glong samples,
|
||||
const GeglRectangle *roi,
|
||||
gint level)
|
||||
{
|
||||
PikaOperationLayerMode *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;
|
||||
|
||||
while (samples--)
|
||||
{
|
||||
gfloat comp_alpha, new_alpha;
|
||||
|
||||
comp_alpha = MIN (in[ALPHA], layer[ALPHA]) * opacity;
|
||||
if (mask)
|
||||
comp_alpha *= *mask;
|
||||
|
||||
new_alpha = in[ALPHA] + (1.0f - in[ALPHA]) * comp_alpha;
|
||||
|
||||
if (comp_alpha && new_alpha)
|
||||
{
|
||||
gfloat ratio = comp_alpha / new_alpha;
|
||||
gint b;
|
||||
|
||||
for (b = RED; b < ALPHA; b++)
|
||||
{
|
||||
gfloat comp = in[b] - layer[b] + 128.0f / 255.0f;
|
||||
comp = CLAMP (comp, 0.0f, 1.0f);
|
||||
|
||||
out[b] = comp * ratio + in[b] * (1.0f - ratio);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
gint b;
|
||||
|
||||
for (b = RED; b < ALPHA; b++)
|
||||
{
|
||||
out[b] = in[b];
|
||||
}
|
||||
}
|
||||
|
||||
out[ALPHA] = in[ALPHA];
|
||||
|
||||
in += 4;
|
||||
layer += 4;
|
||||
out += 4;
|
||||
|
||||
if (mask)
|
||||
mask++;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@ -0,0 +1,57 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationgrainextractlegacy.h
|
||||
* Copyright (C) 2008 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* 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 __PIKA_OPERATION_GRAIN_EXTRACT_LEGACY_H__
|
||||
#define __PIKA_OPERATION_GRAIN_EXTRACT_LEGACY_H__
|
||||
|
||||
|
||||
#include "operations/layer-modes/pikaoperationlayermode.h"
|
||||
|
||||
|
||||
#define PIKA_TYPE_OPERATION_GRAIN_EXTRACT_LEGACY (pika_operation_grain_extract_legacy_get_type ())
|
||||
#define PIKA_OPERATION_GRAIN_EXTRACT_LEGACY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_OPERATION_GRAIN_EXTRACT_LEGACY, PikaOperationGrainExtractLegacy))
|
||||
#define PIKA_OPERATION_GRAIN_EXTRACT_LEGACY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_OPERATION_GRAIN_EXTRACT_LEGACY, PikaOperationGrainExtractLegacyClass))
|
||||
#define PIKA_IS_OPERATION_GRAIN_EXTRACT_LEGACY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_OPERATION_GRAIN_EXTRACT_LEGACY))
|
||||
#define PIKA_IS_OPERATION_GRAIN_EXTRACT_LEGACY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_OPERATION_GRAIN_EXTRACT_LEGACY))
|
||||
#define PIKA_OPERATION_GRAIN_EXTRACT_LEGACY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_OPERATION_GRAIN_EXTRACT_LEGACY, PikaOperationGrainExtractLegacyClass))
|
||||
|
||||
|
||||
typedef struct _PikaOperationGrainExtractLegacy PikaOperationGrainExtractLegacy;
|
||||
typedef struct _PikaOperationGrainExtractLegacyClass PikaOperationGrainExtractLegacyClass;
|
||||
|
||||
struct _PikaOperationGrainExtractLegacy
|
||||
{
|
||||
PikaOperationLayerMode parent_instance;
|
||||
};
|
||||
|
||||
struct _PikaOperationGrainExtractLegacyClass
|
||||
{
|
||||
PikaOperationLayerModeClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType pika_operation_grain_extract_legacy_get_type (void) G_GNUC_CONST;
|
||||
|
||||
|
||||
#endif /* __PIKA_OPERATION_GRAIN_EXTRACT_LEGACY_H__ */
|
||||
@ -0,0 +1,129 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationgrainmergemode.c
|
||||
* Copyright (C) 2008 Michael Natterer <mitch@gimp.org>
|
||||
* 2012 Ville Sokk <ville.sokk@gmail.com>
|
||||
*
|
||||
* 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 <gegl-plugin.h>
|
||||
|
||||
#include "../operations-types.h"
|
||||
|
||||
#include "pikaoperationgrainmergelegacy.h"
|
||||
|
||||
|
||||
static gboolean pika_operation_grain_merge_legacy_process (GeglOperation *op,
|
||||
void *in,
|
||||
void *layer,
|
||||
void *mask,
|
||||
void *out,
|
||||
glong samples,
|
||||
const GeglRectangle *roi,
|
||||
gint level);
|
||||
|
||||
|
||||
G_DEFINE_TYPE (PikaOperationGrainMergeLegacy, pika_operation_grain_merge_legacy,
|
||||
PIKA_TYPE_OPERATION_LAYER_MODE)
|
||||
|
||||
|
||||
static void
|
||||
pika_operation_grain_merge_legacy_class_init (PikaOperationGrainMergeLegacyClass *klass)
|
||||
{
|
||||
GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass);
|
||||
PikaOperationLayerModeClass *layer_mode_class = PIKA_OPERATION_LAYER_MODE_CLASS (klass);
|
||||
|
||||
gegl_operation_class_set_keys (operation_class,
|
||||
"name", "pika:grain-merge-legacy",
|
||||
"description", "PIKA grain merge mode operation",
|
||||
NULL);
|
||||
|
||||
layer_mode_class->process = pika_operation_grain_merge_legacy_process;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_operation_grain_merge_legacy_init (PikaOperationGrainMergeLegacy *self)
|
||||
{
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_operation_grain_merge_legacy_process (GeglOperation *op,
|
||||
void *in_p,
|
||||
void *layer_p,
|
||||
void *mask_p,
|
||||
void *out_p,
|
||||
glong samples,
|
||||
const GeglRectangle *roi,
|
||||
gint level)
|
||||
{
|
||||
PikaOperationLayerMode *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;
|
||||
|
||||
while (samples--)
|
||||
{
|
||||
gfloat comp_alpha, new_alpha;
|
||||
|
||||
comp_alpha = MIN (in[ALPHA], layer[ALPHA]) * opacity;
|
||||
if (mask)
|
||||
comp_alpha *= *mask;
|
||||
|
||||
new_alpha = in[ALPHA] + (1.0f - in[ALPHA]) * comp_alpha;
|
||||
|
||||
if (comp_alpha && new_alpha)
|
||||
{
|
||||
gfloat ratio = comp_alpha / new_alpha;
|
||||
gint b;
|
||||
|
||||
for (b = RED; b < ALPHA; b++)
|
||||
{
|
||||
gfloat comp = in[b] + layer[b] - 128.0f / 255.0f;
|
||||
comp = CLAMP (comp, 0.0f, 1.0f);
|
||||
|
||||
out[b] = comp * ratio + in[b] * (1.0f - ratio);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
gint b;
|
||||
|
||||
for (b = RED; b < ALPHA; b++)
|
||||
{
|
||||
out[b] = in[b];
|
||||
}
|
||||
}
|
||||
|
||||
out[ALPHA] = in[ALPHA];
|
||||
|
||||
in += 4;
|
||||
layer += 4;
|
||||
out += 4;
|
||||
|
||||
if (mask)
|
||||
mask ++;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@ -0,0 +1,57 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationgrainmergelegacy.h
|
||||
* Copyright (C) 2008 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* 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 __PIKA_OPERATION_GRAIN_MERGE_LEGACY_H__
|
||||
#define __PIKA_OPERATION_GRAIN_MERGE_LEGACY_H__
|
||||
|
||||
|
||||
#include "operations/layer-modes/pikaoperationlayermode.h"
|
||||
|
||||
|
||||
#define PIKA_TYPE_OPERATION_GRAIN_MERGE_LEGACY (pika_operation_grain_merge_legacy_get_type ())
|
||||
#define PIKA_OPERATION_GRAIN_MERGE_LEGACY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_OPERATION_GRAIN_MERGE_LEGACY, PikaOperationGrainMergeLegacy))
|
||||
#define PIKA_OPERATION_GRAIN_MERGE_LEGACY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_OPERATION_GRAIN_MERGE_LEGACY, PikaOperationGrainMergeLegacyClass))
|
||||
#define PIKA_IS_OPERATION_GRAIN_MERGE_LEGACY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_OPERATION_GRAIN_MERGE_LEGACY))
|
||||
#define PIKA_IS_OPERATION_GRAIN_MERGE_LEGACY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_OPERATION_GRAIN_MERGE_LEGACY))
|
||||
#define PIKA_OPERATION_GRAIN_MERGE_LEGACY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_OPERATION_GRAIN_MERGE_LEGACY, PikaOperationGrainMergeLegacyClass))
|
||||
|
||||
|
||||
typedef struct _PikaOperationGrainMergeLegacy PikaOperationGrainMergeLegacy;
|
||||
typedef struct _PikaOperationGrainMergeLegacyClass PikaOperationGrainMergeLegacyClass;
|
||||
|
||||
struct _PikaOperationGrainMergeLegacy
|
||||
{
|
||||
PikaOperationLayerMode parent_instance;
|
||||
};
|
||||
|
||||
struct _PikaOperationGrainMergeLegacyClass
|
||||
{
|
||||
PikaOperationLayerModeClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType pika_operation_grain_merge_legacy_get_type (void) G_GNUC_CONST;
|
||||
|
||||
|
||||
#endif /* __PIKA_OPERATION_GRAIN_MERGE_LEGACY_H__ */
|
||||
139
app/operations/layer-modes-legacy/pikaoperationhardlightlegacy.c
Normal file
139
app/operations/layer-modes-legacy/pikaoperationhardlightlegacy.c
Normal file
@ -0,0 +1,139 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationhardlightmode.c
|
||||
* Copyright (C) 2008 Michael Natterer <mitch@gimp.org>
|
||||
* 2012 Ville Sokk <ville.sokk@gmail.com>
|
||||
*
|
||||
* 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 <gegl-plugin.h>
|
||||
|
||||
#include "../operations-types.h"
|
||||
|
||||
#include "pikaoperationhardlightlegacy.h"
|
||||
|
||||
|
||||
static gboolean pika_operation_hardlight_legacy_process (GeglOperation *op,
|
||||
void *in,
|
||||
void *layer,
|
||||
void *mask,
|
||||
void *out,
|
||||
glong samples,
|
||||
const GeglRectangle *roi,
|
||||
gint level);
|
||||
|
||||
|
||||
G_DEFINE_TYPE (PikaOperationHardlightLegacy, pika_operation_hardlight_legacy,
|
||||
PIKA_TYPE_OPERATION_LAYER_MODE)
|
||||
|
||||
|
||||
static void
|
||||
pika_operation_hardlight_legacy_class_init (PikaOperationHardlightLegacyClass *klass)
|
||||
{
|
||||
GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass);
|
||||
PikaOperationLayerModeClass *layer_mode_class = PIKA_OPERATION_LAYER_MODE_CLASS (klass);
|
||||
|
||||
gegl_operation_class_set_keys (operation_class,
|
||||
"name", "pika:hardlight-legacy",
|
||||
"description", "PIKA hardlight mode operation",
|
||||
NULL);
|
||||
|
||||
layer_mode_class->process = pika_operation_hardlight_legacy_process;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_operation_hardlight_legacy_init (PikaOperationHardlightLegacy *self)
|
||||
{
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_operation_hardlight_legacy_process (GeglOperation *op,
|
||||
void *in_p,
|
||||
void *layer_p,
|
||||
void *mask_p,
|
||||
void *out_p,
|
||||
glong samples,
|
||||
const GeglRectangle *roi,
|
||||
gint level)
|
||||
{
|
||||
PikaOperationLayerMode *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;
|
||||
|
||||
while (samples--)
|
||||
{
|
||||
gfloat comp_alpha, new_alpha;
|
||||
|
||||
comp_alpha = MIN (in[ALPHA], layer[ALPHA]) * opacity;
|
||||
if (mask)
|
||||
comp_alpha *= *mask;
|
||||
|
||||
new_alpha = in[ALPHA] + (1.0f - in[ALPHA]) * comp_alpha;
|
||||
|
||||
if (comp_alpha && new_alpha)
|
||||
{
|
||||
gfloat ratio = comp_alpha / new_alpha;
|
||||
gint b;
|
||||
|
||||
for (b = RED; b < ALPHA; b++)
|
||||
{
|
||||
gfloat comp;
|
||||
|
||||
if (layer[b] > 128.0f / 255.0f)
|
||||
{
|
||||
comp = (1.0 - in[b]) * (1.0 - (layer[b] - 128.0f / 255.0f) * 2.0f);
|
||||
comp = MIN (1.0f - comp, 1.0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
comp = in[b] * (layer[b] * 2.0f);
|
||||
comp = MIN (comp, 1.0f);
|
||||
}
|
||||
|
||||
out[b] = comp * ratio + in[b] * (1.0f - ratio);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
gint b;
|
||||
|
||||
for (b = RED; b < ALPHA; b++)
|
||||
{
|
||||
out[b] = in[b];
|
||||
}
|
||||
}
|
||||
|
||||
out[ALPHA] = in[ALPHA];
|
||||
|
||||
in += 4;
|
||||
layer += 4;
|
||||
out += 4;
|
||||
|
||||
if (mask)
|
||||
mask ++;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@ -0,0 +1,57 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationhardlightlegacy.h
|
||||
* Copyright (C) 2008 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* 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 __PIKA_OPERATION_HARDLIGHT_LEGACY_H__
|
||||
#define __PIKA_OPERATION_HARDLIGHT_LEGACY_H__
|
||||
|
||||
|
||||
#include "operations/layer-modes/pikaoperationlayermode.h"
|
||||
|
||||
|
||||
#define PIKA_TYPE_OPERATION_HARDLIGHT_LEGACY (pika_operation_hardlight_legacy_get_type ())
|
||||
#define PIKA_OPERATION_HARDLIGHT_LEGACY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_OPERATION_HARDLIGHT_LEGACY, PikaOperationHardlightLegacy))
|
||||
#define PIKA_OPERATION_HARDLIGHT_LEGACY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_OPERATION_HARDLIGHT_LEGACY, PikaOperationHardlightLegacyClass))
|
||||
#define PIKA_IS_OPERATION_HARDLIGHT_LEGACY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_OPERATION_HARDLIGHT_LEGACY))
|
||||
#define PIKA_IS_OPERATION_HARDLIGHT_LEGACY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_OPERATION_HARDLIGHT_LEGACY))
|
||||
#define PIKA_OPERATION_HARDLIGHT_LEGACY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_OPERATION_HARDLIGHT_LEGACY, PikaOperationHardlightLegacyClass))
|
||||
|
||||
|
||||
typedef struct _PikaOperationHardlightLegacy PikaOperationHardlightLegacy;
|
||||
typedef struct _PikaOperationHardlightLegacyClass PikaOperationHardlightLegacyClass;
|
||||
|
||||
struct _PikaOperationHardlightLegacy
|
||||
{
|
||||
PikaOperationLayerMode parent_instance;
|
||||
};
|
||||
|
||||
struct _PikaOperationHardlightLegacyClass
|
||||
{
|
||||
PikaOperationLayerModeClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType pika_operation_hardlight_legacy_get_type (void) G_GNUC_CONST;
|
||||
|
||||
|
||||
#endif /* __PIKA_OPERATION_HARDLIGHT_LEGACY_H__ */
|
||||
145
app/operations/layer-modes-legacy/pikaoperationhslcolorlegacy.c
Normal file
145
app/operations/layer-modes-legacy/pikaoperationhslcolorlegacy.c
Normal file
@ -0,0 +1,145 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationcolormode.c
|
||||
* Copyright (C) 2008 Michael Natterer <mitch@gimp.org>
|
||||
* 2012 Ville Sokk <ville.sokk@gmail.com>
|
||||
*
|
||||
* 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 <gegl-plugin.h>
|
||||
#include <cairo.h>
|
||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||
|
||||
#include "libpikacolor/pikacolor.h"
|
||||
|
||||
#include "../operations-types.h"
|
||||
|
||||
#include "pikaoperationhslcolorlegacy.h"
|
||||
|
||||
|
||||
static gboolean pika_operation_hsl_color_legacy_process (GeglOperation *op,
|
||||
void *in,
|
||||
void *layer,
|
||||
void *mask,
|
||||
void *out,
|
||||
glong samples,
|
||||
const GeglRectangle *roi,
|
||||
gint level);
|
||||
|
||||
|
||||
G_DEFINE_TYPE (PikaOperationHslColorLegacy, pika_operation_hsl_color_legacy,
|
||||
PIKA_TYPE_OPERATION_LAYER_MODE)
|
||||
|
||||
|
||||
static void
|
||||
pika_operation_hsl_color_legacy_class_init (PikaOperationHslColorLegacyClass *klass)
|
||||
{
|
||||
GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass);
|
||||
PikaOperationLayerModeClass *layer_mode_class = PIKA_OPERATION_LAYER_MODE_CLASS (klass);
|
||||
|
||||
gegl_operation_class_set_keys (operation_class,
|
||||
"name", "pika:hsl-color-legacy",
|
||||
"description", "PIKA color mode operation",
|
||||
NULL);
|
||||
|
||||
layer_mode_class->process = pika_operation_hsl_color_legacy_process;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_operation_hsl_color_legacy_init (PikaOperationHslColorLegacy *self)
|
||||
{
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_operation_hsl_color_legacy_process (GeglOperation *op,
|
||||
void *in_p,
|
||||
void *layer_p,
|
||||
void *mask_p,
|
||||
void *out_p,
|
||||
glong samples,
|
||||
const GeglRectangle *roi,
|
||||
gint level)
|
||||
{
|
||||
PikaOperationLayerMode *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;
|
||||
|
||||
while (samples--)
|
||||
{
|
||||
PikaHSL layer_hsl, out_hsl;
|
||||
PikaRGB layer_rgb = {layer[0], layer[1], layer[2]};
|
||||
PikaRGB out_rgb = {in[0], in[1], in[2]};
|
||||
gfloat comp_alpha, new_alpha;
|
||||
|
||||
comp_alpha = MIN (in[ALPHA], layer[ALPHA]) * opacity;
|
||||
if (mask)
|
||||
comp_alpha *= *mask;
|
||||
|
||||
new_alpha = in[ALPHA] + (1.0f - in[ALPHA]) * comp_alpha;
|
||||
|
||||
if (comp_alpha && new_alpha)
|
||||
{
|
||||
gint b;
|
||||
gfloat out_tmp[3];
|
||||
gfloat ratio = comp_alpha / new_alpha;
|
||||
|
||||
pika_rgb_to_hsl (&layer_rgb, &layer_hsl);
|
||||
pika_rgb_to_hsl (&out_rgb, &out_hsl);
|
||||
|
||||
out_hsl.h = layer_hsl.h;
|
||||
out_hsl.s = layer_hsl.s;
|
||||
pika_hsl_to_rgb (&out_hsl, &out_rgb);
|
||||
|
||||
out_tmp[0] = out_rgb.r;
|
||||
out_tmp[1] = out_rgb.g;
|
||||
out_tmp[2] = out_rgb.b;
|
||||
|
||||
for (b = RED; b < ALPHA; b++)
|
||||
{
|
||||
out[b] = out_tmp[b] * ratio + in[b] * (1.0f - ratio);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
gint b;
|
||||
|
||||
for (b = RED; b < ALPHA; b++)
|
||||
{
|
||||
out[b] = in[b];
|
||||
}
|
||||
}
|
||||
|
||||
out[ALPHA] = in[ALPHA];
|
||||
|
||||
in += 4;
|
||||
layer += 4;
|
||||
out += 4;
|
||||
|
||||
if (mask)
|
||||
mask++;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@ -0,0 +1,57 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationhslcolorlegacy.h
|
||||
* Copyright (C) 2008 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* 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 __PIKA_OPERATION_HSL_COLOR_LEGACY_H__
|
||||
#define __PIKA_OPERATION_HSL_COLOR_LEGACY_H__
|
||||
|
||||
|
||||
#include "operations/layer-modes/pikaoperationlayermode.h"
|
||||
|
||||
|
||||
#define PIKA_TYPE_OPERATION_HSL_COLOR_LEGACY (pika_operation_hsl_color_legacy_get_type ())
|
||||
#define PIKA_OPERATION_HSL_COLOR_LEGACY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_OPERATION_HSL_COLOR_LEGACY, PikaOperationHslColorLegacy))
|
||||
#define PIKA_OPERATION_HSL_COLOR_LEGACY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_OPERATION_HSL_COLOR_LEGACY, PikaOperationHslColorLegacyClass))
|
||||
#define PIKA_IS_OPERATION_HSL_COLOR_LEGACY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_OPERATION_HSL_COLOR_LEGACY))
|
||||
#define PIKA_IS_OPERATION_HSL_COLOR_LEGACY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_OPERATION_HSL_COLOR_LEGACY))
|
||||
#define PIKA_OPERATION_HSL_COLOR_LEGACY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_OPERATION_HSL_COLOR_LEGACY, PikaOperationHslColorLegacyClass))
|
||||
|
||||
|
||||
typedef struct _PikaOperationHslColorLegacy PikaOperationHslColorLegacy;
|
||||
typedef struct _PikaOperationHslColorLegacyClass PikaOperationHslColorLegacyClass;
|
||||
|
||||
struct _PikaOperationHslColorLegacy
|
||||
{
|
||||
PikaOperationLayerMode parent_instance;
|
||||
};
|
||||
|
||||
struct _PikaOperationHslColorLegacyClass
|
||||
{
|
||||
PikaOperationLayerModeClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType pika_operation_hsl_color_legacy_get_type (void) G_GNUC_CONST;
|
||||
|
||||
|
||||
#endif /* __PIKA_OPERATION_HSL_COLOR_LEGACY_H__ */
|
||||
150
app/operations/layer-modes-legacy/pikaoperationhsvhuelegacy.c
Normal file
150
app/operations/layer-modes-legacy/pikaoperationhsvhuelegacy.c
Normal file
@ -0,0 +1,150 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationhuemode.c
|
||||
* Copyright (C) 2008 Michael Natterer <mitch@gimp.org>
|
||||
* 2012 Ville Sokk <ville.sokk@gmail.com>
|
||||
*
|
||||
* 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 "libpikacolor/pikacolor.h"
|
||||
|
||||
#include "../operations-types.h"
|
||||
|
||||
#include "pikaoperationhsvhuelegacy.h"
|
||||
|
||||
|
||||
static gboolean pika_operation_hsv_hue_legacy_process (GeglOperation *op,
|
||||
void *in,
|
||||
void *layer,
|
||||
void *mask,
|
||||
void *out,
|
||||
glong samples,
|
||||
const GeglRectangle *roi,
|
||||
gint level);
|
||||
|
||||
|
||||
G_DEFINE_TYPE (PikaOperationHsvHueLegacy, pika_operation_hsv_hue_legacy,
|
||||
PIKA_TYPE_OPERATION_LAYER_MODE)
|
||||
|
||||
|
||||
static void
|
||||
pika_operation_hsv_hue_legacy_class_init (PikaOperationHsvHueLegacyClass *klass)
|
||||
{
|
||||
GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass);
|
||||
PikaOperationLayerModeClass *layer_mode_class = PIKA_OPERATION_LAYER_MODE_CLASS (klass);
|
||||
|
||||
gegl_operation_class_set_keys (operation_class,
|
||||
"name", "pika:hsv-hue-legacy",
|
||||
"description", "PIKA hue mode operation",
|
||||
NULL);
|
||||
|
||||
layer_mode_class->process = pika_operation_hsv_hue_legacy_process;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_operation_hsv_hue_legacy_init (PikaOperationHsvHueLegacy *self)
|
||||
{
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_operation_hsv_hue_legacy_process (GeglOperation *op,
|
||||
void *in_p,
|
||||
void *layer_p,
|
||||
void *mask_p,
|
||||
void *out_p,
|
||||
glong samples,
|
||||
const GeglRectangle *roi,
|
||||
gint level)
|
||||
{
|
||||
PikaOperationLayerMode *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;
|
||||
|
||||
while (samples--)
|
||||
{
|
||||
PikaHSV layer_hsv, out_hsv;
|
||||
PikaRGB layer_rgb = {layer[0], layer[1], layer[2]};
|
||||
PikaRGB out_rgb = {in[0], in[1], in[2]};
|
||||
gfloat comp_alpha, new_alpha;
|
||||
|
||||
comp_alpha = MIN (in[ALPHA], layer[ALPHA]) * opacity;
|
||||
if (mask)
|
||||
comp_alpha *= *mask;
|
||||
|
||||
new_alpha = in[ALPHA] + (1.0f - in[ALPHA]) * comp_alpha;
|
||||
|
||||
if (comp_alpha && new_alpha)
|
||||
{
|
||||
gint b;
|
||||
gfloat out_tmp[3];
|
||||
gfloat ratio = comp_alpha / new_alpha;
|
||||
|
||||
pika_rgb_to_hsv (&layer_rgb, &layer_hsv);
|
||||
pika_rgb_to_hsv (&out_rgb, &out_hsv);
|
||||
|
||||
/* Composition should have no effect if saturation is zero.
|
||||
* otherwise, black would be painted red (see bug #123296).
|
||||
*/
|
||||
if (layer_hsv.s)
|
||||
{
|
||||
out_hsv.h = layer_hsv.h;
|
||||
}
|
||||
pika_hsv_to_rgb (&out_hsv, &out_rgb);
|
||||
|
||||
out_tmp[0] = out_rgb.r;
|
||||
out_tmp[1] = out_rgb.g;
|
||||
out_tmp[2] = out_rgb.b;
|
||||
|
||||
for (b = RED; b < ALPHA; b++)
|
||||
{
|
||||
out[b] = out_tmp[b] * ratio + in[b] * (1.0f - ratio);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
gint b;
|
||||
|
||||
for (b = RED; b < ALPHA; b++)
|
||||
{
|
||||
out[b] = in[b];
|
||||
}
|
||||
}
|
||||
|
||||
out[ALPHA] = in[ALPHA];
|
||||
|
||||
in += 4;
|
||||
layer += 4;
|
||||
out += 4;
|
||||
|
||||
if (mask)
|
||||
mask++;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@ -0,0 +1,57 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationhsvhuelegacy.h
|
||||
* Copyright (C) 2008 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* 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 __PIKA_OPERATION_HSV_HUE_LEGACY_H__
|
||||
#define __PIKA_OPERATION_HSV_HUE_LEGACY_H__
|
||||
|
||||
|
||||
#include "operations/layer-modes/pikaoperationlayermode.h"
|
||||
|
||||
|
||||
#define PIKA_TYPE_OPERATION_HSV_HUE_LEGACY (pika_operation_hsv_hue_legacy_get_type ())
|
||||
#define PIKA_OPERATION_HSV_HUE_LEGACY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_OPERATION_HSV_HUE_LEGACY, PikaOperationHsvHueLegacy))
|
||||
#define PIKA_OPERATION_HSV_HUE_LEGACY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_OPERATION_HSV_HUE_LEGACY, PikaOperationHsvHueLegacyClass))
|
||||
#define PIKA_IS_OPERATION_HSV_HUE_LEGACY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_OPERATION_HSV_HUE_LEGACY))
|
||||
#define PIKA_IS_OPERATION_HSV_HUE_LEGACY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_OPERATION_HSV_HUE_LEGACY))
|
||||
#define PIKA_OPERATION_HSV_HUE_LEGACY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_OPERATION_HSV_HUE_LEGACY, PikaOperationHsvHueLegacyClass))
|
||||
|
||||
|
||||
typedef struct _PikaOperationHsvHueLegacy PikaOperationHsvHueLegacy;
|
||||
typedef struct _PikaOperationHsvHueLegacyClass PikaOperationHsvHueLegacyClass;
|
||||
|
||||
struct _PikaOperationHsvHueLegacy
|
||||
{
|
||||
PikaOperationLayerMode parent_instance;
|
||||
};
|
||||
|
||||
struct _PikaOperationHsvHueLegacyClass
|
||||
{
|
||||
PikaOperationLayerModeClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType pika_operation_hsv_hue_legacy_get_type (void) G_GNUC_CONST;
|
||||
|
||||
|
||||
#endif /* __PIKA_OPERATION_HSV_HUE_LEGACY_H__ */
|
||||
@ -0,0 +1,144 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationsaturationmode.c
|
||||
* Copyright (C) 2008 Michael Natterer <mitch@gimp.org>
|
||||
* 2012 Ville Sokk <ville.sokk@gmail.com>
|
||||
*
|
||||
* 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 <gegl-plugin.h>
|
||||
#include <cairo.h>
|
||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||
|
||||
#include "libpikacolor/pikacolor.h"
|
||||
|
||||
#include "../operations-types.h"
|
||||
|
||||
#include "pikaoperationhsvsaturationlegacy.h"
|
||||
|
||||
|
||||
static gboolean pika_operation_hsv_saturation_legacy_process (GeglOperation *op,
|
||||
void *in,
|
||||
void *layer,
|
||||
void *mask,
|
||||
void *out,
|
||||
glong samples,
|
||||
const GeglRectangle *roi,
|
||||
gint level);
|
||||
|
||||
|
||||
G_DEFINE_TYPE (PikaOperationHsvSaturationLegacy, pika_operation_hsv_saturation_legacy,
|
||||
PIKA_TYPE_OPERATION_LAYER_MODE)
|
||||
|
||||
|
||||
static void
|
||||
pika_operation_hsv_saturation_legacy_class_init (PikaOperationHsvSaturationLegacyClass *klass)
|
||||
{
|
||||
GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass);
|
||||
PikaOperationLayerModeClass *layer_mode_class = PIKA_OPERATION_LAYER_MODE_CLASS (klass);
|
||||
|
||||
gegl_operation_class_set_keys (operation_class,
|
||||
"name", "pika:hsv-saturation-legacy",
|
||||
"description", "PIKA saturation mode operation",
|
||||
NULL);
|
||||
|
||||
layer_mode_class->process = pika_operation_hsv_saturation_legacy_process;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_operation_hsv_saturation_legacy_init (PikaOperationHsvSaturationLegacy *self)
|
||||
{
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_operation_hsv_saturation_legacy_process (GeglOperation *op,
|
||||
void *in_p,
|
||||
void *layer_p,
|
||||
void *mask_p,
|
||||
void *out_p,
|
||||
glong samples,
|
||||
const GeglRectangle *roi,
|
||||
gint level)
|
||||
{
|
||||
PikaOperationLayerMode *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;
|
||||
|
||||
while (samples--)
|
||||
{
|
||||
PikaHSV layer_hsv, out_hsv;
|
||||
PikaRGB layer_rgb = {layer[0], layer[1], layer[2]};
|
||||
PikaRGB out_rgb = {in[0], in[1], in[2]};
|
||||
gfloat comp_alpha, new_alpha;
|
||||
|
||||
comp_alpha = MIN (in[ALPHA], layer[ALPHA]) * opacity;
|
||||
if (mask)
|
||||
comp_alpha *= *mask;
|
||||
|
||||
new_alpha = in[ALPHA] + (1.0f - in[ALPHA]) * comp_alpha;
|
||||
|
||||
if (comp_alpha && new_alpha)
|
||||
{
|
||||
gint b;
|
||||
gfloat out_tmp[3];
|
||||
gfloat ratio = comp_alpha / new_alpha;
|
||||
|
||||
pika_rgb_to_hsv (&layer_rgb, &layer_hsv);
|
||||
pika_rgb_to_hsv (&out_rgb, &out_hsv);
|
||||
|
||||
out_hsv.s = layer_hsv.s;
|
||||
pika_hsv_to_rgb (&out_hsv, &out_rgb);
|
||||
|
||||
out_tmp[0] = out_rgb.r;
|
||||
out_tmp[1] = out_rgb.g;
|
||||
out_tmp[2] = out_rgb.b;
|
||||
|
||||
for (b = RED; b < ALPHA; b++)
|
||||
{
|
||||
out[b] = out_tmp[b] * ratio + in[b] * (1.0f - ratio);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
gint b;
|
||||
|
||||
for (b = RED; b < ALPHA; b++)
|
||||
{
|
||||
out[b] = in[b];
|
||||
}
|
||||
}
|
||||
|
||||
out[ALPHA] = in[ALPHA];
|
||||
|
||||
in += 4;
|
||||
layer += 4;
|
||||
out += 4;
|
||||
|
||||
if (mask)
|
||||
mask++;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@ -0,0 +1,57 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationhsvsaturationlegacy.h
|
||||
* Copyright (C) 2008 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* 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 __PIKA_OPERATION_HSV_SATURATION_LEGACY_H__
|
||||
#define __PIKA_OPERATION_HSV_SATURATION_LEGACY_H__
|
||||
|
||||
|
||||
#include "operations/layer-modes/pikaoperationlayermode.h"
|
||||
|
||||
|
||||
#define PIKA_TYPE_OPERATION_HSV_SATURATION_LEGACY (pika_operation_hsv_saturation_legacy_get_type ())
|
||||
#define PIKA_OPERATION_HSV_SATURATION_LEGACY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_OPERATION_HSV_SATURATION_LEGACY, PikaOperationHsvSaturationLegacy))
|
||||
#define PIKA_OPERATION_HSV_SATURATION_LEGACY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_OPERATION_HSV_SATURATION_LEGACY, PikaOperationHsvSaturationLegacyClass))
|
||||
#define PIKA_IS_OPERATION_HSV_SATURATION_LEGACY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_OPERATION_HSV_SATURATION_LEGACY))
|
||||
#define PIKA_IS_OPERATION_HSV_SATURATION_LEGACY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_OPERATION_HSV_SATURATION_LEGACY))
|
||||
#define PIKA_OPERATION_HSV_SATURATION_LEGACY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_OPERATION_HSV_SATURATION_LEGACY, PikaOperationHsvSaturationLegacyClass))
|
||||
|
||||
|
||||
typedef struct _PikaOperationHsvSaturationLegacy PikaOperationHsvSaturationLegacy;
|
||||
typedef struct _PikaOperationHsvSaturationLegacyClass PikaOperationHsvSaturationLegacyClass;
|
||||
|
||||
struct _PikaOperationHsvSaturationLegacy
|
||||
{
|
||||
PikaOperationLayerMode parent_instance;
|
||||
};
|
||||
|
||||
struct _PikaOperationHsvSaturationLegacyClass
|
||||
{
|
||||
PikaOperationLayerModeClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType pika_operation_hsv_saturation_legacy_get_type (void) G_GNUC_CONST;
|
||||
|
||||
|
||||
#endif /* __PIKA_OPERATION_HSV_SATURATION_LEGACY_H__ */
|
||||
144
app/operations/layer-modes-legacy/pikaoperationhsvvaluelegacy.c
Normal file
144
app/operations/layer-modes-legacy/pikaoperationhsvvaluelegacy.c
Normal file
@ -0,0 +1,144 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationvaluemode.c
|
||||
* Copyright (C) 2008 Michael Natterer <mitch@gimp.org>
|
||||
* 2012 Ville Sokk <ville.sokk@gmail.com>
|
||||
*
|
||||
* 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 <gegl-plugin.h>
|
||||
#include <cairo.h>
|
||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||
|
||||
#include "libpikacolor/pikacolor.h"
|
||||
|
||||
#include "../operations-types.h"
|
||||
|
||||
#include "pikaoperationhsvvaluelegacy.h"
|
||||
|
||||
|
||||
static gboolean pika_operation_hsv_value_legacy_process (GeglOperation *op,
|
||||
void *in,
|
||||
void *layer,
|
||||
void *mask,
|
||||
void *out,
|
||||
glong samples,
|
||||
const GeglRectangle *roi,
|
||||
gint level);
|
||||
|
||||
|
||||
G_DEFINE_TYPE (PikaOperationHsvValueLegacy, pika_operation_hsv_value_legacy,
|
||||
PIKA_TYPE_OPERATION_LAYER_MODE)
|
||||
|
||||
|
||||
static void
|
||||
pika_operation_hsv_value_legacy_class_init (PikaOperationHsvValueLegacyClass *klass)
|
||||
{
|
||||
GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass);
|
||||
PikaOperationLayerModeClass *layer_mode_class = PIKA_OPERATION_LAYER_MODE_CLASS (klass);
|
||||
|
||||
gegl_operation_class_set_keys (operation_class,
|
||||
"name", "pika:hsv-value-legacy",
|
||||
"description", "PIKA value mode operation",
|
||||
NULL);
|
||||
|
||||
layer_mode_class->process = pika_operation_hsv_value_legacy_process;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_operation_hsv_value_legacy_init (PikaOperationHsvValueLegacy *self)
|
||||
{
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_operation_hsv_value_legacy_process (GeglOperation *op,
|
||||
void *in_p,
|
||||
void *layer_p,
|
||||
void *mask_p,
|
||||
void *out_p,
|
||||
glong samples,
|
||||
const GeglRectangle *roi,
|
||||
gint level)
|
||||
{
|
||||
PikaOperationLayerMode *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;
|
||||
|
||||
while (samples--)
|
||||
{
|
||||
PikaHSV layer_hsv, out_hsv;
|
||||
PikaRGB layer_rgb = {layer[0], layer[1], layer[2]};
|
||||
PikaRGB out_rgb = {in[0], in[1], in[2]};
|
||||
gfloat comp_alpha, new_alpha;
|
||||
|
||||
comp_alpha = MIN (in[ALPHA], layer[ALPHA]) * opacity;
|
||||
if (mask)
|
||||
comp_alpha *= *mask;
|
||||
|
||||
new_alpha = in[ALPHA] + (1.0f - in[ALPHA]) * comp_alpha;
|
||||
|
||||
if (comp_alpha && new_alpha)
|
||||
{
|
||||
gint b;
|
||||
gfloat out_tmp[3];
|
||||
gfloat ratio = comp_alpha / new_alpha;
|
||||
|
||||
pika_rgb_to_hsv (&layer_rgb, &layer_hsv);
|
||||
pika_rgb_to_hsv (&out_rgb, &out_hsv);
|
||||
|
||||
out_hsv.v = layer_hsv.v;
|
||||
pika_hsv_to_rgb (&out_hsv, &out_rgb);
|
||||
|
||||
out_tmp[0] = out_rgb.r;
|
||||
out_tmp[1] = out_rgb.g;
|
||||
out_tmp[2] = out_rgb.b;
|
||||
|
||||
for (b = RED; b < ALPHA; b++)
|
||||
{
|
||||
out[b] = out_tmp[b] * ratio + in[b] * (1.0f - ratio);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
gint b;
|
||||
|
||||
for (b = RED; b < ALPHA; b++)
|
||||
{
|
||||
out[b] = in[b];
|
||||
}
|
||||
}
|
||||
|
||||
out[ALPHA] = in[ALPHA];
|
||||
|
||||
in += 4;
|
||||
layer += 4;
|
||||
out += 4;
|
||||
|
||||
if (mask)
|
||||
mask++;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@ -0,0 +1,57 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationhsvvaluelegacy.h
|
||||
* Copyright (C) 2008 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* 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 __PIKA_OPERATION_HSV_VALUE_LEGACY_H__
|
||||
#define __PIKA_OPERATION_HSV_VALUE_LEGACY_H__
|
||||
|
||||
|
||||
#include "operations/layer-modes/pikaoperationlayermode.h"
|
||||
|
||||
|
||||
#define PIKA_TYPE_OPERATION_HSV_VALUE_LEGACY (pika_operation_hsv_value_legacy_get_type ())
|
||||
#define PIKA_OPERATION_HSV_VALUE_LEGACY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_OPERATION_HSV_VALUE_LEGACY, PikaOperationHsvValueLegacy))
|
||||
#define PIKA_OPERATION_HSV_VALUE_LEGACY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_OPERATION_HSV_VALUE_LEGACY, PikaOperationHsvValueLegacyClass))
|
||||
#define PIKA_IS_OPERATION_HSV_VALUE_LEGACY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_OPERATION_HSV_VALUE_LEGACY))
|
||||
#define PIKA_IS_OPERATION_HSV_VALUE_LEGACY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_OPERATION_HSV_VALUE_LEGACY))
|
||||
#define PIKA_OPERATION_HSV_VALUE_LEGACY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_OPERATION_HSV_VALUE_LEGACY, PikaOperationHsvValueLegacyClass))
|
||||
|
||||
|
||||
typedef struct _PikaOperationHsvValueLegacy PikaOperationHsvValueLegacy;
|
||||
typedef struct _PikaOperationHsvValueLegacyClass PikaOperationHsvValueLegacyClass;
|
||||
|
||||
struct _PikaOperationHsvValueLegacy
|
||||
{
|
||||
PikaOperationLayerMode parent_instance;
|
||||
};
|
||||
|
||||
struct _PikaOperationHsvValueLegacyClass
|
||||
{
|
||||
PikaOperationLayerModeClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType pika_operation_hsv_value_legacy_get_type (void) G_GNUC_CONST;
|
||||
|
||||
|
||||
#endif /* __PIKA_OPERATION_HSV_VALUE_LEGACY_H__ */
|
||||
@ -0,0 +1,128 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationlightenonlylegacy.c
|
||||
* Copyright (C) 2008 Michael Natterer <mitch@gimp.org>
|
||||
* 2012 Ville Sokk <ville.sokk@gmail.com>
|
||||
*
|
||||
* 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 <gegl-plugin.h>
|
||||
|
||||
#include "../operations-types.h"
|
||||
|
||||
#include "pikaoperationlightenonlylegacy.h"
|
||||
|
||||
|
||||
static gboolean pika_operation_lighten_only_legacy_process (GeglOperation *op,
|
||||
void *in,
|
||||
void *layer,
|
||||
void *mask,
|
||||
void *out,
|
||||
glong samples,
|
||||
const GeglRectangle *roi,
|
||||
gint level);
|
||||
|
||||
|
||||
G_DEFINE_TYPE (PikaOperationLightenOnlyLegacy, pika_operation_lighten_only_legacy,
|
||||
PIKA_TYPE_OPERATION_LAYER_MODE)
|
||||
|
||||
|
||||
static void
|
||||
pika_operation_lighten_only_legacy_class_init (PikaOperationLightenOnlyLegacyClass *klass)
|
||||
{
|
||||
GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass);
|
||||
PikaOperationLayerModeClass *layer_mode_class = PIKA_OPERATION_LAYER_MODE_CLASS (klass);
|
||||
|
||||
gegl_operation_class_set_keys (operation_class,
|
||||
"name", "pika:lighten-only-legacy",
|
||||
"description", "PIKA lighten only legacy operation",
|
||||
NULL);
|
||||
|
||||
layer_mode_class->process = pika_operation_lighten_only_legacy_process;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_operation_lighten_only_legacy_init (PikaOperationLightenOnlyLegacy *self)
|
||||
{
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_operation_lighten_only_legacy_process (GeglOperation *op,
|
||||
void *in_p,
|
||||
void *layer_p,
|
||||
void *mask_p,
|
||||
void *out_p,
|
||||
glong samples,
|
||||
const GeglRectangle *roi,
|
||||
gint level)
|
||||
{
|
||||
PikaOperationLayerMode *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;
|
||||
|
||||
while (samples--)
|
||||
{
|
||||
gfloat comp_alpha, new_alpha;
|
||||
|
||||
comp_alpha = MIN (in[ALPHA], layer[ALPHA]) * opacity;
|
||||
if (mask)
|
||||
comp_alpha *= *mask;
|
||||
|
||||
new_alpha = in[ALPHA] + (1.0f - in[ALPHA]) * comp_alpha;
|
||||
|
||||
if (comp_alpha && new_alpha)
|
||||
{
|
||||
gint b;
|
||||
gfloat ratio = comp_alpha / new_alpha;
|
||||
|
||||
for (b = RED; b < ALPHA; b++)
|
||||
{
|
||||
gfloat comp = MAX (layer[b], in[b]);
|
||||
|
||||
out[b] = comp * ratio + in[b] * (1.0f - ratio);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
gint b;
|
||||
|
||||
for (b = RED; b < ALPHA; b++)
|
||||
{
|
||||
out[b] = in[b];
|
||||
}
|
||||
}
|
||||
|
||||
out[ALPHA] = in[ALPHA];
|
||||
|
||||
in += 4;
|
||||
layer += 4;
|
||||
out += 4;
|
||||
|
||||
if (mask)
|
||||
mask++;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@ -0,0 +1,57 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationlightenonlylegacy.h
|
||||
* Copyright (C) 2008 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* 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 __PIKA_OPERATION_LIGHTEN_ONLY_LEGACY_H__
|
||||
#define __PIKA_OPERATION_LIGHTEN_ONLY_LEGACY_H__
|
||||
|
||||
|
||||
#include "operations/layer-modes/pikaoperationlayermode.h"
|
||||
|
||||
|
||||
#define PIKA_TYPE_OPERATION_LIGHTEN_ONLY_LEGACY (pika_operation_lighten_only_legacy_get_type ())
|
||||
#define PIKA_OPERATION_LIGHTEN_ONLY_LEGACY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_OPERATION_LIGHTEN_ONLY_LEGACY, PikaOperationLightenOnlyLegacy))
|
||||
#define PIKA_OPERATION_LIGHTEN_ONLY_LEGACY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_OPERATION_LIGHTEN_ONLY_LEGACY, PikaOperationLightenOnlyLegacyClass))
|
||||
#define PIKA_IS_OPERATION_LIGHTEN_ONLY_LEGACY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_OPERATION_LIGHTEN_ONLY_LEGACY))
|
||||
#define PIKA_IS_OPERATION_LIGHTEN_ONLY_LEGACY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_OPERATION_LIGHTEN_ONLY_LEGACY))
|
||||
#define PIKA_OPERATION_LIGHTEN_ONLY_LEGACY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_OPERATION_LIGHTEN_ONLY_LEGACY, PikaOperationLightenOnlyLegacyClass))
|
||||
|
||||
|
||||
typedef struct _PikaOperationLightenOnlyLegacy PikaOperationLightenOnlyLegacy;
|
||||
typedef struct _PikaOperationLightenOnlyLegacyClass PikaOperationLightenOnlyLegacyClass;
|
||||
|
||||
struct _PikaOperationLightenOnlyLegacy
|
||||
{
|
||||
PikaOperationLayerMode parent_instance;
|
||||
};
|
||||
|
||||
struct _PikaOperationLightenOnlyLegacyClass
|
||||
{
|
||||
PikaOperationLayerModeClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType pika_operation_lighten_only_legacy_get_type (void) G_GNUC_CONST;
|
||||
|
||||
|
||||
#endif /* __PIKA_OPERATION_LIGHTEN_ONLY_LEGACY_H__ */
|
||||
128
app/operations/layer-modes-legacy/pikaoperationmultiplylegacy.c
Normal file
128
app/operations/layer-modes-legacy/pikaoperationmultiplylegacy.c
Normal file
@ -0,0 +1,128 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationmultiplylegacy.c
|
||||
* Copyright (C) 2008 Michael Natterer <mitch@gimp.org>
|
||||
* 2012 Ville Sokk <ville.sokk@gmail.com>
|
||||
*
|
||||
* 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 <gegl-plugin.h>
|
||||
|
||||
#include "operations/operations-types.h"
|
||||
|
||||
#include "pikaoperationmultiplylegacy.h"
|
||||
|
||||
|
||||
static gboolean pika_operation_multiply_legacy_process (GeglOperation *op,
|
||||
void *in,
|
||||
void *layer,
|
||||
void *mask,
|
||||
void *out,
|
||||
glong samples,
|
||||
const GeglRectangle *roi,
|
||||
gint level);
|
||||
|
||||
|
||||
G_DEFINE_TYPE (PikaOperationMultiplyLegacy, pika_operation_multiply_legacy,
|
||||
PIKA_TYPE_OPERATION_LAYER_MODE)
|
||||
|
||||
|
||||
static void
|
||||
pika_operation_multiply_legacy_class_init (PikaOperationMultiplyLegacyClass *klass)
|
||||
{
|
||||
GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass);
|
||||
PikaOperationLayerModeClass *layer_mode_class = PIKA_OPERATION_LAYER_MODE_CLASS (klass);
|
||||
|
||||
gegl_operation_class_set_keys (operation_class,
|
||||
"name", "pika:multiply-legacy",
|
||||
"description", "PIKA multiply legacy operation",
|
||||
NULL);
|
||||
|
||||
layer_mode_class->process = pika_operation_multiply_legacy_process;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_operation_multiply_legacy_init (PikaOperationMultiplyLegacy *self)
|
||||
{
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_operation_multiply_legacy_process (GeglOperation *op,
|
||||
void *in_p,
|
||||
void *layer_p,
|
||||
void *mask_p,
|
||||
void *out_p,
|
||||
glong samples,
|
||||
const GeglRectangle *roi,
|
||||
gint level)
|
||||
{
|
||||
PikaOperationLayerMode *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;
|
||||
|
||||
while (samples--)
|
||||
{
|
||||
gfloat comp_alpha, new_alpha;
|
||||
|
||||
comp_alpha = MIN (in[ALPHA], layer[ALPHA]) * opacity;
|
||||
if (mask)
|
||||
comp_alpha *= *mask;
|
||||
|
||||
new_alpha = in[ALPHA] + (1.0f - in[ALPHA]) * comp_alpha;
|
||||
|
||||
if (comp_alpha && new_alpha)
|
||||
{
|
||||
gfloat ratio = comp_alpha / new_alpha;
|
||||
gint b;
|
||||
|
||||
for (b = RED; b < ALPHA; b++)
|
||||
{
|
||||
gfloat comp = layer[b] * in[b];
|
||||
|
||||
out[b] = comp * ratio + in[b] * (1.0f - ratio);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
gint b;
|
||||
|
||||
for (b = RED; b < ALPHA; b++)
|
||||
{
|
||||
out[b] = in[b];
|
||||
}
|
||||
}
|
||||
|
||||
out[ALPHA] = in[ALPHA];
|
||||
|
||||
in += 4;
|
||||
layer += 4;
|
||||
out += 4;
|
||||
|
||||
if (mask)
|
||||
mask++;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@ -0,0 +1,57 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationmultiplylegacy.h
|
||||
* Copyright (C) 2008 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* 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 __PIKA_OPERATION_MULTIPLY_LEGACY_H__
|
||||
#define __PIKA_OPERATION_MULTIPLY_LEGACY_H__
|
||||
|
||||
|
||||
#include "operations/layer-modes/pikaoperationlayermode.h"
|
||||
|
||||
|
||||
#define PIKA_TYPE_OPERATION_MULTIPLY_LEGACY (pika_operation_multiply_legacy_get_type ())
|
||||
#define PIKA_OPERATION_MULTIPLY_LEGACY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_OPERATION_MULTIPLY_LEGACY, PikaOperationMultiplyLegacy))
|
||||
#define PIKA_OPERATION_MULTIPLY_LEGACY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_OPERATION_MULTIPLY_LEGACY, PikaOperationMultiplyLegacyClass))
|
||||
#define PIKA_IS_OPERATION_MULTIPLY_LEGACY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_OPERATION_MULTIPLY_LEGACY))
|
||||
#define PIKA_IS_OPERATION_MULTIPLY_LEGACY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_OPERATION_MULTIPLY_LEGACY))
|
||||
#define PIKA_OPERATION_MULTIPLY_LEGACY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_OPERATION_MULTIPLY_LEGACY, PikaOperationMultiplyLegacyClass))
|
||||
|
||||
|
||||
typedef struct _PikaOperationMultiplyLegacy PikaOperationMultiplyLegacy;
|
||||
typedef struct _PikaOperationMultiplyLegacyClass PikaOperationMultiplyLegacyClass;
|
||||
|
||||
struct _PikaOperationMultiplyLegacy
|
||||
{
|
||||
PikaOperationLayerMode parent_instance;
|
||||
};
|
||||
|
||||
struct _PikaOperationMultiplyLegacyClass
|
||||
{
|
||||
PikaOperationLayerModeClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType pika_operation_multiply_legacy_get_type (void) G_GNUC_CONST;
|
||||
|
||||
|
||||
#endif /* __PIKA_OPERATION_MULTIPLY_LEGACY_H__ */
|
||||
128
app/operations/layer-modes-legacy/pikaoperationscreenlegacy.c
Normal file
128
app/operations/layer-modes-legacy/pikaoperationscreenlegacy.c
Normal file
@ -0,0 +1,128 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationscreenlegacy.c
|
||||
* Copyright (C) 2008 Michael Natterer <mitch@gimp.org>
|
||||
* 2012 Ville Sokk <ville.sokk@gmail.com>
|
||||
*
|
||||
* 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 <gegl-plugin.h>
|
||||
|
||||
#include "../operations-types.h"
|
||||
|
||||
#include "pikaoperationscreenlegacy.h"
|
||||
|
||||
|
||||
static gboolean pika_operation_screen_legacy_process (GeglOperation *op,
|
||||
void *in,
|
||||
void *layer,
|
||||
void *mask,
|
||||
void *out,
|
||||
glong samples,
|
||||
const GeglRectangle *roi,
|
||||
gint level);
|
||||
|
||||
|
||||
G_DEFINE_TYPE (PikaOperationScreenLegacy, pika_operation_screen_legacy,
|
||||
PIKA_TYPE_OPERATION_LAYER_MODE)
|
||||
|
||||
|
||||
static void
|
||||
pika_operation_screen_legacy_class_init (PikaOperationScreenLegacyClass *klass)
|
||||
{
|
||||
GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass);
|
||||
PikaOperationLayerModeClass *layer_mode_class = PIKA_OPERATION_LAYER_MODE_CLASS (klass);
|
||||
|
||||
gegl_operation_class_set_keys (operation_class,
|
||||
"name", "pika:screen-legacy",
|
||||
"description", "PIKA screen mode operation",
|
||||
NULL);
|
||||
|
||||
layer_mode_class->process = pika_operation_screen_legacy_process;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_operation_screen_legacy_init (PikaOperationScreenLegacy *self)
|
||||
{
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_operation_screen_legacy_process (GeglOperation *op,
|
||||
void *in_p,
|
||||
void *layer_p,
|
||||
void *mask_p,
|
||||
void *out_p,
|
||||
glong samples,
|
||||
const GeglRectangle *roi,
|
||||
gint level)
|
||||
{
|
||||
PikaOperationLayerMode *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;
|
||||
|
||||
while (samples--)
|
||||
{
|
||||
gfloat comp_alpha, new_alpha;
|
||||
|
||||
comp_alpha = MIN (in[ALPHA], layer[ALPHA]) * opacity;
|
||||
if (mask)
|
||||
comp_alpha *= *mask;
|
||||
|
||||
new_alpha = in[ALPHA] + (1.0f - in[ALPHA]) * comp_alpha;
|
||||
|
||||
if (comp_alpha && new_alpha)
|
||||
{
|
||||
gfloat ratio = comp_alpha / new_alpha;
|
||||
gint b;
|
||||
|
||||
for (b = RED; b < ALPHA; b++)
|
||||
{
|
||||
gfloat comp = 1.0f - (1.0f - in[b]) * (1.0f - layer[b]);
|
||||
|
||||
out[b] = comp * ratio + in[b] * (1.0f - ratio);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
gint b;
|
||||
|
||||
for (b = RED; b < ALPHA; b++)
|
||||
{
|
||||
out[b] = in[b];
|
||||
}
|
||||
}
|
||||
|
||||
out[ALPHA] = in[ALPHA];
|
||||
|
||||
in += 4;
|
||||
layer += 4;
|
||||
out += 4;
|
||||
|
||||
if (mask)
|
||||
mask++;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@ -0,0 +1,57 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationscreenlegacy.h
|
||||
* Copyright (C) 2008 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* 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 __PIKA_OPERATION_SCREEN_LEGACY_H__
|
||||
#define __PIKA_OPERATION_SCREEN_LEGACY_H__
|
||||
|
||||
|
||||
#include "operations/layer-modes/pikaoperationlayermode.h"
|
||||
|
||||
|
||||
#define PIKA_TYPE_OPERATION_SCREEN_LEGACY (pika_operation_screen_legacy_get_type ())
|
||||
#define PIKA_OPERATION_SCREEN_LEGACY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_OPERATION_SCREEN_LEGACY, PikaOperationScreenLegacy))
|
||||
#define PIKA_OPERATION_SCREEN_LEGACY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_OPERATION_SCREEN_LEGACY, PikaOperationScreenLegacyClass))
|
||||
#define PIKA_IS_OPERATION_SCREEN_LEGACY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_OPERATION_SCREEN_LEGACY))
|
||||
#define PIKA_IS_OPERATION_SCREEN_LEGACY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_OPERATION_SCREEN_LEGACY))
|
||||
#define PIKA_OPERATION_SCREEN_LEGACY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_OPERATION_SCREEN_LEGACY, PikaOperationScreenLegacyClass))
|
||||
|
||||
|
||||
typedef struct _PikaOperationScreenLegacy PikaOperationScreenLegacy;
|
||||
typedef struct _PikaOperationScreenLegacyClass PikaOperationScreenLegacyClass;
|
||||
|
||||
struct _PikaOperationScreenLegacy
|
||||
{
|
||||
PikaOperationLayerMode parent_instance;
|
||||
};
|
||||
|
||||
struct _PikaOperationScreenLegacyClass
|
||||
{
|
||||
PikaOperationLayerModeClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType pika_operation_screen_legacy_get_type (void) G_GNUC_CONST;
|
||||
|
||||
|
||||
#endif /* __PIKA_OPERATION_SCREEN_LEGACY_H__ */
|
||||
161
app/operations/layer-modes-legacy/pikaoperationsoftlightlegacy.c
Normal file
161
app/operations/layer-modes-legacy/pikaoperationsoftlightlegacy.c
Normal file
@ -0,0 +1,161 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationsoftlightmode.c
|
||||
* Copyright (C) 2008 Michael Natterer <mitch@gimp.org>
|
||||
* 2012 Ville Sokk <ville.sokk@gmail.com>
|
||||
*
|
||||
* 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 <gegl-plugin.h>
|
||||
|
||||
#include "../operations-types.h"
|
||||
|
||||
#include "pikaoperationsoftlightlegacy.h"
|
||||
|
||||
|
||||
static gboolean pika_operation_softlight_legacy_process (GeglOperation *op,
|
||||
void *in,
|
||||
void *layer,
|
||||
void *mask,
|
||||
void *out,
|
||||
glong samples,
|
||||
const GeglRectangle *roi,
|
||||
gint level);
|
||||
|
||||
|
||||
G_DEFINE_TYPE (PikaOperationSoftlightLegacy, pika_operation_softlight_legacy,
|
||||
PIKA_TYPE_OPERATION_LAYER_MODE)
|
||||
|
||||
|
||||
static const gchar* reference_xml = "<?xml version='1.0' encoding='UTF-8'?>"
|
||||
"<gegl>"
|
||||
"<node operation='pika:softlight-legacy'>"
|
||||
" <node operation='gegl:load'>"
|
||||
" <params>"
|
||||
" <param name='path'>B.png</param>"
|
||||
" </params>"
|
||||
" </node>"
|
||||
"</node>"
|
||||
"<node operation='gegl:load'>"
|
||||
" <params>"
|
||||
" <param name='path'>A.png</param>"
|
||||
" </params>"
|
||||
"</node>"
|
||||
"</gegl>";
|
||||
|
||||
|
||||
static void
|
||||
pika_operation_softlight_legacy_class_init (PikaOperationSoftlightLegacyClass *klass)
|
||||
{
|
||||
GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass);
|
||||
PikaOperationLayerModeClass *layer_mode_class = PIKA_OPERATION_LAYER_MODE_CLASS (klass);
|
||||
|
||||
gegl_operation_class_set_keys (operation_class,
|
||||
"name", "pika:softlight-legacy",
|
||||
"description", "PIKA softlight mode operation",
|
||||
"reference-image", "soft-light-mode.png",
|
||||
"reference-composition", reference_xml,
|
||||
NULL);
|
||||
|
||||
layer_mode_class->process = pika_operation_softlight_legacy_process;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_operation_softlight_legacy_init (PikaOperationSoftlightLegacy *self)
|
||||
{
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_operation_softlight_legacy_process (GeglOperation *op,
|
||||
void *in_p,
|
||||
void *layer_p,
|
||||
void *mask_p,
|
||||
void *out_p,
|
||||
glong samples,
|
||||
const GeglRectangle *roi,
|
||||
gint level)
|
||||
{
|
||||
PikaOperationLayerMode *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;
|
||||
|
||||
while (samples--)
|
||||
{
|
||||
gfloat comp_alpha, new_alpha;
|
||||
|
||||
comp_alpha = MIN (in[ALPHA], layer[ALPHA]) * opacity;
|
||||
if (mask)
|
||||
comp_alpha *= *mask;
|
||||
|
||||
new_alpha = in[ALPHA] + (1.0f - in[ALPHA]) * comp_alpha;
|
||||
|
||||
if (comp_alpha && new_alpha)
|
||||
{
|
||||
gfloat ratio = comp_alpha / new_alpha;
|
||||
gint b;
|
||||
|
||||
for (b = RED; b < ALPHA; b++)
|
||||
{
|
||||
#if 0
|
||||
/* softlight is now used for what PIKA formerly called
|
||||
* OVERLAY. We fixed OVERLAY to use the right math
|
||||
* (under the name NEW_OVERLAY), and redirect uses of
|
||||
* the old OVERLAY blend mode here. This math was
|
||||
* formerly used for OVERLAY and is exactly the same as
|
||||
* the multiply, screen, comp math used below.
|
||||
* See bug #673501.
|
||||
*/
|
||||
gfloat comp = in[b] * (in[b] + (2.0f * layer[b]) * (1.0f - in[b]));
|
||||
#endif
|
||||
|
||||
gfloat multiply = in[b] * layer[b];
|
||||
gfloat screen = 1.0f - (1.0f - in[b]) * (1.0f - layer[b]);
|
||||
gfloat comp = (1.0f - in[b]) * multiply + in[b] * screen;
|
||||
|
||||
out[b] = comp * ratio + in[b] * (1.0f - ratio);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
gint b;
|
||||
|
||||
for (b = RED; b < ALPHA; b++)
|
||||
{
|
||||
out[b] = in[b];
|
||||
}
|
||||
}
|
||||
|
||||
out[ALPHA] = in[ALPHA];
|
||||
|
||||
in += 4;
|
||||
layer += 4;
|
||||
out += 4;
|
||||
|
||||
if (mask)
|
||||
mask ++;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@ -0,0 +1,57 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationsoftlightlegacy.h
|
||||
* Copyright (C) 2008 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* 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 __PIKA_OPERATION_SOFTLIGHT_LEGACY_H__
|
||||
#define __PIKA_OPERATION_SOFTLIGHT_LEGACY_H__
|
||||
|
||||
|
||||
#include "operations/layer-modes/pikaoperationlayermode.h"
|
||||
|
||||
|
||||
#define PIKA_TYPE_OPERATION_SOFTLIGHT_LEGACY (pika_operation_softlight_legacy_get_type ())
|
||||
#define PIKA_OPERATION_SOFTLIGHT_LEGACY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_OPERATION_SOFTLIGHT_LEGACY, PikaOperationSoftlightLegacy))
|
||||
#define PIKA_OPERATION_SOFTLIGHT_LEGACY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_OPERATION_SOFTLIGHT_LEGACY, PikaOperationSoftlightLegacyClass))
|
||||
#define PIKA_IS_OPERATION_SOFTLIGHT_LEGACY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_OPERATION_SOFTLIGHT_LEGACY))
|
||||
#define PIKA_IS_OPERATION_SOFTLIGHT_LEGACY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_OPERATION_SOFTLIGHT_LEGACY))
|
||||
#define PIKA_OPERATION_SOFTLIGHT_LEGACY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_OPERATION_SOFTLIGHT_LEGACY, PikaOperationSoftlightLegacyClass))
|
||||
|
||||
|
||||
typedef struct _PikaOperationSoftlightLegacy PikaOperationSoftlightLegacy;
|
||||
typedef struct _PikaOperationSoftlightLegacyClass PikaOperationSoftlightLegacyClass;
|
||||
|
||||
struct _PikaOperationSoftlightLegacy
|
||||
{
|
||||
PikaOperationLayerMode parent_instance;
|
||||
};
|
||||
|
||||
struct _PikaOperationSoftlightLegacyClass
|
||||
{
|
||||
PikaOperationLayerModeClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType pika_operation_softlight_legacy_get_type (void) G_GNUC_CONST;
|
||||
|
||||
|
||||
#endif /* __PIKA_OPERATION_SOFTLIGHT_LEGACY_H__ */
|
||||
129
app/operations/layer-modes-legacy/pikaoperationsubtractlegacy.c
Normal file
129
app/operations/layer-modes-legacy/pikaoperationsubtractlegacy.c
Normal file
@ -0,0 +1,129 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationsubtractmode.c
|
||||
* Copyright (C) 2008 Michael Natterer <mitch@gimp.org>
|
||||
* 2012 Ville Sokk <ville.sokk@gmail.com>
|
||||
*
|
||||
* 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 <gegl-plugin.h>
|
||||
|
||||
#include "../operations-types.h"
|
||||
|
||||
#include "pikaoperationsubtractlegacy.h"
|
||||
|
||||
|
||||
static gboolean pika_operation_subtract_legacy_process (GeglOperation *op,
|
||||
void *in,
|
||||
void *layer,
|
||||
void *mask,
|
||||
void *out,
|
||||
glong samples,
|
||||
const GeglRectangle *roi,
|
||||
gint level);
|
||||
|
||||
|
||||
G_DEFINE_TYPE (PikaOperationSubtractLegacy, pika_operation_subtract_legacy,
|
||||
PIKA_TYPE_OPERATION_LAYER_MODE)
|
||||
|
||||
|
||||
static void
|
||||
pika_operation_subtract_legacy_class_init (PikaOperationSubtractLegacyClass *klass)
|
||||
{
|
||||
GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass);
|
||||
PikaOperationLayerModeClass *layer_mode_class = PIKA_OPERATION_LAYER_MODE_CLASS (klass);
|
||||
|
||||
gegl_operation_class_set_keys (operation_class,
|
||||
"name", "pika:subtract-legacy",
|
||||
"description", "PIKA subtract mode operation",
|
||||
NULL);
|
||||
|
||||
layer_mode_class->process = pika_operation_subtract_legacy_process;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_operation_subtract_legacy_init (PikaOperationSubtractLegacy *self)
|
||||
{
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_operation_subtract_legacy_process (GeglOperation *op,
|
||||
void *in_p,
|
||||
void *layer_p,
|
||||
void *mask_p,
|
||||
void *out_p,
|
||||
glong samples,
|
||||
const GeglRectangle *roi,
|
||||
gint level)
|
||||
{
|
||||
PikaOperationLayerMode *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;
|
||||
|
||||
while (samples--)
|
||||
{
|
||||
gfloat comp_alpha, new_alpha;
|
||||
|
||||
comp_alpha = MIN (in[ALPHA], layer[ALPHA]) * opacity;
|
||||
if (mask)
|
||||
comp_alpha *= *mask;
|
||||
|
||||
new_alpha = in[ALPHA] + (1.0f - in[ALPHA]) * comp_alpha;
|
||||
|
||||
if (comp_alpha && new_alpha)
|
||||
{
|
||||
gint b;
|
||||
gfloat ratio = comp_alpha / new_alpha;
|
||||
|
||||
for (b = RED; b < ALPHA; b++)
|
||||
{
|
||||
gfloat comp = in[b] - layer[b];
|
||||
comp = CLAMP (comp, 0.0f, 1.0f);
|
||||
|
||||
out[b] = comp * ratio + in[b] * (1.0f - ratio);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
gint b;
|
||||
|
||||
for (b = RED; b < ALPHA; b++)
|
||||
{
|
||||
out[b] = in[b];
|
||||
}
|
||||
}
|
||||
|
||||
out[ALPHA] = in[ALPHA];
|
||||
|
||||
in += 4;
|
||||
layer += 4;
|
||||
out += 4;
|
||||
|
||||
if (mask)
|
||||
mask++;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@ -0,0 +1,57 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationsubtractlegacy.h
|
||||
* Copyright (C) 2008 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* 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 __PIKA_OPERATION_SUBTRACT_LEGACY_H__
|
||||
#define __PIKA_OPERATION_SUBTRACT_LEGACY_H__
|
||||
|
||||
|
||||
#include "operations/layer-modes/pikaoperationlayermode.h"
|
||||
|
||||
|
||||
#define PIKA_TYPE_OPERATION_SUBTRACT_LEGACY (pika_operation_subtract_legacy_get_type ())
|
||||
#define PIKA_OPERATION_SUBTRACT_LEGACY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_OPERATION_SUBTRACT_LEGACY, PikaOperationSubtractLegacy))
|
||||
#define PIKA_OPERATION_SUBTRACT_LEGACY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_OPERATION_SUBTRACT_LEGACY, PikaOperationSubtractLegacyClass))
|
||||
#define PIKA_IS_OPERATION_SUBTRACT_LEGACY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_OPERATION_SUBTRACT_LEGACY))
|
||||
#define PIKA_IS_OPERATION_SUBTRACT_LEGACY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_OPERATION_SUBTRACT_LEGACY))
|
||||
#define PIKA_OPERATION_SUBTRACT_LEGACY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_OPERATION_SUBTRACT_LEGACY, PikaOperationSubtractLegacyClass))
|
||||
|
||||
|
||||
typedef struct _PikaOperationSubtractLegacy PikaOperationSubtractLegacy;
|
||||
typedef struct _PikaOperationSubtractLegacyClass PikaOperationSubtractLegacyClass;
|
||||
|
||||
struct _PikaOperationSubtractLegacy
|
||||
{
|
||||
PikaOperationLayerMode parent_instance;
|
||||
};
|
||||
|
||||
struct _PikaOperationSubtractLegacyClass
|
||||
{
|
||||
PikaOperationLayerModeClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType pika_operation_subtract_legacy_get_type (void) G_GNUC_CONST;
|
||||
|
||||
|
||||
#endif /* __PIKA_OPERATION_SUBTRACT_LEGACY_H__ */
|
||||
53
app/operations/layer-modes/meson.build
Normal file
53
app/operations/layer-modes/meson.build
Normal file
@ -0,0 +1,53 @@
|
||||
libapplayermodes_composite = simd.check('pikaoperationlayermode-composite-simd',
|
||||
sse2: 'pikaoperationlayermode-composite-sse2.c',
|
||||
compiler: cc,
|
||||
include_directories: [ rootInclude, rootAppInclude, ],
|
||||
dependencies: [
|
||||
cairo,
|
||||
gegl,
|
||||
gdk_pixbuf,
|
||||
],
|
||||
)
|
||||
|
||||
libapplayermodes_normal = simd.check('pikaoperationnormal-simd',
|
||||
sse2: 'pikaoperationnormal-sse2.c',
|
||||
sse41: 'pikaoperationnormal-sse4.c',
|
||||
compiler: cc,
|
||||
include_directories: [ rootInclude, rootAppInclude, ],
|
||||
dependencies: [
|
||||
cairo,
|
||||
gegl,
|
||||
gdk_pixbuf,
|
||||
],
|
||||
)
|
||||
|
||||
libapplayermodes_sources = files(
|
||||
'pika-layer-modes.c',
|
||||
'pikaoperationantierase.c',
|
||||
'pikaoperationbehind.c',
|
||||
'pikaoperationdissolve.c',
|
||||
'pikaoperationerase.c',
|
||||
'pikaoperationlayermode-blend.c',
|
||||
'pikaoperationlayermode-composite.c',
|
||||
'pikaoperationlayermode.c',
|
||||
'pikaoperationmerge.c',
|
||||
'pikaoperationnormal.c',
|
||||
'pikaoperationpassthrough.c',
|
||||
'pikaoperationreplace.c',
|
||||
'pikaoperationsplit.c',
|
||||
)
|
||||
|
||||
libapplayermodes = static_library('applayermodes',
|
||||
libapplayermodes_sources,
|
||||
link_with: [
|
||||
libapplayermodes_composite[0],
|
||||
libapplayermodes_normal[0],
|
||||
],
|
||||
include_directories: [ rootInclude, rootAppInclude, ],
|
||||
c_args: '-DG_LOG_DOMAIN="Pika-Layer-Modes"',
|
||||
dependencies: [
|
||||
cairo,
|
||||
gegl,
|
||||
gdk_pixbuf,
|
||||
],
|
||||
)
|
||||
1574
app/operations/layer-modes/pika-layer-modes.c
Normal file
1574
app/operations/layer-modes/pika-layer-modes.c
Normal file
File diff suppressed because it is too large
Load Diff
79
app/operations/layer-modes/pika-layer-modes.h
Normal file
79
app/operations/layer-modes/pika-layer-modes.h
Normal file
@ -0,0 +1,79 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pika-layer-modes.h
|
||||
* Copyright (C) 2017 Michael Natterer <mitch@gimp.org>
|
||||
* Øyvind Kolås <pippin@gimp.org>
|
||||
*
|
||||
* 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 __PIKA_LAYER_MODES_H__
|
||||
#define __PIKA_LAYER_MODES_H__
|
||||
|
||||
|
||||
void pika_layer_modes_init (void);
|
||||
void pika_layer_modes_exit (void);
|
||||
|
||||
gboolean pika_layer_mode_is_legacy (PikaLayerMode mode);
|
||||
|
||||
gboolean pika_layer_mode_is_blend_space_mutable (PikaLayerMode mode);
|
||||
gboolean pika_layer_mode_is_composite_space_mutable (PikaLayerMode mode);
|
||||
gboolean pika_layer_mode_is_composite_mode_mutable (PikaLayerMode mode);
|
||||
|
||||
gboolean pika_layer_mode_is_subtractive (PikaLayerMode mode);
|
||||
gboolean pika_layer_mode_is_alpha_only (PikaLayerMode mode);
|
||||
gboolean pika_layer_mode_is_trivial (PikaLayerMode mode);
|
||||
|
||||
PikaLayerColorSpace pika_layer_mode_get_blend_space (PikaLayerMode mode);
|
||||
PikaLayerColorSpace pika_layer_mode_get_composite_space (PikaLayerMode mode);
|
||||
PikaLayerCompositeMode pika_layer_mode_get_composite_mode (PikaLayerMode mode);
|
||||
PikaLayerCompositeMode pika_layer_mode_get_paint_composite_mode (PikaLayerMode mode);
|
||||
|
||||
const gchar * pika_layer_mode_get_operation_name (PikaLayerMode mode);
|
||||
GeglOperation * pika_layer_mode_get_operation (PikaLayerMode mode);
|
||||
|
||||
PikaLayerModeFunc pika_layer_mode_get_function (PikaLayerMode mode);
|
||||
PikaLayerModeBlendFunc pika_layer_mode_get_blend_function (PikaLayerMode mode);
|
||||
|
||||
PikaLayerModeContext pika_layer_mode_get_context (PikaLayerMode mode);
|
||||
|
||||
PikaLayerMode * pika_layer_mode_get_context_array (PikaLayerMode mode,
|
||||
PikaLayerModeContext context,
|
||||
gint *n_modes);
|
||||
|
||||
PikaLayerModeGroup pika_layer_mode_get_group (PikaLayerMode mode);
|
||||
|
||||
const PikaLayerMode * pika_layer_mode_get_group_array (PikaLayerModeGroup group,
|
||||
gint *n_modes);
|
||||
|
||||
gboolean pika_layer_mode_get_for_group (PikaLayerMode old_mode,
|
||||
PikaLayerModeGroup new_group,
|
||||
PikaLayerMode *new_mode);
|
||||
|
||||
const Babl * pika_layer_mode_get_format (PikaLayerMode mode,
|
||||
PikaLayerColorSpace blend_space,
|
||||
PikaLayerColorSpace composite_space,
|
||||
PikaLayerCompositeMode composite_mode,
|
||||
const Babl *preferred_format);
|
||||
|
||||
PikaLayerCompositeRegion pika_layer_mode_get_included_region (PikaLayerMode mode,
|
||||
PikaLayerCompositeMode composite_mode);
|
||||
|
||||
|
||||
#endif /* __PIKA_LAYER_MODES_H__ */
|
||||
192
app/operations/layer-modes/pikaoperationantierase.c
Normal file
192
app/operations/layer-modes/pikaoperationantierase.c
Normal file
@ -0,0 +1,192 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationantierase.c
|
||||
* Copyright (C) 2008 Michael Natterer <mitch@gimp.org>
|
||||
* 2012 Ville Sokk <ville.sokk@gmail.com>
|
||||
*
|
||||
* 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 <gegl-plugin.h>
|
||||
|
||||
#include "../operations-types.h"
|
||||
|
||||
#include "pikaoperationantierase.h"
|
||||
|
||||
|
||||
|
||||
static gboolean pika_operation_anti_erase_process (GeglOperation *op,
|
||||
void *in,
|
||||
void *layer,
|
||||
void *mask,
|
||||
void *out,
|
||||
glong samples,
|
||||
const GeglRectangle *roi,
|
||||
gint level);
|
||||
static PikaLayerCompositeRegion pika_operation_anti_erase_get_affected_region (PikaOperationLayerMode *layer_mode);
|
||||
|
||||
|
||||
G_DEFINE_TYPE (PikaOperationAntiErase, pika_operation_anti_erase,
|
||||
PIKA_TYPE_OPERATION_LAYER_MODE)
|
||||
|
||||
|
||||
static void
|
||||
pika_operation_anti_erase_class_init (PikaOperationAntiEraseClass *klass)
|
||||
{
|
||||
GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass);
|
||||
PikaOperationLayerModeClass *layer_mode_class = PIKA_OPERATION_LAYER_MODE_CLASS (klass);
|
||||
|
||||
gegl_operation_class_set_keys (operation_class,
|
||||
"name", "pika:anti-erase",
|
||||
"description", "PIKA anti erase mode operation",
|
||||
NULL);
|
||||
|
||||
layer_mode_class->process = pika_operation_anti_erase_process;
|
||||
layer_mode_class->get_affected_region = pika_operation_anti_erase_get_affected_region;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_operation_anti_erase_init (PikaOperationAntiErase *self)
|
||||
{
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_operation_anti_erase_process (GeglOperation *op,
|
||||
void *in_p,
|
||||
void *layer_p,
|
||||
void *mask_p,
|
||||
void *out_p,
|
||||
glong samples,
|
||||
const GeglRectangle *roi,
|
||||
gint level)
|
||||
{
|
||||
PikaOperationLayerMode *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 PIKA_LAYER_COMPOSITE_UNION:
|
||||
case PIKA_LAYER_COMPOSITE_AUTO:
|
||||
while (samples--)
|
||||
{
|
||||
gfloat value = opacity;
|
||||
gint b;
|
||||
|
||||
if (has_mask)
|
||||
value *= *mask;
|
||||
|
||||
out[ALPHA] = in[ALPHA] + (1.0 - in[ALPHA]) * layer[ALPHA] * value;
|
||||
|
||||
for (b = RED; b < ALPHA; b++)
|
||||
{
|
||||
out[b] = in[b];
|
||||
}
|
||||
|
||||
in += 4;
|
||||
layer += 4;
|
||||
out += 4;
|
||||
|
||||
if (has_mask)
|
||||
mask++;
|
||||
}
|
||||
break;
|
||||
|
||||
case PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP:
|
||||
while (samples--)
|
||||
{
|
||||
gint b;
|
||||
|
||||
out[ALPHA] = in[ALPHA];
|
||||
|
||||
for (b = RED; b < ALPHA; b++)
|
||||
{
|
||||
out[b] = in[b];
|
||||
}
|
||||
|
||||
in += 4;
|
||||
out += 4;
|
||||
}
|
||||
break;
|
||||
|
||||
case PIKA_LAYER_COMPOSITE_CLIP_TO_LAYER:
|
||||
while (samples--)
|
||||
{
|
||||
gfloat value = opacity;
|
||||
gint b;
|
||||
|
||||
if (has_mask)
|
||||
value *= *mask;
|
||||
|
||||
out[ALPHA] = layer[ALPHA] * value;
|
||||
|
||||
for (b = RED; b < ALPHA; b++)
|
||||
{
|
||||
out[b] = in[b];
|
||||
}
|
||||
|
||||
in += 4;
|
||||
layer += 4;
|
||||
out += 4;
|
||||
|
||||
if (has_mask)
|
||||
mask++;
|
||||
}
|
||||
break;
|
||||
|
||||
case PIKA_LAYER_COMPOSITE_INTERSECTION:
|
||||
while (samples--)
|
||||
{
|
||||
gfloat value = opacity;
|
||||
gint b;
|
||||
|
||||
if (has_mask)
|
||||
value *= *mask;
|
||||
|
||||
out[ALPHA] = in[ALPHA] * layer[ALPHA] * value;
|
||||
|
||||
for (b = RED; b < ALPHA; b++)
|
||||
{
|
||||
out[b] = in[b];
|
||||
}
|
||||
|
||||
in += 4;
|
||||
layer += 4;
|
||||
out += 4;
|
||||
|
||||
if (has_mask)
|
||||
mask++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static PikaLayerCompositeRegion
|
||||
pika_operation_anti_erase_get_affected_region (PikaOperationLayerMode *layer_mode)
|
||||
{
|
||||
return PIKA_LAYER_COMPOSITE_REGION_SOURCE;
|
||||
}
|
||||
57
app/operations/layer-modes/pikaoperationantierase.h
Normal file
57
app/operations/layer-modes/pikaoperationantierase.h
Normal file
@ -0,0 +1,57 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationantierase.h
|
||||
* Copyright (C) 2008 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* 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 __PIKA_OPERATION_ANTI_ERASE_H__
|
||||
#define __PIKA_OPERATION_ANTI_ERASE_H__
|
||||
|
||||
|
||||
#include "pikaoperationlayermode.h"
|
||||
|
||||
|
||||
#define PIKA_TYPE_OPERATION_ANTI_ERASE (pika_operation_anti_erase_get_type ())
|
||||
#define PIKA_OPERATION_ANTI_ERASE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_OPERATION_ANTI_ERASE, PikaOperationAntiErase))
|
||||
#define PIKA_OPERATION_ANTI_ERASE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_OPERATION_ANTI_ERASE, PikaOperationAntiEraseClass))
|
||||
#define PIKA_IS_OPERATION_ANTI_ERASE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_OPERATION_ANTI_ERASE))
|
||||
#define PIKA_IS_OPERATION_ANTI_ERASE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_OPERATION_ANTI_ERASE))
|
||||
#define PIKA_OPERATION_ANTI_ERASE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_OPERATION_ANTI_ERASE, PikaOperationAntiEraseClass))
|
||||
|
||||
|
||||
typedef struct _PikaOperationAntiErase PikaOperationAntiErase;
|
||||
typedef struct _PikaOperationAntiEraseClass PikaOperationAntiEraseClass;
|
||||
|
||||
struct _PikaOperationAntiErase
|
||||
{
|
||||
PikaOperationLayerMode parent_instance;
|
||||
};
|
||||
|
||||
struct _PikaOperationAntiEraseClass
|
||||
{
|
||||
PikaOperationLayerModeClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType pika_operation_anti_erase_get_type (void) G_GNUC_CONST;
|
||||
|
||||
|
||||
#endif /* __PIKA_OPERATION_ANTI_ERASE_H__ */
|
||||
240
app/operations/layer-modes/pikaoperationbehind.c
Normal file
240
app/operations/layer-modes/pikaoperationbehind.c
Normal file
@ -0,0 +1,240 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationbehind.c
|
||||
* Copyright (C) 2008 Michael Natterer <mitch@gimp.org>
|
||||
* 2012 Ville Sokk <ville.sokk@gmail.com>
|
||||
*
|
||||
* 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 <gegl-plugin.h>
|
||||
|
||||
#include "../operations-types.h"
|
||||
|
||||
#include "pikaoperationbehind.h"
|
||||
|
||||
|
||||
|
||||
static gboolean pika_operation_behind_process (GeglOperation *op,
|
||||
void *in,
|
||||
void *layer,
|
||||
void *mask,
|
||||
void *out,
|
||||
glong samples,
|
||||
const GeglRectangle *roi,
|
||||
gint level);
|
||||
|
||||
|
||||
G_DEFINE_TYPE (PikaOperationBehind, pika_operation_behind,
|
||||
PIKA_TYPE_OPERATION_LAYER_MODE)
|
||||
|
||||
|
||||
static void
|
||||
pika_operation_behind_class_init (PikaOperationBehindClass *klass)
|
||||
{
|
||||
GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass);
|
||||
PikaOperationLayerModeClass *layer_mode_class = PIKA_OPERATION_LAYER_MODE_CLASS (klass);
|
||||
|
||||
gegl_operation_class_set_keys (operation_class,
|
||||
"name", "pika:behind",
|
||||
"description", "PIKA behind mode operation",
|
||||
NULL);
|
||||
|
||||
layer_mode_class->process = pika_operation_behind_process;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_operation_behind_init (PikaOperationBehind *self)
|
||||
{
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_operation_behind_process (GeglOperation *op,
|
||||
void *in_p,
|
||||
void *layer_p,
|
||||
void *mask_p,
|
||||
void *out_p,
|
||||
glong samples,
|
||||
const GeglRectangle *roi,
|
||||
gint level)
|
||||
{
|
||||
PikaOperationLayerMode *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 PIKA_LAYER_COMPOSITE_UNION:
|
||||
case PIKA_LAYER_COMPOSITE_AUTO:
|
||||
while (samples--)
|
||||
{
|
||||
gfloat src1_alpha = in[ALPHA];
|
||||
gfloat src2_alpha = layer[ALPHA] * opacity;
|
||||
gfloat new_alpha;
|
||||
gint b;
|
||||
|
||||
if (has_mask)
|
||||
src2_alpha *= *mask;
|
||||
|
||||
new_alpha = src2_alpha + (1.0 - src2_alpha) * src1_alpha;
|
||||
|
||||
if (new_alpha)
|
||||
{
|
||||
gfloat ratio = in[ALPHA] / new_alpha;
|
||||
gfloat compl_ratio = 1.0f - ratio;
|
||||
|
||||
for (b = RED; b < ALPHA; b++)
|
||||
{
|
||||
out[b] = in[b] * ratio + layer[b] * compl_ratio;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
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 PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP:
|
||||
while (samples--)
|
||||
{
|
||||
gfloat src1_alpha = in[ALPHA];
|
||||
gfloat new_alpha;
|
||||
gint b;
|
||||
|
||||
new_alpha = src1_alpha;
|
||||
|
||||
if (new_alpha)
|
||||
{
|
||||
for (b = RED; b < ALPHA; b++)
|
||||
out[b] = in[b];
|
||||
}
|
||||
else
|
||||
{
|
||||
for (b = RED; b < ALPHA; b++)
|
||||
out[b] = layer[b];
|
||||
}
|
||||
|
||||
out[ALPHA] = new_alpha;
|
||||
|
||||
in += 4;
|
||||
layer += 4;
|
||||
out += 4;
|
||||
}
|
||||
break;
|
||||
|
||||
case PIKA_LAYER_COMPOSITE_CLIP_TO_LAYER:
|
||||
while (samples--)
|
||||
{
|
||||
gfloat src1_alpha = in[ALPHA];
|
||||
gfloat src2_alpha = layer[ALPHA] * opacity;
|
||||
gfloat new_alpha;
|
||||
gint b;
|
||||
|
||||
if (has_mask)
|
||||
src2_alpha *= *mask;
|
||||
|
||||
new_alpha = src2_alpha;
|
||||
|
||||
if (new_alpha)
|
||||
{
|
||||
for (b = RED; b < ALPHA; b++)
|
||||
{
|
||||
out[b] = layer[b] + (in[b] - layer[b]) * src1_alpha;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
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 PIKA_LAYER_COMPOSITE_INTERSECTION:
|
||||
while (samples--)
|
||||
{
|
||||
gfloat src1_alpha = in[ALPHA];
|
||||
gfloat src2_alpha = layer[ALPHA] * opacity;
|
||||
gfloat new_alpha;
|
||||
gint b;
|
||||
|
||||
if (has_mask)
|
||||
src2_alpha *= *mask;
|
||||
|
||||
new_alpha = src1_alpha * src2_alpha;
|
||||
|
||||
if (new_alpha)
|
||||
{
|
||||
for (b = RED; b < ALPHA; b++)
|
||||
{
|
||||
out[b] = in[b];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
57
app/operations/layer-modes/pikaoperationbehind.h
Normal file
57
app/operations/layer-modes/pikaoperationbehind.h
Normal file
@ -0,0 +1,57 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationbehind.h
|
||||
* Copyright (C) 2008 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* 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 __PIKA_OPERATION_BEHIND_H__
|
||||
#define __PIKA_OPERATION_BEHIND_H__
|
||||
|
||||
|
||||
#include "pikaoperationlayermode.h"
|
||||
|
||||
|
||||
#define PIKA_TYPE_OPERATION_BEHIND (pika_operation_behind_get_type ())
|
||||
#define PIKA_OPERATION_BEHIND(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_OPERATION_BEHIND, PikaOperationBehind))
|
||||
#define PIKA_OPERATION_BEHIND_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_OPERATION_BEHIND, PikaOperationBehindClass))
|
||||
#define PIKA_IS_OPERATION_BEHIND(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_OPERATION_BEHIND))
|
||||
#define PIKA_IS_OPERATION_BEHIND_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_OPERATION_BEHIND))
|
||||
#define PIKA_OPERATION_BEHIND_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_OPERATION_BEHIND, PikaOperationBehindClass))
|
||||
|
||||
|
||||
typedef struct _PikaOperationBehind PikaOperationBehind;
|
||||
typedef struct _PikaOperationBehindClass PikaOperationBehindClass;
|
||||
|
||||
struct _PikaOperationBehind
|
||||
{
|
||||
PikaOperationLayerMode parent_instance;
|
||||
};
|
||||
|
||||
struct _PikaOperationBehindClass
|
||||
{
|
||||
PikaOperationLayerModeClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType pika_operation_behind_get_type (void) G_GNUC_CONST;
|
||||
|
||||
|
||||
#endif /* __PIKA_OPERATION_BEHIND_H__ */
|
||||
179
app/operations/layer-modes/pikaoperationdissolve.c
Normal file
179
app/operations/layer-modes/pikaoperationdissolve.c
Normal file
@ -0,0 +1,179 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationdissolve.c
|
||||
* Copyright (C) 2012 Ville Sokk <ville.sokk@gmail.com>
|
||||
* 2012 Øyvind Kolås <pippin@gimp.org>
|
||||
* 2003 Helvetix Victorinox
|
||||
*
|
||||
* 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 <gegl-plugin.h>
|
||||
|
||||
#include "../operations-types.h"
|
||||
|
||||
#include "pikaoperationdissolve.h"
|
||||
|
||||
|
||||
#define RANDOM_TABLE_SIZE 4096
|
||||
|
||||
|
||||
static gboolean pika_operation_dissolve_process (GeglOperation *op,
|
||||
void *in,
|
||||
void *layer,
|
||||
void *mask,
|
||||
void *out,
|
||||
glong samples,
|
||||
const GeglRectangle *result,
|
||||
gint level);
|
||||
static PikaLayerCompositeRegion pika_operation_dissolve_get_affected_region (PikaOperationLayerMode *layer_mode);
|
||||
|
||||
|
||||
G_DEFINE_TYPE (PikaOperationDissolve, pika_operation_dissolve,
|
||||
PIKA_TYPE_OPERATION_LAYER_MODE)
|
||||
|
||||
|
||||
static gint32 random_table[RANDOM_TABLE_SIZE];
|
||||
|
||||
|
||||
static void
|
||||
pika_operation_dissolve_class_init (PikaOperationDissolveClass *klass)
|
||||
{
|
||||
GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass);
|
||||
PikaOperationLayerModeClass *layer_mode_class = PIKA_OPERATION_LAYER_MODE_CLASS (klass);
|
||||
GRand *gr;
|
||||
gint i;
|
||||
|
||||
gegl_operation_class_set_keys (operation_class,
|
||||
"name", "pika:dissolve",
|
||||
"description", "PIKA dissolve mode operation",
|
||||
"categories", "compositors",
|
||||
NULL);
|
||||
|
||||
layer_mode_class->process = pika_operation_dissolve_process;
|
||||
layer_mode_class->get_affected_region = pika_operation_dissolve_get_affected_region;
|
||||
|
||||
/* generate a table of random seeds */
|
||||
gr = g_rand_new_with_seed (314159265);
|
||||
for (i = 0; i < RANDOM_TABLE_SIZE; i++)
|
||||
random_table[i] = g_rand_int (gr);
|
||||
|
||||
g_rand_free (gr);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_operation_dissolve_init (PikaOperationDissolve *self)
|
||||
{
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_operation_dissolve_process (GeglOperation *op,
|
||||
void *in_p,
|
||||
void *layer_p,
|
||||
void *mask_p,
|
||||
void *out_p,
|
||||
glong samples,
|
||||
const GeglRectangle *result,
|
||||
gint level)
|
||||
{
|
||||
PikaOperationLayerMode *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;
|
||||
gint x, y;
|
||||
|
||||
for (y = result->y; y < result->y + result->height; y++)
|
||||
{
|
||||
GRand *gr;
|
||||
|
||||
/* The offset can be negative. I could just abs() the result, but we
|
||||
* probably prefer to use different indexes of the table when possible for
|
||||
* nicer randomization, so let's cycle the modulo so that -1 is the last
|
||||
* table index.
|
||||
*/
|
||||
gr = g_rand_new_with_seed (random_table[((y % RANDOM_TABLE_SIZE) + RANDOM_TABLE_SIZE) % RANDOM_TABLE_SIZE]);
|
||||
|
||||
/* fast forward through the rows pseudo random sequence */
|
||||
for (x = 0; x < result->x; x++)
|
||||
g_rand_int (gr);
|
||||
|
||||
for (x = result->x; x < result->x + result->width; x++)
|
||||
{
|
||||
gfloat value = layer[ALPHA] * opacity * 255;
|
||||
|
||||
if (has_mask)
|
||||
value *= *mask;
|
||||
|
||||
if (g_rand_int_range (gr, 0, 255) >= value)
|
||||
{
|
||||
out[0] = in[0];
|
||||
out[1] = in[1];
|
||||
out[2] = in[2];
|
||||
|
||||
if (layer_mode->composite_mode == PIKA_LAYER_COMPOSITE_UNION ||
|
||||
layer_mode->composite_mode == PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP)
|
||||
{
|
||||
out[3] = in[3];
|
||||
}
|
||||
else
|
||||
{
|
||||
out[3] = 0.0f;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
out[0] = layer[0];
|
||||
out[1] = layer[1];
|
||||
out[2] = layer[2];
|
||||
|
||||
if (layer_mode->composite_mode == PIKA_LAYER_COMPOSITE_UNION ||
|
||||
layer_mode->composite_mode == PIKA_LAYER_COMPOSITE_CLIP_TO_LAYER)
|
||||
{
|
||||
out[3] = 1.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
out[3] = in[3];
|
||||
}
|
||||
}
|
||||
|
||||
in += 4;
|
||||
layer += 4;
|
||||
out += 4;
|
||||
|
||||
if (has_mask)
|
||||
mask++;
|
||||
}
|
||||
|
||||
g_rand_free (gr);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static PikaLayerCompositeRegion
|
||||
pika_operation_dissolve_get_affected_region (PikaOperationLayerMode *layer_mode)
|
||||
{
|
||||
return PIKA_LAYER_COMPOSITE_REGION_SOURCE;
|
||||
}
|
||||
57
app/operations/layer-modes/pikaoperationdissolve.h
Normal file
57
app/operations/layer-modes/pikaoperationdissolve.h
Normal file
@ -0,0 +1,57 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationdissolve.h
|
||||
* Copyright (C) 2012 Ville Sokk <ville.sokk@gmail.com>
|
||||
*
|
||||
* 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 __PIKA_OPERATION_DISSOLVE_H__
|
||||
#define __PIKA_OPERATION_DISSOLVE_H__
|
||||
|
||||
|
||||
#include "pikaoperationlayermode.h"
|
||||
|
||||
|
||||
#define PIKA_TYPE_OPERATION_DISSOLVE (pika_operation_dissolve_get_type ())
|
||||
#define PIKA_OPERATION_DISSOLVE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_OPERATION_DISSOLVE, PikaOperationDissolve))
|
||||
#define PIKA_OPERATION_DISSOLVE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_OPERATION_DISSOLVE, PikaOperationDissolveClass))
|
||||
#define PIKA_IS_OPERATION_DISSOLVE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_OPERATION_DISSOLVE))
|
||||
#define PIKA_IS_OPERATION_DISSOLVE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_OPERATION_DISSOLVE))
|
||||
#define PIKA_OPERATION_DISSOLVE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_OPERATION_DISSOLVE, PikaOperationDissolveClass))
|
||||
|
||||
|
||||
typedef struct _PikaOperationDissolve PikaOperationDissolve;
|
||||
typedef struct _PikaOperationDissolveClass PikaOperationDissolveClass;
|
||||
|
||||
struct _PikaOperationDissolveClass
|
||||
{
|
||||
PikaOperationLayerModeClass parent_class;
|
||||
};
|
||||
|
||||
struct _PikaOperationDissolve
|
||||
{
|
||||
PikaOperationLayerMode parent_instance;
|
||||
};
|
||||
|
||||
|
||||
GType pika_operation_dissolve_get_type (void) G_GNUC_CONST;
|
||||
|
||||
|
||||
#endif /* __PIKA_OPERATION_DISSOLVE_H__ */
|
||||
218
app/operations/layer-modes/pikaoperationerase.c
Normal file
218
app/operations/layer-modes/pikaoperationerase.c
Normal file
@ -0,0 +1,218 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationerase.c
|
||||
* Copyright (C) 2008 Michael Natterer <mitch@gimp.org>
|
||||
* 2012 Ville Sokk <ville.sokk@gmail.com>
|
||||
*
|
||||
* 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 <gegl-plugin.h>
|
||||
|
||||
#include "../operations-types.h"
|
||||
|
||||
#include "pikaoperationerase.h"
|
||||
|
||||
|
||||
static gboolean pika_operation_erase_process (GeglOperation *op,
|
||||
void *in,
|
||||
void *layer,
|
||||
void *mask,
|
||||
void *out,
|
||||
glong samples,
|
||||
const GeglRectangle *roi,
|
||||
gint level);
|
||||
|
||||
|
||||
G_DEFINE_TYPE (PikaOperationErase, pika_operation_erase,
|
||||
PIKA_TYPE_OPERATION_LAYER_MODE)
|
||||
|
||||
|
||||
static void
|
||||
pika_operation_erase_class_init (PikaOperationEraseClass *klass)
|
||||
{
|
||||
GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass);
|
||||
PikaOperationLayerModeClass *layer_mode_class = PIKA_OPERATION_LAYER_MODE_CLASS (klass);
|
||||
|
||||
gegl_operation_class_set_keys (operation_class,
|
||||
"name", "pika:erase",
|
||||
"description", "PIKA erase mode operation",
|
||||
NULL);
|
||||
|
||||
layer_mode_class->process = pika_operation_erase_process;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_operation_erase_init (PikaOperationErase *self)
|
||||
{
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_operation_erase_process (GeglOperation *op,
|
||||
void *in_p,
|
||||
void *layer_p,
|
||||
void *mask_p,
|
||||
void *out_p,
|
||||
glong samples,
|
||||
const GeglRectangle *roi,
|
||||
gint level)
|
||||
{
|
||||
PikaOperationLayerMode *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 PIKA_LAYER_COMPOSITE_UNION:
|
||||
while (samples--)
|
||||
{
|
||||
gfloat layer_alpha;
|
||||
gfloat new_alpha;
|
||||
gint b;
|
||||
|
||||
layer_alpha = layer[ALPHA] * opacity;
|
||||
|
||||
if (has_mask)
|
||||
layer_alpha *= (*mask);
|
||||
|
||||
new_alpha = in[ALPHA] + layer_alpha - 2.0f * in[ALPHA] * layer_alpha;
|
||||
|
||||
if (new_alpha != 0.0f)
|
||||
{
|
||||
gfloat ratio;
|
||||
|
||||
ratio = (1.0f - in[ALPHA]) * layer_alpha / new_alpha;
|
||||
|
||||
for (b = RED; b < ALPHA; b++)
|
||||
{
|
||||
out[b] = ratio * layer[b] + (1.0f - ratio) * in[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 PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP:
|
||||
case PIKA_LAYER_COMPOSITE_AUTO:
|
||||
while (samples--)
|
||||
{
|
||||
gfloat layer_alpha;
|
||||
gfloat new_alpha;
|
||||
gint b;
|
||||
|
||||
layer_alpha = layer[ALPHA] * opacity;
|
||||
|
||||
if (has_mask)
|
||||
layer_alpha *= (*mask);
|
||||
|
||||
new_alpha = (1.0f - layer_alpha) * in[ALPHA];
|
||||
|
||||
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 PIKA_LAYER_COMPOSITE_CLIP_TO_LAYER:
|
||||
while (samples--)
|
||||
{
|
||||
gfloat layer_alpha;
|
||||
gfloat new_alpha;
|
||||
const gfloat *src;
|
||||
gint b;
|
||||
|
||||
layer_alpha = layer[ALPHA] * opacity;
|
||||
|
||||
if (has_mask)
|
||||
layer_alpha *= (*mask);
|
||||
|
||||
new_alpha = (1.0f - in[ALPHA]) * layer_alpha;
|
||||
|
||||
src = layer;
|
||||
|
||||
if (new_alpha == 0.0f)
|
||||
src = in;
|
||||
|
||||
for (b = RED; b < ALPHA; b++)
|
||||
{
|
||||
out[b] = src[b];
|
||||
}
|
||||
|
||||
out[ALPHA] = new_alpha;
|
||||
|
||||
in += 4;
|
||||
layer += 4;
|
||||
out += 4;
|
||||
|
||||
if (has_mask)
|
||||
mask ++;
|
||||
}
|
||||
break;
|
||||
|
||||
case PIKA_LAYER_COMPOSITE_INTERSECTION:
|
||||
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;
|
||||
}
|
||||
57
app/operations/layer-modes/pikaoperationerase.h
Normal file
57
app/operations/layer-modes/pikaoperationerase.h
Normal file
@ -0,0 +1,57 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationerase.h
|
||||
* Copyright (C) 2008 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* 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 __PIKA_OPERATION_ERASE_H__
|
||||
#define __PIKA_OPERATION_ERASE_H__
|
||||
|
||||
|
||||
#include "pikaoperationlayermode.h"
|
||||
|
||||
|
||||
#define PIKA_TYPE_OPERATION_ERASE (pika_operation_erase_get_type ())
|
||||
#define PIKA_OPERATION_ERASE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_OPERATION_ERASE, PikaOperationErase))
|
||||
#define PIKA_OPERATION_ERASE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_OPERATION_ERASE, PikaOperationEraseClass))
|
||||
#define PIKA_IS_OPERATION_ERASE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_OPERATION_ERASE))
|
||||
#define PIKA_IS_OPERATION_ERASE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_OPERATION_ERASE))
|
||||
#define PIKA_OPERATION_ERASE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_OPERATION_ERASE, PikaOperationEraseClass))
|
||||
|
||||
|
||||
typedef struct _PikaOperationErase PikaOperationErase;
|
||||
typedef struct _PikaOperationEraseClass PikaOperationEraseClass;
|
||||
|
||||
struct _PikaOperationErase
|
||||
{
|
||||
PikaOperationLayerMode parent_instance;
|
||||
};
|
||||
|
||||
struct _PikaOperationEraseClass
|
||||
{
|
||||
PikaOperationLayerModeClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType pika_operation_erase_get_type (void) G_GNUC_CONST;
|
||||
|
||||
|
||||
#endif /* __PIKA_OPERATION_ERASE_MODE_H__ */
|
||||
1240
app/operations/layer-modes/pikaoperationlayermode-blend.c
Normal file
1240
app/operations/layer-modes/pikaoperationlayermode-blend.c
Normal file
File diff suppressed because it is too large
Load Diff
204
app/operations/layer-modes/pikaoperationlayermode-blend.h
Normal file
204
app/operations/layer-modes/pikaoperationlayermode-blend.h
Normal file
@ -0,0 +1,204 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationlayermode-blend.h
|
||||
* Copyright (C) 2017 Michael Natterer <mitch@gimp.org>
|
||||
* 2017 Øyvind Kolås <pippin@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; withcomp 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 __PIKA_OPERATION_LAYER_MODE_BLEND_H__
|
||||
#define __PIKA_OPERATION_LAYER_MODE_BLEND_H__
|
||||
|
||||
|
||||
/* nonsubtractive blend functions */
|
||||
|
||||
void pika_operation_layer_mode_blend_addition (GeglOperation *operation,
|
||||
const gfloat *in,
|
||||
const gfloat *layer,
|
||||
gfloat *comp,
|
||||
gint samples);
|
||||
void pika_operation_layer_mode_blend_burn (GeglOperation *operation,
|
||||
const gfloat *in,
|
||||
const gfloat *layer,
|
||||
gfloat *comp,
|
||||
gint samples);
|
||||
void pika_operation_layer_mode_blend_darken_only (GeglOperation *operation,
|
||||
const gfloat *in,
|
||||
const gfloat *layer,
|
||||
gfloat *comp,
|
||||
gint samples);
|
||||
void pika_operation_layer_mode_blend_difference (GeglOperation *operation,
|
||||
const gfloat *in,
|
||||
const gfloat *layer,
|
||||
gfloat *comp,
|
||||
gint samples);
|
||||
void pika_operation_layer_mode_blend_divide (GeglOperation *operation,
|
||||
const gfloat *in,
|
||||
const gfloat *layer,
|
||||
gfloat *comp,
|
||||
gint samples);
|
||||
void pika_operation_layer_mode_blend_dodge (GeglOperation *operation,
|
||||
const gfloat *in,
|
||||
const gfloat *layer,
|
||||
gfloat *comp,
|
||||
gint samples);
|
||||
void pika_operation_layer_mode_blend_exclusion (GeglOperation *operation,
|
||||
const gfloat *in,
|
||||
const gfloat *layer,
|
||||
gfloat *comp,
|
||||
gint samples);
|
||||
void pika_operation_layer_mode_blend_grain_extract (GeglOperation *operation,
|
||||
const gfloat *in,
|
||||
const gfloat *layer,
|
||||
gfloat *comp,
|
||||
gint samples);
|
||||
void pika_operation_layer_mode_blend_grain_merge (GeglOperation *operation,
|
||||
const gfloat *in,
|
||||
const gfloat *layer,
|
||||
gfloat *comp,
|
||||
gint samples);
|
||||
void pika_operation_layer_mode_blend_hard_mix (GeglOperation *operation,
|
||||
const gfloat *in,
|
||||
const gfloat *layer,
|
||||
gfloat *comp,
|
||||
gint samples);
|
||||
void pika_operation_layer_mode_blend_hardlight (GeglOperation *operation,
|
||||
const gfloat *in,
|
||||
const gfloat *layer,
|
||||
gfloat *comp,
|
||||
gint samples);
|
||||
void pika_operation_layer_mode_blend_hsl_color (GeglOperation *operation,
|
||||
const gfloat *in,
|
||||
const gfloat *layer,
|
||||
gfloat *comp,
|
||||
gint samples);
|
||||
void pika_operation_layer_mode_blend_hsv_hue (GeglOperation *operation,
|
||||
const gfloat *in,
|
||||
const gfloat *layer,
|
||||
gfloat *comp,
|
||||
gint samples);
|
||||
void pika_operation_layer_mode_blend_hsv_saturation (GeglOperation *operation,
|
||||
const gfloat *in,
|
||||
const gfloat *layer,
|
||||
gfloat *comp,
|
||||
gint samples);
|
||||
void pika_operation_layer_mode_blend_hsv_value (GeglOperation *operation,
|
||||
const gfloat *in,
|
||||
const gfloat *layer,
|
||||
gfloat *comp,
|
||||
gint samples);
|
||||
void pika_operation_layer_mode_blend_lch_chroma (GeglOperation *operation,
|
||||
const gfloat *in,
|
||||
const gfloat *layer,
|
||||
gfloat *comp,
|
||||
gint samples);
|
||||
void pika_operation_layer_mode_blend_lch_color (GeglOperation *operation,
|
||||
const gfloat *in,
|
||||
const gfloat *layer,
|
||||
gfloat *comp,
|
||||
gint samples);
|
||||
void pika_operation_layer_mode_blend_lch_hue (GeglOperation *operation,
|
||||
const gfloat *in,
|
||||
const gfloat *layer,
|
||||
gfloat *comp,
|
||||
gint samples);
|
||||
void pika_operation_layer_mode_blend_lch_lightness (GeglOperation *operation,
|
||||
const gfloat *in,
|
||||
const gfloat *layer,
|
||||
gfloat *comp,
|
||||
gint samples);
|
||||
void pika_operation_layer_mode_blend_lighten_only (GeglOperation *operation,
|
||||
const gfloat *in,
|
||||
const gfloat *layer,
|
||||
gfloat *comp,
|
||||
gint samples);
|
||||
void pika_operation_layer_mode_blend_linear_burn (GeglOperation *operation,
|
||||
const gfloat *in,
|
||||
const gfloat *layer,
|
||||
gfloat *comp,
|
||||
gint samples);
|
||||
void pika_operation_layer_mode_blend_linear_light (GeglOperation *operation,
|
||||
const gfloat *in,
|
||||
const gfloat *layer,
|
||||
gfloat *comp,
|
||||
gint samples);
|
||||
void pika_operation_layer_mode_blend_luma_darken_only (GeglOperation *operation,
|
||||
const gfloat *in,
|
||||
const gfloat *layer,
|
||||
gfloat *comp,
|
||||
gint samples);
|
||||
void pika_operation_layer_mode_blend_luma_lighten_only (GeglOperation *operation,
|
||||
const gfloat *in,
|
||||
const gfloat *layer,
|
||||
gfloat *comp,
|
||||
gint samples);
|
||||
void pika_operation_layer_mode_blend_luminance (GeglOperation *operation,
|
||||
const gfloat *in,
|
||||
const gfloat *layer,
|
||||
gfloat *comp,
|
||||
gint samples);
|
||||
void pika_operation_layer_mode_blend_multiply (GeglOperation *operation,
|
||||
const gfloat *in,
|
||||
const gfloat *layer,
|
||||
gfloat *comp,
|
||||
gint samples);
|
||||
void pika_operation_layer_mode_blend_overlay (GeglOperation *operation,
|
||||
const gfloat *in,
|
||||
const gfloat *layer,
|
||||
gfloat *comp,
|
||||
gint samples);
|
||||
void pika_operation_layer_mode_blend_pin_light (GeglOperation *operation,
|
||||
const gfloat *in,
|
||||
const gfloat *layer,
|
||||
gfloat *comp,
|
||||
gint samples);
|
||||
void pika_operation_layer_mode_blend_screen (GeglOperation *operation,
|
||||
const gfloat *in,
|
||||
const gfloat *layer,
|
||||
gfloat *comp,
|
||||
gint samples);
|
||||
void pika_operation_layer_mode_blend_softlight (GeglOperation *operation,
|
||||
const gfloat *in,
|
||||
const gfloat *layer,
|
||||
gfloat *comp,
|
||||
gint samples);
|
||||
void pika_operation_layer_mode_blend_subtract (GeglOperation *operation,
|
||||
const gfloat *in,
|
||||
const gfloat *layer,
|
||||
gfloat *comp,
|
||||
gint samples);
|
||||
void pika_operation_layer_mode_blend_vivid_light (GeglOperation *operation,
|
||||
const gfloat *in,
|
||||
const gfloat *layer,
|
||||
gfloat *comp,
|
||||
gint samples);
|
||||
|
||||
|
||||
/* subtractive blend functions */
|
||||
|
||||
void pika_operation_layer_mode_blend_color_erase (GeglOperation *operation,
|
||||
const gfloat *in,
|
||||
const gfloat *layer,
|
||||
gfloat *comp,
|
||||
gint samples);
|
||||
|
||||
|
||||
#endif /* __PIKA_OPERATION_LAYER_MODE_BLEND_H__ */
|
||||
@ -0,0 +1,109 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationlayermode-composite-sse2.c
|
||||
* Copyright (C) 2017 Michael Natterer <mitch@gimp.org>
|
||||
* 2017 Øyvind Kolås <pippin@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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gegl-plugin.h>
|
||||
#include <cairo.h>
|
||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||
|
||||
#include "../operations-types.h"
|
||||
|
||||
#include "pikaoperationlayermode-composite.h"
|
||||
|
||||
|
||||
#if COMPILE_SSE2_INTRINISICS
|
||||
|
||||
/* SSE2 */
|
||||
#include <emmintrin.h>
|
||||
|
||||
|
||||
/* non-subtractive compositing functions. these functions expect comp[ALPHA]
|
||||
* to be the same as layer[ALPHA]. when in[ALPHA] or layer[ALPHA] are zero,
|
||||
* the value of comp[RED..BLUE] is unconstrained (in particular, it may be
|
||||
* NaN).
|
||||
*/
|
||||
|
||||
|
||||
void
|
||||
pika_operation_layer_mode_composite_clip_to_backdrop_sse2 (const gfloat *in,
|
||||
const gfloat *layer,
|
||||
const gfloat *comp,
|
||||
const gfloat *mask,
|
||||
gfloat opacity,
|
||||
gfloat *out,
|
||||
gint samples)
|
||||
{
|
||||
if ((((uintptr_t)in) | /* alignment check */
|
||||
((uintptr_t)comp) |
|
||||
((uintptr_t)out) ) & 0x0F)
|
||||
{
|
||||
pika_operation_layer_mode_composite_clip_to_backdrop (in, layer, comp,
|
||||
mask, opacity, out,
|
||||
samples);
|
||||
}
|
||||
else
|
||||
{
|
||||
const __v4sf *v_in = (const __v4sf*) in;
|
||||
const __v4sf *v_comp = (const __v4sf*) comp;
|
||||
__v4sf *v_out = (__v4sf*) out;
|
||||
const __v4sf v_one = _mm_set1_ps (1.0f);
|
||||
const __v4sf v_opacity = _mm_set1_ps (opacity);
|
||||
|
||||
while (samples--)
|
||||
{
|
||||
__v4sf alpha, rgba_in, rgba_comp;
|
||||
|
||||
rgba_in = *v_in ++;
|
||||
rgba_comp = *v_comp++;
|
||||
|
||||
alpha = (__v4sf)_mm_shuffle_epi32((__m128i)rgba_comp,_MM_SHUFFLE(3,3,3,3)) * v_opacity;
|
||||
|
||||
if (mask)
|
||||
{
|
||||
alpha = alpha * _mm_set1_ps (*mask++);
|
||||
}
|
||||
|
||||
if (rgba_in[ALPHA] != 0.0f && _mm_ucomineq_ss (alpha, _mm_setzero_ps ()))
|
||||
{
|
||||
__v4sf out_pixel, out_pixel_rbaa, out_alpha;
|
||||
|
||||
out_alpha = (__v4sf)_mm_shuffle_epi32((__m128i)rgba_in,_MM_SHUFFLE(3,3,3,3));
|
||||
out_pixel = rgba_comp * alpha + rgba_in * (v_one - alpha);
|
||||
out_pixel_rbaa = _mm_shuffle_ps (out_pixel, out_alpha, _MM_SHUFFLE (3, 3, 2, 0));
|
||||
out_pixel = _mm_shuffle_ps (out_pixel, out_pixel_rbaa, _MM_SHUFFLE (2, 1, 1, 0));
|
||||
|
||||
*v_out++ = out_pixel;
|
||||
}
|
||||
else
|
||||
{
|
||||
*v_out ++ = rgba_in;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* COMPILE_SSE2_INTRINISICS */
|
||||
438
app/operations/layer-modes/pikaoperationlayermode-composite.c
Normal file
438
app/operations/layer-modes/pikaoperationlayermode-composite.c
Normal file
@ -0,0 +1,438 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationlayermode-composite.c
|
||||
* Copyright (C) 2017 Michael Natterer <mitch@gimp.org>
|
||||
* 2017 Øyvind Kolås <pippin@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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gegl-plugin.h>
|
||||
#include <cairo.h>
|
||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||
|
||||
#include "../operations-types.h"
|
||||
|
||||
#include "pikaoperationlayermode-composite.h"
|
||||
|
||||
|
||||
/* non-subtractive compositing functions. these functions expect comp[ALPHA]
|
||||
* to be the same as layer[ALPHA]. when in[ALPHA] or layer[ALPHA] are zero,
|
||||
* the value of comp[RED..BLUE] is unconstrained (in particular, it may be
|
||||
* NaN).
|
||||
*/
|
||||
|
||||
|
||||
void
|
||||
pika_operation_layer_mode_composite_union (const gfloat *in,
|
||||
const gfloat *layer,
|
||||
const gfloat *comp,
|
||||
const gfloat *mask,
|
||||
gfloat opacity,
|
||||
gfloat *out,
|
||||
gint samples)
|
||||
{
|
||||
while (samples--)
|
||||
{
|
||||
gfloat new_alpha;
|
||||
gfloat in_alpha = in[ALPHA];
|
||||
gfloat layer_alpha = layer[ALPHA] * opacity;
|
||||
|
||||
if (mask)
|
||||
layer_alpha *= *mask;
|
||||
|
||||
new_alpha = layer_alpha + (1.0f - layer_alpha) * in_alpha;
|
||||
|
||||
if (layer_alpha == 0.0f || new_alpha == 0.0f)
|
||||
{
|
||||
out[RED] = in[RED];
|
||||
out[GREEN] = in[GREEN];
|
||||
out[BLUE] = in[BLUE];
|
||||
}
|
||||
else if (in_alpha == 0.0f)
|
||||
{
|
||||
out[RED] = layer[RED];
|
||||
out[GREEN] = layer[GREEN];
|
||||
out[BLUE] = layer[BLUE];
|
||||
}
|
||||
else
|
||||
{
|
||||
gfloat ratio = layer_alpha / new_alpha;
|
||||
gint b;
|
||||
|
||||
for (b = RED; b < ALPHA; b++)
|
||||
out[b] = ratio * (in_alpha * (comp[b] - layer[b]) + layer[b] - in[b]) + in[b];
|
||||
}
|
||||
|
||||
out[ALPHA] = new_alpha;
|
||||
|
||||
in += 4;
|
||||
layer += 4;
|
||||
comp += 4;
|
||||
out += 4;
|
||||
|
||||
if (mask)
|
||||
mask++;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
pika_operation_layer_mode_composite_clip_to_backdrop (const gfloat *in,
|
||||
const gfloat *layer,
|
||||
const gfloat *comp,
|
||||
const gfloat *mask,
|
||||
gfloat opacity,
|
||||
gfloat *out,
|
||||
gint samples)
|
||||
{
|
||||
while (samples--)
|
||||
{
|
||||
gfloat layer_alpha = comp[ALPHA] * opacity;
|
||||
|
||||
if (mask)
|
||||
layer_alpha *= *mask;
|
||||
|
||||
if (in[ALPHA] == 0.0f || layer_alpha == 0.0f)
|
||||
{
|
||||
out[RED] = in[RED];
|
||||
out[GREEN] = in[GREEN];
|
||||
out[BLUE] = in[BLUE];
|
||||
}
|
||||
else
|
||||
{
|
||||
gint b;
|
||||
|
||||
for (b = RED; b < ALPHA; b++)
|
||||
out[b] = comp[b] * layer_alpha + in[b] * (1.0f - layer_alpha);
|
||||
}
|
||||
|
||||
out[ALPHA] = in[ALPHA];
|
||||
|
||||
in += 4;
|
||||
comp += 4;
|
||||
out += 4;
|
||||
|
||||
if (mask)
|
||||
mask++;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
pika_operation_layer_mode_composite_clip_to_layer (const gfloat *in,
|
||||
const gfloat *layer,
|
||||
const gfloat *comp,
|
||||
const gfloat *mask,
|
||||
gfloat opacity,
|
||||
gfloat *out,
|
||||
gint samples)
|
||||
{
|
||||
while (samples--)
|
||||
{
|
||||
gfloat layer_alpha = layer[ALPHA] * opacity;
|
||||
|
||||
if (mask)
|
||||
layer_alpha *= *mask;
|
||||
|
||||
if (layer_alpha == 0.0f)
|
||||
{
|
||||
out[RED] = in[RED];
|
||||
out[GREEN] = in[GREEN];
|
||||
out[BLUE] = in[BLUE];
|
||||
}
|
||||
else if (in[ALPHA] == 0.0f)
|
||||
{
|
||||
out[RED] = layer[RED];
|
||||
out[GREEN] = layer[GREEN];
|
||||
out[BLUE] = layer[BLUE];
|
||||
}
|
||||
else
|
||||
{
|
||||
gint b;
|
||||
|
||||
for (b = RED; b < ALPHA; b++)
|
||||
out[b] = comp[b] * in[ALPHA] + layer[b] * (1.0f - in[ALPHA]);
|
||||
}
|
||||
|
||||
out[ALPHA] = layer_alpha;
|
||||
|
||||
in += 4;
|
||||
layer += 4;
|
||||
comp += 4;
|
||||
out += 4;
|
||||
|
||||
if (mask)
|
||||
mask++;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
pika_operation_layer_mode_composite_intersection (const gfloat *in,
|
||||
const gfloat *layer,
|
||||
const gfloat *comp,
|
||||
const gfloat *mask,
|
||||
gfloat opacity,
|
||||
gfloat *out,
|
||||
gint samples)
|
||||
{
|
||||
while (samples--)
|
||||
{
|
||||
gfloat new_alpha = in[ALPHA] * comp[ALPHA] * opacity;
|
||||
|
||||
if (mask)
|
||||
new_alpha *= *mask;
|
||||
|
||||
if (new_alpha == 0.0f)
|
||||
{
|
||||
out[RED] = in[RED];
|
||||
out[GREEN] = in[GREEN];
|
||||
out[BLUE] = in[BLUE];
|
||||
}
|
||||
else
|
||||
{
|
||||
out[RED] = comp[RED];
|
||||
out[GREEN] = comp[GREEN];
|
||||
out[BLUE] = comp[BLUE];
|
||||
}
|
||||
|
||||
out[ALPHA] = new_alpha;
|
||||
|
||||
in += 4;
|
||||
comp += 4;
|
||||
out += 4;
|
||||
|
||||
if (mask)
|
||||
mask++;
|
||||
}
|
||||
}
|
||||
|
||||
/* subtractive compositing functions. these functions expect comp[ALPHA] to
|
||||
* specify the modified alpha of the overlapping content, as a fraction of the
|
||||
* original overlapping content (i.e., an alpha of 1.0 specifies that no
|
||||
* content is subtracted.) when in[ALPHA] or layer[ALPHA] are zero, the value
|
||||
* of comp[RED..BLUE] is unconstrained (in particular, it may be NaN).
|
||||
*/
|
||||
|
||||
void
|
||||
pika_operation_layer_mode_composite_union_sub (const gfloat *in,
|
||||
const gfloat *layer,
|
||||
const gfloat *comp,
|
||||
const gfloat *mask,
|
||||
gfloat opacity,
|
||||
gfloat *out,
|
||||
gint samples)
|
||||
{
|
||||
while (samples--)
|
||||
{
|
||||
gfloat in_alpha = in[ALPHA];
|
||||
gfloat layer_alpha = layer[ALPHA] * opacity;
|
||||
gfloat comp_alpha = comp[ALPHA];
|
||||
gfloat new_alpha;
|
||||
|
||||
if (mask)
|
||||
layer_alpha *= *mask;
|
||||
|
||||
new_alpha = in_alpha + layer_alpha -
|
||||
(2.0f - comp_alpha) * in_alpha * layer_alpha;
|
||||
|
||||
if (layer_alpha == 0.0f || new_alpha == 0.0f)
|
||||
{
|
||||
out[RED] = in[RED];
|
||||
out[GREEN] = in[GREEN];
|
||||
out[BLUE] = in[BLUE];
|
||||
}
|
||||
else if (in_alpha == 0.0f)
|
||||
{
|
||||
out[RED] = layer[RED];
|
||||
out[GREEN] = layer[GREEN];
|
||||
out[BLUE] = layer[BLUE];
|
||||
}
|
||||
else
|
||||
{
|
||||
gfloat ratio = in_alpha / new_alpha;
|
||||
gfloat layer_coeff = 1.0f / in_alpha - 1.0f;
|
||||
gint b;
|
||||
|
||||
for (b = RED; b < ALPHA; b++)
|
||||
out[b] = ratio * (layer_alpha * (comp_alpha * comp[b] + layer_coeff * layer[b] - in[b]) + in[b]);
|
||||
}
|
||||
|
||||
out[ALPHA] = new_alpha;
|
||||
|
||||
in += 4;
|
||||
layer += 4;
|
||||
comp += 4;
|
||||
out += 4;
|
||||
|
||||
if (mask)
|
||||
mask++;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
pika_operation_layer_mode_composite_clip_to_backdrop_sub (const gfloat *in,
|
||||
const gfloat *layer,
|
||||
const gfloat *comp,
|
||||
const gfloat *mask,
|
||||
gfloat opacity,
|
||||
gfloat *out,
|
||||
gint samples)
|
||||
{
|
||||
while (samples--)
|
||||
{
|
||||
gfloat layer_alpha = layer[ALPHA] * opacity;
|
||||
gfloat comp_alpha = comp[ALPHA];
|
||||
gfloat new_alpha;
|
||||
|
||||
if (mask)
|
||||
layer_alpha *= *mask;
|
||||
|
||||
comp_alpha *= layer_alpha;
|
||||
|
||||
new_alpha = 1.0f - layer_alpha + comp_alpha;
|
||||
|
||||
if (in[ALPHA] == 0.0f || comp_alpha == 0.0f)
|
||||
{
|
||||
out[RED] = in[RED];
|
||||
out[GREEN] = in[GREEN];
|
||||
out[BLUE] = in[BLUE];
|
||||
}
|
||||
else
|
||||
{
|
||||
gfloat ratio = comp_alpha / new_alpha;
|
||||
gint b;
|
||||
|
||||
for (b = RED; b < ALPHA; b++)
|
||||
out[b] = comp[b] * ratio + in[b] * (1.0f - ratio);
|
||||
}
|
||||
|
||||
new_alpha *= in[ALPHA];
|
||||
|
||||
out[ALPHA] = new_alpha;
|
||||
|
||||
in += 4;
|
||||
layer += 4;
|
||||
comp += 4;
|
||||
out += 4;
|
||||
|
||||
if (mask)
|
||||
mask++;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
pika_operation_layer_mode_composite_clip_to_layer_sub (const gfloat *in,
|
||||
const gfloat *layer,
|
||||
const gfloat *comp,
|
||||
const gfloat *mask,
|
||||
gfloat opacity,
|
||||
gfloat *out,
|
||||
gint samples)
|
||||
{
|
||||
while (samples--)
|
||||
{
|
||||
gfloat in_alpha = in[ALPHA];
|
||||
gfloat layer_alpha = layer[ALPHA] * opacity;
|
||||
gfloat comp_alpha = comp[ALPHA];
|
||||
gfloat new_alpha;
|
||||
|
||||
if (mask)
|
||||
layer_alpha *= *mask;
|
||||
|
||||
comp_alpha *= in_alpha;
|
||||
|
||||
new_alpha = 1.0f - in_alpha + comp_alpha;
|
||||
|
||||
if (layer_alpha == 0.0f)
|
||||
{
|
||||
out[RED] = in[RED];
|
||||
out[GREEN] = in[GREEN];
|
||||
out[BLUE] = in[BLUE];
|
||||
}
|
||||
else if (in_alpha == 0.0f)
|
||||
{
|
||||
out[RED] = layer[RED];
|
||||
out[GREEN] = layer[GREEN];
|
||||
out[BLUE] = layer[BLUE];
|
||||
}
|
||||
else
|
||||
{
|
||||
gfloat ratio = comp_alpha / new_alpha;
|
||||
gint b;
|
||||
|
||||
for (b = RED; b < ALPHA; b++)
|
||||
out[b] = comp[b] * ratio + layer[b] * (1.0f - ratio);
|
||||
}
|
||||
|
||||
new_alpha *= layer_alpha;
|
||||
|
||||
out[ALPHA] = new_alpha;
|
||||
|
||||
in += 4;
|
||||
layer += 4;
|
||||
comp += 4;
|
||||
out += 4;
|
||||
|
||||
if (mask)
|
||||
mask++;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
pika_operation_layer_mode_composite_intersection_sub (const gfloat *in,
|
||||
const gfloat *layer,
|
||||
const gfloat *comp,
|
||||
const gfloat *mask,
|
||||
gfloat opacity,
|
||||
gfloat *out,
|
||||
gint samples)
|
||||
{
|
||||
while (samples--)
|
||||
{
|
||||
gfloat new_alpha = in[ALPHA] * layer[ALPHA] * comp[ALPHA] * opacity;
|
||||
|
||||
if (mask)
|
||||
new_alpha *= *mask;
|
||||
|
||||
if (new_alpha == 0.0f)
|
||||
{
|
||||
out[RED] = in[RED];
|
||||
out[GREEN] = in[GREEN];
|
||||
out[BLUE] = in[BLUE];
|
||||
}
|
||||
else
|
||||
{
|
||||
out[RED] = comp[RED];
|
||||
out[GREEN] = comp[GREEN];
|
||||
out[BLUE] = comp[BLUE];
|
||||
}
|
||||
|
||||
out[ALPHA] = new_alpha;
|
||||
|
||||
in += 4;
|
||||
layer += 4;
|
||||
comp += 4;
|
||||
out += 4;
|
||||
|
||||
if (mask)
|
||||
mask++;
|
||||
}
|
||||
}
|
||||
102
app/operations/layer-modes/pikaoperationlayermode-composite.h
Normal file
102
app/operations/layer-modes/pikaoperationlayermode-composite.h
Normal file
@ -0,0 +1,102 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationlayermode-composite.h
|
||||
* Copyright (C) 2017 Michael Natterer <mitch@gimp.org>
|
||||
* 2017 Øyvind Kolås <pippin@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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_OPERATION_LAYER_MODE_COMPOSITE_H__
|
||||
#define __PIKA_OPERATION_LAYER_MODE_COMPOSITE_H__
|
||||
|
||||
|
||||
void pika_operation_layer_mode_composite_union (const gfloat *in,
|
||||
const gfloat *layer,
|
||||
const gfloat *comp,
|
||||
const gfloat *mask,
|
||||
gfloat opacity,
|
||||
gfloat *out,
|
||||
gint samples);
|
||||
void pika_operation_layer_mode_composite_clip_to_backdrop (const gfloat *in,
|
||||
const gfloat *layer,
|
||||
const gfloat *comp,
|
||||
const gfloat *mask,
|
||||
gfloat opacity,
|
||||
gfloat *out,
|
||||
gint samples);
|
||||
void pika_operation_layer_mode_composite_clip_to_layer (const gfloat *in,
|
||||
const gfloat *layer,
|
||||
const gfloat *comp,
|
||||
const gfloat *mask,
|
||||
gfloat opacity,
|
||||
gfloat *out,
|
||||
gint samples);
|
||||
void pika_operation_layer_mode_composite_intersection (const gfloat *in,
|
||||
const gfloat *layer,
|
||||
const gfloat *comp,
|
||||
const gfloat *mask,
|
||||
gfloat opacity,
|
||||
gfloat *out,
|
||||
gint samples);
|
||||
|
||||
void pika_operation_layer_mode_composite_union_sub (const gfloat *in,
|
||||
const gfloat *layer,
|
||||
const gfloat *comp,
|
||||
const gfloat *mask,
|
||||
gfloat opacity,
|
||||
gfloat *out,
|
||||
gint samples);
|
||||
void pika_operation_layer_mode_composite_clip_to_backdrop_sub (const gfloat *in,
|
||||
const gfloat *layer,
|
||||
const gfloat *comp,
|
||||
const gfloat *mask,
|
||||
gfloat opacity,
|
||||
gfloat *out,
|
||||
gint samples);
|
||||
void pika_operation_layer_mode_composite_clip_to_layer_sub (const gfloat *in,
|
||||
const gfloat *layer,
|
||||
const gfloat *comp,
|
||||
const gfloat *mask,
|
||||
gfloat opacity,
|
||||
gfloat *out,
|
||||
gint samples);
|
||||
void pika_operation_layer_mode_composite_intersection_sub (const gfloat *in,
|
||||
const gfloat *layer,
|
||||
const gfloat *comp,
|
||||
const gfloat *mask,
|
||||
gfloat opacity,
|
||||
gfloat *out,
|
||||
gint samples);
|
||||
|
||||
#if COMPILE_SSE2_INTRINISICS
|
||||
|
||||
void pika_operation_layer_mode_composite_clip_to_backdrop_sse2 (const gfloat *in,
|
||||
const gfloat *layer,
|
||||
const gfloat *comp,
|
||||
const gfloat *mask,
|
||||
gfloat opacity,
|
||||
gfloat *out,
|
||||
gint samples);
|
||||
|
||||
#endif /* COMPILE_SSE2_INTRINISICS */
|
||||
|
||||
|
||||
#endif /* __PIKA_OPERATION_LAYER_MODE_COMPOSITE_H__ */
|
||||
960
app/operations/layer-modes/pikaoperationlayermode.c
Normal file
960
app/operations/layer-modes/pikaoperationlayermode.c
Normal file
@ -0,0 +1,960 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationlayermode.c
|
||||
* Copyright (C) 2008 Michael Natterer <mitch@gimp.org>
|
||||
* Copyright (C) 2008 Martin Nordholts <martinn@svn.gnome.org>
|
||||
*
|
||||
* 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 <gegl-plugin.h>
|
||||
#include <cairo.h>
|
||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||
|
||||
#include "libpikabase/pikabase.h"
|
||||
|
||||
#include "../operations-types.h"
|
||||
|
||||
#include "pika-layer-modes.h"
|
||||
#include "pikaoperationlayermode.h"
|
||||
#include "pikaoperationlayermode-composite.h"
|
||||
|
||||
|
||||
/* the maximum number of samples to process in one go. used to limit
|
||||
* the size of the buffers we allocate on the stack.
|
||||
*/
|
||||
#define PIKA_COMPOSITE_BLEND_MAX_SAMPLES ((1 << 18) /* 256 KiB */ / \
|
||||
16 /* bytes per pixel */ / \
|
||||
2 /* max number of buffers */)
|
||||
|
||||
/* number of consecutive unblended samples (whose source or destination alpha
|
||||
* is zero) above which to split the blending process, in order to avoid
|
||||
* performing too many unnecessary conversions.
|
||||
*/
|
||||
#define PIKA_COMPOSITE_BLEND_SPLIT_THRESHOLD 32
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_LAYER_MODE,
|
||||
PROP_OPACITY,
|
||||
PROP_BLEND_SPACE,
|
||||
PROP_COMPOSITE_SPACE,
|
||||
PROP_COMPOSITE_MODE
|
||||
};
|
||||
|
||||
|
||||
typedef void (* CompositeFunc) (const gfloat *in,
|
||||
const gfloat *layer,
|
||||
const gfloat *comp,
|
||||
const gfloat *mask,
|
||||
float opacity,
|
||||
gfloat *out,
|
||||
gint samples);
|
||||
|
||||
|
||||
static void pika_operation_layer_mode_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void pika_operation_layer_mode_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec);
|
||||
|
||||
static void pika_operation_layer_mode_prepare (GeglOperation *operation);
|
||||
static GeglRectangle pika_operation_layer_mode_get_bounding_box (GeglOperation *operation);
|
||||
static gboolean pika_operation_layer_mode_parent_process (GeglOperation *operation,
|
||||
GeglOperationContext *context,
|
||||
const gchar *output_prop,
|
||||
const GeglRectangle *result,
|
||||
gint level);
|
||||
|
||||
static gboolean pika_operation_layer_mode_process (GeglOperation *operation,
|
||||
void *in,
|
||||
void *layer,
|
||||
void *mask,
|
||||
void *out,
|
||||
glong samples,
|
||||
const GeglRectangle *roi,
|
||||
gint level);
|
||||
|
||||
static gboolean pika_operation_layer_mode_real_parent_process (GeglOperation *operation,
|
||||
GeglOperationContext *context,
|
||||
const gchar *output_prop,
|
||||
const GeglRectangle *result,
|
||||
gint level);
|
||||
static gboolean pika_operation_layer_mode_real_process (GeglOperation *operation,
|
||||
void *in,
|
||||
void *layer,
|
||||
void *mask,
|
||||
void *out,
|
||||
glong samples,
|
||||
const GeglRectangle *roi,
|
||||
gint level);
|
||||
|
||||
static gboolean process_last_node (GeglOperation *operation,
|
||||
void *in,
|
||||
void *layer,
|
||||
void *mask,
|
||||
void *out,
|
||||
glong samples,
|
||||
const GeglRectangle *roi,
|
||||
gint level);
|
||||
|
||||
static void pika_operation_layer_mode_cache_fishes (PikaOperationLayerMode *op,
|
||||
const Babl *preferred_format);
|
||||
|
||||
|
||||
G_DEFINE_TYPE (PikaOperationLayerMode, pika_operation_layer_mode,
|
||||
GEGL_TYPE_OPERATION_POINT_COMPOSER3)
|
||||
|
||||
#define parent_class pika_operation_layer_mode_parent_class
|
||||
|
||||
static CompositeFunc composite_union = pika_operation_layer_mode_composite_union;
|
||||
static CompositeFunc composite_clip_to_backdrop = pika_operation_layer_mode_composite_clip_to_backdrop;
|
||||
static CompositeFunc composite_clip_to_layer = pika_operation_layer_mode_composite_clip_to_layer;
|
||||
static CompositeFunc composite_intersection = pika_operation_layer_mode_composite_intersection;
|
||||
|
||||
static CompositeFunc composite_union_sub = pika_operation_layer_mode_composite_union_sub;
|
||||
static CompositeFunc composite_clip_to_backdrop_sub = pika_operation_layer_mode_composite_clip_to_backdrop_sub;
|
||||
static CompositeFunc composite_clip_to_layer_sub = pika_operation_layer_mode_composite_clip_to_layer_sub;
|
||||
static CompositeFunc composite_intersection_sub = pika_operation_layer_mode_composite_intersection_sub;
|
||||
|
||||
|
||||
static void
|
||||
pika_operation_layer_mode_class_init (PikaOperationLayerModeClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass);
|
||||
GeglOperationPointComposer3Class *point_composer3_class = GEGL_OPERATION_POINT_COMPOSER3_CLASS (klass);
|
||||
|
||||
gegl_operation_class_set_keys (operation_class,
|
||||
"name", "pika:layer-mode", NULL);
|
||||
|
||||
object_class->set_property = pika_operation_layer_mode_set_property;
|
||||
object_class->get_property = pika_operation_layer_mode_get_property;
|
||||
|
||||
operation_class->prepare = pika_operation_layer_mode_prepare;
|
||||
operation_class->get_bounding_box = pika_operation_layer_mode_get_bounding_box;
|
||||
operation_class->process = pika_operation_layer_mode_parent_process;
|
||||
|
||||
point_composer3_class->process = pika_operation_layer_mode_process;
|
||||
|
||||
klass->parent_process = pika_operation_layer_mode_real_parent_process;
|
||||
klass->process = pika_operation_layer_mode_real_process;
|
||||
klass->get_affected_region = NULL;
|
||||
|
||||
g_object_class_install_property (object_class, PROP_LAYER_MODE,
|
||||
g_param_spec_enum ("layer-mode",
|
||||
NULL, NULL,
|
||||
PIKA_TYPE_LAYER_MODE,
|
||||
PIKA_LAYER_MODE_NORMAL,
|
||||
PIKA_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_OPACITY,
|
||||
g_param_spec_double ("opacity",
|
||||
NULL, NULL,
|
||||
0.0, 1.0, 1.0,
|
||||
PIKA_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_BLEND_SPACE,
|
||||
g_param_spec_enum ("blend-space",
|
||||
NULL, NULL,
|
||||
PIKA_TYPE_LAYER_COLOR_SPACE,
|
||||
PIKA_LAYER_COLOR_SPACE_RGB_LINEAR,
|
||||
PIKA_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT));
|
||||
|
||||
|
||||
g_object_class_install_property (object_class, PROP_COMPOSITE_SPACE,
|
||||
g_param_spec_enum ("composite-space",
|
||||
NULL, NULL,
|
||||
PIKA_TYPE_LAYER_COLOR_SPACE,
|
||||
PIKA_LAYER_COLOR_SPACE_RGB_LINEAR,
|
||||
PIKA_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_COMPOSITE_MODE,
|
||||
g_param_spec_enum ("composite-mode",
|
||||
NULL, NULL,
|
||||
PIKA_TYPE_LAYER_COMPOSITE_MODE,
|
||||
PIKA_LAYER_COMPOSITE_UNION,
|
||||
PIKA_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT));
|
||||
|
||||
|
||||
#if COMPILE_SSE2_INTRINISICS
|
||||
if (pika_cpu_accel_get_support () & PIKA_CPU_ACCEL_X86_SSE2)
|
||||
composite_clip_to_backdrop = pika_operation_layer_mode_composite_clip_to_backdrop_sse2;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
pika_operation_layer_mode_init (PikaOperationLayerMode *self)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
pika_operation_layer_mode_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaOperationLayerMode *self = PIKA_OPERATION_LAYER_MODE (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_LAYER_MODE:
|
||||
self->layer_mode = g_value_get_enum (value);
|
||||
break;
|
||||
|
||||
case PROP_OPACITY:
|
||||
self->prop_opacity = g_value_get_double (value);
|
||||
break;
|
||||
|
||||
case PROP_BLEND_SPACE:
|
||||
self->blend_space = g_value_get_enum (value);
|
||||
break;
|
||||
|
||||
case PROP_COMPOSITE_SPACE:
|
||||
self->composite_space = g_value_get_enum (value);
|
||||
break;
|
||||
|
||||
case PROP_COMPOSITE_MODE:
|
||||
self->prop_composite_mode = g_value_get_enum (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_operation_layer_mode_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaOperationLayerMode *self = PIKA_OPERATION_LAYER_MODE (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_LAYER_MODE:
|
||||
g_value_set_enum (value, self->layer_mode);
|
||||
break;
|
||||
|
||||
case PROP_OPACITY:
|
||||
g_value_set_double (value, self->prop_opacity);
|
||||
break;
|
||||
|
||||
case PROP_BLEND_SPACE:
|
||||
g_value_set_enum (value, self->blend_space);
|
||||
break;
|
||||
|
||||
case PROP_COMPOSITE_SPACE:
|
||||
g_value_set_enum (value, self->composite_space);
|
||||
break;
|
||||
|
||||
case PROP_COMPOSITE_MODE:
|
||||
g_value_set_enum (value, self->prop_composite_mode);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_operation_layer_mode_prepare (GeglOperation *operation)
|
||||
{
|
||||
PikaOperationLayerMode *self = PIKA_OPERATION_LAYER_MODE (operation);
|
||||
const GeglRectangle *input_extent;
|
||||
const GeglRectangle *mask_extent;
|
||||
const Babl *preferred_format;
|
||||
const Babl *format;
|
||||
|
||||
self->composite_mode = self->prop_composite_mode;
|
||||
|
||||
if (self->composite_mode == PIKA_LAYER_COMPOSITE_AUTO)
|
||||
{
|
||||
self->composite_mode =
|
||||
pika_layer_mode_get_composite_mode (self->layer_mode);
|
||||
|
||||
g_warn_if_fail (self->composite_mode != PIKA_LAYER_COMPOSITE_AUTO);
|
||||
}
|
||||
|
||||
self->function = pika_layer_mode_get_function (self->layer_mode);
|
||||
self->blend_function = pika_layer_mode_get_blend_function (self->layer_mode);
|
||||
|
||||
input_extent = gegl_operation_source_get_bounding_box (operation, "input");
|
||||
mask_extent = gegl_operation_source_get_bounding_box (operation, "aux2");
|
||||
|
||||
/* if the input pad has data, work as usual. */
|
||||
if (input_extent && ! gegl_rectangle_is_empty (input_extent))
|
||||
{
|
||||
self->is_last_node = FALSE;
|
||||
|
||||
preferred_format = gegl_operation_get_source_format (operation, "input");
|
||||
}
|
||||
/* otherwise, we're the last node (corresponding to the bottom layer).
|
||||
* in this case, we render the layer (as if) using UNION mode.
|
||||
*/
|
||||
else
|
||||
{
|
||||
self->is_last_node = TRUE;
|
||||
|
||||
/* if the layer mode doesn't affect the source, use a shortcut
|
||||
* function that only applies the opacity/mask to the layer.
|
||||
*/
|
||||
if (! (pika_operation_layer_mode_get_affected_region (self) &
|
||||
PIKA_LAYER_COMPOSITE_REGION_SOURCE))
|
||||
{
|
||||
self->function = process_last_node;
|
||||
}
|
||||
/* otherwise, use the original process function, but force the
|
||||
* composite mode to UNION.
|
||||
*/
|
||||
else
|
||||
{
|
||||
self->composite_mode = PIKA_LAYER_COMPOSITE_UNION;
|
||||
}
|
||||
|
||||
preferred_format = gegl_operation_get_source_format (operation, "aux");
|
||||
}
|
||||
|
||||
self->has_mask = mask_extent && ! gegl_rectangle_is_empty (mask_extent);
|
||||
|
||||
pika_operation_layer_mode_cache_fishes (self, preferred_format);
|
||||
|
||||
format = pika_layer_mode_get_format (self->layer_mode,
|
||||
self->blend_space,
|
||||
self->composite_space,
|
||||
self->composite_mode,
|
||||
preferred_format);
|
||||
|
||||
gegl_operation_set_format (operation, "input", format);
|
||||
gegl_operation_set_format (operation, "output", format);
|
||||
gegl_operation_set_format (operation, "aux", format);
|
||||
gegl_operation_set_format (operation, "aux2", babl_format_with_space ("Y float", format));
|
||||
}
|
||||
|
||||
static GeglRectangle
|
||||
pika_operation_layer_mode_get_bounding_box (GeglOperation *op)
|
||||
{
|
||||
PikaOperationLayerMode *self = (gpointer) op;
|
||||
GeglRectangle *in_rect;
|
||||
GeglRectangle *aux_rect;
|
||||
GeglRectangle *aux2_rect;
|
||||
GeglRectangle src_rect = {};
|
||||
GeglRectangle dst_rect = {};
|
||||
GeglRectangle result;
|
||||
PikaLayerCompositeRegion included_region;
|
||||
|
||||
in_rect = gegl_operation_source_get_bounding_box (op, "input");
|
||||
aux_rect = gegl_operation_source_get_bounding_box (op, "aux");
|
||||
aux2_rect = gegl_operation_source_get_bounding_box (op, "aux2");
|
||||
|
||||
if (in_rect)
|
||||
dst_rect = *in_rect;
|
||||
|
||||
if (aux_rect)
|
||||
{
|
||||
src_rect = *aux_rect;
|
||||
|
||||
if (aux2_rect)
|
||||
gegl_rectangle_intersect (&src_rect, &src_rect, aux2_rect);
|
||||
}
|
||||
|
||||
if (self->is_last_node)
|
||||
{
|
||||
included_region = PIKA_LAYER_COMPOSITE_REGION_SOURCE;
|
||||
}
|
||||
else
|
||||
{
|
||||
included_region = pika_layer_mode_get_included_region (self->layer_mode,
|
||||
self->composite_mode);
|
||||
}
|
||||
|
||||
if (self->prop_opacity == 0.0)
|
||||
included_region &= ~PIKA_LAYER_COMPOSITE_REGION_SOURCE;
|
||||
|
||||
gegl_rectangle_intersect (&result, &src_rect, &dst_rect);
|
||||
|
||||
if (included_region & PIKA_LAYER_COMPOSITE_REGION_SOURCE)
|
||||
gegl_rectangle_bounding_box (&result, &result, &src_rect);
|
||||
|
||||
if (included_region & PIKA_LAYER_COMPOSITE_REGION_DESTINATION)
|
||||
gegl_rectangle_bounding_box (&result, &result, &dst_rect);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_operation_layer_mode_parent_process (GeglOperation *operation,
|
||||
GeglOperationContext *context,
|
||||
const gchar *output_prop,
|
||||
const GeglRectangle *result,
|
||||
gint level)
|
||||
{
|
||||
PikaOperationLayerMode *point = PIKA_OPERATION_LAYER_MODE (operation);
|
||||
|
||||
point->opacity = point->prop_opacity;
|
||||
|
||||
/* if we have a mask, but it's not included in the output, pretend the
|
||||
* opacity is 0, so that we don't composite 'aux' over 'input' as if there
|
||||
* was no mask.
|
||||
*/
|
||||
if (point->has_mask)
|
||||
{
|
||||
GObject *mask;
|
||||
gboolean has_mask;
|
||||
|
||||
/* get the raw value. this does not increase the reference count. */
|
||||
mask = gegl_operation_context_get_object (context, "aux2");
|
||||
|
||||
/* disregard 'mask' if it's not included in the roi. */
|
||||
has_mask =
|
||||
mask &&
|
||||
gegl_rectangle_intersect (NULL,
|
||||
gegl_buffer_get_extent (GEGL_BUFFER (mask)),
|
||||
result);
|
||||
|
||||
if (! has_mask)
|
||||
point->opacity = 0.0;
|
||||
}
|
||||
|
||||
return PIKA_OPERATION_LAYER_MODE_GET_CLASS (point)->parent_process (
|
||||
operation, context, output_prop, result, level);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_operation_layer_mode_process (GeglOperation *operation,
|
||||
void *in,
|
||||
void *layer,
|
||||
void *mask,
|
||||
void *out,
|
||||
glong samples,
|
||||
const GeglRectangle *roi,
|
||||
gint level)
|
||||
{
|
||||
return ((PikaOperationLayerMode *) operation)->function (
|
||||
operation, in, layer, mask, out, samples, roi, level);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_operation_layer_mode_real_parent_process (GeglOperation *operation,
|
||||
GeglOperationContext *context,
|
||||
const gchar *output_prop,
|
||||
const GeglRectangle *result,
|
||||
gint level)
|
||||
{
|
||||
PikaOperationLayerMode *point = PIKA_OPERATION_LAYER_MODE (operation);
|
||||
GObject *input;
|
||||
GObject *aux;
|
||||
gboolean has_input;
|
||||
gboolean has_aux;
|
||||
PikaLayerCompositeRegion included_region;
|
||||
|
||||
/* get the raw values. this does not increase the reference count. */
|
||||
input = gegl_operation_context_get_object (context, "input");
|
||||
aux = gegl_operation_context_get_object (context, "aux");
|
||||
|
||||
/* disregard 'input' if it's not included in the roi. */
|
||||
has_input =
|
||||
input &&
|
||||
gegl_rectangle_intersect (NULL,
|
||||
gegl_buffer_get_extent (GEGL_BUFFER (input)),
|
||||
result);
|
||||
|
||||
/* disregard 'aux' if it's not included in the roi, or if it's fully
|
||||
* transparent.
|
||||
*/
|
||||
has_aux =
|
||||
aux &&
|
||||
point->opacity != 0.0 &&
|
||||
gegl_rectangle_intersect (NULL,
|
||||
gegl_buffer_get_extent (GEGL_BUFFER (aux)),
|
||||
result);
|
||||
|
||||
if (point->is_last_node)
|
||||
{
|
||||
included_region = PIKA_LAYER_COMPOSITE_REGION_SOURCE;
|
||||
}
|
||||
else
|
||||
{
|
||||
included_region = pika_layer_mode_get_included_region (point->layer_mode,
|
||||
point->composite_mode);
|
||||
}
|
||||
|
||||
/* if there's no 'input' ... */
|
||||
if (! has_input)
|
||||
{
|
||||
/* ... and there's 'aux', and the composite mode includes it (or we're
|
||||
* the last node) ...
|
||||
*/
|
||||
if (has_aux && (included_region & PIKA_LAYER_COMPOSITE_REGION_SOURCE))
|
||||
{
|
||||
PikaLayerCompositeRegion affected_region;
|
||||
|
||||
affected_region =
|
||||
pika_operation_layer_mode_get_affected_region (point);
|
||||
|
||||
/* ... and the op doesn't otherwise affect 'aux', or changes its
|
||||
* alpha ...
|
||||
*/
|
||||
if (! (affected_region & PIKA_LAYER_COMPOSITE_REGION_SOURCE) &&
|
||||
point->opacity == 1.0 &&
|
||||
! gegl_operation_context_get_object (context, "aux2"))
|
||||
{
|
||||
/* pass 'aux' directly as output; */
|
||||
gegl_operation_context_set_object (context, "output", aux);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* otherwise, if the op affects 'aux', or changes its alpha, process
|
||||
* it even though there's no 'input';
|
||||
*/
|
||||
}
|
||||
/* otherwise, there's no 'aux', or the composite mode doesn't include it,
|
||||
* and so ...
|
||||
*/
|
||||
else
|
||||
{
|
||||
/* ... the output is empty. */
|
||||
gegl_operation_context_set_object (context, "output", NULL);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
/* otherwise, if there's 'input' but no 'aux' ... */
|
||||
else if (! has_aux)
|
||||
{
|
||||
/* ... and the composite mode includes 'input' ... */
|
||||
if (included_region & PIKA_LAYER_COMPOSITE_REGION_DESTINATION)
|
||||
{
|
||||
PikaLayerCompositeRegion affected_region;
|
||||
|
||||
affected_region =
|
||||
pika_operation_layer_mode_get_affected_region (point);
|
||||
|
||||
/* ... and the op doesn't otherwise affect 'input' ... */
|
||||
if (! (affected_region & PIKA_LAYER_COMPOSITE_REGION_DESTINATION))
|
||||
{
|
||||
/* pass 'input' directly as output; */
|
||||
gegl_operation_context_set_object (context, "output", input);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* otherwise, if the op affects 'input', process it even though
|
||||
* there's no 'aux';
|
||||
*/
|
||||
}
|
||||
|
||||
/* otherwise, the output is fully transparent, but we process it anyway
|
||||
* to maintain the 'input' color values.
|
||||
*/
|
||||
}
|
||||
|
||||
/* FIXME: we don't actually handle the case where one of the inputs
|
||||
* is NULL -- it'll just segfault. 'input' is not expected to be NULL,
|
||||
* but 'aux' might be, currently.
|
||||
*/
|
||||
if (! input || ! aux)
|
||||
{
|
||||
GObject *empty = G_OBJECT (gegl_buffer_new (NULL, NULL));
|
||||
|
||||
if (! input) gegl_operation_context_set_object (context, "input", empty);
|
||||
if (! aux) gegl_operation_context_set_object (context, "aux", empty);
|
||||
|
||||
if (! input && ! aux)
|
||||
gegl_object_set_has_forked (G_OBJECT (empty));
|
||||
|
||||
g_object_unref (empty);
|
||||
}
|
||||
|
||||
/* chain up, which will create the needed buffers for our actual
|
||||
* process function
|
||||
*/
|
||||
return GEGL_OPERATION_CLASS (parent_class)->process (operation, context,
|
||||
output_prop, result,
|
||||
level);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_operation_layer_mode_real_process (GeglOperation *operation,
|
||||
void *in_p,
|
||||
void *layer_p,
|
||||
void *mask_p,
|
||||
void *out_p,
|
||||
glong samples,
|
||||
const GeglRectangle *roi,
|
||||
gint level)
|
||||
{
|
||||
PikaOperationLayerMode *layer_mode = (gpointer) operation;
|
||||
gfloat *in = in_p;
|
||||
gfloat *out = out_p;
|
||||
gfloat *layer = layer_p;
|
||||
gfloat *mask = mask_p;
|
||||
gfloat opacity = layer_mode->opacity;
|
||||
PikaLayerColorSpace blend_space = layer_mode->blend_space;
|
||||
PikaLayerColorSpace composite_space = layer_mode->composite_space;
|
||||
PikaLayerCompositeMode composite_mode = layer_mode->composite_mode;
|
||||
PikaLayerModeBlendFunc blend_function = layer_mode->blend_function;
|
||||
gboolean composite_needs_in_color;
|
||||
gfloat *blend_in;
|
||||
gfloat *blend_layer;
|
||||
gfloat *blend_out;
|
||||
const Babl *composite_to_blend_fish = NULL;
|
||||
const Babl *blend_to_composite_fish = NULL;
|
||||
|
||||
/* make sure we don't process more than PIKA_COMPOSITE_BLEND_MAX_SAMPLES
|
||||
* at a time, so that we don't overflow the stack if we allocate buffers
|
||||
* on it. note that this has to be done with a nested function call,
|
||||
* because alloca'd buffers remain for the duration of the stack frame.
|
||||
*/
|
||||
while (samples > PIKA_COMPOSITE_BLEND_MAX_SAMPLES)
|
||||
{
|
||||
pika_operation_layer_mode_real_process (operation,
|
||||
in, layer, mask, out,
|
||||
PIKA_COMPOSITE_BLEND_MAX_SAMPLES,
|
||||
roi, level);
|
||||
|
||||
in += 4 * PIKA_COMPOSITE_BLEND_MAX_SAMPLES;
|
||||
layer += 4 * PIKA_COMPOSITE_BLEND_MAX_SAMPLES;
|
||||
if (mask)
|
||||
mask += PIKA_COMPOSITE_BLEND_MAX_SAMPLES;
|
||||
out += 4 * PIKA_COMPOSITE_BLEND_MAX_SAMPLES;
|
||||
|
||||
samples -= PIKA_COMPOSITE_BLEND_MAX_SAMPLES;
|
||||
}
|
||||
|
||||
composite_needs_in_color =
|
||||
composite_mode == PIKA_LAYER_COMPOSITE_UNION ||
|
||||
composite_mode == PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP;
|
||||
|
||||
blend_in = in;
|
||||
blend_layer = layer;
|
||||
blend_out = out;
|
||||
|
||||
if (blend_space != PIKA_LAYER_COLOR_SPACE_AUTO)
|
||||
{
|
||||
pika_assert (composite_space >= 1 && composite_space < 4);
|
||||
pika_assert (blend_space >= 1 && blend_space < 4);
|
||||
|
||||
/* Make sure the cache is set up from the start as the
|
||||
* operation's prepare() method may have not been run yet.
|
||||
*/
|
||||
pika_operation_layer_mode_cache_fishes (layer_mode, NULL);
|
||||
composite_to_blend_fish = layer_mode->space_fish [composite_space - 1]
|
||||
[blend_space - 1];
|
||||
|
||||
blend_to_composite_fish = layer_mode->space_fish [blend_space - 1]
|
||||
[composite_space - 1];
|
||||
}
|
||||
|
||||
/* if we need to convert the samples between the composite and blend
|
||||
* spaces...
|
||||
*/
|
||||
if (composite_to_blend_fish)
|
||||
{
|
||||
gint i;
|
||||
gint end;
|
||||
|
||||
if (in != out || composite_needs_in_color)
|
||||
{
|
||||
/* don't convert input in-place if we're not doing in-place output,
|
||||
* or if we're going to need the original input for compositing.
|
||||
*/
|
||||
blend_in = g_alloca (sizeof (gfloat) * 4 * samples);
|
||||
}
|
||||
blend_layer = g_alloca (sizeof (gfloat) * 4 * samples);
|
||||
|
||||
if (in == out) /* in-place detected, avoid clobbering since we need to
|
||||
read 'in' for the compositing stage */
|
||||
{
|
||||
if (blend_layer != layer)
|
||||
blend_out = blend_layer;
|
||||
else
|
||||
blend_out = g_alloca (sizeof (gfloat) * 4 * samples);
|
||||
}
|
||||
|
||||
/* samples whose the source or destination alpha is zero are not blended,
|
||||
* and therefore do not need to be converted. while it's generally
|
||||
* desirable to perform conversion and blending in bulk, when we have
|
||||
* more than a certain number of consecutive unblended samples, the cost
|
||||
* of converting them outweighs the cost of splitting the process around
|
||||
* them to avoid the conversion.
|
||||
*/
|
||||
|
||||
i = ALPHA;
|
||||
end = 4 * samples + ALPHA;
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
gint first;
|
||||
gint last;
|
||||
gint count;
|
||||
|
||||
/* skip any unblended samples. the color values of `blend_out` for
|
||||
* these samples are unconstrained, in particular, they may be NaN,
|
||||
* but the alpha values should generally be finite, and specifically
|
||||
* 0 when the source alpha is 0.
|
||||
*/
|
||||
while (i < end && (in[i] == 0.0f || layer[i] == 0.0f))
|
||||
{
|
||||
blend_out[i] = 0.0f;
|
||||
i += 4;
|
||||
}
|
||||
|
||||
/* stop if there are no more samples */
|
||||
if (i == end)
|
||||
break;
|
||||
|
||||
/* otherwise, keep scanning the samples until we find
|
||||
* PIKA_COMPOSITE_BLEND_SPLIT_THRESHOLD consecutive unblended
|
||||
* samples.
|
||||
*/
|
||||
|
||||
first = i;
|
||||
i += 4;
|
||||
last = i;
|
||||
|
||||
while (i < end && i - last < 4 * PIKA_COMPOSITE_BLEND_SPLIT_THRESHOLD)
|
||||
{
|
||||
gboolean blended;
|
||||
|
||||
blended = (in[i] != 0.0f && layer[i] != 0.0f);
|
||||
|
||||
i += 4;
|
||||
if (blended)
|
||||
last = i;
|
||||
}
|
||||
|
||||
/* convert and blend the samples in the range [first, last) */
|
||||
|
||||
count = (last - first) / 4;
|
||||
first -= ALPHA;
|
||||
|
||||
babl_process (composite_to_blend_fish,
|
||||
in + first, blend_in + first, count);
|
||||
babl_process (composite_to_blend_fish,
|
||||
layer + first, blend_layer + first, count);
|
||||
|
||||
blend_function (operation, blend_in + first, blend_layer + first,
|
||||
blend_out + first, count);
|
||||
|
||||
babl_process (blend_to_composite_fish,
|
||||
blend_out + first, blend_out + first, count);
|
||||
|
||||
/* make sure the alpha values of `blend_out` are valid for the
|
||||
* trailing unblended samples.
|
||||
*/
|
||||
for (; last < i; last += 4)
|
||||
blend_out[last] = 0.0f;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* if both blending and compositing use the same color space, things are
|
||||
* much simpler.
|
||||
*/
|
||||
|
||||
if (in == out) /* in-place detected, avoid clobbering since we need to
|
||||
read 'in' for the compositing stage */
|
||||
{
|
||||
blend_out = g_alloca (sizeof (gfloat) * 4 * samples);
|
||||
}
|
||||
|
||||
blend_function (operation, blend_in, blend_layer, blend_out, samples);
|
||||
}
|
||||
|
||||
if (! pika_layer_mode_is_subtractive (layer_mode->layer_mode))
|
||||
{
|
||||
switch (composite_mode)
|
||||
{
|
||||
case PIKA_LAYER_COMPOSITE_UNION:
|
||||
case PIKA_LAYER_COMPOSITE_AUTO:
|
||||
composite_union (in, layer, blend_out, mask, opacity,
|
||||
out, samples);
|
||||
break;
|
||||
|
||||
case PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP:
|
||||
composite_clip_to_backdrop (in, layer, blend_out, mask, opacity,
|
||||
out, samples);
|
||||
break;
|
||||
|
||||
case PIKA_LAYER_COMPOSITE_CLIP_TO_LAYER:
|
||||
composite_clip_to_layer (in, layer, blend_out, mask, opacity,
|
||||
out, samples);
|
||||
break;
|
||||
|
||||
case PIKA_LAYER_COMPOSITE_INTERSECTION:
|
||||
composite_intersection (in, layer, blend_out, mask, opacity,
|
||||
out, samples);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (composite_mode)
|
||||
{
|
||||
case PIKA_LAYER_COMPOSITE_UNION:
|
||||
case PIKA_LAYER_COMPOSITE_AUTO:
|
||||
composite_union_sub (in, layer, blend_out, mask, opacity,
|
||||
out, samples);
|
||||
break;
|
||||
|
||||
case PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP:
|
||||
composite_clip_to_backdrop_sub (in, layer, blend_out, mask, opacity,
|
||||
out, samples);
|
||||
break;
|
||||
|
||||
case PIKA_LAYER_COMPOSITE_CLIP_TO_LAYER:
|
||||
composite_clip_to_layer_sub (in, layer, blend_out, mask, opacity,
|
||||
out, samples);
|
||||
break;
|
||||
|
||||
case PIKA_LAYER_COMPOSITE_INTERSECTION:
|
||||
composite_intersection_sub (in, layer, blend_out, mask, opacity,
|
||||
out, samples);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
process_last_node (GeglOperation *operation,
|
||||
void *in_p,
|
||||
void *layer_p,
|
||||
void *mask_p,
|
||||
void *out_p,
|
||||
glong samples,
|
||||
const GeglRectangle *roi,
|
||||
gint level)
|
||||
{
|
||||
gfloat *out = out_p;
|
||||
gfloat *layer = layer_p;
|
||||
gfloat *mask = mask_p;
|
||||
gfloat opacity = PIKA_OPERATION_LAYER_MODE (operation)->opacity;
|
||||
|
||||
while (samples--)
|
||||
{
|
||||
memcpy (out, layer, 3 * sizeof (gfloat));
|
||||
|
||||
out[ALPHA] = layer[ALPHA] * opacity;
|
||||
if (mask)
|
||||
out[ALPHA] *= *mask++;
|
||||
|
||||
layer += 4;
|
||||
out += 4;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_operation_layer_mode_cache_fishes (PikaOperationLayerMode *op,
|
||||
const Babl *preferred_format)
|
||||
{
|
||||
const Babl *format;
|
||||
|
||||
if (! preferred_format)
|
||||
{
|
||||
const GeglRectangle *input_extent;
|
||||
|
||||
input_extent = gegl_operation_source_get_bounding_box (GEGL_OPERATION (op), "input");
|
||||
|
||||
if (input_extent && ! gegl_rectangle_is_empty (input_extent))
|
||||
preferred_format = gegl_operation_get_source_format (GEGL_OPERATION (op), "input");
|
||||
else
|
||||
preferred_format = gegl_operation_get_source_format (GEGL_OPERATION (op), "aux");
|
||||
}
|
||||
|
||||
format = pika_layer_mode_get_format (op->layer_mode,
|
||||
op->blend_space,
|
||||
op->composite_space,
|
||||
op->composite_mode,
|
||||
preferred_format);
|
||||
if (op->cached_fish_format != format)
|
||||
{
|
||||
op->cached_fish_format = format;
|
||||
|
||||
op->space_fish
|
||||
/* from */ [PIKA_LAYER_COLOR_SPACE_RGB_LINEAR - 1]
|
||||
/* to */ [PIKA_LAYER_COLOR_SPACE_RGB_PERCEPTUAL - 1] =
|
||||
babl_fish (babl_format_with_space ("RGBA float", format),
|
||||
babl_format_with_space ("R'G'B'A float", format));
|
||||
op->space_fish
|
||||
/* from */ [PIKA_LAYER_COLOR_SPACE_RGB_LINEAR - 1]
|
||||
/* to */ [PIKA_LAYER_COLOR_SPACE_LAB - 1] =
|
||||
babl_fish (babl_format_with_space ("RGBA float", format),
|
||||
babl_format_with_space ("CIE Lab alpha float", format));
|
||||
|
||||
op->space_fish
|
||||
/* from */ [PIKA_LAYER_COLOR_SPACE_RGB_PERCEPTUAL - 1]
|
||||
/* to */ [PIKA_LAYER_COLOR_SPACE_RGB_LINEAR - 1] =
|
||||
babl_fish (babl_format_with_space("R'G'B'A float", format),
|
||||
babl_format_with_space ( "RGBA float", format));
|
||||
op->space_fish
|
||||
/* from */ [PIKA_LAYER_COLOR_SPACE_RGB_PERCEPTUAL - 1]
|
||||
/* to */ [PIKA_LAYER_COLOR_SPACE_LAB - 1] =
|
||||
babl_fish (babl_format_with_space("R'G'B'A float", format),
|
||||
babl_format_with_space ( "CIE Lab alpha float", format));
|
||||
|
||||
op->space_fish
|
||||
/* from */ [PIKA_LAYER_COLOR_SPACE_LAB - 1]
|
||||
/* to */ [PIKA_LAYER_COLOR_SPACE_RGB_LINEAR - 1] =
|
||||
babl_fish (babl_format_with_space("CIE Lab alpha float", format),
|
||||
babl_format_with_space ( "RGBA float", format));
|
||||
op->space_fish
|
||||
/* from */ [PIKA_LAYER_COLOR_SPACE_LAB - 1]
|
||||
/* to */ [PIKA_LAYER_COLOR_SPACE_RGB_PERCEPTUAL - 1] =
|
||||
babl_fish (babl_format_with_space("CIE Lab alpha float", format),
|
||||
babl_format_with_space ( "R'G'B'A float", format));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* public functions */
|
||||
|
||||
|
||||
PikaLayerCompositeRegion
|
||||
pika_operation_layer_mode_get_affected_region (PikaOperationLayerMode *layer_mode)
|
||||
{
|
||||
PikaOperationLayerModeClass *klass;
|
||||
|
||||
g_return_val_if_fail (PIKA_IS_OPERATION_LAYER_MODE (layer_mode),
|
||||
PIKA_LAYER_COMPOSITE_REGION_INTERSECTION);
|
||||
|
||||
klass = PIKA_OPERATION_LAYER_MODE_GET_CLASS (layer_mode);
|
||||
|
||||
if (klass->get_affected_region)
|
||||
return klass->get_affected_region (layer_mode);
|
||||
|
||||
return PIKA_LAYER_COMPOSITE_REGION_INTERSECTION;
|
||||
}
|
||||
95
app/operations/layer-modes/pikaoperationlayermode.h
Normal file
95
app/operations/layer-modes/pikaoperationlayermode.h
Normal file
@ -0,0 +1,95 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationlayermode.h
|
||||
* Copyright (C) 2008 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* 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 __PIKA_OPERATION_LAYER_MODE_H__
|
||||
#define __PIKA_OPERATION_LAYER_MODE_H__
|
||||
|
||||
|
||||
#include <gegl-plugin.h>
|
||||
|
||||
|
||||
#define PIKA_TYPE_OPERATION_LAYER_MODE (pika_operation_layer_mode_get_type ())
|
||||
#define PIKA_OPERATION_LAYER_MODE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_OPERATION_LAYER_MODE, PikaOperationLayerMode))
|
||||
#define PIKA_OPERATION_LAYER_MODE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_OPERATION_LAYER_MODE, PikaOperationLayerModeClass))
|
||||
#define PIKA_IS_OPERATION_LAYER_MODE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_OPERATION_LAYER_MODE))
|
||||
#define PIKA_IS_OPERATION_LAYER_MODE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_OPERATION_LAYER_MODE))
|
||||
#define PIKA_OPERATION_LAYER_MODE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_OPERATION_LAYER_MODE, PikaOperationLayerModeClass))
|
||||
|
||||
|
||||
typedef struct _PikaOperationLayerModeClass PikaOperationLayerModeClass;
|
||||
|
||||
struct _PikaOperationLayerMode
|
||||
{
|
||||
GeglOperationPointComposer3 parent_instance;
|
||||
|
||||
PikaLayerMode layer_mode;
|
||||
gdouble opacity;
|
||||
PikaLayerColorSpace blend_space;
|
||||
PikaLayerColorSpace composite_space;
|
||||
PikaLayerCompositeMode composite_mode;
|
||||
const Babl *cached_fish_format;
|
||||
const Babl *space_fish[3 /* from */][3 /* to */];
|
||||
|
||||
gdouble prop_opacity;
|
||||
PikaLayerCompositeMode prop_composite_mode;
|
||||
|
||||
PikaLayerModeFunc function;
|
||||
PikaLayerModeBlendFunc blend_function;
|
||||
gboolean is_last_node;
|
||||
gboolean has_mask;
|
||||
};
|
||||
|
||||
struct _PikaOperationLayerModeClass
|
||||
{
|
||||
GeglOperationPointComposer3Class parent_class;
|
||||
|
||||
/* virtual functions */
|
||||
gboolean (* parent_process) (GeglOperation *operation,
|
||||
GeglOperationContext *context,
|
||||
const gchar *output_prop,
|
||||
const GeglRectangle *result,
|
||||
gint level);
|
||||
gboolean (* process) (GeglOperation *operation,
|
||||
void *in,
|
||||
void *aux,
|
||||
void *mask,
|
||||
void *out,
|
||||
glong samples,
|
||||
const GeglRectangle *roi,
|
||||
gint level);
|
||||
|
||||
/* Returns the composite region (any combination of the layer and the
|
||||
* backdrop) that the layer mode affects. Most modes only affect the
|
||||
* overlapping region, and don't need to override this function.
|
||||
*/
|
||||
PikaLayerCompositeRegion (* get_affected_region) (PikaOperationLayerMode *layer_mode);
|
||||
};
|
||||
|
||||
|
||||
GType pika_operation_layer_mode_get_type (void) G_GNUC_CONST;
|
||||
|
||||
PikaLayerCompositeRegion pika_operation_layer_mode_get_affected_region (PikaOperationLayerMode *layer_mode);
|
||||
|
||||
|
||||
#endif /* __PIKA_OPERATION_LAYER_MODE_H__ */
|
||||
247
app/operations/layer-modes/pikaoperationmerge.c
Normal file
247
app/operations/layer-modes/pikaoperationmerge.c
Normal file
@ -0,0 +1,247 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationmerge.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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gegl-plugin.h>
|
||||
|
||||
#include "../operations-types.h"
|
||||
|
||||
#include "pikaoperationmerge.h"
|
||||
|
||||
|
||||
static gboolean pika_operation_merge_process (GeglOperation *op,
|
||||
void *in,
|
||||
void *layer,
|
||||
void *mask,
|
||||
void *out,
|
||||
glong samples,
|
||||
const GeglRectangle *roi,
|
||||
gint level);
|
||||
|
||||
|
||||
G_DEFINE_TYPE (PikaOperationMerge, pika_operation_merge,
|
||||
PIKA_TYPE_OPERATION_LAYER_MODE)
|
||||
|
||||
|
||||
static void
|
||||
pika_operation_merge_class_init (PikaOperationMergeClass *klass)
|
||||
{
|
||||
GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass);
|
||||
PikaOperationLayerModeClass *layer_mode_class = PIKA_OPERATION_LAYER_MODE_CLASS (klass);
|
||||
|
||||
gegl_operation_class_set_keys (operation_class,
|
||||
"name", "pika:merge",
|
||||
"description", "PIKA merge mode operation",
|
||||
NULL);
|
||||
|
||||
layer_mode_class->process = pika_operation_merge_process;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_operation_merge_init (PikaOperationMerge *self)
|
||||
{
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_operation_merge_process (GeglOperation *op,
|
||||
void *in_p,
|
||||
void *layer_p,
|
||||
void *mask_p,
|
||||
void *out_p,
|
||||
glong samples,
|
||||
const GeglRectangle *roi,
|
||||
gint level)
|
||||
{
|
||||
PikaOperationLayerMode *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 PIKA_LAYER_COMPOSITE_UNION:
|
||||
case PIKA_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 PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP:
|
||||
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 PIKA_LAYER_COMPOSITE_CLIP_TO_LAYER:
|
||||
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 PIKA_LAYER_COMPOSITE_INTERSECTION:
|
||||
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;
|
||||
}
|
||||
58
app/operations/layer-modes/pikaoperationmerge.h
Normal file
58
app/operations/layer-modes/pikaoperationmerge.h
Normal file
@ -0,0 +1,58 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationmerge.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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_OPERATION_MERGE_H__
|
||||
#define __PIKA_OPERATION_MERGE_H__
|
||||
|
||||
|
||||
#include "pikaoperationlayermode.h"
|
||||
|
||||
|
||||
#define PIKA_TYPE_OPERATION_MERGE (pika_operation_merge_get_type ())
|
||||
#define PIKA_OPERATION_MERGE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_OPERATION_MERGE, PikaOperationMerge))
|
||||
#define PIKA_OPERATION_MERGE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_OPERATION_MERGE, PikaOperationMergeClass))
|
||||
#define PIKA_IS_OPERATION_MERGE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_OPERATION_MERGE))
|
||||
#define PIKA_IS_OPERATION_MERGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_OPERATION_MERGE))
|
||||
#define PIKA_OPERATION_MERGE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_OPERATION_MERGE, PikaOperationMergeClass))
|
||||
|
||||
|
||||
typedef struct _PikaOperationMerge PikaOperationMerge;
|
||||
typedef struct _PikaOperationMergeClass PikaOperationMergeClass;
|
||||
|
||||
struct _PikaOperationMerge
|
||||
{
|
||||
PikaOperationLayerMode parent_instance;
|
||||
};
|
||||
|
||||
struct _PikaOperationMergeClass
|
||||
{
|
||||
PikaOperationLayerModeClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType pika_operation_merge_get_type (void) G_GNUC_CONST;
|
||||
|
||||
|
||||
#endif /* __PIKA_OPERATION_MERGE_H__ */
|
||||
268
app/operations/layer-modes/pikaoperationnormal-sse2.c
Normal file
268
app/operations/layer-modes/pikaoperationnormal-sse2.c
Normal file
@ -0,0 +1,268 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationnormal-sse2.c
|
||||
* Copyright (C) 2013 Daniel Sabo
|
||||
*
|
||||
* 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 <gegl-plugin.h>
|
||||
|
||||
#include "operations/operations-types.h"
|
||||
|
||||
#include "pikaoperationnormal.h"
|
||||
|
||||
|
||||
#if COMPILE_SSE2_INTRINISICS
|
||||
|
||||
/* SSE2 */
|
||||
#include <emmintrin.h>
|
||||
|
||||
|
||||
gboolean
|
||||
pika_operation_normal_process_sse2 (GeglOperation *op,
|
||||
void *in_p,
|
||||
void *layer_p,
|
||||
void *mask_p,
|
||||
void *out_p,
|
||||
glong samples,
|
||||
const GeglRectangle *roi,
|
||||
gint level)
|
||||
{
|
||||
/* check alignment */
|
||||
if ((((uintptr_t)in_p) | ((uintptr_t)layer_p) | ((uintptr_t)out_p)) & 0x0F)
|
||||
{
|
||||
return pika_operation_normal_process (op,
|
||||
in_p, layer_p, mask_p, out_p,
|
||||
samples, roi, level);
|
||||
}
|
||||
else
|
||||
{
|
||||
PikaOperationLayerMode *layer_mode = (gpointer) op;
|
||||
gfloat opacity = layer_mode->opacity;
|
||||
gfloat *mask = mask_p;
|
||||
const __v4sf *v_in = (const __v4sf*) in_p;
|
||||
const __v4sf *v_layer = (const __v4sf*) layer_p;
|
||||
__v4sf *v_out = ( __v4sf*) out_p;
|
||||
|
||||
const __v4sf one = _mm_set1_ps (1.0f);
|
||||
const __v4sf v_opacity = _mm_set1_ps (opacity);
|
||||
|
||||
switch (layer_mode->composite_mode)
|
||||
{
|
||||
case PIKA_LAYER_COMPOSITE_UNION:
|
||||
case PIKA_LAYER_COMPOSITE_AUTO:
|
||||
while (samples--)
|
||||
{
|
||||
__v4sf rgba_in, rgba_layer, alpha;
|
||||
|
||||
rgba_in = *v_in++;
|
||||
rgba_layer = *v_layer++;
|
||||
|
||||
/* expand alpha */
|
||||
alpha = (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_layer,
|
||||
_MM_SHUFFLE (3, 3, 3, 3));
|
||||
|
||||
if (mask)
|
||||
{
|
||||
__v4sf mask_alpha;
|
||||
|
||||
/* multiply layer's alpha by the mask */
|
||||
mask_alpha = _mm_set1_ps (*mask++);
|
||||
alpha = alpha * mask_alpha;
|
||||
}
|
||||
|
||||
alpha = alpha * v_opacity;
|
||||
|
||||
if (_mm_ucomigt_ss (alpha, _mm_setzero_ps ()))
|
||||
{
|
||||
__v4sf dst_alpha, a_term, out_pixel, out_alpha, out_pixel_rbaa;
|
||||
|
||||
/* expand alpha */
|
||||
dst_alpha = (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_in,
|
||||
_MM_SHUFFLE (3, 3, 3, 3));
|
||||
|
||||
/* a_term = dst_a * (1.0 - src_a) */
|
||||
a_term = dst_alpha * (one - alpha);
|
||||
|
||||
/* out(color) = src * src_a + dst * a_term */
|
||||
out_pixel = rgba_layer * alpha + rgba_in * a_term;
|
||||
|
||||
/* out(alpha) = 1.0 * src_a + 1.0 * a_term */
|
||||
out_alpha = alpha + a_term;
|
||||
|
||||
/* un-premultiply */
|
||||
out_pixel = out_pixel / out_alpha;
|
||||
|
||||
/* swap in the real alpha */
|
||||
out_pixel_rbaa = _mm_shuffle_ps (out_pixel, out_alpha, _MM_SHUFFLE (3, 3, 2, 0));
|
||||
out_pixel = _mm_shuffle_ps (out_pixel, out_pixel_rbaa, _MM_SHUFFLE (2, 1, 1, 0));
|
||||
|
||||
*v_out++ = out_pixel;
|
||||
}
|
||||
else
|
||||
{
|
||||
*v_out++ = rgba_in;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP:
|
||||
while (samples--)
|
||||
{
|
||||
__v4sf rgba_in, rgba_layer, alpha;
|
||||
|
||||
rgba_in = *v_in++;
|
||||
rgba_layer = *v_layer++;
|
||||
|
||||
/* expand alpha */
|
||||
alpha = (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_layer,
|
||||
_MM_SHUFFLE (3, 3, 3, 3));
|
||||
|
||||
if (mask)
|
||||
{
|
||||
__v4sf mask_alpha;
|
||||
|
||||
/* multiply layer's alpha by the mask */
|
||||
mask_alpha = _mm_set1_ps (*mask++);
|
||||
alpha = alpha * mask_alpha;
|
||||
}
|
||||
|
||||
alpha = alpha * v_opacity;
|
||||
|
||||
if (_mm_ucomigt_ss (alpha, _mm_setzero_ps ()))
|
||||
{
|
||||
__v4sf dst_alpha, out_pixel, out_pixel_rbaa;
|
||||
|
||||
/* expand alpha */
|
||||
dst_alpha = (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_in,
|
||||
_MM_SHUFFLE (3, 3, 3, 3));
|
||||
|
||||
/* out(color) = dst * (1 - src_a) + src * src_a */
|
||||
out_pixel = rgba_in + (rgba_layer - rgba_in) * alpha;
|
||||
|
||||
/* swap in the real alpha */
|
||||
out_pixel_rbaa = _mm_shuffle_ps (out_pixel, dst_alpha, _MM_SHUFFLE (3, 3, 2, 0));
|
||||
out_pixel = _mm_shuffle_ps (out_pixel, out_pixel_rbaa, _MM_SHUFFLE (2, 1, 1, 0));
|
||||
|
||||
*v_out++ = out_pixel;
|
||||
}
|
||||
else
|
||||
{
|
||||
*v_out++ = rgba_in;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case PIKA_LAYER_COMPOSITE_CLIP_TO_LAYER:
|
||||
while (samples--)
|
||||
{
|
||||
__v4sf rgba_in, rgba_layer, alpha;
|
||||
__v4sf out_pixel, out_pixel_rbaa;
|
||||
|
||||
rgba_in = *v_in++;
|
||||
rgba_layer = *v_layer++;
|
||||
|
||||
/* expand alpha */
|
||||
alpha = (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_layer,
|
||||
_MM_SHUFFLE (3, 3, 3, 3));
|
||||
|
||||
if (mask)
|
||||
{
|
||||
__v4sf mask_alpha;
|
||||
|
||||
/* multiply layer's alpha by the mask */
|
||||
mask_alpha = _mm_set1_ps (*mask++);
|
||||
alpha = alpha * mask_alpha;
|
||||
}
|
||||
|
||||
alpha = alpha * v_opacity;
|
||||
|
||||
if (_mm_ucomigt_ss (alpha, _mm_setzero_ps ()))
|
||||
{
|
||||
/* out(color) = src */
|
||||
out_pixel = rgba_layer;
|
||||
}
|
||||
else
|
||||
{
|
||||
out_pixel = rgba_in;
|
||||
}
|
||||
|
||||
/* swap in the real alpha */
|
||||
out_pixel_rbaa = _mm_shuffle_ps (out_pixel, alpha, _MM_SHUFFLE (3, 3, 2, 0));
|
||||
out_pixel = _mm_shuffle_ps (out_pixel, out_pixel_rbaa, _MM_SHUFFLE (2, 1, 1, 0));
|
||||
|
||||
*v_out++ = out_pixel;
|
||||
}
|
||||
break;
|
||||
|
||||
case PIKA_LAYER_COMPOSITE_INTERSECTION:
|
||||
while (samples--)
|
||||
{
|
||||
__v4sf rgba_in, rgba_layer, alpha;
|
||||
__v4sf out_pixel, out_pixel_rbaa;
|
||||
|
||||
rgba_in = *v_in++;
|
||||
rgba_layer = *v_layer++;
|
||||
|
||||
/* expand alpha */
|
||||
alpha = (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_layer,
|
||||
_MM_SHUFFLE (3, 3, 3, 3));
|
||||
|
||||
if (mask)
|
||||
{
|
||||
__v4sf mask_alpha;
|
||||
|
||||
/* multiply layer's alpha by the mask */
|
||||
mask_alpha = _mm_set1_ps (*mask++);
|
||||
alpha = alpha * mask_alpha;
|
||||
}
|
||||
|
||||
alpha = alpha * v_opacity;
|
||||
|
||||
/* multiply the alpha by in's alpha */
|
||||
alpha *= (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_in,
|
||||
_MM_SHUFFLE (3, 3, 3, 3));
|
||||
|
||||
if (_mm_ucomigt_ss (alpha, _mm_setzero_ps ()))
|
||||
{
|
||||
/* out(color) = src */
|
||||
out_pixel = rgba_layer;
|
||||
}
|
||||
else
|
||||
{
|
||||
out_pixel = rgba_in;
|
||||
}
|
||||
|
||||
/* swap in the real alpha */
|
||||
out_pixel_rbaa = _mm_shuffle_ps (out_pixel, alpha, _MM_SHUFFLE (3, 3, 2, 0));
|
||||
out_pixel = _mm_shuffle_ps (out_pixel, out_pixel_rbaa, _MM_SHUFFLE (2, 1, 1, 0));
|
||||
|
||||
*v_out++ = out_pixel;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#endif /* COMPILE_SSE2_INTRINISICS */
|
||||
264
app/operations/layer-modes/pikaoperationnormal-sse4.c
Normal file
264
app/operations/layer-modes/pikaoperationnormal-sse4.c
Normal file
@ -0,0 +1,264 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationnormalmode-sse2.c
|
||||
* Copyright (C) 2013 Daniel Sabo
|
||||
*
|
||||
* 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 <gegl-plugin.h>
|
||||
|
||||
#include "operations/operations-types.h"
|
||||
|
||||
#include "pikaoperationnormal.h"
|
||||
|
||||
|
||||
#if COMPILE_SSE4_1_INTRINISICS
|
||||
|
||||
/* SSE4 */
|
||||
#include <smmintrin.h>
|
||||
|
||||
|
||||
gboolean
|
||||
pika_operation_normal_process_sse4 (GeglOperation *op,
|
||||
void *in_p,
|
||||
void *layer_p,
|
||||
void *mask_p,
|
||||
void *out_p,
|
||||
glong samples,
|
||||
const GeglRectangle *roi,
|
||||
gint level)
|
||||
{
|
||||
/* check alignment */
|
||||
if ((((uintptr_t)in_p) | ((uintptr_t)layer_p) | ((uintptr_t)out_p)) & 0x0F)
|
||||
{
|
||||
return pika_operation_normal_process (op,
|
||||
in_p, layer_p, mask_p, out_p,
|
||||
samples, roi, level);
|
||||
}
|
||||
else
|
||||
{
|
||||
PikaOperationLayerMode *layer_mode = (gpointer) op;
|
||||
gfloat opacity = layer_mode->opacity;
|
||||
gfloat *mask = mask_p;
|
||||
const __v4sf *v_in = (const __v4sf*) in_p;
|
||||
const __v4sf *v_layer = (const __v4sf*) layer_p;
|
||||
__v4sf *v_out = ( __v4sf*) out_p;
|
||||
|
||||
const __v4sf one = _mm_set1_ps (1.0f);
|
||||
const __v4sf v_opacity = _mm_set1_ps (opacity);
|
||||
|
||||
switch (layer_mode->composite_mode)
|
||||
{
|
||||
case PIKA_LAYER_COMPOSITE_UNION:
|
||||
case PIKA_LAYER_COMPOSITE_AUTO:
|
||||
while (samples--)
|
||||
{
|
||||
__v4sf rgba_in, rgba_layer, alpha;
|
||||
|
||||
rgba_in = *v_in++;
|
||||
rgba_layer = *v_layer++;
|
||||
|
||||
/* expand alpha */
|
||||
alpha = (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_layer,
|
||||
_MM_SHUFFLE (3, 3, 3, 3));
|
||||
|
||||
if (mask)
|
||||
{
|
||||
__v4sf mask_alpha;
|
||||
|
||||
/* multiply layer's alpha by the mask */
|
||||
mask_alpha = _mm_set1_ps (*mask++);
|
||||
alpha = alpha * mask_alpha;
|
||||
}
|
||||
|
||||
alpha = alpha * v_opacity;
|
||||
|
||||
if (_mm_ucomigt_ss (alpha, _mm_setzero_ps ()))
|
||||
{
|
||||
__v4sf dst_alpha, a_term, out_pixel, out_alpha;
|
||||
|
||||
/* expand alpha */
|
||||
dst_alpha = (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_in,
|
||||
_MM_SHUFFLE (3, 3, 3, 3));
|
||||
|
||||
/* a_term = dst_a * (1.0 - src_a) */
|
||||
a_term = dst_alpha * (one - alpha);
|
||||
|
||||
/* out(color) = src * src_a + dst * a_term */
|
||||
out_pixel = rgba_layer * alpha + rgba_in * a_term;
|
||||
|
||||
/* out(alpha) = 1.0 * src_a + 1.0 * a_term */
|
||||
out_alpha = alpha + a_term;
|
||||
|
||||
/* un-premultiply */
|
||||
out_pixel = out_pixel / out_alpha;
|
||||
|
||||
/* swap in the real alpha */
|
||||
out_pixel = _mm_blend_ps (out_pixel, out_alpha, 0x08);
|
||||
|
||||
*v_out++ = out_pixel;
|
||||
}
|
||||
else
|
||||
{
|
||||
*v_out++ = rgba_in;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP:
|
||||
while (samples--)
|
||||
{
|
||||
__v4sf rgba_in, rgba_layer, alpha;
|
||||
|
||||
rgba_in = *v_in++;
|
||||
rgba_layer = *v_layer++;
|
||||
|
||||
/* expand alpha */
|
||||
alpha = (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_layer,
|
||||
_MM_SHUFFLE (3, 3, 3, 3));
|
||||
|
||||
if (mask)
|
||||
{
|
||||
__v4sf mask_alpha;
|
||||
|
||||
/* multiply layer's alpha by the mask */
|
||||
mask_alpha = _mm_set1_ps (*mask++);
|
||||
alpha = alpha * mask_alpha;
|
||||
}
|
||||
|
||||
alpha = alpha * v_opacity;
|
||||
|
||||
if (_mm_ucomigt_ss (alpha, _mm_setzero_ps ()))
|
||||
{
|
||||
__v4sf dst_alpha, out_pixel;
|
||||
|
||||
/* expand alpha */
|
||||
dst_alpha = (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_in,
|
||||
_MM_SHUFFLE (3, 3, 3, 3));
|
||||
|
||||
/* out(color) = dst * (1 - src_a) + src * src_a */
|
||||
out_pixel = rgba_in + (rgba_layer - rgba_in) * alpha;
|
||||
|
||||
/* swap in the real alpha */
|
||||
out_pixel = _mm_blend_ps (out_pixel, dst_alpha, 0x08);
|
||||
|
||||
*v_out++ = out_pixel;
|
||||
}
|
||||
else
|
||||
{
|
||||
*v_out++ = rgba_in;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case PIKA_LAYER_COMPOSITE_CLIP_TO_LAYER:
|
||||
while (samples--)
|
||||
{
|
||||
__v4sf rgba_in, rgba_layer, alpha;
|
||||
__v4sf out_pixel;
|
||||
|
||||
rgba_in = *v_in++;
|
||||
rgba_layer = *v_layer++;
|
||||
|
||||
/* expand alpha */
|
||||
alpha = (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_layer,
|
||||
_MM_SHUFFLE (3, 3, 3, 3));
|
||||
|
||||
if (mask)
|
||||
{
|
||||
__v4sf mask_alpha;
|
||||
|
||||
/* multiply layer's alpha by the mask */
|
||||
mask_alpha = _mm_set1_ps (*mask++);
|
||||
alpha = alpha * mask_alpha;
|
||||
}
|
||||
|
||||
alpha = alpha * v_opacity;
|
||||
|
||||
if (_mm_ucomigt_ss (alpha, _mm_setzero_ps ()))
|
||||
{
|
||||
/* out(color) = src */
|
||||
out_pixel = rgba_layer;
|
||||
}
|
||||
else
|
||||
{
|
||||
out_pixel = rgba_in;
|
||||
}
|
||||
|
||||
/* swap in the real alpha */
|
||||
out_pixel = _mm_blend_ps (out_pixel, alpha, 0x08);
|
||||
|
||||
*v_out++ = out_pixel;
|
||||
}
|
||||
break;
|
||||
|
||||
case PIKA_LAYER_COMPOSITE_INTERSECTION:
|
||||
while (samples--)
|
||||
{
|
||||
__v4sf rgba_in, rgba_layer, alpha;
|
||||
__v4sf out_pixel;
|
||||
|
||||
rgba_in = *v_in++;
|
||||
rgba_layer = *v_layer++;
|
||||
|
||||
/* expand alpha */
|
||||
alpha = (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_layer,
|
||||
_MM_SHUFFLE (3, 3, 3, 3));
|
||||
|
||||
if (mask)
|
||||
{
|
||||
__v4sf mask_alpha;
|
||||
|
||||
/* multiply layer's alpha by the mask */
|
||||
mask_alpha = _mm_set1_ps (*mask++);
|
||||
alpha = alpha * mask_alpha;
|
||||
}
|
||||
|
||||
alpha = alpha * v_opacity;
|
||||
|
||||
/* multiply the alpha by in's alpha */
|
||||
alpha *= (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_in,
|
||||
_MM_SHUFFLE (3, 3, 3, 3));
|
||||
|
||||
if (_mm_ucomigt_ss (alpha, _mm_setzero_ps ()))
|
||||
{
|
||||
/* out(color) = src */
|
||||
out_pixel = rgba_layer;
|
||||
}
|
||||
else
|
||||
{
|
||||
out_pixel = rgba_in;
|
||||
}
|
||||
|
||||
/* swap in the real alpha */
|
||||
out_pixel = _mm_blend_ps (out_pixel, alpha, 0x08);
|
||||
|
||||
*v_out++ = out_pixel;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#endif /* COMPILE_SSE4_1_INTRINISICS */
|
||||
270
app/operations/layer-modes/pikaoperationnormal.c
Normal file
270
app/operations/layer-modes/pikaoperationnormal.c
Normal file
@ -0,0 +1,270 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationnormalmode.c
|
||||
* Copyright (C) 2012 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* 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 <gio/gio.h>
|
||||
#include <gegl-plugin.h>
|
||||
|
||||
#include "libpikabase/pikabase.h"
|
||||
|
||||
#include "../operations-types.h"
|
||||
|
||||
#include "pikaoperationnormal.h"
|
||||
|
||||
|
||||
G_DEFINE_TYPE (PikaOperationNormal, pika_operation_normal,
|
||||
PIKA_TYPE_OPERATION_LAYER_MODE)
|
||||
|
||||
|
||||
static const gchar* reference_xml = "<?xml version='1.0' encoding='UTF-8'?>"
|
||||
"<gegl>"
|
||||
"<node operation='pika:normal'>"
|
||||
" <node operation='gegl:load'>"
|
||||
" <params>"
|
||||
" <param name='path'>blending-test-B.png</param>"
|
||||
" </params>"
|
||||
" </node>"
|
||||
"</node>"
|
||||
"<node operation='gegl:load'>"
|
||||
" <params>"
|
||||
" <param name='path'>blending-test-A.png</param>"
|
||||
" </params>"
|
||||
"</node>"
|
||||
"</gegl>";
|
||||
|
||||
|
||||
static void
|
||||
pika_operation_normal_class_init (PikaOperationNormalClass *klass)
|
||||
{
|
||||
GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass);
|
||||
PikaOperationLayerModeClass *layer_mode_class = PIKA_OPERATION_LAYER_MODE_CLASS (klass);
|
||||
|
||||
gegl_operation_class_set_keys (operation_class,
|
||||
"name", "pika:normal",
|
||||
"description", "PIKA normal mode operation",
|
||||
"reference-image", "normal-mode.png",
|
||||
"reference-composition", reference_xml,
|
||||
NULL);
|
||||
|
||||
layer_mode_class->process = pika_operation_normal_process;
|
||||
|
||||
#if COMPILE_SSE2_INTRINISICS
|
||||
if (pika_cpu_accel_get_support() & PIKA_CPU_ACCEL_X86_SSE2)
|
||||
layer_mode_class->process = pika_operation_normal_process_sse2;
|
||||
#endif /* COMPILE_SSE2_INTRINISICS */
|
||||
|
||||
#if COMPILE_SSE4_1_INTRINISICS
|
||||
if (pika_cpu_accel_get_support() & PIKA_CPU_ACCEL_X86_SSE4_1)
|
||||
layer_mode_class->process = pika_operation_normal_process_sse4;
|
||||
#endif /* COMPILE_SSE4_1_INTRINISICS */
|
||||
}
|
||||
|
||||
static void
|
||||
pika_operation_normal_init (PikaOperationNormal *self)
|
||||
{
|
||||
}
|
||||
|
||||
gboolean
|
||||
pika_operation_normal_process (GeglOperation *op,
|
||||
void *in_p,
|
||||
void *layer_p,
|
||||
void *mask_p,
|
||||
void *out_p,
|
||||
glong samples,
|
||||
const GeglRectangle *roi,
|
||||
gint level)
|
||||
{
|
||||
PikaOperationLayerMode *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 PIKA_LAYER_COMPOSITE_UNION:
|
||||
case PIKA_LAYER_COMPOSITE_AUTO:
|
||||
while (samples--)
|
||||
{
|
||||
gfloat layer_alpha;
|
||||
|
||||
layer_alpha = layer[ALPHA] * opacity;
|
||||
if (has_mask)
|
||||
layer_alpha *= *mask;
|
||||
|
||||
out[ALPHA] = layer_alpha + in[ALPHA] - layer_alpha * in[ALPHA];
|
||||
|
||||
if (out[ALPHA])
|
||||
{
|
||||
gfloat layer_weight = layer_alpha / out[ALPHA];
|
||||
gfloat in_weight = 1.0f - layer_weight;
|
||||
gint b;
|
||||
|
||||
for (b = RED; b < ALPHA; b++)
|
||||
{
|
||||
out[b] = layer[b] * layer_weight + in[b] * in_weight;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
gint b;
|
||||
|
||||
for (b = RED; b < ALPHA; b++)
|
||||
{
|
||||
out[b] = in[b];
|
||||
}
|
||||
}
|
||||
|
||||
in += 4;
|
||||
layer += 4;
|
||||
out += 4;
|
||||
|
||||
if (has_mask)
|
||||
mask++;
|
||||
}
|
||||
break;
|
||||
|
||||
case PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP:
|
||||
while (samples--)
|
||||
{
|
||||
gfloat layer_alpha;
|
||||
|
||||
layer_alpha = layer[ALPHA] * opacity;
|
||||
if (has_mask)
|
||||
layer_alpha *= *mask;
|
||||
|
||||
out[ALPHA] = in[ALPHA];
|
||||
|
||||
if (out[ALPHA])
|
||||
{
|
||||
gint b;
|
||||
|
||||
for (b = RED; b < ALPHA; b++)
|
||||
{
|
||||
out[b] = in[b] + (layer[b] - in[b]) * layer_alpha;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
gint b;
|
||||
|
||||
for (b = RED; b < ALPHA; b++)
|
||||
{
|
||||
out[b] = in[b];
|
||||
}
|
||||
}
|
||||
|
||||
in += 4;
|
||||
layer += 4;
|
||||
out += 4;
|
||||
|
||||
if (has_mask)
|
||||
mask++;
|
||||
}
|
||||
break;
|
||||
|
||||
case PIKA_LAYER_COMPOSITE_CLIP_TO_LAYER:
|
||||
while (samples--)
|
||||
{
|
||||
gfloat layer_alpha;
|
||||
|
||||
layer_alpha = layer[ALPHA] * opacity;
|
||||
if (has_mask)
|
||||
layer_alpha *= *mask;
|
||||
|
||||
out[ALPHA] = layer_alpha;
|
||||
|
||||
if (out[ALPHA])
|
||||
{
|
||||
gint b;
|
||||
|
||||
for (b = RED; b < ALPHA; b++)
|
||||
{
|
||||
out[b] = layer[b];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
gint b;
|
||||
|
||||
for (b = RED; b < ALPHA; b++)
|
||||
{
|
||||
out[b] = in[b];
|
||||
}
|
||||
}
|
||||
|
||||
in += 4;
|
||||
layer += 4;
|
||||
out += 4;
|
||||
|
||||
if (has_mask)
|
||||
mask++;
|
||||
}
|
||||
break;
|
||||
|
||||
case PIKA_LAYER_COMPOSITE_INTERSECTION:
|
||||
while (samples--)
|
||||
{
|
||||
gfloat layer_alpha;
|
||||
|
||||
layer_alpha = layer[ALPHA] * opacity;
|
||||
if (has_mask)
|
||||
layer_alpha *= *mask;
|
||||
|
||||
out[ALPHA] = in[ALPHA] * layer_alpha;
|
||||
|
||||
if (out[ALPHA])
|
||||
{
|
||||
gint b;
|
||||
|
||||
for (b = RED; b < ALPHA; b++)
|
||||
{
|
||||
out[b] = layer[b];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
gint b;
|
||||
|
||||
for (b = RED; b < ALPHA; b++)
|
||||
{
|
||||
out[b] = in[b];
|
||||
}
|
||||
}
|
||||
|
||||
in += 4;
|
||||
layer += 4;
|
||||
out += 4;
|
||||
|
||||
if (has_mask)
|
||||
mask++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
95
app/operations/layer-modes/pikaoperationnormal.h
Normal file
95
app/operations/layer-modes/pikaoperationnormal.h
Normal file
@ -0,0 +1,95 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationnormal.h
|
||||
* Copyright (C) 2012 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* 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 __PIKA_OPERATION_NORMAL_H__
|
||||
#define __PIKA_OPERATION_NORMAL_H__
|
||||
|
||||
|
||||
#include "pikaoperationlayermode.h"
|
||||
|
||||
|
||||
#define PIKA_TYPE_OPERATION_NORMAL (pika_operation_normal_get_type ())
|
||||
#define PIKA_OPERATION_NORMAL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_OPERATION_NORMAL, PikaOperationNormal))
|
||||
#define PIKA_OPERATION_NORMAL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_OPERATION_NORMAL, PikaOperationNormalClass))
|
||||
#define PIKA_IS_OPERATION_NORMAL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_OPERATION_NORMAL))
|
||||
#define PIKA_IS_OPERATION_NORMAL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_OPERATION_NORMAL))
|
||||
#define PIKA_OPERATION_NORMAL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_OPERATION_NORMAL, PikaOperationNormalClass))
|
||||
|
||||
|
||||
typedef struct _PikaOperationNormal PikaOperationNormal;
|
||||
typedef struct _PikaOperationNormalClass PikaOperationNormalClass;
|
||||
|
||||
struct _PikaOperationNormal
|
||||
{
|
||||
PikaOperationLayerMode parent_instance;
|
||||
};
|
||||
|
||||
struct _PikaOperationNormalClass
|
||||
{
|
||||
PikaOperationLayerModeClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType pika_operation_normal_get_type (void) G_GNUC_CONST;
|
||||
|
||||
|
||||
/* protected */
|
||||
|
||||
gboolean pika_operation_normal_process (GeglOperation *op,
|
||||
void *in,
|
||||
void *layer,
|
||||
void *mask,
|
||||
void *out,
|
||||
glong samples,
|
||||
const GeglRectangle *roi,
|
||||
gint level);
|
||||
|
||||
#if COMPILE_SSE2_INTRINISICS
|
||||
|
||||
gboolean pika_operation_normal_process_sse2 (GeglOperation *op,
|
||||
void *in,
|
||||
void *layer,
|
||||
void *mask,
|
||||
void *out,
|
||||
glong samples,
|
||||
const GeglRectangle *roi,
|
||||
gint level);
|
||||
|
||||
#endif /* COMPILE_SSE2_INTRINISICS */
|
||||
|
||||
#if COMPILE_SSE4_1_INTRINISICS
|
||||
|
||||
gboolean pika_operation_normal_process_sse4 (GeglOperation *op,
|
||||
void *in,
|
||||
void *layer,
|
||||
void *mask,
|
||||
void *out,
|
||||
glong samples,
|
||||
const GeglRectangle *roi,
|
||||
gint level);
|
||||
|
||||
#endif /* COMPILE_SSE4_1_INTRINISICS */
|
||||
|
||||
|
||||
#endif /* __PIKA_OPERATION_NORMAL_H__ */
|
||||
59
app/operations/layer-modes/pikaoperationpassthrough.c
Normal file
59
app/operations/layer-modes/pikaoperationpassthrough.c
Normal file
@ -0,0 +1,59 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationpassthrough.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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gegl-plugin.h>
|
||||
|
||||
#include "../operations-types.h"
|
||||
|
||||
#include "pikaoperationpassthrough.h"
|
||||
|
||||
|
||||
G_DEFINE_TYPE (PikaOperationPassThrough, pika_operation_pass_through,
|
||||
PIKA_TYPE_OPERATION_REPLACE)
|
||||
|
||||
|
||||
static void
|
||||
pika_operation_pass_through_class_init (PikaOperationPassThroughClass *klass)
|
||||
{
|
||||
GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass);
|
||||
PikaOperationLayerModeClass *layer_mode_class = PIKA_OPERATION_LAYER_MODE_CLASS (klass);
|
||||
|
||||
gegl_operation_class_set_keys (operation_class,
|
||||
"name", "pika:pass-through",
|
||||
"description", "PIKA pass through mode operation",
|
||||
NULL);
|
||||
|
||||
/* don't use REPLACE mode's specialized get_affected_region(); PASS_THROUGH
|
||||
* behaves like an ordinary layer mode here.
|
||||
*/
|
||||
layer_mode_class->get_affected_region = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_operation_pass_through_init (PikaOperationPassThrough *self)
|
||||
{
|
||||
}
|
||||
58
app/operations/layer-modes/pikaoperationpassthrough.h
Normal file
58
app/operations/layer-modes/pikaoperationpassthrough.h
Normal file
@ -0,0 +1,58 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationpassthrough.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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_OPERATION_PASS_THROUGH_H__
|
||||
#define __PIKA_OPERATION_PASS_THROUGH_H__
|
||||
|
||||
|
||||
#include "pikaoperationreplace.h"
|
||||
|
||||
|
||||
#define PIKA_TYPE_OPERATION_PASS_THROUGH (pika_operation_pass_through_get_type ())
|
||||
#define PIKA_OPERATION_PASS_THROUGH(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_OPERATION_PASS_THROUGH, PikaOperationPassThrough))
|
||||
#define PIKA_OPERATION_PASS_THROUGH_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_OPERATION_PASS_THROUGH, PikaOperationPassThroughClass))
|
||||
#define PIKA_IS_OPERATION_PASS_THROUGH(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_OPERATION_PASS_THROUGH))
|
||||
#define PIKA_IS_OPERATION_PASS_THROUGH_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_OPERATION_PASS_THROUGH))
|
||||
#define PIKA_OPERATION_PASS_THROUGH_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_OPERATION_PASS_THROUGH, PikaOperationPassThroughClass))
|
||||
|
||||
|
||||
typedef struct _PikaOperationPassThrough PikaOperationPassThrough;
|
||||
typedef struct _PikaOperationPassThroughClass PikaOperationPassThroughClass;
|
||||
|
||||
struct _PikaOperationPassThrough
|
||||
{
|
||||
PikaOperationReplace parent_instance;
|
||||
};
|
||||
|
||||
struct _PikaOperationPassThroughClass
|
||||
{
|
||||
PikaOperationReplaceClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType pika_operation_pass_through_get_type (void) G_GNUC_CONST;
|
||||
|
||||
|
||||
#endif /* __PIKA_OPERATION_PASS_THROUGH_H__ */
|
||||
351
app/operations/layer-modes/pikaoperationreplace.c
Normal file
351
app/operations/layer-modes/pikaoperationreplace.c
Normal file
@ -0,0 +1,351 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationreplace.c
|
||||
* Copyright (C) 2008 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* 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 <string.h>
|
||||
|
||||
#include <gegl-plugin.h>
|
||||
|
||||
#include "../operations-types.h"
|
||||
|
||||
#include "pika-layer-modes.h"
|
||||
#include "pikaoperationreplace.h"
|
||||
|
||||
|
||||
static GeglRectangle pika_operation_replace_get_bounding_box (GeglOperation *op);
|
||||
|
||||
static gboolean pika_operation_replace_parent_process (GeglOperation *op,
|
||||
GeglOperationContext *context,
|
||||
const gchar *output_prop,
|
||||
const GeglRectangle *result,
|
||||
gint level);
|
||||
static gboolean pika_operation_replace_process (GeglOperation *op,
|
||||
void *in,
|
||||
void *layer,
|
||||
void *mask,
|
||||
void *out,
|
||||
glong samples,
|
||||
const GeglRectangle *roi,
|
||||
gint level);
|
||||
static PikaLayerCompositeRegion pika_operation_replace_get_affected_region (PikaOperationLayerMode *layer_mode);
|
||||
|
||||
|
||||
G_DEFINE_TYPE (PikaOperationReplace, pika_operation_replace,
|
||||
PIKA_TYPE_OPERATION_LAYER_MODE)
|
||||
|
||||
#define parent_class pika_operation_replace_parent_class
|
||||
|
||||
|
||||
static void
|
||||
pika_operation_replace_class_init (PikaOperationReplaceClass *klass)
|
||||
{
|
||||
GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass);
|
||||
PikaOperationLayerModeClass *layer_mode_class = PIKA_OPERATION_LAYER_MODE_CLASS (klass);
|
||||
|
||||
gegl_operation_class_set_keys (operation_class,
|
||||
"name", "pika:replace",
|
||||
"description", "PIKA replace mode operation",
|
||||
NULL);
|
||||
|
||||
operation_class->get_bounding_box = pika_operation_replace_get_bounding_box;
|
||||
|
||||
layer_mode_class->parent_process = pika_operation_replace_parent_process;
|
||||
layer_mode_class->process = pika_operation_replace_process;
|
||||
layer_mode_class->get_affected_region = pika_operation_replace_get_affected_region;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_operation_replace_init (PikaOperationReplace *self)
|
||||
{
|
||||
}
|
||||
|
||||
static GeglRectangle
|
||||
pika_operation_replace_get_bounding_box (GeglOperation *op)
|
||||
{
|
||||
PikaOperationLayerMode *self = (gpointer) op;
|
||||
GeglRectangle *in_rect;
|
||||
GeglRectangle *aux_rect;
|
||||
GeglRectangle *aux2_rect;
|
||||
GeglRectangle src_rect = {};
|
||||
GeglRectangle dst_rect = {};
|
||||
GeglRectangle result;
|
||||
PikaLayerCompositeRegion included_region;
|
||||
|
||||
in_rect = gegl_operation_source_get_bounding_box (op, "input");
|
||||
aux_rect = gegl_operation_source_get_bounding_box (op, "aux");
|
||||
aux2_rect = gegl_operation_source_get_bounding_box (op, "aux2");
|
||||
|
||||
if (in_rect)
|
||||
dst_rect = *in_rect;
|
||||
|
||||
if (aux_rect)
|
||||
{
|
||||
src_rect = *aux_rect;
|
||||
|
||||
if (aux2_rect)
|
||||
gegl_rectangle_intersect (&src_rect, &src_rect, aux2_rect);
|
||||
}
|
||||
|
||||
if (self->is_last_node)
|
||||
{
|
||||
included_region = PIKA_LAYER_COMPOSITE_REGION_SOURCE;
|
||||
}
|
||||
else
|
||||
{
|
||||
included_region = pika_layer_mode_get_included_region (self->layer_mode,
|
||||
self->composite_mode);
|
||||
}
|
||||
|
||||
if (self->prop_opacity == 0.0)
|
||||
included_region &= ~PIKA_LAYER_COMPOSITE_REGION_SOURCE;
|
||||
else if (self->prop_opacity == 1.0 && ! aux2_rect)
|
||||
included_region &= ~PIKA_LAYER_COMPOSITE_REGION_DESTINATION;
|
||||
|
||||
gegl_rectangle_intersect (&result, &src_rect, &dst_rect);
|
||||
|
||||
if (included_region & PIKA_LAYER_COMPOSITE_REGION_SOURCE)
|
||||
gegl_rectangle_bounding_box (&result, &result, &src_rect);
|
||||
|
||||
if (included_region & PIKA_LAYER_COMPOSITE_REGION_DESTINATION)
|
||||
gegl_rectangle_bounding_box (&result, &result, &dst_rect);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_operation_replace_parent_process (GeglOperation *op,
|
||||
GeglOperationContext *context,
|
||||
const gchar *output_prop,
|
||||
const GeglRectangle *result,
|
||||
gint level)
|
||||
{
|
||||
PikaOperationLayerMode *layer_mode = (gpointer) op;
|
||||
PikaLayerCompositeRegion included_region;
|
||||
|
||||
included_region = pika_layer_mode_get_included_region
|
||||
(layer_mode->layer_mode, layer_mode->composite_mode);
|
||||
|
||||
/* if the layer's opacity is 100%, it has no mask, and its composite mode
|
||||
* contains "aux" (the latter should always be the case in practice,
|
||||
* currently,) we can just pass "aux" directly as output.
|
||||
*/
|
||||
if (layer_mode->opacity == 1.0 &&
|
||||
! gegl_operation_context_get_object (context, "aux2") &&
|
||||
(included_region & PIKA_LAYER_COMPOSITE_REGION_SOURCE))
|
||||
{
|
||||
GObject *aux;
|
||||
|
||||
aux = gegl_operation_context_get_object (context, "aux");
|
||||
|
||||
gegl_operation_context_set_object (context, "output", aux);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
/* the opposite case, where the opacity is 0%, is handled by
|
||||
* PikaOperationLayerMode.
|
||||
*/
|
||||
else if (layer_mode->opacity == 0.0)
|
||||
{
|
||||
}
|
||||
/* if both buffers are included in the result, and if both of them have the
|
||||
* same content -- i.e., if they share the same storage, same alignment, and
|
||||
* same abyss (or if the abyss is irrelevant) -- we can just pass either of
|
||||
* them directly as output.
|
||||
*/
|
||||
else if (included_region == PIKA_LAYER_COMPOSITE_REGION_UNION)
|
||||
{
|
||||
GObject *input;
|
||||
GObject *aux;
|
||||
|
||||
input = gegl_operation_context_get_object (context, "input");
|
||||
aux = gegl_operation_context_get_object (context, "aux");
|
||||
|
||||
if (input && aux &&
|
||||
gegl_buffer_share_storage (GEGL_BUFFER (input), GEGL_BUFFER (aux)))
|
||||
{
|
||||
gint input_shift_x;
|
||||
gint input_shift_y;
|
||||
gint aux_shift_x;
|
||||
gint aux_shift_y;
|
||||
|
||||
g_object_get (input,
|
||||
"shift-x", &input_shift_x,
|
||||
"shift-y", &input_shift_y,
|
||||
NULL);
|
||||
g_object_get (aux,
|
||||
"shift-x", &aux_shift_x,
|
||||
"shift-y", &aux_shift_y,
|
||||
NULL);
|
||||
|
||||
if (input_shift_x == aux_shift_x && input_shift_y == aux_shift_y)
|
||||
{
|
||||
const GeglRectangle *input_abyss;
|
||||
const GeglRectangle *aux_abyss;
|
||||
|
||||
input_abyss = gegl_buffer_get_abyss (GEGL_BUFFER (input));
|
||||
aux_abyss = gegl_buffer_get_abyss (GEGL_BUFFER (aux));
|
||||
|
||||
if (gegl_rectangle_equal (input_abyss, aux_abyss) ||
|
||||
(gegl_rectangle_contains (input_abyss, result) &&
|
||||
gegl_rectangle_contains (aux_abyss, result)))
|
||||
{
|
||||
gegl_operation_context_set_object (context, "output", input);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return PIKA_OPERATION_LAYER_MODE_CLASS (parent_class)->parent_process (
|
||||
op, context, output_prop, result, level);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_operation_replace_process (GeglOperation *op,
|
||||
void *in_p,
|
||||
void *layer_p,
|
||||
void *mask_p,
|
||||
void *out_p,
|
||||
glong samples,
|
||||
const GeglRectangle *roi,
|
||||
gint level)
|
||||
{
|
||||
PikaOperationLayerMode *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 PIKA_LAYER_COMPOSITE_UNION:
|
||||
case PIKA_LAYER_COMPOSITE_AUTO:
|
||||
while (samples--)
|
||||
{
|
||||
gfloat opacity_value = opacity;
|
||||
gfloat new_alpha;
|
||||
gfloat ratio;
|
||||
gint b;
|
||||
|
||||
if (has_mask)
|
||||
opacity_value *= *mask;
|
||||
|
||||
new_alpha = (layer[ALPHA] - in[ALPHA]) * opacity_value + in[ALPHA];
|
||||
|
||||
ratio = opacity_value;
|
||||
|
||||
if (new_alpha)
|
||||
ratio *= layer[ALPHA] / new_alpha;
|
||||
|
||||
for (b = RED; b < ALPHA; b++)
|
||||
out[b] = (layer[b] - in[b]) * ratio + in[b];
|
||||
|
||||
out[ALPHA] = new_alpha;
|
||||
|
||||
in += 4;
|
||||
layer += 4;
|
||||
out += 4;
|
||||
|
||||
if (has_mask)
|
||||
mask++;
|
||||
}
|
||||
break;
|
||||
|
||||
case PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP:
|
||||
while (samples--)
|
||||
{
|
||||
gfloat opacity_value = opacity;
|
||||
gfloat new_alpha;
|
||||
gint b;
|
||||
|
||||
if (has_mask)
|
||||
opacity_value *= *mask;
|
||||
|
||||
new_alpha = in[ALPHA] * (1.0f - opacity_value);
|
||||
|
||||
for (b = RED; b < ALPHA; b++)
|
||||
out[b] = in[b];
|
||||
|
||||
out[ALPHA] = new_alpha;
|
||||
|
||||
in += 4;
|
||||
out += 4;
|
||||
|
||||
if (has_mask)
|
||||
mask++;
|
||||
}
|
||||
break;
|
||||
|
||||
case PIKA_LAYER_COMPOSITE_CLIP_TO_LAYER:
|
||||
while (samples--)
|
||||
{
|
||||
gfloat opacity_value = opacity;
|
||||
gfloat new_alpha;
|
||||
gint b;
|
||||
|
||||
if (has_mask)
|
||||
opacity_value *= *mask;
|
||||
|
||||
new_alpha = layer[ALPHA] * opacity_value;
|
||||
|
||||
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 PIKA_LAYER_COMPOSITE_INTERSECTION:
|
||||
memset (out, 0, 4 * samples * sizeof (gfloat));
|
||||
break;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static PikaLayerCompositeRegion
|
||||
pika_operation_replace_get_affected_region (PikaOperationLayerMode *layer_mode)
|
||||
{
|
||||
PikaLayerCompositeRegion affected_region = PIKA_LAYER_COMPOSITE_REGION_INTERSECTION;
|
||||
|
||||
if (layer_mode->prop_opacity != 0.0)
|
||||
affected_region |= PIKA_LAYER_COMPOSITE_REGION_DESTINATION;
|
||||
|
||||
/* if opacity != 1.0, or we have a mask, then we also affect SOURCE, but this
|
||||
* is considered the case anyway, so no need for special handling.
|
||||
*/
|
||||
|
||||
return affected_region;
|
||||
}
|
||||
57
app/operations/layer-modes/pikaoperationreplace.h
Normal file
57
app/operations/layer-modes/pikaoperationreplace.h
Normal file
@ -0,0 +1,57 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationreplace.h
|
||||
* Copyright (C) 2008 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* 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 __PIKA_OPERATION_REPLACE_H__
|
||||
#define __PIKA_OPERATION_REPLACE_H__
|
||||
|
||||
|
||||
#include "pikaoperationlayermode.h"
|
||||
|
||||
|
||||
#define PIKA_TYPE_OPERATION_REPLACE (pika_operation_replace_get_type ())
|
||||
#define PIKA_OPERATION_REPLACE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_OPERATION_REPLACE, PikaOperationReplace))
|
||||
#define PIKA_OPERATION_REPLACE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_OPERATION_REPLACE, PikaOperationReplaceClass))
|
||||
#define PIKA_IS_OPERATION_REPLACE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_OPERATION_REPLACE))
|
||||
#define PIKA_IS_OPERATION_REPLACE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_OPERATION_REPLACE))
|
||||
#define PIKA_OPERATION_REPLACE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_OPERATION_REPLACE, PikaOperationReplaceClass))
|
||||
|
||||
|
||||
typedef struct _PikaOperationReplace PikaOperationReplace;
|
||||
typedef struct _PikaOperationReplaceClass PikaOperationReplaceClass;
|
||||
|
||||
struct _PikaOperationReplace
|
||||
{
|
||||
PikaOperationLayerMode parent_instance;
|
||||
};
|
||||
|
||||
struct _PikaOperationReplaceClass
|
||||
{
|
||||
PikaOperationLayerModeClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType pika_operation_replace_get_type (void) G_GNUC_CONST;
|
||||
|
||||
|
||||
#endif /* __PIKA_OPERATION_REPLACE_H__ */
|
||||
217
app/operations/layer-modes/pikaoperationsplit.c
Normal file
217
app/operations/layer-modes/pikaoperationsplit.c
Normal file
@ -0,0 +1,217 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationsplit.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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gegl-plugin.h>
|
||||
|
||||
#include "../operations-types.h"
|
||||
|
||||
#include "pikaoperationsplit.h"
|
||||
|
||||
|
||||
static gboolean pika_operation_split_process (GeglOperation *op,
|
||||
void *in,
|
||||
void *layer,
|
||||
void *mask,
|
||||
void *out,
|
||||
glong samples,
|
||||
const GeglRectangle *roi,
|
||||
gint level);
|
||||
|
||||
|
||||
G_DEFINE_TYPE (PikaOperationSplit, pika_operation_split,
|
||||
PIKA_TYPE_OPERATION_LAYER_MODE)
|
||||
|
||||
|
||||
static void
|
||||
pika_operation_split_class_init (PikaOperationSplitClass *klass)
|
||||
{
|
||||
GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass);
|
||||
PikaOperationLayerModeClass *layer_mode_class = PIKA_OPERATION_LAYER_MODE_CLASS (klass);
|
||||
|
||||
gegl_operation_class_set_keys (operation_class,
|
||||
"name", "pika:split",
|
||||
"description", "PIKA split mode operation",
|
||||
NULL);
|
||||
|
||||
layer_mode_class->process = pika_operation_split_process;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_operation_split_init (PikaOperationSplit *self)
|
||||
{
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_operation_split_process (GeglOperation *op,
|
||||
void *in_p,
|
||||
void *layer_p,
|
||||
void *mask_p,
|
||||
void *out_p,
|
||||
glong samples,
|
||||
const GeglRectangle *roi,
|
||||
gint level)
|
||||
{
|
||||
PikaOperationLayerMode *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 PIKA_LAYER_COMPOSITE_UNION:
|
||||
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 PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP:
|
||||
case PIKA_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 PIKA_LAYER_COMPOSITE_CLIP_TO_LAYER:
|
||||
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 PIKA_LAYER_COMPOSITE_INTERSECTION:
|
||||
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;
|
||||
}
|
||||
58
app/operations/layer-modes/pikaoperationsplit.h
Normal file
58
app/operations/layer-modes/pikaoperationsplit.h
Normal file
@ -0,0 +1,58 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationsplit.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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_OPERATION_SPLIT_H__
|
||||
#define __PIKA_OPERATION_SPLIT_H__
|
||||
|
||||
|
||||
#include "pikaoperationlayermode.h"
|
||||
|
||||
|
||||
#define PIKA_TYPE_OPERATION_SPLIT (pika_operation_split_get_type ())
|
||||
#define PIKA_OPERATION_SPLIT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_OPERATION_SPLIT, PikaOperationSplit))
|
||||
#define PIKA_OPERATION_SPLIT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_OPERATION_SPLIT, PikaOperationSplitClass))
|
||||
#define PIKA_IS_OPERATION_SPLIT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_OPERATION_SPLIT))
|
||||
#define PIKA_IS_OPERATION_SPLIT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_OPERATION_SPLIT))
|
||||
#define PIKA_OPERATION_SPLIT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_OPERATION_SPLIT, PikaOperationSplitClass))
|
||||
|
||||
|
||||
typedef struct _PikaOperationSplit PikaOperationSplit;
|
||||
typedef struct _PikaOperationSplitClass PikaOperationSplitClass;
|
||||
|
||||
struct _PikaOperationSplit
|
||||
{
|
||||
PikaOperationLayerMode parent_instance;
|
||||
};
|
||||
|
||||
struct _PikaOperationSplitClass
|
||||
{
|
||||
PikaOperationLayerModeClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType pika_operation_split_get_type (void) G_GNUC_CONST;
|
||||
|
||||
|
||||
#endif /* __PIKA_OPERATION_SPLIT_H__ */
|
||||
75
app/operations/meson.build
Normal file
75
app/operations/meson.build
Normal file
@ -0,0 +1,75 @@
|
||||
stamp_operations_enums = custom_target('stamp-operations-enums.h',
|
||||
input : [
|
||||
files(
|
||||
'operations-enums.h'
|
||||
),
|
||||
],
|
||||
output: [ 'stamp-operations-enums.h', ],
|
||||
command: [
|
||||
mkenums_wrap, perl,
|
||||
meson.project_source_root(), meson.current_source_dir(),
|
||||
meson.current_build_dir(),
|
||||
'operations-',
|
||||
'#include <gio/gio.h>\n' +
|
||||
'#include "libpikabase/pikabase.h"\n',
|
||||
'#include "pika-intl.h"'
|
||||
],
|
||||
build_by_default: true
|
||||
)
|
||||
|
||||
libappoperations_sources = [
|
||||
'pika-operation-config.c',
|
||||
'pika-operations.c',
|
||||
'pikabrightnesscontrastconfig.c',
|
||||
'pikacageconfig.c',
|
||||
'pikacolorbalanceconfig.c',
|
||||
'pikacurvesconfig.c',
|
||||
'pikahuesaturationconfig.c',
|
||||
'pikalevelsconfig.c',
|
||||
'pikaoperationborder.c',
|
||||
'pikaoperationbrightnesscontrast.c',
|
||||
'pikaoperationbuffersourcevalidate.c',
|
||||
'pikaoperationcagecoefcalc.c',
|
||||
'pikaoperationcagetransform.c',
|
||||
'pikaoperationcolorbalance.c',
|
||||
'pikaoperationcolorize.c',
|
||||
'pikaoperationcomposecrop.c',
|
||||
'pikaoperationcurves.c',
|
||||
'pikaoperationdesaturate.c',
|
||||
'pikaoperationequalize.c',
|
||||
'pikaoperationfillsource.c',
|
||||
'pikaoperationflood.c',
|
||||
'pikaoperationgradient.c',
|
||||
'pikaoperationgrow.c',
|
||||
'pikaoperationhistogramsink.c',
|
||||
'pikaoperationhuesaturation.c',
|
||||
'pikaoperationlevels.c',
|
||||
'pikaoperationmaskcomponents.cc',
|
||||
'pikaoperationoffset.c',
|
||||
'pikaoperationpointfilter.c',
|
||||
'pikaoperationposterize.c',
|
||||
'pikaoperationprofiletransform.c',
|
||||
'pikaoperationscalarmultiply.c',
|
||||
'pikaoperationsemiflatten.c',
|
||||
'pikaoperationsetalpha.c',
|
||||
'pikaoperationsettings.c',
|
||||
'pikaoperationshrink.c',
|
||||
'pikaoperationthreshold.c',
|
||||
'pikaoperationthresholdalpha.c',
|
||||
|
||||
'operations-enums.c',
|
||||
stamp_operations_enums,
|
||||
]
|
||||
|
||||
libappoperations = static_library('appoperations',
|
||||
libappoperations_sources,
|
||||
include_directories: [ rootInclude, rootAppInclude, ],
|
||||
c_args: '-DG_LOG_DOMAIN="Pika-Operations"',
|
||||
dependencies: [
|
||||
cairo, gegl, gdk_pixbuf,
|
||||
],
|
||||
)
|
||||
|
||||
subdir('layer-modes')
|
||||
subdir('layer-modes-legacy')
|
||||
subdir('tests')
|
||||
371
app/operations/operations-enums.c
Normal file
371
app/operations/operations-enums.c
Normal file
@ -0,0 +1,371 @@
|
||||
|
||||
/* Generated data (by pika-mkenums) */
|
||||
|
||||
#include "stamp-operations-enums.h"
|
||||
#include "config.h"
|
||||
#include <gio/gio.h>
|
||||
#include "libpikabase/pikabase.h"
|
||||
#include "operations-enums.h"
|
||||
#include "pika-intl.h"
|
||||
|
||||
/* enumerations from "operations-enums.h" */
|
||||
GType
|
||||
pika_layer_color_space_get_type (void)
|
||||
{
|
||||
static const GEnumValue values[] =
|
||||
{
|
||||
{ PIKA_LAYER_COLOR_SPACE_AUTO, "PIKA_LAYER_COLOR_SPACE_AUTO", "auto" },
|
||||
{ PIKA_LAYER_COLOR_SPACE_RGB_LINEAR, "PIKA_LAYER_COLOR_SPACE_RGB_LINEAR", "rgb-linear" },
|
||||
{ PIKA_LAYER_COLOR_SPACE_RGB_PERCEPTUAL, "PIKA_LAYER_COLOR_SPACE_RGB_PERCEPTUAL", "rgb-perceptual" },
|
||||
{ PIKA_LAYER_COLOR_SPACE_LAB, "PIKA_LAYER_COLOR_SPACE_LAB", "lab" },
|
||||
{ 0, NULL, NULL }
|
||||
};
|
||||
|
||||
static const PikaEnumDesc descs[] =
|
||||
{
|
||||
{ PIKA_LAYER_COLOR_SPACE_AUTO, NC_("layer-color-space", "Auto"), NULL },
|
||||
{ PIKA_LAYER_COLOR_SPACE_RGB_LINEAR, NC_("layer-color-space", "RGB (linear)"), NULL },
|
||||
{ PIKA_LAYER_COLOR_SPACE_RGB_PERCEPTUAL, NC_("layer-color-space", "RGB (perceptual)"), NULL },
|
||||
{ PIKA_LAYER_COLOR_SPACE_LAB, NC_("layer-color-space", "LAB"), NULL },
|
||||
{ 0, NULL, NULL }
|
||||
};
|
||||
|
||||
static GType type = 0;
|
||||
|
||||
if (G_UNLIKELY (! type))
|
||||
{
|
||||
type = g_enum_register_static ("PikaLayerColorSpace", values);
|
||||
pika_type_set_translation_context (type, "layer-color-space");
|
||||
pika_enum_set_value_descriptions (type, descs);
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
GType
|
||||
pika_layer_composite_mode_get_type (void)
|
||||
{
|
||||
static const GEnumValue values[] =
|
||||
{
|
||||
{ PIKA_LAYER_COMPOSITE_AUTO, "PIKA_LAYER_COMPOSITE_AUTO", "auto" },
|
||||
{ PIKA_LAYER_COMPOSITE_UNION, "PIKA_LAYER_COMPOSITE_UNION", "union" },
|
||||
{ PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP, "PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP", "clip-to-backdrop" },
|
||||
{ PIKA_LAYER_COMPOSITE_CLIP_TO_LAYER, "PIKA_LAYER_COMPOSITE_CLIP_TO_LAYER", "clip-to-layer" },
|
||||
{ PIKA_LAYER_COMPOSITE_INTERSECTION, "PIKA_LAYER_COMPOSITE_INTERSECTION", "intersection" },
|
||||
{ 0, NULL, NULL }
|
||||
};
|
||||
|
||||
static const PikaEnumDesc descs[] =
|
||||
{
|
||||
{ PIKA_LAYER_COMPOSITE_AUTO, NC_("layer-composite-mode", "Auto"), NULL },
|
||||
{ PIKA_LAYER_COMPOSITE_UNION, NC_("layer-composite-mode", "Union"), NULL },
|
||||
{ PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP, NC_("layer-composite-mode", "Clip to backdrop"), NULL },
|
||||
{ PIKA_LAYER_COMPOSITE_CLIP_TO_LAYER, NC_("layer-composite-mode", "Clip to layer"), NULL },
|
||||
{ PIKA_LAYER_COMPOSITE_INTERSECTION, NC_("layer-composite-mode", "Intersection"), NULL },
|
||||
{ 0, NULL, NULL }
|
||||
};
|
||||
|
||||
static GType type = 0;
|
||||
|
||||
if (G_UNLIKELY (! type))
|
||||
{
|
||||
type = g_enum_register_static ("PikaLayerCompositeMode", values);
|
||||
pika_type_set_translation_context (type, "layer-composite-mode");
|
||||
pika_enum_set_value_descriptions (type, descs);
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
GType
|
||||
pika_layer_mode_get_type (void)
|
||||
{
|
||||
static const GEnumValue values[] =
|
||||
{
|
||||
{ PIKA_LAYER_MODE_NORMAL_LEGACY, "PIKA_LAYER_MODE_NORMAL_LEGACY", "normal-legacy" },
|
||||
{ PIKA_LAYER_MODE_DISSOLVE, "PIKA_LAYER_MODE_DISSOLVE", "dissolve" },
|
||||
{ PIKA_LAYER_MODE_BEHIND_LEGACY, "PIKA_LAYER_MODE_BEHIND_LEGACY", "behind-legacy" },
|
||||
{ PIKA_LAYER_MODE_MULTIPLY_LEGACY, "PIKA_LAYER_MODE_MULTIPLY_LEGACY", "multiply-legacy" },
|
||||
{ PIKA_LAYER_MODE_SCREEN_LEGACY, "PIKA_LAYER_MODE_SCREEN_LEGACY", "screen-legacy" },
|
||||
{ PIKA_LAYER_MODE_OVERLAY_LEGACY, "PIKA_LAYER_MODE_OVERLAY_LEGACY", "overlay-legacy" },
|
||||
{ PIKA_LAYER_MODE_DIFFERENCE_LEGACY, "PIKA_LAYER_MODE_DIFFERENCE_LEGACY", "difference-legacy" },
|
||||
{ PIKA_LAYER_MODE_ADDITION_LEGACY, "PIKA_LAYER_MODE_ADDITION_LEGACY", "addition-legacy" },
|
||||
{ PIKA_LAYER_MODE_SUBTRACT_LEGACY, "PIKA_LAYER_MODE_SUBTRACT_LEGACY", "subtract-legacy" },
|
||||
{ PIKA_LAYER_MODE_DARKEN_ONLY_LEGACY, "PIKA_LAYER_MODE_DARKEN_ONLY_LEGACY", "darken-only-legacy" },
|
||||
{ PIKA_LAYER_MODE_LIGHTEN_ONLY_LEGACY, "PIKA_LAYER_MODE_LIGHTEN_ONLY_LEGACY", "lighten-only-legacy" },
|
||||
{ PIKA_LAYER_MODE_HSV_HUE_LEGACY, "PIKA_LAYER_MODE_HSV_HUE_LEGACY", "hsv-hue-legacy" },
|
||||
{ PIKA_LAYER_MODE_HSV_SATURATION_LEGACY, "PIKA_LAYER_MODE_HSV_SATURATION_LEGACY", "hsv-saturation-legacy" },
|
||||
{ PIKA_LAYER_MODE_HSL_COLOR_LEGACY, "PIKA_LAYER_MODE_HSL_COLOR_LEGACY", "hsl-color-legacy" },
|
||||
{ PIKA_LAYER_MODE_HSV_VALUE_LEGACY, "PIKA_LAYER_MODE_HSV_VALUE_LEGACY", "hsv-value-legacy" },
|
||||
{ PIKA_LAYER_MODE_DIVIDE_LEGACY, "PIKA_LAYER_MODE_DIVIDE_LEGACY", "divide-legacy" },
|
||||
{ PIKA_LAYER_MODE_DODGE_LEGACY, "PIKA_LAYER_MODE_DODGE_LEGACY", "dodge-legacy" },
|
||||
{ PIKA_LAYER_MODE_BURN_LEGACY, "PIKA_LAYER_MODE_BURN_LEGACY", "burn-legacy" },
|
||||
{ PIKA_LAYER_MODE_HARDLIGHT_LEGACY, "PIKA_LAYER_MODE_HARDLIGHT_LEGACY", "hardlight-legacy" },
|
||||
{ PIKA_LAYER_MODE_SOFTLIGHT_LEGACY, "PIKA_LAYER_MODE_SOFTLIGHT_LEGACY", "softlight-legacy" },
|
||||
{ PIKA_LAYER_MODE_GRAIN_EXTRACT_LEGACY, "PIKA_LAYER_MODE_GRAIN_EXTRACT_LEGACY", "grain-extract-legacy" },
|
||||
{ PIKA_LAYER_MODE_GRAIN_MERGE_LEGACY, "PIKA_LAYER_MODE_GRAIN_MERGE_LEGACY", "grain-merge-legacy" },
|
||||
{ PIKA_LAYER_MODE_COLOR_ERASE_LEGACY, "PIKA_LAYER_MODE_COLOR_ERASE_LEGACY", "color-erase-legacy" },
|
||||
{ PIKA_LAYER_MODE_OVERLAY, "PIKA_LAYER_MODE_OVERLAY", "overlay" },
|
||||
{ PIKA_LAYER_MODE_LCH_HUE, "PIKA_LAYER_MODE_LCH_HUE", "lch-hue" },
|
||||
{ PIKA_LAYER_MODE_LCH_CHROMA, "PIKA_LAYER_MODE_LCH_CHROMA", "lch-chroma" },
|
||||
{ PIKA_LAYER_MODE_LCH_COLOR, "PIKA_LAYER_MODE_LCH_COLOR", "lch-color" },
|
||||
{ PIKA_LAYER_MODE_LCH_LIGHTNESS, "PIKA_LAYER_MODE_LCH_LIGHTNESS", "lch-lightness" },
|
||||
{ PIKA_LAYER_MODE_NORMAL, "PIKA_LAYER_MODE_NORMAL", "normal" },
|
||||
{ PIKA_LAYER_MODE_BEHIND, "PIKA_LAYER_MODE_BEHIND", "behind" },
|
||||
{ PIKA_LAYER_MODE_MULTIPLY, "PIKA_LAYER_MODE_MULTIPLY", "multiply" },
|
||||
{ PIKA_LAYER_MODE_SCREEN, "PIKA_LAYER_MODE_SCREEN", "screen" },
|
||||
{ PIKA_LAYER_MODE_DIFFERENCE, "PIKA_LAYER_MODE_DIFFERENCE", "difference" },
|
||||
{ PIKA_LAYER_MODE_ADDITION, "PIKA_LAYER_MODE_ADDITION", "addition" },
|
||||
{ PIKA_LAYER_MODE_SUBTRACT, "PIKA_LAYER_MODE_SUBTRACT", "subtract" },
|
||||
{ PIKA_LAYER_MODE_DARKEN_ONLY, "PIKA_LAYER_MODE_DARKEN_ONLY", "darken-only" },
|
||||
{ PIKA_LAYER_MODE_LIGHTEN_ONLY, "PIKA_LAYER_MODE_LIGHTEN_ONLY", "lighten-only" },
|
||||
{ PIKA_LAYER_MODE_HSV_HUE, "PIKA_LAYER_MODE_HSV_HUE", "hsv-hue" },
|
||||
{ PIKA_LAYER_MODE_HSV_SATURATION, "PIKA_LAYER_MODE_HSV_SATURATION", "hsv-saturation" },
|
||||
{ PIKA_LAYER_MODE_HSL_COLOR, "PIKA_LAYER_MODE_HSL_COLOR", "hsl-color" },
|
||||
{ PIKA_LAYER_MODE_HSV_VALUE, "PIKA_LAYER_MODE_HSV_VALUE", "hsv-value" },
|
||||
{ PIKA_LAYER_MODE_DIVIDE, "PIKA_LAYER_MODE_DIVIDE", "divide" },
|
||||
{ PIKA_LAYER_MODE_DODGE, "PIKA_LAYER_MODE_DODGE", "dodge" },
|
||||
{ PIKA_LAYER_MODE_BURN, "PIKA_LAYER_MODE_BURN", "burn" },
|
||||
{ PIKA_LAYER_MODE_HARDLIGHT, "PIKA_LAYER_MODE_HARDLIGHT", "hardlight" },
|
||||
{ PIKA_LAYER_MODE_SOFTLIGHT, "PIKA_LAYER_MODE_SOFTLIGHT", "softlight" },
|
||||
{ PIKA_LAYER_MODE_GRAIN_EXTRACT, "PIKA_LAYER_MODE_GRAIN_EXTRACT", "grain-extract" },
|
||||
{ PIKA_LAYER_MODE_GRAIN_MERGE, "PIKA_LAYER_MODE_GRAIN_MERGE", "grain-merge" },
|
||||
{ PIKA_LAYER_MODE_VIVID_LIGHT, "PIKA_LAYER_MODE_VIVID_LIGHT", "vivid-light" },
|
||||
{ PIKA_LAYER_MODE_PIN_LIGHT, "PIKA_LAYER_MODE_PIN_LIGHT", "pin-light" },
|
||||
{ PIKA_LAYER_MODE_LINEAR_LIGHT, "PIKA_LAYER_MODE_LINEAR_LIGHT", "linear-light" },
|
||||
{ PIKA_LAYER_MODE_HARD_MIX, "PIKA_LAYER_MODE_HARD_MIX", "hard-mix" },
|
||||
{ PIKA_LAYER_MODE_EXCLUSION, "PIKA_LAYER_MODE_EXCLUSION", "exclusion" },
|
||||
{ PIKA_LAYER_MODE_LINEAR_BURN, "PIKA_LAYER_MODE_LINEAR_BURN", "linear-burn" },
|
||||
{ PIKA_LAYER_MODE_LUMA_DARKEN_ONLY, "PIKA_LAYER_MODE_LUMA_DARKEN_ONLY", "luma-darken-only" },
|
||||
{ PIKA_LAYER_MODE_LUMA_LIGHTEN_ONLY, "PIKA_LAYER_MODE_LUMA_LIGHTEN_ONLY", "luma-lighten-only" },
|
||||
{ PIKA_LAYER_MODE_LUMINANCE, "PIKA_LAYER_MODE_LUMINANCE", "luminance" },
|
||||
{ PIKA_LAYER_MODE_COLOR_ERASE, "PIKA_LAYER_MODE_COLOR_ERASE", "color-erase" },
|
||||
{ PIKA_LAYER_MODE_ERASE, "PIKA_LAYER_MODE_ERASE", "erase" },
|
||||
{ PIKA_LAYER_MODE_MERGE, "PIKA_LAYER_MODE_MERGE", "merge" },
|
||||
{ PIKA_LAYER_MODE_SPLIT, "PIKA_LAYER_MODE_SPLIT", "split" },
|
||||
{ PIKA_LAYER_MODE_PASS_THROUGH, "PIKA_LAYER_MODE_PASS_THROUGH", "pass-through" },
|
||||
{ PIKA_LAYER_MODE_REPLACE, "PIKA_LAYER_MODE_REPLACE", "replace" },
|
||||
{ PIKA_LAYER_MODE_ANTI_ERASE, "PIKA_LAYER_MODE_ANTI_ERASE", "anti-erase" },
|
||||
{ 0, NULL, NULL }
|
||||
};
|
||||
|
||||
static const PikaEnumDesc descs[] =
|
||||
{
|
||||
{ PIKA_LAYER_MODE_NORMAL_LEGACY, NC_("layer-mode", "Normal (legacy)"), NULL },
|
||||
/* Translators: this is an abbreviated version of "Normal (legacy)".
|
||||
Keep it short. */
|
||||
{ PIKA_LAYER_MODE_NORMAL_LEGACY, NC_("layer-mode", "Normal (l)"), NULL },
|
||||
{ PIKA_LAYER_MODE_DISSOLVE, NC_("layer-mode", "Dissolve"), NULL },
|
||||
{ PIKA_LAYER_MODE_BEHIND_LEGACY, NC_("layer-mode", "Behind (legacy)"), NULL },
|
||||
/* Translators: this is an abbreviated version of "Behind (legacy)".
|
||||
Keep it short. */
|
||||
{ PIKA_LAYER_MODE_BEHIND_LEGACY, NC_("layer-mode", "Behind (l)"), NULL },
|
||||
{ PIKA_LAYER_MODE_MULTIPLY_LEGACY, NC_("layer-mode", "Multiply (legacy)"), NULL },
|
||||
/* Translators: this is an abbreviated version of "Multiply (legacy)".
|
||||
Keep it short. */
|
||||
{ PIKA_LAYER_MODE_MULTIPLY_LEGACY, NC_("layer-mode", "Multiply (l)"), NULL },
|
||||
{ PIKA_LAYER_MODE_SCREEN_LEGACY, NC_("layer-mode", "Screen (legacy)"), NULL },
|
||||
/* Translators: this is an abbreviated version of "Screen (legacy)".
|
||||
Keep it short. */
|
||||
{ PIKA_LAYER_MODE_SCREEN_LEGACY, NC_("layer-mode", "Screen (l)"), NULL },
|
||||
{ PIKA_LAYER_MODE_OVERLAY_LEGACY, NC_("layer-mode", "Old broken Overlay"), NULL },
|
||||
/* Translators: this is an abbreviated version of "Old broken Overlay".
|
||||
Keep it short. */
|
||||
{ PIKA_LAYER_MODE_OVERLAY_LEGACY, NC_("layer-mode", "Old Overlay"), NULL },
|
||||
{ PIKA_LAYER_MODE_DIFFERENCE_LEGACY, NC_("layer-mode", "Difference (legacy)"), NULL },
|
||||
/* Translators: this is an abbreviated version of "Difference (legacy)".
|
||||
Keep it short. */
|
||||
{ PIKA_LAYER_MODE_DIFFERENCE_LEGACY, NC_("layer-mode", "Difference (l)"), NULL },
|
||||
{ PIKA_LAYER_MODE_ADDITION_LEGACY, NC_("layer-mode", "Addition (legacy)"), NULL },
|
||||
/* Translators: this is an abbreviated version of "Addition (legacy)".
|
||||
Keep it short. */
|
||||
{ PIKA_LAYER_MODE_ADDITION_LEGACY, NC_("layer-mode", "Addition (l)"), NULL },
|
||||
{ PIKA_LAYER_MODE_SUBTRACT_LEGACY, NC_("layer-mode", "Subtract (legacy)"), NULL },
|
||||
/* Translators: this is an abbreviated version of "Subtract (legacy)".
|
||||
Keep it short. */
|
||||
{ PIKA_LAYER_MODE_SUBTRACT_LEGACY, NC_("layer-mode", "Subtract (l)"), NULL },
|
||||
{ PIKA_LAYER_MODE_DARKEN_ONLY_LEGACY, NC_("layer-mode", "Darken only (legacy)"), NULL },
|
||||
/* Translators: this is an abbreviated version of "Darken only (legacy)".
|
||||
Keep it short. */
|
||||
{ PIKA_LAYER_MODE_DARKEN_ONLY_LEGACY, NC_("layer-mode", "Darken only (l)"), NULL },
|
||||
{ PIKA_LAYER_MODE_LIGHTEN_ONLY_LEGACY, NC_("layer-mode", "Lighten only (legacy)"), NULL },
|
||||
/* Translators: this is an abbreviated version of "Lighten only (legacy)".
|
||||
Keep it short. */
|
||||
{ PIKA_LAYER_MODE_LIGHTEN_ONLY_LEGACY, NC_("layer-mode", "Lighten only (l)"), NULL },
|
||||
{ PIKA_LAYER_MODE_HSV_HUE_LEGACY, NC_("layer-mode", "HSV Hue (legacy)"), NULL },
|
||||
/* Translators: this is an abbreviated version of "HSV Hue (legacy)".
|
||||
Keep it short. */
|
||||
{ PIKA_LAYER_MODE_HSV_HUE_LEGACY, NC_("layer-mode", "HSV Hue (l)"), NULL },
|
||||
{ PIKA_LAYER_MODE_HSV_SATURATION_LEGACY, NC_("layer-mode", "HSV Saturation (legacy)"), NULL },
|
||||
/* Translators: this is an abbreviated version of "HSV Saturation (legacy)".
|
||||
Keep it short. */
|
||||
{ PIKA_LAYER_MODE_HSV_SATURATION_LEGACY, NC_("layer-mode", "HSV Saturation (l)"), NULL },
|
||||
{ PIKA_LAYER_MODE_HSL_COLOR_LEGACY, NC_("layer-mode", "HSL Color (legacy)"), NULL },
|
||||
/* Translators: this is an abbreviated version of "HSL Color (legacy)".
|
||||
Keep it short. */
|
||||
{ PIKA_LAYER_MODE_HSL_COLOR_LEGACY, NC_("layer-mode", "HSL Color (l)"), NULL },
|
||||
{ PIKA_LAYER_MODE_HSV_VALUE_LEGACY, NC_("layer-mode", "HSV Value (legacy)"), NULL },
|
||||
/* Translators: this is an abbreviated version of "HSV Value (legacy)".
|
||||
Keep it short. */
|
||||
{ PIKA_LAYER_MODE_HSV_VALUE_LEGACY, NC_("layer-mode", "HSV Value (l)"), NULL },
|
||||
{ PIKA_LAYER_MODE_DIVIDE_LEGACY, NC_("layer-mode", "Divide (legacy)"), NULL },
|
||||
/* Translators: this is an abbreviated version of "Divide (legacy)".
|
||||
Keep it short. */
|
||||
{ PIKA_LAYER_MODE_DIVIDE_LEGACY, NC_("layer-mode", "Divide (l)"), NULL },
|
||||
{ PIKA_LAYER_MODE_DODGE_LEGACY, NC_("layer-mode", "Dodge (legacy)"), NULL },
|
||||
/* Translators: this is an abbreviated version of "Dodge (legacy)".
|
||||
Keep it short. */
|
||||
{ PIKA_LAYER_MODE_DODGE_LEGACY, NC_("layer-mode", "Dodge (l)"), NULL },
|
||||
{ PIKA_LAYER_MODE_BURN_LEGACY, NC_("layer-mode", "Burn (legacy)"), NULL },
|
||||
/* Translators: this is an abbreviated version of "Burn (legacy)".
|
||||
Keep it short. */
|
||||
{ PIKA_LAYER_MODE_BURN_LEGACY, NC_("layer-mode", "Burn (l)"), NULL },
|
||||
{ PIKA_LAYER_MODE_HARDLIGHT_LEGACY, NC_("layer-mode", "Hard light (legacy)"), NULL },
|
||||
/* Translators: this is an abbreviated version of "Hard light (legacy)".
|
||||
Keep it short. */
|
||||
{ PIKA_LAYER_MODE_HARDLIGHT_LEGACY, NC_("layer-mode", "Hard light (l)"), NULL },
|
||||
{ PIKA_LAYER_MODE_SOFTLIGHT_LEGACY, NC_("layer-mode", "Soft light (legacy)"), NULL },
|
||||
/* Translators: this is an abbreviated version of "Soft light (legacy)".
|
||||
Keep it short. */
|
||||
{ PIKA_LAYER_MODE_SOFTLIGHT_LEGACY, NC_("layer-mode", "Soft light (l)"), NULL },
|
||||
{ PIKA_LAYER_MODE_GRAIN_EXTRACT_LEGACY, NC_("layer-mode", "Grain extract (legacy)"), NULL },
|
||||
/* Translators: this is an abbreviated version of "Grain extract (legacy)".
|
||||
Keep it short. */
|
||||
{ PIKA_LAYER_MODE_GRAIN_EXTRACT_LEGACY, NC_("layer-mode", "Grain extract (l)"), NULL },
|
||||
{ PIKA_LAYER_MODE_GRAIN_MERGE_LEGACY, NC_("layer-mode", "Grain merge (legacy)"), NULL },
|
||||
/* Translators: this is an abbreviated version of "Grain merge (legacy)".
|
||||
Keep it short. */
|
||||
{ PIKA_LAYER_MODE_GRAIN_MERGE_LEGACY, NC_("layer-mode", "Grain merge (l)"), NULL },
|
||||
{ PIKA_LAYER_MODE_COLOR_ERASE_LEGACY, NC_("layer-mode", "Color erase (legacy)"), NULL },
|
||||
/* Translators: this is an abbreviated version of "Color erase (legacy)".
|
||||
Keep it short. */
|
||||
{ PIKA_LAYER_MODE_COLOR_ERASE_LEGACY, NC_("layer-mode", "Color erase (l)"), NULL },
|
||||
{ PIKA_LAYER_MODE_OVERLAY, NC_("layer-mode", "Overlay"), NULL },
|
||||
{ PIKA_LAYER_MODE_LCH_HUE, NC_("layer-mode", "LCh Hue"), NULL },
|
||||
{ PIKA_LAYER_MODE_LCH_CHROMA, NC_("layer-mode", "LCh Chroma"), NULL },
|
||||
{ PIKA_LAYER_MODE_LCH_COLOR, NC_("layer-mode", "LCh Color"), NULL },
|
||||
{ PIKA_LAYER_MODE_LCH_LIGHTNESS, NC_("layer-mode", "LCh Lightness"), NULL },
|
||||
{ PIKA_LAYER_MODE_NORMAL, NC_("layer-mode", "Normal"), NULL },
|
||||
{ PIKA_LAYER_MODE_BEHIND, NC_("layer-mode", "Behind"), NULL },
|
||||
{ PIKA_LAYER_MODE_MULTIPLY, NC_("layer-mode", "Multiply"), NULL },
|
||||
{ PIKA_LAYER_MODE_SCREEN, NC_("layer-mode", "Screen"), NULL },
|
||||
{ PIKA_LAYER_MODE_DIFFERENCE, NC_("layer-mode", "Difference"), NULL },
|
||||
{ PIKA_LAYER_MODE_ADDITION, NC_("layer-mode", "Addition"), NULL },
|
||||
{ PIKA_LAYER_MODE_SUBTRACT, NC_("layer-mode", "Subtract"), NULL },
|
||||
{ PIKA_LAYER_MODE_DARKEN_ONLY, NC_("layer-mode", "Darken only"), NULL },
|
||||
{ PIKA_LAYER_MODE_LIGHTEN_ONLY, NC_("layer-mode", "Lighten only"), NULL },
|
||||
{ PIKA_LAYER_MODE_HSV_HUE, NC_("layer-mode", "HSV Hue"), NULL },
|
||||
{ PIKA_LAYER_MODE_HSV_SATURATION, NC_("layer-mode", "HSV Saturation"), NULL },
|
||||
{ PIKA_LAYER_MODE_HSL_COLOR, NC_("layer-mode", "HSL Color"), NULL },
|
||||
{ PIKA_LAYER_MODE_HSV_VALUE, NC_("layer-mode", "HSV Value"), NULL },
|
||||
{ PIKA_LAYER_MODE_DIVIDE, NC_("layer-mode", "Divide"), NULL },
|
||||
{ PIKA_LAYER_MODE_DODGE, NC_("layer-mode", "Dodge"), NULL },
|
||||
{ PIKA_LAYER_MODE_BURN, NC_("layer-mode", "Burn"), NULL },
|
||||
{ PIKA_LAYER_MODE_HARDLIGHT, NC_("layer-mode", "Hard light"), NULL },
|
||||
{ PIKA_LAYER_MODE_SOFTLIGHT, NC_("layer-mode", "Soft light"), NULL },
|
||||
{ PIKA_LAYER_MODE_GRAIN_EXTRACT, NC_("layer-mode", "Grain extract"), NULL },
|
||||
{ PIKA_LAYER_MODE_GRAIN_MERGE, NC_("layer-mode", "Grain merge"), NULL },
|
||||
{ PIKA_LAYER_MODE_VIVID_LIGHT, NC_("layer-mode", "Vivid light"), NULL },
|
||||
{ PIKA_LAYER_MODE_PIN_LIGHT, NC_("layer-mode", "Pin light"), NULL },
|
||||
{ PIKA_LAYER_MODE_LINEAR_LIGHT, NC_("layer-mode", "Linear light"), NULL },
|
||||
{ PIKA_LAYER_MODE_HARD_MIX, NC_("layer-mode", "Hard mix"), NULL },
|
||||
{ PIKA_LAYER_MODE_EXCLUSION, NC_("layer-mode", "Exclusion"), NULL },
|
||||
{ PIKA_LAYER_MODE_LINEAR_BURN, NC_("layer-mode", "Linear burn"), NULL },
|
||||
{ PIKA_LAYER_MODE_LUMA_DARKEN_ONLY, NC_("layer-mode", "Luma/Luminance darken only"), NULL },
|
||||
/* Translators: this is an abbreviated version of "Luma/Luminance darken only".
|
||||
Keep it short. */
|
||||
{ PIKA_LAYER_MODE_LUMA_DARKEN_ONLY, NC_("layer-mode", "Luma darken only"), NULL },
|
||||
{ PIKA_LAYER_MODE_LUMA_LIGHTEN_ONLY, NC_("layer-mode", "Luma/Luminance lighten only"), NULL },
|
||||
/* Translators: this is an abbreviated version of "Luma/Luminance lighten only".
|
||||
Keep it short. */
|
||||
{ PIKA_LAYER_MODE_LUMA_LIGHTEN_ONLY, NC_("layer-mode", "Luma lighten only"), NULL },
|
||||
{ PIKA_LAYER_MODE_LUMINANCE, NC_("layer-mode", "Luminance"), NULL },
|
||||
{ PIKA_LAYER_MODE_COLOR_ERASE, NC_("layer-mode", "Color erase"), NULL },
|
||||
{ PIKA_LAYER_MODE_ERASE, NC_("layer-mode", "Erase"), NULL },
|
||||
{ PIKA_LAYER_MODE_MERGE, NC_("layer-mode", "Merge"), NULL },
|
||||
{ PIKA_LAYER_MODE_SPLIT, NC_("layer-mode", "Split"), NULL },
|
||||
{ PIKA_LAYER_MODE_PASS_THROUGH, NC_("layer-mode", "Pass through"), NULL },
|
||||
{ PIKA_LAYER_MODE_REPLACE, NC_("layer-mode", "Replace"), NULL },
|
||||
{ PIKA_LAYER_MODE_ANTI_ERASE, NC_("layer-mode", "Anti erase"), NULL },
|
||||
{ 0, NULL, NULL }
|
||||
};
|
||||
|
||||
static GType type = 0;
|
||||
|
||||
if (G_UNLIKELY (! type))
|
||||
{
|
||||
type = g_enum_register_static ("PikaLayerMode", values);
|
||||
pika_type_set_translation_context (type, "layer-mode");
|
||||
pika_enum_set_value_descriptions (type, descs);
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
GType
|
||||
pika_layer_mode_group_get_type (void)
|
||||
{
|
||||
static const GEnumValue values[] =
|
||||
{
|
||||
{ PIKA_LAYER_MODE_GROUP_DEFAULT, "PIKA_LAYER_MODE_GROUP_DEFAULT", "default" },
|
||||
{ PIKA_LAYER_MODE_GROUP_LEGACY, "PIKA_LAYER_MODE_GROUP_LEGACY", "legacy" },
|
||||
{ 0, NULL, NULL }
|
||||
};
|
||||
|
||||
static const PikaEnumDesc descs[] =
|
||||
{
|
||||
{ PIKA_LAYER_MODE_GROUP_DEFAULT, NC_("layer-mode-group", "Default"), NULL },
|
||||
{ PIKA_LAYER_MODE_GROUP_LEGACY, NC_("layer-mode-group", "Legacy"), NULL },
|
||||
{ 0, NULL, NULL }
|
||||
};
|
||||
|
||||
static GType type = 0;
|
||||
|
||||
if (G_UNLIKELY (! type))
|
||||
{
|
||||
type = g_enum_register_static ("PikaLayerModeGroup", values);
|
||||
pika_type_set_translation_context (type, "layer-mode-group");
|
||||
pika_enum_set_value_descriptions (type, descs);
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
GType
|
||||
pika_layer_mode_context_get_type (void)
|
||||
{
|
||||
static const GFlagsValue values[] =
|
||||
{
|
||||
{ PIKA_LAYER_MODE_CONTEXT_LAYER, "PIKA_LAYER_MODE_CONTEXT_LAYER", "layer" },
|
||||
{ PIKA_LAYER_MODE_CONTEXT_GROUP, "PIKA_LAYER_MODE_CONTEXT_GROUP", "group" },
|
||||
{ PIKA_LAYER_MODE_CONTEXT_PAINT, "PIKA_LAYER_MODE_CONTEXT_PAINT", "paint" },
|
||||
{ PIKA_LAYER_MODE_CONTEXT_FILTER, "PIKA_LAYER_MODE_CONTEXT_FILTER", "filter" },
|
||||
{ PIKA_LAYER_MODE_CONTEXT_ALL, "PIKA_LAYER_MODE_CONTEXT_ALL", "all" },
|
||||
{ 0, NULL, NULL }
|
||||
};
|
||||
|
||||
static const PikaFlagsDesc descs[] =
|
||||
{
|
||||
{ PIKA_LAYER_MODE_CONTEXT_LAYER, "PIKA_LAYER_MODE_CONTEXT_LAYER", NULL },
|
||||
{ PIKA_LAYER_MODE_CONTEXT_GROUP, "PIKA_LAYER_MODE_CONTEXT_GROUP", NULL },
|
||||
{ PIKA_LAYER_MODE_CONTEXT_PAINT, "PIKA_LAYER_MODE_CONTEXT_PAINT", NULL },
|
||||
{ PIKA_LAYER_MODE_CONTEXT_FILTER, "PIKA_LAYER_MODE_CONTEXT_FILTER", NULL },
|
||||
{ PIKA_LAYER_MODE_CONTEXT_ALL, "PIKA_LAYER_MODE_CONTEXT_ALL", NULL },
|
||||
{ 0, NULL, NULL }
|
||||
};
|
||||
|
||||
static GType type = 0;
|
||||
|
||||
if (G_UNLIKELY (! type))
|
||||
{
|
||||
type = g_flags_register_static ("PikaLayerModeContext", values);
|
||||
pika_type_set_translation_context (type, "layer-mode-context");
|
||||
pika_flags_set_value_descriptions (type, descs);
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
|
||||
/* Generated data ends here */
|
||||
|
||||
194
app/operations/operations-enums.h
Normal file
194
app/operations/operations-enums.h
Normal file
@ -0,0 +1,194 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* operations-enums.h
|
||||
*
|
||||
* 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 __OPERATIONS_ENUMS_H__
|
||||
#define __OPERATIONS_ENUMS_H__
|
||||
|
||||
|
||||
#define PIKA_TYPE_LAYER_COLOR_SPACE (pika_layer_color_space_get_type ())
|
||||
|
||||
GType pika_layer_color_space_get_type (void) G_GNUC_CONST;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
PIKA_LAYER_COLOR_SPACE_AUTO, /*< desc="Auto" >*/
|
||||
PIKA_LAYER_COLOR_SPACE_RGB_LINEAR, /*< desc="RGB (linear)" >*/
|
||||
PIKA_LAYER_COLOR_SPACE_RGB_PERCEPTUAL, /*< desc="RGB (perceptual)" >*/
|
||||
PIKA_LAYER_COLOR_SPACE_LAB, /*< desc="LAB", pdb-skip >*/
|
||||
} PikaLayerColorSpace;
|
||||
|
||||
|
||||
#define PIKA_TYPE_LAYER_COMPOSITE_MODE (pika_layer_composite_mode_get_type ())
|
||||
|
||||
GType pika_layer_composite_mode_get_type (void) G_GNUC_CONST;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
PIKA_LAYER_COMPOSITE_AUTO, /*< desc="Auto" >*/
|
||||
PIKA_LAYER_COMPOSITE_UNION, /*< desc="Union" >*/
|
||||
PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP, /*< desc="Clip to backdrop" >*/
|
||||
PIKA_LAYER_COMPOSITE_CLIP_TO_LAYER, /*< desc="Clip to layer" >*/
|
||||
PIKA_LAYER_COMPOSITE_INTERSECTION /*< desc="Intersection" >*/
|
||||
} PikaLayerCompositeMode;
|
||||
|
||||
|
||||
#define PIKA_TYPE_LAYER_MODE (pika_layer_mode_get_type ())
|
||||
|
||||
GType pika_layer_mode_get_type (void) G_GNUC_CONST;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
/* Modes that exist since ancient times */
|
||||
PIKA_LAYER_MODE_NORMAL_LEGACY, /*< desc="Normal (legacy)", abbrev="Normal (l)" >*/
|
||||
PIKA_LAYER_MODE_DISSOLVE, /*< desc="Dissolve" >*/
|
||||
PIKA_LAYER_MODE_BEHIND_LEGACY, /*< desc="Behind (legacy)", abbrev="Behind (l)" >*/
|
||||
PIKA_LAYER_MODE_MULTIPLY_LEGACY, /*< desc="Multiply (legacy)", abbrev="Multiply (l)" >*/
|
||||
PIKA_LAYER_MODE_SCREEN_LEGACY, /*< desc="Screen (legacy)", abbrev="Screen (l)" >*/
|
||||
PIKA_LAYER_MODE_OVERLAY_LEGACY, /*< desc="Old broken Overlay", abbrev="Old Overlay" >*/
|
||||
PIKA_LAYER_MODE_DIFFERENCE_LEGACY, /*< desc="Difference (legacy)", abbrev="Difference (l)" >*/
|
||||
PIKA_LAYER_MODE_ADDITION_LEGACY, /*< desc="Addition (legacy)", abbrev="Addition (l)" >*/
|
||||
PIKA_LAYER_MODE_SUBTRACT_LEGACY, /*< desc="Subtract (legacy)", abbrev="Subtract (l)" >*/
|
||||
PIKA_LAYER_MODE_DARKEN_ONLY_LEGACY, /*< desc="Darken only (legacy)", abbrev="Darken only (l)" >*/
|
||||
PIKA_LAYER_MODE_LIGHTEN_ONLY_LEGACY, /*< desc="Lighten only (legacy)", abbrev="Lighten only (l)" >*/
|
||||
PIKA_LAYER_MODE_HSV_HUE_LEGACY, /*< desc="HSV Hue (legacy)", abbrev="HSV Hue (l)" >*/
|
||||
PIKA_LAYER_MODE_HSV_SATURATION_LEGACY, /*< desc="HSV Saturation (legacy)", abbrev="HSV Saturation (l)" >*/
|
||||
PIKA_LAYER_MODE_HSL_COLOR_LEGACY, /*< desc="HSL Color (legacy)", abbrev="HSL Color (l)" >*/
|
||||
PIKA_LAYER_MODE_HSV_VALUE_LEGACY, /*< desc="HSV Value (legacy)", abbrev="HSV Value (l)" >*/
|
||||
PIKA_LAYER_MODE_DIVIDE_LEGACY, /*< desc="Divide (legacy)", abbrev="Divide (l)" >*/
|
||||
PIKA_LAYER_MODE_DODGE_LEGACY, /*< desc="Dodge (legacy)", abbrev="Dodge (l)" >*/
|
||||
PIKA_LAYER_MODE_BURN_LEGACY, /*< desc="Burn (legacy)", abbrev="Burn (l)" >*/
|
||||
PIKA_LAYER_MODE_HARDLIGHT_LEGACY, /*< desc="Hard light (legacy)", abbrev="Hard light (l)" >*/
|
||||
|
||||
/* Since 2.8 (XCF version 2) */
|
||||
PIKA_LAYER_MODE_SOFTLIGHT_LEGACY, /*< desc="Soft light (legacy)", abbrev="Soft light (l)" >*/
|
||||
PIKA_LAYER_MODE_GRAIN_EXTRACT_LEGACY, /*< desc="Grain extract (legacy)", abbrev="Grain extract (l)" >*/
|
||||
PIKA_LAYER_MODE_GRAIN_MERGE_LEGACY, /*< desc="Grain merge (legacy)", abbrev="Grain merge (l)" >*/
|
||||
PIKA_LAYER_MODE_COLOR_ERASE_LEGACY, /*< desc="Color erase (legacy)", abbrev="Color erase (l)" >*/
|
||||
|
||||
/* Since 2.10 (XCF version 9) */
|
||||
PIKA_LAYER_MODE_OVERLAY, /*< desc="Overlay" >*/
|
||||
PIKA_LAYER_MODE_LCH_HUE, /*< desc="LCh Hue" >*/
|
||||
PIKA_LAYER_MODE_LCH_CHROMA, /*< desc="LCh Chroma" >*/
|
||||
PIKA_LAYER_MODE_LCH_COLOR, /*< desc="LCh Color" >*/
|
||||
PIKA_LAYER_MODE_LCH_LIGHTNESS, /*< desc="LCh Lightness" >*/
|
||||
|
||||
/* Since 2.10 (XCF version 10) */
|
||||
PIKA_LAYER_MODE_NORMAL, /*< desc="Normal" >*/
|
||||
PIKA_LAYER_MODE_BEHIND, /*< desc="Behind" >*/
|
||||
PIKA_LAYER_MODE_MULTIPLY, /*< desc="Multiply" >*/
|
||||
PIKA_LAYER_MODE_SCREEN, /*< desc="Screen" >*/
|
||||
PIKA_LAYER_MODE_DIFFERENCE, /*< desc="Difference" >*/
|
||||
PIKA_LAYER_MODE_ADDITION, /*< desc="Addition" >*/
|
||||
PIKA_LAYER_MODE_SUBTRACT, /*< desc="Subtract" >*/
|
||||
PIKA_LAYER_MODE_DARKEN_ONLY, /*< desc="Darken only" >*/
|
||||
PIKA_LAYER_MODE_LIGHTEN_ONLY, /*< desc="Lighten only" >*/
|
||||
PIKA_LAYER_MODE_HSV_HUE, /*< desc="HSV Hue" >*/
|
||||
PIKA_LAYER_MODE_HSV_SATURATION, /*< desc="HSV Saturation" >*/
|
||||
PIKA_LAYER_MODE_HSL_COLOR, /*< desc="HSL Color" >*/
|
||||
PIKA_LAYER_MODE_HSV_VALUE, /*< desc="HSV Value" >*/
|
||||
PIKA_LAYER_MODE_DIVIDE, /*< desc="Divide" >*/
|
||||
PIKA_LAYER_MODE_DODGE, /*< desc="Dodge" >*/
|
||||
PIKA_LAYER_MODE_BURN, /*< desc="Burn" >*/
|
||||
PIKA_LAYER_MODE_HARDLIGHT, /*< desc="Hard light" >*/
|
||||
PIKA_LAYER_MODE_SOFTLIGHT, /*< desc="Soft light" >*/
|
||||
PIKA_LAYER_MODE_GRAIN_EXTRACT, /*< desc="Grain extract" >*/
|
||||
PIKA_LAYER_MODE_GRAIN_MERGE, /*< desc="Grain merge" >*/
|
||||
PIKA_LAYER_MODE_VIVID_LIGHT, /*< desc="Vivid light" >*/
|
||||
PIKA_LAYER_MODE_PIN_LIGHT, /*< desc="Pin light" >*/
|
||||
PIKA_LAYER_MODE_LINEAR_LIGHT, /*< desc="Linear light" >*/
|
||||
PIKA_LAYER_MODE_HARD_MIX, /*< desc="Hard mix" >*/
|
||||
PIKA_LAYER_MODE_EXCLUSION, /*< desc="Exclusion" >*/
|
||||
PIKA_LAYER_MODE_LINEAR_BURN, /*< desc="Linear burn" >*/
|
||||
PIKA_LAYER_MODE_LUMA_DARKEN_ONLY, /*< desc="Luma/Luminance darken only", abbrev="Luma darken only" >*/
|
||||
PIKA_LAYER_MODE_LUMA_LIGHTEN_ONLY, /*< desc="Luma/Luminance lighten only", abbrev="Luma lighten only" >*/
|
||||
PIKA_LAYER_MODE_LUMINANCE, /*< desc="Luminance" >*/
|
||||
PIKA_LAYER_MODE_COLOR_ERASE, /*< desc="Color erase" >*/
|
||||
PIKA_LAYER_MODE_ERASE, /*< desc="Erase" >*/
|
||||
PIKA_LAYER_MODE_MERGE, /*< desc="Merge" >*/
|
||||
PIKA_LAYER_MODE_SPLIT, /*< desc="Split" >*/
|
||||
PIKA_LAYER_MODE_PASS_THROUGH, /*< desc="Pass through" >*/
|
||||
|
||||
/* Internal modes, not available to the PDB, must be kept at the end */
|
||||
PIKA_LAYER_MODE_REPLACE, /*< pdb-skip, desc="Replace" >*/
|
||||
PIKA_LAYER_MODE_ANTI_ERASE, /*< pdb-skip, desc="Anti erase" >*/
|
||||
|
||||
/* Layer mode menu separator */
|
||||
PIKA_LAYER_MODE_SEPARATOR = -1 /*< pdb-skip, skip >*/
|
||||
} PikaLayerMode;
|
||||
|
||||
|
||||
#define PIKA_TYPE_LAYER_MODE_GROUP (pika_layer_mode_group_get_type ())
|
||||
|
||||
GType pika_layer_mode_group_get_type (void) G_GNUC_CONST;
|
||||
|
||||
typedef enum /*< pdb-skip >*/
|
||||
{
|
||||
PIKA_LAYER_MODE_GROUP_DEFAULT, /*< desc="Default" >*/
|
||||
PIKA_LAYER_MODE_GROUP_LEGACY, /*< desc="Legacy" >*/
|
||||
} PikaLayerModeGroup;
|
||||
|
||||
|
||||
#define PIKA_TYPE_LAYER_MODE_CONTEXT (pika_layer_mode_context_get_type ())
|
||||
|
||||
GType pika_layer_mode_context_get_type (void) G_GNUC_CONST;
|
||||
|
||||
typedef enum /*< pdb-skip >*/
|
||||
{
|
||||
PIKA_LAYER_MODE_CONTEXT_LAYER = 1 << 0,
|
||||
PIKA_LAYER_MODE_CONTEXT_GROUP = 1 << 1,
|
||||
PIKA_LAYER_MODE_CONTEXT_PAINT = 1 << 2,
|
||||
PIKA_LAYER_MODE_CONTEXT_FILTER = 1 << 3,
|
||||
|
||||
PIKA_LAYER_MODE_CONTEXT_ALL = (PIKA_LAYER_MODE_CONTEXT_LAYER |
|
||||
PIKA_LAYER_MODE_CONTEXT_GROUP |
|
||||
PIKA_LAYER_MODE_CONTEXT_PAINT |
|
||||
PIKA_LAYER_MODE_CONTEXT_FILTER)
|
||||
} PikaLayerModeContext;
|
||||
|
||||
|
||||
/*
|
||||
* non-registered enums; register them if needed
|
||||
*/
|
||||
|
||||
typedef enum /*< pdb-skip, skip >*/
|
||||
{
|
||||
PIKA_LAYER_COMPOSITE_REGION_INTERSECTION = 0,
|
||||
PIKA_LAYER_COMPOSITE_REGION_DESTINATION = 1 << 0,
|
||||
PIKA_LAYER_COMPOSITE_REGION_SOURCE = 1 << 1,
|
||||
PIKA_LAYER_COMPOSITE_REGION_UNION = (PIKA_LAYER_COMPOSITE_REGION_DESTINATION |
|
||||
PIKA_LAYER_COMPOSITE_REGION_SOURCE),
|
||||
} PikaLayerCompositeRegion;
|
||||
|
||||
typedef enum /*< pdb-skip, skip >*/
|
||||
{
|
||||
PIKA_LAYER_MODE_FLAG_LEGACY = 1 << 0,
|
||||
PIKA_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE = 1 << 1,
|
||||
PIKA_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE = 1 << 2,
|
||||
PIKA_LAYER_MODE_FLAG_COMPOSITE_MODE_IMMUTABLE = 1 << 3,
|
||||
PIKA_LAYER_MODE_FLAG_SUBTRACTIVE = 1 << 4,
|
||||
PIKA_LAYER_MODE_FLAG_ALPHA_ONLY = 1 << 5,
|
||||
PIKA_LAYER_MODE_FLAG_TRIVIAL = 1 << 6
|
||||
} PikaLayerModeFlags;
|
||||
|
||||
|
||||
#endif /* __OPERATIONS_ENUMS_H__ */
|
||||
80
app/operations/operations-types.h
Normal file
80
app/operations/operations-types.h
Normal file
@ -0,0 +1,80 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* operations-types.h
|
||||
*
|
||||
* 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 __OPERATIONS_TYPES_H__
|
||||
#define __OPERATIONS_TYPES_H__
|
||||
|
||||
|
||||
#include <gegl-types.h>
|
||||
|
||||
#include "gegl/pika-gegl-types.h"
|
||||
|
||||
#include "operations-enums.h"
|
||||
|
||||
|
||||
/* operations */
|
||||
|
||||
typedef struct _PikaOperationPointFilter PikaOperationPointFilter;
|
||||
typedef struct _PikaOperationLayerMode PikaOperationLayerMode;
|
||||
|
||||
|
||||
/* operation config objects */
|
||||
|
||||
typedef struct _PikaOperationSettings PikaOperationSettings;
|
||||
|
||||
typedef struct _PikaBrightnessContrastConfig PikaBrightnessContrastConfig;
|
||||
typedef struct _PikaCageConfig PikaCageConfig;
|
||||
typedef struct _PikaColorBalanceConfig PikaColorBalanceConfig;
|
||||
typedef struct _PikaColorizeConfig PikaColorizeConfig;
|
||||
typedef struct _PikaCurvesConfig PikaCurvesConfig;
|
||||
typedef struct _PikaDesaturateConfig PikaDesaturateConfig;
|
||||
typedef struct _PikaHueSaturationConfig PikaHueSaturationConfig;
|
||||
typedef struct _PikaLevelsConfig PikaLevelsConfig;
|
||||
typedef struct _PikaPosterizeConfig PikaPosterizeConfig;
|
||||
typedef struct _PikaThresholdConfig PikaThresholdConfig;
|
||||
|
||||
|
||||
/* non-object types */
|
||||
|
||||
typedef struct _PikaCagePoint PikaCagePoint;
|
||||
|
||||
|
||||
/* functions */
|
||||
|
||||
typedef gboolean (* PikaLayerModeFunc) (GeglOperation *operation,
|
||||
void *in,
|
||||
void *aux,
|
||||
void *mask,
|
||||
void *out,
|
||||
glong samples,
|
||||
const GeglRectangle *roi,
|
||||
gint level);
|
||||
|
||||
typedef void (* PikaLayerModeBlendFunc) (GeglOperation *operation,
|
||||
const gfloat *in,
|
||||
const gfloat *layer,
|
||||
gfloat *out,
|
||||
gint samples);
|
||||
|
||||
|
||||
#endif /* __OPERATIONS_TYPES_H__ */
|
||||
671
app/operations/pika-operation-config.c
Normal file
671
app/operations/pika-operation-config.c
Normal file
@ -0,0 +1,671 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* 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 <string.h>
|
||||
|
||||
#include <cairo.h>
|
||||
#include <gegl.h>
|
||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||
|
||||
#include "libpikabase/pikabase.h"
|
||||
#include "libpikacolor/pikacolor.h"
|
||||
#include "libpikaconfig/pikaconfig.h"
|
||||
|
||||
#include "operations-types.h"
|
||||
|
||||
#include "core/pika.h"
|
||||
|
||||
#include "core/pikalist.h"
|
||||
#include "core/pikaviewable.h"
|
||||
|
||||
#include "gegl/pika-gegl-utils.h"
|
||||
|
||||
#include "pika-operation-config.h"
|
||||
|
||||
|
||||
/* local function prototypes */
|
||||
|
||||
static void pika_operation_config_config_sync (GObject *config,
|
||||
const GParamSpec *pika_pspec,
|
||||
GeglNode *node);
|
||||
static void pika_operation_config_config_notify (GObject *config,
|
||||
const GParamSpec *pika_pspec,
|
||||
GeglNode *node);
|
||||
static void pika_operation_config_node_notify (GeglNode *node,
|
||||
const GParamSpec *gegl_pspec,
|
||||
GObject *config);
|
||||
|
||||
static GFile * pika_operation_config_get_file (GType config_type);
|
||||
static void pika_operation_config_add_sep (PikaContainer *container);
|
||||
static void pika_operation_config_remove_sep (PikaContainer *container);
|
||||
|
||||
|
||||
/* public functions */
|
||||
|
||||
static GHashTable *
|
||||
pika_operation_config_get_type_table (Pika *pika)
|
||||
{
|
||||
static GHashTable *config_types = NULL;
|
||||
|
||||
if (! config_types)
|
||||
config_types = g_hash_table_new_full (g_str_hash,
|
||||
g_str_equal,
|
||||
(GDestroyNotify) g_free,
|
||||
NULL);
|
||||
|
||||
return config_types;
|
||||
}
|
||||
|
||||
static GHashTable *
|
||||
pika_operation_config_get_container_table (Pika *pika)
|
||||
{
|
||||
static GHashTable *config_containers = NULL;
|
||||
|
||||
if (! config_containers)
|
||||
config_containers = g_hash_table_new_full (g_direct_hash,
|
||||
g_direct_equal,
|
||||
NULL,
|
||||
(GDestroyNotify) g_object_unref);
|
||||
|
||||
return config_containers;
|
||||
}
|
||||
|
||||
|
||||
/* public functions */
|
||||
|
||||
void
|
||||
pika_operation_config_register (Pika *pika,
|
||||
const gchar *operation,
|
||||
GType config_type)
|
||||
{
|
||||
GHashTable *config_types;
|
||||
|
||||
g_return_if_fail (PIKA_IS_PIKA (pika));
|
||||
g_return_if_fail (operation != NULL);
|
||||
g_return_if_fail (g_type_is_a (config_type, PIKA_TYPE_OBJECT));
|
||||
|
||||
config_types = pika_operation_config_get_type_table (pika);
|
||||
|
||||
g_hash_table_insert (config_types,
|
||||
g_strdup (operation),
|
||||
(gpointer) config_type);
|
||||
}
|
||||
|
||||
GType
|
||||
pika_operation_config_get_type (Pika *pika,
|
||||
const gchar *operation,
|
||||
const gchar *icon_name,
|
||||
GType parent_type)
|
||||
{
|
||||
GHashTable *config_types;
|
||||
GType config_type;
|
||||
|
||||
g_return_val_if_fail (PIKA_IS_PIKA (pika), G_TYPE_NONE);
|
||||
g_return_val_if_fail (operation != NULL, G_TYPE_NONE);
|
||||
g_return_val_if_fail (g_type_is_a (parent_type, PIKA_TYPE_OBJECT),
|
||||
G_TYPE_NONE);
|
||||
|
||||
config_types = pika_operation_config_get_type_table (pika);
|
||||
|
||||
config_type = (GType) g_hash_table_lookup (config_types, operation);
|
||||
|
||||
if (! config_type)
|
||||
{
|
||||
GParamSpec **pspecs;
|
||||
guint n_pspecs;
|
||||
gchar *type_name;
|
||||
gint i, j;
|
||||
|
||||
pspecs = gegl_operation_list_properties (operation, &n_pspecs);
|
||||
|
||||
for (i = 0, j = 0; i < n_pspecs; i++)
|
||||
{
|
||||
GParamSpec *pspec = pspecs[i];
|
||||
|
||||
if ((pspec->flags & G_PARAM_READABLE) &&
|
||||
(pspec->flags & G_PARAM_WRITABLE) &&
|
||||
strcmp (pspec->name, "input") &&
|
||||
strcmp (pspec->name, "output"))
|
||||
{
|
||||
pspecs[j] = pspec;
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
n_pspecs = j;
|
||||
|
||||
type_name = g_strdup_printf ("PikaGegl-%s-config", operation);
|
||||
|
||||
g_strcanon (type_name,
|
||||
G_CSET_DIGITS "-" G_CSET_a_2_z G_CSET_A_2_Z, '-');
|
||||
|
||||
config_type = pika_config_type_register (parent_type,
|
||||
type_name,
|
||||
pspecs, n_pspecs);
|
||||
|
||||
g_free (pspecs);
|
||||
g_free (type_name);
|
||||
|
||||
if (icon_name && g_type_is_a (config_type, PIKA_TYPE_VIEWABLE))
|
||||
{
|
||||
PikaViewableClass *viewable_class = g_type_class_ref (config_type);
|
||||
|
||||
viewable_class->default_icon_name = g_strdup (icon_name);
|
||||
|
||||
g_type_class_unref (viewable_class);
|
||||
}
|
||||
|
||||
pika_operation_config_register (pika, operation, config_type);
|
||||
}
|
||||
|
||||
return config_type;
|
||||
}
|
||||
|
||||
PikaContainer *
|
||||
pika_operation_config_get_container (Pika *pika,
|
||||
GType config_type,
|
||||
GCompareFunc sort_func)
|
||||
{
|
||||
GHashTable *config_containers;
|
||||
PikaContainer *container;
|
||||
|
||||
g_return_val_if_fail (PIKA_IS_PIKA (pika), NULL);
|
||||
g_return_val_if_fail (g_type_is_a (config_type, PIKA_TYPE_OBJECT), NULL);
|
||||
|
||||
config_containers = pika_operation_config_get_container_table (pika);
|
||||
|
||||
container = g_hash_table_lookup (config_containers, (gpointer) config_type);
|
||||
|
||||
if (! container)
|
||||
{
|
||||
container = pika_list_new (config_type, TRUE);
|
||||
pika_list_set_sort_func (PIKA_LIST (container), sort_func);
|
||||
|
||||
g_hash_table_insert (config_containers,
|
||||
(gpointer) config_type, container);
|
||||
|
||||
pika_operation_config_deserialize (pika, container, NULL);
|
||||
|
||||
if (pika_container_get_n_children (container) == 0)
|
||||
{
|
||||
GFile *file = pika_operation_config_get_file (config_type);
|
||||
|
||||
if (! g_file_query_exists (file, NULL))
|
||||
{
|
||||
GQuark quark = g_quark_from_static_string ("compat-file");
|
||||
GFile *compat_file;
|
||||
|
||||
compat_file = g_type_get_qdata (config_type, quark);
|
||||
|
||||
if (compat_file)
|
||||
{
|
||||
if (! g_file_move (compat_file, file, 0,
|
||||
NULL, NULL, NULL, NULL))
|
||||
{
|
||||
pika_operation_config_deserialize (pika, container,
|
||||
compat_file);
|
||||
}
|
||||
else
|
||||
{
|
||||
pika_operation_config_deserialize (pika, container, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
g_object_unref (file);
|
||||
}
|
||||
|
||||
pika_operation_config_add_sep (container);
|
||||
}
|
||||
|
||||
return container;
|
||||
}
|
||||
|
||||
void
|
||||
pika_operation_config_serialize (Pika *pika,
|
||||
PikaContainer *container,
|
||||
GFile *file)
|
||||
{
|
||||
GError *error = NULL;
|
||||
|
||||
g_return_if_fail (PIKA_IS_PIKA (pika));
|
||||
g_return_if_fail (PIKA_IS_CONTAINER (container));
|
||||
g_return_if_fail (file == NULL || G_IS_FILE (file));
|
||||
|
||||
if (file)
|
||||
{
|
||||
g_object_ref (file);
|
||||
}
|
||||
else
|
||||
{
|
||||
GType config_type = pika_container_get_children_type (container);
|
||||
|
||||
file = pika_operation_config_get_file (config_type);
|
||||
}
|
||||
|
||||
if (pika->be_verbose)
|
||||
g_print ("Writing '%s'\n", pika_file_get_utf8_name (file));
|
||||
|
||||
pika_operation_config_remove_sep (container);
|
||||
|
||||
if (! pika_config_serialize_to_file (PIKA_CONFIG (container),
|
||||
file,
|
||||
"settings",
|
||||
"end of settings",
|
||||
NULL, &error))
|
||||
{
|
||||
pika_message_literal (pika, NULL, PIKA_MESSAGE_ERROR,
|
||||
error->message);
|
||||
g_clear_error (&error);
|
||||
}
|
||||
|
||||
pika_operation_config_add_sep (container);
|
||||
|
||||
g_object_unref (file);
|
||||
}
|
||||
|
||||
void
|
||||
pika_operation_config_deserialize (Pika *pika,
|
||||
PikaContainer *container,
|
||||
GFile *file)
|
||||
{
|
||||
GError *error = NULL;
|
||||
|
||||
g_return_if_fail (PIKA_IS_PIKA (pika));
|
||||
g_return_if_fail (PIKA_IS_CONTAINER (container));
|
||||
g_return_if_fail (file == NULL || G_IS_FILE (file));
|
||||
|
||||
if (file)
|
||||
{
|
||||
g_object_ref (file);
|
||||
}
|
||||
else
|
||||
{
|
||||
GType config_type = pika_container_get_children_type (container);
|
||||
|
||||
file = pika_operation_config_get_file (config_type);
|
||||
}
|
||||
|
||||
if (pika->be_verbose)
|
||||
g_print ("Parsing '%s'\n", pika_file_get_utf8_name (file));
|
||||
|
||||
if (! pika_config_deserialize_file (PIKA_CONFIG (container),
|
||||
file,
|
||||
NULL, &error))
|
||||
{
|
||||
if (error->code != PIKA_CONFIG_ERROR_OPEN_ENOENT)
|
||||
pika_message_literal (pika, NULL, PIKA_MESSAGE_ERROR,
|
||||
error->message);
|
||||
|
||||
g_clear_error (&error);
|
||||
}
|
||||
|
||||
g_object_unref (file);
|
||||
}
|
||||
|
||||
void
|
||||
pika_operation_config_sync_node (GObject *config,
|
||||
GeglNode *node)
|
||||
{
|
||||
GParamSpec **pspecs;
|
||||
gchar *operation;
|
||||
guint n_pspecs;
|
||||
gint i;
|
||||
|
||||
g_return_if_fail (G_IS_OBJECT (config));
|
||||
g_return_if_fail (GEGL_IS_NODE (node));
|
||||
|
||||
gegl_node_get (node,
|
||||
"operation", &operation,
|
||||
NULL);
|
||||
|
||||
g_return_if_fail (operation != NULL);
|
||||
|
||||
pspecs = gegl_operation_list_properties (operation, &n_pspecs);
|
||||
g_free (operation);
|
||||
|
||||
for (i = 0; i < n_pspecs; i++)
|
||||
{
|
||||
GParamSpec *gegl_pspec = pspecs[i];
|
||||
GParamSpec *pika_pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (config),
|
||||
gegl_pspec->name);
|
||||
|
||||
/* if the operation has an object property of the config's
|
||||
* type, use the config object directly
|
||||
*/
|
||||
if (G_IS_PARAM_SPEC_OBJECT (gegl_pspec) &&
|
||||
gegl_pspec->value_type == G_TYPE_FROM_INSTANCE (config))
|
||||
{
|
||||
gegl_node_set (node,
|
||||
gegl_pspec->name, config,
|
||||
NULL);
|
||||
}
|
||||
else if (pika_pspec)
|
||||
{
|
||||
GValue value = G_VALUE_INIT;
|
||||
|
||||
g_value_init (&value, pika_pspec->value_type);
|
||||
|
||||
g_object_get_property (G_OBJECT (config), pika_pspec->name,
|
||||
&value);
|
||||
|
||||
if (GEGL_IS_PARAM_SPEC_COLOR (gegl_pspec))
|
||||
{
|
||||
PikaRGB pika_color;
|
||||
GeglColor *gegl_color;
|
||||
|
||||
pika_value_get_rgb (&value, &pika_color);
|
||||
g_value_unset (&value);
|
||||
|
||||
gegl_color = pika_gegl_color_new (&pika_color, NULL);
|
||||
|
||||
g_value_init (&value, gegl_pspec->value_type);
|
||||
g_value_take_object (&value, gegl_color);
|
||||
}
|
||||
|
||||
gegl_node_set_property (node, gegl_pspec->name,
|
||||
&value);
|
||||
|
||||
g_value_unset (&value);
|
||||
}
|
||||
}
|
||||
|
||||
g_free (pspecs);
|
||||
}
|
||||
|
||||
void
|
||||
pika_operation_config_connect_node (GObject *config,
|
||||
GeglNode *node)
|
||||
{
|
||||
GParamSpec **pspecs;
|
||||
gchar *operation;
|
||||
guint n_pspecs;
|
||||
gint i;
|
||||
|
||||
g_return_if_fail (G_IS_OBJECT (config));
|
||||
g_return_if_fail (GEGL_IS_NODE (node));
|
||||
|
||||
gegl_node_get (node,
|
||||
"operation", &operation,
|
||||
NULL);
|
||||
|
||||
g_return_if_fail (operation != NULL);
|
||||
|
||||
pspecs = gegl_operation_list_properties (operation, &n_pspecs);
|
||||
g_free (operation);
|
||||
|
||||
for (i = 0; i < n_pspecs; i++)
|
||||
{
|
||||
GParamSpec *pspec = pspecs[i];
|
||||
|
||||
/* if the operation has an object property of the config's
|
||||
* type, connect it to a special callback and done
|
||||
*/
|
||||
if (G_IS_PARAM_SPEC_OBJECT (pspec) &&
|
||||
pspec->value_type == G_TYPE_FROM_INSTANCE (config))
|
||||
{
|
||||
g_signal_connect_object (config, "notify",
|
||||
G_CALLBACK (pika_operation_config_config_sync),
|
||||
node, 0);
|
||||
g_free (pspecs);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < n_pspecs; i++)
|
||||
{
|
||||
GParamSpec *gegl_pspec = pspecs[i];
|
||||
GParamSpec *pika_pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (config),
|
||||
gegl_pspec->name);
|
||||
|
||||
if (pika_pspec)
|
||||
{
|
||||
gchar *notify_name = g_strconcat ("notify::", pika_pspec->name, NULL);
|
||||
|
||||
g_signal_connect_object (config, notify_name,
|
||||
G_CALLBACK (pika_operation_config_config_notify),
|
||||
node, 0);
|
||||
|
||||
g_signal_connect_object (node, notify_name,
|
||||
G_CALLBACK (pika_operation_config_node_notify),
|
||||
config, 0);
|
||||
|
||||
g_free (notify_name);
|
||||
}
|
||||
}
|
||||
|
||||
g_free (pspecs);
|
||||
}
|
||||
|
||||
GParamSpec **
|
||||
pika_operation_config_list_properties (GObject *config,
|
||||
GType owner_type,
|
||||
GParamFlags flags,
|
||||
guint *n_pspecs)
|
||||
{
|
||||
GParamSpec **param_specs;
|
||||
guint n_param_specs;
|
||||
gint i, j;
|
||||
|
||||
g_return_val_if_fail (G_IS_OBJECT (config), NULL);
|
||||
|
||||
param_specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (config),
|
||||
&n_param_specs);
|
||||
|
||||
for (i = 0, j = 0; i < n_param_specs; i++)
|
||||
{
|
||||
GParamSpec *pspec = param_specs[i];
|
||||
|
||||
/* ignore properties of parent classes of owner_type */
|
||||
if (! g_type_is_a (pspec->owner_type, owner_type))
|
||||
continue;
|
||||
|
||||
if (flags && ((pspec->flags & flags) != flags))
|
||||
continue;
|
||||
|
||||
if (pika_gegl_param_spec_has_key (pspec, "role", "output-extent"))
|
||||
continue;
|
||||
|
||||
param_specs[j] = param_specs[i];
|
||||
j++;
|
||||
}
|
||||
|
||||
if (n_pspecs)
|
||||
*n_pspecs = j;
|
||||
|
||||
if (j == 0)
|
||||
{
|
||||
g_free (param_specs);
|
||||
param_specs = NULL;
|
||||
}
|
||||
|
||||
return param_specs;
|
||||
}
|
||||
|
||||
|
||||
/* private functions */
|
||||
|
||||
static void
|
||||
pika_operation_config_config_sync (GObject *config,
|
||||
const GParamSpec *pika_pspec,
|
||||
GeglNode *node)
|
||||
{
|
||||
pika_operation_config_sync_node (config, node);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_operation_config_config_notify (GObject *config,
|
||||
const GParamSpec *pika_pspec,
|
||||
GeglNode *node)
|
||||
{
|
||||
GParamSpec *gegl_pspec = gegl_node_find_property (node, pika_pspec->name);
|
||||
|
||||
if (gegl_pspec)
|
||||
{
|
||||
GValue value = G_VALUE_INIT;
|
||||
gulong handler;
|
||||
|
||||
g_value_init (&value, pika_pspec->value_type);
|
||||
g_object_get_property (config, pika_pspec->name, &value);
|
||||
|
||||
if (GEGL_IS_PARAM_SPEC_COLOR (gegl_pspec))
|
||||
{
|
||||
PikaRGB pika_color;
|
||||
GeglColor *gegl_color;
|
||||
|
||||
pika_value_get_rgb (&value, &pika_color);
|
||||
g_value_unset (&value);
|
||||
|
||||
gegl_color = pika_gegl_color_new (&pika_color, NULL);
|
||||
|
||||
g_value_init (&value, gegl_pspec->value_type);
|
||||
g_value_take_object (&value, gegl_color);
|
||||
}
|
||||
|
||||
handler = g_signal_handler_find (node,
|
||||
G_SIGNAL_MATCH_DETAIL |
|
||||
G_SIGNAL_MATCH_FUNC |
|
||||
G_SIGNAL_MATCH_DATA,
|
||||
0,
|
||||
g_quark_from_string (gegl_pspec->name),
|
||||
NULL,
|
||||
pika_operation_config_node_notify,
|
||||
config);
|
||||
|
||||
if (handler)
|
||||
g_signal_handler_block (node, handler);
|
||||
|
||||
gegl_node_set_property (node, gegl_pspec->name, &value);
|
||||
g_value_unset (&value);
|
||||
|
||||
if (handler)
|
||||
g_signal_handler_unblock (node, handler);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_operation_config_node_notify (GeglNode *node,
|
||||
const GParamSpec *gegl_pspec,
|
||||
GObject *config)
|
||||
{
|
||||
GParamSpec *pika_pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (config),
|
||||
gegl_pspec->name);
|
||||
|
||||
if (pika_pspec)
|
||||
{
|
||||
GValue value = G_VALUE_INIT;
|
||||
gulong handler;
|
||||
|
||||
g_value_init (&value, gegl_pspec->value_type);
|
||||
gegl_node_get_property (node, gegl_pspec->name, &value);
|
||||
|
||||
if (GEGL_IS_PARAM_SPEC_COLOR (gegl_pspec))
|
||||
{
|
||||
GeglColor *gegl_color;
|
||||
PikaRGB pika_color;
|
||||
|
||||
gegl_color = g_value_dup_object (&value);
|
||||
g_value_unset (&value);
|
||||
|
||||
if (gegl_color)
|
||||
{
|
||||
gegl_color_get_rgba (gegl_color,
|
||||
&pika_color.r,
|
||||
&pika_color.g,
|
||||
&pika_color.b,
|
||||
&pika_color.a);
|
||||
g_object_unref (gegl_color);
|
||||
}
|
||||
else
|
||||
{
|
||||
pika_rgba_set (&pika_color, 0.0, 0.0, 0.0, 1.0);
|
||||
}
|
||||
|
||||
g_value_init (&value, pika_pspec->value_type);
|
||||
pika_value_set_rgb (&value, &pika_color);
|
||||
}
|
||||
|
||||
handler = g_signal_handler_find (config,
|
||||
G_SIGNAL_MATCH_DETAIL |
|
||||
G_SIGNAL_MATCH_FUNC |
|
||||
G_SIGNAL_MATCH_DATA,
|
||||
0,
|
||||
g_quark_from_string (pika_pspec->name),
|
||||
NULL,
|
||||
pika_operation_config_config_notify,
|
||||
node);
|
||||
|
||||
if (handler)
|
||||
g_signal_handler_block (config, handler);
|
||||
|
||||
g_object_set_property (config, pika_pspec->name, &value);
|
||||
g_value_unset (&value);
|
||||
|
||||
if (handler)
|
||||
g_signal_handler_unblock (config, handler);
|
||||
}
|
||||
}
|
||||
|
||||
static GFile *
|
||||
pika_operation_config_get_file (GType config_type)
|
||||
{
|
||||
GFile *file;
|
||||
gchar *basename;
|
||||
|
||||
basename = g_strconcat (g_type_name (config_type), ".settings", NULL);
|
||||
file = pika_directory_file ("filters", basename, NULL);
|
||||
g_free (basename);
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_operation_config_add_sep (PikaContainer *container)
|
||||
{
|
||||
PikaObject *sep = g_object_get_data (G_OBJECT (container), "separator");
|
||||
|
||||
if (! sep)
|
||||
{
|
||||
sep = g_object_new (pika_container_get_children_type (container),
|
||||
NULL);
|
||||
|
||||
pika_container_add (container, sep);
|
||||
g_object_unref (sep);
|
||||
|
||||
g_object_set_data (G_OBJECT (container), "separator", sep);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_operation_config_remove_sep (PikaContainer *container)
|
||||
{
|
||||
PikaObject *sep = g_object_get_data (G_OBJECT (container), "separator");
|
||||
|
||||
if (sep)
|
||||
{
|
||||
pika_container_remove (container, sep);
|
||||
|
||||
g_object_set_data (G_OBJECT (container), "separator", NULL);
|
||||
}
|
||||
}
|
||||
57
app/operations/pika-operation-config.h
Normal file
57
app/operations/pika-operation-config.h
Normal file
@ -0,0 +1,57 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* 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 __PIKA_OPERATION_CONFIG_H__
|
||||
#define __PIKA_OPERATION_CONFIG_H__
|
||||
|
||||
|
||||
void pika_operation_config_register (Pika *pika,
|
||||
const gchar *operation,
|
||||
GType config_type);
|
||||
|
||||
GType pika_operation_config_get_type (Pika *pika,
|
||||
const gchar *operation,
|
||||
const gchar *icon_name,
|
||||
GType parent_type);
|
||||
|
||||
PikaContainer * pika_operation_config_get_container (Pika *pika,
|
||||
GType config_type,
|
||||
GCompareFunc sort_func);
|
||||
|
||||
void pika_operation_config_serialize (Pika *pika,
|
||||
PikaContainer *container,
|
||||
GFile *file);
|
||||
void pika_operation_config_deserialize (Pika *pika,
|
||||
PikaContainer *container,
|
||||
GFile *file);
|
||||
|
||||
void pika_operation_config_sync_node (GObject *config,
|
||||
GeglNode *node);
|
||||
void pika_operation_config_connect_node (GObject *config,
|
||||
GeglNode *node);
|
||||
|
||||
GParamSpec ** pika_operation_config_list_properties (GObject *config,
|
||||
GType owner_type,
|
||||
GParamFlags flags,
|
||||
guint *n_pspecs);
|
||||
|
||||
|
||||
#endif /* __PIKA_OPERATION_CONFIG_H__ */
|
||||
237
app/operations/pika-operations.c
Normal file
237
app/operations/pika-operations.c
Normal file
@ -0,0 +1,237 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pika-operations.c
|
||||
*
|
||||
* 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 <gdk-pixbuf/gdk-pixbuf.h>
|
||||
#include <gegl.h>
|
||||
|
||||
#include "libpikabase/pikabase.h"
|
||||
|
||||
#include "operations-types.h"
|
||||
|
||||
#include "core/pika.h"
|
||||
|
||||
#include "pika-operations.h"
|
||||
|
||||
#include "pikaoperationborder.h"
|
||||
#include "pikaoperationbuffersourcevalidate.h"
|
||||
#include "pikaoperationcagecoefcalc.h"
|
||||
#include "pikaoperationcagetransform.h"
|
||||
#include "pikaoperationcomposecrop.h"
|
||||
#include "pikaoperationequalize.h"
|
||||
#include "pikaoperationfillsource.h"
|
||||
#include "pikaoperationflood.h"
|
||||
#include "pikaoperationgradient.h"
|
||||
#include "pikaoperationgrow.h"
|
||||
#include "pikaoperationhistogramsink.h"
|
||||
#include "pikaoperationmaskcomponents.h"
|
||||
#include "pikaoperationoffset.h"
|
||||
#include "pikaoperationprofiletransform.h"
|
||||
#include "pikaoperationscalarmultiply.h"
|
||||
#include "pikaoperationsemiflatten.h"
|
||||
#include "pikaoperationsetalpha.h"
|
||||
#include "pikaoperationshrink.h"
|
||||
#include "pikaoperationthresholdalpha.h"
|
||||
|
||||
#include "pikaoperationbrightnesscontrast.h"
|
||||
#include "pikaoperationcolorbalance.h"
|
||||
#include "pikaoperationcolorize.h"
|
||||
#include "pikaoperationcurves.h"
|
||||
#include "pikaoperationdesaturate.h"
|
||||
#include "pikaoperationhuesaturation.h"
|
||||
#include "pikaoperationlevels.h"
|
||||
#include "pikaoperationposterize.h"
|
||||
#include "pikaoperationthreshold.h"
|
||||
|
||||
#include "pika-operation-config.h"
|
||||
#include "pikabrightnesscontrastconfig.h"
|
||||
#include "pikacolorbalanceconfig.h"
|
||||
#include "pikacurvesconfig.h"
|
||||
#include "pikahuesaturationconfig.h"
|
||||
#include "pikalevelsconfig.h"
|
||||
|
||||
#include "layer-modes-legacy/pikaoperationadditionlegacy.h"
|
||||
#include "layer-modes-legacy/pikaoperationburnlegacy.h"
|
||||
#include "layer-modes-legacy/pikaoperationdarkenonlylegacy.h"
|
||||
#include "layer-modes-legacy/pikaoperationdifferencelegacy.h"
|
||||
#include "layer-modes-legacy/pikaoperationdividelegacy.h"
|
||||
#include "layer-modes-legacy/pikaoperationdodgelegacy.h"
|
||||
#include "layer-modes-legacy/pikaoperationgrainextractlegacy.h"
|
||||
#include "layer-modes-legacy/pikaoperationgrainmergelegacy.h"
|
||||
#include "layer-modes-legacy/pikaoperationhardlightlegacy.h"
|
||||
#include "layer-modes-legacy/pikaoperationhslcolorlegacy.h"
|
||||
#include "layer-modes-legacy/pikaoperationhsvhuelegacy.h"
|
||||
#include "layer-modes-legacy/pikaoperationhsvsaturationlegacy.h"
|
||||
#include "layer-modes-legacy/pikaoperationhsvvaluelegacy.h"
|
||||
#include "layer-modes-legacy/pikaoperationlightenonlylegacy.h"
|
||||
#include "layer-modes-legacy/pikaoperationmultiplylegacy.h"
|
||||
#include "layer-modes-legacy/pikaoperationscreenlegacy.h"
|
||||
#include "layer-modes-legacy/pikaoperationsoftlightlegacy.h"
|
||||
#include "layer-modes-legacy/pikaoperationsubtractlegacy.h"
|
||||
|
||||
#include "layer-modes/pika-layer-modes.h"
|
||||
#include "layer-modes/pikaoperationantierase.h"
|
||||
#include "layer-modes/pikaoperationbehind.h"
|
||||
#include "layer-modes/pikaoperationdissolve.h"
|
||||
#include "layer-modes/pikaoperationerase.h"
|
||||
#include "layer-modes/pikaoperationmerge.h"
|
||||
#include "layer-modes/pikaoperationnormal.h"
|
||||
#include "layer-modes/pikaoperationpassthrough.h"
|
||||
#include "layer-modes/pikaoperationreplace.h"
|
||||
#include "layer-modes/pikaoperationsplit.h"
|
||||
|
||||
|
||||
static void
|
||||
set_compat_file (GType type,
|
||||
const gchar *basename)
|
||||
{
|
||||
GFile *file = pika_directory_file ("tool-options", basename, NULL);
|
||||
GQuark quark = g_quark_from_static_string ("compat-file");
|
||||
|
||||
g_type_set_qdata (type, quark, file);
|
||||
}
|
||||
|
||||
static void
|
||||
set_settings_folder (GType type,
|
||||
const gchar *basename)
|
||||
{
|
||||
GFile *file = pika_directory_file (basename, NULL);
|
||||
GQuark quark = g_quark_from_static_string ("settings-folder");
|
||||
|
||||
g_type_set_qdata (type, quark, file);
|
||||
}
|
||||
|
||||
void
|
||||
pika_operations_init (Pika *pika)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_PIKA (pika));
|
||||
|
||||
pika_layer_modes_init ();
|
||||
|
||||
g_type_class_ref (PIKA_TYPE_OPERATION_BORDER);
|
||||
g_type_class_ref (PIKA_TYPE_OPERATION_BUFFER_SOURCE_VALIDATE);
|
||||
g_type_class_ref (PIKA_TYPE_OPERATION_CAGE_COEF_CALC);
|
||||
g_type_class_ref (PIKA_TYPE_OPERATION_CAGE_TRANSFORM);
|
||||
g_type_class_ref (PIKA_TYPE_OPERATION_COMPOSE_CROP);
|
||||
g_type_class_ref (PIKA_TYPE_OPERATION_EQUALIZE);
|
||||
g_type_class_ref (PIKA_TYPE_OPERATION_FILL_SOURCE);
|
||||
g_type_class_ref (PIKA_TYPE_OPERATION_FLOOD);
|
||||
g_type_class_ref (PIKA_TYPE_OPERATION_GRADIENT);
|
||||
g_type_class_ref (PIKA_TYPE_OPERATION_GROW);
|
||||
g_type_class_ref (PIKA_TYPE_OPERATION_HISTOGRAM_SINK);
|
||||
g_type_class_ref (PIKA_TYPE_OPERATION_MASK_COMPONENTS);
|
||||
g_type_class_ref (PIKA_TYPE_OPERATION_OFFSET);
|
||||
g_type_class_ref (PIKA_TYPE_OPERATION_PROFILE_TRANSFORM);
|
||||
g_type_class_ref (PIKA_TYPE_OPERATION_SCALAR_MULTIPLY);
|
||||
g_type_class_ref (PIKA_TYPE_OPERATION_SEMI_FLATTEN);
|
||||
g_type_class_ref (PIKA_TYPE_OPERATION_SET_ALPHA);
|
||||
g_type_class_ref (PIKA_TYPE_OPERATION_SHRINK);
|
||||
g_type_class_ref (PIKA_TYPE_OPERATION_THRESHOLD_ALPHA);
|
||||
|
||||
g_type_class_ref (PIKA_TYPE_OPERATION_BRIGHTNESS_CONTRAST);
|
||||
g_type_class_ref (PIKA_TYPE_OPERATION_COLOR_BALANCE);
|
||||
g_type_class_ref (PIKA_TYPE_OPERATION_COLORIZE);
|
||||
g_type_class_ref (PIKA_TYPE_OPERATION_CURVES);
|
||||
g_type_class_ref (PIKA_TYPE_OPERATION_DESATURATE);
|
||||
g_type_class_ref (PIKA_TYPE_OPERATION_HUE_SATURATION);
|
||||
g_type_class_ref (PIKA_TYPE_OPERATION_LEVELS);
|
||||
g_type_class_ref (PIKA_TYPE_OPERATION_POSTERIZE);
|
||||
g_type_class_ref (PIKA_TYPE_OPERATION_THRESHOLD);
|
||||
|
||||
g_type_class_ref (PIKA_TYPE_OPERATION_NORMAL);
|
||||
g_type_class_ref (PIKA_TYPE_OPERATION_DISSOLVE);
|
||||
g_type_class_ref (PIKA_TYPE_OPERATION_BEHIND);
|
||||
g_type_class_ref (PIKA_TYPE_OPERATION_MULTIPLY_LEGACY);
|
||||
g_type_class_ref (PIKA_TYPE_OPERATION_SCREEN_LEGACY);
|
||||
g_type_class_ref (PIKA_TYPE_OPERATION_DIFFERENCE_LEGACY);
|
||||
g_type_class_ref (PIKA_TYPE_OPERATION_ADDITION_LEGACY);
|
||||
g_type_class_ref (PIKA_TYPE_OPERATION_SUBTRACT_LEGACY);
|
||||
g_type_class_ref (PIKA_TYPE_OPERATION_DARKEN_ONLY_LEGACY);
|
||||
g_type_class_ref (PIKA_TYPE_OPERATION_LIGHTEN_ONLY_LEGACY);
|
||||
g_type_class_ref (PIKA_TYPE_OPERATION_HSV_HUE_LEGACY);
|
||||
g_type_class_ref (PIKA_TYPE_OPERATION_HSV_SATURATION_LEGACY);
|
||||
g_type_class_ref (PIKA_TYPE_OPERATION_HSL_COLOR_LEGACY);
|
||||
g_type_class_ref (PIKA_TYPE_OPERATION_HSV_VALUE_LEGACY);
|
||||
g_type_class_ref (PIKA_TYPE_OPERATION_DIVIDE_LEGACY);
|
||||
g_type_class_ref (PIKA_TYPE_OPERATION_DODGE_LEGACY);
|
||||
g_type_class_ref (PIKA_TYPE_OPERATION_BURN_LEGACY);
|
||||
g_type_class_ref (PIKA_TYPE_OPERATION_HARDLIGHT_LEGACY);
|
||||
g_type_class_ref (PIKA_TYPE_OPERATION_SOFTLIGHT_LEGACY);
|
||||
g_type_class_ref (PIKA_TYPE_OPERATION_GRAIN_EXTRACT_LEGACY);
|
||||
g_type_class_ref (PIKA_TYPE_OPERATION_GRAIN_MERGE_LEGACY);
|
||||
g_type_class_ref (PIKA_TYPE_OPERATION_ERASE);
|
||||
g_type_class_ref (PIKA_TYPE_OPERATION_MERGE);
|
||||
g_type_class_ref (PIKA_TYPE_OPERATION_SPLIT);
|
||||
g_type_class_ref (PIKA_TYPE_OPERATION_PASS_THROUGH);
|
||||
g_type_class_ref (PIKA_TYPE_OPERATION_REPLACE);
|
||||
g_type_class_ref (PIKA_TYPE_OPERATION_ANTI_ERASE);
|
||||
|
||||
pika_operation_config_register (pika,
|
||||
"pika:brightness-contrast",
|
||||
PIKA_TYPE_BRIGHTNESS_CONTRAST_CONFIG);
|
||||
set_compat_file (PIKA_TYPE_BRIGHTNESS_CONTRAST_CONFIG,
|
||||
"pika-brightness-contrast-tool.settings");
|
||||
set_settings_folder (PIKA_TYPE_BRIGHTNESS_CONTRAST_CONFIG,
|
||||
"brightness-contrast");
|
||||
|
||||
pika_operation_config_register (pika,
|
||||
"pika:color-balance",
|
||||
PIKA_TYPE_COLOR_BALANCE_CONFIG);
|
||||
set_compat_file (PIKA_TYPE_COLOR_BALANCE_CONFIG,
|
||||
"pika-color-balance-tool.settings");
|
||||
set_settings_folder (PIKA_TYPE_COLOR_BALANCE_CONFIG,
|
||||
"color-balance");
|
||||
|
||||
pika_operation_config_register (pika,
|
||||
"pika:curves",
|
||||
PIKA_TYPE_CURVES_CONFIG);
|
||||
set_compat_file (PIKA_TYPE_CURVES_CONFIG,
|
||||
"pika-curves-tool.settings");
|
||||
set_settings_folder (PIKA_TYPE_CURVES_CONFIG,
|
||||
"curves");
|
||||
|
||||
pika_operation_config_register (pika,
|
||||
"pika:hue-saturation",
|
||||
PIKA_TYPE_HUE_SATURATION_CONFIG);
|
||||
set_compat_file (PIKA_TYPE_HUE_SATURATION_CONFIG,
|
||||
"pika-hue-saturation-tool.settings");
|
||||
set_settings_folder (PIKA_TYPE_HUE_SATURATION_CONFIG,
|
||||
"hue-saturation");
|
||||
|
||||
pika_operation_config_register (pika,
|
||||
"pika:levels",
|
||||
PIKA_TYPE_LEVELS_CONFIG);
|
||||
set_compat_file (PIKA_TYPE_LEVELS_CONFIG,
|
||||
"pika-levels-tool.settings");
|
||||
set_settings_folder (PIKA_TYPE_LEVELS_CONFIG,
|
||||
"levels");
|
||||
}
|
||||
|
||||
void
|
||||
pika_operations_exit (Pika *pika)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_PIKA (pika));
|
||||
|
||||
pika_layer_modes_exit ();
|
||||
}
|
||||
32
app/operations/pika-operations.h
Normal file
32
app/operations/pika-operations.h
Normal file
@ -0,0 +1,32 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pika-operations.h
|
||||
*
|
||||
* 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 __PIKA_OPERATIONS_H__
|
||||
#define __PIKA_OPERATIONS_H__
|
||||
|
||||
|
||||
void pika_operations_init (Pika *pika);
|
||||
void pika_operations_exit (Pika *pika);
|
||||
|
||||
|
||||
#endif /* __PIKA_OPERATIONS_H__ */
|
||||
252
app/operations/pikabrightnesscontrastconfig.c
Normal file
252
app/operations/pikabrightnesscontrastconfig.c
Normal file
@ -0,0 +1,252 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikabrightnesscontrastconfig.c
|
||||
* Copyright (C) 2007 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* 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 <gdk-pixbuf/gdk-pixbuf.h>
|
||||
#include <gegl.h>
|
||||
|
||||
#include "libpikamath/pikamath.h"
|
||||
#include "libpikaconfig/pikaconfig.h"
|
||||
|
||||
#include "operations-types.h"
|
||||
|
||||
#include "pikabrightnesscontrastconfig.h"
|
||||
#include "pikalevelsconfig.h"
|
||||
|
||||
#include "pika-intl.h"
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_BRIGHTNESS,
|
||||
PROP_CONTRAST
|
||||
};
|
||||
|
||||
|
||||
static void pika_brightness_contrast_config_iface_init (PikaConfigInterface *iface);
|
||||
|
||||
static void pika_brightness_contrast_config_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void pika_brightness_contrast_config_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec);
|
||||
|
||||
static gboolean pika_brightness_contrast_config_equal (PikaConfig *a,
|
||||
PikaConfig *b);
|
||||
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (PikaBrightnessContrastConfig,
|
||||
pika_brightness_contrast_config,
|
||||
PIKA_TYPE_OPERATION_SETTINGS,
|
||||
G_IMPLEMENT_INTERFACE (PIKA_TYPE_CONFIG,
|
||||
pika_brightness_contrast_config_iface_init))
|
||||
|
||||
#define parent_class pika_brightness_contrast_config_parent_class
|
||||
|
||||
|
||||
static void
|
||||
pika_brightness_contrast_config_class_init (PikaBrightnessContrastConfigClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
PikaViewableClass *viewable_class = PIKA_VIEWABLE_CLASS (klass);
|
||||
|
||||
object_class->set_property = pika_brightness_contrast_config_set_property;
|
||||
object_class->get_property = pika_brightness_contrast_config_get_property;
|
||||
|
||||
viewable_class->default_icon_name = "pika-tool-brightness-contrast";
|
||||
|
||||
PIKA_CONFIG_PROP_DOUBLE (object_class, PROP_BRIGHTNESS,
|
||||
"brightness",
|
||||
_("Brightness"),
|
||||
_("Brightness"),
|
||||
-1.0, 1.0, 0.0, 0);
|
||||
|
||||
PIKA_CONFIG_PROP_DOUBLE (object_class, PROP_CONTRAST,
|
||||
"contrast",
|
||||
_("Contrast"),
|
||||
_("Contrast"),
|
||||
-1.0, 1.0, 0.0, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_brightness_contrast_config_iface_init (PikaConfigInterface *iface)
|
||||
{
|
||||
iface->equal = pika_brightness_contrast_config_equal;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_brightness_contrast_config_init (PikaBrightnessContrastConfig *self)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
pika_brightness_contrast_config_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaBrightnessContrastConfig *self = PIKA_BRIGHTNESS_CONTRAST_CONFIG (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_BRIGHTNESS:
|
||||
g_value_set_double (value, self->brightness);
|
||||
break;
|
||||
|
||||
case PROP_CONTRAST:
|
||||
g_value_set_double (value, self->contrast);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_brightness_contrast_config_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaBrightnessContrastConfig *self = PIKA_BRIGHTNESS_CONTRAST_CONFIG (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_BRIGHTNESS:
|
||||
self->brightness = g_value_get_double (value);
|
||||
break;
|
||||
|
||||
case PROP_CONTRAST:
|
||||
self->contrast = g_value_get_double (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_brightness_contrast_config_equal (PikaConfig *a,
|
||||
PikaConfig *b)
|
||||
{
|
||||
PikaBrightnessContrastConfig *config_a = PIKA_BRIGHTNESS_CONTRAST_CONFIG (a);
|
||||
PikaBrightnessContrastConfig *config_b = PIKA_BRIGHTNESS_CONTRAST_CONFIG (b);
|
||||
|
||||
if (! pika_operation_settings_config_equal_base (a, b) ||
|
||||
config_a->brightness != config_b->brightness ||
|
||||
config_a->contrast != config_b->contrast)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/* public functions */
|
||||
|
||||
PikaLevelsConfig *
|
||||
pika_brightness_contrast_config_to_levels_config (PikaBrightnessContrastConfig *config)
|
||||
{
|
||||
PikaLevelsConfig *levels;
|
||||
gdouble brightness;
|
||||
gdouble slant;
|
||||
gdouble value;
|
||||
|
||||
g_return_val_if_fail (PIKA_IS_BRIGHTNESS_CONTRAST_CONFIG (config), NULL);
|
||||
|
||||
levels = g_object_new (PIKA_TYPE_LEVELS_CONFIG, NULL);
|
||||
|
||||
pika_operation_settings_config_copy_base (PIKA_CONFIG (config),
|
||||
PIKA_CONFIG (levels),
|
||||
0);
|
||||
|
||||
brightness = config->brightness / 2.0;
|
||||
slant = tan ((config->contrast + 1) * G_PI_4);
|
||||
|
||||
if (config->brightness >= 0)
|
||||
{
|
||||
value = -0.5 * slant + brightness * slant + 0.5;
|
||||
|
||||
if (value < 0.0)
|
||||
{
|
||||
value = 0.0;
|
||||
|
||||
/* this slightly convoluted math follows by inverting the
|
||||
* calculation of the brightness/contrast LUT in base/lut-funcs.h */
|
||||
|
||||
levels->low_input[PIKA_HISTOGRAM_VALUE] =
|
||||
(- brightness * slant + 0.5 * slant - 0.5) / (slant - brightness * slant);
|
||||
}
|
||||
|
||||
levels->low_output[PIKA_HISTOGRAM_VALUE] = value;
|
||||
|
||||
value = 0.5 * slant + 0.5;
|
||||
|
||||
if (value > 1.0)
|
||||
{
|
||||
value = 1.0;
|
||||
|
||||
levels->high_input[PIKA_HISTOGRAM_VALUE] =
|
||||
(- brightness * slant + 0.5 * slant + 0.5) / (slant - brightness * slant);
|
||||
}
|
||||
|
||||
levels->high_output[PIKA_HISTOGRAM_VALUE] = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
value = 0.5 - 0.5 * slant;
|
||||
|
||||
if (value < 0.0)
|
||||
{
|
||||
value = 0.0;
|
||||
|
||||
levels->low_input[PIKA_HISTOGRAM_VALUE] =
|
||||
(0.5 * slant - 0.5) / (slant + brightness * slant);
|
||||
}
|
||||
|
||||
levels->low_output[PIKA_HISTOGRAM_VALUE] = value;
|
||||
|
||||
value = slant * brightness + slant * 0.5 + 0.5;
|
||||
|
||||
if (value > 1.0)
|
||||
{
|
||||
value = 1.0;
|
||||
|
||||
levels->high_input[PIKA_HISTOGRAM_VALUE] =
|
||||
(0.5 * slant + 0.5) / (slant + brightness * slant);
|
||||
}
|
||||
|
||||
levels->high_output[PIKA_HISTOGRAM_VALUE] = value;
|
||||
}
|
||||
|
||||
return levels;
|
||||
}
|
||||
62
app/operations/pikabrightnesscontrastconfig.h
Normal file
62
app/operations/pikabrightnesscontrastconfig.h
Normal file
@ -0,0 +1,62 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikabrightnesscontrastconfig.h
|
||||
* Copyright (C) 2007 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* 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 __PIKA_BRIGHTNESS_CONTRAST_CONFIG_H__
|
||||
#define __PIKA_BRIGHTNESS_CONTRAST_CONFIG_H__
|
||||
|
||||
|
||||
#include "pikaoperationsettings.h"
|
||||
|
||||
|
||||
#define PIKA_TYPE_BRIGHTNESS_CONTRAST_CONFIG (pika_brightness_contrast_config_get_type ())
|
||||
#define PIKA_BRIGHTNESS_CONTRAST_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_BRIGHTNESS_CONTRAST_CONFIG, PikaBrightnessContrastConfig))
|
||||
#define PIKA_BRIGHTNESS_CONTRAST_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_BRIGHTNESS_CONTRAST_CONFIG, PikaBrightnessContrastConfigClass))
|
||||
#define PIKA_IS_BRIGHTNESS_CONTRAST_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_BRIGHTNESS_CONTRAST_CONFIG))
|
||||
#define PIKA_IS_BRIGHTNESS_CONTRAST_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_BRIGHTNESS_CONTRAST_CONFIG))
|
||||
#define PIKA_BRIGHTNESS_CONTRAST_CONFIG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_BRIGHTNESS_CONTRAST_CONFIG, PikaBrightnessContrastConfigClass))
|
||||
|
||||
|
||||
typedef struct _PikaBrightnessContrastConfigClass PikaBrightnessContrastConfigClass;
|
||||
|
||||
struct _PikaBrightnessContrastConfig
|
||||
{
|
||||
PikaOperationSettings parent_instance;
|
||||
|
||||
gdouble brightness;
|
||||
gdouble contrast;
|
||||
};
|
||||
|
||||
struct _PikaBrightnessContrastConfigClass
|
||||
{
|
||||
PikaOperationSettingsClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType pika_brightness_contrast_config_get_type (void) G_GNUC_CONST;
|
||||
|
||||
PikaLevelsConfig *
|
||||
pika_brightness_contrast_config_to_levels_config (PikaBrightnessContrastConfig *config);
|
||||
|
||||
|
||||
#endif /* __PIKA_BRIGHTNESS_CONTRAST_CONFIG_H__ */
|
||||
836
app/operations/pikacageconfig.c
Normal file
836
app/operations/pikacageconfig.c
Normal file
@ -0,0 +1,836 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
*
|
||||
* pikacageconfig.c
|
||||
* Copyright (C) 2010 Michael Muré <batolettre@gmail.com>
|
||||
*
|
||||
* 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 <gdk-pixbuf/gdk-pixbuf.h>
|
||||
#include <gegl.h>
|
||||
|
||||
#include "libpikaconfig/pikaconfig.h"
|
||||
#include "libpikamath/pikamath.h"
|
||||
#include "libpikabase/pikabase.h"
|
||||
|
||||
#include "operations-types.h"
|
||||
|
||||
#include "pikacageconfig.h"
|
||||
|
||||
|
||||
/*#define DEBUG_CAGE */
|
||||
|
||||
/* This DELTA is aimed to not have handle on exact pixel during computation,
|
||||
* to avoid particular case. It shouldn't be so useful, but it's a double
|
||||
* safety. */
|
||||
#define DELTA 0.010309278351
|
||||
|
||||
|
||||
static void pika_cage_config_finalize (GObject *object);
|
||||
static void pika_cage_config_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void pika_cage_config_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec);
|
||||
|
||||
static void pika_cage_config_compute_scaling_factor (PikaCageConfig *gcc);
|
||||
static void pika_cage_config_compute_edges_normal (PikaCageConfig *gcc);
|
||||
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (PikaCageConfig, pika_cage_config,
|
||||
PIKA_TYPE_OPERATION_SETTINGS,
|
||||
G_IMPLEMENT_INTERFACE (PIKA_TYPE_CONFIG,
|
||||
NULL))
|
||||
|
||||
#define parent_class pika_cage_config_parent_class
|
||||
|
||||
#ifdef DEBUG_CAGE
|
||||
static void
|
||||
print_cage (PikaCageConfig *gcc)
|
||||
{
|
||||
gint i;
|
||||
GeglRectangle bounding_box;
|
||||
PikaCagePoint *point;
|
||||
|
||||
g_return_if_fail (PIKA_IS_CAGE_CONFIG (gcc));
|
||||
|
||||
bounding_box = pika_cage_config_get_bounding_box (gcc);
|
||||
|
||||
for (i = 0; i < gcc->cage_points->len; i++)
|
||||
{
|
||||
point = &g_array_index (gcc->cage_points, PikaCagePoint, i);
|
||||
g_printerr ("cgx: %.0f cgy: %.0f cvdx: %.0f cvdy: %.0f sf: %.2f normx: %.2f normy: %.2f %s\n",
|
||||
point->src_point.x + ((gcc->cage_mode==PIKA_CAGE_MODE_CAGE_CHANGE)?gcc->displacement_x:0),
|
||||
point->src_point.y + ((gcc->cage_mode==PIKA_CAGE_MODE_CAGE_CHANGE)?gcc->displacement_y:0),
|
||||
point->dest_point.x + ((gcc->cage_mode==PIKA_CAGE_MODE_DEFORM)?gcc->displacement_x:0),
|
||||
point->dest_point.y + ((gcc->cage_mode==PIKA_CAGE_MODE_DEFORM)?gcc->displacement_y:0),
|
||||
point->edge_scaling_factor,
|
||||
point->edge_normal.x,
|
||||
point->edge_normal.y,
|
||||
((point->selected) ? "S" : "NS"));
|
||||
}
|
||||
|
||||
g_printerr ("bounding box: x: %d y: %d width: %d height: %d\n", bounding_box.x, bounding_box.y, bounding_box.width, bounding_box.height);
|
||||
g_printerr ("disp x: %f disp y: %f\n", gcc->displacement_x, gcc->displacement_y);
|
||||
g_printerr ("done\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
pika_cage_config_class_init (PikaCageConfigClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->set_property = pika_cage_config_set_property;
|
||||
object_class->get_property = pika_cage_config_get_property;
|
||||
|
||||
object_class->finalize = pika_cage_config_finalize;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_cage_config_init (PikaCageConfig *self)
|
||||
{
|
||||
/*pre-allocation for 50 vertices for the cage.*/
|
||||
self->cage_points = g_array_sized_new (FALSE, FALSE, sizeof(PikaCagePoint), 50);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_cage_config_finalize (GObject *object)
|
||||
{
|
||||
PikaCageConfig *gcc = PIKA_CAGE_CONFIG (object);
|
||||
|
||||
g_array_free (gcc->cage_points, TRUE);
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_cage_config_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
switch (property_id)
|
||||
{
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_cage_config_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
switch (property_id)
|
||||
{
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* pika_cage_config_get_n_points:
|
||||
* @gcc: the cage config
|
||||
*
|
||||
* Returns: the number of points of the cage
|
||||
*/
|
||||
guint
|
||||
pika_cage_config_get_n_points (PikaCageConfig *gcc)
|
||||
{
|
||||
return gcc->cage_points->len;
|
||||
}
|
||||
|
||||
/**
|
||||
* pika_cage_config_add_cage_point:
|
||||
* @gcc: the cage config
|
||||
* @x: x value of the new point
|
||||
* @y: y value of the new point
|
||||
*
|
||||
* Add a new point in the last index of the polygon of the cage.
|
||||
* Point is added in both source and destination cage
|
||||
*/
|
||||
void
|
||||
pika_cage_config_add_cage_point (PikaCageConfig *gcc,
|
||||
gdouble x,
|
||||
gdouble y)
|
||||
{
|
||||
pika_cage_config_insert_cage_point (gcc, gcc->cage_points->len, x, y);
|
||||
}
|
||||
|
||||
/**
|
||||
* pika_cage_config_insert_cage_point:
|
||||
* @gcc: the cage config
|
||||
* @point_number: index where the point will be inserted
|
||||
* @x: x value of the new point
|
||||
* @y: y value of the new point
|
||||
*
|
||||
* Insert a new point in the polygon of the cage at the given index.
|
||||
* Point is added in both source and destination cage
|
||||
*/
|
||||
void
|
||||
pika_cage_config_insert_cage_point (PikaCageConfig *gcc,
|
||||
gint point_number,
|
||||
gdouble x,
|
||||
gdouble y)
|
||||
{
|
||||
PikaCagePoint point;
|
||||
|
||||
g_return_if_fail (PIKA_IS_CAGE_CONFIG (gcc));
|
||||
g_return_if_fail (point_number <= gcc->cage_points->len);
|
||||
g_return_if_fail (point_number >= 0);
|
||||
|
||||
point.src_point.x = x + DELTA;
|
||||
point.src_point.y = y + DELTA;
|
||||
|
||||
point.dest_point.x = x + DELTA;
|
||||
point.dest_point.y = y + DELTA;
|
||||
|
||||
g_array_insert_val (gcc->cage_points, point_number, point);
|
||||
|
||||
pika_cage_config_compute_scaling_factor (gcc);
|
||||
pika_cage_config_compute_edges_normal (gcc);
|
||||
}
|
||||
|
||||
/**
|
||||
* pika_cage_config_remove_last_cage_point:
|
||||
* @gcc: the cage config
|
||||
*
|
||||
* Remove the last point of the cage, in both source and destination cage
|
||||
*/
|
||||
void
|
||||
pika_cage_config_remove_last_cage_point (PikaCageConfig *gcc)
|
||||
{
|
||||
pika_cage_config_remove_cage_point (gcc, gcc->cage_points->len - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* pika_cage_config_remove_cage_point:
|
||||
* @gcc: the cage config
|
||||
* @point_number: the index of the point to remove
|
||||
*
|
||||
* Remove the given point from the cage
|
||||
*/
|
||||
void
|
||||
pika_cage_config_remove_cage_point (PikaCageConfig *gcc,
|
||||
gint point_number)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_CAGE_CONFIG (gcc));
|
||||
g_return_if_fail (point_number < gcc->cage_points->len);
|
||||
g_return_if_fail (point_number >= 0);
|
||||
|
||||
if (gcc->cage_points->len > 0)
|
||||
g_array_remove_index (gcc->cage_points, gcc->cage_points->len - 1);
|
||||
|
||||
pika_cage_config_compute_scaling_factor (gcc);
|
||||
pika_cage_config_compute_edges_normal (gcc);
|
||||
}
|
||||
|
||||
/**
|
||||
* pika_cage_config_remove_selected_points:
|
||||
* @gcc: the cage config
|
||||
*
|
||||
* Remove all the selected points from the cage
|
||||
*/
|
||||
void
|
||||
pika_cage_config_remove_selected_points (PikaCageConfig *gcc)
|
||||
{
|
||||
gint i;
|
||||
PikaCagePoint *point;
|
||||
|
||||
g_return_if_fail (PIKA_IS_CAGE_CONFIG (gcc));
|
||||
|
||||
for (i = 0; i < gcc->cage_points->len; i++)
|
||||
{
|
||||
point = &g_array_index (gcc->cage_points, PikaCagePoint, i);
|
||||
|
||||
if (point->selected)
|
||||
{
|
||||
g_array_remove_index (gcc->cage_points, i);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
|
||||
pika_cage_config_compute_scaling_factor (gcc);
|
||||
pika_cage_config_compute_edges_normal (gcc);
|
||||
}
|
||||
|
||||
/**
|
||||
* pika_cage_config_get_point_coordinate:
|
||||
* @gcc: the cage config
|
||||
* @mode: the actual mode of the cage, PIKA_CAGE_MODE_CAGE_CHANGE or PIKA_CAGE_MODE_DEFORM
|
||||
* @point_number: the index of the point to return
|
||||
*
|
||||
* Returns: the real position of the given point, as a PikaVector2
|
||||
*/
|
||||
PikaVector2
|
||||
pika_cage_config_get_point_coordinate (PikaCageConfig *gcc,
|
||||
PikaCageMode mode,
|
||||
gint point_number)
|
||||
{
|
||||
PikaVector2 result = { 0.0, 0.0 };
|
||||
PikaCagePoint *point;
|
||||
|
||||
g_return_val_if_fail (PIKA_IS_CAGE_CONFIG (gcc), result);
|
||||
g_return_val_if_fail (point_number < gcc->cage_points->len, result);
|
||||
g_return_val_if_fail (point_number >= 0, result);
|
||||
|
||||
point = &g_array_index (gcc->cage_points, PikaCagePoint, point_number);
|
||||
|
||||
if (point->selected)
|
||||
{
|
||||
if (mode == PIKA_CAGE_MODE_CAGE_CHANGE)
|
||||
{
|
||||
result.x = point->src_point.x + gcc->displacement_x;
|
||||
result.y = point->src_point.y + gcc->displacement_y;
|
||||
}
|
||||
else
|
||||
{
|
||||
result.x = point->dest_point.x + gcc->displacement_x;
|
||||
result.y = point->dest_point.y + gcc->displacement_y;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mode == PIKA_CAGE_MODE_CAGE_CHANGE)
|
||||
{
|
||||
result.x = point->src_point.x;
|
||||
result.y = point->src_point.y;
|
||||
}
|
||||
else
|
||||
{
|
||||
result.x = point->dest_point.x;
|
||||
result.y = point->dest_point.y;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* pika_cage_config_add_displacement:
|
||||
* @gcc: the cage config
|
||||
* @mode: the actual mode of the cage, PIKA_CAGE_MODE_CAGE_CHANGE or PIKA_CAGE_MODE_DEFORM
|
||||
* @point_number: the point of the cage to move
|
||||
* @x: x displacement value
|
||||
* @y: y displacement value
|
||||
*
|
||||
* Add a displacement for all selected points of the cage.
|
||||
* This displacement need to be committed to become effective.
|
||||
*/
|
||||
void
|
||||
pika_cage_config_add_displacement (PikaCageConfig *gcc,
|
||||
PikaCageMode mode,
|
||||
gdouble x,
|
||||
gdouble y)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_CAGE_CONFIG (gcc));
|
||||
|
||||
gcc->cage_mode = mode;
|
||||
gcc->displacement_x = x;
|
||||
gcc->displacement_y = y;
|
||||
|
||||
#ifdef DEBUG_CAGE
|
||||
print_cage (gcc);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* pika_cage_config_commit_displacement:
|
||||
* @gcc: the cage config
|
||||
*
|
||||
* Apply the displacement to the cage
|
||||
*/
|
||||
void
|
||||
pika_cage_config_commit_displacement (PikaCageConfig *gcc)
|
||||
{
|
||||
gint i;
|
||||
|
||||
g_return_if_fail (PIKA_IS_CAGE_CONFIG (gcc));
|
||||
|
||||
for (i = 0; i < gcc->cage_points->len; i++)
|
||||
{
|
||||
PikaCagePoint *point;
|
||||
point = &g_array_index (gcc->cage_points, PikaCagePoint, i);
|
||||
|
||||
if (point->selected)
|
||||
{
|
||||
if (gcc->cage_mode == PIKA_CAGE_MODE_CAGE_CHANGE)
|
||||
{
|
||||
point->src_point.x += gcc->displacement_x;
|
||||
point->src_point.y += gcc->displacement_y;
|
||||
point->dest_point.x += gcc->displacement_x;
|
||||
point->dest_point.y += gcc->displacement_y;
|
||||
}
|
||||
else
|
||||
{
|
||||
point->dest_point.x += gcc->displacement_x;
|
||||
point->dest_point.y += gcc->displacement_y;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pika_cage_config_compute_scaling_factor (gcc);
|
||||
pika_cage_config_compute_edges_normal (gcc);
|
||||
pika_cage_config_reset_displacement (gcc);
|
||||
}
|
||||
|
||||
/**
|
||||
* pika_cage_config_reset_displacement:
|
||||
* @gcc: the cage config
|
||||
*
|
||||
* Set the displacement to zero.
|
||||
*/
|
||||
void
|
||||
pika_cage_config_reset_displacement (PikaCageConfig *gcc)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_CAGE_CONFIG (gcc));
|
||||
|
||||
gcc->displacement_x = 0.0;
|
||||
gcc->displacement_y = 0.0;
|
||||
}
|
||||
|
||||
/**
|
||||
* pika_cage_config_get_bounding_box:
|
||||
* @gcc: the cage config
|
||||
*
|
||||
* Compute the bounding box of the source cage
|
||||
*
|
||||
* Returns: the bounding box of the source cage, as a GeglRectangle
|
||||
*/
|
||||
GeglRectangle
|
||||
pika_cage_config_get_bounding_box (PikaCageConfig *gcc)
|
||||
{
|
||||
GeglRectangle bounding_box = { 0, 0, 0, 0};
|
||||
gint i;
|
||||
PikaCagePoint *point;
|
||||
|
||||
g_return_val_if_fail (PIKA_IS_CAGE_CONFIG (gcc), bounding_box);
|
||||
|
||||
if (gcc->cage_points->len == 0)
|
||||
return bounding_box;
|
||||
|
||||
point = &g_array_index (gcc->cage_points, PikaCagePoint, 0);
|
||||
|
||||
if (point->selected)
|
||||
{
|
||||
bounding_box.x = point->src_point.x + gcc->displacement_x;
|
||||
bounding_box.y = point->src_point.y + gcc->displacement_y;
|
||||
}
|
||||
else
|
||||
{
|
||||
bounding_box.x = point->src_point.x;
|
||||
bounding_box.y = point->src_point.y;
|
||||
}
|
||||
|
||||
for (i = 1; i < gcc->cage_points->len; i++)
|
||||
{
|
||||
gdouble x,y;
|
||||
point = &g_array_index (gcc->cage_points, PikaCagePoint, i);
|
||||
|
||||
if (point->selected)
|
||||
{
|
||||
x = point->src_point.x + gcc->displacement_x;
|
||||
y = point->src_point.y + gcc->displacement_y;
|
||||
}
|
||||
else
|
||||
{
|
||||
x = point->src_point.x;
|
||||
y = point->src_point.y;
|
||||
}
|
||||
|
||||
if (x < bounding_box.x)
|
||||
{
|
||||
bounding_box.width += bounding_box.x - x;
|
||||
bounding_box.x = x;
|
||||
}
|
||||
|
||||
if (y < bounding_box.y)
|
||||
{
|
||||
bounding_box.height += bounding_box.y - y;
|
||||
bounding_box.y = y;
|
||||
}
|
||||
|
||||
if (x > bounding_box.x + bounding_box.width)
|
||||
{
|
||||
bounding_box.width = x - bounding_box.x;
|
||||
}
|
||||
|
||||
if (y > bounding_box.y + bounding_box.height)
|
||||
{
|
||||
bounding_box.height = y - bounding_box.y;
|
||||
}
|
||||
}
|
||||
|
||||
return bounding_box;
|
||||
}
|
||||
|
||||
/**
|
||||
* pika_cage_config_reverse_cage:
|
||||
* @gcc: the cage config
|
||||
*
|
||||
* When using non-simple cage (like a cage in 8), user may want to
|
||||
* manually inverse inside and outside of the cage. This function
|
||||
* reverse the cage
|
||||
*/
|
||||
void
|
||||
pika_cage_config_reverse_cage (PikaCageConfig *gcc)
|
||||
{
|
||||
PikaCagePoint temp;
|
||||
gint i;
|
||||
|
||||
g_return_if_fail (PIKA_IS_CAGE_CONFIG (gcc));
|
||||
|
||||
for (i = 0; i < gcc->cage_points->len / 2; i++)
|
||||
{
|
||||
temp = g_array_index (gcc->cage_points, PikaCagePoint, i);
|
||||
|
||||
g_array_index (gcc->cage_points, PikaCagePoint, i) =
|
||||
g_array_index (gcc->cage_points, PikaCagePoint, gcc->cage_points->len - i - 1);
|
||||
|
||||
g_array_index (gcc->cage_points, PikaCagePoint, gcc->cage_points->len - i - 1) = temp;
|
||||
}
|
||||
|
||||
pika_cage_config_compute_scaling_factor (gcc);
|
||||
pika_cage_config_compute_edges_normal (gcc);
|
||||
}
|
||||
|
||||
/**
|
||||
* pika_cage_config_reverse_cage_if_needed:
|
||||
* @gcc: the cage config
|
||||
*
|
||||
* Since the cage need to be defined counter-clockwise to have the
|
||||
* topological inside in the actual 'physical' inside of the cage,
|
||||
* this function compute if the cage is clockwise or not, and reverse
|
||||
* the cage if needed.
|
||||
*
|
||||
* This function does not take into account an eventual displacement
|
||||
*/
|
||||
void
|
||||
pika_cage_config_reverse_cage_if_needed (PikaCageConfig *gcc)
|
||||
{
|
||||
gint i;
|
||||
gdouble sum;
|
||||
|
||||
g_return_if_fail (PIKA_IS_CAGE_CONFIG (gcc));
|
||||
|
||||
sum = 0.0;
|
||||
|
||||
/* this is a bit crappy, but should works most of the case */
|
||||
/* we do the sum of the projection of each point to the previous
|
||||
segment, and see the final sign */
|
||||
for (i = 0; i < gcc->cage_points->len ; i++)
|
||||
{
|
||||
PikaVector2 P1, P2, P3;
|
||||
gdouble z;
|
||||
|
||||
P1 = (g_array_index (gcc->cage_points, PikaCagePoint, i)).src_point;
|
||||
P2 = (g_array_index (gcc->cage_points, PikaCagePoint, (i+1) % gcc->cage_points->len)).src_point;
|
||||
P3 = (g_array_index (gcc->cage_points, PikaCagePoint, (i+2) % gcc->cage_points->len)).src_point;
|
||||
|
||||
z = P1.x * (P2.y - P3.y) + P2.x * (P3.y - P1.y) + P3.x * (P1.y - P2.y);
|
||||
|
||||
sum += z;
|
||||
}
|
||||
|
||||
/* sum > 0 mean a cage defined counter-clockwise, so we reverse it */
|
||||
if (sum > 0)
|
||||
{
|
||||
pika_cage_config_reverse_cage (gcc);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* pika_cage_config_compute_scaling_factor:
|
||||
* @gcc: the cage config
|
||||
*
|
||||
* Update Green Coordinate scaling factor for the destination cage.
|
||||
* This function does not take into account an eventual displacement.
|
||||
*/
|
||||
static void
|
||||
pika_cage_config_compute_scaling_factor (PikaCageConfig *gcc)
|
||||
{
|
||||
PikaVector2 edge;
|
||||
gdouble length, length_d;
|
||||
gint i;
|
||||
PikaCagePoint *current, *last;
|
||||
|
||||
g_return_if_fail (PIKA_IS_CAGE_CONFIG (gcc));
|
||||
if (gcc->cage_points->len < 2)
|
||||
return;
|
||||
|
||||
last = &g_array_index (gcc->cage_points, PikaCagePoint, 0);
|
||||
|
||||
for (i = 1; i <= gcc->cage_points->len; i++)
|
||||
{
|
||||
current = &g_array_index (gcc->cage_points, PikaCagePoint, i % gcc->cage_points->len);
|
||||
|
||||
pika_vector2_sub (&edge,
|
||||
&(last->src_point),
|
||||
&(current->src_point));
|
||||
length = pika_vector2_length (&edge);
|
||||
|
||||
pika_vector2_sub (&edge,
|
||||
&(last->dest_point),
|
||||
&(current->dest_point));
|
||||
length_d = pika_vector2_length (&edge);
|
||||
|
||||
last->edge_scaling_factor = length_d / length;
|
||||
last = current;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* pika_cage_config_compute_edges_normal:
|
||||
* @gcc: the cage config
|
||||
*
|
||||
* Update edges normal for the destination cage.
|
||||
* This function does not take into account an eventual displacement.
|
||||
*/
|
||||
static void
|
||||
pika_cage_config_compute_edges_normal (PikaCageConfig *gcc)
|
||||
{
|
||||
PikaVector2 normal;
|
||||
gint i;
|
||||
PikaCagePoint *current, *last;
|
||||
|
||||
g_return_if_fail (PIKA_IS_CAGE_CONFIG (gcc));
|
||||
|
||||
last = &g_array_index (gcc->cage_points, PikaCagePoint, 0);
|
||||
|
||||
for (i = 1; i <= gcc->cage_points->len; i++)
|
||||
{
|
||||
current = &g_array_index (gcc->cage_points, PikaCagePoint, i % gcc->cage_points->len);
|
||||
|
||||
pika_vector2_sub (&normal,
|
||||
&(current->dest_point),
|
||||
&(last->dest_point));
|
||||
|
||||
last->edge_normal = pika_vector2_normal (&normal);
|
||||
last = current;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* pika_cage_config_point_inside:
|
||||
* @gcc: the cage config
|
||||
* @x: x coordinate of the point to test
|
||||
* @y: y coordinate of the point to test
|
||||
*
|
||||
* Check if the given point is inside the cage. This test is done in
|
||||
* the regard of the topological inside of the source cage.
|
||||
*
|
||||
* Returns: TRUE if the point is inside, FALSE if not.
|
||||
* This function does not take into account an eventual displacement.
|
||||
*/
|
||||
gboolean
|
||||
pika_cage_config_point_inside (PikaCageConfig *gcc,
|
||||
gfloat x,
|
||||
gfloat y)
|
||||
{
|
||||
PikaVector2 *last, *current;
|
||||
gboolean inside = FALSE;
|
||||
gint i;
|
||||
|
||||
g_return_val_if_fail (PIKA_IS_CAGE_CONFIG (gcc), FALSE);
|
||||
|
||||
last = &((g_array_index (gcc->cage_points, PikaCagePoint, gcc->cage_points->len - 1)).src_point);
|
||||
|
||||
for (i = 0; i < gcc->cage_points->len; i++)
|
||||
{
|
||||
current = &((g_array_index (gcc->cage_points, PikaCagePoint, i)).src_point);
|
||||
|
||||
if ((((current->y <= y) && (y < last->y))
|
||||
|| ((last->y <= y) && (y < current->y)))
|
||||
&& (x < (last->x - current->x) * (y - current->y) / (last->y - current->y) + current->x))
|
||||
{
|
||||
inside = !inside;
|
||||
}
|
||||
|
||||
last = current;
|
||||
}
|
||||
|
||||
return inside;
|
||||
}
|
||||
|
||||
/**
|
||||
* pika_cage_config_select_point:
|
||||
* @gcc: the cage config
|
||||
* @point_number: the index of the point to select
|
||||
*
|
||||
* Select the given point of the cage, and deselect the others.
|
||||
*/
|
||||
void
|
||||
pika_cage_config_select_point (PikaCageConfig *gcc,
|
||||
gint point_number)
|
||||
{
|
||||
gint i;
|
||||
PikaCagePoint *point;
|
||||
|
||||
g_return_if_fail (PIKA_IS_CAGE_CONFIG (gcc));
|
||||
g_return_if_fail (point_number < gcc->cage_points->len);
|
||||
g_return_if_fail (point_number >= 0);
|
||||
|
||||
for (i = 0; i < gcc->cage_points->len; i++)
|
||||
{
|
||||
point = &g_array_index (gcc->cage_points, PikaCagePoint, i);
|
||||
|
||||
if (i == point_number)
|
||||
{
|
||||
point->selected = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
point->selected = FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* pika_cage_config_select_area:
|
||||
* @gcc: the cage config
|
||||
* @mode: the actual mode of the cage, PIKA_CAGE_MODE_CAGE_CHANGE or PIKA_CAGE_MODE_DEFORM
|
||||
* @area: the area to select
|
||||
*
|
||||
* Select cage's point inside the given area and deselect others
|
||||
*/
|
||||
void
|
||||
pika_cage_config_select_area (PikaCageConfig *gcc,
|
||||
PikaCageMode mode,
|
||||
GeglRectangle area)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_CAGE_CONFIG (gcc));
|
||||
|
||||
pika_cage_config_deselect_points (gcc);
|
||||
pika_cage_config_select_add_area (gcc, mode, area);
|
||||
}
|
||||
|
||||
/**
|
||||
* pika_cage_config_select_add_area:
|
||||
* @gcc: the cage config
|
||||
* @mode: the actual mode of the cage, PIKA_CAGE_MODE_CAGE_CHANGE or PIKA_CAGE_MODE_DEFORM
|
||||
* @area: the area to select
|
||||
*
|
||||
* Select cage's point inside the given area. Already selected point stay selected.
|
||||
*/
|
||||
void
|
||||
pika_cage_config_select_add_area (PikaCageConfig *gcc,
|
||||
PikaCageMode mode,
|
||||
GeglRectangle area)
|
||||
{
|
||||
gint i;
|
||||
PikaCagePoint *point;
|
||||
|
||||
g_return_if_fail (PIKA_IS_CAGE_CONFIG (gcc));
|
||||
|
||||
for (i = 0; i < gcc->cage_points->len; i++)
|
||||
{
|
||||
point = &g_array_index (gcc->cage_points, PikaCagePoint, i);
|
||||
|
||||
if (mode == PIKA_CAGE_MODE_CAGE_CHANGE)
|
||||
{
|
||||
if (point->src_point.x >= area.x &&
|
||||
point->src_point.x <= area.x + area.width &&
|
||||
point->src_point.y >= area.y &&
|
||||
point->src_point.y <= area.y + area.height)
|
||||
{
|
||||
point->selected = TRUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (point->dest_point.x >= area.x &&
|
||||
point->dest_point.x <= area.x + area.width &&
|
||||
point->dest_point.y >= area.y &&
|
||||
point->dest_point.y <= area.y + area.height)
|
||||
{
|
||||
point->selected = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* pika_cage_config_toggle_point_selection:
|
||||
* @gcc: the cage config
|
||||
* @point_number: the index of the point to toggle selection
|
||||
*
|
||||
* Toggle the selection of the given cage point
|
||||
*/
|
||||
void
|
||||
pika_cage_config_toggle_point_selection (PikaCageConfig *gcc,
|
||||
gint point_number)
|
||||
{
|
||||
PikaCagePoint *point;
|
||||
|
||||
g_return_if_fail (PIKA_IS_CAGE_CONFIG (gcc));
|
||||
g_return_if_fail (point_number < gcc->cage_points->len);
|
||||
g_return_if_fail (point_number >= 0);
|
||||
|
||||
point = &g_array_index (gcc->cage_points, PikaCagePoint, point_number);
|
||||
point->selected = ! point->selected;
|
||||
}
|
||||
|
||||
/**
|
||||
* pika_cage_deselect_points:
|
||||
* @gcc: the cage config
|
||||
*
|
||||
* Deselect all cage points.
|
||||
*/
|
||||
void
|
||||
pika_cage_config_deselect_points (PikaCageConfig *gcc)
|
||||
{
|
||||
gint i;
|
||||
|
||||
g_return_if_fail (PIKA_IS_CAGE_CONFIG (gcc));
|
||||
|
||||
for (i = 0; i < gcc->cage_points->len; i++)
|
||||
{
|
||||
(g_array_index (gcc->cage_points, PikaCagePoint, i)).selected = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* pika_cage_config_point_is_selected:
|
||||
* @gcc: the cage config
|
||||
* @point_number: the index of the point to test
|
||||
*
|
||||
* Returns: TRUE if the point is selected, FALSE otherwise.
|
||||
*/
|
||||
gboolean
|
||||
pika_cage_config_point_is_selected (PikaCageConfig *gcc,
|
||||
gint point_number)
|
||||
{
|
||||
PikaCagePoint *point;
|
||||
|
||||
g_return_val_if_fail (PIKA_IS_CAGE_CONFIG (gcc), FALSE);
|
||||
g_return_val_if_fail (point_number < gcc->cage_points->len, FALSE);
|
||||
g_return_val_if_fail (point_number >= 0, FALSE);
|
||||
|
||||
point = &(g_array_index (gcc->cage_points, PikaCagePoint, point_number));
|
||||
|
||||
return point->selected;
|
||||
}
|
||||
112
app/operations/pikacageconfig.h
Normal file
112
app/operations/pikacageconfig.h
Normal file
@ -0,0 +1,112 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
*
|
||||
* pikacageconfig.h
|
||||
* Copyright (C) 2010 Michael Muré <batolettre@gmail.com>
|
||||
*
|
||||
* 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 __PIKA_CAGE_CONFIG_H__
|
||||
#define __PIKA_CAGE_CONFIG_H__
|
||||
|
||||
|
||||
#include "pikaoperationsettings.h"
|
||||
|
||||
|
||||
struct _PikaCagePoint
|
||||
{
|
||||
PikaVector2 src_point;
|
||||
PikaVector2 dest_point;
|
||||
PikaVector2 edge_normal;
|
||||
gdouble edge_scaling_factor;
|
||||
gboolean selected;
|
||||
};
|
||||
|
||||
|
||||
#define PIKA_TYPE_CAGE_CONFIG (pika_cage_config_get_type ())
|
||||
#define PIKA_CAGE_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_CAGE_CONFIG, PikaCageConfig))
|
||||
#define PIKA_CAGE_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_CAGE_CONFIG, PikaCageConfigClass))
|
||||
#define PIKA_IS_CAGE_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_CAGE_CONFIG))
|
||||
#define PIKA_IS_CAGE_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_CAGE_CONFIG))
|
||||
#define PIKA_CAGE_CONFIG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_CAGE_CONFIG, PikaCageConfigClass))
|
||||
|
||||
|
||||
typedef struct _PikaCageConfigClass PikaCageConfigClass;
|
||||
|
||||
struct _PikaCageConfig
|
||||
{
|
||||
PikaOperationSettings parent_instance;
|
||||
|
||||
GArray *cage_points;
|
||||
|
||||
gdouble displacement_x;
|
||||
gdouble displacement_y;
|
||||
PikaCageMode cage_mode; /* Cage mode, used to commit displacement */
|
||||
};
|
||||
|
||||
struct _PikaCageConfigClass
|
||||
{
|
||||
PikaOperationSettingsClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType pika_cage_config_get_type (void) G_GNUC_CONST;
|
||||
|
||||
guint pika_cage_config_get_n_points (PikaCageConfig *gcc);
|
||||
void pika_cage_config_add_cage_point (PikaCageConfig *gcc,
|
||||
gdouble x,
|
||||
gdouble y);
|
||||
void pika_cage_config_insert_cage_point (PikaCageConfig *gcc,
|
||||
gint point_number,
|
||||
gdouble x,
|
||||
gdouble y);
|
||||
void pika_cage_config_remove_last_cage_point (PikaCageConfig *gcc);
|
||||
void pika_cage_config_remove_cage_point (PikaCageConfig *gcc,
|
||||
gint point_number);
|
||||
void pika_cage_config_remove_selected_points (PikaCageConfig *gcc);
|
||||
PikaVector2 pika_cage_config_get_point_coordinate (PikaCageConfig *gcc,
|
||||
PikaCageMode mode,
|
||||
gint point_number);
|
||||
void pika_cage_config_add_displacement (PikaCageConfig *gcc,
|
||||
PikaCageMode mode,
|
||||
gdouble x,
|
||||
gdouble y);
|
||||
void pika_cage_config_commit_displacement (PikaCageConfig *gcc);
|
||||
void pika_cage_config_reset_displacement (PikaCageConfig *gcc);
|
||||
GeglRectangle pika_cage_config_get_bounding_box (PikaCageConfig *gcc);
|
||||
void pika_cage_config_reverse_cage_if_needed (PikaCageConfig *gcc);
|
||||
void pika_cage_config_reverse_cage (PikaCageConfig *gcc);
|
||||
gboolean pika_cage_config_point_inside (PikaCageConfig *gcc,
|
||||
gfloat x,
|
||||
gfloat y);
|
||||
void pika_cage_config_select_point (PikaCageConfig *gcc,
|
||||
gint point_number);
|
||||
void pika_cage_config_select_area (PikaCageConfig *gcc,
|
||||
PikaCageMode mode,
|
||||
GeglRectangle area);
|
||||
void pika_cage_config_select_add_area (PikaCageConfig *gcc,
|
||||
PikaCageMode mode,
|
||||
GeglRectangle area);
|
||||
void pika_cage_config_toggle_point_selection (PikaCageConfig *gcc,
|
||||
gint point_number);
|
||||
void pika_cage_config_deselect_points (PikaCageConfig *gcc);
|
||||
gboolean pika_cage_config_point_is_selected (PikaCageConfig *gcc,
|
||||
gint point_number);
|
||||
|
||||
|
||||
#endif /* __PIKA_CAGE_CONFIG_H__ */
|
||||
386
app/operations/pikacolorbalanceconfig.c
Normal file
386
app/operations/pikacolorbalanceconfig.c
Normal file
@ -0,0 +1,386 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikacolorbalanceconfig.c
|
||||
* Copyright (C) 2007 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* 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.h>
|
||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||
|
||||
#include "libpikacolor/pikacolor.h"
|
||||
#include "libpikamath/pikamath.h"
|
||||
#include "libpikaconfig/pikaconfig.h"
|
||||
|
||||
#include "operations-types.h"
|
||||
|
||||
#include "pikacolorbalanceconfig.h"
|
||||
|
||||
#include "pika-intl.h"
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_RANGE,
|
||||
PROP_CYAN_RED,
|
||||
PROP_MAGENTA_GREEN,
|
||||
PROP_YELLOW_BLUE,
|
||||
PROP_PRESERVE_LUMINOSITY
|
||||
};
|
||||
|
||||
|
||||
static void pika_color_balance_config_iface_init (PikaConfigInterface *iface);
|
||||
|
||||
static void pika_color_balance_config_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void pika_color_balance_config_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec);
|
||||
|
||||
static gboolean pika_color_balance_config_serialize (PikaConfig *config,
|
||||
PikaConfigWriter *writer,
|
||||
gpointer data);
|
||||
static gboolean pika_color_balance_config_deserialize (PikaConfig *config,
|
||||
GScanner *scanner,
|
||||
gint nest_level,
|
||||
gpointer data);
|
||||
static gboolean pika_color_balance_config_equal (PikaConfig *a,
|
||||
PikaConfig *b);
|
||||
static void pika_color_balance_config_reset (PikaConfig *config);
|
||||
static gboolean pika_color_balance_config_copy (PikaConfig *src,
|
||||
PikaConfig *dest,
|
||||
GParamFlags flags);
|
||||
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (PikaColorBalanceConfig, pika_color_balance_config,
|
||||
PIKA_TYPE_OPERATION_SETTINGS,
|
||||
G_IMPLEMENT_INTERFACE (PIKA_TYPE_CONFIG,
|
||||
pika_color_balance_config_iface_init))
|
||||
|
||||
#define parent_class pika_color_balance_config_parent_class
|
||||
|
||||
|
||||
static void
|
||||
pika_color_balance_config_class_init (PikaColorBalanceConfigClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
PikaViewableClass *viewable_class = PIKA_VIEWABLE_CLASS (klass);
|
||||
|
||||
object_class->set_property = pika_color_balance_config_set_property;
|
||||
object_class->get_property = pika_color_balance_config_get_property;
|
||||
|
||||
viewable_class->default_icon_name = "pika-tool-color-balance";
|
||||
|
||||
PIKA_CONFIG_PROP_ENUM (object_class, PROP_RANGE,
|
||||
"range",
|
||||
_("Range"),
|
||||
_("The affected range"),
|
||||
PIKA_TYPE_TRANSFER_MODE,
|
||||
PIKA_TRANSFER_MIDTONES, 0);
|
||||
|
||||
PIKA_CONFIG_PROP_DOUBLE (object_class, PROP_CYAN_RED,
|
||||
"cyan-red",
|
||||
_("Cyan-Red"),
|
||||
_("Cyan-Red"),
|
||||
-1.0, 1.0, 0.0, 0);
|
||||
|
||||
PIKA_CONFIG_PROP_DOUBLE (object_class, PROP_MAGENTA_GREEN,
|
||||
"magenta-green",
|
||||
_("Magenta-Green"),
|
||||
_("Magenta-Green"),
|
||||
-1.0, 1.0, 0.0, 0);
|
||||
|
||||
PIKA_CONFIG_PROP_DOUBLE (object_class, PROP_YELLOW_BLUE,
|
||||
"yellow-blue",
|
||||
_("Yellow-Blue"),
|
||||
_("Yellow-Blue"),
|
||||
-1.0, 1.0, 0.0, 0);
|
||||
|
||||
PIKA_CONFIG_PROP_BOOLEAN (object_class, PROP_PRESERVE_LUMINOSITY,
|
||||
"preserve-luminosity",
|
||||
_("Preserve Luminosity"),
|
||||
_("Preserve Luminosity"),
|
||||
TRUE, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_color_balance_config_iface_init (PikaConfigInterface *iface)
|
||||
{
|
||||
iface->serialize = pika_color_balance_config_serialize;
|
||||
iface->deserialize = pika_color_balance_config_deserialize;
|
||||
iface->equal = pika_color_balance_config_equal;
|
||||
iface->reset = pika_color_balance_config_reset;
|
||||
iface->copy = pika_color_balance_config_copy;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_color_balance_config_init (PikaColorBalanceConfig *self)
|
||||
{
|
||||
pika_config_reset (PIKA_CONFIG (self));
|
||||
}
|
||||
|
||||
static void
|
||||
pika_color_balance_config_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaColorBalanceConfig *self = PIKA_COLOR_BALANCE_CONFIG (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_RANGE:
|
||||
g_value_set_enum (value, self->range);
|
||||
break;
|
||||
|
||||
case PROP_CYAN_RED:
|
||||
g_value_set_double (value, self->cyan_red[self->range]);
|
||||
break;
|
||||
|
||||
case PROP_MAGENTA_GREEN:
|
||||
g_value_set_double (value, self->magenta_green[self->range]);
|
||||
break;
|
||||
|
||||
case PROP_YELLOW_BLUE:
|
||||
g_value_set_double (value, self->yellow_blue[self->range]);
|
||||
break;
|
||||
|
||||
case PROP_PRESERVE_LUMINOSITY:
|
||||
g_value_set_boolean (value, self->preserve_luminosity);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_color_balance_config_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaColorBalanceConfig *self = PIKA_COLOR_BALANCE_CONFIG (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_RANGE:
|
||||
self->range = g_value_get_enum (value);
|
||||
g_object_notify (object, "cyan-red");
|
||||
g_object_notify (object, "magenta-green");
|
||||
g_object_notify (object, "yellow-blue");
|
||||
break;
|
||||
|
||||
case PROP_CYAN_RED:
|
||||
self->cyan_red[self->range] = g_value_get_double (value);
|
||||
break;
|
||||
|
||||
case PROP_MAGENTA_GREEN:
|
||||
self->magenta_green[self->range] = g_value_get_double (value);
|
||||
break;
|
||||
|
||||
case PROP_YELLOW_BLUE:
|
||||
self->yellow_blue[self->range] = g_value_get_double (value);
|
||||
break;
|
||||
|
||||
case PROP_PRESERVE_LUMINOSITY:
|
||||
self->preserve_luminosity = g_value_get_boolean (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_color_balance_config_serialize (PikaConfig *config,
|
||||
PikaConfigWriter *writer,
|
||||
gpointer data)
|
||||
{
|
||||
PikaColorBalanceConfig *bc_config = PIKA_COLOR_BALANCE_CONFIG (config);
|
||||
PikaTransferMode range;
|
||||
PikaTransferMode old_range;
|
||||
gboolean success = TRUE;
|
||||
|
||||
if (! pika_operation_settings_config_serialize_base (config, writer, data))
|
||||
return FALSE;
|
||||
|
||||
old_range = bc_config->range;
|
||||
|
||||
for (range = PIKA_TRANSFER_SHADOWS;
|
||||
range <= PIKA_TRANSFER_HIGHLIGHTS;
|
||||
range++)
|
||||
{
|
||||
bc_config->range = range;
|
||||
|
||||
success = (pika_config_serialize_property_by_name (config,
|
||||
"range",
|
||||
writer) &&
|
||||
pika_config_serialize_property_by_name (config,
|
||||
"cyan-red",
|
||||
writer) &&
|
||||
pika_config_serialize_property_by_name (config,
|
||||
"magenta-green",
|
||||
writer) &&
|
||||
pika_config_serialize_property_by_name (config,
|
||||
"yellow-blue",
|
||||
writer));
|
||||
|
||||
if (! success)
|
||||
break;
|
||||
}
|
||||
|
||||
if (success)
|
||||
success = pika_config_serialize_property_by_name (config,
|
||||
"preserve-luminosity",
|
||||
writer);
|
||||
|
||||
bc_config->range = old_range;
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_color_balance_config_deserialize (PikaConfig *config,
|
||||
GScanner *scanner,
|
||||
gint nest_level,
|
||||
gpointer data)
|
||||
{
|
||||
PikaColorBalanceConfig *cb_config = PIKA_COLOR_BALANCE_CONFIG (config);
|
||||
PikaTransferMode old_range;
|
||||
gboolean success = TRUE;
|
||||
|
||||
old_range = cb_config->range;
|
||||
|
||||
success = pika_config_deserialize_properties (config, scanner, nest_level);
|
||||
|
||||
g_object_set (config, "range", old_range, NULL);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_color_balance_config_equal (PikaConfig *a,
|
||||
PikaConfig *b)
|
||||
{
|
||||
PikaColorBalanceConfig *config_a = PIKA_COLOR_BALANCE_CONFIG (a);
|
||||
PikaColorBalanceConfig *config_b = PIKA_COLOR_BALANCE_CONFIG (b);
|
||||
PikaTransferMode range;
|
||||
|
||||
if (! pika_operation_settings_config_equal_base (a, b))
|
||||
return FALSE;
|
||||
|
||||
for (range = PIKA_TRANSFER_SHADOWS;
|
||||
range <= PIKA_TRANSFER_HIGHLIGHTS;
|
||||
range++)
|
||||
{
|
||||
if (config_a->cyan_red[range] != config_b->cyan_red[range] ||
|
||||
config_a->magenta_green[range] != config_b->magenta_green[range] ||
|
||||
config_a->yellow_blue[range] != config_b->yellow_blue[range])
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* don't compare "range" */
|
||||
|
||||
if (config_a->preserve_luminosity != config_b->preserve_luminosity)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_color_balance_config_reset (PikaConfig *config)
|
||||
{
|
||||
PikaColorBalanceConfig *cb_config = PIKA_COLOR_BALANCE_CONFIG (config);
|
||||
PikaTransferMode range;
|
||||
|
||||
pika_operation_settings_config_reset_base (config);
|
||||
|
||||
for (range = PIKA_TRANSFER_SHADOWS;
|
||||
range <= PIKA_TRANSFER_HIGHLIGHTS;
|
||||
range++)
|
||||
{
|
||||
cb_config->range = range;
|
||||
pika_color_balance_config_reset_range (cb_config);
|
||||
}
|
||||
|
||||
pika_config_reset_property (G_OBJECT (config), "range");
|
||||
pika_config_reset_property (G_OBJECT (config), "preserve-luminosity");
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_color_balance_config_copy (PikaConfig *src,
|
||||
PikaConfig *dest,
|
||||
GParamFlags flags)
|
||||
{
|
||||
PikaColorBalanceConfig *src_config = PIKA_COLOR_BALANCE_CONFIG (src);
|
||||
PikaColorBalanceConfig *dest_config = PIKA_COLOR_BALANCE_CONFIG (dest);
|
||||
PikaTransferMode range;
|
||||
|
||||
if (! pika_operation_settings_config_copy_base (src, dest, flags))
|
||||
return FALSE;
|
||||
|
||||
for (range = PIKA_TRANSFER_SHADOWS;
|
||||
range <= PIKA_TRANSFER_HIGHLIGHTS;
|
||||
range++)
|
||||
{
|
||||
dest_config->cyan_red[range] = src_config->cyan_red[range];
|
||||
dest_config->magenta_green[range] = src_config->magenta_green[range];
|
||||
dest_config->yellow_blue[range] = src_config->yellow_blue[range];
|
||||
}
|
||||
|
||||
g_object_notify (G_OBJECT (dest), "cyan-red");
|
||||
g_object_notify (G_OBJECT (dest), "magenta-green");
|
||||
g_object_notify (G_OBJECT (dest), "yellow-blue");
|
||||
|
||||
dest_config->range = src_config->range;
|
||||
dest_config->preserve_luminosity = src_config->preserve_luminosity;
|
||||
|
||||
g_object_notify (G_OBJECT (dest), "range");
|
||||
g_object_notify (G_OBJECT (dest), "preserve-luminosity");
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/* public functions */
|
||||
|
||||
void
|
||||
pika_color_balance_config_reset_range (PikaColorBalanceConfig *config)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_COLOR_BALANCE_CONFIG (config));
|
||||
|
||||
g_object_freeze_notify (G_OBJECT (config));
|
||||
|
||||
pika_config_reset_property (G_OBJECT (config), "cyan-red");
|
||||
pika_config_reset_property (G_OBJECT (config), "magenta-green");
|
||||
pika_config_reset_property (G_OBJECT (config), "yellow-blue");
|
||||
|
||||
g_object_thaw_notify (G_OBJECT (config));
|
||||
}
|
||||
66
app/operations/pikacolorbalanceconfig.h
Normal file
66
app/operations/pikacolorbalanceconfig.h
Normal file
@ -0,0 +1,66 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikacolorbalanceconfig.h
|
||||
* Copyright (C) 2007 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* 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 __PIKA_COLOR_BALANCE_CONFIG_H__
|
||||
#define __PIKA_COLOR_BALANCE_CONFIG_H__
|
||||
|
||||
|
||||
#include "pikaoperationsettings.h"
|
||||
|
||||
|
||||
#define PIKA_TYPE_COLOR_BALANCE_CONFIG (pika_color_balance_config_get_type ())
|
||||
#define PIKA_COLOR_BALANCE_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_COLOR_BALANCE_CONFIG, PikaColorBalanceConfig))
|
||||
#define PIKA_COLOR_BALANCE_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_COLOR_BALANCE_CONFIG, PikaColorBalanceConfigClass))
|
||||
#define PIKA_IS_COLOR_BALANCE_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_COLOR_BALANCE_CONFIG))
|
||||
#define PIKA_IS_COLOR_BALANCE_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_COLOR_BALANCE_CONFIG))
|
||||
#define PIKA_COLOR_BALANCE_CONFIG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_COLOR_BALANCE_CONFIG, PikaColorBalanceConfigClass))
|
||||
|
||||
|
||||
typedef struct _PikaColorBalanceConfigClass PikaColorBalanceConfigClass;
|
||||
|
||||
struct _PikaColorBalanceConfig
|
||||
{
|
||||
PikaOperationSettings parent_instance;
|
||||
|
||||
PikaTransferMode range;
|
||||
|
||||
gdouble cyan_red[3];
|
||||
gdouble magenta_green[3];
|
||||
gdouble yellow_blue[3];
|
||||
|
||||
gboolean preserve_luminosity;
|
||||
};
|
||||
|
||||
struct _PikaColorBalanceConfigClass
|
||||
{
|
||||
PikaOperationSettingsClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType pika_color_balance_config_get_type (void) G_GNUC_CONST;
|
||||
|
||||
void pika_color_balance_config_reset_range (PikaColorBalanceConfig *config);
|
||||
|
||||
|
||||
#endif /* __PIKA_COLOR_BALANCE_CONFIG_H__ */
|
||||
718
app/operations/pikacurvesconfig.c
Normal file
718
app/operations/pikacurvesconfig.c
Normal file
@ -0,0 +1,718 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikacurvesconfig.c
|
||||
* Copyright (C) 2007 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* 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.h>
|
||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||
|
||||
#include "libpikabase/pikabase.h"
|
||||
#include "libpikacolor/pikacolor.h"
|
||||
#include "libpikamath/pikamath.h"
|
||||
#include "libpikaconfig/pikaconfig.h"
|
||||
|
||||
#include "operations-types.h"
|
||||
|
||||
#include "core/pika-utils.h"
|
||||
#include "core/pikacurve.h"
|
||||
#include "core/pikahistogram.h"
|
||||
|
||||
#include "pikacurvesconfig.h"
|
||||
|
||||
#include "pika-intl.h"
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_TRC,
|
||||
PROP_LINEAR,
|
||||
PROP_CHANNEL,
|
||||
PROP_CURVE
|
||||
};
|
||||
|
||||
|
||||
static void pika_curves_config_iface_init (PikaConfigInterface *iface);
|
||||
|
||||
static void pika_curves_config_finalize (GObject *object);
|
||||
static void pika_curves_config_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void pika_curves_config_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec);
|
||||
|
||||
static gboolean pika_curves_config_serialize (PikaConfig *config,
|
||||
PikaConfigWriter *writer,
|
||||
gpointer data);
|
||||
static gboolean pika_curves_config_deserialize (PikaConfig *config,
|
||||
GScanner *scanner,
|
||||
gint nest_level,
|
||||
gpointer data);
|
||||
static gboolean pika_curves_config_equal (PikaConfig *a,
|
||||
PikaConfig *b);
|
||||
static void pika_curves_config_reset (PikaConfig *config);
|
||||
static gboolean pika_curves_config_copy (PikaConfig *src,
|
||||
PikaConfig *dest,
|
||||
GParamFlags flags);
|
||||
|
||||
static void pika_curves_config_curve_dirty (PikaCurve *curve,
|
||||
PikaCurvesConfig *config);
|
||||
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (PikaCurvesConfig, pika_curves_config,
|
||||
PIKA_TYPE_OPERATION_SETTINGS,
|
||||
G_IMPLEMENT_INTERFACE (PIKA_TYPE_CONFIG,
|
||||
pika_curves_config_iface_init))
|
||||
|
||||
#define parent_class pika_curves_config_parent_class
|
||||
|
||||
|
||||
static void
|
||||
pika_curves_config_class_init (PikaCurvesConfigClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
PikaViewableClass *viewable_class = PIKA_VIEWABLE_CLASS (klass);
|
||||
|
||||
object_class->finalize = pika_curves_config_finalize;
|
||||
object_class->set_property = pika_curves_config_set_property;
|
||||
object_class->get_property = pika_curves_config_get_property;
|
||||
|
||||
viewable_class->default_icon_name = "pika-tool-curves";
|
||||
|
||||
PIKA_CONFIG_PROP_ENUM (object_class, PROP_TRC,
|
||||
"trc",
|
||||
_("Linear/Perceptual"),
|
||||
_("Work on linear or perceptual RGB"),
|
||||
PIKA_TYPE_TRC_TYPE,
|
||||
PIKA_TRC_NON_LINEAR, 0);
|
||||
|
||||
/* compat */
|
||||
PIKA_CONFIG_PROP_BOOLEAN (object_class, PROP_LINEAR,
|
||||
"linear",
|
||||
_("Linear"),
|
||||
_("Work on linear RGB"),
|
||||
FALSE, 0);
|
||||
|
||||
PIKA_CONFIG_PROP_ENUM (object_class, PROP_CHANNEL,
|
||||
"channel",
|
||||
_("Channel"),
|
||||
_("The affected channel"),
|
||||
PIKA_TYPE_HISTOGRAM_CHANNEL,
|
||||
PIKA_HISTOGRAM_VALUE, 0);
|
||||
|
||||
PIKA_CONFIG_PROP_OBJECT (object_class, PROP_CURVE,
|
||||
"curve",
|
||||
_("Curve"),
|
||||
_("Curve"),
|
||||
PIKA_TYPE_CURVE,
|
||||
PIKA_CONFIG_PARAM_AGGREGATE);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_curves_config_iface_init (PikaConfigInterface *iface)
|
||||
{
|
||||
iface->serialize = pika_curves_config_serialize;
|
||||
iface->deserialize = pika_curves_config_deserialize;
|
||||
iface->equal = pika_curves_config_equal;
|
||||
iface->reset = pika_curves_config_reset;
|
||||
iface->copy = pika_curves_config_copy;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_curves_config_init (PikaCurvesConfig *self)
|
||||
{
|
||||
PikaHistogramChannel channel;
|
||||
|
||||
for (channel = PIKA_HISTOGRAM_VALUE;
|
||||
channel <= PIKA_HISTOGRAM_ALPHA;
|
||||
channel++)
|
||||
{
|
||||
self->curve[channel] = PIKA_CURVE (pika_curve_new ("curves config"));
|
||||
|
||||
g_signal_connect_object (self->curve[channel], "dirty",
|
||||
G_CALLBACK (pika_curves_config_curve_dirty),
|
||||
self, 0);
|
||||
}
|
||||
|
||||
pika_config_reset (PIKA_CONFIG (self));
|
||||
}
|
||||
|
||||
static void
|
||||
pika_curves_config_finalize (GObject *object)
|
||||
{
|
||||
PikaCurvesConfig *self = PIKA_CURVES_CONFIG (object);
|
||||
PikaHistogramChannel channel;
|
||||
|
||||
for (channel = PIKA_HISTOGRAM_VALUE;
|
||||
channel <= PIKA_HISTOGRAM_ALPHA;
|
||||
channel++)
|
||||
{
|
||||
g_object_unref (self->curve[channel]);
|
||||
self->curve[channel] = NULL;
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_curves_config_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaCurvesConfig *self = PIKA_CURVES_CONFIG (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_TRC:
|
||||
g_value_set_enum (value, self->trc);
|
||||
break;
|
||||
|
||||
case PROP_LINEAR:
|
||||
g_value_set_boolean (value, self->trc == PIKA_TRC_LINEAR ? TRUE : FALSE);
|
||||
break;
|
||||
|
||||
case PROP_CHANNEL:
|
||||
g_value_set_enum (value, self->channel);
|
||||
break;
|
||||
|
||||
case PROP_CURVE:
|
||||
g_value_set_object (value, self->curve[self->channel]);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_curves_config_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaCurvesConfig *self = PIKA_CURVES_CONFIG (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_TRC:
|
||||
self->trc = g_value_get_enum (value);
|
||||
break;
|
||||
|
||||
case PROP_LINEAR:
|
||||
self->trc = g_value_get_boolean (value) ?
|
||||
PIKA_TRC_LINEAR : PIKA_TRC_NON_LINEAR;
|
||||
g_object_notify (object, "trc");
|
||||
break;
|
||||
|
||||
case PROP_CHANNEL:
|
||||
self->channel = g_value_get_enum (value);
|
||||
g_object_notify (object, "curve");
|
||||
break;
|
||||
|
||||
case PROP_CURVE:
|
||||
{
|
||||
PikaCurve *src_curve = g_value_get_object (value);
|
||||
PikaCurve *dest_curve = self->curve[self->channel];
|
||||
|
||||
if (src_curve && dest_curve)
|
||||
{
|
||||
pika_config_copy (PIKA_CONFIG (src_curve),
|
||||
PIKA_CONFIG (dest_curve), 0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_curves_config_serialize (PikaConfig *config,
|
||||
PikaConfigWriter *writer,
|
||||
gpointer data)
|
||||
{
|
||||
PikaCurvesConfig *c_config = PIKA_CURVES_CONFIG (config);
|
||||
PikaHistogramChannel channel;
|
||||
PikaHistogramChannel old_channel;
|
||||
gboolean success = TRUE;
|
||||
|
||||
if (! pika_operation_settings_config_serialize_base (config, writer, data) ||
|
||||
! pika_config_serialize_property_by_name (config, "trc", writer))
|
||||
return FALSE;
|
||||
|
||||
old_channel = c_config->channel;
|
||||
|
||||
for (channel = PIKA_HISTOGRAM_VALUE;
|
||||
channel <= PIKA_HISTOGRAM_ALPHA;
|
||||
channel++)
|
||||
{
|
||||
c_config->channel = channel;
|
||||
|
||||
/* serialize the channel properties manually (not using
|
||||
* pika_config_serialize_properties()), so the parent class'
|
||||
* properties don't end up in the config file one per channel.
|
||||
* See bug #700653.
|
||||
*/
|
||||
success =
|
||||
(pika_config_serialize_property_by_name (config, "channel", writer) &&
|
||||
pika_config_serialize_property_by_name (config, "curve", writer));
|
||||
|
||||
if (! success)
|
||||
break;
|
||||
}
|
||||
|
||||
c_config->channel = old_channel;
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_curves_config_deserialize (PikaConfig *config,
|
||||
GScanner *scanner,
|
||||
gint nest_level,
|
||||
gpointer data)
|
||||
{
|
||||
PikaCurvesConfig *c_config = PIKA_CURVES_CONFIG (config);
|
||||
PikaHistogramChannel old_channel;
|
||||
gboolean success = TRUE;
|
||||
|
||||
old_channel = c_config->channel;
|
||||
|
||||
success = pika_config_deserialize_properties (config, scanner, nest_level);
|
||||
|
||||
g_object_set (config, "channel", old_channel, NULL);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_curves_config_equal (PikaConfig *a,
|
||||
PikaConfig *b)
|
||||
{
|
||||
PikaCurvesConfig *config_a = PIKA_CURVES_CONFIG (a);
|
||||
PikaCurvesConfig *config_b = PIKA_CURVES_CONFIG (b);
|
||||
PikaHistogramChannel channel;
|
||||
|
||||
if (! pika_operation_settings_config_equal_base (a, b) ||
|
||||
config_a->trc != config_b->trc)
|
||||
return FALSE;
|
||||
|
||||
for (channel = PIKA_HISTOGRAM_VALUE;
|
||||
channel <= PIKA_HISTOGRAM_ALPHA;
|
||||
channel++)
|
||||
{
|
||||
PikaCurve *curve_a = config_a->curve[channel];
|
||||
PikaCurve *curve_b = config_b->curve[channel];
|
||||
|
||||
if (curve_a && curve_b)
|
||||
{
|
||||
if (! pika_config_is_equal_to (PIKA_CONFIG (curve_a),
|
||||
PIKA_CONFIG (curve_b)))
|
||||
return FALSE;
|
||||
}
|
||||
else if (curve_a || curve_b)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* don't compare "channel" */
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_curves_config_reset (PikaConfig *config)
|
||||
{
|
||||
PikaCurvesConfig *c_config = PIKA_CURVES_CONFIG (config);
|
||||
PikaHistogramChannel channel;
|
||||
|
||||
pika_operation_settings_config_reset_base (config);
|
||||
|
||||
for (channel = PIKA_HISTOGRAM_VALUE;
|
||||
channel <= PIKA_HISTOGRAM_ALPHA;
|
||||
channel++)
|
||||
{
|
||||
c_config->channel = channel;
|
||||
pika_curves_config_reset_channel (c_config);
|
||||
}
|
||||
|
||||
pika_config_reset_property (G_OBJECT (config), "trc");
|
||||
pika_config_reset_property (G_OBJECT (config), "channel");
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_curves_config_copy (PikaConfig *src,
|
||||
PikaConfig *dest,
|
||||
GParamFlags flags)
|
||||
{
|
||||
PikaCurvesConfig *src_config = PIKA_CURVES_CONFIG (src);
|
||||
PikaCurvesConfig *dest_config = PIKA_CURVES_CONFIG (dest);
|
||||
PikaHistogramChannel channel;
|
||||
|
||||
if (! pika_operation_settings_config_copy_base (src, dest, flags))
|
||||
return FALSE;
|
||||
|
||||
for (channel = PIKA_HISTOGRAM_VALUE;
|
||||
channel <= PIKA_HISTOGRAM_ALPHA;
|
||||
channel++)
|
||||
{
|
||||
pika_config_copy (PIKA_CONFIG (src_config->curve[channel]),
|
||||
PIKA_CONFIG (dest_config->curve[channel]),
|
||||
flags);
|
||||
}
|
||||
|
||||
dest_config->trc = src_config->trc;
|
||||
dest_config->channel = src_config->channel;
|
||||
|
||||
g_object_notify (G_OBJECT (dest), "trc");
|
||||
g_object_notify (G_OBJECT (dest), "channel");
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_curves_config_curve_dirty (PikaCurve *curve,
|
||||
PikaCurvesConfig *config)
|
||||
{
|
||||
g_object_notify (G_OBJECT (config), "curve");
|
||||
}
|
||||
|
||||
|
||||
/* public functions */
|
||||
|
||||
GObject *
|
||||
pika_curves_config_new_spline (gint32 channel,
|
||||
const gdouble *points,
|
||||
gint n_points)
|
||||
{
|
||||
PikaCurvesConfig *config;
|
||||
PikaCurve *curve;
|
||||
gint i;
|
||||
|
||||
g_return_val_if_fail (channel >= PIKA_HISTOGRAM_VALUE &&
|
||||
channel <= PIKA_HISTOGRAM_ALPHA, NULL);
|
||||
g_return_val_if_fail (points != NULL, NULL);
|
||||
g_return_val_if_fail (n_points >= 2 && n_points <= 1024, NULL);
|
||||
|
||||
config = g_object_new (PIKA_TYPE_CURVES_CONFIG, NULL);
|
||||
|
||||
curve = config->curve[channel];
|
||||
|
||||
pika_data_freeze (PIKA_DATA (curve));
|
||||
|
||||
pika_curve_set_curve_type (curve, PIKA_CURVE_SMOOTH);
|
||||
pika_curve_clear_points (curve);
|
||||
|
||||
for (i = 0; i < n_points; i++)
|
||||
pika_curve_add_point (curve,
|
||||
(gdouble) points[i * 2],
|
||||
(gdouble) points[i * 2 + 1]);
|
||||
|
||||
pika_data_thaw (PIKA_DATA (curve));
|
||||
|
||||
return G_OBJECT (config);
|
||||
}
|
||||
|
||||
GObject *
|
||||
pika_curves_config_new_explicit (gint32 channel,
|
||||
const gdouble *samples,
|
||||
gint n_samples)
|
||||
{
|
||||
PikaCurvesConfig *config;
|
||||
PikaCurve *curve;
|
||||
gint i;
|
||||
|
||||
g_return_val_if_fail (channel >= PIKA_HISTOGRAM_VALUE &&
|
||||
channel <= PIKA_HISTOGRAM_ALPHA, NULL);
|
||||
g_return_val_if_fail (samples != NULL, NULL);
|
||||
g_return_val_if_fail (n_samples >= 2 && n_samples <= 4096, NULL);
|
||||
|
||||
config = g_object_new (PIKA_TYPE_CURVES_CONFIG, NULL);
|
||||
|
||||
curve = config->curve[channel];
|
||||
|
||||
pika_data_freeze (PIKA_DATA (curve));
|
||||
|
||||
pika_curve_set_curve_type (curve, PIKA_CURVE_FREE);
|
||||
pika_curve_set_n_samples (curve, n_samples);
|
||||
|
||||
for (i = 0; i < n_samples; i++)
|
||||
pika_curve_set_curve (curve,
|
||||
(gdouble) i / (gdouble) (n_samples - 1),
|
||||
(gdouble) samples[i]);
|
||||
|
||||
pika_data_thaw (PIKA_DATA (curve));
|
||||
|
||||
return G_OBJECT (config);
|
||||
}
|
||||
|
||||
GObject *
|
||||
pika_curves_config_new_spline_cruft (gint32 channel,
|
||||
const guint8 *points,
|
||||
gint n_points)
|
||||
{
|
||||
GObject *config;
|
||||
gdouble *d_points;
|
||||
gint i;
|
||||
|
||||
g_return_val_if_fail (channel >= PIKA_HISTOGRAM_VALUE &&
|
||||
channel <= PIKA_HISTOGRAM_ALPHA, NULL);
|
||||
g_return_val_if_fail (points != NULL, NULL);
|
||||
g_return_val_if_fail (n_points >= 2 && n_points <= 1024, NULL);
|
||||
|
||||
d_points = g_new (gdouble, 2 * n_points);
|
||||
|
||||
for (i = 0; i < n_points; i++)
|
||||
{
|
||||
d_points[i * 2] = (gdouble) points[i * 2] / 255.0;
|
||||
d_points[i * 2 + 1] = (gdouble) points[i * 2 + 1] / 255.0;
|
||||
}
|
||||
|
||||
config = pika_curves_config_new_spline (channel, d_points, n_points);
|
||||
|
||||
g_free (d_points);
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
GObject *
|
||||
pika_curves_config_new_explicit_cruft (gint32 channel,
|
||||
const guint8 *samples,
|
||||
gint n_samples)
|
||||
{
|
||||
GObject *config;
|
||||
gdouble *d_samples;
|
||||
gint i;
|
||||
|
||||
g_return_val_if_fail (channel >= PIKA_HISTOGRAM_VALUE &&
|
||||
channel <= PIKA_HISTOGRAM_ALPHA, NULL);
|
||||
g_return_val_if_fail (samples != NULL, NULL);
|
||||
g_return_val_if_fail (n_samples >= 2 && n_samples <= 4096, NULL);
|
||||
|
||||
d_samples = g_new (gdouble, n_samples);
|
||||
|
||||
for (i = 0; i < n_samples; i++)
|
||||
{
|
||||
d_samples[i] = (gdouble) samples[i] / 255.0;
|
||||
}
|
||||
|
||||
config = pika_curves_config_new_explicit (channel, d_samples, n_samples);
|
||||
|
||||
g_free (d_samples);
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
void
|
||||
pika_curves_config_reset_channel (PikaCurvesConfig *config)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_CURVES_CONFIG (config));
|
||||
|
||||
pika_config_reset (PIKA_CONFIG (config->curve[config->channel]));
|
||||
}
|
||||
|
||||
#define PIKA_CURVE_N_CRUFT_POINTS 17
|
||||
|
||||
gboolean
|
||||
pika_curves_config_load_cruft (PikaCurvesConfig *config,
|
||||
GInputStream *input,
|
||||
GError **error)
|
||||
{
|
||||
GDataInputStream *data_input;
|
||||
gint index[5][PIKA_CURVE_N_CRUFT_POINTS];
|
||||
gint value[5][PIKA_CURVE_N_CRUFT_POINTS];
|
||||
gchar *line;
|
||||
gsize line_len;
|
||||
gint i, j;
|
||||
|
||||
g_return_val_if_fail (PIKA_IS_CURVES_CONFIG (config), FALSE);
|
||||
g_return_val_if_fail (G_IS_INPUT_STREAM (input), FALSE);
|
||||
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
||||
|
||||
data_input = g_data_input_stream_new (input);
|
||||
|
||||
line_len = 64;
|
||||
line = pika_data_input_stream_read_line_always (data_input, &line_len,
|
||||
NULL, error);
|
||||
if (! line)
|
||||
return FALSE;
|
||||
|
||||
if (strcmp (line, "# PIKA Curves File") != 0)
|
||||
{
|
||||
g_set_error_literal (error, PIKA_CONFIG_ERROR, PIKA_CONFIG_ERROR_PARSE,
|
||||
_("not a PIKA Curves file"));
|
||||
g_object_unref (data_input);
|
||||
g_free (line);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
for (i = 0; i < 5; i++)
|
||||
{
|
||||
for (j = 0; j < PIKA_CURVE_N_CRUFT_POINTS; j++)
|
||||
{
|
||||
gchar *x_str = NULL;
|
||||
gchar *y_str = NULL;
|
||||
|
||||
if (! (x_str = g_data_input_stream_read_upto (data_input, " ", -1,
|
||||
NULL, NULL, error)) ||
|
||||
! g_data_input_stream_read_byte (data_input, NULL, error) ||
|
||||
! (y_str = g_data_input_stream_read_upto (data_input, " ", -1,
|
||||
NULL, NULL, error)) ||
|
||||
! g_data_input_stream_read_byte (data_input, NULL, error))
|
||||
{
|
||||
g_free (x_str);
|
||||
g_free (y_str);
|
||||
g_object_unref (data_input);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (sscanf (x_str, "%d", &index[i][j]) != 1 ||
|
||||
sscanf (y_str, "%d", &value[i][j]) != 1)
|
||||
{
|
||||
g_set_error_literal (error,
|
||||
PIKA_CONFIG_ERROR, PIKA_CONFIG_ERROR_PARSE,
|
||||
_("Parse error, didn't find 2 integers"));
|
||||
g_free (x_str);
|
||||
g_free (y_str);
|
||||
g_object_unref (data_input);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
g_free (x_str);
|
||||
g_free (y_str);
|
||||
}
|
||||
}
|
||||
|
||||
g_object_unref (data_input);
|
||||
|
||||
g_object_freeze_notify (G_OBJECT (config));
|
||||
|
||||
for (i = 0; i < 5; i++)
|
||||
{
|
||||
PikaCurve *curve = config->curve[i];
|
||||
|
||||
pika_data_freeze (PIKA_DATA (curve));
|
||||
|
||||
pika_curve_set_curve_type (curve, PIKA_CURVE_SMOOTH);
|
||||
pika_curve_clear_points (curve);
|
||||
|
||||
for (j = 0; j < PIKA_CURVE_N_CRUFT_POINTS; j++)
|
||||
{
|
||||
gdouble x;
|
||||
gdouble y;
|
||||
|
||||
x = (gdouble) index[i][j] / 255.0;
|
||||
y = (gdouble) value[i][j] / 255.0;
|
||||
|
||||
if (x >= 0.0)
|
||||
pika_curve_add_point (curve, x, y);
|
||||
}
|
||||
|
||||
pika_data_thaw (PIKA_DATA (curve));
|
||||
}
|
||||
|
||||
config->trc = PIKA_TRC_NON_LINEAR;
|
||||
|
||||
g_object_notify (G_OBJECT (config), "trc");
|
||||
|
||||
g_object_thaw_notify (G_OBJECT (config));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
pika_curves_config_save_cruft (PikaCurvesConfig *config,
|
||||
GOutputStream *output,
|
||||
GError **error)
|
||||
{
|
||||
GString *string;
|
||||
gint i;
|
||||
|
||||
g_return_val_if_fail (PIKA_IS_CURVES_CONFIG (config), FALSE);
|
||||
g_return_val_if_fail (G_IS_OUTPUT_STREAM (output), FALSE);
|
||||
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
||||
|
||||
string = g_string_new ("# PIKA Curves File\n");
|
||||
|
||||
for (i = 0; i < 5; i++)
|
||||
{
|
||||
PikaCurve *curve = config->curve[i];
|
||||
gint j;
|
||||
|
||||
if (curve->curve_type == PIKA_CURVE_SMOOTH)
|
||||
{
|
||||
g_object_ref (curve);
|
||||
}
|
||||
else
|
||||
{
|
||||
curve = PIKA_CURVE (pika_data_duplicate (PIKA_DATA (curve)));
|
||||
|
||||
pika_curve_set_curve_type (curve, PIKA_CURVE_SMOOTH);
|
||||
}
|
||||
|
||||
for (j = 0; j < PIKA_CURVE_N_CRUFT_POINTS; j++)
|
||||
{
|
||||
gint x = -1;
|
||||
gint y = -1;
|
||||
|
||||
if (j < pika_curve_get_n_points (curve))
|
||||
{
|
||||
gdouble point_x;
|
||||
gdouble point_y;
|
||||
|
||||
pika_curve_get_point (curve, j, &point_x, &point_y);
|
||||
|
||||
x = floor (point_x * 255.999);
|
||||
y = floor (point_y * 255.999);
|
||||
}
|
||||
|
||||
g_string_append_printf (string, "%d %d ", x, y);
|
||||
}
|
||||
|
||||
g_string_append_printf (string, "\n");
|
||||
|
||||
g_object_unref (curve);
|
||||
}
|
||||
|
||||
if (! g_output_stream_write_all (output, string->str, string->len,
|
||||
NULL, NULL, error))
|
||||
{
|
||||
g_prefix_error (error, _("Writing curves file failed: "));
|
||||
g_string_free (string, TRUE);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
g_string_free (string, TRUE);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
85
app/operations/pikacurvesconfig.h
Normal file
85
app/operations/pikacurvesconfig.h
Normal file
@ -0,0 +1,85 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikacurvesconfig.h
|
||||
* Copyright (C) 2007 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* 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 __PIKA_CURVES_CONFIG_H__
|
||||
#define __PIKA_CURVES_CONFIG_H__
|
||||
|
||||
|
||||
#include "pikaoperationsettings.h"
|
||||
|
||||
|
||||
#define PIKA_TYPE_CURVES_CONFIG (pika_curves_config_get_type ())
|
||||
#define PIKA_CURVES_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_CURVES_CONFIG, PikaCurvesConfig))
|
||||
#define PIKA_CURVES_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_CURVES_CONFIG, PikaCurvesConfigClass))
|
||||
#define PIKA_IS_CURVES_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_CURVES_CONFIG))
|
||||
#define PIKA_IS_CURVES_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_CURVES_CONFIG))
|
||||
#define PIKA_CURVES_CONFIG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_CURVES_CONFIG, PikaCurvesConfigClass))
|
||||
|
||||
|
||||
typedef struct _PikaCurvesConfigClass PikaCurvesConfigClass;
|
||||
|
||||
struct _PikaCurvesConfig
|
||||
{
|
||||
PikaOperationSettings parent_instance;
|
||||
|
||||
PikaTRCType trc;
|
||||
|
||||
PikaHistogramChannel channel;
|
||||
|
||||
PikaCurve *curve[5];
|
||||
};
|
||||
|
||||
struct _PikaCurvesConfigClass
|
||||
{
|
||||
PikaOperationSettingsClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType pika_curves_config_get_type (void) G_GNUC_CONST;
|
||||
|
||||
GObject * pika_curves_config_new_spline (gint32 channel,
|
||||
const gdouble *points,
|
||||
gint n_points);
|
||||
GObject * pika_curves_config_new_explicit (gint32 channel,
|
||||
const gdouble *samples,
|
||||
gint n_samples);
|
||||
|
||||
GObject * pika_curves_config_new_spline_cruft (gint32 channel,
|
||||
const guint8 *points,
|
||||
gint n_points);
|
||||
GObject * pika_curves_config_new_explicit_cruft (gint32 channel,
|
||||
const guint8 *samples,
|
||||
gint n_samples);
|
||||
|
||||
void pika_curves_config_reset_channel (PikaCurvesConfig *config);
|
||||
|
||||
gboolean pika_curves_config_load_cruft (PikaCurvesConfig *config,
|
||||
GInputStream *input,
|
||||
GError **error);
|
||||
gboolean pika_curves_config_save_cruft (PikaCurvesConfig *config,
|
||||
GOutputStream *output,
|
||||
GError **error);
|
||||
|
||||
|
||||
#endif /* __PIKA_CURVES_CONFIG_H__ */
|
||||
371
app/operations/pikahuesaturationconfig.c
Normal file
371
app/operations/pikahuesaturationconfig.c
Normal file
@ -0,0 +1,371 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikahuesaturationconfig.c
|
||||
* Copyright (C) 2007 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* 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 <gdk-pixbuf/gdk-pixbuf.h>
|
||||
#include <gegl.h>
|
||||
|
||||
#include "libpikaconfig/pikaconfig.h"
|
||||
|
||||
#include "operations-types.h"
|
||||
|
||||
#include "pikahuesaturationconfig.h"
|
||||
|
||||
#include "pika-intl.h"
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_RANGE,
|
||||
PROP_HUE,
|
||||
PROP_SATURATION,
|
||||
PROP_LIGHTNESS,
|
||||
PROP_OVERLAP
|
||||
};
|
||||
|
||||
|
||||
static void pika_hue_saturation_config_iface_init (PikaConfigInterface *iface);
|
||||
|
||||
static void pika_hue_saturation_config_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void pika_hue_saturation_config_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec);
|
||||
|
||||
static gboolean pika_hue_saturation_config_serialize (PikaConfig *config,
|
||||
PikaConfigWriter *writer,
|
||||
gpointer data);
|
||||
static gboolean pika_hue_saturation_config_deserialize (PikaConfig *config,
|
||||
GScanner *scanner,
|
||||
gint nest_level,
|
||||
gpointer data);
|
||||
static gboolean pika_hue_saturation_config_equal (PikaConfig *a,
|
||||
PikaConfig *b);
|
||||
static void pika_hue_saturation_config_reset (PikaConfig *config);
|
||||
static gboolean pika_hue_saturation_config_copy (PikaConfig *src,
|
||||
PikaConfig *dest,
|
||||
GParamFlags flags);
|
||||
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (PikaHueSaturationConfig, pika_hue_saturation_config,
|
||||
PIKA_TYPE_OPERATION_SETTINGS,
|
||||
G_IMPLEMENT_INTERFACE (PIKA_TYPE_CONFIG,
|
||||
pika_hue_saturation_config_iface_init))
|
||||
|
||||
#define parent_class pika_hue_saturation_config_parent_class
|
||||
|
||||
|
||||
static void
|
||||
pika_hue_saturation_config_class_init (PikaHueSaturationConfigClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
PikaViewableClass *viewable_class = PIKA_VIEWABLE_CLASS (klass);
|
||||
|
||||
object_class->set_property = pika_hue_saturation_config_set_property;
|
||||
object_class->get_property = pika_hue_saturation_config_get_property;
|
||||
|
||||
viewable_class->default_icon_name = "pika-tool-hue-saturation";
|
||||
|
||||
PIKA_CONFIG_PROP_ENUM (object_class, PROP_RANGE,
|
||||
"range",
|
||||
_("Range"),
|
||||
_("The affected range"),
|
||||
PIKA_TYPE_HUE_RANGE,
|
||||
PIKA_HUE_RANGE_ALL, 0);
|
||||
|
||||
PIKA_CONFIG_PROP_DOUBLE (object_class, PROP_HUE,
|
||||
"hue",
|
||||
_("Hue"),
|
||||
_("Hue"),
|
||||
-1.0, 1.0, 0.0, 0);
|
||||
|
||||
PIKA_CONFIG_PROP_DOUBLE (object_class, PROP_SATURATION,
|
||||
"saturation",
|
||||
_("Saturation"),
|
||||
_("Saturation"),
|
||||
-1.0, 1.0, 0.0, 0);
|
||||
|
||||
PIKA_CONFIG_PROP_DOUBLE (object_class, PROP_LIGHTNESS,
|
||||
"lightness",
|
||||
_("Lightness"),
|
||||
_("Lightness"),
|
||||
-1.0, 1.0, 0.0, 0);
|
||||
|
||||
PIKA_CONFIG_PROP_DOUBLE (object_class, PROP_OVERLAP,
|
||||
"overlap",
|
||||
_("Overlap"),
|
||||
_("Overlap"),
|
||||
0.0, 1.0, 0.0, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_hue_saturation_config_iface_init (PikaConfigInterface *iface)
|
||||
{
|
||||
iface->serialize = pika_hue_saturation_config_serialize;
|
||||
iface->deserialize = pika_hue_saturation_config_deserialize;
|
||||
iface->equal = pika_hue_saturation_config_equal;
|
||||
iface->reset = pika_hue_saturation_config_reset;
|
||||
iface->copy = pika_hue_saturation_config_copy;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_hue_saturation_config_init (PikaHueSaturationConfig *self)
|
||||
{
|
||||
pika_config_reset (PIKA_CONFIG (self));
|
||||
}
|
||||
|
||||
static void
|
||||
pika_hue_saturation_config_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaHueSaturationConfig *self = PIKA_HUE_SATURATION_CONFIG (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_RANGE:
|
||||
g_value_set_enum (value, self->range);
|
||||
break;
|
||||
|
||||
case PROP_HUE:
|
||||
g_value_set_double (value, self->hue[self->range]);
|
||||
break;
|
||||
|
||||
case PROP_SATURATION:
|
||||
g_value_set_double (value, self->saturation[self->range]);
|
||||
break;
|
||||
|
||||
case PROP_LIGHTNESS:
|
||||
g_value_set_double (value, self->lightness[self->range]);
|
||||
break;
|
||||
|
||||
case PROP_OVERLAP:
|
||||
g_value_set_double (value, self->overlap);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_hue_saturation_config_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaHueSaturationConfig *self = PIKA_HUE_SATURATION_CONFIG (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_RANGE:
|
||||
self->range = g_value_get_enum (value);
|
||||
g_object_notify (object, "hue");
|
||||
g_object_notify (object, "saturation");
|
||||
g_object_notify (object, "lightness");
|
||||
break;
|
||||
|
||||
case PROP_HUE:
|
||||
self->hue[self->range] = g_value_get_double (value);
|
||||
break;
|
||||
|
||||
case PROP_SATURATION:
|
||||
self->saturation[self->range] = g_value_get_double (value);
|
||||
break;
|
||||
|
||||
case PROP_LIGHTNESS:
|
||||
self->lightness[self->range] = g_value_get_double (value);
|
||||
break;
|
||||
|
||||
case PROP_OVERLAP:
|
||||
self->overlap = g_value_get_double (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_hue_saturation_config_serialize (PikaConfig *config,
|
||||
PikaConfigWriter *writer,
|
||||
gpointer data)
|
||||
{
|
||||
PikaHueSaturationConfig *hs_config = PIKA_HUE_SATURATION_CONFIG (config);
|
||||
PikaHueRange range;
|
||||
PikaHueRange old_range;
|
||||
gboolean success = TRUE;
|
||||
|
||||
if (! pika_operation_settings_config_serialize_base (config, writer, data))
|
||||
return FALSE;
|
||||
|
||||
old_range = hs_config->range;
|
||||
|
||||
for (range = PIKA_HUE_RANGE_ALL; range <= PIKA_HUE_RANGE_MAGENTA; range++)
|
||||
{
|
||||
hs_config->range = range;
|
||||
|
||||
success = (pika_config_serialize_property_by_name (config, "range",
|
||||
writer) &&
|
||||
pika_config_serialize_property_by_name (config, "hue",
|
||||
writer) &&
|
||||
pika_config_serialize_property_by_name (config, "saturation",
|
||||
writer) &&
|
||||
pika_config_serialize_property_by_name (config, "lightness",
|
||||
writer));
|
||||
|
||||
if (! success)
|
||||
break;
|
||||
}
|
||||
|
||||
if (success)
|
||||
success = pika_config_serialize_property_by_name (config, "overlap",
|
||||
writer);
|
||||
|
||||
hs_config->range = old_range;
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_hue_saturation_config_deserialize (PikaConfig *config,
|
||||
GScanner *scanner,
|
||||
gint nest_level,
|
||||
gpointer data)
|
||||
{
|
||||
PikaHueSaturationConfig *hs_config = PIKA_HUE_SATURATION_CONFIG (config);
|
||||
PikaHueRange old_range;
|
||||
gboolean success = TRUE;
|
||||
|
||||
old_range = hs_config->range;
|
||||
|
||||
success = pika_config_deserialize_properties (config, scanner, nest_level);
|
||||
|
||||
g_object_set (config, "range", old_range, NULL);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_hue_saturation_config_equal (PikaConfig *a,
|
||||
PikaConfig *b)
|
||||
{
|
||||
PikaHueSaturationConfig *config_a = PIKA_HUE_SATURATION_CONFIG (a);
|
||||
PikaHueSaturationConfig *config_b = PIKA_HUE_SATURATION_CONFIG (b);
|
||||
PikaHueRange range;
|
||||
|
||||
if (! pika_operation_settings_config_equal_base (a, b))
|
||||
return FALSE;
|
||||
|
||||
for (range = PIKA_HUE_RANGE_ALL; range <= PIKA_HUE_RANGE_MAGENTA; range++)
|
||||
{
|
||||
if (config_a->hue[range] != config_b->hue[range] ||
|
||||
config_a->saturation[range] != config_b->saturation[range] ||
|
||||
config_a->lightness[range] != config_b->lightness[range])
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* don't compare "range" */
|
||||
|
||||
if (config_a->overlap != config_b->overlap)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_hue_saturation_config_reset (PikaConfig *config)
|
||||
{
|
||||
PikaHueSaturationConfig *hs_config = PIKA_HUE_SATURATION_CONFIG (config);
|
||||
PikaHueRange range;
|
||||
|
||||
pika_operation_settings_config_reset_base (config);
|
||||
|
||||
for (range = PIKA_HUE_RANGE_ALL; range <= PIKA_HUE_RANGE_MAGENTA; range++)
|
||||
{
|
||||
hs_config->range = range;
|
||||
pika_hue_saturation_config_reset_range (hs_config);
|
||||
}
|
||||
|
||||
pika_config_reset_property (G_OBJECT (config), "range");
|
||||
pika_config_reset_property (G_OBJECT (config), "overlap");
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_hue_saturation_config_copy (PikaConfig *src,
|
||||
PikaConfig *dest,
|
||||
GParamFlags flags)
|
||||
{
|
||||
PikaHueSaturationConfig *src_config = PIKA_HUE_SATURATION_CONFIG (src);
|
||||
PikaHueSaturationConfig *dest_config = PIKA_HUE_SATURATION_CONFIG (dest);
|
||||
PikaHueRange range;
|
||||
|
||||
if (! pika_operation_settings_config_copy_base (src, dest, flags))
|
||||
return FALSE;
|
||||
|
||||
for (range = PIKA_HUE_RANGE_ALL; range <= PIKA_HUE_RANGE_MAGENTA; range++)
|
||||
{
|
||||
dest_config->hue[range] = src_config->hue[range];
|
||||
dest_config->saturation[range] = src_config->saturation[range];
|
||||
dest_config->lightness[range] = src_config->lightness[range];
|
||||
}
|
||||
|
||||
g_object_notify (G_OBJECT (dest), "hue");
|
||||
g_object_notify (G_OBJECT (dest), "saturation");
|
||||
g_object_notify (G_OBJECT (dest), "lightness");
|
||||
|
||||
dest_config->range = src_config->range;
|
||||
dest_config->overlap = src_config->overlap;
|
||||
|
||||
g_object_notify (G_OBJECT (dest), "range");
|
||||
g_object_notify (G_OBJECT (dest), "overlap");
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/* public functions */
|
||||
|
||||
void
|
||||
pika_hue_saturation_config_reset_range (PikaHueSaturationConfig *config)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_HUE_SATURATION_CONFIG (config));
|
||||
|
||||
g_object_freeze_notify (G_OBJECT (config));
|
||||
|
||||
pika_config_reset_property (G_OBJECT (config), "hue");
|
||||
pika_config_reset_property (G_OBJECT (config), "saturation");
|
||||
pika_config_reset_property (G_OBJECT (config), "lightness");
|
||||
|
||||
g_object_thaw_notify (G_OBJECT (config));
|
||||
}
|
||||
66
app/operations/pikahuesaturationconfig.h
Normal file
66
app/operations/pikahuesaturationconfig.h
Normal file
@ -0,0 +1,66 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikahuesaturationconfig.h
|
||||
* Copyright (C) 2007 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* 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 __PIKA_HUE_SATURATION_CONFIG_H__
|
||||
#define __PIKA_HUE_SATURATION_CONFIG_H__
|
||||
|
||||
|
||||
#include "pikaoperationsettings.h"
|
||||
|
||||
|
||||
#define PIKA_TYPE_HUE_SATURATION_CONFIG (pika_hue_saturation_config_get_type ())
|
||||
#define PIKA_HUE_SATURATION_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_HUE_SATURATION_CONFIG, PikaHueSaturationConfig))
|
||||
#define PIKA_HUE_SATURATION_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_HUE_SATURATION_CONFIG, PikaHueSaturationConfigClass))
|
||||
#define PIKA_IS_HUE_SATURATION_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_HUE_SATURATION_CONFIG))
|
||||
#define PIKA_IS_HUE_SATURATION_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_HUE_SATURATION_CONFIG))
|
||||
#define PIKA_HUE_SATURATION_CONFIG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_HUE_SATURATION_CONFIG, PikaHueSaturationConfigClass))
|
||||
|
||||
|
||||
typedef struct _PikaHueSaturationConfigClass PikaHueSaturationConfigClass;
|
||||
|
||||
struct _PikaHueSaturationConfig
|
||||
{
|
||||
PikaOperationSettings parent_instance;
|
||||
|
||||
PikaHueRange range;
|
||||
|
||||
gdouble hue[7];
|
||||
gdouble saturation[7];
|
||||
gdouble lightness[7];
|
||||
|
||||
gdouble overlap;
|
||||
};
|
||||
|
||||
struct _PikaHueSaturationConfigClass
|
||||
{
|
||||
PikaOperationSettingsClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType pika_hue_saturation_config_get_type (void) G_GNUC_CONST;
|
||||
|
||||
void pika_hue_saturation_config_reset_range (PikaHueSaturationConfig *config);
|
||||
|
||||
|
||||
#endif /* __PIKA_HUE_SATURATION_CONFIG_H__ */
|
||||
987
app/operations/pikalevelsconfig.c
Normal file
987
app/operations/pikalevelsconfig.c
Normal file
@ -0,0 +1,987 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikalevelsconfig.c
|
||||
* Copyright (C) 2007 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* 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 <errno.h>
|
||||
|
||||
#include <cairo.h>
|
||||
#include <gegl.h>
|
||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||
|
||||
#include "libpikabase/pikabase.h"
|
||||
#include "libpikacolor/pikacolor.h"
|
||||
#include "libpikamath/pikamath.h"
|
||||
#include "libpikaconfig/pikaconfig.h"
|
||||
|
||||
#include "operations-types.h"
|
||||
|
||||
#include "core/pika-utils.h"
|
||||
#include "core/pikacurve.h"
|
||||
#include "core/pikahistogram.h"
|
||||
|
||||
#include "pikacurvesconfig.h"
|
||||
#include "pikalevelsconfig.h"
|
||||
#include "pikaoperationlevels.h"
|
||||
|
||||
#include "pika-intl.h"
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_TRC,
|
||||
PROP_LINEAR,
|
||||
PROP_CHANNEL,
|
||||
PROP_LOW_INPUT,
|
||||
PROP_HIGH_INPUT,
|
||||
PROP_CLAMP_INPUT,
|
||||
PROP_GAMMA,
|
||||
PROP_LOW_OUTPUT,
|
||||
PROP_HIGH_OUTPUT,
|
||||
PROP_CLAMP_OUTPUT
|
||||
};
|
||||
|
||||
|
||||
static void pika_levels_config_iface_init (PikaConfigInterface *iface);
|
||||
|
||||
static void pika_levels_config_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void pika_levels_config_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec);
|
||||
|
||||
static gboolean pika_levels_config_serialize (PikaConfig *config,
|
||||
PikaConfigWriter *writer,
|
||||
gpointer data);
|
||||
static gboolean pika_levels_config_deserialize (PikaConfig *config,
|
||||
GScanner *scanner,
|
||||
gint nest_level,
|
||||
gpointer data);
|
||||
static gboolean pika_levels_config_equal (PikaConfig *a,
|
||||
PikaConfig *b);
|
||||
static void pika_levels_config_reset (PikaConfig *config);
|
||||
static gboolean pika_levels_config_copy (PikaConfig *src,
|
||||
PikaConfig *dest,
|
||||
GParamFlags flags);
|
||||
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (PikaLevelsConfig, pika_levels_config,
|
||||
PIKA_TYPE_OPERATION_SETTINGS,
|
||||
G_IMPLEMENT_INTERFACE (PIKA_TYPE_CONFIG,
|
||||
pika_levels_config_iface_init))
|
||||
|
||||
#define parent_class pika_levels_config_parent_class
|
||||
|
||||
|
||||
static void
|
||||
pika_levels_config_class_init (PikaLevelsConfigClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
PikaViewableClass *viewable_class = PIKA_VIEWABLE_CLASS (klass);
|
||||
|
||||
object_class->set_property = pika_levels_config_set_property;
|
||||
object_class->get_property = pika_levels_config_get_property;
|
||||
|
||||
viewable_class->default_icon_name = "pika-tool-levels";
|
||||
|
||||
PIKA_CONFIG_PROP_ENUM (object_class, PROP_TRC,
|
||||
"trc",
|
||||
_("Linear/Perceptual"),
|
||||
_("Work on linear or perceptual RGB"),
|
||||
PIKA_TYPE_TRC_TYPE,
|
||||
PIKA_TRC_NON_LINEAR, 0);
|
||||
|
||||
/* compat */
|
||||
PIKA_CONFIG_PROP_BOOLEAN (object_class, PROP_LINEAR,
|
||||
"linear",
|
||||
_("Linear"),
|
||||
_("Work on linear RGB"),
|
||||
FALSE, 0);
|
||||
|
||||
PIKA_CONFIG_PROP_ENUM (object_class, PROP_CHANNEL,
|
||||
"channel",
|
||||
_("Channel"),
|
||||
_("The affected channel"),
|
||||
PIKA_TYPE_HISTOGRAM_CHANNEL,
|
||||
PIKA_HISTOGRAM_VALUE, 0);
|
||||
|
||||
PIKA_CONFIG_PROP_DOUBLE (object_class, PROP_LOW_INPUT,
|
||||
"low-input",
|
||||
_("Low Input"),
|
||||
_("Low Input"),
|
||||
0.0, 1.0, 0.0, 0);
|
||||
|
||||
PIKA_CONFIG_PROP_DOUBLE (object_class, PROP_HIGH_INPUT,
|
||||
"high-input",
|
||||
_("High Input"),
|
||||
_("High Input"),
|
||||
0.0, 1.0, 1.0, 0);
|
||||
|
||||
PIKA_CONFIG_PROP_BOOLEAN (object_class, PROP_CLAMP_INPUT,
|
||||
"clamp-input",
|
||||
_("Clamp Input"),
|
||||
_("Clamp input values before applying output mapping."),
|
||||
FALSE, 0);
|
||||
|
||||
PIKA_CONFIG_PROP_DOUBLE (object_class, PROP_GAMMA,
|
||||
"gamma",
|
||||
_("Gamma"),
|
||||
_("Gamma"),
|
||||
0.1, 10.0, 1.0, 0);
|
||||
|
||||
PIKA_CONFIG_PROP_DOUBLE (object_class, PROP_LOW_OUTPUT,
|
||||
"low-output",
|
||||
_("Low Output"),
|
||||
_("Low Output"),
|
||||
0.0, 1.0, 0.0, 0);
|
||||
|
||||
PIKA_CONFIG_PROP_DOUBLE (object_class, PROP_HIGH_OUTPUT,
|
||||
"high-output",
|
||||
_("High Output"),
|
||||
_("High Output"),
|
||||
0.0, 1.0, 1.0, 0);
|
||||
|
||||
PIKA_CONFIG_PROP_BOOLEAN (object_class, PROP_CLAMP_OUTPUT,
|
||||
"clamp-output",
|
||||
_("Clamp Output"),
|
||||
_("Clamp final output values."),
|
||||
FALSE, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_levels_config_iface_init (PikaConfigInterface *iface)
|
||||
{
|
||||
iface->serialize = pika_levels_config_serialize;
|
||||
iface->deserialize = pika_levels_config_deserialize;
|
||||
iface->equal = pika_levels_config_equal;
|
||||
iface->reset = pika_levels_config_reset;
|
||||
iface->copy = pika_levels_config_copy;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_levels_config_init (PikaLevelsConfig *self)
|
||||
{
|
||||
pika_config_reset (PIKA_CONFIG (self));
|
||||
}
|
||||
|
||||
static void
|
||||
pika_levels_config_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaLevelsConfig *self = PIKA_LEVELS_CONFIG (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_TRC:
|
||||
g_value_set_enum (value, self->trc);
|
||||
break;
|
||||
|
||||
case PROP_LINEAR:
|
||||
g_value_set_boolean (value, self->trc == PIKA_TRC_LINEAR ? TRUE : FALSE);
|
||||
break;
|
||||
|
||||
case PROP_CHANNEL:
|
||||
g_value_set_enum (value, self->channel);
|
||||
break;
|
||||
|
||||
case PROP_LOW_INPUT:
|
||||
g_value_set_double (value, self->low_input[self->channel]);
|
||||
break;
|
||||
|
||||
case PROP_HIGH_INPUT:
|
||||
g_value_set_double (value, self->high_input[self->channel]);
|
||||
break;
|
||||
|
||||
case PROP_CLAMP_INPUT:
|
||||
g_value_set_boolean (value, self->clamp_input);
|
||||
break;
|
||||
|
||||
case PROP_GAMMA:
|
||||
g_value_set_double (value, self->gamma[self->channel]);
|
||||
break;
|
||||
|
||||
case PROP_LOW_OUTPUT:
|
||||
g_value_set_double (value, self->low_output[self->channel]);
|
||||
break;
|
||||
|
||||
case PROP_HIGH_OUTPUT:
|
||||
g_value_set_double (value, self->high_output[self->channel]);
|
||||
break;
|
||||
|
||||
case PROP_CLAMP_OUTPUT:
|
||||
g_value_set_boolean (value, self->clamp_output);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_levels_config_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaLevelsConfig *self = PIKA_LEVELS_CONFIG (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_TRC:
|
||||
self->trc = g_value_get_enum (value);
|
||||
break;
|
||||
|
||||
case PROP_LINEAR:
|
||||
self->trc = g_value_get_boolean (value) ?
|
||||
PIKA_TRC_LINEAR : PIKA_TRC_NON_LINEAR;
|
||||
g_object_notify (object, "trc");
|
||||
break;
|
||||
|
||||
case PROP_CHANNEL:
|
||||
self->channel = g_value_get_enum (value);
|
||||
g_object_notify (object, "low-input");
|
||||
g_object_notify (object, "high-input");
|
||||
g_object_notify (object, "gamma");
|
||||
g_object_notify (object, "low-output");
|
||||
g_object_notify (object, "high-output");
|
||||
break;
|
||||
|
||||
case PROP_LOW_INPUT:
|
||||
self->low_input[self->channel] = g_value_get_double (value);
|
||||
break;
|
||||
|
||||
case PROP_HIGH_INPUT:
|
||||
self->high_input[self->channel] = g_value_get_double (value);
|
||||
break;
|
||||
|
||||
case PROP_CLAMP_INPUT:
|
||||
self->clamp_input = g_value_get_boolean (value);
|
||||
break;
|
||||
|
||||
case PROP_GAMMA:
|
||||
self->gamma[self->channel] = g_value_get_double (value);
|
||||
break;
|
||||
|
||||
case PROP_LOW_OUTPUT:
|
||||
self->low_output[self->channel] = g_value_get_double (value);
|
||||
break;
|
||||
|
||||
case PROP_HIGH_OUTPUT:
|
||||
self->high_output[self->channel] = g_value_get_double (value);
|
||||
break;
|
||||
|
||||
case PROP_CLAMP_OUTPUT:
|
||||
self->clamp_output = g_value_get_boolean (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_levels_config_serialize (PikaConfig *config,
|
||||
PikaConfigWriter *writer,
|
||||
gpointer data)
|
||||
{
|
||||
PikaLevelsConfig *l_config = PIKA_LEVELS_CONFIG (config);
|
||||
PikaHistogramChannel channel;
|
||||
PikaHistogramChannel old_channel;
|
||||
gboolean success = TRUE;
|
||||
|
||||
if (! pika_operation_settings_config_serialize_base (config, writer, data) ||
|
||||
! pika_config_serialize_property_by_name (config, "trc", writer) ||
|
||||
! pika_config_serialize_property_by_name (config, "clamp-input", writer) ||
|
||||
! pika_config_serialize_property_by_name (config, "clamp-output", writer))
|
||||
return FALSE;
|
||||
|
||||
old_channel = l_config->channel;
|
||||
|
||||
for (channel = PIKA_HISTOGRAM_VALUE;
|
||||
channel <= PIKA_HISTOGRAM_ALPHA;
|
||||
channel++)
|
||||
{
|
||||
l_config->channel = channel;
|
||||
|
||||
/* serialize the channel properties manually (not using
|
||||
* pika_config_serialize_properties()), so the parent class'
|
||||
* properties don't end up in the config file one per channel.
|
||||
* See bug #700653.
|
||||
*/
|
||||
success =
|
||||
(pika_config_serialize_property_by_name (config, "channel", writer) &&
|
||||
pika_config_serialize_property_by_name (config, "low-input", writer) &&
|
||||
pika_config_serialize_property_by_name (config, "high-input", writer) &&
|
||||
pika_config_serialize_property_by_name (config, "gamma", writer) &&
|
||||
pika_config_serialize_property_by_name (config, "low-output", writer) &&
|
||||
pika_config_serialize_property_by_name (config, "high-output", writer));
|
||||
|
||||
if (! success)
|
||||
break;
|
||||
}
|
||||
|
||||
l_config->channel = old_channel;
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_levels_config_deserialize (PikaConfig *config,
|
||||
GScanner *scanner,
|
||||
gint nest_level,
|
||||
gpointer data)
|
||||
{
|
||||
PikaLevelsConfig *l_config = PIKA_LEVELS_CONFIG (config);
|
||||
PikaHistogramChannel old_channel;
|
||||
gboolean success = TRUE;
|
||||
|
||||
old_channel = l_config->channel;
|
||||
|
||||
success = pika_config_deserialize_properties (config, scanner, nest_level);
|
||||
|
||||
g_object_set (config, "channel", old_channel, NULL);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_levels_config_equal (PikaConfig *a,
|
||||
PikaConfig *b)
|
||||
{
|
||||
PikaLevelsConfig *config_a = PIKA_LEVELS_CONFIG (a);
|
||||
PikaLevelsConfig *config_b = PIKA_LEVELS_CONFIG (b);
|
||||
PikaHistogramChannel channel;
|
||||
|
||||
if (! pika_operation_settings_config_equal_base (a, b) ||
|
||||
config_a->trc != config_b->trc ||
|
||||
config_a->clamp_input != config_b->clamp_input ||
|
||||
config_a->clamp_output != config_b->clamp_output)
|
||||
return FALSE;
|
||||
|
||||
for (channel = PIKA_HISTOGRAM_VALUE;
|
||||
channel <= PIKA_HISTOGRAM_ALPHA;
|
||||
channel++)
|
||||
{
|
||||
if (config_a->gamma[channel] != config_b->gamma[channel] ||
|
||||
config_a->low_input[channel] != config_b->low_input[channel] ||
|
||||
config_a->high_input[channel] != config_b->high_input[channel] ||
|
||||
config_a->low_output[channel] != config_b->low_output[channel] ||
|
||||
config_a->high_output[channel] != config_b->high_output[channel])
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* don't compare "channel" */
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_levels_config_reset (PikaConfig *config)
|
||||
{
|
||||
PikaLevelsConfig *l_config = PIKA_LEVELS_CONFIG (config);
|
||||
PikaHistogramChannel channel;
|
||||
|
||||
pika_operation_settings_config_reset_base (config);
|
||||
|
||||
for (channel = PIKA_HISTOGRAM_VALUE;
|
||||
channel <= PIKA_HISTOGRAM_ALPHA;
|
||||
channel++)
|
||||
{
|
||||
l_config->channel = channel;
|
||||
pika_levels_config_reset_channel (l_config);
|
||||
}
|
||||
|
||||
pika_config_reset_property (G_OBJECT (config), "trc");
|
||||
pika_config_reset_property (G_OBJECT (config), "channel");
|
||||
pika_config_reset_property (G_OBJECT (config), "clamp-input");
|
||||
pika_config_reset_property (G_OBJECT (config), "clamp_output");
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_levels_config_copy (PikaConfig *src,
|
||||
PikaConfig *dest,
|
||||
GParamFlags flags)
|
||||
{
|
||||
PikaLevelsConfig *src_config = PIKA_LEVELS_CONFIG (src);
|
||||
PikaLevelsConfig *dest_config = PIKA_LEVELS_CONFIG (dest);
|
||||
PikaHistogramChannel channel;
|
||||
|
||||
if (! pika_operation_settings_config_copy_base (src, dest, flags))
|
||||
return FALSE;
|
||||
|
||||
for (channel = PIKA_HISTOGRAM_VALUE;
|
||||
channel <= PIKA_HISTOGRAM_ALPHA;
|
||||
channel++)
|
||||
{
|
||||
dest_config->gamma[channel] = src_config->gamma[channel];
|
||||
dest_config->low_input[channel] = src_config->low_input[channel];
|
||||
dest_config->high_input[channel] = src_config->high_input[channel];
|
||||
dest_config->low_output[channel] = src_config->low_output[channel];
|
||||
dest_config->high_output[channel] = src_config->high_output[channel];
|
||||
}
|
||||
|
||||
g_object_notify (G_OBJECT (dest), "gamma");
|
||||
g_object_notify (G_OBJECT (dest), "low-input");
|
||||
g_object_notify (G_OBJECT (dest), "high-input");
|
||||
g_object_notify (G_OBJECT (dest), "low-output");
|
||||
g_object_notify (G_OBJECT (dest), "high-output");
|
||||
|
||||
dest_config->trc = src_config->trc;
|
||||
dest_config->channel = src_config->channel;
|
||||
dest_config->clamp_input = src_config->clamp_input;
|
||||
dest_config->clamp_output = src_config->clamp_output;
|
||||
|
||||
g_object_notify (G_OBJECT (dest), "trc");
|
||||
g_object_notify (G_OBJECT (dest), "channel");
|
||||
g_object_notify (G_OBJECT (dest), "clamp-input");
|
||||
g_object_notify (G_OBJECT (dest), "clamp-output");
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/* public functions */
|
||||
|
||||
void
|
||||
pika_levels_config_reset_channel (PikaLevelsConfig *config)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_LEVELS_CONFIG (config));
|
||||
|
||||
g_object_freeze_notify (G_OBJECT (config));
|
||||
|
||||
pika_config_reset_property (G_OBJECT (config), "gamma");
|
||||
pika_config_reset_property (G_OBJECT (config), "low-input");
|
||||
pika_config_reset_property (G_OBJECT (config), "high-input");
|
||||
pika_config_reset_property (G_OBJECT (config), "low-output");
|
||||
pika_config_reset_property (G_OBJECT (config), "high-output");
|
||||
|
||||
g_object_thaw_notify (G_OBJECT (config));
|
||||
}
|
||||
|
||||
void
|
||||
pika_levels_config_stretch (PikaLevelsConfig *config,
|
||||
PikaHistogram *histogram,
|
||||
gboolean is_color)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_LEVELS_CONFIG (config));
|
||||
g_return_if_fail (histogram != NULL);
|
||||
|
||||
g_object_freeze_notify (G_OBJECT (config));
|
||||
|
||||
if (is_color)
|
||||
{
|
||||
PikaHistogramChannel channel;
|
||||
|
||||
/* Set the overall value to defaults */
|
||||
channel = config->channel;
|
||||
config->channel = PIKA_HISTOGRAM_VALUE;
|
||||
pika_levels_config_reset_channel (config);
|
||||
config->channel = channel;
|
||||
|
||||
for (channel = PIKA_HISTOGRAM_RED;
|
||||
channel <= PIKA_HISTOGRAM_BLUE;
|
||||
channel++)
|
||||
{
|
||||
pika_levels_config_stretch_channel (config, histogram, channel);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pika_levels_config_stretch_channel (config, histogram,
|
||||
PIKA_HISTOGRAM_VALUE);
|
||||
}
|
||||
|
||||
g_object_thaw_notify (G_OBJECT (config));
|
||||
}
|
||||
|
||||
void
|
||||
pika_levels_config_stretch_channel (PikaLevelsConfig *config,
|
||||
PikaHistogram *histogram,
|
||||
PikaHistogramChannel channel)
|
||||
{
|
||||
gdouble count;
|
||||
gdouble bias = 0.006;
|
||||
gint n_bins;
|
||||
gint i;
|
||||
|
||||
g_return_if_fail (PIKA_IS_LEVELS_CONFIG (config));
|
||||
g_return_if_fail (histogram != NULL);
|
||||
|
||||
g_object_freeze_notify (G_OBJECT (config));
|
||||
|
||||
config->gamma[channel] = 1.0;
|
||||
config->low_output[channel] = 0.0;
|
||||
config->high_output[channel] = 1.0;
|
||||
|
||||
n_bins = pika_histogram_n_bins (histogram);
|
||||
count = pika_histogram_get_count (histogram, channel, 0, n_bins - 1);
|
||||
|
||||
if (count == 0.0)
|
||||
{
|
||||
config->low_input[channel] = 0.0;
|
||||
config->high_input[channel] = 0.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
gdouble new_count;
|
||||
gdouble percentage;
|
||||
gdouble next_percentage;
|
||||
|
||||
/* Set the low input */
|
||||
new_count = 0.0;
|
||||
|
||||
for (i = 0; i < (n_bins - 1); i++)
|
||||
{
|
||||
new_count += pika_histogram_get_value (histogram, channel, i);
|
||||
percentage = new_count / count;
|
||||
next_percentage = (new_count +
|
||||
pika_histogram_get_value (histogram,
|
||||
channel,
|
||||
i + 1)) / count;
|
||||
|
||||
if (fabs (percentage - bias) < fabs (next_percentage - bias))
|
||||
{
|
||||
config->low_input[channel] = (gdouble) (i + 1) / (n_bins - 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Set the high input */
|
||||
new_count = 0.0;
|
||||
|
||||
for (i = (n_bins - 1); i > 0; i--)
|
||||
{
|
||||
new_count += pika_histogram_get_value (histogram, channel, i);
|
||||
percentage = new_count / count;
|
||||
next_percentage = (new_count +
|
||||
pika_histogram_get_value (histogram,
|
||||
channel,
|
||||
i - 1)) / count;
|
||||
|
||||
if (fabs (percentage - bias) < fabs (next_percentage - bias))
|
||||
{
|
||||
config->high_input[channel] = (gdouble) (i - 1) / (n_bins - 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
g_object_notify (G_OBJECT (config), "gamma");
|
||||
g_object_notify (G_OBJECT (config), "low-input");
|
||||
g_object_notify (G_OBJECT (config), "high-input");
|
||||
g_object_notify (G_OBJECT (config), "low-output");
|
||||
g_object_notify (G_OBJECT (config), "high-output");
|
||||
|
||||
g_object_thaw_notify (G_OBJECT (config));
|
||||
}
|
||||
|
||||
static gdouble
|
||||
pika_levels_config_input_from_color (PikaHistogramChannel channel,
|
||||
const PikaRGB *color)
|
||||
{
|
||||
switch (channel)
|
||||
{
|
||||
case PIKA_HISTOGRAM_VALUE:
|
||||
return MAX (MAX (color->r, color->g), color->b);
|
||||
|
||||
case PIKA_HISTOGRAM_RED:
|
||||
return color->r;
|
||||
|
||||
case PIKA_HISTOGRAM_GREEN:
|
||||
return color->g;
|
||||
|
||||
case PIKA_HISTOGRAM_BLUE:
|
||||
return color->b;
|
||||
|
||||
case PIKA_HISTOGRAM_ALPHA:
|
||||
return color->a;
|
||||
|
||||
case PIKA_HISTOGRAM_RGB:
|
||||
return MIN (MIN (color->r, color->g), color->b);
|
||||
|
||||
case PIKA_HISTOGRAM_LUMINANCE:
|
||||
return PIKA_RGB_LUMINANCE (color->r, color->g, color->b);
|
||||
}
|
||||
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
void
|
||||
pika_levels_config_adjust_by_colors (PikaLevelsConfig *config,
|
||||
PikaHistogramChannel channel,
|
||||
const PikaRGB *black,
|
||||
const PikaRGB *gray,
|
||||
const PikaRGB *white)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_LEVELS_CONFIG (config));
|
||||
|
||||
g_object_freeze_notify (G_OBJECT (config));
|
||||
|
||||
if (black)
|
||||
{
|
||||
config->low_input[channel] = pika_levels_config_input_from_color (channel,
|
||||
black);
|
||||
g_object_notify (G_OBJECT (config), "low-input");
|
||||
}
|
||||
|
||||
|
||||
if (white)
|
||||
{
|
||||
config->high_input[channel] = pika_levels_config_input_from_color (channel,
|
||||
white);
|
||||
g_object_notify (G_OBJECT (config), "high-input");
|
||||
}
|
||||
|
||||
if (gray)
|
||||
{
|
||||
gdouble input;
|
||||
gdouble range;
|
||||
gdouble inten;
|
||||
gdouble out_light;
|
||||
gdouble lightness;
|
||||
|
||||
/* Calculate lightness value */
|
||||
lightness = PIKA_RGB_LUMINANCE (gray->r, gray->g, gray->b);
|
||||
|
||||
input = pika_levels_config_input_from_color (channel, gray);
|
||||
|
||||
range = config->high_input[channel] - config->low_input[channel];
|
||||
if (range <= 0)
|
||||
goto out;
|
||||
|
||||
input -= config->low_input[channel];
|
||||
if (input < 0)
|
||||
goto out;
|
||||
|
||||
/* Normalize input and lightness */
|
||||
inten = input / range;
|
||||
out_light = lightness / range;
|
||||
|
||||
/* See bug 622054: picking pure black or white as gamma doesn't
|
||||
* work. But we cannot compare to 0.0 or 1.0 because cpus and
|
||||
* compilers are shit. If you try to check out_light using
|
||||
* printf() it will give exact 0.0 or 1.0 anyway, probably
|
||||
* because the generated code is different and out_light doesn't
|
||||
* live in a register. That must be why the cpu/compiler mafia
|
||||
* invented epsilon and defined this shit to be the programmer's
|
||||
* responsibility.
|
||||
*/
|
||||
if (out_light <= 0.0001 || out_light >= 0.9999)
|
||||
goto out;
|
||||
|
||||
/* Map selected color to corresponding lightness */
|
||||
config->gamma[channel] = log (inten) / log (out_light);
|
||||
config->gamma[channel] = CLAMP (config->gamma[channel], 0.1, 10.0);
|
||||
g_object_notify (G_OBJECT (config), "gamma");
|
||||
}
|
||||
|
||||
out:
|
||||
g_object_thaw_notify (G_OBJECT (config));
|
||||
}
|
||||
|
||||
PikaCurvesConfig *
|
||||
pika_levels_config_to_curves_config (PikaLevelsConfig *config)
|
||||
{
|
||||
PikaCurvesConfig *curves;
|
||||
PikaHistogramChannel channel;
|
||||
|
||||
g_return_val_if_fail (PIKA_IS_LEVELS_CONFIG (config), NULL);
|
||||
|
||||
curves = g_object_new (PIKA_TYPE_CURVES_CONFIG, NULL);
|
||||
|
||||
pika_operation_settings_config_copy_base (PIKA_CONFIG (config),
|
||||
PIKA_CONFIG (curves),
|
||||
0);
|
||||
|
||||
curves->trc = config->trc;
|
||||
|
||||
for (channel = PIKA_HISTOGRAM_VALUE;
|
||||
channel <= PIKA_HISTOGRAM_ALPHA;
|
||||
channel++)
|
||||
{
|
||||
PikaCurve *curve = curves->curve[channel];
|
||||
static const gint n = 8;
|
||||
gdouble gamma = config->gamma[channel];
|
||||
gdouble delta_in;
|
||||
gdouble delta_out;
|
||||
gdouble x, y;
|
||||
|
||||
/* clear the points set by default */
|
||||
pika_curve_clear_points (curve);
|
||||
|
||||
delta_in = config->high_input[channel] - config->low_input[channel];
|
||||
delta_out = config->high_output[channel] - config->low_output[channel];
|
||||
|
||||
x = config->low_input[channel];
|
||||
y = config->low_output[channel];
|
||||
|
||||
pika_curve_add_point (curve, x, y);
|
||||
|
||||
if (delta_out != 0 && gamma != 1.0)
|
||||
{
|
||||
/* The Levels tool performs gamma adjustment, which is a
|
||||
* power law, while the Curves tool uses cubic Bézier
|
||||
* curves. Here we try to approximate this gamma adjustment
|
||||
* with a Bézier curve with 5 control points. Two of them
|
||||
* must be (low_input, low_output) and (high_input,
|
||||
* high_output), so we need to add 3 more control points in
|
||||
* the middle.
|
||||
*/
|
||||
gint i;
|
||||
|
||||
if (gamma > 1)
|
||||
{
|
||||
/* Case no. 1: γ > 1
|
||||
*
|
||||
* The curve should look like a horizontal
|
||||
* parabola. Since its curvature is greatest when x is
|
||||
* small, we add more control points there, so the
|
||||
* approximation is more accurate. I decided to set the
|
||||
* length of the consecutive segments to x₀, γ⋅x₀, γ²⋅x₀
|
||||
* and γ³⋅x₀ and I saw that the curves looked
|
||||
* good. Still, this is completely arbitrary.
|
||||
*/
|
||||
gdouble dx = 0;
|
||||
gdouble x0;
|
||||
|
||||
for (i = 0; i < n; ++i)
|
||||
dx = dx * gamma + 1;
|
||||
x0 = delta_in / dx;
|
||||
|
||||
dx = 0;
|
||||
for (i = 1; i < n; ++i)
|
||||
{
|
||||
dx = dx * gamma + x0;
|
||||
x = config->low_input[channel] + dx;
|
||||
y = config->low_output[channel] + delta_out *
|
||||
pika_operation_levels_map_input (config, channel, x);
|
||||
pika_curve_add_point (curve, x, y);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Case no. 2: γ < 1
|
||||
*
|
||||
* The curve is the same as the one in case no. 1,
|
||||
* observed through a reflexion along the y = x axis. So
|
||||
* if we invert γ and swap the x and y axes we can use
|
||||
* the same method as in case no. 1.
|
||||
*/
|
||||
PikaLevelsConfig *config_inv;
|
||||
gdouble dy = 0;
|
||||
gdouble y0;
|
||||
const gdouble gamma_inv = 1 / gamma;
|
||||
|
||||
config_inv = pika_config_duplicate (PIKA_CONFIG (config));
|
||||
|
||||
config_inv->gamma[channel] = gamma_inv;
|
||||
config_inv->low_input[channel] = config->low_output[channel];
|
||||
config_inv->low_output[channel] = config->low_input[channel];
|
||||
config_inv->high_input[channel] = config->high_output[channel];
|
||||
config_inv->high_output[channel] = config->high_input[channel];
|
||||
|
||||
for (i = 0; i < n; ++i)
|
||||
dy = dy * gamma_inv + 1;
|
||||
y0 = delta_out / dy;
|
||||
|
||||
dy = 0;
|
||||
for (i = 1; i < n; ++i)
|
||||
{
|
||||
dy = dy * gamma_inv + y0;
|
||||
y = config->low_output[channel] + dy;
|
||||
x = config->low_input[channel] + delta_in *
|
||||
pika_operation_levels_map_input (config_inv, channel, y);
|
||||
pika_curve_add_point (curve, x, y);
|
||||
}
|
||||
|
||||
g_object_unref (config_inv);
|
||||
}
|
||||
}
|
||||
|
||||
x = config->high_input[channel];
|
||||
y = config->high_output[channel];
|
||||
|
||||
pika_curve_add_point (curve, x, y);
|
||||
}
|
||||
|
||||
return curves;
|
||||
}
|
||||
|
||||
gboolean
|
||||
pika_levels_config_load_cruft (PikaLevelsConfig *config,
|
||||
GInputStream *input,
|
||||
GError **error)
|
||||
{
|
||||
GDataInputStream *data_input;
|
||||
gint low_input[5];
|
||||
gint high_input[5];
|
||||
gint low_output[5];
|
||||
gint high_output[5];
|
||||
gdouble gamma[5];
|
||||
gchar *line;
|
||||
gsize line_len;
|
||||
gint i;
|
||||
|
||||
g_return_val_if_fail (PIKA_IS_LEVELS_CONFIG (config), FALSE);
|
||||
g_return_val_if_fail (G_IS_INPUT_STREAM (input), FALSE);
|
||||
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
||||
|
||||
data_input = g_data_input_stream_new (input);
|
||||
|
||||
line_len = 64;
|
||||
line = pika_data_input_stream_read_line_always (data_input, &line_len,
|
||||
NULL, error);
|
||||
if (! line)
|
||||
return FALSE;
|
||||
|
||||
if (strcmp (line, "# PIKA Levels File") != 0)
|
||||
{
|
||||
g_set_error_literal (error, PIKA_CONFIG_ERROR, PIKA_CONFIG_ERROR_PARSE,
|
||||
_("not a PIKA Levels file"));
|
||||
g_object_unref (data_input);
|
||||
g_free (line);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
g_free (line);
|
||||
|
||||
for (i = 0; i < 5; i++)
|
||||
{
|
||||
gchar float_buf[32];
|
||||
gchar *endp;
|
||||
gint fields;
|
||||
|
||||
line_len = 64;
|
||||
line = pika_data_input_stream_read_line_always (data_input, &line_len,
|
||||
NULL, error);
|
||||
if (! line)
|
||||
{
|
||||
g_object_unref (data_input);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
fields = sscanf (line, "%d %d %d %d %31s",
|
||||
&low_input[i],
|
||||
&high_input[i],
|
||||
&low_output[i],
|
||||
&high_output[i],
|
||||
float_buf);
|
||||
|
||||
g_free (line);
|
||||
|
||||
if (fields != 5)
|
||||
goto error;
|
||||
|
||||
gamma[i] = g_ascii_strtod (float_buf, &endp);
|
||||
|
||||
if (endp == float_buf || errno == ERANGE)
|
||||
goto error;
|
||||
}
|
||||
|
||||
g_object_unref (data_input);
|
||||
|
||||
g_object_freeze_notify (G_OBJECT (config));
|
||||
|
||||
for (i = 0; i < 5; i++)
|
||||
{
|
||||
config->low_input[i] = low_input[i] / 255.0;
|
||||
config->high_input[i] = high_input[i] / 255.0;
|
||||
config->gamma[i] = gamma[i];
|
||||
config->low_output[i] = low_output[i] / 255.0;
|
||||
config->high_output[i] = high_output[i] / 255.0;
|
||||
}
|
||||
|
||||
config->trc = PIKA_TRC_NON_LINEAR;
|
||||
config->clamp_input = TRUE;
|
||||
config->clamp_output = TRUE;
|
||||
|
||||
g_object_notify (G_OBJECT (config), "trc");
|
||||
g_object_notify (G_OBJECT (config), "low-input");
|
||||
g_object_notify (G_OBJECT (config), "high-input");
|
||||
g_object_notify (G_OBJECT (config), "clamp-input");
|
||||
g_object_notify (G_OBJECT (config), "gamma");
|
||||
g_object_notify (G_OBJECT (config), "low-output");
|
||||
g_object_notify (G_OBJECT (config), "high-output");
|
||||
g_object_notify (G_OBJECT (config), "clamp-output");
|
||||
|
||||
g_object_thaw_notify (G_OBJECT (config));
|
||||
|
||||
return TRUE;
|
||||
|
||||
error:
|
||||
g_object_unref (data_input);
|
||||
|
||||
g_set_error_literal (error, PIKA_CONFIG_ERROR, PIKA_CONFIG_ERROR_PARSE,
|
||||
_("parse error"));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
pika_levels_config_save_cruft (PikaLevelsConfig *config,
|
||||
GOutputStream *output,
|
||||
GError **error)
|
||||
{
|
||||
GString *string;
|
||||
gint i;
|
||||
|
||||
g_return_val_if_fail (PIKA_IS_LEVELS_CONFIG (config), FALSE);
|
||||
g_return_val_if_fail (G_IS_OUTPUT_STREAM (output), FALSE);
|
||||
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
||||
|
||||
string = g_string_new ("# PIKA Levels File\n");
|
||||
|
||||
for (i = 0; i < 5; i++)
|
||||
{
|
||||
gchar buf[G_ASCII_DTOSTR_BUF_SIZE];
|
||||
|
||||
g_string_append_printf (string,
|
||||
"%d %d %d %d %s\n",
|
||||
(gint) (config->low_input[i] * 255.999),
|
||||
(gint) (config->high_input[i] * 255.999),
|
||||
(gint) (config->low_output[i] * 255.999),
|
||||
(gint) (config->high_output[i] * 255.999),
|
||||
g_ascii_dtostr (buf, G_ASCII_DTOSTR_BUF_SIZE,
|
||||
config->gamma[i]));
|
||||
}
|
||||
|
||||
if (! g_output_stream_write_all (output, string->str, string->len,
|
||||
NULL, NULL, error))
|
||||
{
|
||||
g_prefix_error (error, _("Writing levels file failed: "));
|
||||
g_string_free (string, TRUE);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
g_string_free (string, TRUE);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
96
app/operations/pikalevelsconfig.h
Normal file
96
app/operations/pikalevelsconfig.h
Normal file
@ -0,0 +1,96 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikalevelsconfig.h
|
||||
* Copyright (C) 2007 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* 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 __PIKA_LEVELS_CONFIG_H__
|
||||
#define __PIKA_LEVELS_CONFIG_H__
|
||||
|
||||
|
||||
#include "pikaoperationsettings.h"
|
||||
|
||||
|
||||
#define PIKA_TYPE_LEVELS_CONFIG (pika_levels_config_get_type ())
|
||||
#define PIKA_LEVELS_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_LEVELS_CONFIG, PikaLevelsConfig))
|
||||
#define PIKA_LEVELS_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_LEVELS_CONFIG, PikaLevelsConfigClass))
|
||||
#define PIKA_IS_LEVELS_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_LEVELS_CONFIG))
|
||||
#define PIKA_IS_LEVELS_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_LEVELS_CONFIG))
|
||||
#define PIKA_LEVELS_CONFIG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_LEVELS_CONFIG, PikaLevelsConfigClass))
|
||||
|
||||
|
||||
typedef struct _PikaLevelsConfigClass PikaLevelsConfigClass;
|
||||
|
||||
struct _PikaLevelsConfig
|
||||
{
|
||||
PikaOperationSettings parent_instance;
|
||||
|
||||
PikaTRCType trc;
|
||||
|
||||
PikaHistogramChannel channel;
|
||||
|
||||
gdouble low_input[5];
|
||||
gdouble high_input[5];
|
||||
|
||||
gboolean clamp_input;
|
||||
|
||||
gdouble gamma[5];
|
||||
|
||||
gdouble low_output[5];
|
||||
gdouble high_output[5];
|
||||
|
||||
gboolean clamp_output;
|
||||
};
|
||||
|
||||
struct _PikaLevelsConfigClass
|
||||
{
|
||||
PikaOperationSettingsClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType pika_levels_config_get_type (void) G_GNUC_CONST;
|
||||
|
||||
void pika_levels_config_reset_channel (PikaLevelsConfig *config);
|
||||
|
||||
void pika_levels_config_stretch (PikaLevelsConfig *config,
|
||||
PikaHistogram *histogram,
|
||||
gboolean is_color);
|
||||
void pika_levels_config_stretch_channel (PikaLevelsConfig *config,
|
||||
PikaHistogram *histogram,
|
||||
PikaHistogramChannel channel);
|
||||
void pika_levels_config_adjust_by_colors (PikaLevelsConfig *config,
|
||||
PikaHistogramChannel channel,
|
||||
const PikaRGB *black,
|
||||
const PikaRGB *gray,
|
||||
const PikaRGB *white);
|
||||
|
||||
PikaCurvesConfig *
|
||||
pika_levels_config_to_curves_config (PikaLevelsConfig *config);
|
||||
|
||||
gboolean pika_levels_config_load_cruft (PikaLevelsConfig *config,
|
||||
GInputStream *input,
|
||||
GError **error);
|
||||
gboolean pika_levels_config_save_cruft (PikaLevelsConfig *config,
|
||||
GOutputStream *output,
|
||||
GError **error);
|
||||
|
||||
|
||||
#endif /* __PIKA_LEVELS_CONFIG_H__ */
|
||||
752
app/operations/pikaoperationborder.c
Normal file
752
app/operations/pikaoperationborder.c
Normal file
@ -0,0 +1,752 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationborder.c
|
||||
* Copyright (C) 2012 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* 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.h>
|
||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||
|
||||
#include "libpikacolor/pikacolor.h"
|
||||
#include "libpikamath/pikamath.h"
|
||||
|
||||
#include "operations-types.h"
|
||||
|
||||
#include "pikaoperationborder.h"
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_RADIUS_X,
|
||||
PROP_RADIUS_Y,
|
||||
PROP_FEATHER,
|
||||
PROP_EDGE_LOCK
|
||||
};
|
||||
|
||||
|
||||
static void pika_operation_border_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void pika_operation_border_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec);
|
||||
|
||||
static GeglRectangle
|
||||
pika_operation_border_get_required_for_output (GeglOperation *self,
|
||||
const gchar *input_pad,
|
||||
const GeglRectangle *roi);
|
||||
static GeglRectangle
|
||||
pika_operation_border_get_cached_region (GeglOperation *self,
|
||||
const GeglRectangle *roi);
|
||||
static void pika_operation_border_prepare (GeglOperation *operation);
|
||||
static gboolean pika_operation_border_process (GeglOperation *operation,
|
||||
GeglBuffer *input,
|
||||
GeglBuffer *output,
|
||||
const GeglRectangle *roi,
|
||||
gint level);
|
||||
|
||||
|
||||
G_DEFINE_TYPE (PikaOperationBorder, pika_operation_border,
|
||||
GEGL_TYPE_OPERATION_FILTER)
|
||||
|
||||
#define parent_class pika_operation_border_parent_class
|
||||
|
||||
|
||||
static void
|
||||
pika_operation_border_class_init (PikaOperationBorderClass *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->set_property = pika_operation_border_set_property;
|
||||
object_class->get_property = pika_operation_border_get_property;
|
||||
|
||||
gegl_operation_class_set_keys (operation_class,
|
||||
"name", "pika:border",
|
||||
"categories", "pika",
|
||||
"description", "PIKA Border operation",
|
||||
NULL);
|
||||
|
||||
operation_class->prepare = pika_operation_border_prepare;
|
||||
operation_class->get_required_for_output = pika_operation_border_get_required_for_output;
|
||||
operation_class->get_cached_region = pika_operation_border_get_cached_region;
|
||||
operation_class->threaded = FALSE;
|
||||
|
||||
filter_class->process = pika_operation_border_process;
|
||||
|
||||
g_object_class_install_property (object_class, PROP_RADIUS_X,
|
||||
g_param_spec_int ("radius-x",
|
||||
"Radius X",
|
||||
"Border radius in X diection",
|
||||
1, 2342, 1,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_RADIUS_Y,
|
||||
g_param_spec_int ("radius-y",
|
||||
"Radius Y",
|
||||
"Border radius in Y diection",
|
||||
1, 2342, 1,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_FEATHER,
|
||||
g_param_spec_boolean ("feather",
|
||||
"Feather",
|
||||
"Feather the border",
|
||||
FALSE,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_EDGE_LOCK,
|
||||
g_param_spec_boolean ("edge-lock",
|
||||
"Edge Lock",
|
||||
"Shrink from border",
|
||||
FALSE,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT));
|
||||
}
|
||||
|
||||
static void
|
||||
pika_operation_border_init (PikaOperationBorder *self)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
pika_operation_border_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaOperationBorder *self = PIKA_OPERATION_BORDER (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_RADIUS_X:
|
||||
g_value_set_int (value, self->radius_x);
|
||||
break;
|
||||
|
||||
case PROP_RADIUS_Y:
|
||||
g_value_set_int (value, self->radius_y);
|
||||
break;
|
||||
|
||||
case PROP_FEATHER:
|
||||
g_value_set_boolean (value, self->feather);
|
||||
break;
|
||||
|
||||
case PROP_EDGE_LOCK:
|
||||
g_value_set_boolean (value, self->edge_lock);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_operation_border_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaOperationBorder *self = PIKA_OPERATION_BORDER (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_RADIUS_X:
|
||||
self->radius_x = g_value_get_int (value);
|
||||
break;
|
||||
|
||||
case PROP_RADIUS_Y:
|
||||
self->radius_y = g_value_get_int (value);
|
||||
break;
|
||||
|
||||
case PROP_FEATHER:
|
||||
self->feather = g_value_get_boolean (value);
|
||||
break;
|
||||
|
||||
case PROP_EDGE_LOCK:
|
||||
self->edge_lock = g_value_get_boolean (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_operation_border_prepare (GeglOperation *operation)
|
||||
{
|
||||
const Babl *space = gegl_operation_get_source_space (operation, "input");
|
||||
gegl_operation_set_format (operation, "input", babl_format_with_space ("Y float", space));
|
||||
gegl_operation_set_format (operation, "output", babl_format_with_space ("Y float", space));
|
||||
}
|
||||
|
||||
static GeglRectangle
|
||||
pika_operation_border_get_required_for_output (GeglOperation *self,
|
||||
const gchar *input_pad,
|
||||
const GeglRectangle *roi)
|
||||
{
|
||||
return *gegl_operation_source_get_bounding_box (self, "input");
|
||||
}
|
||||
|
||||
static GeglRectangle
|
||||
pika_operation_border_get_cached_region (GeglOperation *self,
|
||||
const GeglRectangle *roi)
|
||||
{
|
||||
return *gegl_operation_source_get_bounding_box (self, "input");
|
||||
}
|
||||
|
||||
static inline void
|
||||
rotate_pointers (gfloat **p,
|
||||
guint32 n)
|
||||
{
|
||||
guint32 i;
|
||||
gfloat *tmp;
|
||||
|
||||
tmp = p[0];
|
||||
|
||||
for (i = 0; i < n - 1; i++)
|
||||
p[i] = p[i + 1];
|
||||
|
||||
p[i] = tmp;
|
||||
}
|
||||
|
||||
/* Computes whether pixels in `buf[1]', if they are selected, have neighbouring
|
||||
pixels that are unselected. Put result in `transition'. */
|
||||
static void
|
||||
compute_transition (gfloat *transition,
|
||||
gfloat **buf,
|
||||
gint32 width,
|
||||
gboolean edge_lock)
|
||||
{
|
||||
register gint32 x = 0;
|
||||
|
||||
if (width == 1)
|
||||
{
|
||||
if (buf[1][0] >= 0.5 && (buf[0][0] < 0.5 || buf[2][0] < 0.5))
|
||||
transition[0] = 1.0;
|
||||
else
|
||||
transition[0] = 0.0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (buf[1][0] >= 0.5 && edge_lock)
|
||||
{
|
||||
/* The pixel to the left (outside of the canvas) is considered selected,
|
||||
so we check if there are any unselected pixels in neighbouring pixels
|
||||
_on_ the canvas. */
|
||||
if (buf[0][x] < 0.5 || buf[0][x + 1] < 0.5 ||
|
||||
buf[1][x + 1] < 0.5 ||
|
||||
buf[2][x] < 0.5 || buf[2][x + 1] < 0.5 )
|
||||
{
|
||||
transition[x] = 1.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
transition[x] = 0.0;
|
||||
}
|
||||
}
|
||||
else if (buf[1][0] >= 0.5 && !edge_lock)
|
||||
{
|
||||
/* We must not care about neighbouring pixels on the image canvas since
|
||||
there always are unselected pixels to the left (which is outside of
|
||||
the image canvas). */
|
||||
transition[x] = 1.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
transition[x] = 0.0;
|
||||
}
|
||||
|
||||
for (x = 1; x < width - 1; x++)
|
||||
{
|
||||
if (buf[1][x] >= 0.5)
|
||||
{
|
||||
if (buf[0][x - 1] < 0.5 || buf[0][x] < 0.5 || buf[0][x + 1] < 0.5 ||
|
||||
buf[1][x - 1] < 0.5 || buf[1][x + 1] < 0.5 ||
|
||||
buf[2][x - 1] < 0.5 || buf[2][x] < 0.5 || buf[2][x + 1] < 0.5)
|
||||
transition[x] = 1.0;
|
||||
else
|
||||
transition[x] = 0.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
transition[x] = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
if (buf[1][width - 1] >= 0.5 && edge_lock)
|
||||
{
|
||||
/* The pixel to the right (outside of the canvas) is considered selected,
|
||||
so we check if there are any unselected pixels in neighbouring pixels
|
||||
_on_ the canvas. */
|
||||
if ( buf[0][x - 1] < 0.5 || buf[0][x] < 0.5 ||
|
||||
buf[1][x - 1] < 0.5 ||
|
||||
buf[2][x - 1] < 0.5 || buf[2][x] < 0.5)
|
||||
{
|
||||
transition[width - 1] = 1.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
transition[width - 1] = 0.0;
|
||||
}
|
||||
}
|
||||
else if (buf[1][width - 1] >= 0.5 && !edge_lock)
|
||||
{
|
||||
/* We must not care about neighbouring pixels on the image canvas since
|
||||
there always are unselected pixels to the right (which is outside of
|
||||
the image canvas). */
|
||||
transition[width - 1] = 1.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
transition[width - 1] = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_operation_border_process (GeglOperation *operation,
|
||||
GeglBuffer *input,
|
||||
GeglBuffer *output,
|
||||
const GeglRectangle *roi,
|
||||
gint level)
|
||||
{
|
||||
/* This function has no bugs, but if you imagine some you can blame
|
||||
* them on jaycox@gimp.org
|
||||
*/
|
||||
PikaOperationBorder *self = PIKA_OPERATION_BORDER (operation);
|
||||
const Babl *input_format = gegl_operation_get_format (operation, "input");
|
||||
const Babl *output_format = gegl_operation_get_format (operation, "output");
|
||||
|
||||
gint32 i, j, x, y;
|
||||
|
||||
/* A cache used in the algorithm as it works its way down. `buf[1]' is the
|
||||
current row. Thus, at algorithm initialization, `buf[0]' represents the
|
||||
row 'above' the first row of the region. */
|
||||
gfloat *buf[3];
|
||||
|
||||
/* The resulting selection is calculated row by row, and this buffer holds the
|
||||
output for each individual row, on each iteration. */
|
||||
gfloat *out;
|
||||
|
||||
/* Keeps track of transitional pixels (pixels that are selected and have
|
||||
unselected neighbouring pixels). */
|
||||
gfloat **transition;
|
||||
|
||||
/* TODO: Figure out role clearly in algorithm. */
|
||||
gint16 *max;
|
||||
|
||||
/* TODO: Figure out role clearly in algorithm. */
|
||||
gfloat **density;
|
||||
|
||||
gint16 last_index;
|
||||
|
||||
/* optimize this case specifically */
|
||||
if (self->radius_x == 1 && self->radius_y == 1)
|
||||
{
|
||||
gfloat *transition;
|
||||
gfloat *source[3];
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
source[i] = g_new (gfloat, roi->width);
|
||||
|
||||
transition = g_new (gfloat, roi->width);
|
||||
|
||||
/* With `self->edge_lock', initialize row above image as
|
||||
* selected, otherwise, initialize as unselected.
|
||||
*/
|
||||
if (self->edge_lock)
|
||||
{
|
||||
for (i = 0; i < roi->width; i++)
|
||||
source[0][i] = 1.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
memset (source[0], 0, roi->width * sizeof (gfloat));
|
||||
}
|
||||
|
||||
gegl_buffer_get (input,
|
||||
GEGL_RECTANGLE (roi->x, roi->y + 0,
|
||||
roi->width, 1),
|
||||
1.0, input_format, source[1],
|
||||
GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
|
||||
|
||||
if (roi->height > 1)
|
||||
gegl_buffer_get (input,
|
||||
GEGL_RECTANGLE (roi->x, roi->y + 1,
|
||||
roi->width, 1),
|
||||
1.0, input_format, source[2],
|
||||
GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
|
||||
else
|
||||
memcpy (source[2], source[1], roi->width * sizeof (gfloat));
|
||||
|
||||
compute_transition (transition, source, roi->width, self->edge_lock);
|
||||
gegl_buffer_set (output,
|
||||
GEGL_RECTANGLE (roi->x, roi->y,
|
||||
roi->width, 1),
|
||||
0, output_format, transition,
|
||||
GEGL_AUTO_ROWSTRIDE);
|
||||
|
||||
for (y = 1; y < roi->height; y++)
|
||||
{
|
||||
rotate_pointers (source, 3);
|
||||
|
||||
if (y + 1 < roi->height)
|
||||
{
|
||||
gegl_buffer_get (input,
|
||||
GEGL_RECTANGLE (roi->x, roi->y + y + 1,
|
||||
roi->width, 1),
|
||||
1.0, input_format, source[2],
|
||||
GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Depending on `self->edge_lock', set the row below the
|
||||
* image as either selected or non-selected.
|
||||
*/
|
||||
if (self->edge_lock)
|
||||
{
|
||||
for (i = 0; i < roi->width; i++)
|
||||
source[2][i] = 1.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
memset (source[2], 0, roi->width * sizeof (gfloat));
|
||||
}
|
||||
}
|
||||
|
||||
compute_transition (transition, source, roi->width, self->edge_lock);
|
||||
gegl_buffer_set (output,
|
||||
GEGL_RECTANGLE (roi->x, roi->y + y,
|
||||
roi->width, 1),
|
||||
0, output_format, transition,
|
||||
GEGL_AUTO_ROWSTRIDE);
|
||||
}
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
g_free (source[i]);
|
||||
|
||||
g_free (transition);
|
||||
|
||||
/* Finished handling the radius = 1 special case, return here. */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
max = g_new (gint16, roi->width + 2 * self->radius_x);
|
||||
|
||||
for (i = 0; i < (roi->width + 2 * self->radius_x); i++)
|
||||
max[i] = self->radius_y + 2;
|
||||
|
||||
max += self->radius_x;
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
buf[i] = g_new (gfloat, roi->width);
|
||||
|
||||
transition = g_new (gfloat *, self->radius_y + 1);
|
||||
|
||||
for (i = 0; i < self->radius_y + 1; i++)
|
||||
{
|
||||
transition[i] = g_new (gfloat, roi->width + 2 * self->radius_x);
|
||||
memset (transition[i], 0,
|
||||
(roi->width + 2 * self->radius_x) * sizeof (gfloat));
|
||||
transition[i] += self->radius_x;
|
||||
}
|
||||
|
||||
out = g_new (gfloat, roi->width);
|
||||
|
||||
density = g_new (gfloat *, 2 * self->radius_x + 1);
|
||||
density += self->radius_x;
|
||||
|
||||
/* allocate density[][] */
|
||||
for (x = 0; x < (self->radius_x + 1); x++)
|
||||
{
|
||||
density[ x] = g_new (gfloat, 2 * self->radius_y + 1);
|
||||
density[ x] += self->radius_y;
|
||||
density[-x] = density[x];
|
||||
}
|
||||
|
||||
/* compute density[][] */
|
||||
for (x = 0; x < (self->radius_x + 1); x++)
|
||||
{
|
||||
gdouble tmpx, tmpy, dist;
|
||||
gfloat a;
|
||||
|
||||
if (x > 0)
|
||||
tmpx = x - 0.5;
|
||||
else if (x < 0)
|
||||
tmpx = x + 0.5;
|
||||
else
|
||||
tmpx = 0.0;
|
||||
|
||||
for (y = 0; y < (self->radius_y + 1); y++)
|
||||
{
|
||||
if (y > 0)
|
||||
tmpy = y - 0.5;
|
||||
else if (y < 0)
|
||||
tmpy = y + 0.5;
|
||||
else
|
||||
tmpy = 0.0;
|
||||
|
||||
dist = ((tmpy * tmpy) / (self->radius_y * self->radius_y) +
|
||||
(tmpx * tmpx) / (self->radius_x * self->radius_x));
|
||||
|
||||
if (dist < 1.0)
|
||||
{
|
||||
if (self->feather)
|
||||
a = 1.0 - sqrt (dist);
|
||||
else
|
||||
a = 1.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
a = 0.0;
|
||||
}
|
||||
|
||||
density[ x][ y] = a;
|
||||
density[ x][-y] = a;
|
||||
density[-x][ y] = a;
|
||||
density[-x][-y] = a;
|
||||
}
|
||||
}
|
||||
|
||||
/* Since the algorithm considerers `buf[0]' to be 'over' the row
|
||||
* currently calculated, we must start with `buf[0]' as non-selected
|
||||
* if there is no `self->edge_lock. If there is an
|
||||
* 'self->edge_lock', initialize the first row to 'selected'. Refer
|
||||
* to bug #350009.
|
||||
*/
|
||||
if (self->edge_lock)
|
||||
{
|
||||
for (i = 0; i < roi->width; i++)
|
||||
buf[0][i] = 1.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
memset (buf[0], 0, roi->width * sizeof (gfloat));
|
||||
}
|
||||
|
||||
gegl_buffer_get (input,
|
||||
GEGL_RECTANGLE (roi->x, roi->y + 0,
|
||||
roi->width, 1),
|
||||
1.0, input_format, buf[1],
|
||||
GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
|
||||
|
||||
if (roi->height > 1)
|
||||
gegl_buffer_get (input,
|
||||
GEGL_RECTANGLE (roi->x, roi->y + 1,
|
||||
roi->width, 1),
|
||||
1.0, input_format, buf[2],
|
||||
GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
|
||||
else
|
||||
memcpy (buf[2], buf[1], roi->width * sizeof (gfloat));
|
||||
|
||||
compute_transition (transition[1], buf, roi->width, self->edge_lock);
|
||||
|
||||
/* set up top of image */
|
||||
for (y = 1; y < self->radius_y && y + 1 < roi->height; y++)
|
||||
{
|
||||
rotate_pointers (buf, 3);
|
||||
gegl_buffer_get (input,
|
||||
GEGL_RECTANGLE (roi->x, roi->y + y + 1,
|
||||
roi->width, 1),
|
||||
1.0, input_format, buf[2],
|
||||
GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
|
||||
compute_transition (transition[y + 1], buf, roi->width, self->edge_lock);
|
||||
}
|
||||
|
||||
/* set up max[] for top of image */
|
||||
for (x = 0; x < roi->width; x++)
|
||||
{
|
||||
max[x] = -(self->radius_y + 7);
|
||||
|
||||
for (j = 1; j < self->radius_y + 1; j++)
|
||||
if (transition[j][x])
|
||||
{
|
||||
max[x] = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* main calculation loop */
|
||||
for (y = 0; y < roi->height; y++)
|
||||
{
|
||||
rotate_pointers (buf, 3);
|
||||
rotate_pointers (transition, self->radius_y + 1);
|
||||
|
||||
if (y < roi->height - (self->radius_y + 1))
|
||||
{
|
||||
gegl_buffer_get (input,
|
||||
GEGL_RECTANGLE (roi->x,
|
||||
roi->y + y + self->radius_y + 1,
|
||||
roi->width, 1),
|
||||
1.0, input_format, buf[2],
|
||||
GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
|
||||
compute_transition (transition[self->radius_y], buf, roi->width, self->edge_lock);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (self->edge_lock)
|
||||
{
|
||||
memcpy (transition[self->radius_y], transition[self->radius_y - 1], roi->width * sizeof (gfloat));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No edge lock, set everything 'below canvas' as seen
|
||||
* from the algorithm as unselected.
|
||||
*/
|
||||
memset (buf[2], 0, roi->width * sizeof (gfloat));
|
||||
compute_transition (transition[self->radius_y], buf, roi->width, self->edge_lock);
|
||||
}
|
||||
}
|
||||
|
||||
/* update max array */
|
||||
for (x = 0; x < roi->width; x++)
|
||||
{
|
||||
if (max[x] < 1)
|
||||
{
|
||||
if (max[x] <= -self->radius_y)
|
||||
{
|
||||
if (transition[self->radius_y][x])
|
||||
max[x] = self->radius_y;
|
||||
else
|
||||
max[x]--;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (transition[-max[x]][x])
|
||||
max[x] = -max[x];
|
||||
else if (transition[-max[x] + 1][x])
|
||||
max[x] = -max[x] + 1;
|
||||
else
|
||||
max[x]--;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
max[x]--;
|
||||
}
|
||||
|
||||
if (max[x] < -self->radius_y - 1)
|
||||
max[x] = -self->radius_y - 1;
|
||||
}
|
||||
|
||||
last_index = 1;
|
||||
|
||||
/* render scan line */
|
||||
for (x = 0 ; x < roi->width; x++)
|
||||
{
|
||||
gfloat last_max;
|
||||
|
||||
last_index--;
|
||||
|
||||
if (last_index >= 0)
|
||||
{
|
||||
last_max = 0.0;
|
||||
|
||||
for (i = self->radius_x; i >= 0; i--)
|
||||
if (max[x + i] <= self->radius_y && max[x + i] >= -self->radius_y &&
|
||||
density[i][max[x+i]] > last_max)
|
||||
{
|
||||
last_max = density[i][max[x + i]];
|
||||
last_index = i;
|
||||
}
|
||||
|
||||
out[x] = last_max;
|
||||
}
|
||||
else
|
||||
{
|
||||
last_max = 0.0;
|
||||
|
||||
for (i = self->radius_x; i >= -self->radius_x; i--)
|
||||
if (max[x + i] <= self->radius_y && max[x + i] >= -self->radius_y &&
|
||||
density[i][max[x + i]] > last_max)
|
||||
{
|
||||
last_max = density[i][max[x + i]];
|
||||
last_index = i;
|
||||
}
|
||||
|
||||
out[x] = last_max;
|
||||
}
|
||||
|
||||
if (last_max <= 0.0)
|
||||
{
|
||||
for (i = x + 1; i < roi->width; i++)
|
||||
{
|
||||
if (max[i] >= -self->radius_y)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i - x > self->radius_x)
|
||||
{
|
||||
for (; x < i - self->radius_x; x++)
|
||||
out[x] = 0;
|
||||
|
||||
x--;
|
||||
}
|
||||
|
||||
last_index = self->radius_x;
|
||||
}
|
||||
}
|
||||
|
||||
gegl_buffer_set (output,
|
||||
GEGL_RECTANGLE (roi->x, roi->y + y,
|
||||
roi->width, 1),
|
||||
0, output_format, out,
|
||||
GEGL_AUTO_ROWSTRIDE);
|
||||
}
|
||||
|
||||
g_free (out);
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
g_free (buf[i]);
|
||||
|
||||
max -= self->radius_x;
|
||||
g_free (max);
|
||||
|
||||
for (i = 0; i < self->radius_y + 1; i++)
|
||||
{
|
||||
transition[i] -= self->radius_x;
|
||||
g_free (transition[i]);
|
||||
}
|
||||
|
||||
g_free (transition);
|
||||
|
||||
for (i = 0; i < self->radius_x + 1 ; i++)
|
||||
{
|
||||
density[i] -= self->radius_y;
|
||||
g_free (density[i]);
|
||||
}
|
||||
|
||||
density -= self->radius_x;
|
||||
g_free (density);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
62
app/operations/pikaoperationborder.h
Normal file
62
app/operations/pikaoperationborder.h
Normal file
@ -0,0 +1,62 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationborder.h
|
||||
* Copyright (C) 2012 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* 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 __PIKA_OPERATION_BORDER_H__
|
||||
#define __PIKA_OPERATION_BORDER_H__
|
||||
|
||||
|
||||
#include <gegl-plugin.h>
|
||||
|
||||
|
||||
#define PIKA_TYPE_OPERATION_BORDER (pika_operation_border_get_type ())
|
||||
#define PIKA_OPERATION_BORDER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_OPERATION_BORDER, PikaOperationBorder))
|
||||
#define PIKA_OPERATION_BORDER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_OPERATION_BORDER, PikaOperationBorderClass))
|
||||
#define PIKA_IS_OPERATION_BORDER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_OPERATION_BORDER))
|
||||
#define PIKA_IS_OPERATION_BORDER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_OPERATION_BORDER))
|
||||
#define PIKA_OPERATION_BORDER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_OPERATION_BORDER, PikaOperationBorderClass))
|
||||
|
||||
|
||||
typedef struct _PikaOperationBorder PikaOperationBorder;
|
||||
typedef struct _PikaOperationBorderClass PikaOperationBorderClass;
|
||||
|
||||
struct _PikaOperationBorder
|
||||
{
|
||||
GeglOperationFilter parent_instance;
|
||||
|
||||
gint radius_x;
|
||||
gint radius_y;
|
||||
gboolean feather;
|
||||
gboolean edge_lock;
|
||||
};
|
||||
|
||||
struct _PikaOperationBorderClass
|
||||
{
|
||||
GeglOperationFilterClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType pika_operation_border_get_type (void) G_GNUC_CONST;
|
||||
|
||||
|
||||
#endif /* __PIKA_OPERATION_BORDER_H__ */
|
||||
144
app/operations/pikaoperationbrightnesscontrast.c
Normal file
144
app/operations/pikaoperationbrightnesscontrast.c
Normal file
@ -0,0 +1,144 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationbrightnesscontrast.c
|
||||
* Copyright (C) 2012 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* 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.h>
|
||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||
|
||||
#include "libpikacolor/pikacolor.h"
|
||||
#include "libpikamath/pikamath.h"
|
||||
|
||||
#include "operations-types.h"
|
||||
|
||||
#include "pikabrightnesscontrastconfig.h"
|
||||
#include "pikaoperationbrightnesscontrast.h"
|
||||
|
||||
#include "pika-intl.h"
|
||||
|
||||
|
||||
static gboolean pika_operation_brightness_contrast_process (GeglOperation *operation,
|
||||
void *in_buf,
|
||||
void *out_buf,
|
||||
glong samples,
|
||||
const GeglRectangle *roi,
|
||||
gint level);
|
||||
|
||||
|
||||
G_DEFINE_TYPE (PikaOperationBrightnessContrast, pika_operation_brightness_contrast,
|
||||
PIKA_TYPE_OPERATION_POINT_FILTER)
|
||||
|
||||
#define parent_class pika_operation_brightness_contrast_parent_class
|
||||
|
||||
|
||||
static void
|
||||
pika_operation_brightness_contrast_class_init (PikaOperationBrightnessContrastClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass);
|
||||
GeglOperationPointFilterClass *point_class = GEGL_OPERATION_POINT_FILTER_CLASS (klass);
|
||||
|
||||
object_class->set_property = pika_operation_point_filter_set_property;
|
||||
object_class->get_property = pika_operation_point_filter_get_property;
|
||||
|
||||
gegl_operation_class_set_keys (operation_class,
|
||||
"name", "pika:brightness-contrast",
|
||||
"categories", "color",
|
||||
"description", _("Adjust brightness and contrast"),
|
||||
NULL);
|
||||
|
||||
point_class->process = pika_operation_brightness_contrast_process;
|
||||
|
||||
g_object_class_install_property (object_class,
|
||||
PIKA_OPERATION_POINT_FILTER_PROP_CONFIG,
|
||||
g_param_spec_object ("config",
|
||||
"Config",
|
||||
"The config object",
|
||||
PIKA_TYPE_BRIGHTNESS_CONTRAST_CONFIG,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT));
|
||||
}
|
||||
|
||||
static void
|
||||
pika_operation_brightness_contrast_init (PikaOperationBrightnessContrast *self)
|
||||
{
|
||||
}
|
||||
|
||||
static inline gfloat
|
||||
pika_operation_brightness_contrast_map (gfloat value,
|
||||
gdouble brightness,
|
||||
gdouble slant)
|
||||
{
|
||||
/* apply brightness */
|
||||
if (brightness < 0.0)
|
||||
value = value * (1.0 + brightness);
|
||||
else
|
||||
value = value + ((1.0 - value) * brightness);
|
||||
|
||||
value = (value - 0.5) * slant + 0.5;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_operation_brightness_contrast_process (GeglOperation *operation,
|
||||
void *in_buf,
|
||||
void *out_buf,
|
||||
glong samples,
|
||||
const GeglRectangle *roi,
|
||||
gint level)
|
||||
{
|
||||
PikaOperationPointFilter *point = PIKA_OPERATION_POINT_FILTER (operation);
|
||||
PikaBrightnessContrastConfig *config = PIKA_BRIGHTNESS_CONTRAST_CONFIG (point->config);
|
||||
gfloat *src = in_buf;
|
||||
gfloat *dest = out_buf;
|
||||
gdouble brightness;
|
||||
gdouble slant;
|
||||
|
||||
if (! config)
|
||||
return FALSE;
|
||||
|
||||
brightness = config->brightness / 2.0;
|
||||
slant = tan ((config->contrast + 1) * G_PI_4);
|
||||
|
||||
while (samples--)
|
||||
{
|
||||
dest[RED] = pika_operation_brightness_contrast_map (src[RED],
|
||||
brightness,
|
||||
slant);
|
||||
dest[GREEN] = pika_operation_brightness_contrast_map (src[GREEN],
|
||||
brightness,
|
||||
slant);
|
||||
dest[BLUE] = pika_operation_brightness_contrast_map (src[BLUE],
|
||||
brightness,
|
||||
slant);
|
||||
dest[ALPHA] = src[ALPHA];
|
||||
|
||||
src += 4;
|
||||
dest += 4;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
57
app/operations/pikaoperationbrightnesscontrast.h
Normal file
57
app/operations/pikaoperationbrightnesscontrast.h
Normal file
@ -0,0 +1,57 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationbrightnesscontrast.h
|
||||
* Copyright (C) 2012 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* 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 __PIKA_OPERATION_BRIGHTNESS_CONTRAST_H__
|
||||
#define __PIKA_OPERATION_BRIGHTNESS_CONTRAST_H__
|
||||
|
||||
|
||||
#include "pikaoperationpointfilter.h"
|
||||
|
||||
|
||||
#define PIKA_TYPE_OPERATION_BRIGHTNESS_CONTRAST (pika_operation_brightness_contrast_get_type ())
|
||||
#define PIKA_OPERATION_BRIGHTNESS_CONTRAST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_OPERATION_BRIGHTNESS_CONTRAST, PikaOperationBrightnessContrast))
|
||||
#define PIKA_OPERATION_BRIGHTNESS_CONTRAST_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_OPERATION_BRIGHTNESS_CONTRAST, PikaOperationBrightnessContrastClass))
|
||||
#define PIKA_IS_OPERATION_BRIGHTNESS_CONTRAST(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_OPERATION_BRIGHTNESS_CONTRAST))
|
||||
#define PIKA_IS_OPERATION_BRIGHTNESS_CONTRAST_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_OPERATION_BRIGHTNESS_CONTRAST))
|
||||
#define PIKA_OPERATION_BRIGHTNESS_CONTRAST_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_OPERATION_BRIGHTNESS_CONTRAST, PikaOperationBrightnessContrastClass))
|
||||
|
||||
|
||||
typedef struct _PikaOperationBrightnessContrast PikaOperationBrightnessContrast;
|
||||
typedef struct _PikaOperationBrightnessContrastClass PikaOperationBrightnessContrastClass;
|
||||
|
||||
struct _PikaOperationBrightnessContrast
|
||||
{
|
||||
PikaOperationPointFilter parent_instance;
|
||||
};
|
||||
|
||||
struct _PikaOperationBrightnessContrastClass
|
||||
{
|
||||
PikaOperationPointFilterClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType pika_operation_brightness_contrast_get_type (void) G_GNUC_CONST;
|
||||
|
||||
|
||||
#endif /* __PIKA_OPERATION_BRIGHTNESS_CONTRAST_H__ */
|
||||
311
app/operations/pikaoperationbuffersourcevalidate.c
Normal file
311
app/operations/pikaoperationbuffersourcevalidate.c
Normal file
@ -0,0 +1,311 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationbuffersourcevalidate.c
|
||||
* Copyright (C) 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 <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/pikatilehandlervalidate.h"
|
||||
|
||||
#include "pikaoperationbuffersourcevalidate.h"
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_BUFFER
|
||||
};
|
||||
|
||||
|
||||
static void pika_operation_buffer_source_validate_dispose (GObject *object);
|
||||
static void pika_operation_buffer_source_validate_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void pika_operation_buffer_source_validate_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec);
|
||||
|
||||
static GeglRectangle pika_operation_buffer_source_validate_get_bounding_box (GeglOperation *operation);
|
||||
static void pika_operation_buffer_source_validate_prepare (GeglOperation *operation);
|
||||
static gboolean pika_operation_buffer_source_validate_process (GeglOperation *operation,
|
||||
GeglOperationContext *context,
|
||||
const gchar *output_pad,
|
||||
const GeglRectangle *result,
|
||||
gint level);
|
||||
|
||||
static void pika_operation_buffer_source_validate_invalidate (gpointer object,
|
||||
const GeglRectangle *rect,
|
||||
PikaOperationBufferSourceValidate *buffer_source_validate);
|
||||
|
||||
|
||||
G_DEFINE_TYPE (PikaOperationBufferSourceValidate, pika_operation_buffer_source_validate,
|
||||
GEGL_TYPE_OPERATION_SOURCE)
|
||||
|
||||
#define parent_class pika_operation_buffer_source_validate_parent_class
|
||||
|
||||
|
||||
static void
|
||||
pika_operation_buffer_source_validate_class_init (PikaOperationBufferSourceValidateClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass);
|
||||
|
||||
object_class->dispose = pika_operation_buffer_source_validate_dispose;
|
||||
object_class->set_property = pika_operation_buffer_source_validate_set_property;
|
||||
object_class->get_property = pika_operation_buffer_source_validate_get_property;
|
||||
|
||||
operation_class->get_bounding_box = pika_operation_buffer_source_validate_get_bounding_box;
|
||||
operation_class->prepare = pika_operation_buffer_source_validate_prepare;
|
||||
operation_class->process = pika_operation_buffer_source_validate_process;
|
||||
|
||||
operation_class->threaded = FALSE;
|
||||
operation_class->cache_policy = GEGL_CACHE_POLICY_NEVER;
|
||||
|
||||
gegl_operation_class_set_keys (operation_class,
|
||||
"name", "pika:buffer-source-validate",
|
||||
"categories", "pika",
|
||||
"description", "PIKA Buffer-Source Validate operation",
|
||||
NULL);
|
||||
|
||||
g_object_class_install_property (object_class, PROP_BUFFER,
|
||||
g_param_spec_object ("buffer",
|
||||
"Buffer",
|
||||
"Input buffer",
|
||||
GEGL_TYPE_BUFFER,
|
||||
G_PARAM_READWRITE));
|
||||
}
|
||||
|
||||
static void
|
||||
pika_operation_buffer_source_validate_init (PikaOperationBufferSourceValidate *self)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
pika_operation_buffer_source_validate_dispose (GObject *object)
|
||||
{
|
||||
PikaOperationBufferSourceValidate *buffer_source_validate = PIKA_OPERATION_BUFFER_SOURCE_VALIDATE (object);
|
||||
|
||||
if (buffer_source_validate->buffer)
|
||||
{
|
||||
PikaTileHandlerValidate *validate_handler;
|
||||
|
||||
validate_handler = pika_tile_handler_validate_get_assigned (
|
||||
buffer_source_validate->buffer);
|
||||
|
||||
if (validate_handler)
|
||||
{
|
||||
g_signal_connect (
|
||||
validate_handler,
|
||||
"invalidated",
|
||||
G_CALLBACK (pika_operation_buffer_source_validate_invalidate),
|
||||
buffer_source_validate);
|
||||
}
|
||||
|
||||
g_signal_handlers_disconnect_by_func (
|
||||
buffer_source_validate->buffer,
|
||||
pika_operation_buffer_source_validate_invalidate,
|
||||
buffer_source_validate);
|
||||
|
||||
g_clear_object (&buffer_source_validate->buffer);
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_operation_buffer_source_validate_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaOperationBufferSourceValidate *buffer_source_validate = PIKA_OPERATION_BUFFER_SOURCE_VALIDATE (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_BUFFER:
|
||||
g_value_set_object (value, buffer_source_validate->buffer);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_operation_buffer_source_validate_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaOperationBufferSourceValidate *buffer_source_validate = PIKA_OPERATION_BUFFER_SOURCE_VALIDATE (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_BUFFER:
|
||||
{
|
||||
if (buffer_source_validate->buffer)
|
||||
{
|
||||
PikaTileHandlerValidate *validate_handler;
|
||||
|
||||
validate_handler = pika_tile_handler_validate_get_assigned (
|
||||
buffer_source_validate->buffer);
|
||||
|
||||
pika_operation_buffer_source_validate_invalidate (
|
||||
buffer_source_validate->buffer,
|
||||
gegl_buffer_get_extent (buffer_source_validate->buffer),
|
||||
buffer_source_validate);
|
||||
|
||||
g_signal_handlers_disconnect_by_func (
|
||||
buffer_source_validate->buffer,
|
||||
pika_operation_buffer_source_validate_invalidate,
|
||||
buffer_source_validate);
|
||||
|
||||
if (validate_handler)
|
||||
{
|
||||
g_signal_handlers_disconnect_by_func (
|
||||
validate_handler,
|
||||
pika_operation_buffer_source_validate_invalidate,
|
||||
buffer_source_validate);
|
||||
}
|
||||
|
||||
g_clear_object (&buffer_source_validate->buffer);
|
||||
}
|
||||
|
||||
buffer_source_validate->buffer = g_value_dup_object (value);
|
||||
|
||||
if (buffer_source_validate->buffer)
|
||||
{
|
||||
PikaTileHandlerValidate *validate_handler;
|
||||
|
||||
validate_handler = pika_tile_handler_validate_get_assigned (
|
||||
buffer_source_validate->buffer);
|
||||
|
||||
if (validate_handler)
|
||||
{
|
||||
g_signal_connect (
|
||||
validate_handler,
|
||||
"invalidated",
|
||||
G_CALLBACK (pika_operation_buffer_source_validate_invalidate),
|
||||
buffer_source_validate);
|
||||
}
|
||||
|
||||
gegl_buffer_signal_connect (
|
||||
buffer_source_validate->buffer,
|
||||
"changed",
|
||||
G_CALLBACK (pika_operation_buffer_source_validate_invalidate),
|
||||
buffer_source_validate);
|
||||
|
||||
pika_operation_buffer_source_validate_invalidate (
|
||||
buffer_source_validate->buffer,
|
||||
gegl_buffer_get_extent (buffer_source_validate->buffer),
|
||||
buffer_source_validate);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static GeglRectangle
|
||||
pika_operation_buffer_source_validate_get_bounding_box (GeglOperation *operation)
|
||||
{
|
||||
PikaOperationBufferSourceValidate *buffer_source_validate = PIKA_OPERATION_BUFFER_SOURCE_VALIDATE (operation);
|
||||
|
||||
GeglRectangle result = {};
|
||||
|
||||
if (buffer_source_validate->buffer)
|
||||
result = *gegl_buffer_get_extent (buffer_source_validate->buffer);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_operation_buffer_source_validate_prepare (GeglOperation *operation)
|
||||
{
|
||||
PikaOperationBufferSourceValidate *buffer_source_validate = PIKA_OPERATION_BUFFER_SOURCE_VALIDATE (operation);
|
||||
const Babl *format = NULL;
|
||||
|
||||
if (buffer_source_validate->buffer)
|
||||
format = gegl_buffer_get_format (buffer_source_validate->buffer);
|
||||
|
||||
gegl_operation_set_format (operation, "output", format);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_operation_buffer_source_validate_process (GeglOperation *operation,
|
||||
GeglOperationContext *context,
|
||||
const gchar *output_pad,
|
||||
const GeglRectangle *result,
|
||||
gint level)
|
||||
{
|
||||
PikaOperationBufferSourceValidate *buffer_source_validate = PIKA_OPERATION_BUFFER_SOURCE_VALIDATE (operation);
|
||||
GeglBuffer *buffer = buffer_source_validate->buffer;
|
||||
|
||||
if (buffer)
|
||||
{
|
||||
PikaTileHandlerValidate *validate_handler;
|
||||
|
||||
validate_handler = pika_tile_handler_validate_get_assigned (buffer);
|
||||
|
||||
if (validate_handler)
|
||||
{
|
||||
GeglRectangle rect;
|
||||
|
||||
/* align the rectangle to the tile grid */
|
||||
gegl_rectangle_align_to_buffer (
|
||||
&rect, result, buffer_source_validate->buffer,
|
||||
GEGL_RECTANGLE_ALIGNMENT_SUPERSET);
|
||||
|
||||
pika_tile_handler_validate_validate (validate_handler,
|
||||
buffer_source_validate->buffer,
|
||||
&rect,
|
||||
TRUE, FALSE);
|
||||
}
|
||||
|
||||
gegl_operation_context_set_object (context, "output", G_OBJECT (buffer));
|
||||
|
||||
gegl_object_set_has_forked (G_OBJECT (buffer));
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_operation_buffer_source_validate_invalidate (gpointer object,
|
||||
const GeglRectangle *rect,
|
||||
PikaOperationBufferSourceValidate *buffer_source_validate)
|
||||
{
|
||||
gegl_operation_invalidate (GEGL_OPERATION (buffer_source_validate),
|
||||
rect, FALSE);
|
||||
}
|
||||
56
app/operations/pikaoperationbuffersourcevalidate.h
Normal file
56
app/operations/pikaoperationbuffersourcevalidate.h
Normal file
@ -0,0 +1,56 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationbuffersourcevalidate.h
|
||||
* Copyright (C) 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_OPERATION_BUFFER_SOURCE_VALIDATE_H__
|
||||
#define __PIKA_OPERATION_BUFFER_SOURCE_VALIDATE_H__
|
||||
|
||||
|
||||
#define PIKA_TYPE_OPERATION_BUFFER_SOURCE_VALIDATE (pika_operation_buffer_source_validate_get_type ())
|
||||
#define PIKA_OPERATION_BUFFER_SOURCE_VALIDATE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_OPERATION_BUFFER_SOURCE_VALIDATE, PikaOperationBufferSourceValidate))
|
||||
#define PIKA_OPERATION_BUFFER_SOURCE_VALIDATE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_OPERATION_BUFFER_SOURCE_VALIDATE, PikaOperationBufferSourceValidateClass))
|
||||
#define PIKA_IS_OPERATION_BUFFER_SOURCE_VALIDATE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_OPERATION_BUFFER_SOURCE_VALIDATE))
|
||||
#define PIKA_IS_OPERATION_BUFFER_SOURCE_VALIDATE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_OPERATION_BUFFER_SOURCE_VALIDATE))
|
||||
#define PIKA_OPERATION_BUFFER_SOURCE_VALIDATE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_OPERATION_BUFFER_SOURCE_VALIDATE, PikaOperationBufferSourceValidateClass))
|
||||
|
||||
|
||||
typedef struct _PikaOperationBufferSourceValidate PikaOperationBufferSourceValidate;
|
||||
typedef struct _PikaOperationBufferSourceValidateClass PikaOperationBufferSourceValidateClass;
|
||||
|
||||
struct _PikaOperationBufferSourceValidate
|
||||
{
|
||||
GeglOperationSource parent_instance;
|
||||
|
||||
GeglBuffer *buffer;
|
||||
};
|
||||
|
||||
struct _PikaOperationBufferSourceValidateClass
|
||||
{
|
||||
GeglOperationSourceClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType pika_operation_buffer_source_validate_get_type (void) G_GNUC_CONST;
|
||||
|
||||
|
||||
#endif /* __PIKA_OPERATION_BUFFER_SOURCE_VALIDATE_H__ */
|
||||
298
app/operations/pikaoperationcagecoefcalc.c
Normal file
298
app/operations/pikaoperationcagecoefcalc.c
Normal file
@ -0,0 +1,298 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
*
|
||||
* pikaoperationcagecoefcalc.c
|
||||
* Copyright (C) 2010 Michael Muré <batolettre@gmail.com>
|
||||
*
|
||||
* 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 <gdk-pixbuf/gdk-pixbuf.h>
|
||||
#include <gegl.h>
|
||||
|
||||
#include "libpikamath/pikamath.h"
|
||||
|
||||
#include "operations-types.h"
|
||||
|
||||
#include "pikaoperationcagecoefcalc.h"
|
||||
#include "pikacageconfig.h"
|
||||
|
||||
#include "pika-intl.h"
|
||||
|
||||
|
||||
static void pika_operation_cage_coef_calc_finalize (GObject *object);
|
||||
static void pika_operation_cage_coef_calc_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void pika_operation_cage_coef_calc_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec);
|
||||
|
||||
static void pika_operation_cage_coef_calc_prepare (GeglOperation *operation);
|
||||
static GeglRectangle pika_operation_cage_coef_calc_get_bounding_box (GeglOperation *operation);
|
||||
static gboolean pika_operation_cage_coef_calc_process (GeglOperation *operation,
|
||||
GeglBuffer *output,
|
||||
const GeglRectangle *roi,
|
||||
gint level);
|
||||
|
||||
|
||||
G_DEFINE_TYPE (PikaOperationCageCoefCalc, pika_operation_cage_coef_calc,
|
||||
GEGL_TYPE_OPERATION_SOURCE)
|
||||
|
||||
#define parent_class pika_operation_cage_coef_calc_parent_class
|
||||
|
||||
|
||||
static void
|
||||
pika_operation_cage_coef_calc_class_init (PikaOperationCageCoefCalcClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
GeglOperationSourceClass *source_class = GEGL_OPERATION_SOURCE_CLASS (klass);
|
||||
GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass);
|
||||
|
||||
gegl_operation_class_set_keys (operation_class,
|
||||
"name", "pika:cage-coef-calc",
|
||||
"categories", "transform",
|
||||
"description", _("Compute a set of coefficient buffer for the PIKA cage tool"),
|
||||
NULL);
|
||||
|
||||
operation_class->prepare = pika_operation_cage_coef_calc_prepare;
|
||||
operation_class->get_bounding_box = pika_operation_cage_coef_calc_get_bounding_box;
|
||||
operation_class->cache_policy = GEGL_CACHE_POLICY_ALWAYS;
|
||||
operation_class->get_cached_region = NULL;
|
||||
|
||||
source_class->process = pika_operation_cage_coef_calc_process;
|
||||
|
||||
object_class->get_property = pika_operation_cage_coef_calc_get_property;
|
||||
object_class->set_property = pika_operation_cage_coef_calc_set_property;
|
||||
object_class->finalize = pika_operation_cage_coef_calc_finalize;
|
||||
|
||||
g_object_class_install_property (object_class,
|
||||
PIKA_OPERATION_CAGE_COEF_CALC_PROP_CONFIG,
|
||||
g_param_spec_object ("config",
|
||||
"Config",
|
||||
"A PikaCageConfig object, that define the transformation",
|
||||
PIKA_TYPE_CAGE_CONFIG,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT));
|
||||
}
|
||||
|
||||
static void
|
||||
pika_operation_cage_coef_calc_init (PikaOperationCageCoefCalc *self)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
pika_operation_cage_coef_calc_finalize (GObject *object)
|
||||
{
|
||||
PikaOperationCageCoefCalc *self = PIKA_OPERATION_CAGE_COEF_CALC (object);
|
||||
|
||||
g_clear_object (&self->config);
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_operation_cage_coef_calc_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaOperationCageCoefCalc *self = PIKA_OPERATION_CAGE_COEF_CALC (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PIKA_OPERATION_CAGE_COEF_CALC_PROP_CONFIG:
|
||||
g_value_set_object (value, self->config);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_operation_cage_coef_calc_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaOperationCageCoefCalc *self = PIKA_OPERATION_CAGE_COEF_CALC (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PIKA_OPERATION_CAGE_COEF_CALC_PROP_CONFIG:
|
||||
if (self->config)
|
||||
g_object_unref (self->config);
|
||||
self->config = g_value_dup_object (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_operation_cage_coef_calc_is_on_straight (PikaVector2 *d1,
|
||||
PikaVector2 *d2,
|
||||
PikaVector2 *p)
|
||||
{
|
||||
PikaVector2 v1, v2;
|
||||
gfloat deter;
|
||||
|
||||
v1.x = p->x - d1->x;
|
||||
v1.y = p->y - d1->y;
|
||||
v2.x = d2->x - d1->x;
|
||||
v2.y = d2->y - d1->y;
|
||||
|
||||
pika_vector2_normalize (&v1);
|
||||
pika_vector2_normalize (&v2);
|
||||
|
||||
deter = v1.x * v2.y - v2.x * v1.y;
|
||||
|
||||
return (deter < 0.000000001) && (deter > -0.000000001);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_operation_cage_coef_calc_prepare (GeglOperation *operation)
|
||||
{
|
||||
PikaOperationCageCoefCalc *occc = PIKA_OPERATION_CAGE_COEF_CALC (operation);
|
||||
PikaCageConfig *config = PIKA_CAGE_CONFIG (occc->config);
|
||||
|
||||
gegl_operation_set_format (operation,
|
||||
"output",
|
||||
babl_format_n (babl_type ("float"),
|
||||
2 * pika_cage_config_get_n_points (config)));
|
||||
}
|
||||
|
||||
static GeglRectangle
|
||||
pika_operation_cage_coef_calc_get_bounding_box (GeglOperation *operation)
|
||||
{
|
||||
PikaOperationCageCoefCalc *occc = PIKA_OPERATION_CAGE_COEF_CALC (operation);
|
||||
PikaCageConfig *config = PIKA_CAGE_CONFIG (occc->config);
|
||||
|
||||
return pika_cage_config_get_bounding_box (config);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_operation_cage_coef_calc_process (GeglOperation *operation,
|
||||
GeglBuffer *output,
|
||||
const GeglRectangle *roi,
|
||||
gint level)
|
||||
{
|
||||
PikaOperationCageCoefCalc *occc = PIKA_OPERATION_CAGE_COEF_CALC (operation);
|
||||
PikaCageConfig *config = PIKA_CAGE_CONFIG (occc->config);
|
||||
|
||||
const Babl *format;
|
||||
|
||||
GeglBufferIterator *it;
|
||||
guint n_cage_vertices;
|
||||
PikaCagePoint *current, *last;
|
||||
|
||||
if (! config)
|
||||
return FALSE;
|
||||
|
||||
format = babl_format_n (babl_type ("float"), 2 * pika_cage_config_get_n_points (config));
|
||||
|
||||
n_cage_vertices = pika_cage_config_get_n_points (config);
|
||||
|
||||
it = gegl_buffer_iterator_new (output, roi, 0, format,
|
||||
GEGL_ACCESS_WRITE, GEGL_ABYSS_NONE, 1);
|
||||
|
||||
while (gegl_buffer_iterator_next (it))
|
||||
{
|
||||
/* iterate inside the roi */
|
||||
gfloat *coef = it->items[0].data;
|
||||
gint n_pixels = it->length;
|
||||
gint x = it->items[0].roi.x; /* initial x */
|
||||
gint y = it->items[0].roi.y; /* and y coordinates */
|
||||
gint j;
|
||||
|
||||
memset (coef, 0, sizeof * coef * n_pixels * 2 * n_cage_vertices);
|
||||
while(n_pixels--)
|
||||
{
|
||||
if (pika_cage_config_point_inside(config, x, y))
|
||||
{
|
||||
last = &(g_array_index (config->cage_points, PikaCagePoint, 0));
|
||||
|
||||
for( j = 0; j < n_cage_vertices; j++)
|
||||
{
|
||||
PikaVector2 v1,v2,a,b,p;
|
||||
gdouble BA,SRT,L0,L1,A0,A1,A10,L10, Q,S,R, absa;
|
||||
|
||||
current = &(g_array_index (config->cage_points, PikaCagePoint, (j+1) % n_cage_vertices));
|
||||
v1 = last->src_point;
|
||||
v2 = current->src_point;
|
||||
p.x = x;
|
||||
p.y = y;
|
||||
a.x = v2.x - v1.x;
|
||||
a.y = v2.y - v1.y;
|
||||
absa = pika_vector2_length (&a);
|
||||
|
||||
b.x = v1.x - x;
|
||||
b.y = v1.y - y;
|
||||
Q = a.x * a.x + a.y * a.y;
|
||||
S = b.x * b.x + b.y * b.y;
|
||||
R = 2.0 * (a.x * b.x + a.y * b.y);
|
||||
BA = b.x * a.y - b.y * a.x;
|
||||
SRT = sqrt(4.0 * S * Q - R * R);
|
||||
|
||||
L0 = log(S);
|
||||
L1 = log(S + Q + R);
|
||||
A0 = atan2(R, SRT) / SRT;
|
||||
A1 = atan2(2.0 * Q + R, SRT) / SRT;
|
||||
A10 = A1 - A0;
|
||||
L10 = L1 - L0;
|
||||
|
||||
/* edge coef */
|
||||
coef[j + n_cage_vertices] = (-absa / (4.0 * G_PI)) * ((4.0*S-(R*R)/Q) * A10 + (R / (2.0 * Q)) * L10 + L1 - 2.0);
|
||||
|
||||
if (isnan(coef[j + n_cage_vertices]))
|
||||
{
|
||||
coef[j + n_cage_vertices] = 0.0;
|
||||
}
|
||||
|
||||
/* vertice coef */
|
||||
if (!pika_operation_cage_coef_calc_is_on_straight (&v1, &v2, &p))
|
||||
{
|
||||
coef[j] += (BA / (2.0 * G_PI)) * (L10 /(2.0*Q) - A10 * (2.0 + R / Q));
|
||||
coef[(j+1)%n_cage_vertices] -= (BA / (2.0 * G_PI)) * (L10 / (2.0 * Q) - A10 * (R / Q));
|
||||
}
|
||||
|
||||
last = current;
|
||||
}
|
||||
}
|
||||
|
||||
coef += 2 * n_cage_vertices;
|
||||
|
||||
/* update x and y coordinates */
|
||||
x++;
|
||||
if (x >= (it->items[0].roi.x + it->items[0].roi.width))
|
||||
{
|
||||
x = it->items[0].roi.x;
|
||||
y++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
66
app/operations/pikaoperationcagecoefcalc.h
Normal file
66
app/operations/pikaoperationcagecoefcalc.h
Normal file
@ -0,0 +1,66 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
*
|
||||
* pikaoperationcagecoefcalc.h
|
||||
* Copyright (C) 2010 Michael Muré <batolettre@gmail.com>
|
||||
*
|
||||
* 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 __PIKA_OPERATION_CAGE_COEF_CALC_H__
|
||||
#define __PIKA_OPERATION_CAGE_COEF_CALC_H__
|
||||
|
||||
|
||||
#include <gegl-plugin.h>
|
||||
#include <operation/gegl-operation-source.h>
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
PIKA_OPERATION_CAGE_COEF_CALC_PROP_0,
|
||||
PIKA_OPERATION_CAGE_COEF_CALC_PROP_CONFIG
|
||||
};
|
||||
|
||||
|
||||
#define PIKA_TYPE_OPERATION_CAGE_COEF_CALC (pika_operation_cage_coef_calc_get_type ())
|
||||
#define PIKA_OPERATION_CAGE_COEF_CALC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_OPERATION_CAGE_COEF_CALC, PikaOperationCageCoefCalc))
|
||||
#define PIKA_OPERATION_CAGE_COEF_CALC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_OPERATION_CAGE_COEF_CALC, PikaOperationCageCoefCalcClass))
|
||||
#define PIKA_IS_OPERATION_CAGE_COEF_CALC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_OPERATION_CAGE_COEF_CALC))
|
||||
#define PIKA_IS_OPERATION_CAGE_COEF_CALC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_OPERATION_CAGE_COEF_CALC))
|
||||
#define PIKA_OPERATION_CAGE_COEF_CALC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_OPERATION_CAGE_COEF_CALC, PikaOperationCageCoefCalcClass))
|
||||
|
||||
|
||||
typedef struct _PikaOperationCageCoefCalc PikaOperationCageCoefCalc;
|
||||
typedef struct _PikaOperationCageCoefCalcClass PikaOperationCageCoefCalcClass;
|
||||
|
||||
struct _PikaOperationCageCoefCalc
|
||||
{
|
||||
GeglOperationSource parent_instance;
|
||||
|
||||
PikaCageConfig *config;
|
||||
};
|
||||
|
||||
struct _PikaOperationCageCoefCalcClass
|
||||
{
|
||||
GeglOperationSourceClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType pika_operation_cage_coef_calc_get_type (void) G_GNUC_CONST;
|
||||
|
||||
|
||||
#endif /* __PIKA_OPERATION_CAGE_COEF_CALC_H__ */
|
||||
607
app/operations/pikaoperationcagetransform.c
Normal file
607
app/operations/pikaoperationcagetransform.c
Normal file
@ -0,0 +1,607 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
*
|
||||
* pikaoperationcage.c
|
||||
* Copyright (C) 2010 Michael Muré <batolettre@gmail.com>
|
||||
*
|
||||
* 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.h>
|
||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||
|
||||
#include "libpikacolor/pikacolor.h"
|
||||
#include "libpikamath/pikamath.h"
|
||||
|
||||
#include "operations-types.h"
|
||||
|
||||
#include "pikaoperationcagetransform.h"
|
||||
#include "pikacageconfig.h"
|
||||
|
||||
#include "pika-intl.h"
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_CONFIG,
|
||||
PROP_FILL,
|
||||
};
|
||||
|
||||
|
||||
static void pika_operation_cage_transform_finalize (GObject *object);
|
||||
static void pika_operation_cage_transform_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void pika_operation_cage_transform_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void pika_operation_cage_transform_prepare (GeglOperation *operation);
|
||||
static gboolean pika_operation_cage_transform_process (GeglOperation *operation,
|
||||
GeglBuffer *in_buf,
|
||||
GeglBuffer *aux_buf,
|
||||
GeglBuffer *out_buf,
|
||||
const GeglRectangle *roi,
|
||||
gint level);
|
||||
static void pika_operation_cage_transform_interpolate_source_coords_recurs
|
||||
(PikaOperationCageTransform *oct,
|
||||
GeglBuffer *out_buf,
|
||||
const GeglRectangle *roi,
|
||||
PikaVector2 p1_s,
|
||||
PikaVector2 p1_d,
|
||||
PikaVector2 p2_s,
|
||||
PikaVector2 p2_d,
|
||||
PikaVector2 p3_s,
|
||||
PikaVector2 p3_d,
|
||||
gint recursion_depth,
|
||||
gfloat *coords);
|
||||
static PikaVector2 pika_cage_transform_compute_destination (PikaCageConfig *config,
|
||||
gfloat *coef,
|
||||
GeglSampler *coef_sampler,
|
||||
PikaVector2 coords);
|
||||
GeglRectangle pika_operation_cage_transform_get_cached_region (GeglOperation *operation,
|
||||
const GeglRectangle *roi);
|
||||
GeglRectangle pika_operation_cage_transform_get_required_for_output (GeglOperation *operation,
|
||||
const gchar *input_pad,
|
||||
const GeglRectangle *roi);
|
||||
GeglRectangle pika_operation_cage_transform_get_bounding_box (GeglOperation *operation);
|
||||
|
||||
|
||||
G_DEFINE_TYPE (PikaOperationCageTransform, pika_operation_cage_transform,
|
||||
GEGL_TYPE_OPERATION_COMPOSER)
|
||||
|
||||
#define parent_class pika_operation_cage_transform_parent_class
|
||||
|
||||
|
||||
static void
|
||||
pika_operation_cage_transform_class_init (PikaOperationCageTransformClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass);
|
||||
GeglOperationComposerClass *filter_class = GEGL_OPERATION_COMPOSER_CLASS (klass);
|
||||
|
||||
object_class->get_property = pika_operation_cage_transform_get_property;
|
||||
object_class->set_property = pika_operation_cage_transform_set_property;
|
||||
object_class->finalize = pika_operation_cage_transform_finalize;
|
||||
|
||||
gegl_operation_class_set_keys (operation_class,
|
||||
"name", "pika:cage-transform",
|
||||
"categories", "transform",
|
||||
"description", _("Convert a set of coefficient buffer to a coordinate buffer for the PIKA cage tool"),
|
||||
NULL);
|
||||
|
||||
operation_class->prepare = pika_operation_cage_transform_prepare;
|
||||
|
||||
operation_class->get_required_for_output = pika_operation_cage_transform_get_required_for_output;
|
||||
operation_class->get_cached_region = pika_operation_cage_transform_get_cached_region;
|
||||
operation_class->get_bounding_box = pika_operation_cage_transform_get_bounding_box;
|
||||
/* XXX Temporarily disable multi-threading on this operation because
|
||||
* it is much faster when single-threaded. See bug 787663.
|
||||
*/
|
||||
operation_class->threaded = FALSE;
|
||||
|
||||
filter_class->process = pika_operation_cage_transform_process;
|
||||
|
||||
g_object_class_install_property (object_class, PROP_CONFIG,
|
||||
g_param_spec_object ("config",
|
||||
"Config",
|
||||
"A PikaCageConfig object, that define the transformation",
|
||||
PIKA_TYPE_CAGE_CONFIG,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_FILL,
|
||||
g_param_spec_boolean ("fill-plain-color",
|
||||
_("Fill with plain color"),
|
||||
_("Fill the original position of the cage with a plain color"),
|
||||
FALSE,
|
||||
G_PARAM_READWRITE));
|
||||
}
|
||||
|
||||
static void
|
||||
pika_operation_cage_transform_init (PikaOperationCageTransform *self)
|
||||
{
|
||||
self->format_coords = babl_format_n(babl_type("float"), 2);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_operation_cage_transform_finalize (GObject *object)
|
||||
{
|
||||
PikaOperationCageTransform *self = PIKA_OPERATION_CAGE_TRANSFORM (object);
|
||||
|
||||
g_clear_object (&self->config);
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_operation_cage_transform_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaOperationCageTransform *self = PIKA_OPERATION_CAGE_TRANSFORM (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_CONFIG:
|
||||
g_value_set_object (value, self->config);
|
||||
break;
|
||||
case PROP_FILL:
|
||||
g_value_set_boolean (value, self->fill_plain_color);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_operation_cage_transform_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaOperationCageTransform *self = PIKA_OPERATION_CAGE_TRANSFORM (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_CONFIG:
|
||||
if (self->config)
|
||||
g_object_unref (self->config);
|
||||
self->config = g_value_dup_object (value);
|
||||
break;
|
||||
case PROP_FILL:
|
||||
self->fill_plain_color = g_value_get_boolean (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_operation_cage_transform_prepare (GeglOperation *operation)
|
||||
{
|
||||
PikaOperationCageTransform *oct = PIKA_OPERATION_CAGE_TRANSFORM (operation);
|
||||
PikaCageConfig *config = PIKA_CAGE_CONFIG (oct->config);
|
||||
|
||||
gegl_operation_set_format (operation, "input",
|
||||
babl_format_n (babl_type ("float"),
|
||||
2 * pika_cage_config_get_n_points (config)));
|
||||
gegl_operation_set_format (operation, "output",
|
||||
babl_format_n (babl_type ("float"), 2));
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_operation_cage_transform_process (GeglOperation *operation,
|
||||
GeglBuffer *in_buf,
|
||||
GeglBuffer *aux_buf,
|
||||
GeglBuffer *out_buf,
|
||||
const GeglRectangle *roi,
|
||||
gint level)
|
||||
{
|
||||
PikaOperationCageTransform *oct = PIKA_OPERATION_CAGE_TRANSFORM (operation);
|
||||
PikaCageConfig *config = PIKA_CAGE_CONFIG (oct->config);
|
||||
GeglRectangle cage_bb;
|
||||
gfloat *coords;
|
||||
gfloat *coef;
|
||||
const Babl *format_coef;
|
||||
GeglSampler *coef_sampler;
|
||||
PikaVector2 plain_color;
|
||||
GeglBufferIterator *it;
|
||||
gint x, y;
|
||||
gboolean output_set;
|
||||
PikaCagePoint *point;
|
||||
guint n_cage_vertices;
|
||||
|
||||
/* pre-fill the out buffer with no-displacement coordinate */
|
||||
it = gegl_buffer_iterator_new (out_buf, roi, 0, NULL,
|
||||
GEGL_ACCESS_WRITE, GEGL_ABYSS_NONE, 1);
|
||||
cage_bb = pika_cage_config_get_bounding_box (config);
|
||||
|
||||
point = &(g_array_index (config->cage_points, PikaCagePoint, 0));
|
||||
plain_color.x = (gint) point->src_point.x;
|
||||
plain_color.y = (gint) point->src_point.y;
|
||||
|
||||
n_cage_vertices = pika_cage_config_get_n_points (config);
|
||||
|
||||
while (gegl_buffer_iterator_next (it))
|
||||
{
|
||||
/* iterate inside the roi */
|
||||
gint n_pixels = it->length;
|
||||
gfloat *output = it->items[0].data;
|
||||
|
||||
x = it->items[0].roi.x; /* initial x */
|
||||
y = it->items[0].roi.y; /* and y coordinates */
|
||||
|
||||
while (n_pixels--)
|
||||
{
|
||||
output_set = FALSE;
|
||||
if (oct->fill_plain_color)
|
||||
{
|
||||
if (x > cage_bb.x &&
|
||||
y > cage_bb.y &&
|
||||
x < cage_bb.x + cage_bb.width &&
|
||||
y < cage_bb.y + cage_bb.height)
|
||||
{
|
||||
if (pika_cage_config_point_inside (config, x, y))
|
||||
{
|
||||
output[0] = plain_color.x;
|
||||
output[1] = plain_color.y;
|
||||
output_set = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!output_set)
|
||||
{
|
||||
output[0] = x + 0.5;
|
||||
output[1] = y + 0.5;
|
||||
}
|
||||
|
||||
output += 2;
|
||||
|
||||
/* update x and y coordinates */
|
||||
x++;
|
||||
if (x >= (it->items[0].roi.x + it->items[0].roi.width))
|
||||
{
|
||||
x = it->items[0].roi.x;
|
||||
y++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (! aux_buf)
|
||||
return TRUE;
|
||||
|
||||
gegl_operation_progress (operation, 0.0, "");
|
||||
|
||||
/* pre-allocate memory outside of the loop */
|
||||
coords = g_slice_alloc (2 * sizeof (gfloat));
|
||||
coef = g_malloc (n_cage_vertices * 2 * sizeof (gfloat));
|
||||
format_coef = babl_format_n (babl_type ("float"), 2 * n_cage_vertices);
|
||||
coef_sampler = gegl_buffer_sampler_new (aux_buf,
|
||||
format_coef, GEGL_SAMPLER_NEAREST);
|
||||
|
||||
/* compute, reverse and interpolate the transformation */
|
||||
for (y = cage_bb.y; y < cage_bb.y + cage_bb.height - 1; y++)
|
||||
{
|
||||
PikaVector2 p1_d, p2_d, p3_d, p4_d;
|
||||
PikaVector2 p1_s, p2_s, p3_s, p4_s;
|
||||
|
||||
p1_s.y = y;
|
||||
p2_s.y = y+1;
|
||||
p3_s.y = y+1;
|
||||
p3_s.x = cage_bb.x;
|
||||
p4_s.y = y;
|
||||
p4_s.x = cage_bb.x;
|
||||
|
||||
p3_d = pika_cage_transform_compute_destination (config, coef, coef_sampler, p3_s);
|
||||
p4_d = pika_cage_transform_compute_destination (config, coef, coef_sampler, p4_s);
|
||||
|
||||
for (x = cage_bb.x; x < cage_bb.x + cage_bb.width - 1; x++)
|
||||
{
|
||||
p1_s = p4_s;
|
||||
p2_s = p3_s;
|
||||
p3_s.x = x+1;
|
||||
p4_s.x = x+1;
|
||||
|
||||
p1_d = p4_d;
|
||||
p2_d = p3_d;
|
||||
p3_d = pika_cage_transform_compute_destination (config, coef, coef_sampler, p3_s);
|
||||
p4_d = pika_cage_transform_compute_destination (config, coef, coef_sampler, p4_s);
|
||||
|
||||
if (pika_cage_config_point_inside (config, x, y))
|
||||
{
|
||||
pika_operation_cage_transform_interpolate_source_coords_recurs (oct,
|
||||
out_buf,
|
||||
roi,
|
||||
p1_s, p1_d,
|
||||
p2_s, p2_d,
|
||||
p3_s, p3_d,
|
||||
0,
|
||||
coords);
|
||||
|
||||
pika_operation_cage_transform_interpolate_source_coords_recurs (oct,
|
||||
out_buf,
|
||||
roi,
|
||||
p1_s, p1_d,
|
||||
p3_s, p3_d,
|
||||
p4_s, p4_d,
|
||||
0,
|
||||
coords);
|
||||
}
|
||||
}
|
||||
|
||||
if ((y - cage_bb.y) % 20 == 0)
|
||||
{
|
||||
gdouble fraction = ((gdouble) (y - cage_bb.y) /
|
||||
(gdouble) (cage_bb.height));
|
||||
|
||||
/* 0.0 and 1.0 indicate progress start/end, so avoid them */
|
||||
if (fraction > 0.0 && fraction < 1.0)
|
||||
{
|
||||
gegl_operation_progress (operation, fraction, "");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
g_object_unref (coef_sampler);
|
||||
g_free (coef);
|
||||
g_slice_free1 (2 * sizeof (gfloat), coords);
|
||||
|
||||
gegl_operation_progress (operation, 1.0, "");
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
pika_operation_cage_transform_interpolate_source_coords_recurs (PikaOperationCageTransform *oct,
|
||||
GeglBuffer *out_buf,
|
||||
const GeglRectangle *roi,
|
||||
PikaVector2 p1_s,
|
||||
PikaVector2 p1_d,
|
||||
PikaVector2 p2_s,
|
||||
PikaVector2 p2_d,
|
||||
PikaVector2 p3_s,
|
||||
PikaVector2 p3_d,
|
||||
gint recursion_depth,
|
||||
gfloat *coords)
|
||||
{
|
||||
gint xmin, xmax, ymin, ymax, x, y;
|
||||
|
||||
/* Stop recursion if all 3 vertices of the triangle are outside the
|
||||
* ROI (left/right or above/below).
|
||||
*/
|
||||
if (p1_d.x >= roi->x + roi->width &&
|
||||
p2_d.x >= roi->x + roi->width &&
|
||||
p3_d.x >= roi->x + roi->width) return;
|
||||
if (p1_d.y >= roi->y + roi->height &&
|
||||
p2_d.y >= roi->y + roi->height &&
|
||||
p3_d.y >= roi->y + roi->height) return;
|
||||
|
||||
if (p1_d.x < roi->x &&
|
||||
p2_d.x < roi->x &&
|
||||
p3_d.x < roi->x) return;
|
||||
if (p1_d.y < roi->y &&
|
||||
p2_d.y < roi->y &&
|
||||
p3_d.y < roi->y) return;
|
||||
|
||||
xmin = xmax = lrint (p1_d.x);
|
||||
ymin = ymax = lrint (p1_d.y);
|
||||
|
||||
x = lrint (p2_d.x);
|
||||
xmin = MIN (x, xmin);
|
||||
xmax = MAX (x, xmax);
|
||||
|
||||
x = lrint (p3_d.x);
|
||||
xmin = MIN (x, xmin);
|
||||
xmax = MAX (x, xmax);
|
||||
|
||||
y = lrint (p2_d.y);
|
||||
ymin = MIN (y, ymin);
|
||||
ymax = MAX (y, ymax);
|
||||
|
||||
y = lrint (p3_d.y);
|
||||
ymin = MIN (y, ymin);
|
||||
ymax = MAX (y, ymax);
|
||||
|
||||
/* test if there is no more pixel in the triangle */
|
||||
if (xmin == xmax || ymin == ymax)
|
||||
return;
|
||||
|
||||
/* test if the triangle is implausibly large as manifested by too deep recursion */
|
||||
if (recursion_depth > 5)
|
||||
return;
|
||||
|
||||
/* test if the triangle is small enough.
|
||||
*
|
||||
* if yes, we compute the coefficient of the barycenter for the
|
||||
* pixel (x,y) and see if a pixel is inside (ie the 3 coef have the
|
||||
* same sign).
|
||||
*/
|
||||
if (xmax - xmin == 1 && ymax - ymin == 1)
|
||||
{
|
||||
gdouble a, b, c, denom, x, y;
|
||||
|
||||
x = (gdouble) xmin + 0.5;
|
||||
y = (gdouble) ymin + 0.5;
|
||||
|
||||
denom = (p2_d.x - p1_d.x) * p3_d.y + (p1_d.x - p3_d.x) * p2_d.y + (p3_d.x - p2_d.x) * p1_d.y;
|
||||
a = ((p2_d.x - x) * p3_d.y + (x - p3_d.x) * p2_d.y + (p3_d.x - p2_d.x) * y) / denom;
|
||||
b = - ((p1_d.x - x) * p3_d.y + (x - p3_d.x) * p1_d.y + (p3_d.x - p1_d.x) * y) / denom;
|
||||
c = 1.0 - a - b;
|
||||
|
||||
/* if a pixel is inside, we compute its source coordinate and
|
||||
* set it in the output buffer
|
||||
*/
|
||||
if ((a > 0 && b > 0 && c > 0) || (a < 0 && b < 0 && c < 0))
|
||||
{
|
||||
GeglRectangle rect = { 0, 0, 1, 1 };
|
||||
gfloat coords[2];
|
||||
|
||||
rect.x = xmin;
|
||||
rect.y = ymin;
|
||||
|
||||
coords[0] = (a * p1_s.x + b * p2_s.x + c * p3_s.x);
|
||||
coords[1] = (a * p1_s.y + b * p2_s.y + c * p3_s.y);
|
||||
|
||||
gegl_buffer_set (out_buf,
|
||||
&rect,
|
||||
0,
|
||||
oct->format_coords,
|
||||
coords,
|
||||
GEGL_AUTO_ROWSTRIDE);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* we cut the triangle in 4 sub-triangle and treat it recursively */
|
||||
/*
|
||||
* /\
|
||||
* /__\
|
||||
* /\ /\
|
||||
* /__\/__\
|
||||
*
|
||||
*/
|
||||
|
||||
PikaVector2 pm1_d, pm2_d, pm3_d;
|
||||
PikaVector2 pm1_s, pm2_s, pm3_s;
|
||||
gint next_depth = recursion_depth + 1;
|
||||
|
||||
pm1_d.x = (p1_d.x + p2_d.x) / 2.0;
|
||||
pm1_d.y = (p1_d.y + p2_d.y) / 2.0;
|
||||
|
||||
pm2_d.x = (p2_d.x + p3_d.x) / 2.0;
|
||||
pm2_d.y = (p2_d.y + p3_d.y) / 2.0;
|
||||
|
||||
pm3_d.x = (p3_d.x + p1_d.x) / 2.0;
|
||||
pm3_d.y = (p3_d.y + p1_d.y) / 2.0;
|
||||
|
||||
pm1_s.x = (p1_s.x + p2_s.x) / 2.0;
|
||||
pm1_s.y = (p1_s.y + p2_s.y) / 2.0;
|
||||
|
||||
pm2_s.x = (p2_s.x + p3_s.x) / 2.0;
|
||||
pm2_s.y = (p2_s.y + p3_s.y) / 2.0;
|
||||
|
||||
pm3_s.x = (p3_s.x + p1_s.x) / 2.0;
|
||||
pm3_s.y = (p3_s.y + p1_s.y) / 2.0;
|
||||
|
||||
pika_operation_cage_transform_interpolate_source_coords_recurs (oct,
|
||||
out_buf,
|
||||
roi,
|
||||
p1_s, p1_d,
|
||||
pm1_s, pm1_d,
|
||||
pm3_s, pm3_d,
|
||||
next_depth,
|
||||
coords);
|
||||
|
||||
pika_operation_cage_transform_interpolate_source_coords_recurs (oct,
|
||||
out_buf,
|
||||
roi,
|
||||
pm1_s, pm1_d,
|
||||
p2_s, p2_d,
|
||||
pm2_s, pm2_d,
|
||||
next_depth,
|
||||
coords);
|
||||
|
||||
pika_operation_cage_transform_interpolate_source_coords_recurs (oct,
|
||||
out_buf,
|
||||
roi,
|
||||
pm1_s, pm1_d,
|
||||
pm2_s, pm2_d,
|
||||
pm3_s, pm3_d,
|
||||
next_depth,
|
||||
coords);
|
||||
|
||||
pika_operation_cage_transform_interpolate_source_coords_recurs (oct,
|
||||
out_buf,
|
||||
roi,
|
||||
pm3_s, pm3_d,
|
||||
pm2_s, pm2_d,
|
||||
p3_s, p3_d,
|
||||
next_depth,
|
||||
coords);
|
||||
}
|
||||
}
|
||||
|
||||
static PikaVector2
|
||||
pika_cage_transform_compute_destination (PikaCageConfig *config,
|
||||
gfloat *coef,
|
||||
GeglSampler *coef_sampler,
|
||||
PikaVector2 coords)
|
||||
{
|
||||
PikaVector2 result = {0, 0};
|
||||
gint n_cage_vertices = pika_cage_config_get_n_points (config);
|
||||
gint i;
|
||||
PikaCagePoint *point;
|
||||
|
||||
gegl_sampler_get (coef_sampler,
|
||||
coords.x, coords.y, NULL, coef, GEGL_ABYSS_NONE);
|
||||
|
||||
for (i = 0; i < n_cage_vertices; i++)
|
||||
{
|
||||
point = &g_array_index (config->cage_points, PikaCagePoint, i);
|
||||
|
||||
result.x += coef[i] * point->dest_point.x;
|
||||
result.y += coef[i] * point->dest_point.y;
|
||||
|
||||
result.x += coef[i + n_cage_vertices] * point->edge_scaling_factor * point->edge_normal.x;
|
||||
result.y += coef[i + n_cage_vertices] * point->edge_scaling_factor * point->edge_normal.y;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
GeglRectangle
|
||||
pika_operation_cage_transform_get_cached_region (GeglOperation *operation,
|
||||
const GeglRectangle *roi)
|
||||
{
|
||||
GeglRectangle result = *gegl_operation_source_get_bounding_box (operation,
|
||||
"input");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
GeglRectangle
|
||||
pika_operation_cage_transform_get_required_for_output (GeglOperation *operation,
|
||||
const gchar *input_pad,
|
||||
const GeglRectangle *roi)
|
||||
{
|
||||
GeglRectangle result = *gegl_operation_source_get_bounding_box (operation,
|
||||
"input");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
GeglRectangle
|
||||
pika_operation_cage_transform_get_bounding_box (GeglOperation *operation)
|
||||
{
|
||||
GeglRectangle result = *gegl_operation_source_get_bounding_box (operation,
|
||||
"input");
|
||||
|
||||
return result;
|
||||
}
|
||||
62
app/operations/pikaoperationcagetransform.h
Normal file
62
app/operations/pikaoperationcagetransform.h
Normal file
@ -0,0 +1,62 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
*
|
||||
* pikaoperationcagetransform.h
|
||||
* Copyright (C) 2010 Michael Muré <batolettre@gmail.com>
|
||||
*
|
||||
* 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 __PIKA_OPERATION_CAGE_TRANSFORM_H__
|
||||
#define __PIKA_OPERATION_CAGE_TRANSFORM_H__
|
||||
|
||||
|
||||
#include <gegl-plugin.h>
|
||||
#include <operation/gegl-operation-composer.h>
|
||||
|
||||
|
||||
#define PIKA_TYPE_OPERATION_CAGE_TRANSFORM (pika_operation_cage_transform_get_type ())
|
||||
#define PIKA_OPERATION_CAGE_TRANSFORM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_OPERATION_CAGE_TRANSFORM, PikaOperationCageTransform))
|
||||
#define PIKA_OPERATION_CAGE_TRANSFORM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_OPERATION_CAGE_TRANSFORM, PikaOperationCageTransformClass))
|
||||
#define PIKA_IS_OPERATION_CAGE_TRANSFORM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_OPERATION_CAGE_TRANSFORM))
|
||||
#define PIKA_IS_OPERATION_CAGE_TRANSFORM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_OPERATION_CAGE_TRANSFORM))
|
||||
#define PIKA_OPERATION_CAGE_TRANSFORM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_OPERATION_CAGE_TRANSFORM, PikaOperationCageTransformClass))
|
||||
|
||||
|
||||
typedef struct _PikaOperationCageTransform PikaOperationCageTransform;
|
||||
typedef struct _PikaOperationCageTransformClass PikaOperationCageTransformClass;
|
||||
|
||||
struct _PikaOperationCageTransform
|
||||
{
|
||||
GeglOperationComposer parent_instance;
|
||||
|
||||
PikaCageConfig *config;
|
||||
gboolean fill_plain_color;
|
||||
|
||||
const Babl *format_coords;
|
||||
};
|
||||
|
||||
struct _PikaOperationCageTransformClass
|
||||
{
|
||||
GeglOperationComposerClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType pika_operation_cage_transform_get_type (void) G_GNUC_CONST;
|
||||
|
||||
|
||||
#endif /* __PIKA_OPERATION_CAGE_TRANSFORM_H__ */
|
||||
202
app/operations/pikaoperationcolorbalance.c
Normal file
202
app/operations/pikaoperationcolorbalance.c
Normal file
@ -0,0 +1,202 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationcolorbalance.c
|
||||
* Copyright (C) 2007 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* 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.h>
|
||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||
|
||||
#include "libpikacolor/pikacolor.h"
|
||||
#include "libpikamath/pikamath.h"
|
||||
|
||||
#include "operations-types.h"
|
||||
|
||||
#include "pikacolorbalanceconfig.h"
|
||||
#include "pikaoperationcolorbalance.h"
|
||||
|
||||
#include "pika-intl.h"
|
||||
|
||||
|
||||
static gboolean pika_operation_color_balance_process (GeglOperation *operation,
|
||||
void *in_buf,
|
||||
void *out_buf,
|
||||
glong samples,
|
||||
const GeglRectangle *roi,
|
||||
gint level);
|
||||
|
||||
|
||||
G_DEFINE_TYPE (PikaOperationColorBalance, pika_operation_color_balance,
|
||||
PIKA_TYPE_OPERATION_POINT_FILTER)
|
||||
|
||||
#define parent_class pika_operation_color_balance_parent_class
|
||||
|
||||
|
||||
static void
|
||||
pika_operation_color_balance_class_init (PikaOperationColorBalanceClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass);
|
||||
GeglOperationPointFilterClass *point_class = GEGL_OPERATION_POINT_FILTER_CLASS (klass);
|
||||
|
||||
object_class->set_property = pika_operation_point_filter_set_property;
|
||||
object_class->get_property = pika_operation_point_filter_get_property;
|
||||
|
||||
gegl_operation_class_set_keys (operation_class,
|
||||
"name", "pika:color-balance",
|
||||
"categories", "color",
|
||||
"description", _("Adjust color distribution"),
|
||||
NULL);
|
||||
|
||||
point_class->process = pika_operation_color_balance_process;
|
||||
|
||||
g_object_class_install_property (object_class,
|
||||
PIKA_OPERATION_POINT_FILTER_PROP_CONFIG,
|
||||
g_param_spec_object ("config",
|
||||
"Config",
|
||||
"The config object",
|
||||
PIKA_TYPE_COLOR_BALANCE_CONFIG,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT));
|
||||
}
|
||||
|
||||
static void
|
||||
pika_operation_color_balance_init (PikaOperationColorBalance *self)
|
||||
{
|
||||
}
|
||||
|
||||
static inline gfloat
|
||||
pika_operation_color_balance_map (gfloat value,
|
||||
gdouble lightness,
|
||||
gdouble shadows,
|
||||
gdouble midtones,
|
||||
gdouble highlights)
|
||||
{
|
||||
/* Apply masks to the corrections for shadows, midtones and
|
||||
* highlights so that each correction affects only one range.
|
||||
* Those masks look like this:
|
||||
* ‾\___
|
||||
* _/‾\_
|
||||
* ___/‾
|
||||
* with ramps of width a at x = b and x = 1 - b.
|
||||
*
|
||||
* The sum of these masks equals 1 for x in 0..1, so applying the
|
||||
* same correction in the shadows and in the midtones is equivalent
|
||||
* to applying this correction on a virtual shadows_and_midtones
|
||||
* range.
|
||||
*/
|
||||
static const gdouble a = 0.25, b = 0.333, scale = 0.7;
|
||||
|
||||
shadows *= CLAMP ((lightness - b) / -a + 0.5, 0, 1) * scale;
|
||||
midtones *= CLAMP ((lightness - b) / a + 0.5, 0, 1) *
|
||||
CLAMP ((lightness + b - 1) / -a + 0.5, 0, 1) * scale;
|
||||
highlights *= CLAMP ((lightness + b - 1) / a + 0.5, 0, 1) * scale;
|
||||
|
||||
value += shadows;
|
||||
value += midtones;
|
||||
value += highlights;
|
||||
value = CLAMP (value, 0.0, 1.0);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_operation_color_balance_process (GeglOperation *operation,
|
||||
void *in_buf,
|
||||
void *out_buf,
|
||||
glong samples,
|
||||
const GeglRectangle *roi,
|
||||
gint level)
|
||||
{
|
||||
PikaOperationPointFilter *point = PIKA_OPERATION_POINT_FILTER (operation);
|
||||
PikaColorBalanceConfig *config = PIKA_COLOR_BALANCE_CONFIG (point->config);
|
||||
gfloat *src = in_buf;
|
||||
gfloat *dest = out_buf;
|
||||
|
||||
if (! config)
|
||||
return FALSE;
|
||||
|
||||
while (samples--)
|
||||
{
|
||||
gfloat r = src[RED];
|
||||
gfloat g = src[GREEN];
|
||||
gfloat b = src[BLUE];
|
||||
gfloat r_n;
|
||||
gfloat g_n;
|
||||
gfloat b_n;
|
||||
|
||||
PikaRGB rgb = { r, g, b};
|
||||
PikaHSL hsl;
|
||||
|
||||
pika_rgb_to_hsl (&rgb, &hsl);
|
||||
|
||||
r_n = pika_operation_color_balance_map (r, hsl.l,
|
||||
config->cyan_red[PIKA_TRANSFER_SHADOWS],
|
||||
config->cyan_red[PIKA_TRANSFER_MIDTONES],
|
||||
config->cyan_red[PIKA_TRANSFER_HIGHLIGHTS]);
|
||||
|
||||
g_n = pika_operation_color_balance_map (g, hsl.l,
|
||||
config->magenta_green[PIKA_TRANSFER_SHADOWS],
|
||||
config->magenta_green[PIKA_TRANSFER_MIDTONES],
|
||||
config->magenta_green[PIKA_TRANSFER_HIGHLIGHTS]);
|
||||
|
||||
b_n = pika_operation_color_balance_map (b, hsl.l,
|
||||
config->yellow_blue[PIKA_TRANSFER_SHADOWS],
|
||||
config->yellow_blue[PIKA_TRANSFER_MIDTONES],
|
||||
config->yellow_blue[PIKA_TRANSFER_HIGHLIGHTS]);
|
||||
|
||||
if (config->preserve_luminosity)
|
||||
{
|
||||
PikaHSL hsl2;
|
||||
|
||||
rgb.r = r_n;
|
||||
rgb.g = g_n;
|
||||
rgb.b = b_n;
|
||||
pika_rgb_to_hsl (&rgb, &hsl);
|
||||
|
||||
rgb.r = r;
|
||||
rgb.g = g;
|
||||
rgb.b = b;
|
||||
pika_rgb_to_hsl (&rgb, &hsl2);
|
||||
|
||||
hsl.l = hsl2.l;
|
||||
|
||||
pika_hsl_to_rgb (&hsl, &rgb);
|
||||
|
||||
r_n = rgb.r;
|
||||
g_n = rgb.g;
|
||||
b_n = rgb.b;
|
||||
}
|
||||
|
||||
dest[RED] = r_n;
|
||||
dest[GREEN] = g_n;
|
||||
dest[BLUE] = b_n;
|
||||
dest[ALPHA] = src[ALPHA];
|
||||
|
||||
src += 4;
|
||||
dest += 4;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
57
app/operations/pikaoperationcolorbalance.h
Normal file
57
app/operations/pikaoperationcolorbalance.h
Normal file
@ -0,0 +1,57 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationcolorbalance.h
|
||||
* Copyright (C) 2007 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* 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 __PIKA_OPERATION_COLOR_BALANCE_H__
|
||||
#define __PIKA_OPERATION_COLOR_BALANCE_H__
|
||||
|
||||
|
||||
#include "pikaoperationpointfilter.h"
|
||||
|
||||
|
||||
#define PIKA_TYPE_OPERATION_COLOR_BALANCE (pika_operation_color_balance_get_type ())
|
||||
#define PIKA_OPERATION_COLOR_BALANCE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_OPERATION_COLOR_BALANCE, PikaOperationColorBalance))
|
||||
#define PIKA_OPERATION_COLOR_BALANCE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_OPERATION_COLOR_BALANCE, PikaOperationColorBalanceClass))
|
||||
#define PIKA_IS_OPERATION_COLOR_BALANCE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_OPERATION_COLOR_BALANCE))
|
||||
#define PIKA_IS_OPERATION_COLOR_BALANCE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_OPERATION_COLOR_BALANCE))
|
||||
#define PIKA_OPERATION_COLOR_BALANCE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_OPERATION_COLOR_BALANCE, PikaOperationColorBalanceClass))
|
||||
|
||||
|
||||
typedef struct _PikaOperationColorBalance PikaOperationColorBalance;
|
||||
typedef struct _PikaOperationColorBalanceClass PikaOperationColorBalanceClass;
|
||||
|
||||
struct _PikaOperationColorBalance
|
||||
{
|
||||
PikaOperationPointFilter parent_instance;
|
||||
};
|
||||
|
||||
struct _PikaOperationColorBalanceClass
|
||||
{
|
||||
PikaOperationPointFilterClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType pika_operation_color_balance_get_type (void) G_GNUC_CONST;
|
||||
|
||||
|
||||
#endif /* __PIKA_OPERATION_COLOR_BALANCE_H__ */
|
||||
278
app/operations/pikaoperationcolorize.c
Normal file
278
app/operations/pikaoperationcolorize.c
Normal file
@ -0,0 +1,278 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationcolorize.c
|
||||
* Copyright (C) 2007 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* 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 <gdk-pixbuf/gdk-pixbuf.h>
|
||||
#include <gegl.h>
|
||||
|
||||
#include "libpikacolor/pikacolor.h"
|
||||
#include "libpikaconfig/pikaconfig.h"
|
||||
|
||||
#include "operations-types.h"
|
||||
|
||||
#include "pikaoperationcolorize.h"
|
||||
|
||||
#include "pika-intl.h"
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_HUE,
|
||||
PROP_SATURATION,
|
||||
PROP_LIGHTNESS,
|
||||
PROP_COLOR
|
||||
};
|
||||
|
||||
|
||||
static void pika_operation_colorize_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void pika_operation_colorize_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec);
|
||||
|
||||
static gboolean pika_operation_colorize_process (GeglOperation *operation,
|
||||
void *in_buf,
|
||||
void *out_buf,
|
||||
glong samples,
|
||||
const GeglRectangle *roi,
|
||||
gint level);
|
||||
|
||||
|
||||
G_DEFINE_TYPE (PikaOperationColorize, pika_operation_colorize,
|
||||
PIKA_TYPE_OPERATION_POINT_FILTER)
|
||||
|
||||
#define parent_class pika_operation_colorize_parent_class
|
||||
|
||||
|
||||
static void
|
||||
pika_operation_colorize_class_init (PikaOperationColorizeClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass);
|
||||
GeglOperationPointFilterClass *point_class = GEGL_OPERATION_POINT_FILTER_CLASS (klass);
|
||||
PikaHSL hsl;
|
||||
PikaRGB rgb;
|
||||
|
||||
object_class->set_property = pika_operation_colorize_set_property;
|
||||
object_class->get_property = pika_operation_colorize_get_property;
|
||||
|
||||
gegl_operation_class_set_keys (operation_class,
|
||||
"name", "pika:colorize",
|
||||
"categories", "color",
|
||||
"description", _("Colorize the image"),
|
||||
NULL);
|
||||
|
||||
point_class->process = pika_operation_colorize_process;
|
||||
|
||||
PIKA_CONFIG_PROP_DOUBLE (object_class, PROP_HUE,
|
||||
"hue",
|
||||
_("Hue"),
|
||||
_("Hue"),
|
||||
0.0, 1.0, 0.5, 0);
|
||||
|
||||
PIKA_CONFIG_PROP_DOUBLE (object_class, PROP_SATURATION,
|
||||
"saturation",
|
||||
_("Saturation"),
|
||||
_("Saturation"),
|
||||
0.0, 1.0, 0.5, 0);
|
||||
|
||||
PIKA_CONFIG_PROP_DOUBLE (object_class, PROP_LIGHTNESS,
|
||||
"lightness",
|
||||
_("Lightness"),
|
||||
_("Lightness"),
|
||||
-1.0, 1.0, 0.0, 0);
|
||||
|
||||
pika_hsl_set (&hsl, 0.5, 0.5, 0.5);
|
||||
pika_hsl_set_alpha (&hsl, 1.0);
|
||||
pika_hsl_to_rgb (&hsl, &rgb);
|
||||
|
||||
g_object_class_install_property (object_class, PROP_COLOR,
|
||||
pika_param_spec_rgb ("color",
|
||||
_("Color"),
|
||||
_("Color"),
|
||||
FALSE, &rgb,
|
||||
G_PARAM_READWRITE));
|
||||
}
|
||||
|
||||
static void
|
||||
pika_operation_colorize_init (PikaOperationColorize *self)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
pika_operation_colorize_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaOperationColorize *self = PIKA_OPERATION_COLORIZE (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_HUE:
|
||||
g_value_set_double (value, self->hue);
|
||||
break;
|
||||
|
||||
case PROP_SATURATION:
|
||||
g_value_set_double (value, self->saturation);
|
||||
break;
|
||||
|
||||
case PROP_LIGHTNESS:
|
||||
g_value_set_double (value, self->lightness);
|
||||
break;
|
||||
|
||||
case PROP_COLOR:
|
||||
{
|
||||
PikaHSL hsl;
|
||||
PikaRGB rgb;
|
||||
|
||||
pika_hsl_set (&hsl,
|
||||
self->hue,
|
||||
self->saturation,
|
||||
(self->lightness + 1.0) / 2.0);
|
||||
pika_hsl_set_alpha (&hsl, 1.0);
|
||||
pika_hsl_to_rgb (&hsl, &rgb);
|
||||
pika_value_set_rgb (value, &rgb);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_operation_colorize_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaOperationColorize *self = PIKA_OPERATION_COLORIZE (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_HUE:
|
||||
self->hue = g_value_get_double (value);
|
||||
g_object_notify (object, "color");
|
||||
break;
|
||||
|
||||
case PROP_SATURATION:
|
||||
self->saturation = g_value_get_double (value);
|
||||
g_object_notify (object, "color");
|
||||
break;
|
||||
|
||||
case PROP_LIGHTNESS:
|
||||
self->lightness = g_value_get_double (value);
|
||||
g_object_notify (object, "color");
|
||||
break;
|
||||
|
||||
case PROP_COLOR:
|
||||
{
|
||||
PikaRGB rgb;
|
||||
PikaHSL hsl;
|
||||
|
||||
pika_value_get_rgb (value, &rgb);
|
||||
pika_rgb_to_hsl (&rgb, &hsl);
|
||||
|
||||
if (hsl.h == -1)
|
||||
hsl.h = self->hue;
|
||||
|
||||
if (hsl.l == 0.0 || hsl.l == 1.0)
|
||||
hsl.s = self->saturation;
|
||||
|
||||
g_object_set (self,
|
||||
"hue", hsl.h,
|
||||
"saturation", hsl.s,
|
||||
"lightness", hsl.l * 2.0 - 1.0,
|
||||
NULL);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_operation_colorize_process (GeglOperation *operation,
|
||||
void *in_buf,
|
||||
void *out_buf,
|
||||
glong samples,
|
||||
const GeglRectangle *roi,
|
||||
gint level)
|
||||
{
|
||||
PikaOperationColorize *colorize = PIKA_OPERATION_COLORIZE (operation);
|
||||
gfloat *src = in_buf;
|
||||
gfloat *dest = out_buf;
|
||||
PikaHSL hsl;
|
||||
|
||||
hsl.h = colorize->hue;
|
||||
hsl.s = colorize->saturation;
|
||||
|
||||
while (samples--)
|
||||
{
|
||||
PikaRGB rgb;
|
||||
gfloat lum = PIKA_RGB_LUMINANCE (src[RED],
|
||||
src[GREEN],
|
||||
src[BLUE]);
|
||||
|
||||
if (colorize->lightness > 0)
|
||||
{
|
||||
lum = lum * (1.0 - colorize->lightness);
|
||||
|
||||
lum += 1.0 - (1.0 - colorize->lightness);
|
||||
}
|
||||
else if (colorize->lightness < 0)
|
||||
{
|
||||
lum = lum * (colorize->lightness + 1.0);
|
||||
}
|
||||
|
||||
hsl.l = lum;
|
||||
|
||||
pika_hsl_to_rgb (&hsl, &rgb);
|
||||
|
||||
/* the code in base/colorize.c would multiply r,b,g with lum,
|
||||
* but this is a bug since it should multiply with 255. We
|
||||
* don't repeat this bug here (this is the reason why the gegl
|
||||
* colorize is brighter than the legacy one).
|
||||
*/
|
||||
dest[RED] = rgb.r; /* * lum */
|
||||
dest[GREEN] = rgb.g; /* * lum */
|
||||
dest[BLUE] = rgb.b; /* * lum */
|
||||
dest[ALPHA] = src[ALPHA];
|
||||
|
||||
src += 4;
|
||||
dest += 4;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user