[gegl] ops/workshop: add ink simulator
- From: Øyvind Kolås <ok src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gegl] ops/workshop: add ink simulator
- Date: Fri, 14 Mar 2014 01:31:37 +0000 (UTC)
commit fa2e739bfa6dbb795b45cf90ecf4dc837f8158c0
Author: Øyvind Kolås <pippin gimp org>
Date: Fri Mar 14 02:28:11 2014 +0100
ops/workshop: add ink simulator
Initial sketch of a spectral proofing filter.
operations/workshop/Makefile.am | 1 +
operations/workshop/ink-simulator.c | 370 +++++++++++++++++++++++++++++++++++
2 files changed, 371 insertions(+), 0 deletions(-)
---
diff --git a/operations/workshop/Makefile.am b/operations/workshop/Makefile.am
index 8457d6e..c259a31 100644
--- a/operations/workshop/Makefile.am
+++ b/operations/workshop/Makefile.am
@@ -23,6 +23,7 @@ op_LTLIBRARIES = \
gaussian-blur-iir.la \
gblur-1d.la \
hstack.la \
+ ink-simulator.la \
kuwahara.la \
mandelbrot.la \
rawbayer-load.la \
diff --git a/operations/workshop/ink-simulator.c b/operations/workshop/ink-simulator.c
new file mode 100644
index 0000000..a31c284
--- /dev/null
+++ b/operations/workshop/ink-simulator.c
@@ -0,0 +1,370 @@
+/* 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 <http://www.gnu.org/licenses/>.
+ *
+ * Copyright 2014 Øyvind Kolås <pippin gimp org>
+ */
+
+#include "config.h"
+#include <glib/gi18n-lib.h>
+
+#ifdef GEGL_CHANT_PROPERTIES
+
+#define DEFAULT_INKS \
+"illuminant = 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\n" \
+"substrate = white\n" \
+"ink1 = cyan\n"\
+"ink2 = yellow\n"\
+"ink3 = magenta\n"\
+"ink4 = black opaque\n"
+
+gegl_chant_multiline (config, _("ink configuration"), DEFAULT_INKS,
+ _("Textual desciption of inks passed in"))
+
+#else
+
+#define GEGL_CHANT_TYPE_POINT_FILTER
+#define GEGL_CHANT_C_FILE "ink-simulator.c"
+
+#include "gegl-chant.h"
+
+#define SPECTRUM_BANDS 20
+
+typedef struct _Spectrum Spectrum;
+struct _Spectrum {
+ float bands[SPECTRUM_BANDS];
+ /* 20 bands, spaced as follows :
+ *
+ * 0 = 390 - 405nm
+ * 1 = 410 - 425nm
+ * ....
+ */
+};
+
+/* from http://cvrl.ucl.ac.uk/cones.htm */
+static Spectrum STANDARD_OBSERVER_L = {{
+0.002177, 0.0158711, 0.03687185, 0.06265, 0.13059, 0.26828, 0.57836, 0.849104, 0.9704655, 0.9793335,
0.85568175, 0.59266275, 0.30191075, 0.11285, 0.032197, 0.007657, 0.0017424, 0.0004039, 0.000009, 0.000002
+}};
+static Spectrum STANDARD_OBSERVER_M = {{
+0.00207, 0.01863, 0.057983, 0.11151, 0.221277, 0.4010105, 0.75920, 0.97423, 0.93118, 0.694917, 0.37578,
0.14093, 0.03995, 0.0096, 0.002, 0.0004, 0.0001095,
+ 0.0000026, 0
+}};
+static Spectrum STANDARD_OBSERVER_S = {{
+ 0.05312, 0.45811575, 0.9226575, 0.83515125, 0.46085625, 0.146032125, 0.03805695, 0.00723844, 0.0010894,
0.000158823, 0.0000025, 0.000000336, 0
+}};
+
+/* Better reflectances for this sure would be nice */
+#define REFLECTANCE_CYAN {{1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0}}
+#define REFLECTANCE_MAGENTA {{1,1,1,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0}}
+#define REFLECTANCE_YELLOW {{0,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0}}
+#define REFLECTANCE_RED {{0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0}}
+#define REFLECTANCE_GREEN {{0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0}}
+#define REFLECTANCE_BLUE {{0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}}
+#define REFLECTANCE_BLACK {{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}}
+#define REFLECTANCE_GRAY
{{0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5}}
+#define REFLECTANCE_WHITE {{0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}}
+#define ILLUMINANT_E REFLECTANCE_WHITE
+
+/* the even illuminant; which is easy and almost cheating */
+static Spectrum ILLUMINANT = ILLUMINANT_E;
+static Spectrum SUBSTRATE_REFLECTANCE = REFLECTANCE_WHITE;
+
+static int inks = 3;
+static Spectrum INK_REFLECTANCE_INK1 = REFLECTANCE_GREEN;
+static Spectrum INK_REFLECTANCE_INK2 = REFLECTANCE_BLACK;
+static Spectrum INK_REFLECTANCE_INK3 = REFLECTANCE_YELLOW;
+static Spectrum INK_REFLECTANCE_INK4 = REFLECTANCE_WHITE;
+static Spectrum INK_REFLECTANCE_INK5 = REFLECTANCE_WHITE;
+static int ink1_opaque = 0;
+static int ink2_opaque = 0;
+static int ink3_opaque = 0;
+static int ink4_opaque = 0;
+static int ink5_opaque = 0;
+
+
+static Spectrum spectrum_remove_light (Spectrum s, Spectrum ink, float factor)
+{
+ int i;
+ for (i = 0; i < SPECTRUM_BANDS; i++)
+ {
+ s.bands[i] = s.bands[i] * (1.0 - factor) +
+ s.bands[i] * ink.bands[i] * factor;
+ }
+ return s;
+}
+
+static Spectrum spectrum_add_color (Spectrum s, Spectrum ink, float factor)
+{
+ int i;
+ for (i = 0; i < SPECTRUM_BANDS; i++)
+ {
+ s.bands[i] = s.bands[i] * (1.0 - factor) + ink.bands[i] * factor;
+ }
+ return s;
+}
+
+static float spectrum_observed_l (Spectrum s)
+{
+ float result = 0.0;
+ int i;
+ for (i = 0; i < SPECTRUM_BANDS; i++)
+ result += s.bands[i] * STANDARD_OBSERVER_L.bands[i];
+ return (result / SPECTRUM_BANDS) * 3;
+}
+
+static float spectrum_observed_m (Spectrum s)
+{
+ float result = 0.0;
+ int i;
+ for (i = 0; i < SPECTRUM_BANDS; i++)
+ result += s.bands[i] * STANDARD_OBSERVER_M.bands[i];
+ return (result / SPECTRUM_BANDS) * 3;
+}
+
+static float spectrum_observed_s (Spectrum s)
+{
+ float result = 0.0;
+ int i;
+ for (i = 0; i < SPECTRUM_BANDS; i++)
+ result += s.bands[i] * STANDARD_OBSERVER_S.bands[i];
+ return (result / SPECTRUM_BANDS) * 3;
+}
+
+static void parse_config (GeglOperation *operation);
+
+static void
+prepare (GeglOperation *operation)
+{
+
+ /* this RGBA float is interpreted as CMYK ! */
+ gegl_operation_set_format (operation, "input", babl_format ("RGBA float"));
+
+ gegl_operation_set_format (operation, "output", babl_format ("RGB float"));
+
+
+ parse_config (operation);
+}
+
+static gboolean
+process (GeglOperation *op,
+ void *in_buf,
+ void *out_buf,
+ glong samples,
+ const GeglRectangle *roi,
+ gint level)
+{
+ gfloat *in = in_buf;
+ gfloat *out = out_buf;
+
+ while (samples--)
+ {
+ Spectrum spec = ILLUMINANT;
+ float l, m, s;
+
+ spec = spectrum_remove_light (spec, SUBSTRATE_REFLECTANCE, 1.0);
+ if (inks >=1)
+ {
+ if (ink1_opaque)
+ spec = spectrum_add_color (spec, INK_REFLECTANCE_INK1, in[0]);
+ else
+ spec = spectrum_remove_light (spec, INK_REFLECTANCE_INK1, in[0]);
+ }
+ if (inks >=2)
+ {
+ if (ink2_opaque)
+ spec = spectrum_add_color (spec, INK_REFLECTANCE_INK2, in[1]);
+ else
+ spec = spectrum_remove_light (spec, INK_REFLECTANCE_INK2, in[1]);
+ }
+ if (inks >=3)
+ {
+ if (ink3_opaque)
+ spec = spectrum_add_color (spec, INK_REFLECTANCE_INK3, in[2]);
+ else
+ spec = spectrum_remove_light (spec, INK_REFLECTANCE_INK3, in[2]);
+ }
+ if (inks >=4)
+ {
+ if (ink4_opaque)
+ spec = spectrum_add_color (spec, INK_REFLECTANCE_INK4, in[3]);
+ else
+ spec = spectrum_remove_light (spec, INK_REFLECTANCE_INK4, in[3]);
+ }
+
+ l = spectrum_observed_l (spec) /6;
+ m = spectrum_observed_m (spec) /6;
+ s = spectrum_observed_s (spec) /6;
+
+ /* this LMS to linear RGB -- likely no right.. */
+
+ out[0] = ((30.83) * l + (-29.83) * m + (1.61) * s);
+ out[1] = ((-6.481) * l + (17.7155) * m + (-2.532) * s);
+ out[2] = ((-0.375) * l + (-1.19906) * m + (14.27) * s);
+
+
+ in += 4;
+ out += 3;
+ }
+ return TRUE;
+}
+
+
+static Spectrum parse_spectrum (gchar *spectrum)
+{
+ Spectrum s = REFLECTANCE_WHITE;
+ if (!spectrum)
+ return s;
+ while (*spectrum == ' ') spectrum ++;
+
+ if (g_str_has_prefix (spectrum, "red"))
+ { Spectrum color = REFLECTANCE_RED; s = color;
+ } else if (g_str_has_prefix (spectrum, "green"))
+ { Spectrum color = REFLECTANCE_GREEN; s = color;
+ } else if (g_str_has_prefix (spectrum, "blue"))
+ { Spectrum color = REFLECTANCE_BLUE; s = color;
+ } else if (g_str_has_prefix (spectrum, "cyan"))
+ { Spectrum color = REFLECTANCE_CYAN; s = color;
+ } else if (g_str_has_prefix (spectrum, "yellow"))
+ { Spectrum color = REFLECTANCE_YELLOW; s = color;
+ } else if (g_str_has_prefix (spectrum, "magenta"))
+ { Spectrum color = REFLECTANCE_MAGENTA; s = color;
+ } else if (g_str_has_prefix (spectrum, "white"))
+ { Spectrum color = REFLECTANCE_WHITE; s = color;
+ } else if (g_str_has_prefix (spectrum, "black"))
+ { Spectrum color = REFLECTANCE_BLACK; s = color;
+ } else if (g_str_has_prefix (spectrum, "gray"))
+ { Spectrum color = REFLECTANCE_GRAY; s = color;
+ } else
+ {
+ int band = 0;
+ band = 0;
+ do {
+ s.bands[band++] = g_strtod (spectrum, &spectrum);
+ } while (spectrum && band < SPECTRUM_BANDS);
+ }
+
+ return s;
+}
+
+static void parse_config_line (GeglOperation *operation,
+ const char *line)
+{
+ Spectrum s;
+ if (!line)
+ return;
+
+ if (!strchr (line, '='))
+ return;
+
+ while (*line == ' ') line++;
+
+ s = parse_spectrum (strchr (line, '=') + 1);
+
+ inks = 0;
+
+ if (g_str_has_prefix (line, "illuminant"))
+ ILLUMINANT = s;
+ else if (g_str_has_prefix (line, "substrate"))
+ SUBSTRATE_REFLECTANCE = s;
+ else if (g_str_has_prefix (line, "ink1"))
+ {
+ INK_REFLECTANCE_INK1 = s;
+ if (strstr(line, "opaque"))
+ ink1_opaque = 1;
+ inks = MAX(inks, 1);
+ }
+ else if (g_str_has_prefix (line, "ink2"))
+ {
+ INK_REFLECTANCE_INK2 = s;
+ inks = MAX(inks, 2);
+ if (strstr(line, "opaque"))
+ ink2_opaque = 2;
+ }
+ else if (g_str_has_prefix (line, "ink3"))
+ {
+ INK_REFLECTANCE_INK3 = s;
+ inks = MAX(inks, 3);
+ if (strstr(line, "opaque"))
+ ink3_opaque = 3;
+ }
+ else if (g_str_has_prefix (line, "ink4"))
+ {
+ INK_REFLECTANCE_INK4 = s;
+ inks = MAX(inks, 4);
+ if (strstr(line, "opaque"))
+ ink4_opaque = 4;
+ }
+}
+
+static void parse_config (GeglOperation *operation)
+{
+ GeglChantO *o = GEGL_CHANT_PROPERTIES (operation);
+ const char *p = o->config;
+ GString *str;
+
+ if (!p)
+ return;
+
+ memset (&INK_REFLECTANCE_INK1, 0, sizeof (INK_REFLECTANCE_INK1));
+ memset (&INK_REFLECTANCE_INK2, 0, sizeof (INK_REFLECTANCE_INK2));
+ memset (&INK_REFLECTANCE_INK3, 0, sizeof (INK_REFLECTANCE_INK3));
+ memset (&INK_REFLECTANCE_INK4, 0, sizeof (INK_REFLECTANCE_INK4));
+ memset (&INK_REFLECTANCE_INK5, 0, sizeof (INK_REFLECTANCE_INK5));
+ ink1_opaque = 0;
+ ink2_opaque = 0;
+ ink3_opaque = 0;
+ ink4_opaque = 0;
+ ink5_opaque = 0;
+
+ str = g_string_new ("");
+ while (*p)
+ {
+ switch (*p)
+ {
+ case '\n':
+ parse_config_line (operation, str->str);
+ g_string_assign (str, "");
+ break;
+ default:
+ g_string_append_c (str, *p);
+ break;
+ }
+ p++;
+ }
+
+ g_string_free (str, TRUE);
+}
+
+static void
+gegl_chant_class_init (GeglChantClass *klass)
+{
+ GeglOperationClass *operation_class;
+ GeglOperationPointFilterClass *point_filter_class;
+
+ operation_class = GEGL_OPERATION_CLASS (klass);
+ point_filter_class = GEGL_OPERATION_POINT_FILTER_CLASS (klass);
+
+ point_filter_class->process = process;
+ operation_class->prepare = prepare;
+
+ gegl_operation_class_set_keys (operation_class,
+ "name" , "gegl:ink-simulator",
+ "categories" , "misc",
+ "description" ,
+ _("spectral ink simulator, for softproofing/simulating press inks"
+ ""),
+ NULL);
+}
+
+#endif
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]