summaryrefslogtreecommitdiff
path: root/src/main/color-conversions.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/color-conversions.c')
-rw-r--r--src/main/color-conversions.c2207
1 files changed, 2207 insertions, 0 deletions
diff --git a/src/main/color-conversions.c b/src/main/color-conversions.c
new file mode 100644
index 0000000..2b354c6
--- /dev/null
+++ b/src/main/color-conversions.c
@@ -0,0 +1,2207 @@
+/*
+ * "$Id: color-conversions.c,v 1.18 2005/07/01 01:40:08 rlk Exp $"
+ *
+ * Gimp-Print color management module - traditional Gimp-Print algorithm.
+ *
+ * Copyright 1997-2000 Michael Sweet (mike@easysw.com) and
+ * Robert Krawitz (rlk@alum.mit.edu)
+ *
+ * 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 2 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * This file must include only standard C header files. The core code must
+ * compile on generic platforms that don't support glib, gimp, gtk, etc.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <gutenprint/gutenprint.h>
+#include "gutenprint-internal.h"
+#include <gutenprint/gutenprint-intl-internal.h>
+#include <gutenprint/curve-cache.h>
+#include <math.h>
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
+#include <string.h>
+#include "color-conversion.h"
+
+#ifdef __GNUC__
+#define inline __inline__
+#endif
+
+/*
+ * RGB to grayscale luminance constants...
+ */
+
+#define LUM_RED 31
+#define LUM_GREEN 61
+#define LUM_BLUE 8
+
+/* rgb/hsl conversions taken from Gimp common/autostretch_hsv.c */
+
+#define FMAX(a, b) ((a) > (b) ? (a) : (b))
+#define FMIN(a, b) ((a) < (b) ? (a) : (b))
+
+static inline void
+calc_rgb_to_hsl(unsigned short *rgb, double *hue, double *sat,
+ double *lightness)
+{
+ double red, green, blue;
+ double h, s, l;
+ double min, max;
+ double delta;
+ int maxval;
+
+ red = rgb[0] / 65535.0;
+ green = rgb[1] / 65535.0;
+ blue = rgb[2] / 65535.0;
+
+ if (red > green)
+ {
+ if (red > blue)
+ {
+ max = red;
+ maxval = 0;
+ }
+ else
+ {
+ max = blue;
+ maxval = 2;
+ }
+ min = FMIN(green, blue);
+ }
+ else
+ {
+ if (green > blue)
+ {
+ max = green;
+ maxval = 1;
+ }
+ else
+ {
+ max = blue;
+ maxval = 2;
+ }
+ min = FMIN(red, blue);
+ }
+
+ l = (max + min) / 2.0;
+ delta = max - min;
+
+ if (delta < .000001) /* Suggested by Eugene Anikin <eugene@anikin.com> */
+ {
+ s = 0.0;
+ h = 0.0;
+ }
+ else
+ {
+ if (l <= .5)
+ s = delta / (max + min);
+ else
+ s = delta / (2 - max - min);
+
+ if (maxval == 0)
+ h = (green - blue) / delta;
+ else if (maxval == 1)
+ h = 2 + (blue - red) / delta;
+ else
+ h = 4 + (red - green) / delta;
+
+ if (h < 0.0)
+ h += 6.0;
+ else if (h > 6.0)
+ h -= 6.0;
+ }
+
+ *hue = h;
+ *sat = s;
+ *lightness = l;
+}
+
+static inline double
+hsl_value(double n1, double n2, double hue)
+{
+ if (hue < 0)
+ hue += 6.0;
+ else if (hue > 6)
+ hue -= 6.0;
+ if (hue < 1.0)
+ return (n1 + (n2 - n1) * hue);
+ else if (hue < 3.0)
+ return (n2);
+ else if (hue < 4.0)
+ return (n1 + (n2 - n1) * (4.0 - hue));
+ else
+ return (n1);
+}
+
+static inline void
+calc_hsl_to_rgb(unsigned short *rgb, double h, double s, double l)
+{
+ if (s < .0000001)
+ {
+ if (l > 1)
+ l = 1;
+ else if (l < 0)
+ l = 0;
+ rgb[0] = l * 65535;
+ rgb[1] = l * 65535;
+ rgb[2] = l * 65535;
+ }
+ else
+ {
+ double m1, m2;
+ double h1, h2;
+ h1 = h + 2;
+ h2 = h - 2;
+
+ if (l < .5)
+ m2 = l * (1 + s);
+ else
+ m2 = l + s - (l * s);
+ m1 = (l * 2) - m2;
+ rgb[0] = 65535 * hsl_value(m1, m2, h1);
+ rgb[1] = 65535 * hsl_value(m1, m2, h);
+ rgb[2] = 65535 * hsl_value(m1, m2, h2);
+ }
+}
+
+static inline double
+update_saturation(double sat, double adjust, double isat, int bright_colors)
+{
+ if (bright_colors || adjust < 1)
+ sat *= adjust;
+ else if (adjust > 1)
+ {
+ double s1 = sat * adjust;
+ double s2 = 1.0 - ((1.0 - sat) * isat);
+ sat = FMIN(s1, s2);
+ }
+ if (sat > 1)
+ sat = 1.0;
+ return sat;
+}
+
+static inline double
+interpolate_value(const double *vec, double val)
+{
+ double base = floor(val);
+ double frac = val - base;
+ int ibase = (int) base;
+ double lval = vec[ibase];
+ if (frac > 0)
+ lval += (vec[ibase + 1] - lval) * frac;
+ return lval;
+}
+
+static inline void
+update_saturation_from_rgb(unsigned short *rgb,
+ const unsigned short *brightness_lookup,
+ double adjust, double isat, int do_usermap)
+{
+ double h, s, l;
+ calc_rgb_to_hsl(rgb, &h, &s, &l);
+ if (do_usermap)
+ {
+ unsigned short ub = (unsigned short) (l * 65535);
+ unsigned short val = brightness_lookup[ub];
+ l = ((double) val) / 65535;
+ if (val < ub)
+ s = s * (65535 - ub) / (65535 - val);
+ }
+ s = update_saturation(s, adjust, isat, 0);
+ calc_hsl_to_rgb(rgb, h, s, l);
+}
+
+static inline double
+adjust_hue(const double *hue_map, double hue, size_t points)
+{
+ if (hue_map)
+ {
+ hue += interpolate_value(hue_map, hue * points / 6.0);
+ if (hue < 0.0)
+ hue += 6.0;
+ else if (hue >= 6.0)
+ hue -= 6.0;
+ }
+ return hue;
+}
+
+static inline void
+adjust_hsl(unsigned short *rgbout, lut_t *lut, double ssat, double isat,
+ int split_saturation, int adjust_hue_only, int bright_colors)
+{
+ const double *hue_map = CURVE_CACHE_FAST_DOUBLE(&(lut->hue_map));
+ const double *lum_map = CURVE_CACHE_FAST_DOUBLE(&(lut->lum_map));
+ const double *sat_map = CURVE_CACHE_FAST_DOUBLE(&(lut->sat_map));
+ if ((split_saturation || lum_map || hue_map || sat_map) &&
+ (rgbout[0] != rgbout[1] || rgbout[0] != rgbout[2]))
+ {
+ size_t hue_count = CURVE_CACHE_FAST_COUNT(&(lut->hue_map));
+ size_t lum_count = CURVE_CACHE_FAST_COUNT(&(lut->lum_map));
+ size_t sat_count = CURVE_CACHE_FAST_COUNT(&(lut->sat_map));
+ double h, s, l;
+ double oh;
+ rgbout[0] ^= 65535;
+ rgbout[1] ^= 65535;
+ rgbout[2] ^= 65535;
+ calc_rgb_to_hsl(rgbout, &h, &s, &l);
+ s = update_saturation(s, ssat, isat, 0);
+ if (!adjust_hue_only && lut->sat_map.d_cache)
+ {
+ double nh = h * sat_count / 6.0;
+ double tmp = interpolate_value(sat_map, nh);
+ if (tmp < .9999 || tmp > 1.0001)
+ {
+ s = update_saturation(s, tmp, tmp > 1.0 ? 1.0 / tmp : 1.0,
+ bright_colors);
+ }
+ }
+ oh = h;
+ h = adjust_hue(hue_map, h, hue_count);
+ calc_hsl_to_rgb(rgbout, h, s, l);
+
+ if (!adjust_hue_only && s > 0.00001)
+ {
+ /*
+ * Perform luminosity adjustment only on color component.
+ * This way the luminosity of the gray component won't be affected.
+ * We'll add the gray back at the end.
+ */
+
+ unsigned gray = FMIN(rgbout[0], FMIN(rgbout[1], rgbout[2]));
+ int i;
+ /*
+ * Scale the components by the amount of color left.
+ * This way the luminosity calculations will come out right.
+ */
+ if (gray > 0)
+ for (i = 0; i < 3; i++)
+ rgbout[i] = (rgbout[i] - gray) * 65535.0 / (65535 - gray);
+
+ calc_rgb_to_hsl(rgbout, &h, &s, &l);
+ if (lut->lum_map.d_cache && l > 0.00001 && l < .99999)
+ {
+ double nh = oh * lum_count / 6.0;
+ double oel = interpolate_value(lum_map,nh);
+ if (oel <= 1)
+ l *= oel;
+ else
+ {
+ double g1 = pow(l, 1.0 / oel);
+ double g2 = 1.0 - pow(1.0 - l, oel);
+ l = FMIN(g1, g2);
+ }
+ }
+ calc_hsl_to_rgb(rgbout, h, s, l);
+ if (gray > 0)
+ for (i = 0; i < 3; i++)
+ rgbout[i] = gray + (rgbout[i] * (65535 - gray) / 65535.0);
+ }
+
+ rgbout[0] ^= 65535;
+ rgbout[1] ^= 65535;
+ rgbout[2] ^= 65535;
+ }
+}
+
+static inline void
+lookup_rgb(lut_t *lut, unsigned short *rgbout,
+ const unsigned short *red, const unsigned short *green,
+ const unsigned short *blue, unsigned steps)
+{
+ if (steps == 65536)
+ {
+ rgbout[0] = red[rgbout[0]];
+ rgbout[1] = green[rgbout[1]];
+ rgbout[2] = blue[rgbout[2]];
+ }
+ else
+ {
+ rgbout[0] = red[rgbout[0] / 257];
+ rgbout[1] = green[rgbout[1] / 257];
+ rgbout[2] = blue[rgbout[2] / 257];
+ }
+}
+
+static inline int
+short_eq(const unsigned short *i1, const unsigned short *i2, size_t count)
+{
+#if 1
+ int i;
+ for (i = 0; i < count; i++)
+ if (i1[i] != i2[i])
+ return 0;
+ return 1;
+#else
+ return !memcmp(i1, i2, count * sizeof(unsigned short));
+#endif
+}
+
+static inline void
+short_copy(unsigned short *out, const unsigned short *in, size_t count)
+{
+#if 1
+ int i;
+ for (i = 0; i < count; i++)
+ out[i] = in[i];
+#else
+ (void) memcpy(out, in, count * sizeof(unsigned short));
+#endif
+}
+
+static unsigned
+generic_cmy_to_kcmy(const stp_vars_t *vars, const unsigned short *in,
+ unsigned short *out)
+{
+ lut_t *lut = (lut_t *)(stp_get_component_data(vars, "Color"));
+ int width = lut->image_width;
+ int step = 65535 / (lut->steps - 1); /* 1 or 257 */
+
+ const unsigned short *gcr_lookup;
+ const unsigned short *black_lookup;
+ int i;
+ int i0 = -1;
+ int i1 = -1;
+ int i2 = -1;
+ unsigned short o0 = 0;
+ unsigned short o1 = 0;
+ unsigned short o2 = 0;
+ unsigned short o3 = 0;
+ unsigned short nz0 = 0;
+ unsigned short nz1 = 0;
+ unsigned short nz2 = 0;
+ unsigned short nz3 = 0;
+
+ stp_curve_resample(stp_curve_cache_get_curve(&(lut->gcr_curve)), lut->steps);
+ gcr_lookup = stp_curve_cache_get_ushort_data(&(lut->gcr_curve));
+ stp_curve_resample(stp_curve_cache_get_curve
+ (&(lut->channel_curves[CHANNEL_K])), lut->steps);
+ black_lookup =
+ stp_curve_cache_get_ushort_data(&(lut->channel_curves[CHANNEL_K]));
+
+ for (i = 0; i < width; i++, out += 4, in += 3)
+ {
+ if (i0 == in[0] && i1 == in[1] && i2 == in[2])
+ {
+ out[0] = o0;
+ out[1] = o1;
+ out[2] = o2;
+ out[3] = o3;
+ }
+ else
+ {
+ int k;
+ i0 = in[0];
+ i1 = in[1];
+ i2 = in[2];
+ k = FMIN(i0, FMIN(i1, i2));
+ out[0] = 0;
+ out[1] = i0;
+ out[2] = i1;
+ out[3] = i2;
+ if (k > 0)
+ {
+ int where, resid;
+ int kk;
+ if (lut->steps == 65536)
+ kk = gcr_lookup[k];
+ else
+ {
+ where = k / step;
+ resid = k % step;
+ kk = gcr_lookup[where];
+ if (resid > 0)
+ kk += (gcr_lookup[where + 1] - gcr_lookup[where]) * resid /
+ step;
+ }
+ if (kk > k)
+ kk = k;
+ if (kk > 0)
+ {
+ if (lut->steps == 65536)
+ out[0] = black_lookup[kk];
+ else
+ {
+ int k_out;
+ where = kk / step;
+ resid = kk % step;
+ k_out = black_lookup[where];
+ if (resid > 0)
+ k_out +=
+ (black_lookup[where + 1] - black_lookup[where]) *
+ resid / step;
+ out[0] = k_out;
+ }
+ out[1] -= kk;
+ out[2] -= kk;
+ out[3] -= kk;
+ }
+ }
+ o0 = out[0];
+ o1 = out[1];
+ o2 = out[2];
+ o3 = out[3];
+ nz0 |= o0;
+ nz1 |= o1;
+ nz2 |= o2;
+ nz3 |= o3;
+ }
+ }
+ return (nz0 ? 0 : 1) + (nz1 ? 0 : 2) + (nz2 ? 0 : 4) + (nz3 ? 0 : 8);
+}
+
+static unsigned
+raw_cmy_to_kcmy(const stp_vars_t *vars, const unsigned short *in,
+ unsigned short *out)
+{
+ lut_t *lut = (lut_t *)(stp_get_component_data(vars, "Color"));
+ int width = lut->image_width;
+
+ int i;
+ int j;
+ unsigned short nz[4];
+ unsigned retval = 0;
+ const unsigned short *input_cache = NULL;
+ const unsigned short *output_cache = NULL;
+
+ memset(nz, 0, sizeof(nz));
+
+ for (i = 0; i < width; i++, out += 4, in += 3)
+ {
+ if (input_cache && short_eq(input_cache, in, 3))
+ short_copy(out, output_cache, 4);
+ else
+ {
+ int c = in[0];
+ int m = in[1];
+ int y = in[2];
+ int k = FMIN(c, FMIN(m, y));
+ input_cache = in;
+ out[0] = 0;
+ for (j = 0; j < 3; j++)
+ out[j + 1] = in[j];
+ if (k > 0)
+ {
+ out[0] = k;
+ out[1] -= k;
+ out[2] -= k;
+ out[3] -= k;
+ }
+ output_cache = out;
+ for (j = 0; j < 4; j++)
+ if (out[j])
+ nz[j] = 1;
+ }
+ }
+ for (j = 0; j < 4; j++)
+ if (nz[j] == 0)
+ retval |= (1 << j);
+ return retval;
+}
+
+#define GENERIC_COLOR_FUNC(fromname, toname) \
+static unsigned \
+fromname##_to_##toname(const stp_vars_t *vars, const unsigned char *in, \
+ unsigned short *out) \
+{ \
+ lut_t *lut = (lut_t *)(stp_get_component_data(vars, "Color")); \
+ if (!lut->printed_colorfunc) \
+ { \
+ lut->printed_colorfunc = 1; \
+ stp_dprintf(STP_DBG_COLORFUNC, vars, \
+ "Colorfunc is %s_%d_to_%s, %s, %s, %d, %d\n", \
+ #fromname, lut->channel_depth, #toname, \
+ lut->input_color_description->name, \
+ lut->output_color_description->name, \
+ lut->steps, lut->invert_output); \
+ } \
+ if (lut->channel_depth == 8) \
+ return fromname##_8_to_##toname(vars, in, out); \
+ else \
+ return fromname##_16_to_##toname(vars, in, out); \
+}
+
+#define COLOR_TO_COLOR_FUNC(T, bits) \
+static unsigned \
+color_##bits##_to_color(const stp_vars_t *vars, const unsigned char *in, \
+ unsigned short *out) \
+{ \
+ int i; \
+ double isat = 1.0; \
+ double ssat = stp_get_float_parameter(vars, "Saturation"); \
+ double sbright = stp_get_float_parameter(vars, "Brightness"); \
+ int i0 = -1; \
+ int i1 = -1; \
+ int i2 = -1; \
+ unsigned short o0 = 0; \
+ unsigned short o1 = 0; \
+ unsigned short o2 = 0; \
+ unsigned short nz0 = 0; \
+ unsigned short nz1 = 0; \
+ unsigned short nz2 = 0; \
+ const unsigned short *red; \
+ const unsigned short *green; \
+ const unsigned short *blue; \
+ const unsigned short *brightness; \
+ const unsigned short *contrast; \
+ const T *s_in = (const T *) in; \
+ lut_t *lut = (lut_t *)(stp_get_component_data(vars, "Color")); \
+ int compute_saturation = ssat <= .99999 || ssat >= 1.00001; \
+ int split_saturation = ssat > 1.4; \
+ int bright_color_adjustment = 0; \
+ int hue_only_color_adjustment = 0; \
+ int do_user_adjustment = 0; \
+ if (lut->color_correction->correction == COLOR_CORRECTION_BRIGHT) \
+ bright_color_adjustment = 1; \
+ if (lut->color_correction->correction == COLOR_CORRECTION_HUE) \
+ hue_only_color_adjustment = 1; \
+ if (sbright != 1) \
+ do_user_adjustment = 1; \
+ compute_saturation |= do_user_adjustment; \
+ \
+ for (i = CHANNEL_C; i <= CHANNEL_Y; i++) \
+ stp_curve_resample(stp_curve_cache_get_curve(&(lut->channel_curves[i])), \
+ 1 << bits); \
+ stp_curve_resample \
+ (stp_curve_cache_get_curve(&(lut->brightness_correction)), 65536); \
+ stp_curve_resample \
+ (stp_curve_cache_get_curve(&(lut->contrast_correction)), 1 << bits); \
+ red = \
+ stp_curve_cache_get_ushort_data(&(lut->channel_curves[CHANNEL_C])); \
+ green = \
+ stp_curve_cache_get_ushort_data(&(lut->channel_curves[CHANNEL_M])); \
+ blue = \
+ stp_curve_cache_get_ushort_data(&(lut->channel_curves[CHANNEL_Y])); \
+ brightness= \
+ stp_curve_cache_get_ushort_data(&(lut->brightness_correction)); \
+ contrast = \
+ stp_curve_cache_get_ushort_data(&(lut->contrast_correction)); \
+ (void) stp_curve_cache_get_double_data(&(lut->hue_map)); \
+ (void) stp_curve_cache_get_double_data(&(lut->lum_map)); \
+ (void) stp_curve_cache_get_double_data(&(lut->sat_map)); \
+ \
+ if (split_saturation) \
+ ssat = sqrt(ssat); \
+ if (ssat > 1) \
+ isat = 1.0 / ssat; \
+ for (i = 0; i < lut->image_width; i++) \
+ { \
+ if (i0 == s_in[0] && i1 == s_in[1] && i2 == s_in[2]) \
+ { \
+ out[0] = o0; \
+ out[1] = o1; \
+ out[2] = o2; \
+ } \
+ else \
+ { \
+ i0 = s_in[0]; \
+ i1 = s_in[1]; \
+ i2 = s_in[2]; \
+ out[0] = i0 * (65535u / (unsigned) ((1 << bits) - 1)); \
+ out[1] = i1 * (65535u / (unsigned) ((1 << bits) - 1)); \
+ out[2] = i2 * (65535u / (unsigned) ((1 << bits) - 1)); \
+ lookup_rgb(lut, out, contrast, contrast, contrast, 1 << bits); \
+ if ((compute_saturation)) \
+ update_saturation_from_rgb(out, brightness, ssat, isat, \
+ do_user_adjustment); \
+ adjust_hsl(out, lut, ssat, isat, split_saturation, \
+ hue_only_color_adjustment, bright_color_adjustment); \
+ lookup_rgb(lut, out, red, green, blue, 1 << bits); \
+ o0 = out[0]; \
+ o1 = out[1]; \
+ o2 = out[2]; \
+ nz0 |= o0; \
+ nz1 |= o1; \
+ nz2 |= o2; \
+ } \
+ s_in += 3; \
+ out += 3; \
+ } \
+ return (nz0 ? 0 : 1) + (nz1 ? 0 : 2) + (nz2 ? 0 : 4); \
+}
+
+COLOR_TO_COLOR_FUNC(unsigned char, 8)
+COLOR_TO_COLOR_FUNC(unsigned short, 16)
+GENERIC_COLOR_FUNC(color, color)
+
+/*
+ * 'rgb_to_rgb()' - Convert rgb image data to RGB.
+ */
+
+#define FAST_COLOR_TO_COLOR_FUNC(T, bits) \
+static unsigned \
+color_##bits##_to_color_fast(const stp_vars_t *vars, const unsigned char *in, \
+ unsigned short *out) \
+{ \
+ int i; \
+ int i0 = -1; \
+ int i1 = -1; \
+ int i2 = -1; \
+ int o0 = 0; \
+ int o1 = 0; \
+ int o2 = 0; \
+ int nz0 = 0; \
+ int nz1 = 0; \
+ int nz2 = 0; \
+ const T *s_in = (const T *) in; \
+ lut_t *lut = (lut_t *)(stp_get_component_data(vars, "Color")); \
+ const unsigned short *red; \
+ const unsigned short *green; \
+ const unsigned short *blue; \
+ const unsigned short *brightness; \
+ const unsigned short *contrast; \
+ double isat = 1.0; \
+ double saturation = stp_get_float_parameter(vars, "Saturation"); \
+ double sbright = stp_get_float_parameter(vars, "Brightness"); \
+ int compute_saturation = saturation <= .99999 || saturation >= 1.00001; \
+ int do_user_adjustment = 0; \
+ if (sbright != 1) \
+ do_user_adjustment = 1; \
+ compute_saturation |= do_user_adjustment; \
+ \
+ for (i = CHANNEL_C; i <= CHANNEL_Y; i++) \
+ stp_curve_resample(lut->channel_curves[i].curve, 65536); \
+ stp_curve_resample \
+ (stp_curve_cache_get_curve(&(lut->brightness_correction)), 65536); \
+ stp_curve_resample \
+ (stp_curve_cache_get_curve(&(lut->contrast_correction)), 1 << bits); \
+ red = \
+ stp_curve_cache_get_ushort_data(&(lut->channel_curves[CHANNEL_C])); \
+ green = \
+ stp_curve_cache_get_ushort_data(&(lut->channel_curves[CHANNEL_M])); \
+ blue = \
+ stp_curve_cache_get_ushort_data(&(lut->channel_curves[CHANNEL_Y])); \
+ brightness= \
+ stp_curve_cache_get_ushort_data(&(lut->brightness_correction)); \
+ contrast = \
+ stp_curve_cache_get_ushort_data(&(lut->contrast_correction)); \
+ \
+ if (saturation > 1) \
+ isat = 1.0 / saturation; \
+ for (i = 0; i < lut->image_width; i++) \
+ { \
+ if (i0 == s_in[0] && i1 == s_in[1] && i2 == s_in[2]) \
+ { \
+ out[0] = o0; \
+ out[1] = o1; \
+ out[2] = o2; \
+ } \
+ else \
+ { \
+ i0 = s_in[0]; \
+ i1 = s_in[1]; \
+ i2 = s_in[2]; \
+ out[0] = contrast[s_in[0]]; \
+ out[1] = contrast[s_in[1]]; \
+ out[2] = contrast[s_in[2]]; \
+ if ((compute_saturation)) \
+ update_saturation_from_rgb(out, brightness, saturation, isat, 1); \
+ out[0] = red[out[0]]; \
+ out[1] = green[out[1]]; \
+ out[2] = blue[out[2]]; \
+ o0 = out[0]; \
+ o1 = out[1]; \
+ o2 = out[2]; \
+ nz0 |= o0; \
+ nz1 |= o1; \
+ nz2 |= o2; \
+ } \
+ s_in += 3; \
+ out += 3; \
+ } \
+ return (nz0 ? 0 : 1) + (nz1 ? 0 : 2) + (nz2 ? 0 : 4); \
+}
+
+FAST_COLOR_TO_COLOR_FUNC(unsigned char, 8)
+FAST_COLOR_TO_COLOR_FUNC(unsigned short, 16)
+GENERIC_COLOR_FUNC(color, color_fast)
+
+#define RAW_COLOR_TO_COLOR_FUNC(T, bits) \
+static unsigned \
+color_##bits##_to_color_raw(const stp_vars_t *vars, const unsigned char *in,\
+ unsigned short *out) \
+{ \
+ int i; \
+ int j; \
+ int nz = 0; \
+ const T *s_in = (const T *) in; \
+ lut_t *lut = (lut_t *)(stp_get_component_data(vars, "Color")); \
+ unsigned mask = 0; \
+ if (lut->invert_output) \
+ mask = 0xffff; \
+ \
+ for (i = 0; i < lut->image_width; i++) \
+ { \
+ unsigned bit = 1; \
+ for (j = 0; j < 3; j++, bit += bit) \
+ { \
+ out[j] = (s_in[j] * (65535 / ((1 << bits) - 1))) ^ mask; \
+ if (out[j]) \
+ nz |= bit; \
+ } \
+ s_in += 3; \
+ out += 3; \
+ } \
+ return nz; \
+}
+
+RAW_COLOR_TO_COLOR_FUNC(unsigned char, 8)
+RAW_COLOR_TO_COLOR_FUNC(unsigned short, 16)
+GENERIC_COLOR_FUNC(color, color_raw)
+
+/*
+ * 'gray_to_rgb()' - Convert gray image data to RGB.
+ */
+
+#define GRAY_TO_COLOR_FUNC(T, bits) \
+static unsigned \
+gray_##bits##_to_color(const stp_vars_t *vars, const unsigned char *in, \
+ unsigned short *out) \
+{ \
+ int i; \
+ int i0 = -1; \
+ int o0 = 0; \
+ int o1 = 0; \
+ int o2 = 0; \
+ int nz0 = 0; \
+ int nz1 = 0; \
+ int nz2 = 0; \
+ const T *s_in = (const T *) in; \
+ lut_t *lut = (lut_t *)(stp_get_component_data(vars, "Color")); \
+ const unsigned short *red; \
+ const unsigned short *green; \
+ const unsigned short *blue; \
+ const unsigned short *user; \
+ \
+ for (i = CHANNEL_C; i <= CHANNEL_Y; i++) \
+ stp_curve_resample(lut->channel_curves[i].curve, 65536); \
+ stp_curve_resample \
+ (stp_curve_cache_get_curve(&(lut->user_color_correction)), 1 << bits); \
+ red = \
+ stp_curve_cache_get_ushort_data(&(lut->channel_curves[CHANNEL_C])); \
+ green = \
+ stp_curve_cache_get_ushort_data(&(lut->channel_curves[CHANNEL_M])); \
+ blue = \
+ stp_curve_cache_get_ushort_data(&(lut->channel_curves[CHANNEL_Y])); \
+ user = \
+ stp_curve_cache_get_ushort_data(&(lut->user_color_correction)); \
+ \
+ for (i = 0; i < lut->image_width; i++) \
+ { \
+ if (i0 == s_in[0]) \
+ { \
+ out[0] = o0; \
+ out[1] = o1; \
+ out[2] = o2; \
+ } \
+ else \
+ { \
+ i0 = s_in[0]; \
+ out[0] = red[user[s_in[0]]]; \
+ out[1] = green[user[s_in[0]]]; \
+ out[2] = blue[user[s_in[0]]]; \
+ o0 = out[0]; \
+ o1 = out[1]; \
+ o2 = out[2]; \
+ nz0 |= o0; \
+ nz1 |= o1; \
+ nz2 |= o2; \
+ } \
+ s_in += 1; \
+ out += 3; \
+ } \
+ return (nz0 ? 0 : 1) + (nz1 ? 0 : 2) + (nz2 ? 0 : 4); \
+}
+
+GRAY_TO_COLOR_FUNC(unsigned char, 8)
+GRAY_TO_COLOR_FUNC(unsigned short, 16)
+GENERIC_COLOR_FUNC(gray, color)
+
+#define GRAY_TO_COLOR_RAW_FUNC(T, bits) \
+static unsigned \
+gray_##bits##_to_color_raw(const stp_vars_t *vars, const unsigned char *in,\
+ unsigned short *out) \
+{ \
+ int i; \
+ int nz = 7; \
+ const T *s_in = (const T *) in; \
+ lut_t *lut = (lut_t *)(stp_get_component_data(vars, "Color")); \
+ unsigned mask = 0; \
+ if (lut->invert_output) \
+ mask = 0xffff; \
+ \
+ for (i = 0; i < lut->image_width; i++) \
+ { \
+ unsigned outval = (s_in[0] * (65535 / (1 << bits))) ^ mask; \
+ out[0] = outval; \
+ out[1] = outval; \
+ out[2] = outval; \
+ if (outval) \
+ nz = 0; \
+ s_in++; \
+ out += 3; \
+ } \
+ return nz; \
+}
+
+GRAY_TO_COLOR_RAW_FUNC(unsigned char, 8)
+GRAY_TO_COLOR_RAW_FUNC(unsigned short, 16)
+GENERIC_COLOR_FUNC(gray, color_raw)
+
+#define COLOR_TO_KCMY_FUNC(name, name2, name3, name4, bits) \
+static unsigned \
+name##_##bits##_to_##name2(const stp_vars_t *vars, const unsigned char *in, \
+ unsigned short *out) \
+{ \
+ lut_t *lut = (lut_t *)(stp_get_component_data(vars, "Color")); \
+ size_t real_steps = lut->steps; \
+ unsigned status; \
+ if (!lut->cmy_tmp) \
+ lut->cmy_tmp = stp_malloc(4 * 2 * lut->image_width); \
+ name##_##bits##_to_##name3(vars, in, lut->cmy_tmp); \
+ lut->steps = 65536; \
+ status = name4##_cmy_to_kcmy(vars, lut->cmy_tmp, out); \
+ lut->steps = real_steps; \
+ return status; \
+}
+
+COLOR_TO_KCMY_FUNC(gray, kcmy, color, generic, 8)
+COLOR_TO_KCMY_FUNC(gray, kcmy, color, generic, 16)
+GENERIC_COLOR_FUNC(gray, kcmy)
+
+COLOR_TO_KCMY_FUNC(gray, kcmy_raw, color_raw, raw, 8)
+COLOR_TO_KCMY_FUNC(gray, kcmy_raw, color_raw, raw, 16)
+GENERIC_COLOR_FUNC(gray, kcmy_raw)
+
+COLOR_TO_KCMY_FUNC(color, kcmy, color, generic, 8)
+COLOR_TO_KCMY_FUNC(color, kcmy, color, generic, 16)
+GENERIC_COLOR_FUNC(color, kcmy)
+
+COLOR_TO_KCMY_FUNC(color, kcmy_fast, color_fast, generic, 8)
+COLOR_TO_KCMY_FUNC(color, kcmy_fast, color_fast, generic, 16)
+GENERIC_COLOR_FUNC(color, kcmy_fast)
+
+COLOR_TO_KCMY_FUNC(color, kcmy_raw, color_raw, raw, 8)
+COLOR_TO_KCMY_FUNC(color, kcmy_raw, color_raw, raw, 16)
+GENERIC_COLOR_FUNC(color, kcmy_raw)
+
+
+#define COLOR_TO_KCMY_THRESHOLD_FUNC(T, name) \
+static unsigned \
+name##_to_kcmy_threshold(const stp_vars_t *vars, \
+ const unsigned char *in, \
+ unsigned short *out) \
+{ \
+ int i; \
+ int z = 15; \
+ const T *s_in = (const T *) in; \
+ unsigned high_bit = ((1 << ((sizeof(T) * 8) - 1))); \
+ lut_t *lut = (lut_t *)(stp_get_component_data(vars, "Color")); \
+ int width = lut->image_width; \
+ unsigned mask = 0; \
+ memset(out, 0, width * 4 * sizeof(unsigned short)); \
+ if (lut->invert_output) \
+ mask = (1 << (sizeof(T) * 8)) - 1; \
+ \
+ for (i = 0; i < width; i++, out += 4, s_in += 3) \
+ { \
+ unsigned c = s_in[0] ^ mask; \
+ unsigned m = s_in[1] ^ mask; \
+ unsigned y = s_in[2] ^ mask; \
+ unsigned k = (c < m ? (c < y ? c : y) : (m < y ? m : y)); \
+ if (k >= high_bit) \
+ { \
+ c -= k; \
+ m -= k; \
+ y -= k; \
+ } \
+ if (k >= high_bit) \
+ { \
+ z &= 0xe; \
+ out[0] = 65535; \
+ } \
+ if (c >= high_bit) \
+ { \
+ z &= 0xd; \
+ out[1] = 65535; \
+ } \
+ if (m >= high_bit) \
+ { \
+ z &= 0xb; \
+ out[2] = 65535; \
+ } \
+ if (y >= high_bit) \
+ { \
+ z &= 0x7; \
+ out[3] = 65535; \
+ } \
+ } \
+ return z; \
+}
+
+COLOR_TO_KCMY_THRESHOLD_FUNC(unsigned char, color_8)
+COLOR_TO_KCMY_THRESHOLD_FUNC(unsigned short, color_16)
+GENERIC_COLOR_FUNC(color, kcmy_threshold)
+
+#define CMYK_TO_KCMY_THRESHOLD_FUNC(T, name) \
+static unsigned \
+name##_to_kcmy_threshold(const stp_vars_t *vars, \
+ const unsigned char *in, \
+ unsigned short *out) \
+{ \
+ int i; \
+ int z = 15; \
+ const T *s_in = (const T *) in; \
+ unsigned desired_high_bit = 0; \
+ unsigned high_bit = 1 << ((sizeof(T) * 8) - 1); \
+ lut_t *lut = (lut_t *)(stp_get_component_data(vars, "Color")); \
+ int width = lut->image_width; \
+ memset(out, 0, width * 4 * sizeof(unsigned short)); \
+ if (!lut->invert_output) \
+ desired_high_bit = high_bit; \
+ \
+ for (i = 0; i < width; i++, out += 4, s_in += 4) \
+ { \
+ if ((s_in[3] & high_bit) == desired_high_bit) \
+ { \
+ z &= 0xe; \
+ out[0] = 65535; \
+ } \
+ if ((s_in[0] & high_bit) == desired_high_bit) \
+ { \
+ z &= 0xd; \
+ out[1] = 65535; \
+ } \
+ if ((s_in[1] & high_bit) == desired_high_bit) \
+ { \
+ z &= 0xb; \
+ out[2] = 65535; \
+ } \
+ if ((s_in[2] & high_bit) == desired_high_bit) \
+ { \
+ z &= 0x7; \
+ out[3] = 65535; \
+ } \
+ } \
+ return z; \
+}
+
+CMYK_TO_KCMY_THRESHOLD_FUNC(unsigned char, cmyk_8)
+CMYK_TO_KCMY_THRESHOLD_FUNC(unsigned short, cmyk_16)
+GENERIC_COLOR_FUNC(cmyk, kcmy_threshold)
+
+#define KCMY_TO_KCMY_THRESHOLD_FUNC(T, name) \
+static unsigned \
+name##_to_kcmy_threshold(const stp_vars_t *vars, \
+ const unsigned char *in, \
+ unsigned short *out) \
+{ \
+ int i; \
+ int j; \
+ unsigned nz[4]; \
+ unsigned z = 0xf; \
+ const T *s_in = (const T *) in; \
+ unsigned desired_high_bit = 0; \
+ unsigned high_bit = 1 << ((sizeof(T) * 8) - 1); \
+ lut_t *lut = (lut_t *)(stp_get_component_data(vars, "Color")); \
+ int width = lut->image_width; \
+ memset(out, 0, width * 4 * sizeof(unsigned short)); \
+ if (!lut->invert_output) \
+ desired_high_bit = high_bit; \
+ for (i = 0; i < 4; i++) \
+ nz[i] = z & ~(1 << i); \
+ \
+ for (i = 0; i < width; i++) \
+ { \
+ for (j = 0; j < 4; j++) \
+ { \
+ if ((*s_in++ & high_bit) == desired_high_bit) \
+ { \
+ z &= nz[j]; \
+ *out = 65535; \
+ } \
+ out++; \
+ } \
+ } \
+ return z; \
+}
+
+KCMY_TO_KCMY_THRESHOLD_FUNC(unsigned char, kcmy_8)
+KCMY_TO_KCMY_THRESHOLD_FUNC(unsigned short, kcmy_16)
+GENERIC_COLOR_FUNC(kcmy, kcmy_threshold)
+
+#define GRAY_TO_COLOR_THRESHOLD_FUNC(T, name, bits, channels) \
+static unsigned \
+gray_##bits##_to_##name##_threshold(const stp_vars_t *vars, \
+ const unsigned char *in, \
+ unsigned short *out) \
+{ \
+ int i; \
+ int z = (1 << channels) - 1; \
+ int desired_high_bit = 0; \
+ unsigned high_bit = 1 << ((sizeof(T) * 8) - 1); \
+ const T *s_in = (const T *) in; \
+ lut_t *lut = (lut_t *)(stp_get_component_data(vars, "Color")); \
+ int width = lut->image_width; \
+ memset(out, 0, width * channels * sizeof(unsigned short)); \
+ if (!lut->invert_output) \
+ desired_high_bit = high_bit; \
+ \
+ for (i = 0; i < width; i++, out += channels, s_in++) \
+ { \
+ if ((s_in[0] & high_bit) == desired_high_bit) \
+ { \
+ int j; \
+ z = 0; \
+ for (j = 0; j < channels; j++) \
+ out[j] = 65535; \
+ } \
+ } \
+ return z; \
+}
+
+
+GRAY_TO_COLOR_THRESHOLD_FUNC(unsigned char, color, 8, 3)
+GRAY_TO_COLOR_THRESHOLD_FUNC(unsigned short, color, 16, 3)
+GENERIC_COLOR_FUNC(gray, color_threshold)
+
+GRAY_TO_COLOR_THRESHOLD_FUNC(unsigned char, kcmy, 8, 4)
+GRAY_TO_COLOR_THRESHOLD_FUNC(unsigned short, kcmy, 16, 4)
+GENERIC_COLOR_FUNC(gray, kcmy_threshold)
+
+#define COLOR_TO_COLOR_THRESHOLD_FUNC(T, name) \
+static unsigned \
+name##_to_color_threshold(const stp_vars_t *vars, \
+ const unsigned char *in, \
+ unsigned short *out) \
+{ \
+ int i; \
+ int z = 7; \
+ int desired_high_bit = 0; \
+ unsigned high_bit = ((1 << ((sizeof(T) * 8) - 1)) * 4); \
+ const T *s_in = (const T *) in; \
+ lut_t *lut = (lut_t *)(stp_get_component_data(vars, "Color")); \
+ int width = lut->image_width; \
+ memset(out, 0, width * 3 * sizeof(unsigned short)); \
+ if (!lut->invert_output) \
+ desired_high_bit = high_bit; \
+ \
+ for (i = 0; i < width; i++, out += 3, s_in += 3) \
+ { \
+ if ((s_in[0] & high_bit) == desired_high_bit) \
+ { \
+ z &= 6; \
+ out[0] = 65535; \
+ } \
+ if ((s_in[1] & high_bit) == desired_high_bit) \
+ { \
+ z &= 5; \
+ out[1] = 65535; \
+ } \
+ if ((s_in[1] & high_bit) == desired_high_bit) \
+ { \
+ z &= 3; \
+ out[2] = 65535; \
+ } \
+ } \
+ return z; \
+}
+
+COLOR_TO_COLOR_THRESHOLD_FUNC(unsigned char, color_8)
+COLOR_TO_COLOR_THRESHOLD_FUNC(unsigned short, color_16)
+GENERIC_COLOR_FUNC(color, color_threshold)
+
+#define COLOR_TO_GRAY_THRESHOLD_FUNC(T, name, channels, max_channels) \
+static unsigned \
+name##_to_gray_threshold(const stp_vars_t *vars, \
+ const unsigned char *in, \
+ unsigned short *out) \
+{ \
+ int i; \
+ int z = 1; \
+ int desired_high_bit = 0; \
+ unsigned high_bit = ((1 << ((sizeof(T) * 8) - 1))); \
+ const T *s_in = (const T *) in; \
+ lut_t *lut = (lut_t *)(stp_get_component_data(vars, "Color")); \
+ int width = lut->image_width; \
+ memset(out, 0, width * sizeof(unsigned short)); \
+ if (!lut->invert_output) \
+ desired_high_bit = high_bit; \
+ \
+ for (i = 0; i < width; i++, out++, s_in += channels) \
+ { \
+ unsigned gval = \
+ (max_channels - channels) * (1 << ((sizeof(T) * 8) - 1)); \
+ int j; \
+ for (j = 0; j < channels; j++) \
+ gval += s_in[j]; \
+ gval /= channels; \
+ if ((gval & high_bit) == desired_high_bit) \
+ { \
+ out[0] = 65535; \
+ z = 0; \
+ } \
+ } \
+ return z; \
+}
+
+COLOR_TO_GRAY_THRESHOLD_FUNC(unsigned char, cmyk_8, 4, 4)
+COLOR_TO_GRAY_THRESHOLD_FUNC(unsigned short, cmyk_16, 4, 4)
+GENERIC_COLOR_FUNC(cmyk, gray_threshold)
+
+COLOR_TO_GRAY_THRESHOLD_FUNC(unsigned char, kcmy_8, 4, 4)
+COLOR_TO_GRAY_THRESHOLD_FUNC(unsigned short, kcmy_16, 4, 4)
+GENERIC_COLOR_FUNC(kcmy, gray_threshold)
+
+COLOR_TO_GRAY_THRESHOLD_FUNC(unsigned char, color_8, 3, 3)
+COLOR_TO_GRAY_THRESHOLD_FUNC(unsigned short, color_16, 3, 3)
+GENERIC_COLOR_FUNC(color, gray_threshold)
+
+COLOR_TO_GRAY_THRESHOLD_FUNC(unsigned char, gray_8, 1, 1)
+COLOR_TO_GRAY_THRESHOLD_FUNC(unsigned short, gray_16, 1, 1)
+GENERIC_COLOR_FUNC(gray, gray_threshold)
+
+#define CMYK_TO_COLOR_FUNC(namein, name2, T, bits, offset) \
+static unsigned \
+namein##_##bits##_to_##name2(const stp_vars_t *vars, const unsigned char *in, \
+ unsigned short *out) \
+{ \
+ int i; \
+ lut_t *lut = (lut_t *)(stp_get_component_data(vars, "Color")); \
+ unsigned status; \
+ size_t real_steps = lut->steps; \
+ const T *s_in = (const T *) in; \
+ unsigned short *tmp; \
+ int width = lut->image_width; \
+ unsigned mask = 0; \
+ \
+ if (!lut->cmy_tmp) \
+ lut->cmy_tmp = stp_malloc(3 * 2 * lut->image_width); \
+ tmp = lut->cmy_tmp; \
+ memset(lut->cmy_tmp, 0, width * 3 * sizeof(unsigned short)); \
+ if (lut->invert_output) \
+ mask = 0xffff; \
+ \
+ for (i = 0; i < width; i++, tmp += 3, s_in += 4) \
+ { \
+ unsigned c = (s_in[0 + offset] + s_in[(3 + offset) % 4]) * \
+ (65535 / ((1 << bits) - 1)); \
+ unsigned m = (s_in[1 + offset] + s_in[(3 + offset) % 4]) * \
+ (65535 / ((1 << bits) - 1)); \
+ unsigned y = (s_in[2 + offset] + s_in[(3 + offset) % 4]) * \
+ (65535 / ((1 << bits) - 1)); \
+ if (c > 65535) \
+ c = 65535; \
+ if (m > 65535) \
+ m = 65535; \
+ if (y > 65535) \
+ y = 65535; \
+ tmp[0] = c ^ mask; \
+ tmp[1] = m ^ mask; \
+ tmp[2] = y ^ mask; \
+ } \
+ lut->steps = 65536; \
+ status = \
+ color_16_to_##name2(vars, (const unsigned char *) lut->cmy_tmp, out); \
+ lut->steps = real_steps; \
+ return status; \
+}
+
+CMYK_TO_COLOR_FUNC(cmyk, color, unsigned char, 8, 0)
+CMYK_TO_COLOR_FUNC(cmyk, color, unsigned short, 16, 0)
+GENERIC_COLOR_FUNC(cmyk, color)
+CMYK_TO_COLOR_FUNC(kcmy, color, unsigned char, 8, 1)
+CMYK_TO_COLOR_FUNC(kcmy, color, unsigned short, 16, 1)
+GENERIC_COLOR_FUNC(kcmy, color)
+CMYK_TO_COLOR_FUNC(cmyk, color_threshold, unsigned char, 8, 0)
+CMYK_TO_COLOR_FUNC(cmyk, color_threshold, unsigned short, 16, 0)
+GENERIC_COLOR_FUNC(cmyk, color_threshold)
+CMYK_TO_COLOR_FUNC(kcmy, color_threshold, unsigned char, 8, 1)
+CMYK_TO_COLOR_FUNC(kcmy, color_threshold, unsigned short, 16, 1)
+GENERIC_COLOR_FUNC(kcmy, color_threshold)
+CMYK_TO_COLOR_FUNC(cmyk, color_fast, unsigned char, 8, 0)
+CMYK_TO_COLOR_FUNC(cmyk, color_fast, unsigned short, 16, 0)
+GENERIC_COLOR_FUNC(cmyk, color_fast)
+CMYK_TO_COLOR_FUNC(kcmy, color_fast, unsigned char, 8, 1)
+CMYK_TO_COLOR_FUNC(kcmy, color_fast, unsigned short, 16, 1)
+GENERIC_COLOR_FUNC(kcmy, color_fast)
+CMYK_TO_COLOR_FUNC(cmyk, color_raw, unsigned char, 8, 0)
+CMYK_TO_COLOR_FUNC(cmyk, color_raw, unsigned short, 16, 0)
+GENERIC_COLOR_FUNC(cmyk, color_raw)
+CMYK_TO_COLOR_FUNC(kcmy, color_raw, unsigned char, 8, 1)
+CMYK_TO_COLOR_FUNC(kcmy, color_raw, unsigned short, 16, 1)
+GENERIC_COLOR_FUNC(kcmy, color_raw)
+
+#define CMYK_TO_KCMY_FUNC(T, size) \
+static unsigned \
+cmyk_##size##_to_kcmy(const stp_vars_t *vars, \
+ const unsigned char *in, \
+ unsigned short *out) \
+{ \
+ int i; \
+ unsigned retval = 0; \
+ int j; \
+ int nz[4]; \
+ const T *s_in = (const T *) in; \
+ lut_t *lut = (lut_t *)(stp_get_component_data(vars, "Color")); \
+ const unsigned short *user; \
+ const unsigned short *maps[4]; \
+ \
+ for (i = 0; i < 4; i++) \
+ { \
+ stp_curve_resample(lut->channel_curves[i].curve, 65536); \
+ maps[i] = stp_curve_cache_get_ushort_data(&(lut->channel_curves[i])); \
+ } \
+ stp_curve_resample(lut->user_color_correction.curve, 1 << size); \
+ user = stp_curve_cache_get_ushort_data(&(lut->user_color_correction)); \
+ \
+ memset(nz, 0, sizeof(nz)); \
+ \
+ for (i = 0; i < lut->image_width; i++, out += 4) \
+ { \
+ for (j = 0; j < 4; j++) \
+ { \
+ int outpos = (j + 1) & 3; \
+ int inval = *s_in++; \
+ nz[outpos] |= inval; \
+ out[outpos] = maps[outpos][user[inval]]; \
+ } \
+ } \
+ for (j = 0; j < 4; j++) \
+ if (nz[j] == 0) \
+ retval |= (1 << j); \
+ return retval; \
+}
+
+CMYK_TO_KCMY_FUNC(unsigned char, 8)
+CMYK_TO_KCMY_FUNC(unsigned short, 16)
+GENERIC_COLOR_FUNC(cmyk, kcmy)
+
+#define KCMY_TO_KCMY_FUNC(T, size) \
+static unsigned \
+kcmy_##size##_to_kcmy(const stp_vars_t *vars, \
+ const unsigned char *in, \
+ unsigned short *out) \
+{ \
+ int i; \
+ unsigned retval = 0; \
+ int j; \
+ int nz[4]; \
+ const T *s_in = (const T *) in; \
+ lut_t *lut = (lut_t *)(stp_get_component_data(vars, "Color")); \
+ const unsigned short *user; \
+ const unsigned short *maps[4]; \
+ \
+ for (i = 0; i < 4; i++) \
+ { \
+ stp_curve_resample(lut->channel_curves[i].curve, 65536); \
+ maps[i] = stp_curve_cache_get_ushort_data(&(lut->channel_curves[i])); \
+ } \
+ stp_curve_resample(lut->user_color_correction.curve, 1 << size); \
+ user = stp_curve_cache_get_ushort_data(&(lut->user_color_correction)); \
+ \
+ memset(nz, 0, sizeof(nz)); \
+ \
+ for (i = 0; i < lut->image_width; i++, out += 4) \
+ { \
+ for (j = 0; j < 4; j++) \
+ { \
+ int inval = *s_in++; \
+ nz[j] |= inval; \
+ out[j] = maps[j][user[inval]]; \
+ } \
+ } \
+ for (j = 0; j < 4; j++) \
+ if (nz[j] == 0) \
+ retval |= (1 << j); \
+ return retval; \
+}
+
+KCMY_TO_KCMY_FUNC(unsigned char, 8)
+KCMY_TO_KCMY_FUNC(unsigned short, 16)
+GENERIC_COLOR_FUNC(kcmy, kcmy)
+
+
+#define GRAY_TO_GRAY_FUNC(T, bits) \
+static unsigned \
+gray_##bits##_to_gray(const stp_vars_t *vars, \
+ const unsigned char *in, \
+ unsigned short *out) \
+{ \
+ int i; \
+ int i0 = -1; \
+ int o0 = 0; \
+ int nz = 0; \
+ const T *s_in = (const T *) in; \
+ lut_t *lut = (lut_t *)(stp_get_component_data(vars, "Color")); \
+ int width = lut->image_width; \
+ const unsigned short *composite; \
+ const unsigned short *user; \
+ \
+ stp_curve_resample \
+ (stp_curve_cache_get_curve(&(lut->channel_curves[CHANNEL_K])), 65536); \
+ composite = \
+ stp_curve_cache_get_ushort_data(&(lut->channel_curves[CHANNEL_K])); \
+ stp_curve_resample(lut->user_color_correction.curve, 1 << bits); \
+ user = stp_curve_cache_get_ushort_data(&(lut->user_color_correction)); \
+ \
+ memset(out, 0, width * sizeof(unsigned short)); \
+ \
+ for (i = 0; i < lut->image_width; i++) \
+ { \
+ if (i0 != s_in[0]) \
+ { \
+ i0 = s_in[0]; \
+ o0 = composite[user[i0]]; \
+ nz |= o0; \
+ } \
+ out[0] = o0; \
+ s_in ++; \
+ out ++; \
+ } \
+ return nz == 0; \
+}
+
+GRAY_TO_GRAY_FUNC(unsigned char, 8)
+GRAY_TO_GRAY_FUNC(unsigned short, 16)
+GENERIC_COLOR_FUNC(gray, gray)
+
+#define COLOR_TO_GRAY_FUNC(T, bits) \
+static unsigned \
+color_##bits##_to_gray(const stp_vars_t *vars, \
+ const unsigned char *in, \
+ unsigned short *out) \
+{ \
+ int i; \
+ int i0 = -1; \
+ int i1 = -1; \
+ int i2 = -1; \
+ int o0 = 0; \
+ int nz = 0; \
+ const T *s_in = (const T *) in; \
+ lut_t *lut = (lut_t *)(stp_get_component_data(vars, "Color")); \
+ int l_red = LUM_RED; \
+ int l_green = LUM_GREEN; \
+ int l_blue = LUM_BLUE; \
+ const unsigned short *composite; \
+ const unsigned short *user; \
+ \
+ stp_curve_resample \
+ (stp_curve_cache_get_curve(&(lut->channel_curves[CHANNEL_K])), 65536); \
+ composite = \
+ stp_curve_cache_get_ushort_data(&(lut->channel_curves[CHANNEL_K])); \
+ stp_curve_resample(lut->user_color_correction.curve, 1 << bits); \
+ user = stp_curve_cache_get_ushort_data(&(lut->user_color_correction)); \
+ \
+ if (lut->input_color_description->color_model == COLOR_BLACK) \
+ { \
+ l_red = (100 - l_red) / 2; \
+ l_green = (100 - l_green) / 2; \
+ l_blue = (100 - l_blue) / 2; \
+ } \
+ \
+ for (i = 0; i < lut->image_width; i++) \
+ { \
+ if (i0 != s_in[0] || i1 != s_in[1] || i2 != s_in[2]) \
+ { \
+ i0 = s_in[0]; \
+ i1 = s_in[1]; \
+ i2 = s_in[2]; \
+ o0 = \
+ composite[user[(i0 * l_red + i1 * l_green + i2 * l_blue) / 100]]; \
+ nz |= o0; \
+ } \
+ out[0] = o0; \
+ s_in += 3; \
+ out ++; \
+ } \
+ return nz == 0; \
+}
+
+COLOR_TO_GRAY_FUNC(unsigned char, 8)
+COLOR_TO_GRAY_FUNC(unsigned short, 16)
+GENERIC_COLOR_FUNC(color, gray)
+
+
+#define CMYK_TO_GRAY_FUNC(T, bits) \
+static unsigned \
+cmyk_##bits##_to_gray(const stp_vars_t *vars, \
+ const unsigned char *in, \
+ unsigned short *out) \
+{ \
+ int i; \
+ int i0 = -1; \
+ int i1 = -1; \
+ int i2 = -1; \
+ int i3 = -4; \
+ int o0 = 0; \
+ int nz = 0; \
+ const T *s_in = (const T *) in; \
+ lut_t *lut = (lut_t *)(stp_get_component_data(vars, "Color")); \
+ int l_red = LUM_RED; \
+ int l_green = LUM_GREEN; \
+ int l_blue = LUM_BLUE; \
+ int l_white = 0; \
+ const unsigned short *composite; \
+ const unsigned short *user; \
+ \
+ stp_curve_resample \
+ (stp_curve_cache_get_curve(&(lut->channel_curves[CHANNEL_K])), 65536); \
+ composite = \
+ stp_curve_cache_get_ushort_data(&(lut->channel_curves[CHANNEL_K])); \
+ stp_curve_resample(lut->user_color_correction.curve, 1 << bits); \
+ user = stp_curve_cache_get_ushort_data(&(lut->user_color_correction)); \
+ \
+ if (lut->input_color_description->color_model == COLOR_BLACK) \
+ { \
+ l_red = (100 - l_red) / 3; \
+ l_green = (100 - l_green) / 3; \
+ l_blue = (100 - l_blue) / 3; \
+ l_white = (100 - l_white) / 3; \
+ } \
+ \
+ for (i = 0; i < lut->image_width; i++) \
+ { \
+ if (i0 != s_in[0] || i1 != s_in[1] || i2 != s_in[2] || i3 != s_in[3]) \
+ { \
+ i0 = s_in[0]; \
+ i1 = s_in[1]; \
+ i2 = s_in[2]; \
+ i3 = s_in[3]; \
+ o0 = composite[user[(i0 * l_red + i1 * l_green + \
+ i2 * l_blue + i3 * l_white) / 100]]; \
+ nz |= o0; \
+ } \
+ out[0] = o0; \
+ s_in += 4; \
+ out ++; \
+ } \
+ return nz ? 0 : 1; \
+}
+
+CMYK_TO_GRAY_FUNC(unsigned char, 8)
+CMYK_TO_GRAY_FUNC(unsigned short, 16)
+GENERIC_COLOR_FUNC(cmyk, gray)
+
+#define KCMY_TO_GRAY_FUNC(T, bits) \
+static unsigned \
+kcmy_##bits##_to_gray(const stp_vars_t *vars, \
+ const unsigned char *in, \
+ unsigned short *out) \
+{ \
+ int i; \
+ int i0 = -1; \
+ int i1 = -1; \
+ int i2 = -1; \
+ int i3 = -4; \
+ int o0 = 0; \
+ int nz = 0; \
+ const T *s_in = (const T *) in; \
+ lut_t *lut = (lut_t *)(stp_get_component_data(vars, "Color")); \
+ int l_red = LUM_RED; \
+ int l_green = LUM_GREEN; \
+ int l_blue = LUM_BLUE; \
+ int l_white = 0; \
+ const unsigned short *composite; \
+ const unsigned short *user; \
+ \
+ stp_curve_resample \
+ (stp_curve_cache_get_curve(&(lut->channel_curves[CHANNEL_K])), 65536); \
+ composite = \
+ stp_curve_cache_get_ushort_data(&(lut->channel_curves[CHANNEL_K])); \
+ stp_curve_resample(lut->user_color_correction.curve, 1 << bits); \
+ user = stp_curve_cache_get_ushort_data(&(lut->user_color_correction)); \
+ \
+ if (lut->input_color_description->color_model == COLOR_BLACK) \
+ { \
+ l_red = (100 - l_red) / 3; \
+ l_green = (100 - l_green) / 3; \
+ l_blue = (100 - l_blue) / 3; \
+ l_white = (100 - l_white) / 3; \
+ } \
+ \
+ for (i = 0; i < lut->image_width; i++) \
+ { \
+ if (i0 != s_in[0] || i1 != s_in[1] || i2 != s_in[2] || i3 != s_in[3]) \
+ { \
+ i0 = s_in[0]; \
+ i1 = s_in[1]; \
+ i2 = s_in[2]; \
+ i3 = s_in[3]; \
+ o0 = composite[user[(i0 * l_red + i1 * l_green + \
+ i2 * l_blue + i3 * l_white) / 100]]; \
+ nz |= o0; \
+ } \
+ out[0] = o0; \
+ s_in += 4; \
+ out ++; \
+ } \
+ return nz ? 0 : 1; \
+}
+
+KCMY_TO_GRAY_FUNC(unsigned char, 8)
+KCMY_TO_GRAY_FUNC(unsigned short, 16)
+GENERIC_COLOR_FUNC(kcmy, gray)
+
+#define GRAY_TO_GRAY_RAW_FUNC(T, bits) \
+static unsigned \
+gray_##bits##_to_gray_raw(const stp_vars_t *vars, \
+ const unsigned char *in, \
+ unsigned short *out) \
+{ \
+ int i; \
+ int nz = 0; \
+ const T *s_in = (const T *) in; \
+ lut_t *lut = (lut_t *)(stp_get_component_data(vars, "Color")); \
+ int width = lut->image_width; \
+ unsigned mask = 0; \
+ if (lut->invert_output) \
+ mask = 0xffff; \
+ \
+ memset(out, 0, width * sizeof(unsigned short)); \
+ \
+ for (i = 0; i < lut->image_width; i++) \
+ { \
+ out[0] = (s_in[0] * (65535 / ((1 << bits) - 1))) ^ mask; \
+ nz |= out[0]; \
+ s_in ++; \
+ out ++; \
+ } \
+ return nz == 0; \
+}
+
+GRAY_TO_GRAY_RAW_FUNC(unsigned char, 8)
+GRAY_TO_GRAY_RAW_FUNC(unsigned short, 16)
+GENERIC_COLOR_FUNC(gray, gray_raw)
+
+#define COLOR_TO_GRAY_RAW_FUNC(T, bits, invertable, name2) \
+static unsigned \
+color_##bits##_to_gray_##name2(const stp_vars_t *vars, \
+ const unsigned char *in, \
+ unsigned short *out) \
+{ \
+ int i; \
+ int i0 = -1; \
+ int i1 = -1; \
+ int i2 = -1; \
+ int o0 = 0; \
+ int nz = 0; \
+ const T *s_in = (const T *) in; \
+ lut_t *lut = (lut_t *)(stp_get_component_data(vars, "Color")); \
+ int l_red = LUM_RED; \
+ int l_green = LUM_GREEN; \
+ int l_blue = LUM_BLUE; \
+ unsigned mask = 0; \
+ if (lut->invert_output && invertable) \
+ mask = 0xffff; \
+ \
+ if (lut->input_color_description->color_model == COLOR_BLACK) \
+ { \
+ l_red = (100 - l_red) / 2; \
+ l_green = (100 - l_green) / 2; \
+ l_blue = (100 - l_blue) / 2; \
+ } \
+ \
+ for (i = 0; i < lut->image_width; i++) \
+ { \
+ if (i0 != s_in[0] || i1 != s_in[1] || i2 != s_in[2]) \
+ { \
+ i0 = s_in[0]; \
+ i1 = s_in[1]; \
+ i2 = s_in[2]; \
+ o0 = (i0 * (65535 / ((1 << bits) - 1)) * l_red + \
+ i1 * (65535 / ((1 << bits) - 1)) * l_green + \
+ i2 * (65535 / ((1 << bits) - 1)) * l_blue) / 100; \
+ o0 ^= mask; \
+ nz |= o0; \
+ } \
+ out[0] = o0; \
+ s_in += 3; \
+ out ++; \
+ } \
+ return nz == 0; \
+}
+
+COLOR_TO_GRAY_RAW_FUNC(unsigned char, 8, 1, raw)
+COLOR_TO_GRAY_RAW_FUNC(unsigned short, 16, 1, raw)
+GENERIC_COLOR_FUNC(color, gray_raw)
+COLOR_TO_GRAY_RAW_FUNC(unsigned char, 8, 0, noninvert)
+COLOR_TO_GRAY_RAW_FUNC(unsigned short, 16, 0, noninvert)
+
+
+#define CMYK_TO_GRAY_RAW_FUNC(T, bits, invertable, name2) \
+static unsigned \
+cmyk_##bits##_to_gray_##name2(const stp_vars_t *vars, \
+ const unsigned char *in, \
+ unsigned short *out) \
+{ \
+ int i; \
+ int i0 = -1; \
+ int i1 = -1; \
+ int i2 = -1; \
+ int i3 = -4; \
+ int o0 = 0; \
+ int nz = 0; \
+ const T *s_in = (const T *) in; \
+ lut_t *lut = (lut_t *)(stp_get_component_data(vars, "Color")); \
+ int l_red = LUM_RED; \
+ int l_green = LUM_GREEN; \
+ int l_blue = LUM_BLUE; \
+ int l_white = 0; \
+ unsigned mask = 0; \
+ if (lut->invert_output && invertable) \
+ mask = 0xffff; \
+ \
+ if (lut->input_color_description->color_model == COLOR_BLACK) \
+ { \
+ l_red = (100 - l_red) / 3; \
+ l_green = (100 - l_green) / 3; \
+ l_blue = (100 - l_blue) / 3; \
+ l_white = (100 - l_white) / 3; \
+ } \
+ \
+ for (i = 0; i < lut->image_width; i++) \
+ { \
+ if (i0 != s_in[0] || i1 != s_in[1] || i2 != s_in[2] || i3 != s_in[3]) \
+ { \
+ i0 = s_in[0]; \
+ i1 = s_in[1]; \
+ i2 = s_in[2]; \
+ i3 = s_in[3]; \
+ o0 = (i0 * (65535 / ((1 << bits) - 1)) * l_red + \
+ i1 * (65535 / ((1 << bits) - 1)) * l_green + \
+ i2 * (65535 / ((1 << bits) - 1)) * l_blue + \
+ i3 * (65535 / ((1 << bits) - 1)) * l_white) / 100; \
+ o0 ^= mask; \
+ nz |= o0; \
+ } \
+ out[0] = o0; \
+ s_in += 4; \
+ out ++; \
+ } \
+ return nz ? 0 : 1; \
+}
+
+CMYK_TO_GRAY_RAW_FUNC(unsigned char, 8, 1, raw)
+CMYK_TO_GRAY_RAW_FUNC(unsigned short, 16, 1, raw)
+GENERIC_COLOR_FUNC(cmyk, gray_raw)
+CMYK_TO_GRAY_RAW_FUNC(unsigned char, 8, 0, noninvert)
+CMYK_TO_GRAY_RAW_FUNC(unsigned short, 16, 0, noninvert)
+
+#define KCMY_TO_GRAY_RAW_FUNC(T, bits, invertable, name2) \
+static unsigned \
+kcmy_##bits##_to_gray_##name2(const stp_vars_t *vars, \
+ const unsigned char *in, \
+ unsigned short *out) \
+{ \
+ int i; \
+ int i0 = -1; \
+ int i1 = -1; \
+ int i2 = -1; \
+ int i3 = -4; \
+ int o0 = 0; \
+ int nz = 0; \
+ const T *s_in = (const T *) in; \
+ lut_t *lut = (lut_t *)(stp_get_component_data(vars, "Color")); \
+ int l_red = LUM_RED; \
+ int l_green = LUM_GREEN; \
+ int l_blue = LUM_BLUE; \
+ int l_white = 0; \
+ unsigned mask = 0; \
+ if (lut->invert_output && invertable) \
+ mask = 0xffff; \
+ \
+ if (lut->input_color_description->color_model == COLOR_BLACK) \
+ { \
+ l_red = (100 - l_red) / 3; \
+ l_green = (100 - l_green) / 3; \
+ l_blue = (100 - l_blue) / 3; \
+ l_white = (100 - l_white) / 3; \
+ } \
+ \
+ for (i = 0; i < lut->image_width; i++) \
+ { \
+ if (i0 != s_in[0] || i1 != s_in[1] || i2 != s_in[2] || i3 != s_in[3]) \
+ { \
+ i0 = s_in[0]; \
+ i1 = s_in[1]; \
+ i2 = s_in[2]; \
+ i3 = s_in[3]; \
+ o0 = (i0 * (65535 / ((1 << bits) - 1)) * l_white + \
+ i1 * (65535 / ((1 << bits) - 1)) * l_red + \
+ i2 * (65535 / ((1 << bits) - 1)) * l_green + \
+ i3 * (65535 / ((1 << bits) - 1)) * l_blue) / 100; \
+ o0 ^= mask; \
+ nz |= o0; \
+ } \
+ out[0] = o0; \
+ s_in += 4; \
+ out ++; \
+ } \
+ return nz ? 0 : 1; \
+}
+
+KCMY_TO_GRAY_RAW_FUNC(unsigned char, 8, 1, raw)
+KCMY_TO_GRAY_RAW_FUNC(unsigned short, 16, 1, raw)
+GENERIC_COLOR_FUNC(kcmy, gray_raw)
+KCMY_TO_GRAY_RAW_FUNC(unsigned char, 8, 0, noninvert)
+KCMY_TO_GRAY_RAW_FUNC(unsigned short, 16, 0, noninvert)
+
+#define CMYK_TO_KCMY_RAW_FUNC(T, bits) \
+static unsigned \
+cmyk_##bits##_to_kcmy_raw(const stp_vars_t *vars, \
+ const unsigned char *in, \
+ unsigned short *out) \
+{ \
+ int i; \
+ int j; \
+ int nz[4]; \
+ unsigned retval = 0; \
+ const T *s_in = (const T *) in; \
+ lut_t *lut = (lut_t *)(stp_get_component_data(vars, "Color")); \
+ \
+ memset(nz, 0, sizeof(nz)); \
+ for (i = 0; i < lut->image_width; i++) \
+ { \
+ out[0] = s_in[3] * (65535 / ((1 << bits) - 1)); \
+ out[1] = s_in[0] * (65535 / ((1 << bits) - 1)); \
+ out[2] = s_in[1] * (65535 / ((1 << bits) - 1)); \
+ out[3] = s_in[2] * (65535 / ((1 << bits) - 1)); \
+ for (j = 0; j < 4; j++) \
+ nz[j] |= out[j]; \
+ s_in += 4; \
+ out += 4; \
+ } \
+ for (j = 0; j < 4; j++) \
+ if (nz[j] == 0) \
+ retval |= (1 << j); \
+ return retval; \
+}
+
+CMYK_TO_KCMY_RAW_FUNC(unsigned char, 8)
+CMYK_TO_KCMY_RAW_FUNC(unsigned short, 16)
+GENERIC_COLOR_FUNC(cmyk, kcmy_raw)
+
+#define KCMY_TO_KCMY_RAW_FUNC(T, bits) \
+static unsigned \
+kcmy_##bits##_to_kcmy_raw(const stp_vars_t *vars, \
+ const unsigned char *in, \
+ unsigned short *out) \
+{ \
+ int i; \
+ int j; \
+ int nz[4]; \
+ unsigned retval = 0; \
+ const T *s_in = (const T *) in; \
+ lut_t *lut = (lut_t *)(stp_get_component_data(vars, "Color")); \
+ \
+ memset(nz, 0, sizeof(nz)); \
+ for (i = 0; i < lut->image_width; i++) \
+ { \
+ for (j = 0; j < 4; j++) \
+ { \
+ out[j] = s_in[j] * (65535 / ((1 << bits) - 1)); \
+ nz[j] |= out[j]; \
+ } \
+ s_in += 4; \
+ out += 4; \
+ } \
+ for (j = 0; j < 4; j++) \
+ if (nz[j] == 0) \
+ retval |= (1 << j); \
+ return retval; \
+}
+
+KCMY_TO_KCMY_RAW_FUNC(unsigned char, 8)
+KCMY_TO_KCMY_RAW_FUNC(unsigned short, 16)
+GENERIC_COLOR_FUNC(kcmy, kcmy_raw)
+
+#define DESATURATED_FUNC(name, name2, bits) \
+static unsigned \
+name##_##bits##_to_##name2##_desaturated(const stp_vars_t *vars, \
+ const unsigned char *in, \
+ unsigned short *out) \
+{ \
+ lut_t *lut = (lut_t *)(stp_get_component_data(vars, "Color")); \
+ size_t real_steps = lut->steps; \
+ unsigned status; \
+ if (!lut->gray_tmp) \
+ lut->gray_tmp = stp_malloc(2 * lut->image_width); \
+ name##_##bits##_to_gray_noninvert(vars, in, lut->gray_tmp); \
+ lut->steps = 65536; \
+ status = gray_16_to_##name2(vars, (unsigned char *) lut->gray_tmp, out); \
+ lut->steps = real_steps; \
+ return status; \
+}
+
+DESATURATED_FUNC(color, color, 8)
+DESATURATED_FUNC(color, color, 16)
+GENERIC_COLOR_FUNC(color, color_desaturated)
+DESATURATED_FUNC(color, kcmy, 8)
+DESATURATED_FUNC(color, kcmy, 16)
+GENERIC_COLOR_FUNC(color, kcmy_desaturated)
+
+DESATURATED_FUNC(cmyk, color, 8)
+DESATURATED_FUNC(cmyk, color, 16)
+GENERIC_COLOR_FUNC(cmyk, color_desaturated)
+DESATURATED_FUNC(cmyk, kcmy, 8)
+DESATURATED_FUNC(cmyk, kcmy, 16)
+GENERIC_COLOR_FUNC(cmyk, kcmy_desaturated)
+
+DESATURATED_FUNC(kcmy, color, 8)
+DESATURATED_FUNC(kcmy, color, 16)
+GENERIC_COLOR_FUNC(kcmy, color_desaturated)
+DESATURATED_FUNC(kcmy, kcmy, 8)
+DESATURATED_FUNC(kcmy, kcmy, 16)
+GENERIC_COLOR_FUNC(kcmy, kcmy_desaturated)
+
+#define CMYK_DISPATCH(name) \
+static unsigned \
+CMYK_to_##name(const stp_vars_t *vars, const unsigned char *in, \
+ unsigned short *out) \
+{ \
+ lut_t *lut = (lut_t *)(stp_get_component_data(vars, "Color")); \
+ if (lut->input_color_description->color_id == COLOR_ID_CMYK) \
+ return cmyk_to_##name(vars, in, out); \
+ else if (lut->input_color_description->color_id == COLOR_ID_KCMY) \
+ return kcmy_to_##name(vars, in, out); \
+ else \
+ { \
+ stp_eprintf(vars, "Bad dispatch to CMYK_to_%s: %d\n", #name, \
+ lut->input_color_description->color_id); \
+ return 0; \
+ } \
+}
+
+CMYK_DISPATCH(color)
+CMYK_DISPATCH(color_raw)
+CMYK_DISPATCH(color_fast)
+CMYK_DISPATCH(color_threshold)
+CMYK_DISPATCH(color_desaturated)
+CMYK_DISPATCH(kcmy)
+CMYK_DISPATCH(kcmy_raw)
+CMYK_DISPATCH(kcmy_threshold)
+CMYK_DISPATCH(kcmy_desaturated)
+CMYK_DISPATCH(gray)
+CMYK_DISPATCH(gray_raw)
+CMYK_DISPATCH(gray_threshold)
+
+#define RAW_TO_RAW_THRESHOLD_FUNC(T, name) \
+static unsigned \
+name##_to_raw_threshold(const stp_vars_t *vars, \
+ const unsigned char *in, \
+ unsigned short *out) \
+{ \
+ int i; \
+ int j; \
+ lut_t *lut = (lut_t *)(stp_get_component_data(vars, "Color")); \
+ unsigned nz[STP_CHANNEL_LIMIT]; \
+ unsigned z = (1 << lut->out_channels) - 1; \
+ const T *s_in = (const T *) in; \
+ unsigned desired_high_bit = 0; \
+ unsigned high_bit = 1 << ((sizeof(T) * 8) - 1); \
+ int width = lut->image_width; \
+ memset(out, 0, width * lut->out_channels * sizeof(unsigned short)); \
+ if (!lut->invert_output) \
+ desired_high_bit = high_bit; \
+ for (i = 0; i < lut->out_channels; i++) \
+ nz[i] = z & ~(1 << i); \
+ \
+ for (i = 0; i < width; i++) \
+ { \
+ for (j = 0; j < lut->out_channels; j++) \
+ { \
+ if ((*s_in++ & high_bit) == desired_high_bit) \
+ { \
+ z &= nz[j]; \
+ *out = 65535; \
+ } \
+ out++; \
+ } \
+ } \
+ return z; \
+}
+
+RAW_TO_RAW_THRESHOLD_FUNC(unsigned char, raw_8)
+RAW_TO_RAW_THRESHOLD_FUNC(unsigned short, raw_16)
+GENERIC_COLOR_FUNC(raw, raw_threshold)
+
+#define RAW_TO_RAW_FUNC(T, size) \
+static unsigned \
+raw_##size##_to_raw(const stp_vars_t *vars, \
+ const unsigned char *in, \
+ unsigned short *out) \
+{ \
+ int i; \
+ unsigned retval = 0; \
+ int j; \
+ int nz[STP_CHANNEL_LIMIT]; \
+ const T *s_in = (const T *) in; \
+ lut_t *lut = (lut_t *)(stp_get_component_data(vars, "Color")); \
+ const unsigned short *maps[STP_CHANNEL_LIMIT]; \
+ const unsigned short *user; \
+ \
+ for (i = 0; i < lut->out_channels; i++) \
+ { \
+ stp_curve_resample(lut->channel_curves[i].curve, 65536); \
+ maps[i] = stp_curve_cache_get_ushort_data(&(lut->channel_curves[i])); \
+ } \
+ stp_curve_resample(lut->user_color_correction.curve, 1 << size); \
+ user = stp_curve_cache_get_ushort_data(&(lut->user_color_correction)); \
+ \
+ memset(nz, 0, sizeof(nz)); \
+ \
+ for (i = 0; i < lut->image_width; i++, out += lut->out_channels) \
+ { \
+ for (j = 0; j < lut->out_channels; j++) \
+ { \
+ int inval = *s_in++; \
+ nz[j] |= inval; \
+ out[j] = maps[j][user[inval]]; \
+ } \
+ } \
+ for (j = 0; j < lut->out_channels; j++) \
+ if (nz[j] == 0) \
+ retval |= (1 << j); \
+ return retval; \
+}
+
+RAW_TO_RAW_FUNC(unsigned char, 8)
+RAW_TO_RAW_FUNC(unsigned short, 16)
+GENERIC_COLOR_FUNC(raw, raw)
+
+
+#define RAW_TO_RAW_RAW_FUNC(T, bits) \
+static unsigned \
+raw_##bits##_to_raw_raw(const stp_vars_t *vars, \
+ const unsigned char *in, \
+ unsigned short *out) \
+{ \
+ int i; \
+ int j; \
+ int nz[STP_CHANNEL_LIMIT]; \
+ unsigned retval = 0; \
+ const T *s_in = (const T *) in; \
+ lut_t *lut = (lut_t *)(stp_get_component_data(vars, "Color")); \
+ int colors = lut->in_channels; \
+ \
+ memset(nz, 0, sizeof(nz)); \
+ for (i = 0; i < lut->image_width; i++) \
+ { \
+ for (j = 0; j < colors; j++) \
+ { \
+ nz[j] |= s_in[j]; \
+ out[j] = s_in[j] * (65535 / ((1 << bits) - 1)); \
+ } \
+ s_in += colors; \
+ out += colors; \
+ } \
+ for (j = 0; j < colors; j++) \
+ if (nz[j] == 0) \
+ retval |= (1 << j); \
+ return retval; \
+}
+
+RAW_TO_RAW_RAW_FUNC(unsigned char, 8)
+RAW_TO_RAW_RAW_FUNC(unsigned short, 16)
+GENERIC_COLOR_FUNC(raw, raw_raw)
+
+
+#define CONVERSION_FUNCTION_WITH_FAST(from, to, from2) \
+static unsigned \
+generic_##from##_to_##to(const stp_vars_t *v, \
+ const unsigned char *in, \
+ unsigned short *out) \
+{ \
+ lut_t *lut = (lut_t *)(stp_get_component_data(v, "Color")); \
+ switch (lut->color_correction->correction) \
+ { \
+ case COLOR_CORRECTION_UNCORRECTED: \
+ return from2##_to_##to##_fast(v, in, out); \
+ case COLOR_CORRECTION_ACCURATE: \
+ case COLOR_CORRECTION_BRIGHT: \
+ case COLOR_CORRECTION_HUE: \
+ return from2##_to_##to(v, in, out); \
+ case COLOR_CORRECTION_DESATURATED: \
+ return from2##_to_##to##_desaturated(v, in, out); \
+ case COLOR_CORRECTION_THRESHOLD: \
+ case COLOR_CORRECTION_PREDITHERED: \
+ return from2##_to_##to##_threshold(v, in, out); \
+ case COLOR_CORRECTION_DENSITY: \
+ case COLOR_CORRECTION_RAW: \
+ return from2##_to_##to##_raw(v, in, out); \
+ default: \
+ return (unsigned) -1; \
+ } \
+}
+
+#define CONVERSION_FUNCTION_WITHOUT_FAST(from, to, from2) \
+static unsigned \
+generic_##from##_to_##to(const stp_vars_t *v, \
+ const unsigned char *in, \
+ unsigned short *out) \
+{ \
+ lut_t *lut = (lut_t *)(stp_get_component_data(v, "Color")); \
+ switch (lut->color_correction->correction) \
+ { \
+ case COLOR_CORRECTION_UNCORRECTED: \
+ case COLOR_CORRECTION_ACCURATE: \
+ case COLOR_CORRECTION_BRIGHT: \
+ case COLOR_CORRECTION_HUE: \
+ return from2##_to_##to(v, in, out); \
+ case COLOR_CORRECTION_DESATURATED: \
+ return from2##_to_##to##_desaturated(v, in, out); \
+ case COLOR_CORRECTION_THRESHOLD: \
+ case COLOR_CORRECTION_PREDITHERED: \
+ return from2##_to_##to##_threshold(v, in, out); \
+ case COLOR_CORRECTION_DENSITY: \
+ case COLOR_CORRECTION_RAW: \
+ return from2##_to_##to##_raw(v, in, out); \
+ default: \
+ return (unsigned) -1; \
+ } \
+}
+
+#define CONVERSION_FUNCTION_WITHOUT_DESATURATED(from, to, from2) \
+static unsigned \
+generic_##from##_to_##to(const stp_vars_t *v, \
+ const unsigned char *in, \
+ unsigned short *out) \
+{ \
+ lut_t *lut = (lut_t *)(stp_get_component_data(v, "Color")); \
+ switch (lut->color_correction->correction) \
+ { \
+ case COLOR_CORRECTION_UNCORRECTED: \
+ case COLOR_CORRECTION_ACCURATE: \
+ case COLOR_CORRECTION_BRIGHT: \
+ case COLOR_CORRECTION_HUE: \
+ case COLOR_CORRECTION_DESATURATED: \
+ return from2##_to_##to(v, in, out); \
+ case COLOR_CORRECTION_THRESHOLD: \
+ case COLOR_CORRECTION_PREDITHERED: \
+ return from2##_to_##to##_threshold(v, in, out); \
+ case COLOR_CORRECTION_DENSITY: \
+ case COLOR_CORRECTION_RAW: \
+ return from2##_to_##to##_raw(v, in, out); \
+ default: \
+ return (unsigned) -1; \
+ } \
+}
+
+CONVERSION_FUNCTION_WITH_FAST(cmyk, color, CMYK)
+CONVERSION_FUNCTION_WITH_FAST(color, color, color)
+CONVERSION_FUNCTION_WITH_FAST(color, kcmy, color)
+CONVERSION_FUNCTION_WITHOUT_FAST(cmyk, kcmy, CMYK)
+CONVERSION_FUNCTION_WITHOUT_DESATURATED(cmyk, gray, CMYK)
+CONVERSION_FUNCTION_WITHOUT_DESATURATED(color, gray, color)
+CONVERSION_FUNCTION_WITHOUT_DESATURATED(gray, gray, gray)
+CONVERSION_FUNCTION_WITHOUT_DESATURATED(gray, color, gray)
+CONVERSION_FUNCTION_WITHOUT_DESATURATED(gray, kcmy, gray)
+
+unsigned
+stpi_color_convert_to_gray(const stp_vars_t *v,
+ const unsigned char *in,
+ unsigned short *out)
+{
+ lut_t *lut = (lut_t *)(stp_get_component_data(v, "Color"));
+ switch (lut->input_color_description->color_id)
+ {
+ case COLOR_ID_GRAY:
+ case COLOR_ID_WHITE:
+ return generic_gray_to_gray(v, in, out);
+ case COLOR_ID_RGB:
+ case COLOR_ID_CMY:
+ return generic_color_to_gray(v, in, out);
+ case COLOR_ID_CMYK:
+ case COLOR_ID_KCMY:
+ return generic_cmyk_to_gray(v, in, out);
+ default:
+ return (unsigned) -1;
+ }
+}
+
+unsigned
+stpi_color_convert_to_color(const stp_vars_t *v,
+ const unsigned char *in,
+ unsigned short *out)
+{
+ lut_t *lut = (lut_t *)(stp_get_component_data(v, "Color"));
+ switch (lut->input_color_description->color_id)
+ {
+ case COLOR_ID_GRAY:
+ case COLOR_ID_WHITE:
+ return generic_gray_to_color(v, in, out);
+ case COLOR_ID_RGB:
+ case COLOR_ID_CMY:
+ return generic_color_to_color(v, in, out);
+ case COLOR_ID_CMYK:
+ case COLOR_ID_KCMY:
+ return generic_cmyk_to_color(v, in, out);
+ default:
+ return (unsigned) -1;
+ }
+}
+
+unsigned
+stpi_color_convert_to_kcmy(const stp_vars_t *v,
+ const unsigned char *in,
+ unsigned short *out)
+{
+ lut_t *lut = (lut_t *)(stp_get_component_data(v, "Color"));
+ switch (lut->input_color_description->color_id)
+ {
+ case COLOR_ID_GRAY:
+ case COLOR_ID_WHITE:
+ return generic_gray_to_kcmy(v, in, out);
+ case COLOR_ID_RGB:
+ case COLOR_ID_CMY:
+ return generic_color_to_kcmy(v, in, out);
+ case COLOR_ID_CMYK:
+ case COLOR_ID_KCMY:
+ return generic_cmyk_to_kcmy(v, in, out);
+ default:
+ return (unsigned) -1;
+ }
+}
+
+unsigned
+stpi_color_convert_raw(const stp_vars_t *v,
+ const unsigned char *in,
+ unsigned short *out)
+{
+ lut_t *lut = (lut_t *)(stp_get_component_data(v, "Color"));
+ switch (lut->color_correction->correction)
+ {
+ case COLOR_CORRECTION_THRESHOLD:
+ case COLOR_CORRECTION_PREDITHERED:
+ return raw_to_raw_threshold(v, in, out);
+ case COLOR_CORRECTION_UNCORRECTED:
+ case COLOR_CORRECTION_BRIGHT:
+ case COLOR_CORRECTION_HUE:
+ case COLOR_CORRECTION_ACCURATE:
+ case COLOR_CORRECTION_DESATURATED:
+ return raw_to_raw(v, in, out);
+ case COLOR_CORRECTION_RAW:
+ case COLOR_CORRECTION_DEFAULT:
+ case COLOR_CORRECTION_DENSITY:
+ return raw_to_raw_raw(v, in, out);
+ default:
+ return (unsigned) -1;
+ }
+}