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