[gegl] ink-simulator: added stochastic ink separator
- From: Øyvind Kolås <ok src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gegl] ink-simulator: added stochastic ink separator
- Date: Fri, 21 Mar 2014 00:32:46 +0000 (UTC)
commit 56272dc5bd3b0c773724d84152bbe1dbd26acf5c
Author: Øyvind Kolås <pippin gimp org>
Date: Wed Mar 19 06:22:13 2014 +0100
ink-simulator: added stochastic ink separator
operations/workshop/ink-simulator.c | 300 +++++++++++++++++++++++-----------
1 files changed, 203 insertions(+), 97 deletions(-)
---
diff --git a/operations/workshop/ink-simulator.c b/operations/workshop/ink-simulator.c
index 8155a1f..784ebbf 100644
--- a/operations/workshop/ink-simulator.c
+++ b/operations/workshop/ink-simulator.c
@@ -22,16 +22,25 @@
#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 s=3\n"\
-"ink2 = magenta s=3\n"\
-"ink3 = yellow s=2\n"\
-"ink4 = black s=1\n"
+"illuminant=1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\n" \
+"substrate= rgb 0.98 0.98 0.98 \n" \
+"ink1=cyan s=1.5\n"\
+"ink2=magenta s=1.5\n"\
+"ink3=yellow s=1.5\n"\
+"ink4=black s=1\n"\
+"inklimit=150\n"
+
+gegl_chant_register_enum (ink_sim_mode)
+ enum_value (GEGL_INK_SIMULATOR_PROOF, "simulate printing of inks")
+ enum_value (GEGL_INK_SIMULATOR_SEPARATE, "separate to inks")
+ enum_value (GEGL_INK_SIMULATOR_SEPARATE_PROOF, "separate and simulate")
+gegl_chant_register_enum_end (GeglInkSimMode)
gegl_chant_multiline (config, _("ink configuration"), DEFAULT_INKS,
_("Textual desciption of inks passed in"))
+gegl_chant_enum (mode, _("mode"), GeglInkSimMode, ink_sim_mode, GEGL_INK_SIMULATOR_SEPARATE_PROOF, _("how
the ink simulator is used"))
+
#else
#define GEGL_CHANT_TYPE_POINT_FILTER
@@ -41,7 +50,11 @@ gegl_chant_multiline (config, _("ink configuration"), DEFAULT_INKS,
#define SPECTRUM_BANDS 20
+typedef struct _Config Config;
+typedef struct _Ink Ink;
typedef struct _Spectrum Spectrum;
+
+
struct _Spectrum {
float bands[SPECTRUM_BANDS];
/* 20 bands, spaced as follows :
@@ -52,6 +65,22 @@ struct _Spectrum {
*/
};
+struct _Ink {
+ Spectrum transmittance; /* spectral energy of this ink; as reflected of a fully reflective background */
+ float opacity; /* how much this ink covers up instead of mixes with background (substrate+inks) */
+ float scale; /* scale factor; increasing the amount of spectral contribution */
+};
+
+struct _Config {
+ Spectrum illuminant;
+ Spectrum substrate;
+ Ink ink_def[4];
+ float ink_limit;
+ int inks;
+};
+
+static Config config;
+
/* 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
@@ -80,20 +109,11 @@ static Spectrum STANDARD_OBSERVER_S = {{
#define ILLUMINANT_E TRANSMITTANCE_WHITE
/* the even illuminant; which is easy and almost cheating */
-static Spectrum ILLUMINANT = ILLUMINANT_E;
-static Spectrum SUBSTRATE_TRANSMITTANCE = TRANSMITTANCE_WHITE;
-
-static int inks = 3;
-static Spectrum INK_TRANSMITTANCE_INK1 = TRANSMITTANCE_GREEN;
-static Spectrum INK_TRANSMITTANCE_INK2 = TRANSMITTANCE_BLACK;
-static Spectrum INK_TRANSMITTANCE_INK3 = TRANSMITTANCE_YELLOW;
-static Spectrum INK_TRANSMITTANCE_INK4 = TRANSMITTANCE_WHITE;
-static Spectrum INK_TRANSMITTANCE_INK5 = TRANSMITTANCE_WHITE;
-static float ink1_opacity = 0;
-static float ink2_opacity = 0;
-static float ink3_opacity = 0;
-static float ink4_opacity = 0;
-static float ink5_opacity = 0;
+
+//static int inks = 3;
+//static Ink ink_defs[4] = {{{{0}}}};
+//static Spectrum ILLUMINANT = ILLUMINANT_E;
+//static Spectrum SUBSTRATE_TRANSMITTANCE = TRANSMITTANCE_WHITE;
static inline Spectrum add_ink (Spectrum s, Spectrum ink, float coverage, float opacity)
{
@@ -109,7 +129,12 @@ static inline Spectrum add_ink (Spectrum s, Spectrum ink, float coverage, float
static Spectrum spectrum_remove_light (Spectrum s, Spectrum ink, float coverage)
{
- return add_ink (s, ink, coverage, 0.0);
+ int i;
+ for (i = 0; i < SPECTRUM_BANDS; i++)
+ {
+ s.bands[i] = s.bands[i] * (1.0 - coverage) + s.bands[i] * ink.bands[i] * coverage;
+ }
+ return s;
}
static float spectrum_integrate (Spectrum s, Spectrum is, float scale)
@@ -126,16 +151,93 @@ 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"));
-
+ gegl_operation_set_format (operation, "output", babl_format ("RGBA float"));
parse_config (operation);
}
-static float ink_scale[4] = {1,1,1,1};
+static inline void spectrum_to_rgba (Spectrum spec, float *rgba)
+{
+ float l, m, s;
+ l = spectrum_integrate (spec, STANDARD_OBSERVER_L, 0.4);
+ m = spectrum_integrate (spec, STANDARD_OBSERVER_M, 0.4);
+ s = spectrum_integrate (spec, STANDARD_OBSERVER_S, 0.4);
+ /* this LMS to linear RGB -- likely not right.. */
+ rgba[0] = ((30.83) * l + (-29.83) * m + (1.61) * s);
+ rgba[1] = ((-6.481) * l + (17.7155) * m + (-2.532) * s);
+ rgba[2] = ((-0.375) * l + (-1.19906) * m + (14.27) * s);
+ rgba[3] = 1.0;
+}
+
+static inline Spectrum inks_to_spectrum (Config *config, float *ink_levels)
+{
+ int i;
+ Spectrum spec = config->illuminant;
+
+ spec = spectrum_remove_light (spec, config->substrate, 1.0);
+ for (i = 0; i < config->inks; i++)
+ spec = add_ink (spec,
+ config->ink_def[i].transmittance,
+ ink_levels[i] * config->ink_def[i].scale,
+ config->ink_def[i].opacity);
+ return spec;
+}
+
+static inline void spectral_proof (Config *config, float *ink_levels, float *rgba)
+{
+ spectrum_to_rgba (inks_to_spectrum (config, ink_levels), rgba);
+}
+
+static inline double colordiff (float *cola, float *colb)
+{
+ return
+ (cola[0]-colb[0])*(cola[0]-colb[0])+
+ (cola[1]-colb[1])*(cola[1]-colb[1])+
+ (cola[2]-colb[2])*(cola[2]-colb[2]);
+}
+
+static inline void rgb_to_inks (Config *config, float *rgb, float *ink_levels)
+{
+ float best[8] = {0.5,0.5,0.5,0.5,0.5};
+ float bestdiff = 3;
+ int i;
+
+ float rrange = 0.5;
+ for (i = 0; i < 64; i++)
+ {
+ int j;
+ float attempt[8];
+ float softrgb[4];
+ float diff;
+ float inksum = 0;
+ do{
+ inksum = 0.0;
+ for (j = 0; j < config->inks; j++)
+ {
+ attempt[j] = best[j] + g_random_double_range(-rrange, rrange);
+ if (attempt[j] < 0) attempt[j] = 0;
+ if (attempt[j] > 1) attempt[j] = 1;
+ inksum += attempt[j];
+ }
+ } while (inksum > config->ink_limit);
+
+ spectral_proof (config, attempt, softrgb);
+ diff = colordiff (rgb, softrgb);
+ if (diff < bestdiff)
+ {
+ bestdiff = diff;
+ for (j = 0; j < config->inks; j++)
+ best[j] = attempt[j];
+ rrange *= 0.8;
+ //if (diff < 0.001) /* bail early */
+ // i = 1000;
+ }
+ }
+ for (i = 0; i < config->inks; i++)
+ ink_levels[i] = best[i];
+}
static gboolean
process (GeglOperation *op,
@@ -145,38 +247,49 @@ process (GeglOperation *op,
const GeglRectangle *roi,
gint level)
{
+ GeglChantO *o = GEGL_CHANT_PROPERTIES (op);
gfloat *in = in_buf;
gfloat *out = out_buf;
- while (samples--)
- {
- Spectrum spec = ILLUMINANT;
- float l, m, s;
-
- spec = spectrum_remove_light (spec, SUBSTRATE_TRANSMITTANCE, 1.0);
- if (inks >=1) spec = add_ink (spec, INK_TRANSMITTANCE_INK1, in[0] * ink_scale[0], ink1_opacity);
- if (inks >=2) spec = add_ink (spec, INK_TRANSMITTANCE_INK2, in[1] * ink_scale[1], ink2_opacity);
- if (inks >=3) spec = add_ink (spec, INK_TRANSMITTANCE_INK3, in[2] * ink_scale[2], ink3_opacity);
- if (inks >=4) spec = add_ink (spec, INK_TRANSMITTANCE_INK4, in[3] * ink_scale[3], ink4_opacity);
-
- l = spectrum_integrate (spec, STANDARD_OBSERVER_L, 0.4);
- m = spectrum_integrate (spec, STANDARD_OBSERVER_M, 0.4);
- s = spectrum_integrate (spec, STANDARD_OBSERVER_S, 0.4);
-
- /* 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);
-
+ switch (o->mode)
+ {
+ case GEGL_INK_SIMULATOR_PROOF:
+ while (samples--)
+ {
+ spectral_proof (&config, in, out);
+ in += 4;
+ out += 4;
+ }
+ break;
+ case GEGL_INK_SIMULATOR_SEPARATE:
+ while (samples--)
+ {
+ rgb_to_inks (&config, in, out);
+ if (config.inks < 4)
+ out[3] = 1.0;
+ if (config.inks < 3)
+ out[2] = 0.0;
+ if (config.inks < 2)
+ out[1] = 0.0;
+ in += 4;
+ out += 4;
+ }
+ break;
+ case GEGL_INK_SIMULATOR_SEPARATE_PROOF:
+ while (samples--)
+ {
+ float temp[4];
+ rgb_to_inks (&config, in, temp);
+ spectral_proof (&config, temp, out);
+ in += 4;
+ out += 4;
+ }
+ break;
+ }
- in += 4;
- out += 3;
- }
return TRUE;
}
-
static Spectrum parse_spectrum (gchar *spectrum)
{
Spectrum s = TRANSMITTANCE_WHITE;
@@ -184,7 +297,23 @@ static Spectrum parse_spectrum (gchar *spectrum)
return s;
while (*spectrum == ' ') spectrum ++;
- if (g_str_has_prefix (spectrum, "red"))
+ if (g_str_has_prefix (spectrum, "rgb"))
+ {
+ Spectrum red = TRANSMITTANCE_RED;
+ Spectrum green = TRANSMITTANCE_GREEN;
+ Spectrum blue = TRANSMITTANCE_BLUE;
+ int i;
+ float r = 0, g = 0, b = 0;
+ gchar *p = spectrum + 3;
+
+ r = g_strtod (p, &p);
+ if (p) g = g_strtod (p, &p);
+ if (p) b = g_strtod (p, &p);
+
+ for (i = 0; i<SPECTRUM_BANDS; i++)
+ s.bands[i] = red.bands[i] * r + green.bands[i] * g + blue.bands[i] * b;
+
+ } else if (g_str_has_prefix (spectrum, "red"))
{ Spectrum color = TRANSMITTANCE_RED; s = color;
} else if (g_str_has_prefix (spectrum, "green"))
{ Spectrum color = TRANSMITTANCE_GREEN; s = color;
@@ -218,50 +347,36 @@ static void parse_config_line (GeglOperation *operation,
const char *line)
{
Spectrum s;
+ int i;
if (!line)
return;
-
if (!strchr (line, '='))
return;
-
while (*line == ' ') line++;
-
- inks = 0;
-
s = parse_spectrum (strchr (line, '=') +1);
-
if (g_str_has_prefix (line, "illuminant"))
- ILLUMINANT = s;
+ config.illuminant = s;
else if (g_str_has_prefix (line, "substrate"))
- SUBSTRATE_TRANSMITTANCE = s;
- else if (g_str_has_prefix (line, "ink1"))
+ config.substrate = s;
+ else if (g_str_has_prefix (line, "inklimit"))
{
- INK_TRANSMITTANCE_INK1 = s;
- if (strstr(line, "o=")) ink1_opacity = g_strtod (strstr(line, "o=") + 2, NULL);
- if (strstr(line, "s=")) ink_scale[0] = g_strtod (strstr(line, "s=") + 2, NULL);
- inks = MAX(inks, 1);
- }
- else if (g_str_has_prefix (line, "ink2"))
- {
- INK_TRANSMITTANCE_INK2 = s;
- inks = MAX(inks, 2);
- if (strstr(line, "o=")) ink2_opacity = g_strtod (strstr(line, "o=") + 2, NULL);
- if (strstr(line, "s=")) ink_scale[1] = g_strtod (strstr(line, "s=") + 2, NULL);
- }
- else if (g_str_has_prefix (line, "ink3"))
- {
- INK_TRANSMITTANCE_INK3 = s;
- inks = MAX(inks, 3);
- if (strstr(line, "o=")) ink3_opacity = g_strtod (strstr(line, "o=") + 2, NULL);
- if (strstr(line, "s=")) ink_scale[2] = g_strtod (strstr(line, "s=") + 2, NULL);
- }
- else if (g_str_has_prefix (line, "ink4"))
- {
- INK_TRANSMITTANCE_INK4 = s;
- inks = MAX(inks, 4);
- if (strstr(line, "o=")) ink4_opacity = g_strtod (strstr(line, "o=") + 2, NULL);
- if (strstr(line, "s=")) ink_scale[3] = g_strtod (strstr(line, "s=") + 2, NULL);
+ config.ink_limit = strchr(line, '=') ? g_strtod (strchr (line, '=')+1, NULL) : 3.0;
+ if (config.ink_limit < 0.2)
+ config.ink_limit = 0.2;
}
+ else
+ for (i = 0; i < 4; i++)
+ {
+ gchar prefix[] = "ink1";
+ prefix[3] = (i+1) + '0';
+ if (g_str_has_prefix (line, prefix))
+ {
+ config.ink_def[i].transmittance = s;
+ if (strstr(line, "o=")) config.ink_def[i].opacity = g_strtod (strstr(line, "o=") + 2, NULL);
+ if (strstr(line, "s=")) config.ink_def[i].scale = g_strtod (strstr(line, "s=") + 2, NULL);
+ config.inks = MAX(config.inks, i+1);
+ }
+ }
}
static void parse_config (GeglOperation *operation)
@@ -274,18 +389,9 @@ static void parse_config (GeglOperation *operation)
if (!p)
return;
- memset (&INK_TRANSMITTANCE_INK1, 0, sizeof (INK_TRANSMITTANCE_INK1));
- memset (&INK_TRANSMITTANCE_INK2, 0, sizeof (INK_TRANSMITTANCE_INK2));
- memset (&INK_TRANSMITTANCE_INK3, 0, sizeof (INK_TRANSMITTANCE_INK3));
- memset (&INK_TRANSMITTANCE_INK4, 0, sizeof (INK_TRANSMITTANCE_INK4));
- memset (&INK_TRANSMITTANCE_INK5, 0, sizeof (INK_TRANSMITTANCE_INK5));
-
- for (i = 0; i < 4; i++) ink_scale[i] = 2.0;
- ink1_opacity = 0;
- ink2_opacity = 0;
- ink3_opacity = 0;
- ink4_opacity = 0;
- ink5_opacity = 0;
+ memset (&config, 0, sizeof (config));
+ for (i = 0; i < 4; i++) config.ink_def[i].scale = 1.0;
+ config.ink_limit = 3.0;
str = g_string_new ("");
while (*p)
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]