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