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

src/main/print-color.c

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

Generated on Wed Aug 25 07:56:14 2004 for libgimpprint API Reference by doxygen 1.3.6