1/* 2 * "$Id: print-color.c,v 1.143 2011/03/08 13:03:05 rlk Exp $" 3 * 4 * Gutenprint color management module - traditional Gutenprint algorithm. 5 * 6 * Copyright 1997-2000 Michael Sweet (mike@easysw.com) and 7 * Robert Krawitz (rlk@alum.mit.edu) 8 * 9 * This program is free software; you can redistribute it and/or modify it 10 * under the terms of the GNU General Public License as published by the Free 11 * Software Foundation; either version 2 of the License, or (at your option) 12 * any later version. 13 * 14 * This program is distributed in the hope that it will be useful, but 15 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 16 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 17 * for more details. 18 * 19 * You should have received a copy of the GNU General Public License 20 * along with this program; if not, write to the Free Software 21 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 22 */ 23 24/* 25 * This file must include only standard C header files. The core code must 26 * compile on generic platforms that don't support glib, gimp, gtk, etc. 27 */ 28 29#ifdef HAVE_CONFIG_H 30#include <config.h> 31#endif 32#include <gutenprint/gutenprint.h> 33#include "gutenprint-internal.h" 34#include <gutenprint/gutenprint-intl-internal.h> 35#include <gutenprint/curve-cache.h> 36#include <math.h> 37#ifdef HAVE_LIMITS_H 38#include <limits.h> 39#endif 40#include <string.h> 41#include "color-conversion.h" 42 43#ifdef __GNUC__ 44#define inline __inline__ 45#endif 46 47static const color_correction_t color_corrections[] = 48{ 49 { "None", N_("Default"), COLOR_CORRECTION_DEFAULT, 1 }, 50 { "Accurate", N_("High Accuracy"), COLOR_CORRECTION_ACCURATE, 1 }, 51 { "Bright", N_("Bright Colors"), COLOR_CORRECTION_BRIGHT, 1 }, 52 { "Hue", N_("Correct Hue Only"), COLOR_CORRECTION_HUE, 1 }, 53 { "Uncorrected", N_("Uncorrected"), COLOR_CORRECTION_UNCORRECTED, 0 }, 54 { "Desaturated", N_("Desaturated"), COLOR_CORRECTION_DESATURATED, 0 }, 55 { "Threshold", N_("Threshold"), COLOR_CORRECTION_THRESHOLD, 0 }, 56 { "Density", N_("Density"), COLOR_CORRECTION_DENSITY, 0 }, 57 { "Raw", N_("Raw"), COLOR_CORRECTION_RAW, 0 }, 58 { "Predithered", N_("Pre-Dithered"), COLOR_CORRECTION_PREDITHERED, 0 }, 59}; 60 61static const int color_correction_count = 62sizeof(color_corrections) / sizeof(color_correction_t); 63 64static const channel_param_t channel_params[] = 65{ 66 { CMASK_K, "BlackGamma", "BlackCurve", "WhiteGamma", "WhiteCurve" }, 67 { CMASK_C, "CyanGamma", "CyanCurve", "RedGamma", "RedCurve" }, 68 { CMASK_M, "MagentaGamma", "MagentaCurve", "GreenGamma", "GreenCurve" }, 69 { CMASK_Y, "YellowGamma", "YellowCurve", "BlueGamma", "BlueCurve" }, 70 { CMASK_W, "WhiteGamma", "WhiteCurve", "BlackGamma", "BlackCurve" }, 71 { CMASK_R, "RedGamma", "RedCurve", "CyanGamma", "CyanCurve" }, 72 { CMASK_G, "GreenGamma", "GreenCurve", "MagentaGamma", "MagentaCurve" }, 73 { CMASK_B, "BlueGamma", "BlueCurve", "YellowGamma", "YellowCurve" }, 74}; 75 76static const int channel_param_count = 77sizeof(channel_params) / sizeof(channel_param_t); 78 79static const channel_param_t raw_channel_params[] = 80{ 81 { 0, "GammaCh0", "CurveCh0", "GammaCh0", "CurveCh0" }, 82 { 1, "GammaCh1", "CurveCh1", "GammaCh1", "CurveCh1" }, 83 { 2, "GammaCh2", "CurveCh2", "GammaCh2", "CurveCh2" }, 84 { 3, "GammaCh3", "CurveCh3", "GammaCh3", "CurveCh3" }, 85 { 4, "GammaCh4", "CurveCh4", "GammaCh4", "CurveCh4" }, 86 { 5, "GammaCh5", "CurveCh5", "GammaCh5", "CurveCh5" }, 87 { 6, "GammaCh6", "CurveCh6", "GammaCh6", "CurveCh6" }, 88 { 7, "GammaCh7", "CurveCh7", "GammaCh7", "CurveCh7" }, 89 { 8, "GammaCh8", "CurveCh8", "GammaCh8", "CurveCh8" }, 90 { 9, "GammaCh9", "CurveCh9", "GammaCh9", "CurveCh9" }, 91 { 10, "GammaCh10", "CurveCh10", "GammaCh10", "CurveCh10" }, 92 { 11, "GammaCh11", "CurveCh11", "GammaCh11", "CurveCh11" }, 93 { 12, "GammaCh12", "CurveCh12", "GammaCh12", "CurveCh12" }, 94 { 13, "GammaCh13", "CurveCh13", "GammaCh13", "CurveCh13" }, 95 { 14, "GammaCh14", "CurveCh14", "GammaCh14", "CurveCh14" }, 96 { 15, "GammaCh15", "CurveCh15", "GammaCh15", "CurveCh15" }, 97 { 16, "GammaCh16", "CurveCh16", "GammaCh16", "CurveCh16" }, 98 { 17, "GammaCh17", "CurveCh17", "GammaCh17", "CurveCh17" }, 99 { 18, "GammaCh18", "CurveCh18", "GammaCh18", "CurveCh18" }, 100 { 19, "GammaCh19", "CurveCh19", "GammaCh19", "CurveCh19" }, 101 { 20, "GammaCh20", "CurveCh20", "GammaCh20", "CurveCh20" }, 102 { 21, "GammaCh21", "CurveCh21", "GammaCh21", "CurveCh21" }, 103 { 22, "GammaCh22", "CurveCh22", "GammaCh22", "CurveCh22" }, 104 { 23, "GammaCh23", "CurveCh23", "GammaCh23", "CurveCh23" }, 105 { 24, "GammaCh24", "CurveCh24", "GammaCh24", "CurveCh24" }, 106 { 25, "GammaCh25", "CurveCh25", "GammaCh25", "CurveCh25" }, 107 { 26, "GammaCh26", "CurveCh26", "GammaCh26", "CurveCh26" }, 108 { 27, "GammaCh27", "CurveCh27", "GammaCh27", "CurveCh27" }, 109 { 28, "GammaCh28", "CurveCh28", "GammaCh28", "CurveCh28" }, 110 { 29, "GammaCh29", "CurveCh29", "GammaCh29", "CurveCh29" }, 111 { 30, "GammaCh30", "CurveCh30", "GammaCh30", "CurveCh30" }, 112 { 31, "GammaCh31", "CurveCh31", "GammaCh31", "CurveCh31" }, 113}; 114 115static const int raw_channel_param_count = 116sizeof(raw_channel_params) / sizeof(channel_param_t); 117 118 119static const color_description_t color_descriptions[] = 120{ 121 { N_("Grayscale"), 1, 1, COLOR_ID_GRAY, COLOR_BLACK, CMASK_K, 1, 122 COLOR_CORRECTION_UNCORRECTED, &stpi_color_convert_to_gray }, 123 { N_("Whitescale"), 1, 1, COLOR_ID_WHITE, COLOR_WHITE, CMASK_K, 1, 124 COLOR_CORRECTION_UNCORRECTED, &stpi_color_convert_to_gray }, 125 { N_("RGB"), 1, 1, COLOR_ID_RGB, COLOR_WHITE, CMASK_CMY, 3, 126 COLOR_CORRECTION_ACCURATE, &stpi_color_convert_to_color }, 127 { N_("CMY"), 1, 1, COLOR_ID_CMY, COLOR_BLACK, CMASK_CMY, 3, 128 COLOR_CORRECTION_ACCURATE, &stpi_color_convert_to_color }, 129 { N_("CMYK"), 1, 0, COLOR_ID_CMYK, COLOR_BLACK, CMASK_CMYK, 4, 130 COLOR_CORRECTION_ACCURATE, &stpi_color_convert_to_kcmy }, 131 { N_("KCMY"), 1, 1, COLOR_ID_KCMY, COLOR_BLACK, CMASK_CMYK, 4, 132 COLOR_CORRECTION_ACCURATE, &stpi_color_convert_to_kcmy }, 133 { N_("Raw"), 1, 1, COLOR_ID_RAW, COLOR_UNKNOWN, 0, -1, 134 COLOR_CORRECTION_RAW, &stpi_color_convert_raw }, 135}; 136 137static const int color_description_count = 138sizeof(color_descriptions) / sizeof(color_description_t); 139 140 141static const channel_depth_t channel_depths[] = 142{ 143 { "8", 8 }, 144 { "16", 16 } 145}; 146 147static const int channel_depth_count = 148sizeof(channel_depths) / sizeof(channel_depth_t); 149 150 151typedef struct 152{ 153 const stp_parameter_t param; 154 double min; 155 double max; 156 double defval; 157 unsigned channel_mask; 158 int color_only; 159 int is_rgb; 160} float_param_t; 161 162#define RAW_GAMMA_CHANNEL(channel) \ 163 { \ 164 { \ 165 "GammaCh" #channel, N_("Channel " #channel " Gamma"), "Color=Yes,Category=Gamma", \ 166 N_("Gamma for raw channel " #channel), \ 167 STP_PARAMETER_TYPE_DOUBLE, STP_PARAMETER_CLASS_OUTPUT, \ 168 STP_PARAMETER_LEVEL_INTERNAL, 0, 1, channel, 1, 0 \ 169 }, 0.1, 4.0, 1.0, CMASK_RAW, 0, -1 \ 170 } 171 172static const float_param_t float_parameters[] = 173{ 174 { 175 { 176 "ColorCorrection", N_("Color Correction"), "Color=Yes,Category=Basic Image Adjustment", 177 N_("Color correction to be applied"), 178 STP_PARAMETER_TYPE_STRING_LIST, STP_PARAMETER_CLASS_OUTPUT, 179 STP_PARAMETER_LEVEL_BASIC, 1, 1, -1, 1, 0 180 }, 0.0, 0.0, 0.0, CMASK_EVERY, 0, -1 181 }, 182 { 183 { 184 "ChannelBitDepth", N_("Channel Bit Depth"), "Color=Yes,Category=Core Parameter", 185 N_("Bit depth per channel"), 186 STP_PARAMETER_TYPE_STRING_LIST, STP_PARAMETER_CLASS_CORE, 187 STP_PARAMETER_LEVEL_BASIC, 1, 1, -1, 1, 0 188 }, 0.0, 0.0, 0.0, CMASK_EVERY, 0, -1 189 }, 190 { 191 { 192 "InputImageType", N_("Input Image Type"), "Color=Yes,Category=Core Parameter", 193 N_("Input image type"), 194 STP_PARAMETER_TYPE_STRING_LIST, STP_PARAMETER_CLASS_CORE, 195 STP_PARAMETER_LEVEL_BASIC, 1, 1, -1, 1, 0 196 }, 0.0, 0.0, 0.0, CMASK_EVERY, 0, -1 197 }, 198 { 199 { 200 "STPIOutputType", N_("Output Image Type"), "Color=Yes,Category=Core Parameter", 201 N_("Output image type"), 202 STP_PARAMETER_TYPE_STRING_LIST, STP_PARAMETER_CLASS_CORE, 203 STP_PARAMETER_LEVEL_INTERNAL, 1, 1, -1, 1, 0 204 }, 0.0, 0.0, 0.0, CMASK_EVERY, 0, -1 205 }, 206 { 207 { 208 "STPIRawChannels", N_("Raw Channels"), "Color=Yes,Category=Core Parameter", 209 N_("Raw Channels"), 210 STP_PARAMETER_TYPE_INT, STP_PARAMETER_CLASS_CORE, 211 STP_PARAMETER_LEVEL_INTERNAL, 1, 1, -1, 1, 0 212 }, 1.0, STP_CHANNEL_LIMIT, 1.0, CMASK_EVERY, 0, -1 213 }, 214 { 215 { 216 "SimpleGamma", N_("SimpleGamma"), "Color=Yes,Category=Gamma", 217 N_("Do not correct for screen gamma"), 218 STP_PARAMETER_TYPE_BOOLEAN, STP_PARAMETER_CLASS_OUTPUT, 219 STP_PARAMETER_LEVEL_INTERNAL, 0, 1, -1, 1, 0 220 }, 0.0, 1.0, 0.0, CMASK_EVERY, 0, -1 221 }, 222 { 223 { 224 "Brightness", N_("Brightness"), "Color=Yes,Category=Basic Image Adjustment", 225 N_("Brightness of the print"), 226 STP_PARAMETER_TYPE_DOUBLE, STP_PARAMETER_CLASS_OUTPUT, 227 STP_PARAMETER_LEVEL_BASIC, 1, 1, -1, 1, 0 228 }, 0.0, 2.0, 1.0, CMASK_ALL, 0, -1 229 }, 230 { 231 { 232 "Contrast", N_("Contrast"), "Color=Yes,Category=Basic Image Adjustment", 233 N_("Contrast of the print (0 is solid gray)"), 234 STP_PARAMETER_TYPE_DOUBLE, STP_PARAMETER_CLASS_OUTPUT, 235 STP_PARAMETER_LEVEL_BASIC, 1, 1, -1, 1, 0 236 }, 0.0, 4.0, 1.0, CMASK_ALL, 0, -1 237 }, 238 { 239 { 240 "LinearContrast", N_("Linear Contrast Adjustment"), "Color=Yes,Category=Advanced Image Control", 241 N_("Use linear vs. fixed end point contrast adjustment"), 242 STP_PARAMETER_TYPE_BOOLEAN, STP_PARAMETER_CLASS_OUTPUT, 243 STP_PARAMETER_LEVEL_ADVANCED3, 1, 1, -1, 1, 0 244 }, 0.0, 0.0, 0.0, CMASK_ALL, 0, -1 245 }, 246 { 247 { 248 "Gamma", N_("Composite Gamma"), "Color=Yes,Category=Gamma", 249 N_("Adjust the gamma of the print. Larger values will " 250 "produce a generally brighter print, while smaller " 251 "values will produce a generally darker print. "), 252 STP_PARAMETER_TYPE_DOUBLE, STP_PARAMETER_CLASS_OUTPUT, 253 STP_PARAMETER_LEVEL_ADVANCED1, 0, 1, -1, 1, 0 254 }, 0.1, 4.0, 1.0, CMASK_EVERY, 0, -1 255 }, 256 { 257 { 258 "AppGamma", N_("AppGamma"), "Color=Yes,Category=Gamma", 259 N_("Gamma value assumed by application"), 260 STP_PARAMETER_TYPE_DOUBLE, STP_PARAMETER_CLASS_OUTPUT, 261 STP_PARAMETER_LEVEL_INTERNAL, 0, 1, -1, 1, 0 262 }, 0.1, 4.0, 1.0, CMASK_EVERY, 0, -1 263 }, 264 { 265 { 266 "CyanGamma", N_("Cyan"), "Color=Yes,Category=Gamma", 267 N_("Adjust the cyan gamma"), 268 STP_PARAMETER_TYPE_DOUBLE, STP_PARAMETER_CLASS_OUTPUT, 269 STP_PARAMETER_LEVEL_ADVANCED1, 0, 1, 1, 1, 0 270 }, 0.0, 4.0, 1.0, CMASK_C, 1, 0 271 }, 272 { 273 { 274 "MagentaGamma", N_("Magenta"), "Color=Yes,Category=Gamma", 275 N_("Adjust the magenta gamma"), 276 STP_PARAMETER_TYPE_DOUBLE, STP_PARAMETER_CLASS_OUTPUT, 277 STP_PARAMETER_LEVEL_ADVANCED1, 0, 1, 2, 1, 0 278 }, 0.0, 4.0, 1.0, CMASK_M, 1, 0 279 }, 280 { 281 { 282 "YellowGamma", N_("Yellow"), "Color=Yes,Category=Gamma", 283 N_("Adjust the yellow gamma"), 284 STP_PARAMETER_TYPE_DOUBLE, STP_PARAMETER_CLASS_OUTPUT, 285 STP_PARAMETER_LEVEL_ADVANCED1, 0, 1, 3, 1, 0 286 }, 0.0, 4.0, 1.0, CMASK_Y, 1, 0 287 }, 288 { 289 { 290 "RedGamma", N_("Red"), "Color=Yes,Category=Gamma", 291 N_("Adjust the red gamma"), 292 STP_PARAMETER_TYPE_DOUBLE, STP_PARAMETER_CLASS_OUTPUT, 293 STP_PARAMETER_LEVEL_ADVANCED1, 0, 1, 1, 1, 0 294 }, 0.0, 4.0, 1.0, CMASK_C, 1, 1 295 }, 296 { 297 { 298 "GreenGamma", N_("Green"), "Color=Yes,Category=Gamma", 299 N_("Adjust the green gamma"), 300 STP_PARAMETER_TYPE_DOUBLE, STP_PARAMETER_CLASS_OUTPUT, 301 STP_PARAMETER_LEVEL_ADVANCED1, 0, 1, 2, 1, 0 302 }, 0.0, 4.0, 1.0, CMASK_M, 1, 1 303 }, 304 { 305 { 306 "BlueGamma", N_("Blue"), "Color=Yes,Category=Gamma", 307 N_("Adjust the blue gamma"), 308 STP_PARAMETER_TYPE_DOUBLE, STP_PARAMETER_CLASS_OUTPUT, 309 STP_PARAMETER_LEVEL_ADVANCED1, 0, 1, 3, 1, 0 310 }, 0.0, 4.0, 1.0, CMASK_Y, 1, 1 311 }, 312 { 313 { 314 "BlackGamma", N_("Black"), "Color=Yes,Category=Gamma", 315 N_("Adjust the black gamma"), 316 STP_PARAMETER_TYPE_DOUBLE, STP_PARAMETER_CLASS_OUTPUT, 317 STP_PARAMETER_LEVEL_ADVANCED1, 0, 1, 3, 1, 0 318 }, 0.0, 4.0, 1.0, CMASK_K, 1, 0 319 }, 320 { 321 { 322 "CyanBalance", N_("Cyan Balance"), "Color=Yes,Category=GrayBalance", 323 N_("Adjust the cyan gray balance"), 324 STP_PARAMETER_TYPE_DOUBLE, STP_PARAMETER_CLASS_OUTPUT, 325 STP_PARAMETER_LEVEL_ADVANCED1, 0, 1, 1, 1, 0 326 }, 0.0, 1.0, 1.0, CMASK_C, 1, 0 327 }, 328 { 329 { 330 "MagentaBalance", N_("Magenta Balance"), "Color=Yes,Category=GrayBalance", 331 N_("Adjust the magenta gray balance"), 332 STP_PARAMETER_TYPE_DOUBLE, STP_PARAMETER_CLASS_OUTPUT, 333 STP_PARAMETER_LEVEL_ADVANCED1, 0, 1, 2, 1, 0 334 }, 0.0, 1.0, 1.0, CMASK_M, 1, 0 335 }, 336 { 337 { 338 "YellowBalance", N_("Yellow Balance"), "Color=Yes,Category=GrayBalance", 339 N_("Adjust the yellow gray balance"), 340 STP_PARAMETER_TYPE_DOUBLE, STP_PARAMETER_CLASS_OUTPUT, 341 STP_PARAMETER_LEVEL_ADVANCED1, 0, 1, 3, 1, 0 342 }, 0.0, 1.0, 1.0, CMASK_Y, 1, 0 343 }, 344 { 345 { 346 "Saturation", N_("Saturation"), "Color=Yes,Category=Basic Image Adjustment", 347 N_("Adjust the saturation (color balance) of the print\n" 348 "Use zero saturation to produce grayscale output " 349 "using color and black inks"), 350 STP_PARAMETER_TYPE_DOUBLE, STP_PARAMETER_CLASS_OUTPUT, 351 STP_PARAMETER_LEVEL_BASIC, 1, 1, -1, 1, 0 352 }, 0.0, 9.0, 1.0, CMASK_CMY | CMASK_RGB, 1, 0 353 }, 354 /* Need to think this through a bit more -- rlk 20030712 */ 355 { 356 { 357 "InkLimit", N_("Ink Limit"), "Color=Yes,Category=Advanced Output Control", 358 N_("Limit the total ink printed to the page"), 359 STP_PARAMETER_TYPE_DOUBLE, STP_PARAMETER_CLASS_OUTPUT, 360 STP_PARAMETER_LEVEL_ADVANCED4, 0, 1, -1, 0, 0 361 }, 0.0, STP_CHANNEL_LIMIT, STP_CHANNEL_LIMIT, CMASK_CMY, 0, -1 362 }, 363 { 364 { 365 "BlackTrans", N_("GCR Transition"), "Color=Yes,Category=Advanced Output Control", 366 N_("Adjust the gray component transition rate"), 367 STP_PARAMETER_TYPE_DOUBLE, STP_PARAMETER_CLASS_OUTPUT, 368 STP_PARAMETER_LEVEL_ADVANCED4, 0, 1, 0, 1, 0 369 }, 0.0, 1.0, 1.0, CMASK_K, 1, 0 370 }, 371 { 372 { 373 "GCRLower", N_("GCR Lower Bound"), "Color=Yes,Category=Advanced Output Control", 374 N_("Lower bound of gray component reduction"), 375 STP_PARAMETER_TYPE_DOUBLE, STP_PARAMETER_CLASS_OUTPUT, 376 STP_PARAMETER_LEVEL_ADVANCED4, 0, 1, 0, 1, 0 377 }, 0.0, 1.0, 0.2, CMASK_K, 1, 0 378 }, 379 { 380 { 381 "GCRUpper", N_("GCR Upper Bound"), "Color=Yes,Category=Advanced Output Control", 382 N_("Upper bound of gray component reduction"), 383 STP_PARAMETER_TYPE_DOUBLE, STP_PARAMETER_CLASS_OUTPUT, 384 STP_PARAMETER_LEVEL_ADVANCED4, 0, 1, 0, 1, 0 385 }, 0.0, 5.0, 0.5, CMASK_K, 1, 0 386 }, 387 RAW_GAMMA_CHANNEL(0), 388 RAW_GAMMA_CHANNEL(1), 389 RAW_GAMMA_CHANNEL(2), 390 RAW_GAMMA_CHANNEL(3), 391 RAW_GAMMA_CHANNEL(4), 392 RAW_GAMMA_CHANNEL(5), 393 RAW_GAMMA_CHANNEL(6), 394 RAW_GAMMA_CHANNEL(7), 395 RAW_GAMMA_CHANNEL(8), 396 RAW_GAMMA_CHANNEL(9), 397 RAW_GAMMA_CHANNEL(10), 398 RAW_GAMMA_CHANNEL(11), 399 RAW_GAMMA_CHANNEL(12), 400 RAW_GAMMA_CHANNEL(13), 401 RAW_GAMMA_CHANNEL(14), 402 RAW_GAMMA_CHANNEL(15), 403 RAW_GAMMA_CHANNEL(16), 404 RAW_GAMMA_CHANNEL(17), 405 RAW_GAMMA_CHANNEL(18), 406 RAW_GAMMA_CHANNEL(19), 407 RAW_GAMMA_CHANNEL(20), 408 RAW_GAMMA_CHANNEL(21), 409 RAW_GAMMA_CHANNEL(22), 410 RAW_GAMMA_CHANNEL(23), 411 RAW_GAMMA_CHANNEL(24), 412 RAW_GAMMA_CHANNEL(25), 413 RAW_GAMMA_CHANNEL(26), 414 RAW_GAMMA_CHANNEL(27), 415 RAW_GAMMA_CHANNEL(28), 416 RAW_GAMMA_CHANNEL(29), 417 RAW_GAMMA_CHANNEL(30), 418 RAW_GAMMA_CHANNEL(31), 419 { 420 { 421 "LUTDumpFile", N_("LUT dump file"), N_("Advanced Output Control"), 422 N_("Dump file for LUT for external color adjustment"), 423 STP_PARAMETER_TYPE_FILE, STP_PARAMETER_CLASS_OUTPUT, 424 STP_PARAMETER_LEVEL_ADVANCED4, 0, 1, -1, 1, 0 425 }, 0.0, 0.0, 0.0, CMASK_EVERY, 0, -1 426 }, 427}; 428 429static const int float_parameter_count = 430sizeof(float_parameters) / sizeof(float_param_t); 431 432typedef struct 433{ 434 stp_parameter_t param; 435 stp_curve_t **defval; 436 unsigned channel_mask; 437 int hsl_only; 438 int color_only; 439 int is_rgb; 440} curve_param_t; 441 442static int standard_curves_initialized = 0; 443 444static stp_curve_t *hue_map_bounds = NULL; 445static stp_curve_t *lum_map_bounds = NULL; 446static stp_curve_t *sat_map_bounds = NULL; 447static stp_curve_t *color_curve_bounds = NULL; 448static stp_curve_t *gcr_curve_bounds = NULL; 449 450 451#define RAW_CURVE_CHANNEL(channel) \ 452 { \ 453 { \ 454 "CurveCh" #channel, N_("Channel " #channel " Curve"), \ 455 "Color=Yes,Category=Output Curves", \ 456 N_("Curve for raw channel " #channel), \ 457 STP_PARAMETER_TYPE_CURVE, STP_PARAMETER_CLASS_OUTPUT, \ 458 STP_PARAMETER_LEVEL_INTERNAL, 0, 1, channel, 1, 0 \ 459 }, &color_curve_bounds, CMASK_RAW, 0, 0, -1 \ 460 } 461 462static curve_param_t curve_parameters[] = 463{ 464 { 465 { 466 "CyanCurve", N_("Cyan Curve"), "Color=Yes,Category=Output Curves", 467 N_("Cyan curve"), 468 STP_PARAMETER_TYPE_CURVE, STP_PARAMETER_CLASS_OUTPUT, 469 STP_PARAMETER_LEVEL_ADVANCED2, 0, 1, 1, 1, 0 470 }, &color_curve_bounds, CMASK_C, 0, 1, 0 471 }, 472 { 473 { 474 "MagentaCurve", N_("Magenta Curve"), "Color=Yes,Category=Output Curves", 475 N_("Magenta curve"), 476 STP_PARAMETER_TYPE_CURVE, STP_PARAMETER_CLASS_OUTPUT, 477 STP_PARAMETER_LEVEL_ADVANCED2, 0, 1, 2, 1, 0 478 }, &color_curve_bounds, CMASK_M, 0, 1, 0 479 }, 480 { 481 { 482 "YellowCurve", N_("Yellow Curve"), "Color=Yes,Category=Output Curves", 483 N_("Yellow curve"), 484 STP_PARAMETER_TYPE_CURVE, STP_PARAMETER_CLASS_OUTPUT, 485 STP_PARAMETER_LEVEL_ADVANCED2, 0, 1, 3, 1, 0 486 }, &color_curve_bounds, CMASK_Y, 0, 1, 0 487 }, 488 { 489 { 490 "BlackCurve", N_("Black Curve"), "Color=Yes,Category=Output Curves", 491 N_("Black curve"), 492 STP_PARAMETER_TYPE_CURVE, STP_PARAMETER_CLASS_OUTPUT, 493 STP_PARAMETER_LEVEL_ADVANCED2, 0, 1, 0, 1, 0 494 }, &color_curve_bounds, CMASK_K, 0, 0, 0 495 }, 496 { 497 { 498 "RedCurve", N_("Red Curve"), "Color=Yes,Category=Output Curves", 499 N_("Red curve"), 500 STP_PARAMETER_TYPE_CURVE, STP_PARAMETER_CLASS_OUTPUT, 501 STP_PARAMETER_LEVEL_ADVANCED2, 0, 1, 1, 1, 0 502 }, &color_curve_bounds, CMASK_C, 0, 1, 1 503 }, 504 { 505 { 506 "GreenCurve", N_("Green Curve"), "Color=Yes,Category=Output Curves", 507 N_("Green curve"), 508 STP_PARAMETER_TYPE_CURVE, STP_PARAMETER_CLASS_OUTPUT, 509 STP_PARAMETER_LEVEL_ADVANCED2, 0, 1, 2, 1, 0 510 }, &color_curve_bounds, CMASK_M, 0, 1, 1 511 }, 512 { 513 { 514 "BlueCurve", N_("Blue Curve"), "Color=Yes,Category=Output Curves", 515 N_("Blue curve"), 516 STP_PARAMETER_TYPE_CURVE, STP_PARAMETER_CLASS_OUTPUT, 517 STP_PARAMETER_LEVEL_ADVANCED2, 0, 1, 3, 1, 0 518 }, &color_curve_bounds, CMASK_Y, 0, 1, 1 519 }, 520 { 521 { 522 "WhiteCurve", N_("White Curve"), "Color=Yes,Category=Output Curves", 523 N_("White curve"), 524 STP_PARAMETER_TYPE_CURVE, STP_PARAMETER_CLASS_OUTPUT, 525 STP_PARAMETER_LEVEL_ADVANCED2, 0, 1, 1, 1, 0 526 }, &color_curve_bounds, CMASK_W, 0, 0, 1 527 }, 528 { 529 { 530 "HueMap", N_("Hue Map"), "Color=Yes,Category=Advanced HSL Curves", 531 N_("Hue adjustment curve"), 532 STP_PARAMETER_TYPE_CURVE, STP_PARAMETER_CLASS_OUTPUT, 533 STP_PARAMETER_LEVEL_ADVANCED3, 0, 1, -1, 1, 0 534 }, &hue_map_bounds, CMASK_CMY | CMASK_RGB, 1, 1, -1 535 }, 536 { 537 { 538 "SatMap", N_("Saturation Map"), "Color=Yes,Category=Advanced HSL Curves", 539 N_("Saturation adjustment curve"), 540 STP_PARAMETER_TYPE_CURVE, STP_PARAMETER_CLASS_OUTPUT, 541 STP_PARAMETER_LEVEL_ADVANCED3, 0, 1, -1, 1, 0 542 }, &sat_map_bounds, CMASK_CMY | CMASK_RGB, 1, 1, -1 543 }, 544 { 545 { 546 "LumMap", N_("Luminosity Map"), "Color=Yes,Category=Advanced HSL Curves", 547 N_("Luminosity adjustment curve"), 548 STP_PARAMETER_TYPE_CURVE, STP_PARAMETER_CLASS_OUTPUT, 549 STP_PARAMETER_LEVEL_ADVANCED3, 0, 1, -1, 1, 0 550 }, &lum_map_bounds, CMASK_CMY | CMASK_RGB, 1, 1, -1 551 }, 552 { 553 { 554 "GCRCurve", N_("Gray Component Reduction"), "Color=Yes,Category=Advanced Output Control", 555 N_("Gray component reduction curve"), 556 STP_PARAMETER_TYPE_CURVE, STP_PARAMETER_CLASS_OUTPUT, 557 STP_PARAMETER_LEVEL_ADVANCED4, 0, 1, 0, 1, 0 558 }, &gcr_curve_bounds, CMASK_K, 0, 1, -1 559 }, 560 RAW_CURVE_CHANNEL(0), 561 RAW_CURVE_CHANNEL(1), 562 RAW_CURVE_CHANNEL(2), 563 RAW_CURVE_CHANNEL(3), 564 RAW_CURVE_CHANNEL(4), 565 RAW_CURVE_CHANNEL(5), 566 RAW_CURVE_CHANNEL(6), 567 RAW_CURVE_CHANNEL(7), 568 RAW_CURVE_CHANNEL(8), 569 RAW_CURVE_CHANNEL(9), 570 RAW_CURVE_CHANNEL(10), 571 RAW_CURVE_CHANNEL(11), 572 RAW_CURVE_CHANNEL(12), 573 RAW_CURVE_CHANNEL(13), 574 RAW_CURVE_CHANNEL(14), 575 RAW_CURVE_CHANNEL(15), 576 RAW_CURVE_CHANNEL(16), 577 RAW_CURVE_CHANNEL(17), 578 RAW_CURVE_CHANNEL(18), 579 RAW_CURVE_CHANNEL(19), 580 RAW_CURVE_CHANNEL(20), 581 RAW_CURVE_CHANNEL(21), 582 RAW_CURVE_CHANNEL(22), 583 RAW_CURVE_CHANNEL(23), 584 RAW_CURVE_CHANNEL(24), 585 RAW_CURVE_CHANNEL(25), 586 RAW_CURVE_CHANNEL(26), 587 RAW_CURVE_CHANNEL(27), 588 RAW_CURVE_CHANNEL(28), 589 RAW_CURVE_CHANNEL(29), 590 RAW_CURVE_CHANNEL(30), 591 RAW_CURVE_CHANNEL(31), 592}; 593 594static const int curve_parameter_count = 595sizeof(curve_parameters) / sizeof(curve_param_t); 596 597 598static const color_description_t * 599get_color_description(const char *name) 600{ 601 int i; 602 if (name) 603 for (i = 0; i < color_description_count; i++) 604 { 605 if (strcmp(name, color_descriptions[i].name) == 0) 606 return &(color_descriptions[i]); 607 } 608 return NULL; 609} 610 611static const channel_depth_t * 612get_channel_depth(const char *name) 613{ 614 int i; 615 if (name) 616 for (i = 0; i < channel_depth_count; i++) 617 { 618 if (strcmp(name, channel_depths[i].name) == 0) 619 return &(channel_depths[i]); 620 } 621 return NULL; 622} 623 624static const color_correction_t * 625get_color_correction(const char *name) 626{ 627 int i; 628 if (name) 629 for (i = 0; i < color_correction_count; i++) 630 { 631 if (strcmp(name, color_corrections[i].name) == 0) 632 return &(color_corrections[i]); 633 } 634 return NULL; 635} 636 637static const color_correction_t * 638get_color_correction_by_tag(color_correction_enum_t correction) 639{ 640 int i; 641 for (i = 0; i < color_correction_count; i++) 642 { 643 if (correction == color_corrections[i].correction) 644 return &(color_corrections[i]); 645 } 646 return NULL; 647} 648 649 650static void 651initialize_channels(stp_vars_t *v, stp_image_t *image) 652{ 653 lut_t *lut = (lut_t *)(stp_get_component_data(v, "Color")); 654 if (stp_check_float_parameter(v, "InkLimit", STP_PARAMETER_ACTIVE)) 655 stp_channel_set_ink_limit(v, stp_get_float_parameter(v, "InkLimit")); 656 stp_channel_initialize(v, image, lut->out_channels); 657 lut->channels_are_initialized = 1; 658} 659 660static int 661stpi_color_traditional_get_row(stp_vars_t *v, 662 stp_image_t *image, 663 int row, 664 unsigned *zero_mask) 665{ 666 const lut_t *lut = (const lut_t *)(stp_get_component_data(v, "Color")); 667 unsigned zero; 668 if (stp_image_get_row(image, lut->in_data, 669 lut->image_width * lut->in_channels * lut->channel_depth / 8, row) 670 != STP_IMAGE_STATUS_OK) 671 return 2; 672 if (!lut->channels_are_initialized) 673 initialize_channels(v, image); 674 zero = (lut->output_color_description->conversion_function) 675 (v, lut->in_data, stp_channel_get_input(v)); 676 if (zero_mask) 677 *zero_mask = zero; 678 stp_channel_convert(v, zero_mask); 679 return 0; 680} 681 682static void 683free_channels(lut_t *lut) 684{ 685 int i; 686 for (i = 0; i < STP_CHANNEL_LIMIT; i++) 687 stp_curve_free_curve_cache(&(lut->channel_curves[i])); 688} 689 690static lut_t * 691allocate_lut(void) 692{ 693 int i; 694 lut_t *ret = stp_zalloc(sizeof(lut_t)); 695 for (i = 0; i < STP_CHANNEL_LIMIT; i++) 696 { 697 ret->gamma_values[i] = 1.0; 698 } 699 ret->print_gamma = 1.0; 700 ret->app_gamma = 1.0; 701 ret->contrast = 1.0; 702 ret->brightness = 1.0; 703 ret->simple_gamma_correction = 0; 704 return ret; 705} 706 707static void * 708copy_lut(void *vlut) 709{ 710 const lut_t *src = (const lut_t *)vlut; 711 int i; 712 lut_t *dest; 713 if (!src) 714 return NULL; 715 dest = allocate_lut(); 716 free_channels(dest); 717 718 dest->steps = src->steps; 719 dest->channel_depth = src->channel_depth; 720 dest->image_width = src->image_width; 721 dest->in_channels = src->in_channels; 722 dest->out_channels = src->out_channels; 723 /* Don't copy channels_are_initialized */ 724 dest->invert_output = src->invert_output; 725 dest->input_color_description = src->input_color_description; 726 dest->output_color_description = src->output_color_description; 727 dest->color_correction = src->color_correction; 728 for (i = 0; i < STP_CHANNEL_LIMIT; i++) 729 { 730 stp_curve_cache_copy(&(dest->channel_curves[i]), &(src->channel_curves[i])); 731 dest->gamma_values[i] = src->gamma_values[i]; 732 } 733 stp_curve_cache_copy(&(dest->brightness_correction), 734 &(src->brightness_correction)); 735 stp_curve_cache_copy(&(dest->contrast_correction), 736 &(src->contrast_correction)); 737 stp_curve_cache_copy(&(dest->user_color_correction), 738 &(src->user_color_correction)); 739 dest->print_gamma = src->print_gamma; 740 dest->app_gamma = src->app_gamma; 741 dest->screen_gamma = src->screen_gamma; 742 dest->contrast = src->contrast; 743 dest->brightness = src->brightness; 744 dest->simple_gamma_correction = src->simple_gamma_correction; 745 dest->linear_contrast_adjustment = src->linear_contrast_adjustment; 746 stp_curve_cache_copy(&(dest->hue_map), &(src->hue_map)); 747 stp_curve_cache_copy(&(dest->lum_map), &(src->lum_map)); 748 stp_curve_cache_copy(&(dest->sat_map), &(src->sat_map)); 749 /* Don't copy gray_tmp */ 750 /* Don't copy cmy_tmp */ 751 if (src->in_data) 752 { 753 dest->in_data = stp_malloc(src->image_width * src->in_channels); 754 memset(dest->in_data, 0, src->image_width * src->in_channels); 755 } 756 return dest; 757} 758 759static void 760free_lut(void *vlut) 761{ 762 lut_t *lut = (lut_t *)vlut; 763 free_channels(lut); 764 stp_curve_free_curve_cache(&(lut->brightness_correction)); 765 stp_curve_free_curve_cache(&(lut->contrast_correction)); 766 stp_curve_free_curve_cache(&(lut->user_color_correction)); 767 stp_curve_free_curve_cache(&(lut->hue_map)); 768 stp_curve_free_curve_cache(&(lut->lum_map)); 769 stp_curve_free_curve_cache(&(lut->sat_map)); 770 STP_SAFE_FREE(lut->gray_tmp); 771 STP_SAFE_FREE(lut->cmy_tmp); 772 STP_SAFE_FREE(lut->in_data); 773 memset(lut, 0, sizeof(lut_t)); 774 stp_free(lut); 775} 776 777static stp_curve_t * 778compute_gcr_curve(const stp_vars_t *vars) 779{ 780 stp_curve_t *curve; 781 lut_t *lut = (lut_t *)(stp_get_component_data(vars, "Color")); 782 double k_lower = 0.0; 783 double k_upper = 1.0; 784 double k_trans = 1.0; 785 double i_k_trans = 1.0; 786 double *tmp_data = stp_malloc(sizeof(double) * lut->steps); 787 int i; 788 789 if (stp_check_float_parameter(vars, "GCRUpper", STP_PARAMETER_DEFAULTED)) 790 k_upper = stp_get_float_parameter(vars, "GCRUpper"); 791 if (stp_check_float_parameter(vars, "GCRLower", STP_PARAMETER_DEFAULTED)) 792 k_lower = stp_get_float_parameter(vars, "GCRLower"); 793 if (stp_check_float_parameter(vars, "BlackTrans", STP_PARAMETER_DEFAULTED)) 794 k_trans = stp_get_float_parameter(vars, "BlackTrans"); 795 k_upper *= lut->steps; 796 k_lower *= lut->steps; 797 stp_dprintf(STP_DBG_LUT, vars, " k_lower %.3f\n", k_lower); 798 stp_dprintf(STP_DBG_LUT, vars, " k_upper %.3f\n", k_upper); 799 800 if (k_lower > lut->steps) 801 k_lower = lut->steps; 802 if (k_upper < k_lower) 803 k_upper = k_lower + 1; 804 i_k_trans = 1.0 / k_trans; 805 806 for (i = 0; i < k_lower; i ++) 807 tmp_data[i] = 0; 808 if (k_upper < lut->steps) 809 { 810 for (i = ceil(k_lower); i < k_upper; i ++) 811 { 812 double where = (i - k_lower) / (k_upper - k_lower); 813 double g1 = pow(where, i_k_trans); 814 double g2 = 1.0 - pow(1.0 - where, k_trans); 815 double value = (i_k_trans <= 1.0 ? g1 : g2); 816 tmp_data[i] = 65535.0 * k_upper * value / (double) (lut->steps - 1); 817 tmp_data[i] = floor(tmp_data[i] + .5); 818 } 819 for (i = ceil(k_upper); i < lut->steps; i ++) 820 tmp_data[i] = 65535.0 * i / (double) (lut->steps - 1); 821 } 822 else if (k_lower < lut->steps) 823 for (i = ceil(k_lower); i < lut->steps; i ++) 824 { 825 double where = (i - k_lower) / (k_upper - k_lower); 826 double g1 = pow(where, i_k_trans); 827 double g2 = 1.0 - pow(1.0 - where, k_trans); 828 double value = (i_k_trans <= 1.0 ? g1 : g2); 829 tmp_data[i] = 65535.0 * lut->steps * value / (double) (lut->steps - 1); 830 tmp_data[i] = floor(tmp_data[i] + .5); 831 } 832 curve = stp_curve_create(STP_CURVE_WRAP_NONE); 833 stp_curve_set_bounds(curve, 0, 65535); 834 STPI_ASSERT(stp_curve_set_data(curve, lut->steps, tmp_data), v); 835 stp_free(tmp_data); 836 return curve; 837} 838 839static void 840initialize_gcr_curve(stp_vars_t *vars) 841{ 842 lut_t *lut = (lut_t *)(stp_get_component_data(vars, "Color")); 843 stp_curve_t *curve = NULL; 844 if (stp_check_curve_parameter(vars, "GCRCurve", STP_PARAMETER_DEFAULTED)) 845 { 846 double data; 847 size_t count; 848 int i; 849 curve = stp_curve_create_copy(stp_get_curve_parameter(vars, "GCRCurve")); 850 stp_curve_resample(curve, lut->steps); 851 count = stp_curve_count_points(curve); 852 stp_curve_set_bounds(curve, 0.0, 65535.0); 853 for (i = 0; i < count; i++) 854 { 855 stp_curve_get_point(curve, i, &data); 856 data = 65535.0 * data * (double) i / (count - 1); 857 stp_curve_set_point(curve, i, data); 858 } 859 } 860 else 861 curve = compute_gcr_curve(vars); 862 stp_channel_set_gcr_curve(vars, curve); 863 if (curve) 864 stp_curve_destroy(curve); 865} 866 867/* 868 * Channels that are synthesized (e. g. the black channel in CMY -> CMYK 869 * conversion) need to be computed differently from channels that are 870 * mapped 1-1 from input to output. Channels that are simply mapped need 871 * to be inverted if necessary, and in addition the contrast, brightness, 872 * and other gamma factors are factored in. Channels that are synthesized 873 * are never inverted, since they're computed from the output of other 874 * channels that have already been inverted. 875 * 876 * This isn't simply a matter of comparing the input channels to the output 877 * channels, since some of the conversions (K -> CMYK) work by means 878 * of a chain of conversions (K->CMY->CMYK). In this case, we need to 879 * fully compute the CMY channels, but the K channel in the output is 880 * not inverted. 881 * 882 * The rules that are implemented by the logic below are: 883 * 884 * 1) If the input is raw, we always perform the normal computation (without 885 * synthesizing channels). 886 * 887 * 2) If the output is CMY or K only, we never synthesize channels. We've 888 * now covered raw, black, and CMY/RGB outputs, leaving CMYK and MULTI. 889 * 890 * 3) Output channels above CMYK are synthesized. 891 * 892 * 4) If the input is CMYK, we do not synthesize channels. 893 * 894 * 5) The black channel (in CMYK) is synthesized. 895 * 896 * 6) All other channels (CMY/RGB) are not synthesized. 897 */ 898 899static int 900channel_is_synthesized(lut_t *lut, int channel) 901{ 902 if (lut->output_color_description->color_id == COLOR_ID_RAW) 903 return 1; /* Case 1 */ 904 else if (lut->output_color_description->channels == CMASK_CMY || 905 lut->output_color_description->channels == CMASK_K) 906 return 0; /* Case 2 */ 907 else if (channel >= CHANNEL_W) 908 return 1; /* Case 3 */ 909 else if (lut->input_color_description->channels == CMASK_CMYK) 910 return 0; /* Case 4 */ 911 else if (channel == CHANNEL_K) 912 return 1; /* Case 5 */ 913 else 914 return 0; /* Case 6 */ 915} 916 917static void 918compute_user_correction(lut_t *lut) 919{ 920 double *tmp; 921 double *tmp_brightness; 922 double *tmp_contrast; 923 double xcontrast = lut->contrast; 924 stp_curve_t *curve = 925 stp_curve_cache_get_curve(&(lut->user_color_correction)); 926 stp_curve_t *brightness_curve = 927 stp_curve_cache_get_curve(&(lut->brightness_correction)); 928 stp_curve_t *contrast_curve = 929 stp_curve_cache_get_curve(&(lut->contrast_correction)); 930 double brightness = lut->brightness; 931 int i; 932 int isteps = lut->steps; 933 if (isteps > 256) 934 isteps = 256; 935 tmp = stp_malloc(sizeof(double) * lut->steps); 936 tmp_brightness = stp_malloc(sizeof(double) * lut->steps); 937 tmp_contrast = stp_malloc(sizeof(double) * lut->steps); 938 if (brightness < .001) 939 brightness = 1000; 940 else if (brightness > 1.999) 941 brightness = .001; 942 else if (brightness > 1) 943 brightness = 2.0 - brightness; 944 else 945 brightness = 1.0 / brightness; 946 for (i = 0; i < isteps; i ++) 947 { 948 double temp_pixel, pixel; 949 pixel = (double) i / (double) (isteps - 1); 950 /* 951 * First, correct contrast 952 */ 953 if (pixel >= .5) 954 temp_pixel = 1.0 - pixel; 955 else 956 temp_pixel = pixel; 957 if (lut->contrast > 3.99999) 958 { 959 if (temp_pixel < .5) 960 temp_pixel = 0; 961 else 962 temp_pixel = 1; 963 } 964 if (temp_pixel <= .000001 && lut->contrast <= .0001) 965 temp_pixel = .5; 966 else if (temp_pixel > 1) 967 temp_pixel = .5 * pow(2 * temp_pixel, xcontrast); 968 else if (temp_pixel < 1) 969 { 970 if (lut->linear_contrast_adjustment) 971 temp_pixel = 0.5 - 972 ((0.5 - .5 * pow(2 * temp_pixel, lut->contrast)) * 973 lut->contrast); 974 else 975 temp_pixel = 0.5 - 976 ((0.5 - .5 * pow(2 * temp_pixel, lut->contrast))); 977 } 978 if (temp_pixel > .5) 979 temp_pixel = .5; 980 else if (temp_pixel < 0) 981 temp_pixel = 0; 982 if (pixel < .5) 983 pixel = temp_pixel; 984 else 985 pixel = 1 - temp_pixel; 986 tmp_contrast[i] = floor((pixel * 65535) + .5); 987 988 /* 989 * Second, do brightness 990 */ 991 if (brightness < 1) 992 pixel = pow(pixel, brightness); 993 else 994 pixel = 1.0 - pow(1.0 - pixel, 1.0 / brightness); 995 tmp[i] = floor((pixel * 65535) + .5); 996 997 pixel = (double) i / (double) (isteps - 1); 998 if (brightness < 1) 999 pixel = pow(pixel, brightness); 1000 else 1001 pixel = 1.0 - pow(1.0 - pixel, 1.0 / brightness); 1002 tmp_brightness[i] = floor((pixel * 65535) + .5); 1003 } 1004 stp_curve_set_data(curve, isteps, tmp); 1005 if (isteps != lut->steps) 1006 stp_curve_resample(curve, lut->steps); 1007 stp_curve_set_data(brightness_curve, isteps, tmp_brightness); 1008 if (isteps != lut->steps) 1009 stp_curve_resample(brightness_curve, lut->steps); 1010 stp_curve_set_data(contrast_curve, isteps, tmp_contrast); 1011 if (isteps != lut->steps) 1012 stp_curve_resample(contrast_curve, lut->steps); 1013 stp_free(tmp); 1014 stp_free(tmp_brightness); 1015 stp_free(tmp_contrast); 1016} 1017 1018static void 1019compute_a_curve_full(lut_t *lut, int channel) 1020{ 1021 double *tmp; 1022 double pivot = .25; 1023 double ipivot = 1.0 - pivot; 1024 double xgamma = pow(pivot, lut->screen_gamma); 1025 double print_gamma=1.0+9.0*(lut->print_gamma-1.0); 1026 double pivot2 = .75; 1027 double ipivot2 = 1.0 - pivot2; 1028 double xgamma2 = pow(pivot2, print_gamma); 1029 stp_curve_t *curve = stp_curve_cache_get_curve(&(lut->channel_curves[channel])); 1030 int i; 1031 int isteps = lut->steps; 1032 if (isteps > 256) 1033 isteps = 256; 1034 tmp = stp_malloc(sizeof(double) * lut->steps); 1035 for (i = 0; i < isteps; i ++) 1036 { 1037 double pixel = (double) i / (double) (isteps - 1); 1038 1039 if (lut->input_color_description->color_model == COLOR_BLACK) 1040 pixel = 1.0 - pixel; 1041 1042 pixel = 1.0 - 1043 (1.0 / (1.0 - xgamma)) * 1044 (pow(pivot + ipivot * pixel, lut->screen_gamma) - xgamma); 1045 1046 /* 1047 * Fourth, fix up cyan, magenta, yellow values 1048 */ 1049 if (pixel < 0.0) 1050 pixel = 0.0; 1051 else if (pixel > 1.0) 1052 pixel = 1.0; 1053 1054 if (pixel > .9999 && lut->gamma_values[channel] < .00001) 1055 pixel = 0; 1056 else 1057 pixel = 1 - pow(1 - pixel, lut->gamma_values[channel]); 1058 /* 1059 * Finally, fix up print gamma and scale 1060 */ 1061 1062 /* 1063 * Change to this function suggested by Alastair Robinson 1064 * blackfive@fakenhamweb.co.uk 1065 */ 1066 pixel = 65535 * (1.0 / (1.0 - xgamma2)) * 1067 (pow(pivot2 + ipivot2 * pixel, print_gamma) - xgamma2); 1068 if (lut->output_color_description->color_model == COLOR_WHITE) 1069 pixel = 65535 - pixel; 1070 1071 if (pixel <= 0.0) 1072 tmp[i] = 0; 1073 else if (pixel >= 65535.0) 1074 tmp[i] = 65535; 1075 else 1076 tmp[i] = (pixel); 1077 tmp[i] = floor(tmp[i] + 0.5); /* rounding is done here */ 1078 } 1079 stp_curve_set_data(curve, isteps, tmp); 1080 if (isteps != lut->steps) 1081 stp_curve_resample(curve, lut->steps); 1082 stp_free(tmp); 1083} 1084 1085static void 1086compute_a_curve_fast(lut_t *lut, int channel) 1087{ 1088 double *tmp; 1089 stp_curve_t *curve = stp_curve_cache_get_curve(&(lut->channel_curves[channel])); 1090 int i; 1091 int isteps = lut->steps; 1092 if (isteps > 256) 1093 isteps = 256; 1094 tmp = stp_malloc(sizeof(double) * lut->steps); 1095 for (i = 0; i < isteps; i++) 1096 { 1097 double pixel = (double) i / (double) (isteps - 1); 1098 pixel = 1 - pow(1 - pixel, lut->gamma_values[channel]); 1099 tmp[i] = floor((65535.0 * pixel) + 0.5); 1100 } 1101 stp_curve_set_data(curve, isteps, tmp); 1102 if (isteps != lut->steps) 1103 stp_curve_resample(curve, lut->steps); 1104 stp_free(tmp); 1105} 1106 1107static void 1108compute_a_curve_simple(lut_t *lut, int channel) 1109{ 1110 double *tmp; 1111 stp_curve_t *curve = stp_curve_cache_get_curve(&(lut->channel_curves[channel])); 1112 int i; 1113 int isteps = lut->steps; 1114 double gamma = 1.0 / (lut->gamma_values[channel] * lut->print_gamma); 1115 if (isteps > 256) 1116 isteps = 256; 1117 tmp = stp_malloc(sizeof(double) * lut->steps); 1118 for (i = 0; i < isteps; i++) 1119 { 1120 double pixel = (double) i / (double) (isteps - 1); 1121 if (lut->input_color_description->color_model == COLOR_BLACK) 1122 pixel = 1.0 - pixel; 1123 pixel = pow(pixel, gamma); 1124 if (lut->output_color_description->color_model == COLOR_BLACK) 1125 pixel = 1.0 - pixel; 1126 tmp[i] = floor((65535.0 * pixel) + 0.5); 1127 } 1128 stp_curve_set_data(curve, isteps, tmp); 1129 if (isteps != lut->steps) 1130 stp_curve_resample(curve, lut->steps); 1131 stp_free(tmp); 1132} 1133 1134/* 1135 * If the input and output color spaces both have a particular channel, 1136 * we want to use the general algorithm. If not (i. e. we have to 1137 * synthesize the channel), use a simple gamma curve. 1138 */ 1139static void 1140compute_a_curve(lut_t *lut, int channel) 1141{ 1142 if (channel_is_synthesized(lut, channel)) 1143 compute_a_curve_fast(lut, channel); 1144 else if (lut->simple_gamma_correction) 1145 compute_a_curve_simple(lut, channel); 1146 else 1147 compute_a_curve_full(lut, channel); 1148} 1149 1150static void 1151invert_curve(stp_curve_t *curve, int invert_output) 1152{ 1153 double lo, hi; 1154 int i; 1155 size_t count; 1156 const double *data = stp_curve_get_data(curve, &count); 1157 double f_gamma = stp_curve_get_gamma(curve); 1158 double *tmp_data; 1159 1160 stp_curve_get_bounds(curve, &lo, &hi); 1161 1162 if (f_gamma) 1163 stp_curve_set_gamma(curve, -f_gamma); 1164 else 1165 { 1166 tmp_data = stp_malloc(sizeof(double) * count); 1167 for (i = 0; i < count; i++) 1168 tmp_data[i] = data[count - i - 1]; 1169 stp_curve_set_data(curve, count, tmp_data); 1170 stp_free(tmp_data); 1171 } 1172 if (!invert_output) 1173 { 1174 stp_curve_rescale(curve, -1, STP_CURVE_COMPOSE_MULTIPLY, 1175 STP_CURVE_BOUNDS_RESCALE); 1176 stp_curve_rescale(curve, lo + hi, STP_CURVE_COMPOSE_ADD, 1177 STP_CURVE_BOUNDS_RESCALE); 1178 } 1179} 1180 1181static void 1182compute_one_lut(lut_t *lut, int i) 1183{ 1184 stp_curve_t *curve = 1185 stp_curve_cache_get_curve(&(lut->channel_curves[i])); 1186 if (curve) 1187 { 1188 int invert_output = 1189 !channel_is_synthesized(lut, i) && lut->invert_output; 1190 stp_curve_rescale(curve, 65535.0, STP_CURVE_COMPOSE_MULTIPLY, 1191 STP_CURVE_BOUNDS_RESCALE); 1192 if (stp_curve_is_piecewise(curve)) 1193 stp_curve_resample(curve, lut->steps); 1194 if (lut->invert_output) 1195 invert_curve(curve, invert_output); 1196 stp_curve_resample(curve, lut->steps); 1197 } 1198 else 1199 { 1200 curve = stp_curve_create_copy(color_curve_bounds); 1201 stp_curve_rescale(curve, 65535.0, STP_CURVE_COMPOSE_MULTIPLY, 1202 STP_CURVE_BOUNDS_RESCALE); 1203 stp_curve_cache_set_curve(&(lut->channel_curves[i]), curve); 1204 compute_a_curve(lut, i); 1205 } 1206} 1207 1208static void 1209setup_channel(stp_vars_t *v, int i, const channel_param_t *p) 1210{ 1211 lut_t *lut = (lut_t *)(stp_get_component_data(v, "Color")); 1212 const char *gamma_name = 1213 (lut->output_color_description->color_model == COLOR_BLACK ? 1214 p->gamma_name : p->rgb_gamma_name); 1215 const char *curve_name = 1216 (lut->output_color_description->color_model == COLOR_BLACK ? 1217 p->curve_name : p->rgb_curve_name); 1218 if (stp_check_float_parameter(v, p->gamma_name, STP_PARAMETER_DEFAULTED)) 1219 lut->gamma_values[i] = stp_get_float_parameter(v, gamma_name); 1220 1221 if (stp_get_curve_parameter_active(v, curve_name) > 0 && 1222 stp_get_curve_parameter_active(v, curve_name) >= 1223 stp_get_float_parameter_active(v, gamma_name)) 1224 stp_curve_cache_set_curve_copy 1225 (&(lut->channel_curves[i]), stp_get_curve_parameter(v, curve_name)); 1226 1227 stp_dprintf(STP_DBG_LUT, v, " %s %.3f\n", gamma_name, lut->gamma_values[i]); 1228 compute_one_lut(lut, i); 1229} 1230 1231static void 1232stpi_print_lut_curve(FILE *fp, const char *text, stp_cached_curve_t *c, 1233 int reverse) 1234{ 1235 if (stp_curve_cache_get_curve(c)) 1236 { 1237 fprintf(fp, "%s: '", text); 1238 if (reverse) 1239 { 1240 stp_curve_t *rev = stp_curve_create_reverse(stp_curve_cache_get_curve(c)); 1241 stp_curve_write(fp, rev); 1242 stp_curve_destroy(rev); 1243 } 1244 else 1245 stp_curve_write(fp, stp_curve_cache_get_curve(c)); 1246 fprintf(fp, "'\n"); 1247 } 1248} 1249 1250static void 1251stpi_do_dump_lut_to_file(stp_vars_t *v, FILE *fp) 1252{ 1253 int i; 1254 lut_t *lut = (lut_t *)(stp_get_component_data(v, "Color")); 1255 const stp_curve_t *curve; 1256 fprintf(fp, "Gutenprint LUT dump version 0\n\n"); 1257 fprintf(fp, "Input color description: '%s'\n", lut->input_color_description->name); 1258 fprintf(fp, "Output color description: '%s'\n", lut->output_color_description->name); 1259 fprintf(fp, "Color correction type: '%s'\n", lut->color_correction->name); 1260 fprintf(fp, "Ink limit: %f\n", stp_get_float_parameter(v, "InkLimit")); 1261 stpi_print_lut_curve(fp, "Brightness correction", &(lut->brightness_correction), 0); 1262 stpi_print_lut_curve(fp, "Contrast correction", &(lut->contrast_correction), 0); 1263 stpi_print_lut_curve(fp, "User color correction", &(lut->user_color_correction), 0); 1264 for (i = 0; i < STP_CHANNEL_LIMIT; i++) 1265 { 1266 char buf[64]; 1267 sprintf(buf, "Channel %d curve", i); 1268 stpi_print_lut_curve(fp, buf, &(lut->channel_curves[i]), 1269 lut->invert_output && ! channel_is_synthesized(lut, i)); 1270 } 1271 curve = stp_channel_get_gcr_curve(v); 1272 if (curve) 1273 { 1274 fprintf(fp, "GCR curve: '"); 1275 stp_curve_write(fp, curve); 1276 fprintf(fp, "'\n"); 1277 } 1278} 1279 1280static void 1281stpi_dump_lut_to_file(stp_vars_t *v, const char *dump_file) 1282{ 1283 FILE *fp; 1284 if (!dump_file) 1285 return; 1286 fp = fopen(dump_file, "w"); 1287 if (fp) 1288 { 1289 stp_dprintf(STP_DBG_LUT, v, "Dumping LUT to %s\n", dump_file); 1290 stpi_do_dump_lut_to_file(v, fp); 1291 (void) fclose(fp); 1292 } 1293} 1294 1295static void 1296stpi_compute_lut(stp_vars_t *v) 1297{ 1298 int i; 1299 lut_t *lut = (lut_t *)(stp_get_component_data(v, "Color")); 1300 stp_curve_t *curve; 1301 stp_dprintf(STP_DBG_LUT, v, "stpi_compute_lut\n"); 1302 1303 if (lut->input_color_description->color_model == COLOR_UNKNOWN || 1304 lut->output_color_description->color_model == COLOR_UNKNOWN || 1305 lut->input_color_description->color_model == 1306 lut->output_color_description->color_model) 1307 lut->invert_output = 0; 1308 else 1309 lut->invert_output = 1; 1310 1311 lut->linear_contrast_adjustment = 0; 1312 lut->print_gamma = 1.0; 1313 lut->app_gamma = 1.0; 1314 lut->contrast = 1.0; 1315 lut->brightness = 1.0; 1316 lut->simple_gamma_correction = 0; 1317 1318 if (stp_check_boolean_parameter(v, "LinearContrast", STP_PARAMETER_DEFAULTED)) 1319 lut->linear_contrast_adjustment = 1320 stp_get_boolean_parameter(v, "LinearContrast"); 1321 if (stp_check_float_parameter(v, "Gamma", STP_PARAMETER_DEFAULTED)) 1322 lut->print_gamma = stp_get_float_parameter(v, "Gamma"); 1323 if (stp_check_float_parameter(v, "Contrast", STP_PARAMETER_DEFAULTED)) 1324 lut->contrast = stp_get_float_parameter(v, "Contrast"); 1325 if (stp_check_float_parameter(v, "Brightness", STP_PARAMETER_DEFAULTED)) 1326 lut->brightness = stp_get_float_parameter(v, "Brightness"); 1327 1328 if (stp_check_float_parameter(v, "AppGamma", STP_PARAMETER_ACTIVE)) 1329 lut->app_gamma = stp_get_float_parameter(v, "AppGamma"); 1330 if (stp_check_boolean_parameter(v, "SimpleGamma", STP_PARAMETER_ACTIVE)) 1331 lut->simple_gamma_correction = stp_get_boolean_parameter(v, "SimpleGamma"); 1332 lut->screen_gamma = lut->app_gamma / 4.0; /* "Empirical" */ 1333 curve = stp_curve_create_copy(color_curve_bounds); 1334 stp_curve_rescale(curve, 65535.0, STP_CURVE_COMPOSE_MULTIPLY, 1335 STP_CURVE_BOUNDS_RESCALE); 1336 stp_curve_cache_set_curve(&(lut->user_color_correction), curve); 1337 curve = stp_curve_create_copy(color_curve_bounds); 1338 stp_curve_rescale(curve, 65535.0, STP_CURVE_COMPOSE_MULTIPLY, 1339 STP_CURVE_BOUNDS_RESCALE); 1340 stp_curve_cache_set_curve(&(lut->brightness_correction), curve); 1341 curve = stp_curve_create_copy(color_curve_bounds); 1342 stp_curve_rescale(curve, 65535.0, STP_CURVE_COMPOSE_MULTIPLY, 1343 STP_CURVE_BOUNDS_RESCALE); 1344 stp_curve_cache_set_curve(&(lut->contrast_correction), curve); 1345 compute_user_correction(lut); 1346 1347 /* 1348 * TODO check that these are wraparound curves and all that 1349 */ 1350 1351 if (lut->color_correction->correct_hsl) 1352 { 1353 if (stp_check_curve_parameter(v, "HueMap", STP_PARAMETER_DEFAULTED)) 1354 { 1355 lut->hue_map.curve = 1356 stp_curve_create_copy(stp_get_curve_parameter(v, "HueMap")); 1357 if (stp_curve_is_piecewise(lut->hue_map.curve)) 1358 stp_curve_resample(lut->hue_map.curve, 384); 1359 } 1360 if (stp_check_curve_parameter(v, "LumMap", STP_PARAMETER_DEFAULTED)) 1361 { 1362 lut->lum_map.curve = 1363 stp_curve_create_copy(stp_get_curve_parameter(v, "LumMap")); 1364 if (stp_curve_is_piecewise(lut->lum_map.curve)) 1365 stp_curve_resample(lut->lum_map.curve, 384); 1366 } 1367 if (stp_check_curve_parameter(v, "SatMap", STP_PARAMETER_DEFAULTED)) 1368 { 1369 lut->sat_map.curve = 1370 stp_curve_create_copy(stp_get_curve_parameter(v, "SatMap")); 1371 if (stp_curve_is_piecewise(lut->sat_map.curve)) 1372 stp_curve_resample(lut->sat_map.curve, 384); 1373 } 1374 } 1375 1376 stp_dprintf(STP_DBG_LUT, v, " print_gamma %.3f\n", lut->print_gamma); 1377 stp_dprintf(STP_DBG_LUT, v, " contrast %.3f\n", lut->contrast); 1378 stp_dprintf(STP_DBG_LUT, v, " brightness %.3f\n", lut->brightness); 1379 stp_dprintf(STP_DBG_LUT, v, " screen_gamma %.3f\n", lut->screen_gamma); 1380 1381 for (i = 0; i < STP_CHANNEL_LIMIT; i++) 1382 { 1383 if (lut->output_color_description->channel_count < 1 && 1384 i < lut->out_channels) 1385 setup_channel(v, i, &(raw_channel_params[i])); 1386 else if (i < channel_param_count && 1387 lut->output_color_description->channels & (1 << i)) 1388 setup_channel(v, i, &(channel_params[i])); 1389 } 1390 if (((lut->output_color_description->channels & CMASK_CMYK) == CMASK_CMYK) && 1391 (lut->color_correction->correction == COLOR_CORRECTION_DESATURATED || 1392 lut->input_color_description->color_id == COLOR_ID_GRAY || 1393 lut->input_color_description->color_id == COLOR_ID_WHITE || 1394 lut->input_color_description->color_id == COLOR_ID_RGB || 1395 lut->input_color_description->color_id == COLOR_ID_CMY)) 1396 initialize_gcr_curve(v); 1397 if (stp_check_file_parameter(v, "LUTDumpFile", STP_PARAMETER_ACTIVE)) 1398 stpi_dump_lut_to_file(v, stp_get_file_parameter(v, "LUTDumpFile")); 1399} 1400 1401static int 1402stpi_color_traditional_init(stp_vars_t *v, 1403 stp_image_t *image, 1404 size_t steps) 1405{ 1406 lut_t *lut; 1407 const char *image_type = stp_get_string_parameter(v, "ImageType"); 1408 const char *color_correction = stp_get_string_parameter(v, "ColorCorrection"); 1409 const channel_depth_t *channel_depth = 1410 get_channel_depth(stp_get_string_parameter(v, "ChannelBitDepth")); 1411 size_t total_channel_bits; 1412 1413 if (steps != 256 && steps != 65536) 1414 return -1; 1415 if (!channel_depth) 1416 return -1; 1417 1418 lut = allocate_lut(); 1419 lut->input_color_description = 1420 get_color_description(stp_get_string_parameter(v, "InputImageType")); 1421 lut->output_color_description = 1422 get_color_description(stp_get_string_parameter(v, "STPIOutputType")); 1423 1424 if (!lut->input_color_description || !lut->output_color_description) 1425 { 1426 free_lut(lut); 1427 return -1; 1428 } 1429 1430 if (lut->input_color_description->color_id == COLOR_ID_RAW) 1431 { 1432 if (stp_verify_parameter(v, "STPIRawChannels", 1) != PARAMETER_OK) 1433 { 1434 free_lut(lut); 1435 return -1; 1436 } 1437 lut->out_channels = stp_get_int_parameter(v, "STPIRawChannels"); 1438 lut->in_channels = lut->out_channels; 1439 } 1440 else 1441 { 1442 lut->out_channels = lut->output_color_description->channel_count; 1443 lut->in_channels = lut->input_color_description->channel_count; 1444 } 1445 1446 stp_allocate_component_data(v, "Color", copy_lut, free_lut, lut); 1447 lut->steps = steps; 1448 lut->channel_depth = channel_depth->bits; 1449 1450 if ((!color_correction || strcmp(color_correction, "None") == 0) && 1451 image_type && strcmp(image_type, "None") != 0) 1452 { 1453 if (strcmp(image_type, "Text") == 0) 1454 lut->color_correction = get_color_correction("Threshold"); 1455 else 1456 lut->color_correction = get_color_correction("None"); 1457 } 1458 else if (color_correction) 1459 lut->color_correction = get_color_correction(color_correction); 1460 else 1461 lut->color_correction = get_color_correction("None"); 1462 if (lut->color_correction->correction == COLOR_CORRECTION_DEFAULT) 1463 lut->color_correction = 1464 (get_color_correction_by_tag 1465 (lut->output_color_description->default_correction)); 1466 1467 stpi_compute_lut(v); 1468 1469 lut->image_width = stp_image_width(image); 1470 total_channel_bits = lut->in_channels * lut->channel_depth; 1471 lut->in_data = stp_malloc(((lut->image_width * total_channel_bits) + 7)/8); 1472 memset(lut->in_data, 0, ((lut->image_width * total_channel_bits) + 7) / 8); 1473 return lut->out_channels; 1474} 1475 1476static void 1477initialize_standard_curves(void) 1478{ 1479 if (!standard_curves_initialized) 1480 { 1481 int i; 1482 hue_map_bounds = stp_curve_create_from_string 1483 ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" 1484 "<gutenprint>\n" 1485 "<curve wrap=\"wrap\" type=\"linear\" gamma=\"0\">\n" 1486 "<sequence count=\"2\" lower-bound=\"-6\" upper-bound=\"6\">\n" 1487 "0 0\n" 1488 "</sequence>\n" 1489 "</curve>\n" 1490 "</gutenprint>"); 1491 lum_map_bounds = stp_curve_create_from_string 1492 ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" 1493 "<gutenprint>\n" 1494 "<curve wrap=\"wrap\" type=\"linear\" gamma=\"0\">\n" 1495 "<sequence count=\"2\" lower-bound=\"0\" upper-bound=\"4\">\n" 1496 "1 1\n" 1497 "</sequence>\n" 1498 "</curve>\n" 1499 "</gutenprint>"); 1500 sat_map_bounds = stp_curve_create_from_string 1501 ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" 1502 "<gutenprint>\n" 1503 "<curve wrap=\"wrap\" type=\"linear\" gamma=\"0\">\n" 1504 "<sequence count=\"2\" lower-bound=\"0\" upper-bound=\"4\">\n" 1505 "1 1\n" 1506 "</sequence>\n" 1507 "</curve>\n" 1508 "</gutenprint>"); 1509 color_curve_bounds = stp_curve_create_from_string 1510 ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" 1511 "<gutenprint>\n" 1512 "<curve wrap=\"nowrap\" type=\"linear\" gamma=\"1.0\">\n" 1513 "<sequence count=\"0\" lower-bound=\"0\" upper-bound=\"1\">\n" 1514 "</sequence>\n" 1515 "</curve>\n" 1516 "</gutenprint>"); 1517 gcr_curve_bounds = stp_curve_create_from_string 1518 ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" 1519 "<gutenprint>\n" 1520 "<curve wrap=\"nowrap\" type=\"linear\" gamma=\"0.0\">\n" 1521 "<sequence count=\"2\" lower-bound=\"0\" upper-bound=\"1\">\n" 1522 "1 1\n" 1523 "</sequence>\n" 1524 "</curve>\n" 1525 "</gutenprint>"); 1526 for (i = 0; i < curve_parameter_count; i++) 1527 curve_parameters[i].param.deflt.curve = 1528 *(curve_parameters[i].defval); 1529 standard_curves_initialized = 1; 1530 } 1531} 1532 1533static stp_parameter_list_t 1534stpi_color_traditional_list_parameters(const stp_vars_t *v) 1535{ 1536 stp_list_t *ret = stp_parameter_list_create(); 1537 int i; 1538 initialize_standard_curves(); 1539 for (i = 0; i < float_parameter_count; i++) 1540 stp_parameter_list_add_param(ret, &(float_parameters[i].param)); 1541 for (i = 0; i < curve_parameter_count; i++) 1542 stp_parameter_list_add_param(ret, &(curve_parameters[i].param)); 1543 return ret; 1544} 1545 1546static void 1547stpi_color_traditional_describe_parameter(const stp_vars_t *v, 1548 const char *name, 1549 stp_parameter_t *description) 1550{ 1551 int i, j; 1552 description->p_type = STP_PARAMETER_TYPE_INVALID; 1553 initialize_standard_curves(); 1554 if (name == NULL) 1555 return; 1556 1557 for (i = 0; i < float_parameter_count; i++) 1558 { 1559 const float_param_t *param = &(float_parameters[i]); 1560 if (strcmp(name, param->param.name) == 0) 1561 { 1562 stp_fill_parameter_settings(description, &(param->param)); 1563 if (param->channel_mask != CMASK_EVERY) 1564 { 1565 const color_description_t *color_description = 1566 get_color_description(stp_describe_output(v)); 1567 if (color_description && 1568 (param->channel_mask & color_description->channels) && 1569 (param->is_rgb < 0 || 1570 (param->is_rgb == 0 && 1571 color_description->color_model == COLOR_BLACK) || 1572 (param->is_rgb == 1 && 1573 color_description->color_model == COLOR_WHITE)) && 1574 param->channel_mask != CMASK_RAW) 1575 description->is_active = 1; 1576 else 1577 description->is_active = 0; 1578 if (param->color_only && 1579 !(color_description->channels & ~CMASK_K)) 1580 description->is_active = 0; 1581 } 1582 switch (param->param.p_type) 1583 { 1584 case STP_PARAMETER_TYPE_BOOLEAN: 1585 description->deflt.boolean = (int) param->defval; 1586 break; 1587 case STP_PARAMETER_TYPE_INT: 1588 description->bounds.integer.upper = (int) param->max; 1589 description->bounds.integer.lower = (int) param->min; 1590 description->deflt.integer = (int) param->defval; 1591 break; 1592 case STP_PARAMETER_TYPE_DOUBLE: 1593 description->bounds.dbl.upper = param->max; 1594 description->bounds.dbl.lower = param->min; 1595 description->deflt.dbl = param->defval; 1596 if (strcmp(name, "InkLimit") == 0) 1597 { 1598 stp_parameter_t ink_limit_desc; 1599 stp_describe_parameter(v, "InkChannels", &ink_limit_desc); 1600 if (ink_limit_desc.p_type == STP_PARAMETER_TYPE_INT) 1601 { 1602 if (ink_limit_desc.deflt.integer > 1) 1603 { 1604 description->bounds.dbl.upper = 1605 ink_limit_desc.deflt.integer; 1606 description->deflt.dbl = 1607 ink_limit_desc.deflt.integer; 1608 } 1609 else 1610 description->is_active = 0; 1611 } 1612 stp_parameter_description_destroy(&ink_limit_desc); 1613 } 1614 break; 1615 case STP_PARAMETER_TYPE_STRING_LIST: 1616 if (!strcmp(param->param.name, "ColorCorrection")) 1617 { 1618 description->bounds.str = stp_string_list_create(); 1619 for (j = 0; j < color_correction_count; j++) 1620 stp_string_list_add_string 1621 (description->bounds.str, color_corrections[j].name, 1622 gettext(color_corrections[j].text)); 1623 description->deflt.str = 1624 stp_string_list_param(description->bounds.str, 0)->name; 1625 } 1626 else if (strcmp(name, "ChannelBitDepth") == 0) 1627 { 1628 description->bounds.str = stp_string_list_create(); 1629 for (j = 0; j < channel_depth_count; j++) 1630 stp_string_list_add_string 1631 (description->bounds.str, channel_depths[j].name, 1632 channel_depths[j].name); 1633 description->deflt.str = 1634 stp_string_list_param(description->bounds.str, 0)->name; 1635 } 1636 else if (strcmp(name, "InputImageType") == 0) 1637 { 1638 description->bounds.str = stp_string_list_create(); 1639 for (j = 0; j < color_description_count; j++) 1640 if (color_descriptions[j].input) 1641 { 1642 if (color_descriptions[j].color_id == COLOR_ID_RAW) 1643 { 1644 stp_parameter_t desc; 1645 stp_describe_parameter(v, "RawChannels", &desc); 1646 if (desc.p_type == STP_PARAMETER_TYPE_STRING_LIST) 1647 stp_string_list_add_string 1648 (description->bounds.str, 1649 color_descriptions[j].name, 1650 gettext(color_descriptions[j].name)); 1651 stp_parameter_description_destroy(&desc); 1652 } 1653 else 1654 stp_string_list_add_string 1655 (description->bounds.str, 1656 color_descriptions[j].name, 1657 gettext(color_descriptions[j].name)); 1658 } 1659 description->deflt.str = 1660 stp_string_list_param(description->bounds.str, 0)->name; 1661 } 1662 else if (strcmp(name, "OutputImageType") == 0) 1663 { 1664 description->bounds.str = stp_string_list_create(); 1665 for (j = 0; j < color_description_count; j++) 1666 if (color_descriptions[j].output) 1667 stp_string_list_add_string 1668 (description->bounds.str, color_descriptions[j].name, 1669 gettext(color_descriptions[j].name)); 1670 description->deflt.str = 1671 stp_string_list_param(description->bounds.str, 0)->name; 1672 } 1673 break; 1674 default: 1675 break; 1676 } 1677 return; 1678 } 1679 } 1680 for (i = 0; i < curve_parameter_count; i++) 1681 { 1682 curve_param_t *param = &(curve_parameters[i]); 1683 if (strcmp(name, param->param.name) == 0) 1684 { 1685 description->is_active = 1; 1686 stp_fill_parameter_settings(description, &(param->param)); 1687 if (param->channel_mask != CMASK_EVERY) 1688 { 1689 const color_description_t *color_description = 1690 get_color_description(stp_describe_output(v)); 1691 if (color_description && 1692 (param->is_rgb < 0 || 1693 (param->is_rgb == 0 && 1694 color_description->color_model == COLOR_BLACK) || 1695 (param->is_rgb == 1 && 1696 color_description->color_model == COLOR_WHITE)) && 1697 (param->channel_mask & color_description->channels)) 1698 description->is_active = 1; 1699 else 1700 description->is_active = 0; 1701 if (param->color_only && 1702 !(color_description->channels & ~CMASK_K)) 1703 description->is_active = 0; 1704 } 1705 if (param->hsl_only) 1706 { 1707 const color_correction_t *correction = 1708 (get_color_correction 1709 (stp_get_string_parameter (v, "ColorCorrection"))); 1710 if (correction && !correction->correct_hsl) 1711 description->is_active = 0; 1712 } 1713 switch (param->param.p_type) 1714 { 1715 case STP_PARAMETER_TYPE_CURVE: 1716 description->deflt.curve = *(param->defval); 1717 description->bounds.curve = 1718 stp_curve_create_copy(*(param->defval)); 1719 break; 1720 default: 1721 break; 1722 } 1723 return; 1724 } 1725 } 1726} 1727 1728 1729static const stp_colorfuncs_t stpi_color_traditional_colorfuncs = 1730{ 1731 &stpi_color_traditional_init, 1732 &stpi_color_traditional_get_row, 1733 &stpi_color_traditional_list_parameters, 1734 &stpi_color_traditional_describe_parameter 1735}; 1736 1737static const stp_color_t stpi_color_traditional_module_data = 1738 { 1739 "traditional", 1740 N_("Traditional Gutenprint color conversion"), 1741 &stpi_color_traditional_colorfuncs 1742 }; 1743 1744 1745static int 1746color_traditional_module_init(void) 1747{ 1748 return stp_color_register(&stpi_color_traditional_module_data); 1749} 1750 1751 1752static int 1753color_traditional_module_exit(void) 1754{ 1755 return stp_color_unregister(&stpi_color_traditional_module_data); 1756} 1757 1758 1759/* Module header */ 1760#define stp_module_version color_traditional_LTX_stp_module_version 1761#define stp_module_data color_traditional_LTX_stp_module_data 1762 1763stp_module_version_t stp_module_version = {0, 0}; 1764 1765stp_module_t stp_module_data = 1766 { 1767 "traditional", 1768 VERSION, 1769 "Traditional Gutenprint color conversion", 1770 STP_MODULE_CLASS_COLOR, 1771 NULL, 1772 color_traditional_module_init, 1773 color_traditional_module_exit, 1774 (void *) &stpi_color_traditional_module_data 1775 }; 1776