[gegl] piecewise-blend: new op in common-cxx
- From: Ell <ell src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gegl] piecewise-blend: new op in common-cxx
- Date: Thu, 14 May 2020 21:50:45 +0000 (UTC)
commit 198f314813847b65f55159294d8badd93eee9345
Author: Ell <ell_se yahoo com>
Date: Thu May 14 21:38:51 2020 +0300
piecewise-blend: new op in common-cxx
Add a new gegl:piecewise-blend op, which takes a series of inputs
through "aux1".."aux16", and blends them based on a mask given
through "input". The inputs are spaced uniformly over the mask
range, and for each mask value, the two adjacent inputs are
interpolated.
operations/common-cxx/meson.build | 1 +
operations/common-cxx/piecewise-blend.cc | 306 +++++++++++++++++++++++++++++++
po/POTFILES.in | 1 +
3 files changed, 308 insertions(+)
---
diff --git a/operations/common-cxx/meson.build b/operations/common-cxx/meson.build
index d84a9d343..0a6ca2cb9 100644
--- a/operations/common-cxx/meson.build
+++ b/operations/common-cxx/meson.build
@@ -1,6 +1,7 @@
gegl_common_cxx_sources = files(
'distance-transform.cc',
+ 'piecewise-blend.cc',
'warp.cc',
)
diff --git a/operations/common-cxx/piecewise-blend.cc b/operations/common-cxx/piecewise-blend.cc
new file mode 100644
index 000000000..cadebbfd0
--- /dev/null
+++ b/operations/common-cxx/piecewise-blend.cc
@@ -0,0 +1,306 @@
+/* This file is an image processing operation for GEGL
+ *
+ * GEGL is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * GEGL 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GEGL; if not, see <https://www.gnu.org/licenses/>.
+ *
+ * Copyright (C) 2020 Ell
+ */
+
+#include "config.h"
+#include <glib/gi18n-lib.h>
+#include <math.h>
+#include <stdio.h>
+
+#define N_AUX_INPUTS 16
+
+#ifdef GEGL_PROPERTIES
+
+property_int (levels, _("Levels"), 0)
+ description (_("Number of blend levels"))
+ value_range (0, N_AUX_INPUTS)
+
+property_boolean (normalized_mask, _("Normalized mask"), TRUE)
+ description (_("Mask values are in the [0,1] range"))
+
+property_boolean (linear_mask, _("Linear mask"), TRUE)
+ description (_("Use linear mask values"))
+
+#else
+
+#define GEGL_OP_BASE
+#define GEGL_OP_NAME piecewise_blend
+#define GEGL_OP_C_SOURCE piecewise-blend.cc
+
+#include "gegl-op.h"
+
+static void
+attach (GeglOperation *operation)
+{
+ GParamSpec *pspec;
+ gint i;
+
+ pspec = g_param_spec_object ("output",
+ "Output",
+ "Output pad for generated image buffer.",
+ GEGL_TYPE_BUFFER,
+ (GParamFlags) (G_PARAM_READABLE |
+ GEGL_PARAM_PAD_OUTPUT));
+ gegl_operation_create_pad (operation, pspec);
+ g_param_spec_sink (pspec);
+
+ pspec = g_param_spec_object ("input",
+ "Input",
+ "Input pad, for image buffer input.",
+ GEGL_TYPE_BUFFER,
+ (GParamFlags) (G_PARAM_READABLE |
+ GEGL_PARAM_PAD_INPUT));
+ gegl_operation_create_pad (operation, pspec);
+ g_param_spec_sink (pspec);
+
+ for (i = 1; i <= N_AUX_INPUTS; i++)
+ {
+ gchar aux_name[32];
+ gchar aux_desc[32];
+
+ sprintf (aux_name, "aux%d", i);
+ sprintf (aux_desc, "Aux %d", i);
+
+ pspec = g_param_spec_object (aux_name,
+ aux_desc,
+ "Auxiliary image buffer input pad.",
+ GEGL_TYPE_BUFFER,
+ (GParamFlags) (G_PARAM_READABLE |
+ GEGL_PARAM_PAD_INPUT));
+ gegl_operation_create_pad (operation, pspec);
+ g_param_spec_sink (pspec);
+ }
+}
+
+static GeglRectangle
+get_bounding_box (GeglOperation *operation)
+{
+ GeglRectangle *in_rect;
+ GeglRectangle result = {};
+
+ in_rect = gegl_operation_source_get_bounding_box (operation, "input");
+
+ if (in_rect)
+ result = *in_rect;
+
+ return result;
+}
+
+static void
+prepare (GeglOperation *operation)
+{
+ GeglProperties *o = GEGL_PROPERTIES (operation);
+ const Babl *space;
+ const Babl *input_space;
+ const Babl *format;
+ const Babl *input_format;
+ gint i;
+
+ input_space = gegl_operation_get_source_space (operation, "input");
+ input_format = babl_format_with_space (o->linear_mask ? "Y float" :
+ "Y' float",
+ input_space);
+
+ space = gegl_operation_get_source_space (operation, "aux1");
+ format = babl_format_with_space ("RaGaBaA float", space);
+
+ gegl_operation_set_format (operation, "input", input_format);
+ gegl_operation_set_format (operation, "output", format);
+
+ for (i = 1; i <= N_AUX_INPUTS; i++)
+ {
+ gchar aux_name[32];
+
+ sprintf (aux_name, "aux%d", i);
+
+ gegl_operation_set_format (operation, aux_name, format);
+ }
+}
+
+static GeglRectangle
+get_required_for_output (GeglOperation *operation,
+ const gchar *input_pad,
+ const GeglRectangle *roi)
+{
+ GeglProperties *o = GEGL_PROPERTIES (operation);
+ GeglRectangle result = {};
+
+ if (! strcmp (input_pad, "input"))
+ {
+ result = *roi;
+ }
+ else if (g_str_has_prefix (input_pad, "aux"))
+ {
+ gint i = atoi (input_pad + 3);
+
+ if (i <= o->levels)
+ result = *roi;
+ }
+
+ return result;
+}
+
+static gboolean
+process (GeglOperation *operation,
+ GeglOperationContext *context,
+ const gchar *output_prop,
+ const GeglRectangle *result,
+ gint level)
+{
+ GeglProperties *o = GEGL_PROPERTIES (operation);
+ GeglBuffer *input;
+ GeglBuffer *output;
+ const Babl *format;
+ const Babl *input_format;
+ gfloat scale;
+ gint levels;
+
+ levels = o->levels;
+
+ if (o->normalized_mask)
+ scale = levels - 1.0f;
+ else
+ scale = 1.0f;
+
+ if (levels == 0)
+ {
+ return TRUE;
+ }
+ else if (levels == 1)
+ {
+ gegl_operation_context_set_object (
+ context, "output",
+ gegl_operation_context_get_object (context, "aux1"));
+
+ return TRUE;
+ }
+
+ format = gegl_operation_get_format (operation, "output");
+ input_format = gegl_operation_get_format (operation, "input");
+
+ input = GEGL_BUFFER (gegl_operation_context_get_object (context, "input"));
+ output = gegl_operation_context_get_output_maybe_in_place (operation,
+ context,
+ input,
+ result);
+
+ gegl_parallel_distribute_area (
+ result, gegl_operation_get_pixels_per_thread (operation),
+ [=] (const GeglRectangle *area)
+ {
+ GeglBuffer *empty_buffer = NULL;
+ GeglBufferIterator *iter;
+ gint i;
+
+ iter = gegl_buffer_iterator_new (output, area, level, format,
+ GEGL_ACCESS_WRITE, GEGL_ABYSS_NONE,
+ 2 + levels);
+
+ gegl_buffer_iterator_add (iter, input, area, level, input_format,
+ GEGL_ACCESS_READ, GEGL_ABYSS_NONE);
+
+ for (i = 1; i <= levels; i++)
+ {
+ GeglBuffer *aux;
+ gchar aux_name[32];
+
+ sprintf (aux_name, "aux%d", i);
+
+ aux = GEGL_BUFFER (gegl_operation_context_get_object (context,
+ aux_name));
+
+ if (! aux)
+ {
+ if (! empty_buffer)
+ {
+ empty_buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0, 0, 0),
+ format);
+ }
+
+ aux = empty_buffer;
+ }
+
+ gegl_buffer_iterator_add (iter, aux, area, level, format,
+ GEGL_ACCESS_READ, GEGL_ABYSS_NONE);
+ }
+
+ while (gegl_buffer_iterator_next (iter))
+ {
+ gfloat *out = ( gfloat *) iter->items[0].data;
+ const gfloat *in = (const gfloat *) iter->items[1].data;
+ gint i;
+
+ for (i = 0; i < iter->length; i++)
+ {
+ const gfloat *aux1;
+ const gfloat *aux2;
+ gfloat v;
+ gint j;
+ gint c;
+
+ v = *in * scale;
+
+ v = v > 0.0f ? v < scale ? v : scale : 0.0f;
+
+ j = (gint) v;
+ j = MIN (j, levels - 2);
+
+ v -= j;
+
+ aux1 = (const gfloat *) iter->items[2 + j ].data + 4 * i;
+ aux2 = (const gfloat *) iter->items[2 + j + 1].data + 4 * i;
+
+ for (c = 0; c < 4; c++)
+ out[c] = aux1[c] + v * (aux2[c] - aux1[c]);
+
+ out += 4;
+ in++;
+ }
+ }
+
+ g_clear_object (&empty_buffer);
+ });
+
+ return TRUE;
+}
+
+static void
+gegl_op_class_init (GeglOpClass *klass)
+{
+ GeglOperationClass *operation_class;
+
+ operation_class = GEGL_OPERATION_CLASS (klass);
+
+ operation_class->attach = attach;
+ operation_class->get_bounding_box = get_bounding_box;
+ operation_class->prepare = prepare;
+ operation_class->get_required_for_output = get_required_for_output;
+ operation_class->get_invalidated_by_change = get_required_for_output;
+ operation_class->process = process;
+
+ operation_class->threaded = TRUE;
+ operation_class->want_in_place = TRUE;
+
+ gegl_operation_class_set_keys (operation_class,
+ "name", "gegl:piecewise-blend",
+ "title", _("Piecewise Blend"),
+ "categories", "blend",
+ "description", _("Blend a chain of inputs using a mask"),
+ NULL);
+}
+
+#endif
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 084c98153..fe0b95a2c 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -126,6 +126,7 @@ operations/common/wavelet-blur.c
operations/common/weighted-blend.c
operations/common/write-buffer.c
operations/common-cxx/distance-transform.cc
+operations/common-cxx/piecewise-blend.cc
operations/common-cxx/warp.cc
operations/common-gpl3+/antialias.c
operations/common-gpl3+/apply-lens.c
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]