Main Page | Modules | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals | Related Pages

print-color.c

Go to the documentation of this file.
00001 /*
00002  * "$Id: print-color.c,v 1.125 2004/09/17 18:38:21 rleigh Exp $"
00003  *
00004  *   Gutenprint color management module - traditional Gutenprint 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 <gutenprint/gutenprint.h>
00033 #include "gutenprint-internal.h"
00034 #include <gutenprint/gutenprint-intl-internal.h>
00035 #include <gutenprint/curve-cache.h>
00036 #include <math.h>
00037 #ifdef HAVE_LIMITS_H
00038 #include <limits.h>
00039 #endif
00040 #include <string.h>
00041 #include "color-conversion.h"
00042 
00043 #ifdef __GNUC__
00044 #define inline __inline__
00045 #endif
00046 
00047 static const color_correction_t color_corrections[] =
00048 {
00049   { "None",        N_("Default"),       COLOR_CORRECTION_DEFAULT,     1 },
00050   { "Accurate",    N_("High Accuracy"), COLOR_CORRECTION_ACCURATE,    1 },
00051   { "Bright",      N_("Bright Colors"), COLOR_CORRECTION_BRIGHT,      1 },
00052   { "Uncorrected", N_("Uncorrected"),   COLOR_CORRECTION_UNCORRECTED, 0 },
00053   { "Desaturated", N_("Desaturated"),   COLOR_CORRECTION_DESATURATED, 0 },
00054   { "Threshold",   N_("Threshold"),     COLOR_CORRECTION_THRESHOLD,   0 },
00055   { "Density",     N_("Density"),       COLOR_CORRECTION_DENSITY,     0 },
00056   { "Raw",         N_("Raw"),           COLOR_CORRECTION_RAW,         0 },
00057   { "Predithered", N_("Pre-Dithered"),  COLOR_CORRECTION_PREDITHERED, 0 },
00058 };
00059 
00060 static const int color_correction_count =
00061 sizeof(color_corrections) / sizeof(color_correction_t);
00062 
00063 static const channel_param_t channel_params[] =
00064 {
00065   { CMASK_K, "BlackGamma",   "BlackCurve",   "WhiteGamma",   "WhiteCurve"   },
00066   { CMASK_C, "CyanGamma",    "CyanCurve",    "RedGamma",     "RedCurve"     },
00067   { CMASK_M, "MagentaGamma", "MagentaCurve", "GreenGamma",   "GreenCurve"   },
00068   { CMASK_Y, "YellowGamma",  "YellowCurve",  "BlueGamma",    "BlueCurve"    },
00069   { CMASK_W, "WhiteGamma",   "WhiteCurve",   "BlackGamma",   "BlackCurve"   },
00070   { CMASK_R, "RedGamma",     "RedCurve",     "CyanGamma",    "CyanCurve"    },
00071   { CMASK_G, "GreenGamma",   "GreenCurve",   "MagentaGamma", "MagentaCurve" },
00072   { CMASK_B, "BlueGamma",    "BlueCurve",    "YellowGamma",  "YellowCurve"  },
00073 };
00074 
00075 static const int channel_param_count =
00076 sizeof(channel_params) / sizeof(channel_param_t);
00077 
00078 static const channel_param_t raw_channel_params[] =
00079 {
00080   { 0,  "GammaCh0",  "CurveCh0",  "GammaCh0",  "CurveCh0"  },
00081   { 1,  "GammaCh1",  "CurveCh1",  "GammaCh1",  "CurveCh1"  },
00082   { 2,  "GammaCh2",  "CurveCh2",  "GammaCh2",  "CurveCh2"  },
00083   { 3,  "GammaCh3",  "CurveCh3",  "GammaCh3",  "CurveCh3"  },
00084   { 4,  "GammaCh4",  "CurveCh4",  "GammaCh4",  "CurveCh4"  },
00085   { 5,  "GammaCh5",  "CurveCh5",  "GammaCh5",  "CurveCh5"  },
00086   { 6,  "GammaCh6",  "CurveCh6",  "GammaCh6",  "CurveCh6"  },
00087   { 7,  "GammaCh7",  "CurveCh7",  "GammaCh7",  "CurveCh7"  },
00088   { 8,  "GammaCh8",  "CurveCh8",  "GammaCh8",  "CurveCh8"  },
00089   { 9,  "GammaCh9",  "CurveCh9",  "GammaCh9",  "CurveCh9"  },
00090   { 10, "GammaCh10", "CurveCh10", "GammaCh10", "CurveCh10" },
00091   { 11, "GammaCh11", "CurveCh11", "GammaCh11", "CurveCh11" },
00092   { 12, "GammaCh12", "CurveCh12", "GammaCh12", "CurveCh12" },
00093   { 13, "GammaCh13", "CurveCh13", "GammaCh13", "CurveCh13" },
00094   { 14, "GammaCh14", "CurveCh14", "GammaCh14", "CurveCh14" },
00095   { 15, "GammaCh15", "CurveCh15", "GammaCh15", "CurveCh15" },
00096   { 16, "GammaCh16", "CurveCh16", "GammaCh16", "CurveCh16" },
00097   { 17, "GammaCh17", "CurveCh17", "GammaCh17", "CurveCh17" },
00098   { 18, "GammaCh18", "CurveCh18", "GammaCh18", "CurveCh18" },
00099   { 19, "GammaCh19", "CurveCh19", "GammaCh19", "CurveCh19" },
00100   { 20, "GammaCh20", "CurveCh20", "GammaCh20", "CurveCh20" },
00101   { 21, "GammaCh21", "CurveCh21", "GammaCh21", "CurveCh21" },
00102   { 22, "GammaCh22", "CurveCh22", "GammaCh22", "CurveCh22" },
00103   { 23, "GammaCh23", "CurveCh23", "GammaCh23", "CurveCh23" },
00104   { 24, "GammaCh24", "CurveCh24", "GammaCh24", "CurveCh24" },
00105   { 25, "GammaCh25", "CurveCh25", "GammaCh25", "CurveCh25" },
00106   { 26, "GammaCh26", "CurveCh26", "GammaCh26", "CurveCh26" },
00107   { 27, "GammaCh27", "CurveCh27", "GammaCh27", "CurveCh27" },
00108   { 28, "GammaCh28", "CurveCh28", "GammaCh28", "CurveCh28" },
00109   { 29, "GammaCh29", "CurveCh29", "GammaCh29", "CurveCh29" },
00110   { 30, "GammaCh30", "CurveCh30", "GammaCh30", "CurveCh30" },
00111   { 31, "GammaCh31", "CurveCh31", "GammaCh31", "CurveCh31" },
00112 };
00113 
00114 static const int raw_channel_param_count =
00115 sizeof(raw_channel_params) / sizeof(channel_param_t);
00116 
00117 
00118 static const color_description_t color_descriptions[] =
00119 {
00120   { "Grayscale",  1, 1, COLOR_ID_GRAY,   COLOR_BLACK,   CMASK_K,      1,
00121     COLOR_CORRECTION_UNCORRECTED, &stpi_color_convert_to_gray   },
00122   { "Whitescale", 1, 1, COLOR_ID_WHITE,  COLOR_WHITE,   CMASK_K,      1,
00123     COLOR_CORRECTION_UNCORRECTED, &stpi_color_convert_to_gray   },
00124   { "RGB",        1, 1, COLOR_ID_RGB,    COLOR_WHITE,   CMASK_CMY,    3,
00125     COLOR_CORRECTION_ACCURATE,    &stpi_color_convert_to_color  },
00126   { "CMY",        1, 1, COLOR_ID_CMY,    COLOR_BLACK,   CMASK_CMY,    3,
00127     COLOR_CORRECTION_ACCURATE,    &stpi_color_convert_to_color  },
00128   { "CMYK",       1, 0, COLOR_ID_CMYK,   COLOR_BLACK,   CMASK_CMYK,   4,
00129     COLOR_CORRECTION_ACCURATE,    &stpi_color_convert_to_kcmy   },
00130   { "KCMY",       1, 1, COLOR_ID_KCMY,   COLOR_BLACK,   CMASK_CMYK,   4,
00131     COLOR_CORRECTION_ACCURATE,    &stpi_color_convert_to_kcmy   },
00132   { "CMYKRB",     0, 1, COLOR_ID_CMYKRB, COLOR_BLACK,   CMASK_CMYKRB, 6,
00133     COLOR_CORRECTION_ACCURATE,    &stpi_color_convert_to_cmykrb },
00134   { "Raw",        1, 1, COLOR_ID_RAW,    COLOR_UNKNOWN, 0,           -1,
00135     COLOR_CORRECTION_RAW,         &stpi_color_convert_raw       },
00136 };
00137 
00138 static const int color_description_count =
00139 sizeof(color_descriptions) / sizeof(color_description_t);
00140 
00141 
00142 static const channel_depth_t channel_depths[] =
00143 {
00144   { "8",  8  },
00145   { "16", 16 }
00146 };
00147 
00148 static const int channel_depth_count =
00149 sizeof(channel_depths) / sizeof(channel_depth_t);
00150 
00151 
00152 typedef struct
00153 {
00154   const stp_parameter_t param;
00155   double min;
00156   double max;
00157   double defval;
00158   unsigned channel_mask;
00159   int color_only;
00160 } float_param_t;
00161 
00162 #define RAW_GAMMA_CHANNEL(channel)                                       \
00163   {                                                                      \
00164     {                                                                    \
00165       "GammaCh" #channel, N_("Channel " #channel " Gamma"), N_("Gamma"), \
00166       N_("Gamma for raw channel " #channel),                             \
00167       STP_PARAMETER_TYPE_DOUBLE, STP_PARAMETER_CLASS_OUTPUT,             \
00168       STP_PARAMETER_LEVEL_INTERNAL, 0, 1, channel, 1, 0                  \
00169     }, 0.1, 4.0, 1.0, CMASK_RAW, 0                                       \
00170   }
00171 
00172 static const float_param_t float_parameters[] =
00173 {
00174   {
00175     {
00176       "ColorCorrection", N_("Color Correction"), N_("Basic Image Adjustment"),
00177       N_("Color correction to be applied"),
00178       STP_PARAMETER_TYPE_STRING_LIST, STP_PARAMETER_CLASS_OUTPUT,
00179       STP_PARAMETER_LEVEL_ADVANCED, 1, 1, -1, 1, 0
00180     }, 0.0, 0.0, 0.0, CMASK_EVERY, 0
00181   },
00182   {
00183     {
00184       "ChannelBitDepth", N_("Channel Bit Depth"), N_("Core Parameter"),
00185       N_("Bit depth per channel"),
00186       STP_PARAMETER_TYPE_STRING_LIST, STP_PARAMETER_CLASS_CORE,
00187       STP_PARAMETER_LEVEL_BASIC, 1, 1, -1, 1, 0
00188     }, 0.0, 0.0, 0.0, CMASK_EVERY, 0
00189   },
00190   {
00191     {
00192       "InputImageType", N_("Input Image Type"), N_("Core Parameter"),
00193       N_("Input image type"),
00194       STP_PARAMETER_TYPE_STRING_LIST, STP_PARAMETER_CLASS_CORE,
00195       STP_PARAMETER_LEVEL_BASIC, 1, 1, -1, 1, 0
00196     }, 0.0, 0.0, 0.0, CMASK_EVERY, 0
00197   },
00198   {
00199     {
00200       "STPIOutputType", N_("Output Image Type"), N_("Core Parameter"),
00201       N_("Output image type"),
00202       STP_PARAMETER_TYPE_STRING_LIST, STP_PARAMETER_CLASS_CORE,
00203       STP_PARAMETER_LEVEL_INTERNAL, 1, 1, -1, 1, 0
00204     }, 0.0, 0.0, 0.0, CMASK_EVERY, 0
00205   },
00206   {
00207     {
00208       "STPIRawChannels", N_("Raw Channels"), N_("Core Parameter"),
00209       N_("Raw Channels"),
00210       STP_PARAMETER_TYPE_INT, STP_PARAMETER_CLASS_CORE,
00211       STP_PARAMETER_LEVEL_INTERNAL, 1, 1, -1, 1, 0
00212     }, 1.0, STP_CHANNEL_LIMIT, 1.0, CMASK_EVERY, 0
00213   },
00214   {
00215     {
00216       "Brightness", N_("Brightness"), N_("Basic Image Adjustment"),
00217       N_("Brightness of the print"),
00218       STP_PARAMETER_TYPE_DOUBLE, STP_PARAMETER_CLASS_OUTPUT,
00219       STP_PARAMETER_LEVEL_BASIC, 1, 1, -1, 1, 0
00220     }, 0.0, 2.0, 1.0, CMASK_ALL, 0
00221   },
00222   {
00223     {
00224       "Contrast", N_("Contrast"), N_("Basic Image Adjustment"),
00225       N_("Contrast of the print (0 is solid gray)"),
00226       STP_PARAMETER_TYPE_DOUBLE, STP_PARAMETER_CLASS_OUTPUT,
00227       STP_PARAMETER_LEVEL_BASIC, 1, 1, -1, 1, 0
00228     }, 0.0, 4.0, 1.0, CMASK_ALL, 0
00229   },
00230   {
00231     {
00232       "LinearContrast", N_("Linear Contrast Adjustment"), N_("Advanced Image Control"),
00233       N_("Use linear vs. fixed end point contrast adjustment"),
00234       STP_PARAMETER_TYPE_BOOLEAN, STP_PARAMETER_CLASS_OUTPUT,
00235       STP_PARAMETER_LEVEL_ADVANCED3, 1, 1, -1, 1, 0
00236     }, 0.0, 0.0, 0.0, CMASK_ALL, 0
00237   },
00238   {
00239     {
00240       "Gamma", N_("Composite Gamma"), N_("Gamma"),
00241       N_("Adjust the gamma of the print. Larger values will "
00242          "produce a generally brighter print, while smaller "
00243          "values will produce a generally darker print. "),
00244       STP_PARAMETER_TYPE_DOUBLE, STP_PARAMETER_CLASS_OUTPUT,
00245       STP_PARAMETER_LEVEL_ADVANCED1, 0, 1, -1, 1, 0
00246     }, 0.1, 4.0, 1.0, CMASK_EVERY, 0
00247   },
00248   {
00249     {
00250       "AppGamma", N_("AppGamma"), N_("Gamma"),
00251       N_("Gamma value assumed by application"),
00252       STP_PARAMETER_TYPE_DOUBLE, STP_PARAMETER_CLASS_OUTPUT,
00253       STP_PARAMETER_LEVEL_INTERNAL, 0, 1, -1, 1, 0
00254     }, 0.1, 4.0, 1.0, CMASK_EVERY, 0
00255   },
00256   {
00257     {
00258       "CyanGamma", N_("Cyan"), N_("Gamma"),
00259       N_("Adjust the cyan gamma"),
00260       STP_PARAMETER_TYPE_DOUBLE, STP_PARAMETER_CLASS_OUTPUT,
00261       STP_PARAMETER_LEVEL_ADVANCED1, 0, 1, 1, 1, 0
00262     }, 0.0, 4.0, 1.0, CMASK_C, 1
00263   },
00264   {
00265     {
00266       "MagentaGamma", N_("Magenta"), N_("Gamma"),
00267       N_("Adjust the magenta gamma"),
00268       STP_PARAMETER_TYPE_DOUBLE, STP_PARAMETER_CLASS_OUTPUT,
00269       STP_PARAMETER_LEVEL_ADVANCED1, 0, 1, 2, 1, 0
00270     }, 0.0, 4.0, 1.0, CMASK_M, 1
00271   },
00272   {
00273     {
00274       "YellowGamma", N_("Yellow"), N_("Gamma"),
00275       N_("Adjust the yellow gamma"),
00276       STP_PARAMETER_TYPE_DOUBLE, STP_PARAMETER_CLASS_OUTPUT,
00277       STP_PARAMETER_LEVEL_ADVANCED1, 0, 1, 3, 1, 0
00278     }, 0.0, 4.0, 1.0, CMASK_Y, 1
00279   },
00280   {
00281     {
00282       "RedGamma", N_("Red"), N_("Gamma"),
00283       N_("Adjust the red gamma"),
00284       STP_PARAMETER_TYPE_DOUBLE, STP_PARAMETER_CLASS_OUTPUT,
00285       STP_PARAMETER_LEVEL_ADVANCED1, 0, 1, 1, 1, 0
00286     }, 0.0, 4.0, 1.0, CMASK_R, 1
00287   },
00288   {
00289     {
00290       "GreenGamma", N_("Green"), N_("Gamma"),
00291       N_("Adjust the green gamma"),
00292       STP_PARAMETER_TYPE_DOUBLE, STP_PARAMETER_CLASS_OUTPUT,
00293       STP_PARAMETER_LEVEL_ADVANCED1, 0, 1, 2, 1, 0
00294     }, 0.0, 4.0, 1.0, CMASK_G, 1
00295   },
00296   {
00297     {
00298       "BlueGamma", N_("Blue"), N_("Gamma"),
00299       N_("Adjust the blue gamma"),
00300       STP_PARAMETER_TYPE_DOUBLE, STP_PARAMETER_CLASS_OUTPUT,
00301       STP_PARAMETER_LEVEL_ADVANCED1, 0, 1, 3, 1, 0
00302     }, 0.0, 4.0, 1.0, CMASK_B, 1
00303   },
00304   {
00305     {
00306       "BlackGamma", N_("Black"), N_("Gamma"),
00307       N_("Adjust the black gamma"),
00308       STP_PARAMETER_TYPE_DOUBLE, STP_PARAMETER_CLASS_OUTPUT,
00309       STP_PARAMETER_LEVEL_ADVANCED1, 0, 1, 3, 1, 0
00310     }, 0.0, 4.0, 1.0, CMASK_K, 1
00311   },
00312   {
00313     {
00314       "Saturation", N_("Saturation"), N_("Basic Image Adjustment"),
00315       N_("Adjust the saturation (color balance) of the print\n"
00316          "Use zero saturation to produce grayscale output "
00317          "using color and black inks"),
00318       STP_PARAMETER_TYPE_DOUBLE, STP_PARAMETER_CLASS_OUTPUT,
00319       STP_PARAMETER_LEVEL_BASIC, 1, 1, -1, 1, 0
00320     }, 0.0, 9.0, 1.0, CMASK_CMY | CMASK_RGB, 1
00321   },
00322   /* Need to think this through a bit more -- rlk 20030712 */
00323   {
00324     {
00325       "InkLimit", N_("Ink Limit"), N_("Advanced Output Control"),
00326       N_("Limit the total ink printed to the page"),
00327       STP_PARAMETER_TYPE_DOUBLE, STP_PARAMETER_CLASS_OUTPUT,
00328       STP_PARAMETER_LEVEL_ADVANCED4, 0, 1, -1, 0, 0
00329     }, 0.0, STP_CHANNEL_LIMIT, STP_CHANNEL_LIMIT, CMASK_CMY, 0
00330   },
00331   {
00332     {
00333       "BlackTrans", N_("GCR Transition"), N_("Advanced Output Control"),
00334       N_("Adjust the gray component transition rate"),
00335       STP_PARAMETER_TYPE_DOUBLE, STP_PARAMETER_CLASS_OUTPUT,
00336       STP_PARAMETER_LEVEL_ADVANCED4, 0, 1, 0, 1, 0
00337     }, 0.0, 1.0, 1.0, CMASK_K, 1
00338   },
00339   {
00340     {
00341       "GCRLower", N_("GCR Lower Bound"), N_("Advanced Output Control"),
00342       N_("Lower bound of gray component reduction"),
00343       STP_PARAMETER_TYPE_DOUBLE, STP_PARAMETER_CLASS_OUTPUT,
00344       STP_PARAMETER_LEVEL_ADVANCED4, 0, 1, 0, 1, 0
00345     }, 0.0, 1.0, 0.2, CMASK_K, 1
00346   },
00347   {
00348     {
00349       "GCRUpper", N_("GCR Upper Bound"), N_("Advanced Output Control"),
00350       N_("Upper bound of gray component reduction"),
00351       STP_PARAMETER_TYPE_DOUBLE, STP_PARAMETER_CLASS_OUTPUT,
00352       STP_PARAMETER_LEVEL_ADVANCED4, 0, 1, 0, 1, 0
00353     }, 0.0, 5.0, 0.5, CMASK_K, 1
00354   },
00355   RAW_GAMMA_CHANNEL(0),
00356   RAW_GAMMA_CHANNEL(1),
00357   RAW_GAMMA_CHANNEL(2),
00358   RAW_GAMMA_CHANNEL(3),
00359   RAW_GAMMA_CHANNEL(4),
00360   RAW_GAMMA_CHANNEL(5),
00361   RAW_GAMMA_CHANNEL(6),
00362   RAW_GAMMA_CHANNEL(7),
00363   RAW_GAMMA_CHANNEL(8),
00364   RAW_GAMMA_CHANNEL(9),
00365   RAW_GAMMA_CHANNEL(10),
00366   RAW_GAMMA_CHANNEL(11),
00367   RAW_GAMMA_CHANNEL(12),
00368   RAW_GAMMA_CHANNEL(13),
00369   RAW_GAMMA_CHANNEL(14),
00370   RAW_GAMMA_CHANNEL(15),
00371   RAW_GAMMA_CHANNEL(16),
00372   RAW_GAMMA_CHANNEL(17),
00373   RAW_GAMMA_CHANNEL(18),
00374   RAW_GAMMA_CHANNEL(19),
00375   RAW_GAMMA_CHANNEL(20),
00376   RAW_GAMMA_CHANNEL(21),
00377   RAW_GAMMA_CHANNEL(22),
00378   RAW_GAMMA_CHANNEL(23),
00379   RAW_GAMMA_CHANNEL(24),
00380   RAW_GAMMA_CHANNEL(25),
00381   RAW_GAMMA_CHANNEL(26),
00382   RAW_GAMMA_CHANNEL(27),
00383   RAW_GAMMA_CHANNEL(28),
00384   RAW_GAMMA_CHANNEL(29),
00385   RAW_GAMMA_CHANNEL(30),
00386   RAW_GAMMA_CHANNEL(31),
00387 };
00388 
00389 static const int float_parameter_count =
00390 sizeof(float_parameters) / sizeof(float_param_t);
00391 
00392 typedef struct
00393 {
00394   stp_parameter_t param;
00395   stp_curve_t **defval;
00396   unsigned channel_mask;
00397   int hsl_only;
00398   int color_only;
00399 } curve_param_t;
00400 
00401 static int standard_curves_initialized = 0;
00402 
00403 static stp_curve_t *hue_map_bounds = NULL;
00404 static stp_curve_t *lum_map_bounds = NULL;
00405 static stp_curve_t *sat_map_bounds = NULL;
00406 static stp_curve_t *color_curve_bounds = NULL;
00407 static stp_curve_t *gcr_curve_bounds = NULL;
00408 
00409 
00410 #define RAW_CURVE_CHANNEL(channel)                                      \
00411   {                                                                     \
00412     {                                                                   \
00413       "CurveCh" #channel, N_("Channel " #channel " Curve"),             \
00414       N_("Output Curves"), N_("Curve for raw channel " #channel),       \
00415       STP_PARAMETER_TYPE_CURVE, STP_PARAMETER_CLASS_OUTPUT,             \
00416       STP_PARAMETER_LEVEL_INTERNAL, 0, 1, channel, 1, 0                 \
00417     }, &color_curve_bounds, CMASK_RAW, 0, 0                             \
00418   }
00419 
00420 static curve_param_t curve_parameters[] =
00421 {
00422   {
00423     {
00424       "CyanCurve", N_("Cyan Curve"), N_("Output Curves"),
00425       N_("Cyan curve"),
00426       STP_PARAMETER_TYPE_CURVE, STP_PARAMETER_CLASS_OUTPUT,
00427       STP_PARAMETER_LEVEL_ADVANCED2, 0, 1, 1, 1, 0
00428     }, &color_curve_bounds, CMASK_C, 0, 1
00429   },
00430   {
00431     {
00432       "MagentaCurve", N_("Magenta Curve"), N_("Output Curves"),
00433       N_("Magenta curve"),
00434       STP_PARAMETER_TYPE_CURVE, STP_PARAMETER_CLASS_OUTPUT,
00435       STP_PARAMETER_LEVEL_ADVANCED2, 0, 1, 2, 1, 0
00436     }, &color_curve_bounds, CMASK_M, 0, 1
00437   },
00438   {
00439     {
00440       "YellowCurve", N_("Yellow Curve"), N_("Output Curves"),
00441       N_("Yellow curve"),
00442       STP_PARAMETER_TYPE_CURVE, STP_PARAMETER_CLASS_OUTPUT,
00443       STP_PARAMETER_LEVEL_ADVANCED2, 0, 1, 3, 1, 0
00444     }, &color_curve_bounds, CMASK_Y, 0, 1
00445   },
00446   {
00447     {
00448       "BlackCurve", N_("Black Curve"), N_("Output Curves"),
00449       N_("Black curve"),
00450       STP_PARAMETER_TYPE_CURVE, STP_PARAMETER_CLASS_OUTPUT,
00451       STP_PARAMETER_LEVEL_ADVANCED2, 0, 1, 0, 1, 0
00452     }, &color_curve_bounds, CMASK_K, 0, 0
00453   },
00454   {
00455     {
00456       "RedCurve", N_("Red Curve"), N_("Output Curves"),
00457       N_("Red curve"),
00458       STP_PARAMETER_TYPE_CURVE, STP_PARAMETER_CLASS_OUTPUT,
00459       STP_PARAMETER_LEVEL_ADVANCED2, 0, 1, 1, 1, 0
00460     }, &color_curve_bounds, CMASK_R, 0, 1
00461   },
00462   {
00463     {
00464       "GreenCurve", N_("Green Curve"), N_("Output Curves"),
00465       N_("Green curve"),
00466       STP_PARAMETER_TYPE_CURVE, STP_PARAMETER_CLASS_OUTPUT,
00467       STP_PARAMETER_LEVEL_ADVANCED2, 0, 1, 1, 1, 0
00468     }, &color_curve_bounds, CMASK_G, 0, 1
00469   },
00470   {
00471     {
00472       "BlueCurve", N_("Blue Curve"), N_("Output Curves"),
00473       N_("Blue curve"),
00474       STP_PARAMETER_TYPE_CURVE, STP_PARAMETER_CLASS_OUTPUT,
00475       STP_PARAMETER_LEVEL_ADVANCED2, 0, 1, 1, 1, 0
00476     }, &color_curve_bounds, CMASK_B, 0, 1
00477   },
00478   {
00479     {
00480       "WhiteCurve", N_("White Curve"), N_("Output Curves"),
00481       N_("White curve"),
00482       STP_PARAMETER_TYPE_CURVE, STP_PARAMETER_CLASS_OUTPUT,
00483       STP_PARAMETER_LEVEL_ADVANCED2, 0, 1, 1, 1, 0
00484     }, &color_curve_bounds, CMASK_W, 0, 0
00485   },
00486   {
00487     {
00488       "HueMap", N_("Hue Map"), N_("Advanced HSL Curves"),
00489       N_("Hue adjustment curve"),
00490       STP_PARAMETER_TYPE_CURVE, STP_PARAMETER_CLASS_OUTPUT,
00491       STP_PARAMETER_LEVEL_ADVANCED3, 0, 1, -1, 1, 0
00492     }, &hue_map_bounds, CMASK_CMY | CMASK_RGB, 1, 1
00493   },
00494   {
00495     {
00496       "SatMap", N_("Saturation Map"), N_("Advanced HSL Curves"),
00497       N_("Saturation adjustment curve"),
00498       STP_PARAMETER_TYPE_CURVE, STP_PARAMETER_CLASS_OUTPUT,
00499       STP_PARAMETER_LEVEL_ADVANCED3, 0, 1, -1, 1, 0
00500     }, &sat_map_bounds, CMASK_CMY | CMASK_RGB, 1, 1
00501   },
00502   {
00503     {
00504       "LumMap", N_("Luminosity Map"), N_("Advanced HSL Curves"),
00505       N_("Luminosity adjustment curve"),
00506       STP_PARAMETER_TYPE_CURVE, STP_PARAMETER_CLASS_OUTPUT,
00507       STP_PARAMETER_LEVEL_ADVANCED3, 0, 1, -1, 1, 0
00508     }, &lum_map_bounds, CMASK_CMY | CMASK_RGB, 1, 1
00509   },
00510   {
00511     {
00512       "GCRCurve", N_("Gray Component Reduction"), N_("Advanced Output Control"),
00513       N_("Gray component reduction curve"),
00514       STP_PARAMETER_TYPE_CURVE, STP_PARAMETER_CLASS_OUTPUT,
00515       STP_PARAMETER_LEVEL_ADVANCED3, 0, 1, 0, 1, 0
00516     }, &gcr_curve_bounds, CMASK_K, 0, 1
00517   },
00518   RAW_CURVE_CHANNEL(0),
00519   RAW_CURVE_CHANNEL(1),
00520   RAW_CURVE_CHANNEL(2),
00521   RAW_CURVE_CHANNEL(3),
00522   RAW_CURVE_CHANNEL(4),
00523   RAW_CURVE_CHANNEL(5),
00524   RAW_CURVE_CHANNEL(6),
00525   RAW_CURVE_CHANNEL(7),
00526   RAW_CURVE_CHANNEL(8),
00527   RAW_CURVE_CHANNEL(9),
00528   RAW_CURVE_CHANNEL(10),
00529   RAW_CURVE_CHANNEL(11),
00530   RAW_CURVE_CHANNEL(12),
00531   RAW_CURVE_CHANNEL(13),
00532   RAW_CURVE_CHANNEL(14),
00533   RAW_CURVE_CHANNEL(15),
00534   RAW_CURVE_CHANNEL(16),
00535   RAW_CURVE_CHANNEL(17),
00536   RAW_CURVE_CHANNEL(18),
00537   RAW_CURVE_CHANNEL(19),
00538   RAW_CURVE_CHANNEL(20),
00539   RAW_CURVE_CHANNEL(21),
00540   RAW_CURVE_CHANNEL(22),
00541   RAW_CURVE_CHANNEL(23),
00542   RAW_CURVE_CHANNEL(24),
00543   RAW_CURVE_CHANNEL(25),
00544   RAW_CURVE_CHANNEL(26),
00545   RAW_CURVE_CHANNEL(27),
00546   RAW_CURVE_CHANNEL(28),
00547   RAW_CURVE_CHANNEL(29),
00548   RAW_CURVE_CHANNEL(30),
00549   RAW_CURVE_CHANNEL(31),
00550 };
00551 
00552 static const int curve_parameter_count =
00553 sizeof(curve_parameters) / sizeof(curve_param_t);
00554 
00555 
00556 static const color_description_t *
00557 get_color_description(const char *name)
00558 {
00559   int i;
00560   if (name)
00561     for (i = 0; i < color_description_count; i++)
00562       {
00563         if (strcmp(name, color_descriptions[i].name) == 0)
00564           return &(color_descriptions[i]);
00565       }
00566   return NULL;
00567 }
00568 
00569 static const channel_depth_t *
00570 get_channel_depth(const char *name)
00571 {
00572   int i;
00573   if (name)
00574     for (i = 0; i < channel_depth_count; i++)
00575       {
00576         if (strcmp(name, channel_depths[i].name) == 0)
00577           return &(channel_depths[i]);
00578       }
00579   return NULL;
00580 }
00581 
00582 static const color_correction_t *
00583 get_color_correction(const char *name)
00584 {
00585   int i;
00586   if (name)
00587     for (i = 0; i < color_correction_count; i++)
00588       {
00589         if (strcmp(name, color_corrections[i].name) == 0)
00590           return &(color_corrections[i]);
00591       }
00592   return NULL;
00593 }
00594 
00595 static const color_correction_t *
00596 get_color_correction_by_tag(color_correction_enum_t correction)
00597 {
00598   int i;
00599   for (i = 0; i < color_correction_count; i++)
00600     {
00601       if (correction == color_corrections[i].correction)
00602         return &(color_corrections[i]);
00603     }
00604   return NULL;
00605 }
00606 
00607 
00608 static void
00609 initialize_channels(stp_vars_t *v, stp_image_t *image)
00610 {
00611   lut_t *lut = (lut_t *)(stp_get_component_data(v, "Color"));
00612   if (stp_check_float_parameter(v, "InkLimit", STP_PARAMETER_ACTIVE))
00613     stp_channel_set_ink_limit(v, stp_get_float_parameter(v, "InkLimit"));
00614   stp_channel_initialize(v, image, lut->out_channels);
00615   lut->channels_are_initialized = 1;
00616 }
00617 
00618 static int
00619 stpi_color_traditional_get_row(stp_vars_t *v,
00620                                stp_image_t *image,
00621                                int row,
00622                                unsigned *zero_mask)
00623 {
00624   const lut_t *lut = (const lut_t *)(stp_get_component_data(v, "Color"));
00625   unsigned zero;
00626   if (stp_image_get_row(image, lut->in_data,
00627                         lut->image_width * lut->in_channels, row)
00628       != STP_IMAGE_STATUS_OK)
00629     return 2;
00630   if (!lut->channels_are_initialized)
00631     initialize_channels(v, image);
00632   zero = (lut->output_color_description->conversion_function)
00633     (v, lut->in_data, stp_channel_get_input(v));
00634   if (zero_mask)
00635     *zero_mask = zero;
00636   stp_channel_convert(v, zero_mask);
00637   return 0;
00638 }
00639 
00640 static void
00641 free_channels(lut_t *lut)
00642 {
00643   int i;
00644   for (i = 0; i < STP_CHANNEL_LIMIT; i++)
00645     stp_curve_free_curve_cache(&(lut->channel_curves[i]));
00646 }
00647 
00648 static lut_t *
00649 allocate_lut(void)
00650 {
00651   int i;
00652   lut_t *ret = stp_zalloc(sizeof(lut_t));
00653   for (i = 0; i < STP_CHANNEL_LIMIT; i++)
00654     {
00655       ret->gamma_values[i] = 1.0;
00656     }
00657   ret->print_gamma = 1.0;
00658   ret->app_gamma = 1.0;
00659   ret->contrast = 1.0;
00660   ret->brightness = 1.0;
00661   return ret;
00662 }
00663 
00664 static void *
00665 copy_lut(void *vlut)
00666 {
00667   const lut_t *src = (const lut_t *)vlut;
00668   int i;
00669   lut_t *dest;
00670   if (!src)
00671     return NULL;
00672   dest = allocate_lut();
00673   free_channels(dest);
00674 
00675   dest->steps = src->steps;
00676   dest->channel_depth = src->channel_depth;
00677   dest->image_width = src->image_width;
00678   dest->in_channels = src->in_channels;
00679   dest->out_channels = src->out_channels;
00680   /* Don't copy channels_are_initialized */
00681   dest->invert_output = src->invert_output;
00682   dest->input_color_description = src->input_color_description;
00683   dest->output_color_description = src->output_color_description;
00684   dest->color_correction = src->color_correction;
00685   for (i = 0; i < STP_CHANNEL_LIMIT; i++)
00686     {
00687       stp_curve_cache_copy(&(dest->channel_curves[i]), &(src->channel_curves[i]));
00688       dest->gamma_values[i] = src->gamma_values[i];
00689     }
00690   stp_curve_cache_copy(&(dest->brightness_correction),
00691                        &(src->brightness_correction));
00692   stp_curve_cache_copy(&(dest->contrast_correction),
00693                        &(src->contrast_correction));
00694   stp_curve_cache_copy(&(dest->user_color_correction),
00695                        &(src->user_color_correction));
00696   dest->print_gamma = src->print_gamma;
00697   dest->app_gamma = src->app_gamma;
00698   dest->screen_gamma = src->screen_gamma;
00699   dest->contrast = src->contrast;
00700   dest->brightness = src->brightness;
00701   dest->linear_contrast_adjustment = src->linear_contrast_adjustment;
00702   stp_curve_cache_copy(&(dest->hue_map), &(src->hue_map));
00703   stp_curve_cache_copy(&(dest->lum_map), &(src->lum_map));
00704   stp_curve_cache_copy(&(dest->sat_map), &(src->sat_map));
00705   stp_curve_cache_copy(&(dest->gcr_curve), &(src->gcr_curve));
00706   /* Don't copy gray_tmp */
00707   /* Don't copy cmy_tmp */
00708   /* Don't copy cmyk_tmp */
00709   if (src->in_data)
00710     {
00711       dest->in_data = stp_malloc(src->image_width * src->in_channels);
00712       memset(dest->in_data, 0, src->image_width * src->in_channels);
00713     }
00714   return dest;
00715 }
00716 
00717 static void
00718 free_lut(void *vlut)
00719 {
00720   lut_t *lut = (lut_t *)vlut;
00721   free_channels(lut);
00722   stp_curve_free_curve_cache(&(lut->brightness_correction));
00723   stp_curve_free_curve_cache(&(lut->contrast_correction));
00724   stp_curve_free_curve_cache(&(lut->user_color_correction));
00725   stp_curve_free_curve_cache(&(lut->hue_map));
00726   stp_curve_free_curve_cache(&(lut->lum_map));
00727   stp_curve_free_curve_cache(&(lut->sat_map));
00728   stp_curve_free_curve_cache(&(lut->gcr_curve));
00729   STP_SAFE_FREE(lut->gray_tmp);
00730   STP_SAFE_FREE(lut->cmy_tmp);
00731   STP_SAFE_FREE(lut->cmyk_tmp);
00732   STP_SAFE_FREE(lut->in_data);
00733   memset(lut, 0, sizeof(lut_t));
00734   stp_free(lut);
00735 }
00736 
00737 static stp_curve_t *
00738 compute_gcr_curve(const stp_vars_t *vars)
00739 {
00740   stp_curve_t *curve;
00741   lut_t *lut = (lut_t *)(stp_get_component_data(vars, "Color"));
00742   double k_lower = 0.0;
00743   double k_upper = 1.0;
00744   double k_trans = 1.0;
00745   double i_k_trans = 1.0;
00746   double *tmp_data = stp_malloc(sizeof(double) * lut->steps);
00747   int i;
00748 
00749   if (stp_check_float_parameter(vars, "GCRUpper", STP_PARAMETER_DEFAULTED))
00750     k_upper = stp_get_float_parameter(vars, "GCRUpper");
00751   if (stp_check_float_parameter(vars, "GCRLower", STP_PARAMETER_DEFAULTED))
00752     k_lower = stp_get_float_parameter(vars, "GCRLower");
00753   if (stp_check_float_parameter(vars, "BlackTrans", STP_PARAMETER_DEFAULTED))
00754     k_trans = stp_get_float_parameter(vars, "BlackTrans");
00755   k_upper *= lut->steps;
00756   k_lower *= lut->steps;
00757 
00758   if (k_lower > lut->steps)
00759     k_lower = lut->steps;
00760   if (k_upper < k_lower)
00761     k_upper = k_lower + 1;
00762   i_k_trans = 1.0 / k_trans;
00763 
00764   for (i = 0; i < k_lower; i ++)
00765     tmp_data[i] = 0;
00766   if (k_upper < lut->steps)
00767     {
00768       for (i = ceil(k_lower); i < k_upper; i ++)
00769         {
00770           double where = (i - k_lower) / (k_upper - k_lower);
00771           double g1 = pow(where, i_k_trans);
00772           double g2 = 1.0 - pow(1.0 - where, k_trans);
00773           double value = (g1 > g2 ? g1 : g2);
00774           tmp_data[i] = 65535.0 * k_upper * value / (double) (lut->steps - 1);
00775           tmp_data[i] = floor(tmp_data[i] + .5);
00776         }
00777       for (i = ceil(k_upper); i < lut->steps; i ++)
00778         tmp_data[i] = 65535.0 * i / (double) (lut->steps - 1);
00779     }
00780   else if (k_lower < lut->steps)
00781     for (i = ceil(k_lower); i < lut->steps; i ++)
00782       {
00783         double where = (i - k_lower) / (k_upper - k_lower);
00784         double g1 = pow(where, i_k_trans);
00785         double g2 = 1.0 - pow(1.0 - where, k_trans);
00786         double value = (g1 > g2 ? g1 : g2);
00787         tmp_data[i] = 65535.0 * lut->steps * value / (double) (lut->steps - 1);
00788         tmp_data[i] = floor(tmp_data[i] + .5);
00789       }
00790   curve = stp_curve_create(STP_CURVE_WRAP_NONE);
00791   stp_curve_set_bounds(curve, 0, 65535);
00792   if (! stp_curve_set_data(curve, lut->steps, tmp_data))
00793     {
00794       stp_eprintf(vars, "set curve data failed!\n");
00795       stp_abort();
00796     }
00797   stp_free(tmp_data);
00798   return curve;
00799 }
00800 
00801 static void
00802 initialize_gcr_curve(const stp_vars_t *vars)
00803 {
00804   lut_t *lut = (lut_t *)(stp_get_component_data(vars, "Color"));
00805   if (!stp_curve_cache_get_curve(&(lut->gcr_curve)))
00806     {
00807       if (stp_check_curve_parameter(vars, "GCRCurve", STP_PARAMETER_DEFAULTED))
00808         {
00809           double data;
00810           size_t count;
00811           int i;
00812           stp_curve_t *curve =
00813             stp_curve_create_copy(stp_get_curve_parameter(vars, "GCRCurve"));
00814           stp_curve_resample(curve, lut->steps);
00815           count = stp_curve_count_points(curve);
00816           stp_curve_set_bounds(curve, 0.0, 65535.0);
00817           for (i = 0; i < count; i++)
00818             {
00819               stp_curve_get_point(curve, i, &data);
00820               data = 65535.0 * data * (double) i / (count - 1);
00821               stp_curve_set_point(curve, i, data);
00822             }
00823           stp_curve_cache_set_curve(&(lut->gcr_curve), curve);
00824         }
00825       else
00826         stp_curve_cache_set_curve(&(lut->gcr_curve), compute_gcr_curve(vars));
00827     }
00828 }
00829 
00830 /*
00831  * Channels that are synthesized (e. g. the black channel in CMY -> CMYK
00832  * conversion) need to be computed differently from channels that are
00833  * mapped 1-1 from input to output.  Channels that are simply mapped need
00834  * to be inverted if necessary, and in addition the contrast, brightness,
00835  * and other gamma factors are factored in.  Channels that are synthesized
00836  * are never inverted, since they're computed from the output of other
00837  * channels that have already been inverted.
00838  *
00839  * This isn't simply a matter of comparing the input channels to the output
00840  * channels, since some of the conversions (K -> CMYK) work by means
00841  * of a chain of conversions (K->CMY->CMYK).  In this case, we need to
00842  * fully compute the CMY channels, but the K channel in the output is
00843  * not inverted.
00844  *
00845  * The rules that are implemented by the logic below are:
00846  *
00847  * 1) If the input is raw, we always perform the normal computation (without
00848  *    synthesizing channels).
00849  *
00850  * 2) If the output is CMY or K only, we never synthesize channels.  We've
00851  *    now covered raw, black, and CMY/RGB outputs, leaving CMYK and CMYKRB.
00852  *
00853  * 3) Output channels above CMYK are synthesized (e. g. RB in CMYKRB).
00854  *
00855  * 4) If the input is CMYK, we do not synthesize channels.
00856  *
00857  * 5) The black channel (in CMYK) is synthesized.
00858  *
00859  * 6) All other channels (CMY/RGB) are not synthesized.
00860  */
00861 
00862 static int
00863 channel_is_synthesized(lut_t *lut, int channel)
00864 {
00865   if (lut->output_color_description->color_id == COLOR_ID_RAW)
00866     return 1;                   /* Case 1 */
00867   else if (lut->output_color_description->channels == CMASK_CMY ||
00868            lut->output_color_description->channels == CMASK_K)
00869     return 0;                   /* Case 2 */
00870   else if (channel >= CHANNEL_W)
00871     return 1;                   /* Case 3 */
00872   else if (lut->input_color_description->channels == CMASK_CMYK)
00873     return 0;                   /* Case 4 */
00874   else if (channel == CHANNEL_K)
00875     return 1;                   /* Case 5 */
00876   else
00877     return 0;                   /* Case 6 */
00878 }
00879 
00880 static void
00881 compute_user_correction(lut_t *lut)
00882 {
00883   double *tmp;
00884   double *tmp_brightness;
00885   double *tmp_contrast;
00886   double xcontrast = lut->contrast;
00887   stp_curve_t *curve =
00888     stp_curve_cache_get_curve(&(lut->user_color_correction));
00889   stp_curve_t *brightness_curve =
00890     stp_curve_cache_get_curve(&(lut->brightness_correction));
00891   stp_curve_t *contrast_curve =
00892     stp_curve_cache_get_curve(&(lut->contrast_correction));
00893   double brightness = lut->brightness;
00894   int i;
00895   int isteps = lut->steps;
00896   if (isteps > 256)
00897     isteps = 256;
00898   tmp = stp_malloc(sizeof(double) * lut->steps);
00899   tmp_brightness = stp_malloc(sizeof(double) * lut->steps);
00900   tmp_contrast = stp_malloc(sizeof(double) * lut->steps);
00901   if (brightness < .001)
00902     brightness = 1000;
00903   else if (brightness > 1.999)
00904     brightness = .001;
00905   else if (brightness > 1)
00906     brightness = 2.0 - brightness;
00907   else
00908     brightness = 1.0 / brightness;
00909   for (i = 0; i < isteps; i ++)
00910     {
00911       double temp_pixel, pixel;
00912       pixel = (double) i / (double) (isteps - 1);
00913       /*
00914        * First, correct contrast
00915        */
00916       if (pixel >= .5)
00917         temp_pixel = 1.0 - pixel;
00918       else
00919         temp_pixel = pixel;
00920       if (lut->contrast > 3.99999)
00921         {
00922           if (temp_pixel < .5)
00923             temp_pixel = 0;
00924           else
00925             temp_pixel = 1;
00926         }
00927       if (temp_pixel <= .000001 && lut->contrast <= .0001)
00928         temp_pixel = .5;
00929       else if (temp_pixel > 1)
00930         temp_pixel = .5 * pow(2 * temp_pixel, xcontrast);
00931       else if (temp_pixel < 1)
00932         {
00933           if (lut->linear_contrast_adjustment)
00934             temp_pixel = 0.5 -
00935               ((0.5 - .5 * pow(2 * temp_pixel, lut->contrast)) *
00936                lut->contrast);
00937           else
00938             temp_pixel = 0.5 -
00939               ((0.5 - .5 * pow(2 * temp_pixel, lut->contrast)));
00940         }
00941       if (temp_pixel > .5)
00942         temp_pixel = .5;
00943       else if (temp_pixel < 0)
00944         temp_pixel = 0;
00945       if (pixel < .5)
00946         pixel = temp_pixel;
00947       else
00948         pixel = 1 - temp_pixel;
00949       tmp_contrast[i] = floor((pixel * 65535) + .5);
00950 
00951       /*
00952        * Second, do brightness
00953        */
00954       if (brightness < 1)
00955         pixel = pow(pixel, brightness);
00956       else
00957         pixel = 1.0 - pow(1.0 - pixel, 1.0 / brightness);
00958       tmp[i] = floor((pixel * 65535) + .5);
00959       
00960       pixel = (double) i / (double) (isteps - 1);
00961       if (brightness < 1)
00962         pixel = pow(pixel, brightness);
00963       else
00964         pixel = 1.0 - pow(1.0 - pixel, 1.0 / brightness);
00965       tmp_brightness[i] = floor((pixel * 65535) + .5);
00966     }  
00967   stp_curve_set_data(curve, isteps, tmp);
00968   if (isteps != lut->steps)
00969     stp_curve_resample(curve, lut->steps);
00970   stp_curve_set_data(brightness_curve, isteps, tmp_brightness);
00971   if (isteps != lut->steps)
00972     stp_curve_resample(brightness_curve, lut->steps);
00973   stp_curve_set_data(contrast_curve, isteps, tmp_contrast);
00974   if (isteps != lut->steps)
00975     stp_curve_resample(contrast_curve, lut->steps);
00976   stp_free(tmp);
00977   stp_free(tmp_brightness);
00978   stp_free(tmp_contrast);
00979 }
00980 
00981 static void
00982 compute_a_curve_full(lut_t *lut, int channel)
00983 {
00984   double *tmp;
00985   double pivot = .25;
00986   double ipivot = 1.0 - pivot;
00987   double xgamma = pow(pivot, lut->screen_gamma);
00988   double print_gamma=1.0+9.0*(lut->print_gamma-1.0);
00989   double pivot2 = .75;
00990   double ipivot2 = 1.0 - pivot2;
00991   double xgamma2 = pow(pivot2, print_gamma);
00992   stp_curve_t *curve = stp_curve_cache_get_curve(&(lut->channel_curves[channel]));
00993   int i;
00994   int isteps = lut->steps;
00995   if (isteps > 256)
00996     isteps = 256;
00997   tmp = stp_malloc(sizeof(double) * lut->steps);
00998   for (i = 0; i < isteps; i ++)
00999     {
01000       double pixel = (double) i / (double) (isteps - 1);
01001 
01002       if (lut->input_color_description->color_model == COLOR_BLACK)
01003         pixel = 1.0 - pixel;
01004 
01005       pixel = 1.0 -
01006         (1.0 / (1.0 - xgamma)) *
01007         (pow(pivot + ipivot * pixel, lut->screen_gamma) - xgamma);
01008 
01009       /*
01010        * Fourth, fix up cyan, magenta, yellow values
01011        */
01012       if (pixel < 0.0)
01013         pixel = 0.0;
01014       else if (pixel > 1.0)
01015         pixel = 1.0;
01016 
01017       if (pixel > .9999 && lut->gamma_values[channel] < .00001)
01018         pixel = 0;
01019       else
01020         pixel = 1 - pow(1 - pixel, lut->gamma_values[channel]);
01021       /*
01022        * Finally, fix up print gamma and scale
01023        */
01024 
01025       /*
01026        * Change to this function suggested by Alastair Robinson
01027        * blackfive@fakenhamweb.co.uk
01028        */
01029       pixel = 65535 * (1.0 / (1.0 - xgamma2)) *
01030         (pow(pivot2 + ipivot2 * pixel, print_gamma) - xgamma2);
01031       if (lut->output_color_description->color_model == COLOR_WHITE)
01032         pixel = 65535 - pixel;
01033 
01034       if (pixel <= 0.0)
01035         tmp[i] = 0;
01036       else if (pixel >= 65535.0)
01037         tmp[i] = 65535;
01038       else
01039         tmp[i] = (pixel);
01040       tmp[i] = floor(tmp[i] + 0.5);             /* rounding is done here */
01041     }
01042   stp_curve_set_data(curve, isteps, tmp);
01043   if (isteps != lut->steps)
01044     stp_curve_resample(curve, lut->steps);
01045   stp_free(tmp);
01046 }
01047 
01048 static void
01049 compute_a_curve_fast(lut_t *lut, int channel)
01050 {
01051   double *tmp;
01052   stp_curve_t *curve = stp_curve_cache_get_curve(&(lut->channel_curves[channel]));
01053   int i;
01054   int isteps = lut->steps;
01055   if (isteps > 256)
01056     isteps = 256;
01057   tmp = stp_malloc(sizeof(double) * lut->steps);
01058   for (i = 0; i < isteps; i++)
01059     {
01060       double pixel = (double) i / (double) (isteps - 1);
01061       pixel = 1 - pow(1 - pixel, lut->gamma_values[channel]);
01062       tmp[i] = floor((65535.0 * pixel) + 0.5);
01063     }
01064   stp_curve_set_data(curve, isteps, tmp);
01065   if (isteps != lut->steps)
01066     stp_curve_resample(curve, lut->steps);
01067   stp_free(tmp);
01068 }
01069 
01070 /*
01071  * If the input and output color spaces both have a particular channel,
01072  * we want to use the general algorithm.  If not (i. e. we have to
01073  * synthesize the channel), use a simple gamma curve.
01074  */
01075 static void
01076 compute_a_curve(lut_t *lut, int channel)
01077 {
01078   if (channel_is_synthesized(lut, channel))
01079     compute_a_curve_fast(lut, channel);
01080   else
01081     compute_a_curve_full(lut, channel);
01082 }
01083 
01084 static void
01085 invert_curve(stp_curve_t *curve, int invert_output)
01086 {
01087   double lo, hi;
01088   int i;
01089   size_t count;
01090   const double *data = stp_curve_get_data(curve, &count);
01091   double f_gamma = stp_curve_get_gamma(curve);
01092   double *tmp_data;
01093 
01094   stp_curve_get_bounds(curve, &lo, &hi);
01095 
01096   if (f_gamma)
01097     stp_curve_set_gamma(curve, -f_gamma);
01098   else
01099     {
01100       tmp_data = stp_malloc(sizeof(double) * count);
01101       for (i = 0; i < count; i++)
01102         tmp_data[i] = data[count - i - 1];
01103       stp_curve_set_data(curve, count, tmp_data);
01104       stp_free(tmp_data);
01105     }
01106   if (!invert_output)
01107     {
01108       stp_curve_rescale(curve, -1, STP_CURVE_COMPOSE_MULTIPLY,
01109                         STP_CURVE_BOUNDS_RESCALE);
01110       stp_curve_rescale(curve, lo + hi, STP_CURVE_COMPOSE_ADD,
01111                         STP_CURVE_BOUNDS_RESCALE);
01112     }
01113 }
01114 
01115 static void
01116 compute_one_lut(lut_t *lut, int i)
01117 {
01118   stp_curve_t *curve =
01119     stp_curve_cache_get_curve(&(lut->channel_curves[i]));
01120   if (curve)
01121     {
01122       int invert_output =
01123         !channel_is_synthesized(lut, i) && lut->invert_output;
01124       stp_curve_rescale(curve, 65535.0, STP_CURVE_COMPOSE_MULTIPLY,
01125                         STP_CURVE_BOUNDS_RESCALE);
01126       if (stp_curve_is_piecewise(curve))
01127         stp_curve_resample(curve, lut->steps);
01128       invert_curve(curve, invert_output);
01129       stp_curve_resample(curve, lut->steps);
01130     }
01131   else
01132     {
01133       curve = stp_curve_create_copy(color_curve_bounds);
01134       stp_curve_rescale(curve, 65535.0, STP_CURVE_COMPOSE_MULTIPLY,
01135                         STP_CURVE_BOUNDS_RESCALE);
01136       stp_curve_cache_set_curve(&(lut->channel_curves[i]), curve);
01137       compute_a_curve(lut, i);
01138     }
01139 }
01140 
01141 static void
01142 setup_channel(stp_vars_t *v, int i, const channel_param_t *p)
01143 {
01144   lut_t *lut = (lut_t *)(stp_get_component_data(v, "Color"));
01145   const char *gamma_name =
01146     (lut->output_color_description->color_model == COLOR_BLACK ?
01147      p->gamma_name : p->rgb_gamma_name);
01148   const char *curve_name =
01149     (lut->output_color_description->color_model == COLOR_BLACK ?
01150      p->curve_name : p->rgb_curve_name);
01151   if (stp_check_float_parameter(v, p->gamma_name, STP_PARAMETER_DEFAULTED))
01152     lut->gamma_values[i] = stp_get_float_parameter(v, gamma_name);
01153 
01154   if (stp_get_curve_parameter_active(v, curve_name) > 0 &&
01155       stp_get_curve_parameter_active(v, curve_name) >=
01156       stp_get_float_parameter_active(v, gamma_name))
01157     stp_curve_cache_set_curve_copy
01158       (&(lut->channel_curves[i]), stp_get_curve_parameter(v, curve_name));
01159 
01160   stp_dprintf(STP_DBG_LUT, v, " %s %.3f\n", gamma_name, lut->gamma_values[i]);
01161   compute_one_lut(lut, i);
01162 }
01163 
01164 
01165 static void
01166 stpi_compute_lut(stp_vars_t *v)
01167 {
01168   int i;
01169   lut_t *lut = (lut_t *)(stp_get_component_data(v, "Color"));
01170   stp_curve_t *curve;
01171   stp_dprintf(STP_DBG_LUT, v, "stpi_compute_lut\n");
01172 
01173   if (lut->input_color_description->color_model == COLOR_UNKNOWN ||
01174       lut->output_color_description->color_model == COLOR_UNKNOWN ||
01175       lut->input_color_description->color_model ==
01176       lut->output_color_description->color_model)
01177     lut->invert_output = 0;
01178   else
01179     lut->invert_output = 1;
01180 
01181   lut->linear_contrast_adjustment = 0;
01182   lut->print_gamma = 1.0;
01183   lut->app_gamma = 1.0;
01184   lut->contrast = 1.0;
01185   lut->brightness = 1.0;
01186 
01187   if (stp_check_boolean_parameter(v, "LinearContrast", STP_PARAMETER_DEFAULTED))
01188     lut->linear_contrast_adjustment =
01189       stp_get_boolean_parameter(v, "LinearContrast");
01190   if (stp_check_float_parameter(v, "Gamma", STP_PARAMETER_DEFAULTED))
01191     lut->print_gamma = stp_get_float_parameter(v, "Gamma");
01192   if (stp_check_float_parameter(v, "Contrast", STP_PARAMETER_DEFAULTED))
01193     lut->contrast = stp_get_float_parameter(v, "Contrast");
01194   if (stp_check_float_parameter(v, "Brightness", STP_PARAMETER_DEFAULTED))
01195     lut->brightness = stp_get_float_parameter(v, "Brightness");
01196 
01197   if (stp_check_float_parameter(v, "AppGamma", STP_PARAMETER_ACTIVE))
01198     lut->app_gamma = stp_get_float_parameter(v, "AppGamma");
01199   lut->screen_gamma = lut->app_gamma / 4.0; /* "Empirical" */
01200   curve = stp_curve_create_copy(color_curve_bounds);
01201   stp_curve_rescale(curve, 65535.0, STP_CURVE_COMPOSE_MULTIPLY,
01202                     STP_CURVE_BOUNDS_RESCALE);
01203   stp_curve_cache_set_curve(&(lut->user_color_correction), curve);
01204   curve = stp_curve_create_copy(color_curve_bounds);
01205   stp_curve_rescale(curve, 65535.0, STP_CURVE_COMPOSE_MULTIPLY,
01206                     STP_CURVE_BOUNDS_RESCALE);
01207   stp_curve_cache_set_curve(&(lut->brightness_correction), curve);
01208   curve = stp_curve_create_copy(color_curve_bounds);
01209   stp_curve_rescale(curve, 65535.0, STP_CURVE_COMPOSE_MULTIPLY,
01210                     STP_CURVE_BOUNDS_RESCALE);
01211   stp_curve_cache_set_curve(&(lut->contrast_correction), curve);
01212   compute_user_correction(lut);
01213 
01214   /*
01215    * TODO check that these are wraparound curves and all that
01216    */
01217 
01218   if (lut->color_correction->correct_hsl)
01219     {
01220       if (stp_check_curve_parameter(v, "HueMap", STP_PARAMETER_DEFAULTED))
01221         {
01222           lut->hue_map.curve =
01223             stp_curve_create_copy(stp_get_curve_parameter(v, "HueMap"));
01224           if (stp_curve_is_piecewise(lut->hue_map.curve))
01225             stp_curve_resample(lut->hue_map.curve, 384);
01226         }
01227       if (stp_check_curve_parameter(v, "LumMap", STP_PARAMETER_DEFAULTED))
01228         {
01229           lut->lum_map.curve =
01230             stp_curve_create_copy(stp_get_curve_parameter(v, "LumMap"));
01231           if (stp_curve_is_piecewise(lut->lum_map.curve))
01232             stp_curve_resample(lut->lum_map.curve, 384);
01233         }
01234       if (stp_check_curve_parameter(v, "SatMap", STP_PARAMETER_DEFAULTED))
01235         {
01236           lut->sat_map.curve =
01237             stp_curve_create_copy(stp_get_curve_parameter(v, "SatMap"));
01238           if (stp_curve_is_piecewise(lut->sat_map.curve))
01239             stp_curve_resample(lut->sat_map.curve, 384);
01240         }
01241     }
01242 
01243   stp_dprintf(STP_DBG_LUT, v, " print_gamma %.3f\n", lut->print_gamma);
01244   stp_dprintf(STP_DBG_LUT, v, " contrast %.3f\n", lut->contrast);
01245   stp_dprintf(STP_DBG_LUT, v, " brightness %.3f\n", lut->brightness);
01246   stp_dprintf(STP_DBG_LUT, v, " screen_gamma %.3f\n", lut->screen_gamma);
01247 
01248   for (i = 0; i < STP_CHANNEL_LIMIT; i++)
01249     {
01250       if (lut->output_color_description->channel_count < 1 &&
01251           i < lut->out_channels)
01252         setup_channel(v, i, &(raw_channel_params[i]));
01253       else if (i < channel_param_count &&
01254                lut->output_color_description->channels & (1 << i))
01255         setup_channel(v, i, &(channel_params[i]));
01256     }
01257   if (((lut->output_color_description->channels & CMASK_CMYK) == CMASK_CMYK) &&
01258       (lut->color_correction->correction == COLOR_CORRECTION_DESATURATED ||
01259        lut->input_color_description->color_id == COLOR_ID_GRAY ||
01260        lut->input_color_description->color_id == COLOR_ID_WHITE ||
01261        lut->input_color_description->color_id == COLOR_ID_RGB ||
01262        lut->input_color_description->color_id == COLOR_ID_CMY))
01263     initialize_gcr_curve(v);
01264 }
01265 
01266 static int
01267 stpi_color_traditional_init(stp_vars_t *v,
01268                             stp_image_t *image,
01269                             size_t steps)
01270 {
01271   lut_t *lut;
01272   const char *image_type = stp_get_string_parameter(v, "ImageType");
01273   const char *color_correction = stp_get_string_parameter(v, "ColorCorrection");
01274   const channel_depth_t *channel_depth =
01275     get_channel_depth(stp_get_string_parameter(v, "ChannelBitDepth"));
01276   size_t total_channel_bits;
01277 
01278   if (steps != 256 && steps != 65536)
01279     return -1;
01280   if (!channel_depth)
01281     return -1;
01282 
01283   lut = allocate_lut();
01284   lut->input_color_description =
01285     get_color_description(stp_get_string_parameter(v, "InputImageType"));
01286   lut->output_color_description =
01287     get_color_description(stp_get_string_parameter(v, "STPIOutputType"));
01288 
01289   if (!lut->input_color_description || !lut->output_color_description)
01290     {
01291       free_lut(lut);
01292       return -1;
01293     }
01294 
01295   if (lut->input_color_description->color_id == COLOR_ID_RAW)
01296     {
01297       if (stp_verify_parameter(v, "STPIRawChannels", 1) != PARAMETER_OK)
01298         {
01299           free_lut(lut);
01300           return -1;
01301         }
01302       lut->out_channels = stp_get_int_parameter(v, "STPIRawChannels");
01303       lut->in_channels = lut->out_channels;
01304     }
01305   else
01306     {
01307       lut->out_channels = lut->output_color_description->channel_count;
01308       lut->in_channels = lut->input_color_description->channel_count;
01309     }
01310 
01311   stp_allocate_component_data(v, "Color", copy_lut, free_lut, lut);
01312   lut->steps = steps;
01313   lut->channel_depth = channel_depth->bits;
01314 
01315   if (image_type && strcmp(image_type, "None") != 0)
01316     {
01317       if (strcmp(image_type, "Text") == 0)
01318         lut->color_correction = get_color_correction("Threshold");
01319       else
01320         lut->color_correction = get_color_correction("None");
01321     }
01322   else if (color_correction)
01323     lut->color_correction = get_color_correction(color_correction);
01324   else
01325     lut->color_correction = get_color_correction("None");
01326   if (lut->color_correction->correction == COLOR_CORRECTION_DEFAULT)
01327     lut->color_correction =
01328       (get_color_correction_by_tag
01329        (lut->output_color_description->default_correction));
01330 
01331   stpi_compute_lut(v);
01332 
01333   lut->image_width = stp_image_width(image);
01334   total_channel_bits = lut->in_channels * lut->channel_depth;
01335   lut->in_data = stp_malloc(((lut->image_width * total_channel_bits) + 7)/8);
01336   memset(lut->in_data, 0, ((lut->image_width * total_channel_bits) + 7) / 8);
01337   return lut->out_channels;
01338 }
01339 
01340 static void
01341 initialize_standard_curves(void)
01342 {
01343   if (!standard_curves_initialized)
01344     {
01345       int i;
01346       hue_map_bounds = stp_curve_create_from_string
01347         ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
01348          "<gutenprint>\n"
01349          "<curve wrap=\"wrap\" type=\"linear\" gamma=\"0\">\n"
01350          "<sequence count=\"2\" lower-bound=\"-6\" upper-bound=\"6\">\n"
01351          "0 0\n"
01352          "</sequence>\n"
01353          "</curve>\n"
01354          "</gutenprint>");
01355       lum_map_bounds = stp_curve_create_from_string
01356         ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
01357          "<gutenprint>\n"
01358          "<curve wrap=\"wrap\" type=\"linear\" gamma=\"0\">\n"
01359          "<sequence count=\"2\" lower-bound=\"0\" upper-bound=\"4\">\n"
01360          "1 1\n"
01361          "</sequence>\n"
01362          "</curve>\n"
01363          "</gutenprint>");
01364       sat_map_bounds = stp_curve_create_from_string
01365         ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
01366          "<gutenprint>\n"
01367          "<curve wrap=\"wrap\" type=\"linear\" gamma=\"0\">\n"
01368          "<sequence count=\"2\" lower-bound=\"0\" upper-bound=\"4\">\n"
01369          "1 1\n"
01370          "</sequence>\n"
01371          "</curve>\n"
01372          "</gutenprint>");
01373       color_curve_bounds = stp_curve_create_from_string
01374         ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
01375          "<gutenprint>\n"
01376          "<curve wrap=\"nowrap\" type=\"linear\" gamma=\"1.0\">\n"
01377          "<sequence count=\"0\" lower-bound=\"0\" upper-bound=\"1\">\n"
01378          "</sequence>\n"
01379          "</curve>\n"
01380          "</gutenprint>");
01381       gcr_curve_bounds = stp_curve_create_from_string
01382         ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
01383          "<gutenprint>\n"
01384          "<curve wrap=\"nowrap\" type=\"linear\" gamma=\"0.0\">\n"
01385          "<sequence count=\"2\" lower-bound=\"0\" upper-bound=\"1\">\n"
01386          "1 1\n"
01387          "</sequence>\n"
01388          "</curve>\n"
01389          "</gutenprint>");
01390       for (i = 0; i < curve_parameter_count; i++)
01391         curve_parameters[i].param.deflt.curve =
01392          *(curve_parameters[i].defval);
01393       standard_curves_initialized = 1;
01394     }
01395 }
01396 
01397 static stp_parameter_list_t
01398 stpi_color_traditional_list_parameters(const stp_vars_t *v)
01399 {
01400   stp_list_t *ret = stp_parameter_list_create();
01401   int i;
01402   initialize_standard_curves();
01403   for (i = 0; i < float_parameter_count; i++)
01404     stp_parameter_list_add_param(ret, &(float_parameters[i].param));
01405   for (i = 0; i < curve_parameter_count; i++)
01406     stp_parameter_list_add_param(ret, &(curve_parameters[i].param));
01407   return ret;
01408 }
01409 
01410 static void
01411 stpi_color_traditional_describe_parameter(const stp_vars_t *v,
01412                                           const char *name,
01413                                           stp_parameter_t *description)
01414 {
01415   int i, j;
01416   description->p_type = STP_PARAMETER_TYPE_INVALID;
01417   initialize_standard_curves();
01418   if (name == NULL)
01419     return;
01420 
01421   for (i = 0; i < float_parameter_count; i++)
01422     {
01423       const float_param_t *param = &(float_parameters[i]);
01424       if (strcmp(name, param->param.name) == 0)
01425         {
01426           stp_fill_parameter_settings(description, &(param->param));
01427           if (param->channel_mask != CMASK_EVERY)
01428             {
01429               const color_description_t *color_description =
01430                 get_color_description(stp_describe_output(v));
01431               if (color_description &&
01432                   (param->channel_mask & color_description->channels) &&
01433                   param->channel_mask != CMASK_RAW)
01434                 description->is_active = 1;
01435               else
01436                 description->is_active = 0;
01437               if (param->color_only &&
01438                   !(color_description->channels & ~CMASK_K))
01439                 description->is_active = 0;
01440             }
01441           if (stp_check_string_parameter(v, "ImageType", STP_PARAMETER_ACTIVE) &&
01442               strcmp(stp_get_string_parameter(v, "ImageType"), "None") != 0 &&
01443               description->p_level > STP_PARAMETER_LEVEL_BASIC)
01444             description->is_active = 0;
01445           switch (param->param.p_type)
01446             {
01447             case STP_PARAMETER_TYPE_BOOLEAN:
01448               description->deflt.boolean = (int) param->defval;
01449               break;
01450             case STP_PARAMETER_TYPE_INT:
01451               description->bounds.integer.upper = (int) param->max;
01452               description->bounds.integer.lower = (int) param->min;
01453               description->deflt.integer = (int) param->defval;
01454               break;
01455             case STP_PARAMETER_TYPE_DOUBLE:
01456               description->bounds.dbl.upper = param->max;
01457               description->bounds.dbl.lower = param->min;
01458               description->deflt.dbl = param->defval;
01459               if (strcmp(name, "InkLimit") == 0)
01460                 {
01461                   stp_parameter_t ink_limit_desc;
01462                   stp_describe_parameter(v, "InkChannels", &ink_limit_desc);
01463                   if (ink_limit_desc.p_type == STP_PARAMETER_TYPE_INT)
01464                     {
01465                       if (ink_limit_desc.deflt.integer > 1)
01466                         {
01467                           description->bounds.dbl.upper =
01468                             ink_limit_desc.deflt.integer;
01469                           description->deflt.dbl =
01470                             ink_limit_desc.deflt.integer;
01471                         }
01472                       else
01473                         description->is_active = 0;
01474                     }
01475                   stp_parameter_description_destroy(&ink_limit_desc);
01476                 }
01477               break;
01478             case STP_PARAMETER_TYPE_STRING_LIST:
01479               if (!strcmp(param->param.name, "ColorCorrection"))
01480                 {
01481                   description->bounds.str = stp_string_list_create();
01482                   for (j = 0; j < color_correction_count; j++)
01483                     stp_string_list_add_string
01484                       (description->bounds.str, color_corrections[j].name,
01485                        _(color_corrections[j].text));
01486                   description->deflt.str =
01487                     stp_string_list_param(description->bounds.str, 0)->name;
01488                 }
01489               else if (strcmp(name, "ChannelBitDepth") == 0)
01490                 {
01491                   description->bounds.str = stp_string_list_create();
01492                   for (j = 0; j < channel_depth_count; j++)
01493                     stp_string_list_add_string
01494                       (description->bounds.str, channel_depths[j].name,
01495                        channel_depths[j].name);
01496                   description->deflt.str =
01497                     stp_string_list_param(description->bounds.str, 0)->name;
01498                 }
01499               else if (strcmp(name, "InputImageType") == 0)
01500                 {
01501                   description->bounds.str = stp_string_list_create();
01502                   for (j = 0; j < color_description_count; j++)
01503                     if (color_descriptions[j].input)
01504                       {
01505                         if (color_descriptions[j].color_id == COLOR_ID_RAW)
01506                           {
01507                             stp_parameter_t desc;
01508                             stp_describe_parameter(v, "RawChannels", &desc);
01509                             if (desc.p_type == STP_PARAMETER_TYPE_STRING_LIST)
01510                               stp_string_list_add_string
01511                                 (description->bounds.str,
01512                                  color_descriptions[j].name,
01513                                  color_descriptions[j].name);
01514                             stp_parameter_description_destroy(&desc);
01515                           }
01516                         else
01517                           stp_string_list_add_string
01518                             (description->bounds.str,
01519                              color_descriptions[j].name,
01520                              color_descriptions[j].name);
01521                       }
01522                   description->deflt.str =
01523                     stp_string_list_param(description->bounds.str, 0)->name;
01524                 }
01525               else if (strcmp(name, "OutputImageType") == 0)
01526                 {
01527                   description->bounds.str = stp_string_list_create();
01528                   for (j = 0; j < color_description_count; j++)
01529                     if (color_descriptions[j].output)
01530                       stp_string_list_add_string
01531                         (description->bounds.str, color_descriptions[j].name,
01532                          color_descriptions[j].name);
01533                   description->deflt.str =
01534                     stp_string_list_param(description->bounds.str, 0)->name;
01535                 }
01536               break;
01537             default:
01538               break;
01539             }
01540           return;
01541         }
01542     }
01543   for (i = 0; i < curve_parameter_count; i++)
01544     {
01545       curve_param_t *param = &(curve_parameters[i]);
01546       if (strcmp(name, param->param.name) == 0)
01547         {
01548           description->is_active = 1;
01549           stp_fill_parameter_settings(description, &(param->param));
01550           if (param->channel_mask != CMASK_EVERY)
01551             {
01552               const color_description_t *color_description =
01553                 get_color_description(stp_describe_output(v));
01554               if (color_description &&
01555                   (param->channel_mask & color_description->channels))
01556                 description->is_active = 1;
01557               else
01558                 description->is_active = 0;
01559               if (param->color_only &&
01560                   !(color_description->channels & ~CMASK_K))
01561                 description->is_active = 0;
01562             }
01563           if (stp_check_string_parameter(v, "ImageType", STP_PARAMETER_ACTIVE) &&
01564               strcmp(stp_get_string_parameter(v, "ImageType"), "None") != 0 &&
01565               description->p_level > STP_PARAMETER_LEVEL_BASIC)
01566             description->is_active = 0;
01567           else if (param->hsl_only)
01568             {
01569               const color_correction_t *correction =
01570                 (get_color_correction
01571                  (stp_get_string_parameter (v, "ColorCorrection")));
01572               if (correction && !correction->correct_hsl)
01573                 description->is_active = 0;
01574             }
01575           switch (param->param.p_type)
01576             {
01577             case STP_PARAMETER_TYPE_CURVE:
01578               description->deflt.curve = *(param->defval);
01579               description->bounds.curve =
01580                 stp_curve_create_copy(*(param->defval));
01581               break;
01582             default:
01583               break;
01584             }
01585           return;
01586         }
01587     }
01588 }
01589 
01590 
01591 static const stp_colorfuncs_t stpi_color_traditional_colorfuncs =
01592 {
01593   &stpi_color_traditional_init,
01594   &stpi_color_traditional_get_row,
01595   &stpi_color_traditional_list_parameters,
01596   &stpi_color_traditional_describe_parameter
01597 };
01598 
01599 static const stp_color_t stpi_color_traditional_module_data =
01600   {
01601     "traditional",
01602     N_("Traditional Gutenprint color conversion"),
01603     &stpi_color_traditional_colorfuncs
01604   };
01605 
01606 
01607 static int
01608 color_traditional_module_init(void)
01609 {
01610   return stp_color_register(&stpi_color_traditional_module_data);
01611 }
01612 
01613 
01614 static int
01615 color_traditional_module_exit(void)
01616 {
01617   return stp_color_unregister(&stpi_color_traditional_module_data);
01618 }
01619 
01620 
01621 /* Module header */
01622 #define stp_module_version color_traditional_LTX_stp_module_version
01623 #define stp_module_data color_traditional_LTX_stp_module_data
01624 
01625 stp_module_version_t stp_module_version = {0, 0};
01626 
01627 stp_module_t stp_module_data =
01628   {
01629     "traditional",
01630     VERSION,
01631     "Traditional Gutenprint color conversion",
01632     STP_MODULE_CLASS_COLOR,
01633     NULL,
01634     color_traditional_module_init,
01635     color_traditional_module_exit,
01636     (void *) &stpi_color_traditional_module_data
01637   };

Generated on Thu Feb 10 19:29:30 2005 for libgutenprint API Reference by  doxygen 1.4.1