Initial checkin of Pika from heckimp

This commit is contained in:
2023-09-25 15:35:21 -07:00
commit 891e999216
6761 changed files with 5240685 additions and 0 deletions

View 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,
],
)

View 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;
}

View 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
*
* 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__ */

View 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;
}

View 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__ */

View 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
*
* 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;
}

View 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
*
* 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__ */

View 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
*
* 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;
}

View 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
*
* 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__ */

View 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;
}

View 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
*
* 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__ */

View 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;
}

View 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__ */

View 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
*
* 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;
}

View 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
*
* 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__ */

View 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
*
* 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;
}

View 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
*
* 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__ */

View 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;
}

View 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
*
* 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__ */

View 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;
}

View 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
*
* 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__ */

View 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;
}

View 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
*
* 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__ */

View 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
*
* 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;
}

View 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
*
* 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__ */

View 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;
}

View 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
*
* 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__ */

View 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
*
* 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;
}

View 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
*
* 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__ */

View 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;
}

View 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
*
* 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__ */

View 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;
}

View 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
*
* 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__ */

View 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;
}

View 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
*
* 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__ */

View 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;
}

View 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
*
* 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__ */

View 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,
],
)

File diff suppressed because it is too large Load Diff

View 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__ */

View 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;
}

View 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__ */

View 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;
}

View 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__ */

View 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;
}

View 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__ */

View 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;
}

View 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__ */

File diff suppressed because it is too large Load Diff

View 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__ */

View File

@ -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 */

View 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++;
}
}

View 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__ */

View 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;
}

View 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__ */

View 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;
}

View 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__ */

View 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 */

View 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 */

View 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;
}

View 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__ */

View 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)
{
}

View 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__ */

View 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;
}

View 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__ */

View 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;
}

View 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__ */

View 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')

View 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 */

View 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__ */

View 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__ */

View 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);
}
}

View 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__ */

View 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 ();
}

View 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__ */

View 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;
}

View 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__ */

View 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;
}

View 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__ */

View 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));
}

View 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__ */

View 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;
}

View 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__ */

View 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));
}

View 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__ */

View 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;
}

View 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__ */

View 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;
}

View 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__ */

View 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;
}

View 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__ */

View 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);
}

View 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__ */

View 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;
}

View 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__ */

View 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;
}

View 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__ */

View 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;
}

View 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__ */

View 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