00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #ifdef HAVE_CONFIG_H
00030 #include <config.h>
00031 #endif
00032 #include <gimp-print/gimp-print.h>
00033 #include "gimp-print-internal.h"
00034 #include <gimp-print/gimp-print-intl-internal.h>
00035 #include <math.h>
00036 #ifdef HAVE_LIMITS_H
00037 #include <limits.h>
00038 #endif
00039 #include <string.h>
00040 #include "lut.h"
00041
00042 #ifdef __GNUC__
00043 #define inline __inline__
00044 #endif
00045
00046 static inline void
00047 calc_rgb_to_hsl(unsigned short *rgb, double *hue, double *sat,
00048 double *lightness)
00049 {
00050 double red, green, blue;
00051 double h, s, l;
00052 double min, max;
00053 double delta;
00054 int maxval;
00055
00056 red = rgb[0] / 65535.0;
00057 green = rgb[1] / 65535.0;
00058 blue = rgb[2] / 65535.0;
00059
00060 if (red > green)
00061 {
00062 if (red > blue)
00063 {
00064 max = red;
00065 maxval = 0;
00066 }
00067 else
00068 {
00069 max = blue;
00070 maxval = 2;
00071 }
00072 min = FMIN(green, blue);
00073 }
00074 else
00075 {
00076 if (green > blue)
00077 {
00078 max = green;
00079 maxval = 1;
00080 }
00081 else
00082 {
00083 max = blue;
00084 maxval = 2;
00085 }
00086 min = FMIN(red, blue);
00087 }
00088
00089 l = (max + min) / 2.0;
00090 delta = max - min;
00091
00092 if (delta < .000001)
00093 {
00094 s = 0.0;
00095 h = 0.0;
00096 }
00097 else
00098 {
00099 if (l <= .5)
00100 s = delta / (max + min);
00101 else
00102 s = delta / (2 - max - min);
00103
00104 if (maxval == 0)
00105 h = (green - blue) / delta;
00106 else if (maxval == 1)
00107 h = 2 + (blue - red) / delta;
00108 else
00109 h = 4 + (red - green) / delta;
00110
00111 if (h < 0.0)
00112 h += 6.0;
00113 else if (h > 6.0)
00114 h -= 6.0;
00115 }
00116
00117 *hue = h;
00118 *sat = s;
00119 *lightness = l;
00120 }
00121
00122 static inline double
00123 hsl_value(double n1, double n2, double hue)
00124 {
00125 if (hue < 0)
00126 hue += 6.0;
00127 else if (hue > 6)
00128 hue -= 6.0;
00129 if (hue < 1.0)
00130 return (n1 + (n2 - n1) * hue);
00131 else if (hue < 3.0)
00132 return (n2);
00133 else if (hue < 4.0)
00134 return (n1 + (n2 - n1) * (4.0 - hue));
00135 else
00136 return (n1);
00137 }
00138
00139 static inline void
00140 calc_hsl_to_rgb(unsigned short *rgb, double h, double s, double l)
00141 {
00142 if (s < .0000001)
00143 {
00144 if (l > 1)
00145 l = 1;
00146 else if (l < 0)
00147 l = 0;
00148 rgb[0] = l * 65535;
00149 rgb[1] = l * 65535;
00150 rgb[2] = l * 65535;
00151 }
00152 else
00153 {
00154 double m1, m2;
00155 double h1, h2;
00156 h1 = h + 2;
00157 h2 = h - 2;
00158
00159 if (l < .5)
00160 m2 = l * (1 + s);
00161 else
00162 m2 = l + s - (l * s);
00163 m1 = (l * 2) - m2;
00164 rgb[0] = 65535 * hsl_value(m1, m2, h1);
00165 rgb[1] = 65535 * hsl_value(m1, m2, h);
00166 rgb[2] = 65535 * hsl_value(m1, m2, h2);
00167 }
00168 }
00169
00170 static inline double
00171 update_saturation(double sat, double adjust, double isat)
00172 {
00173 if (adjust < 1)
00174 sat *= adjust;
00175 else
00176 {
00177 double s1 = sat * adjust;
00178 double s2 = 1.0 - ((1.0 - sat) * isat);
00179 sat = FMIN(s1, s2);
00180 }
00181 if (sat > 1)
00182 sat = 1.0;
00183 return sat;
00184 }
00185
00186 static inline double
00187 interpolate_value(const double *vec, double val)
00188 {
00189 double base = floor(val);
00190 double frac = val - base;
00191 int ibase = (int) base;
00192 double lval = vec[ibase];
00193 if (frac > 0)
00194 lval += (vec[ibase + 1] - lval) * frac;
00195 return lval;
00196 }
00197
00198 static inline void
00199 update_saturation_from_rgb(unsigned short *rgb, double adjust, double isat)
00200 {
00201 double h, s, l;
00202 calc_rgb_to_hsl(rgb, &h, &s, &l);
00203 s = update_saturation(s, adjust, isat);
00204 calc_hsl_to_rgb(rgb, h, s, l);
00205 }
00206
00207 static inline double
00208 adjust_hue(const double *hue_map, double hue, size_t points)
00209 {
00210 if (hue_map)
00211 {
00212 hue += interpolate_value(hue_map, hue * points / 6.0);
00213 if (hue < 0.0)
00214 hue += 6.0;
00215 else if (hue >= 6.0)
00216 hue -= 6.0;
00217 }
00218 return hue;
00219 }
00220
00221 static inline void
00222 adjust_hsl(unsigned short *rgbout, lut_t *lut, double ssat, double isat,
00223 int split_saturation)
00224 {
00225 const double *hue_map = cache_fast_double(&(lut->hue_map));
00226 const double *lum_map = cache_fast_double(&(lut->lum_map));
00227 const double *sat_map = cache_fast_double(&(lut->sat_map));
00228 if ((split_saturation || lum_map || hue_map || sat_map) &&
00229 (rgbout[0] != rgbout[1] || rgbout[0] != rgbout[2]))
00230 {
00231 size_t hue_count = cache_fast_count(&(lut->hue_map));
00232 size_t lum_count = cache_fast_count(&(lut->lum_map));
00233 size_t sat_count = cache_fast_count(&(lut->sat_map));
00234 double h, s, l;
00235 double oh;
00236 rgbout[0] ^= 65535;
00237 rgbout[1] ^= 65535;
00238 rgbout[2] ^= 65535;
00239 calc_rgb_to_hsl(rgbout, &h, &s, &l);
00240 s = update_saturation(s, ssat, isat);
00241 oh = h;
00242 h = adjust_hue(hue_map, h, hue_count);
00243 if (lut->lum_map.d_cache && l > 0.0001 && l < .9999)
00244 {
00245 double nh = oh * lum_count / 6.0;
00246 double el = interpolate_value(lum_map, nh);
00247 double sreflection = .8 - ((1.0 - el) / 1.3) ;
00248 double isreflection = 1.0 - sreflection;
00249 double sadj = l - sreflection;
00250 double isadj = 1;
00251 double sisadj = 1;
00252 if (sadj > 0)
00253 {
00254 isadj = (1.0 / isreflection) * (isreflection - sadj);
00255 sisadj = sqrt(isadj);
00256
00257
00258
00259 s *= sqrt(isadj * sisadj);
00260 }
00261 if (el < .9999)
00262 {
00263 double es = s;
00264 es = 1 - es;
00265 es *= es * es;
00266 es = 1 - es;
00267 el = 1.0 + (es * (el - 1.0));
00268 l *= el;
00269 }
00270 else if (el > 1.0001)
00271 l = 1.0 - pow(1.0 - l, el);
00272 if (sadj > 0)
00273 {
00274
00275 l = 1.0 - ((1.0 - l) * sqrt(sqrt(sisadj)));
00276 }
00277 }
00278 if (lut->sat_map.d_cache)
00279 {
00280 double nh = oh * sat_count / 6.0;
00281 double tmp = interpolate_value(sat_map, nh);
00282 if (tmp < .9999 || tmp > 1.0001)
00283 {
00284 s = update_saturation(s, tmp, tmp > 1.0 ? 1.0 / tmp : 1.0);
00285 }
00286 }
00287 calc_hsl_to_rgb(rgbout, h, s, l);
00288 rgbout[0] ^= 65535;
00289 rgbout[1] ^= 65535;
00290 rgbout[2] ^= 65535;
00291 }
00292 }
00293
00294 static inline void
00295 adjust_hsl_bright(unsigned short *rgbout, lut_t *lut, double ssat, double isat,
00296 int split_saturation)
00297 {
00298 const double *hue_map = cache_fast_double(&(lut->hue_map));
00299 const double *lum_map = cache_fast_double(&(lut->lum_map));
00300 if ((split_saturation || lum_map || hue_map) &&
00301 (rgbout[0] != rgbout[1] || rgbout[0] != rgbout[2]))
00302 {
00303 size_t hue_count = cache_fast_count(&(lut->hue_map));
00304 size_t lum_count = cache_fast_count(&(lut->lum_map));
00305 double h, s, l;
00306 rgbout[0] ^= 65535;
00307 rgbout[1] ^= 65535;
00308 rgbout[2] ^= 65535;
00309 calc_rgb_to_hsl(rgbout, &h, &s, &l);
00310 s = update_saturation(s, ssat, isat);
00311 h = adjust_hue(hue_map, h, hue_count);
00312 if (lum_map && l > 0.0001 && l < .9999)
00313 {
00314 double nh = h * lum_count / 6.0;
00315 double el = interpolate_value(lum_map, nh);
00316 el = 1.0 + (s * (el - 1.0));
00317 l = 1.0 - pow(1.0 - l, el);
00318 }
00319 calc_hsl_to_rgb(rgbout, h, s, l);
00320 rgbout[0] ^= 65535;
00321 rgbout[1] ^= 65535;
00322 rgbout[2] ^= 65535;
00323 }
00324 }
00325
00326 static inline void
00327 lookup_rgb(lut_t *lut, unsigned short *rgbout,
00328 const unsigned short *red, const unsigned short *green,
00329 const unsigned short *blue)
00330 {
00331 if (lut->steps == 65536)
00332 {
00333 rgbout[0] = red[rgbout[0]];
00334 rgbout[1] = green[rgbout[1]];
00335 rgbout[2] = blue[rgbout[2]];
00336 }
00337 else
00338 {
00339 rgbout[0] = red[rgbout[0] / 256];
00340 rgbout[1] = green[rgbout[1] / 256];
00341 rgbout[2] = blue[rgbout[2] / 256];
00342 }
00343 }
00344
00345 #define COLOR_TO_COLOR_FUNC(T, bits) \
00346 static unsigned \
00347 color_##bits##_to_color(stp_const_vars_t vars, const unsigned char *in, \
00348 unsigned short *out) \
00349 { \
00350 int i; \
00351 double isat = 1.0; \
00352 double ssat = stp_get_float_parameter(vars, "Saturation"); \
00353 int i0 = -1; \
00354 int i1 = -1; \
00355 int i2 = -1; \
00356 unsigned short o0 = 0; \
00357 unsigned short o1 = 0; \
00358 unsigned short o2 = 0; \
00359 unsigned short nz0 = 0; \
00360 unsigned short nz1 = 0; \
00361 unsigned short nz2 = 0; \
00362 const unsigned short *red; \
00363 const unsigned short *green; \
00364 const unsigned short *blue; \
00365 const T *s_in = (const T *) in; \
00366 lut_t *lut = (lut_t *)(stpi_get_component_data(vars, "Color")); \
00367 int compute_saturation = ssat <= .99999 || ssat >= 1.00001; \
00368 int split_saturation = ssat > 1.4; \
00369 int bright_color_adjustment = 0; \
00370 int offset = 0; \
00371 \
00372 if (lut->output_color_description->color_model == COLOR_WHITE) \
00373 offset = CHANNEL_RGB_OFFSET; \
00374 \
00375 for (i = CHANNEL_C; i <= CHANNEL_Y; i++) \
00376 stp_curve_resample(cache_get_curve(&(lut->channel_curves[i + offset])), \
00377 1 << bits); \
00378 red = cache_get_ushort_data(&(lut->channel_curves[CHANNEL_C + offset])); \
00379 green = cache_get_ushort_data(&(lut->channel_curves[CHANNEL_M + offset])); \
00380 blue = cache_get_ushort_data(&(lut->channel_curves[CHANNEL_Y + offset])); \
00381 (void) cache_get_double_data(&(lut->hue_map)); \
00382 (void) cache_get_double_data(&(lut->lum_map)); \
00383 (void) cache_get_double_data(&(lut->sat_map)); \
00384 \
00385 if (split_saturation) \
00386 ssat = sqrt(ssat); \
00387 if (ssat > 1) \
00388 isat = 1.0 / ssat; \
00389 for (i = 0; i < lut->image_width; i++) \
00390 { \
00391 if (i0 == s_in[0] && i1 == s_in[1] && i2 == s_in[2]) \
00392 { \
00393 out[0] = o0; \
00394 out[1] = o1; \
00395 out[2] = o2; \
00396 } \
00397 else \
00398 { \
00399 i0 = s_in[0]; \
00400 i1 = s_in[1]; \
00401 i2 = s_in[2]; \
00402 out[0] = i0 * (65535u / (unsigned) ((1 << bits) - 1)); \
00403 out[1] = i1 * (65535u / (unsigned) ((1 << bits) - 1)); \
00404 out[2] = i2 * (65535u / (unsigned) ((1 << bits) - 1)); \
00405 if ((compute_saturation) && (out[0] != out[1] || out[0] != out[2])) \
00406 update_saturation_from_rgb(out, ssat, isat); \
00407 if (bright_color_adjustment) \
00408 adjust_hsl_bright(out, lut, ssat, isat, split_saturation); \
00409 else \
00410 adjust_hsl(out, lut, ssat, isat, split_saturation); \
00411 lookup_rgb(lut, out, red, green, blue); \
00412 o0 = out[0]; \
00413 o1 = out[1]; \
00414 o2 = out[2]; \
00415 nz0 |= o0; \
00416 nz1 |= o1; \
00417 nz2 |= o2; \
00418 } \
00419 s_in += 3; \
00420 out += 3; \
00421 } \
00422 return (nz0 ? 1 : 0) + (nz1 ? 2 : 0) + (nz2 ? 4 : 0); \
00423 }
00424
00425 COLOR_TO_COLOR_FUNC(unsigned char, 8)
00426 COLOR_TO_COLOR_FUNC(unsigned short, 16)
00427 GENERIC_COLOR_FUNC(color, color)
00428
00429
00430
00431
00432
00433 #define FAST_COLOR_TO_COLOR_FUNC(T, bits) \
00434 static unsigned \
00435 color_##bits##_to_color_fast(stp_const_vars_t vars, const unsigned char *in, \
00436 unsigned short *out) \
00437 { \
00438 int i; \
00439 int i0 = -1; \
00440 int i1 = -1; \
00441 int i2 = -1; \
00442 int o0 = 0; \
00443 int o1 = 0; \
00444 int o2 = 0; \
00445 int nz0 = 0; \
00446 int nz1 = 0; \
00447 int nz2 = 0; \
00448 const T *s_in = (const T *) in; \
00449 lut_t *lut = (lut_t *)(stpi_get_component_data(vars, "Color")); \
00450 const unsigned short *red; \
00451 const unsigned short *green; \
00452 const unsigned short *blue; \
00453 double isat = 1.0; \
00454 double saturation = stp_get_float_parameter(vars, "Saturation"); \
00455 int offset = 0; \
00456 \
00457 if (lut->output_color_description->color_model == COLOR_WHITE) \
00458 offset = CHANNEL_RGB_OFFSET; \
00459 \
00460 for (i = CHANNEL_C; i <= CHANNEL_Y; i++) \
00461 stp_curve_resample(lut->channel_curves[i + offset].curve, 1 << bits); \
00462 red = cache_get_ushort_data(&(lut->channel_curves[CHANNEL_C + offset])); \
00463 green = cache_get_ushort_data(&(lut->channel_curves[CHANNEL_M + offset])); \
00464 blue = cache_get_ushort_data(&(lut->channel_curves[CHANNEL_Y + offset])); \
00465 \
00466 if (saturation > 1) \
00467 isat = 1.0 / saturation; \
00468 for (i = 0; i < lut->image_width; i++) \
00469 { \
00470 if (i0 == s_in[0] && i1 == s_in[1] && i2 == s_in[2]) \
00471 { \
00472 out[0] = o0; \
00473 out[1] = o1; \
00474 out[2] = o2; \
00475 } \
00476 else \
00477 { \
00478 i0 = s_in[0]; \
00479 i1 = s_in[1]; \
00480 i2 = s_in[2]; \
00481 out[0] = red[s_in[0]]; \
00482 out[1] = green[s_in[1]]; \
00483 out[2] = blue[s_in[2]]; \
00484 if (saturation != 1.0) \
00485 update_saturation_from_rgb(out, saturation, isat); \
00486 o0 = out[0]; \
00487 o1 = out[1]; \
00488 o2 = out[2]; \
00489 nz0 |= o0; \
00490 nz1 |= o1; \
00491 nz2 |= o2; \
00492 } \
00493 s_in += 3; \
00494 out += 3; \
00495 } \
00496 return (nz0 ? 1 : 0) + (nz1 ? 2 : 0) + (nz2 ? 4 : 0); \
00497 }
00498
00499 FAST_COLOR_TO_COLOR_FUNC(unsigned char, 8)
00500 FAST_COLOR_TO_COLOR_FUNC(unsigned short, 16)
00501 GENERIC_COLOR_FUNC(color, color_fast)