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

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