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