libgimpprint API Reference: src/main/print-color.c Source File

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_8c-source.html,v 1.1.1.2 2004/12/22 23:49:06 jlovell 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   };