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

src/main/print-color.c

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

Generated on Sat Jun 26 10:11:53 2004 for libgimpprint API Reference by doxygen1.2.17