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