Main Page   Modules   Alphabetical List   Data Structures   File List   Data Fields   Globals  

src/main/color-corrected.c

Go to the documentation of this file.
00001 /*
00002  * "$Id: print-color.c,v 1.106.2.31 2004/03/25 01:01:05 rlk Exp $"
00003  *
00004  *   Gimp-Print color management module - traditional Gimp-Print algorithm.
00005  *
00006  *   Copyright 1997-2000 Michael Sweet (mike@easysw.com) and
00007  *      Robert Krawitz (rlk@alum.mit.edu)
00008  *
00009  *   This program is free software; you can redistribute it and/or modify it
00010  *   under the terms of the GNU General Public License as published by the Free
00011  *   Software Foundation; either version 2 of the License, or (at your option)
00012  *   any later version.
00013  *
00014  *   This program is distributed in the hope that it will be useful, but
00015  *   WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
00016  *   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00017  *   for more details.
00018  *
00019  *   You should have received a copy of the GNU General Public License
00020  *   along with this program; if not, write to the Free Software
00021  *   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00022  */
00023 
00024 /*
00025  * This file must include only standard C header files.  The core code must
00026  * compile on generic platforms that don't support glib, gimp, gtk, etc.
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)  /* Suggested by Eugene Anikin <eugene@anikin.com> */
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                 s *= isadj * sisadj;
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               /*                  s *= sqrt(isadj); */
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  * 'rgb_to_rgb()' - Convert rgb image data to RGB.
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)

Generated on Wed May 12 20:21:28 2004 for libgimpprint API Reference by doxygen1.2.17