[gegl] color-to-alpha-plus: add new op to workshop
- From: N/A <ell src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gegl] color-to-alpha-plus: add new op to workshop
- Date: Mon, 16 Oct 2017 16:38:31 +0000 (UTC)
commit cdc1fdd4886d31ea77ebbc4ba687a7a525aa7bc6
Author: Ell <ell_se yahoo com>
Date: Mon Oct 16 11:20:22 2017 -0400
color-to-alpha-plus: add new op to workshop
color-to-alpha-plus is an extension of color-to-alpha, introducing
a pair of properties controlling the range of colors whose alpha is
modified:
- transparency-threshold, controls the radius around the selected
color, below which colors become fully transparent.
- opacity-threshold, controls the radius around the selected
color, above which colors remain fully opaque.
Colors between transparency-threshold and opacity-threshold become
partially transparent.
When transparency-threshold is 0 and opacity-threshold is 1, which
is the default configuration, the result is the same as that of
color-to-alpha. The plan is to eventually merge the new
functionality into color-to-alpha, not to add a new op.
operations/workshop/Makefile.am | 1 +
operations/workshop/color-to-alpha-plus.c | 234 +++++++++++++++++++++++++++++
po/POTFILES.in | 1 +
3 files changed, 236 insertions(+), 0 deletions(-)
---
diff --git a/operations/workshop/Makefile.am b/operations/workshop/Makefile.am
index 6f2ba29..df12c92 100644
--- a/operations/workshop/Makefile.am
+++ b/operations/workshop/Makefile.am
@@ -12,6 +12,7 @@ opdir = $(ext_dir)
op_LTLIBRARIES = \
bayer-matrix.la \
bilateral-filter-fast.la \
+ color-to-alpha-plus.la \
demosaic-bimedian.la \
demosaic-simple.la \
ditto.la \
diff --git a/operations/workshop/color-to-alpha-plus.c b/operations/workshop/color-to-alpha-plus.c
new file mode 100644
index 0000000..11a6e51
--- /dev/null
+++ b/operations/workshop/color-to-alpha-plus.c
@@ -0,0 +1,234 @@
+/* This file is an image processing operation for GEGL
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Color To Alpha plug-in v1.0 by Seth Burgess, sjburges gimp org 1999/05/14
+ * with algorithm by clahey
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ * Copyright (C) 2011 Robert Sasu <sasu robert gmail com>
+ * Copyright (C) 2012 Øyvind Kolås <pippin gimp org>
+ * Copyright (C) 2017 Ell
+ */
+
+#include "config.h"
+#include <glib/gi18n-lib.h>
+
+#ifdef GEGL_PROPERTIES
+
+property_color (color, _("Color"), "white")
+ description(_("The color to make transparent."))
+
+property_double (transparency_threshold, _("Transparency threshold"), 0.0)
+ description(_("The limit below which colors become transparent."))
+ value_range (0.0, 1.0)
+
+property_double (opacity_threshold, _("Opacity threshold"), 1.0)
+ description(_("The limit above which colors remain opaque."))
+ value_range (0.0, 1.0)
+
+#else
+
+#define GEGL_OP_POINT_FILTER
+#define GEGL_OP_NAME color_to_alpha_plus
+#define GEGL_OP_C_SOURCE color-to-alpha-plus.c
+
+#include "gegl-op.h"
+#include <stdio.h>
+#include <math.h>
+
+#define EPSILON 0.00001
+
+static void
+prepare (GeglOperation *operation)
+{
+ gegl_operation_set_format (operation, "input",
+ babl_format ("R'G'B'A float"));
+ gegl_operation_set_format (operation, "output",
+ babl_format ("R'G'B'A float"));
+}
+
+/*
+ * An excerpt from a discussion on #gimp that sheds some light on the ideas
+ * behind the algorithm that is being used here.
+ *
+ <clahey> so if a1 > c1, a2 > c2, and a3 > c2 and a1 - c1 > a2-c2, a3-c3,
+ then a1 = b1 * alpha + c1 * (1-alpha)
+ So, maximizing alpha without taking b1 above 1 gives
+ a1 = alpha + c1(1-alpha) and therefore alpha = (a1-c1) / (1-c1).
+ <sjburges> clahey: btw, the ordering of that a2, a3 in the white->alpha didn't
+ matter
+ <clahey> sjburges: You mean that it could be either a1, a2, a3 or
+ a1, a3, a2?
+ <sjburges> yeah
+ <sjburges> because neither one uses the other
+ <clahey> sjburges: That's exactly as it should be. They are both just
+ getting reduced to the same amount, limited by the the darkest
+ color.
+ <clahey> Then a2 = b2 * alpha + c2 * (1- alpha). Solving for b2 gives
+ b2 = (a1-c2)/alpha + c2.
+ <sjburges> yeah
+ <clahey> That gives us are formula for if the background is darker than the
+ foreground? Yep.
+ <clahey> Next if a1 < c1, a2 < c2, a3 < c3, and c1-a1 > c2-a2, c3-a3, and
+ by our desired result a1 = b1 * alpha + c1 * (1-alpha),
+ we maximize alpha without taking b1 negative gives
+ alpha = 1 - a1 / c1.
+ <clahey> And then again, b2 = (a2-c2) / alpha + c2 by the same formula.
+ (Actually, I think we can use that formula for all cases, though
+ it may possibly introduce rounding error.
+ <clahey> sjburges: I like the idea of using floats to avoid rounding error.
+ Good call.
+*/
+
+static void
+color_to_alpha (const gfloat *color,
+ const gfloat *src,
+ gfloat *dst,
+ gfloat transparency_radius,
+ gfloat opacity_radius)
+{
+ gint i;
+ gfloat dist = 0.0f;
+ gfloat alpha = 0.0f;
+
+ for (i = 0; i < 4; i++)
+ dst[i] = src[i];
+
+ for (i = 0; i < 3; i++)
+ {
+ gfloat d;
+ gfloat a;
+
+ d = fabsf (dst[i] - color[i]);
+
+ if (d < transparency_radius + EPSILON)
+ a = 0.0f;
+ else if (d > opacity_radius - EPSILON)
+ a = 1.0f;
+ else if (dst[i] < color[i])
+ a = (d - transparency_radius) / (MIN (opacity_radius, color[i]) - transparency_radius);
+ else
+ a = (d - transparency_radius) / (MIN (opacity_radius, 1.0f - color[i]) - transparency_radius);
+
+ if (a > alpha)
+ {
+ alpha = a;
+ dist = d;
+ }
+ }
+
+ if (alpha > EPSILON)
+ {
+ gfloat ratio = transparency_radius / dist;
+ gfloat alpha_inv = 1.0f / alpha;
+
+ for (i = 0; i < 3; i++)
+ {
+ gfloat c;
+
+ c = color[i] + (dst[i] - color[i]) * ratio;
+
+ dst[i] = c + (dst[i] - c) * alpha_inv;
+ }
+ }
+
+ dst[3] *= alpha;
+}
+
+static gboolean
+process (GeglOperation *operation,
+ void *in_buf,
+ void *out_buf,
+ glong n_pixels,
+ const GeglRectangle *roi,
+ gint level)
+{
+ GeglProperties *o = GEGL_PROPERTIES (operation);
+ const Babl *format = babl_format ("R'G'B'A float");
+ gfloat color[4];
+ gfloat radius = 0.0;
+ gfloat transparency_radius;
+ gfloat opacity_radius;
+ gint i;
+ gint x;
+
+ gfloat *in_buff = in_buf;
+ gfloat *out_buff = out_buf;
+
+ gegl_color_get_pixel (o->color, format, color);
+
+ for (i = 0; i < 3; i++)
+ radius = MAX (radius, MAX (color[i], 1.0 - color[i]));
+
+ transparency_radius = radius * o->transparency_threshold;
+ opacity_radius = radius * o->opacity_threshold;
+
+ for (x = 0; x < n_pixels; x++)
+ {
+ color_to_alpha (color, in_buff, out_buff,
+ transparency_radius, opacity_radius);
+ in_buff += 4;
+ out_buff += 4;
+ }
+
+ return TRUE;
+}
+
+static void
+gegl_op_class_init (GeglOpClass *klass)
+{
+ GeglOperationClass *operation_class;
+ GeglOperationPointFilterClass *filter_class;
+ gchar *composition =
+ "<?xml version='1.0' encoding='UTF-8'?>"
+ "<gegl>"
+ "<node operation='svg:dst-over'>"
+ " <node operation='gegl:crop'>"
+ " <params>"
+ " <param name='width'>200.0</param>"
+ " <param name='height'>200.0</param>"
+ " </params>"
+ " </node>"
+ " <node operation='gegl:checkerboard'>"
+ " <params><param name='color1'>rgb(0.5, 0.5, 0.5)</param></params>"
+ " </node>"
+ "</node>"
+ "<node operation='gegl:color-to-alpha-plus'>"
+ "</node>"
+ "<node operation='gegl:load'>"
+ " <params>"
+ " <param name='path'>standard-input.png</param>"
+ " </params>"
+ "</node>"
+ "</gegl>";
+
+ operation_class = GEGL_OPERATION_CLASS (klass);
+ filter_class = GEGL_OPERATION_POINT_FILTER_CLASS (klass);
+
+ filter_class->process = process;
+
+ operation_class->prepare = prepare;
+
+ gegl_operation_class_set_keys (operation_class,
+ "name", "gegl:color-to-alpha-plus",
+ "title", _("Color to Alpha +"),
+ "categories", "color",
+ "license", "GPL3+",
+ "reference-hash", "f110613097308e0fe96ac29f54ca4c2e",
+ "description", _("Convert a specified color to transparency, works best with white."),
+ "reference-composition", composition,
+ NULL);
+}
+
+#endif
diff --git a/po/POTFILES.in b/po/POTFILES.in
index b8c3b29..c9b07bc 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -231,6 +231,7 @@ operations/transform/transform-core.c
operations/transform/translate.c
operations/workshop/bayer-matrix.c
operations/workshop/bilateral-filter-fast.c
+operations/workshop/color-to-alpha-plus.c
operations/workshop/demosaic-bimedian.c
operations/workshop/demosaic-simple.c
operations/workshop/ditto.c
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]