diff options
Diffstat (limited to 'driver/cmyk.c')
-rw-r--r-- | driver/cmyk.c | 1955 |
1 files changed, 1955 insertions, 0 deletions
diff --git a/driver/cmyk.c b/driver/cmyk.c new file mode 100644 index 0000000..757584b --- /dev/null +++ b/driver/cmyk.c @@ -0,0 +1,1955 @@ +/* + * "$Id: cmyk.c 9042 2010-03-24 00:45:34Z mike $" + * + * CMYK color separation code for CUPS. + * + * Copyright 2007-2010 by Apple Inc. + * Copyright 1993-2005 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Apple Inc. and are protected by Federal copyright + * law. Distribution and use rights are outlined in the file "LICENSE.txt" + * which should have been included with this file. If this file is + * file is missing or damaged, see the license at "http://www.cups.org/". + * + * Contents: + * + * cupsCMYKDelete() - Delete a color separation. + * cupsCMYKDoBlack() - Do a black separation... + * cupsCMYKDoCMYK() - Do a CMYK separation... + * cupsCMYKDoGray() - Do a grayscale separation... + * cupsCMYKDoRGB() - Do an sRGB separation... + * cupsCMYKLoad() - Load a CMYK color profile from PPD attributes. + * cupsCMYKNew() - Create a new CMYK color separation. + * cupsCMYKSetBlack() - Set the transition range for CMY to black. + * cupsCMYKSetCurve() - Set a color transform curve using points. + * cupsCMYKSetGamma() - Set a color transform curve using gamma and + * density. + * cupsCMYKSetInkLimit() - Set the limit on the amount of ink. + * cupsCMYKSetLtDk() - Set light/dark ink transforms. + */ + +/* + * Include necessary headers. + */ + +#include "driver.h" +#include <cups/string-private.h> + + +/* + * 'cupsCMYKDelete()' - Delete a color separation. + */ + +void +cupsCMYKDelete(cups_cmyk_t *cmyk) /* I - Color separation */ +{ + /* + * Range check input... + */ + + if (cmyk == NULL) + return; + + /* + * Free memory used... + */ + + free(cmyk->channels[0]); + free(cmyk); +} + + +/* + * 'cupsCMYKDoBlack()' - Do a black separation... + */ + +void +cupsCMYKDoBlack(const cups_cmyk_t *cmyk, + /* I - Color separation */ + const unsigned char *input, + /* I - Input grayscale pixels */ + short *output, + /* O - Output Device-N pixels */ + int num_pixels) + /* I - Number of pixels */ +{ + int k; /* Current black value */ + const short **channels; /* Copy of channel LUTs */ + int ink, /* Amount of ink */ + ink_limit; /* Ink limit from separation */ + + + /* + * Range check input... + */ + + if (cmyk == NULL || input == NULL || output == NULL || num_pixels <= 0) + return; + + /* + * Loop through it all... + */ + + channels = (const short **)cmyk->channels; + ink_limit = cmyk->ink_limit; + + switch (cmyk->num_channels) + { + case 1 : /* Black */ + while (num_pixels > 0) + { + /* + * Get the input black value and then set the corresponding color + * channel values... + */ + + k = *input++; + *output++ = channels[0][k]; + + num_pixels --; + } + break; + + case 2 : /* Black, light black */ + while (num_pixels > 0) + { + /* + * Get the input black value and then set the corresponding color + * channel values... + */ + + k = *input++; + output[0] = channels[0][k]; + output[1] = channels[1][k]; + + if (ink_limit) + { + ink = output[0] + output[1]; + + if (ink > ink_limit) + { + output[0] = ink_limit * output[0] / ink; + output[1] = ink_limit * output[1] / ink; + } + } + + output += 2; + num_pixels --; + } + break; + + case 3 : /* CMY */ + while (num_pixels > 0) + { + /* + * Get the input black value and then set the corresponding color + * channel values... + */ + + k = *input++; + output[0] = channels[0][k]; + output[1] = channels[1][k]; + output[2] = channels[2][k]; + + if (ink_limit) + { + ink = output[0] + output[1] + output[2]; + + if (ink > ink_limit) + { + output[0] = ink_limit * output[0] / ink; + output[1] = ink_limit * output[1] / ink; + output[2] = ink_limit * output[2] / ink; + } + } + + output += 3; + num_pixels --; + } + break; + + case 4 : /* CMYK */ + while (num_pixels > 0) + { + /* + * Get the input black value and then set the corresponding color + * channel values... + */ + + k = *input++; + *output++ = 0; + *output++ = 0; + *output++ = 0; + *output++ = channels[3][k]; + + num_pixels --; + } + break; + + case 6 : /* CcMmYK */ + while (num_pixels > 0) + { + /* + * Get the input black value and then set the corresponding color + * channel values... + */ + + k = *input++; + *output++ = 0; + *output++ = 0; + *output++ = 0; + *output++ = 0; + *output++ = 0; + *output++ = channels[5][k]; + + num_pixels --; + } + break; + + case 7 : /* CcMmYKk */ + while (num_pixels > 0) + { + /* + * Get the input black value and then set the corresponding color + * channel values... + */ + + k = *input++; + output[0] = 0; + output[1] = 0; + output[2] = 0; + output[3] = 0; + output[4] = 0; + output[5] = channels[5][k]; + output[6] = channels[6][k]; + + if (ink_limit) + { + ink = output[5] + output[6]; + + if (ink > ink_limit) + { + output[5] = ink_limit * output[5] / ink; + output[6] = ink_limit * output[6] / ink; + } + } + + output += 7; + num_pixels --; + } + break; + } +} + + +/* + * 'cupsCMYKDoCMYK()' - Do a CMYK separation... + */ + +void +cupsCMYKDoCMYK(const cups_cmyk_t *cmyk, + /* I - Color separation */ + const unsigned char *input, + /* I - Input grayscale pixels */ + short *output, + /* O - Output Device-N pixels */ + int num_pixels) + /* I - Number of pixels */ +{ + int c, /* Current cyan value */ + m, /* Current magenta value */ + y, /* Current yellow value */ + k; /* Current black value */ + const short **channels; /* Copy of channel LUTs */ + int ink, /* Amount of ink */ + ink_limit; /* Ink limit from separation */ + + + /* + * Range check input... + */ + + if (cmyk == NULL || input == NULL || output == NULL || num_pixels <= 0) + return; + + /* + * Loop through it all... + */ + + channels = (const short **)cmyk->channels; + ink_limit = cmyk->ink_limit; + + switch (cmyk->num_channels) + { + case 1 : /* Black */ + while (num_pixels > 0) + { + /* + * Get the input black value and then set the corresponding color + * channel values... + */ + + c = *input++; + m = *input++; + y = *input++; + k = *input++ + (c * 31 + m * 61 + y * 8) / 100; + + if (k < 255) + *output++ = channels[0][k]; + else + *output++ = channels[0][255]; + + num_pixels --; + } + break; + + case 2 : /* Black, light black */ + while (num_pixels > 0) + { + /* + * Get the input black value and then set the corresponding color + * channel values... + */ + + c = *input++; + m = *input++; + y = *input++; + k = *input++ + (c * 31 + m * 61 + y * 8) / 100; + + if (k < 255) + { + output[0] = channels[0][k]; + output[1] = channels[1][k]; + } + else + { + output[0] = channels[0][255]; + output[1] = channels[1][255]; + } + + if (ink_limit) + { + ink = output[0] + output[1]; + + if (ink > ink_limit) + { + output[0] = ink_limit * output[0] / ink; + output[1] = ink_limit * output[1] / ink; + } + } + + output += 2; + num_pixels --; + } + break; + + case 3 : /* CMY */ + while (num_pixels > 0) + { + /* + * Get the input black value and then set the corresponding color + * channel values... + */ + + c = *input++; + m = *input++; + y = *input++; + k = *input++; + c += k; + m += k; + y += k; + + if (c < 255) + output[0] = channels[0][c]; + else + output[0] = channels[0][255]; + + if (m < 255) + output[1] = channels[1][m]; + else + output[1] = channels[1][255]; + + if (y < 255) + output[2] = channels[2][y]; + else + output[2] = channels[2][255]; + + if (ink_limit) + { + ink = output[0] + output[1] + output[2]; + + if (ink > ink_limit) + { + output[0] = ink_limit * output[0] / ink; + output[1] = ink_limit * output[1] / ink; + output[2] = ink_limit * output[2] / ink; + } + } + + output += 3; + num_pixels --; + } + break; + + case 4 : /* CMYK */ + while (num_pixels > 0) + { + /* + * Get the input black value and then set the corresponding color + * channel values... + */ + + c = *input++; + m = *input++; + y = *input++; + k = *input++; + + output[0] = channels[0][c]; + output[1] = channels[1][m]; + output[2] = channels[2][y]; + output[3] = channels[3][k]; + + if (ink_limit) + { + ink = output[0] + output[1] + output[2] + output[3]; + + if (ink > ink_limit) + { + output[0] = ink_limit * output[0] / ink; + output[1] = ink_limit * output[1] / ink; + output[2] = ink_limit * output[2] / ink; + output[3] = ink_limit * output[3] / ink; + } + } + + output += 4; + num_pixels --; + } + break; + + case 6 : /* CcMmYK */ + while (num_pixels > 0) + { + /* + * Get the input black value and then set the corresponding color + * channel values... + */ + + c = *input++; + m = *input++; + y = *input++; + k = *input++; + + output[0] = channels[0][c]; + output[1] = channels[1][c]; + output[2] = channels[2][m]; + output[3] = channels[3][m]; + output[4] = channels[4][y]; + output[5] = channels[5][k]; + + if (ink_limit) + { + ink = output[0] + output[1] + output[2] + output[3] + + output[4] + output[5]; + + if (ink > ink_limit) + { + output[0] = ink_limit * output[0] / ink; + output[1] = ink_limit * output[1] / ink; + output[2] = ink_limit * output[2] / ink; + output[3] = ink_limit * output[3] / ink; + output[4] = ink_limit * output[4] / ink; + output[5] = ink_limit * output[5] / ink; + } + } + + output += 6; + num_pixels --; + } + break; + + case 7 : /* CcMmYKk */ + while (num_pixels > 0) + { + /* + * Get the input black value and then set the corresponding color + * channel values... + */ + + c = *input++; + m = *input++; + y = *input++; + k = *input++; + + output[0] = channels[0][c]; + output[1] = channels[1][c]; + output[2] = channels[2][m]; + output[3] = channels[3][m]; + output[4] = channels[4][y]; + output[5] = channels[5][k]; + output[6] = channels[6][k]; + + if (ink_limit) + { + ink = output[0] + output[1] + output[2] + output[3] + + output[4] + output[5] + output[6]; + + if (ink > ink_limit) + { + output[0] = ink_limit * output[0] / ink; + output[1] = ink_limit * output[1] / ink; + output[2] = ink_limit * output[2] / ink; + output[3] = ink_limit * output[3] / ink; + output[4] = ink_limit * output[4] / ink; + output[5] = ink_limit * output[5] / ink; + output[6] = ink_limit * output[6] / ink; + } + } + + output += 7; + num_pixels --; + } + break; + } +} + + +/* + * 'cupsCMYKDoGray()' - Do a grayscale separation... + */ + +void +cupsCMYKDoGray(const cups_cmyk_t *cmyk, + /* I - Color separation */ + const unsigned char *input, + /* I - Input grayscale pixels */ + short *output, + /* O - Output Device-N pixels */ + int num_pixels) + /* I - Number of pixels */ +{ + int k, /* Current black value */ + kc; /* Current black color value */ + const short **channels; /* Copy of channel LUTs */ + int ink, /* Amount of ink */ + ink_limit; /* Ink limit from separation */ + + + /* + * Range check input... + */ + + if (cmyk == NULL || input == NULL || output == NULL || num_pixels <= 0) + return; + + /* + * Loop through it all... + */ + + channels = (const short **)cmyk->channels; + ink_limit = cmyk->ink_limit; + + switch (cmyk->num_channels) + { + case 1 : /* Black */ + while (num_pixels > 0) + { + /* + * Get the input black value and then set the corresponding color + * channel values... + */ + + k = cups_scmy_lut[*input++]; + *output++ = channels[0][k]; + + num_pixels --; + } + break; + + case 2 : /* Black, light black */ + while (num_pixels > 0) + { + /* + * Get the input black value and then set the corresponding color + * channel values... + */ + + k = cups_scmy_lut[*input++]; + output[0] = channels[0][k]; + output[1] = channels[1][k]; + + if (ink_limit) + { + ink = output[0] + output[1]; + + if (ink > ink_limit) + { + output[0] = ink_limit * output[0] / ink; + output[1] = ink_limit * output[1] / ink; + } + } + + output += 2; + num_pixels --; + } + break; + + case 3 : /* CMY */ + while (num_pixels > 0) + { + /* + * Get the input black value and then set the corresponding color + * channel values... + */ + + k = cups_scmy_lut[*input++]; + output[0] = channels[0][k]; + output[1] = channels[1][k]; + output[2] = channels[2][k]; + + if (ink_limit) + { + ink = output[0] + output[1] + output[2]; + + if (ink > ink_limit) + { + output[0] = ink_limit * output[0] / ink; + output[1] = ink_limit * output[1] / ink; + output[2] = ink_limit * output[2] / ink; + } + } + + output += 3; + num_pixels --; + } + break; + + case 4 : /* CMYK */ + while (num_pixels > 0) + { + /* + * Get the input black value and then set the corresponding color + * channel values... + */ + + k = cups_scmy_lut[*input++]; + kc = cmyk->color_lut[k]; + k = cmyk->black_lut[k]; + output[0] = channels[0][kc]; + output[1] = channels[1][kc]; + output[2] = channels[2][kc]; + output[3] = channels[3][k]; + + if (ink_limit) + { + ink = output[0] + output[1] + output[2] + output[3]; + + if (ink > ink_limit) + { + output[0] = ink_limit * output[0] / ink; + output[1] = ink_limit * output[1] / ink; + output[2] = ink_limit * output[2] / ink; + output[3] = ink_limit * output[3] / ink; + } + } + + output += 4; + num_pixels --; + } + break; + + case 6 : /* CcMmYK */ + while (num_pixels > 0) + { + /* + * Get the input black value and then set the corresponding color + * channel values... + */ + + k = cups_scmy_lut[*input++]; + kc = cmyk->color_lut[k]; + k = cmyk->black_lut[k]; + output[0] = channels[0][kc]; + output[1] = channels[1][kc]; + output[2] = channels[2][kc]; + output[3] = channels[3][kc]; + output[4] = channels[4][kc]; + output[5] = channels[5][k]; + + if (ink_limit) + { + ink = output[0] + output[1] + output[2] + output[3] + + output[4] + output[5]; + + if (ink > ink_limit) + { + output[0] = ink_limit * output[0] / ink; + output[1] = ink_limit * output[1] / ink; + output[2] = ink_limit * output[2] / ink; + output[3] = ink_limit * output[3] / ink; + output[4] = ink_limit * output[4] / ink; + output[5] = ink_limit * output[5] / ink; + } + } + + output += 6; + num_pixels --; + } + break; + + case 7 : /* CcMmYKk */ + while (num_pixels > 0) + { + /* + * Get the input black value and then set the corresponding color + * channel values... + */ + + k = cups_scmy_lut[*input++]; + kc = cmyk->color_lut[k]; + k = cmyk->black_lut[k]; + output[0] = channels[0][kc]; + output[1] = channels[1][kc]; + output[2] = channels[2][kc]; + output[3] = channels[3][kc]; + output[4] = channels[4][kc]; + output[5] = channels[5][k]; + output[6] = channels[6][k]; + + if (ink_limit) + { + ink = output[0] + output[1] + output[2] + output[3] + + output[4] + output[5] + output[6]; + + if (ink > ink_limit) + { + output[0] = ink_limit * output[0] / ink; + output[1] = ink_limit * output[1] / ink; + output[2] = ink_limit * output[2] / ink; + output[3] = ink_limit * output[3] / ink; + output[4] = ink_limit * output[4] / ink; + output[5] = ink_limit * output[5] / ink; + output[6] = ink_limit * output[6] / ink; + } + } + + output += 7; + num_pixels --; + } + break; + } +} + + +/* + * 'cupsCMYKDoRGB()' - Do an sRGB separation... + */ + +void +cupsCMYKDoRGB(const cups_cmyk_t *cmyk, + /* I - Color separation */ + const unsigned char *input, + /* I - Input grayscale pixels */ + short *output, + /* O - Output Device-N pixels */ + int num_pixels) + /* I - Number of pixels */ +{ + int c, /* Current cyan value */ + m, /* Current magenta value */ + y, /* Current yellow value */ + k, /* Current black value */ + kc, /* Current black color value */ + km; /* Maximum black value */ + const short **channels; /* Copy of channel LUTs */ + int ink, /* Amount of ink */ + ink_limit; /* Ink limit from separation */ + + + /* + * Range check input... + */ + + if (cmyk == NULL || input == NULL || output == NULL || num_pixels <= 0) + return; + + /* + * Loop through it all... + */ + + channels = (const short **)cmyk->channels; + ink_limit = cmyk->ink_limit; + + switch (cmyk->num_channels) + { + case 1 : /* Black */ + while (num_pixels > 0) + { + /* + * Get the input black value and then set the corresponding color + * channel values... + */ + + c = cups_scmy_lut[*input++]; + m = cups_scmy_lut[*input++]; + y = cups_scmy_lut[*input++]; + k = (c * 31 + m * 61 + y * 8) / 100; + + *output++ = channels[0][k]; + + num_pixels --; + } + break; + + case 2 : /* Black, light black */ + while (num_pixels > 0) + { + /* + * Get the input black value and then set the corresponding color + * channel values... + */ + + c = cups_scmy_lut[*input++]; + m = cups_scmy_lut[*input++]; + y = cups_scmy_lut[*input++]; + k = (c * 31 + m * 61 + y * 8) / 100; + + output[0] = channels[0][k]; + output[1] = channels[1][k]; + + if (ink_limit) + { + ink = output[0] + output[1]; + + if (ink > ink_limit) + { + output[0] = ink_limit * output[0] / ink; + output[1] = ink_limit * output[1] / ink; + } + } + + output += 2; + num_pixels --; + } + break; + + case 3 : /* CMY */ + while (num_pixels > 0) + { + /* + * Get the input black value and then set the corresponding color + * channel values... + */ + + c = cups_scmy_lut[*input++]; + m = cups_scmy_lut[*input++]; + y = cups_scmy_lut[*input++]; + + output[0] = channels[0][c]; + output[1] = channels[1][m]; + output[2] = channels[2][y]; + + if (ink_limit) + { + ink = output[0] + output[1] + output[2]; + + if (ink > ink_limit) + { + output[0] = ink_limit * output[0] / ink; + output[1] = ink_limit * output[1] / ink; + output[2] = ink_limit * output[2] / ink; + } + } + + output += 3; + num_pixels --; + } + break; + + case 4 : /* CMYK */ + while (num_pixels > 0) + { + /* + * Get the input black value and then set the corresponding color + * channel values... + */ + + c = cups_scmy_lut[*input++]; + m = cups_scmy_lut[*input++]; + y = cups_scmy_lut[*input++]; + k = min(c, min(m, y)); + + if ((km = max(c, max(m, y))) > k) + k = k * k * k / (km * km); + + kc = cmyk->color_lut[k] - k; + k = cmyk->black_lut[k]; + c += kc; + m += kc; + y += kc; + + output[0] = channels[0][c]; + output[1] = channels[1][m]; + output[2] = channels[2][y]; + output[3] = channels[3][k]; + + if (ink_limit) + { + ink = output[0] + output[1] + output[2] + output[3]; + + if (ink > ink_limit) + { + output[0] = ink_limit * output[0] / ink; + output[1] = ink_limit * output[1] / ink; + output[2] = ink_limit * output[2] / ink; + output[3] = ink_limit * output[3] / ink; + } + } + + output += 4; + num_pixels --; + } + break; + + case 6 : /* CcMmYK */ + while (num_pixels > 0) + { + /* + * Get the input black value and then set the corresponding color + * channel values... + */ + + c = cups_scmy_lut[*input++]; + m = cups_scmy_lut[*input++]; + y = cups_scmy_lut[*input++]; + k = min(c, min(m, y)); + + if ((km = max(c, max(m, y))) > k) + k = k * k * k / (km * km); + + kc = cmyk->color_lut[k] - k; + k = cmyk->black_lut[k]; + c += kc; + m += kc; + y += kc; + + output[0] = channels[0][c]; + output[1] = channels[1][c]; + output[2] = channels[2][m]; + output[3] = channels[3][m]; + output[4] = channels[4][y]; + output[5] = channels[5][k]; + + if (ink_limit) + { + ink = output[0] + output[1] + output[2] + output[3] + + output[4] + output[5]; + + if (ink > ink_limit) + { + output[0] = ink_limit * output[0] / ink; + output[1] = ink_limit * output[1] / ink; + output[2] = ink_limit * output[2] / ink; + output[3] = ink_limit * output[3] / ink; + output[4] = ink_limit * output[4] / ink; + output[5] = ink_limit * output[5] / ink; + } + } + + output += 6; + num_pixels --; + } + break; + + case 7 : /* CcMmYKk */ + while (num_pixels > 0) + { + /* + * Get the input black value and then set the corresponding color + * channel values... + */ + + c = cups_scmy_lut[*input++]; + m = cups_scmy_lut[*input++]; + y = cups_scmy_lut[*input++]; + k = min(c, min(m, y)); + + if ((km = max(c, max(m, y))) > k) + k = k * k * k / (km * km); + + kc = cmyk->color_lut[k] - k; + k = cmyk->black_lut[k]; + c += kc; + m += kc; + y += kc; + + output[0] = channels[0][c]; + output[1] = channels[1][c]; + output[2] = channels[2][m]; + output[3] = channels[3][m]; + output[4] = channels[4][y]; + output[5] = channels[5][k]; + output[6] = channels[6][k]; + + if (ink_limit) + { + ink = output[0] + output[1] + output[2] + output[3] + + output[4] + output[5] + output[6]; + + if (ink > ink_limit) + { + output[0] = ink_limit * output[0] / ink; + output[1] = ink_limit * output[1] / ink; + output[2] = ink_limit * output[2] / ink; + output[3] = ink_limit * output[3] / ink; + output[4] = ink_limit * output[4] / ink; + output[5] = ink_limit * output[5] / ink; + output[6] = ink_limit * output[6] / ink; + } + } + + output += 7; + num_pixels --; + } + break; + } +} + + +/* + * 'cupsCMYKLoad()' - Load a CMYK color profile from PPD attributes. + */ + +cups_cmyk_t * /* O - CMYK color separation */ +cupsCMYKLoad(ppd_file_t *ppd, /* I - PPD file */ + const char *colormodel, /* I - ColorModel value */ + const char *media, /* I - MediaType value */ + const char *resolution) /* I - Resolution value */ +{ + cups_cmyk_t *cmyk; /* CMYK color separation */ + char spec[PPD_MAX_NAME]; /* Profile name */ + ppd_attr_t *attr; /* Attribute from PPD file */ + int num_channels; /* Number of color components */ + float gamval, /* Gamma correction value */ + density, /* Density value */ + light, /* Light ink limit */ + dark, /* Light ink cut-off */ + lower, /* Start of black ink */ + upper; /* End of color ink */ + int num_xypoints; /* Number of X,Y points */ + float xypoints[100 * 2], /* X,Y points */ + *xyptr; /* Current X,Y point */ + + + /* + * Range check input... + */ + + if (ppd == NULL || colormodel == NULL || resolution == NULL || media == NULL) + return (NULL); + + /* + * Find the following attributes: + * + * cupsAllGamma - Set default curve using gamma + density + * cupsAllXY - Set default curve using XY points + * cupsBlackGamma - Set black curve using gamma + density + * cupsBlackGeneration - Set black generation + * cupsBlackLightDark - Set black light/dark transition + * cupsBlackXY - Set black curve using XY points + * cupsCyanGamma - Set cyan curve using gamma + density + * cupsCyanLightDark - Set cyan light/dark transition + * cupsCyanXY - Set cyan curve using XY points + * cupsInkChannels - Set number of color channels + * cupsInkLimit - Set total ink limit + * cupsLightBlackGamma - Set light black curve using gamma + density + * cupsLightBlackXY - Set light black curve using XY points + * cupsLightCyanGamma - Set light cyan curve using gamma + density + * cupsLightCyanXY - Set light cyan curve using XY points + * cupsLightMagentaGamma - Set light magenta curve using gamma + density + * cupsLightMagentaXY - Set light magenta curve using XY points + * cupsMagentaGamma - Set magenta curve using gamma + density + * cupsMagentaLightDark - Set magenta light/dark transition + * cupsMagentaXY - Set magenta curve using XY points + * cupsYellowGamma - Set yellow curve using gamma + density + * cupsYellowXY - Set yellow curve using XY points + * + * The only required attribute is cupsInkChannels. + * + * The *XY attributes have precedence over the *Gamma attributes, and + * the *Light* attributes have precedence over the corresponding + * *LightDark* attributes. + */ + + /* + * Get the required cupsInkChannels attribute... + */ + + if ((attr = cupsFindAttr(ppd, "cupsInkChannels", colormodel, media, + resolution, spec, sizeof(spec))) == NULL) + return (NULL); + + num_channels = atoi(attr->value); + + if (num_channels < 1 || num_channels > 7 || num_channels == 5) + return (NULL); + + if ((cmyk = cupsCMYKNew(num_channels)) == NULL) + return (NULL); + + /* + * Get the optional cupsInkLimit attribute... + */ + + if ((attr = cupsFindAttr(ppd, "cupsInkLimit", colormodel, media, + resolution, spec, sizeof(spec))) != NULL) + cupsCMYKSetInkLimit(cmyk, atof(attr->value)); + + /* + * Get the optional cupsBlackGeneration attribute... + */ + + if ((attr = cupsFindAttr(ppd, "cupsBlackGeneration", colormodel, media, + resolution, spec, sizeof(spec))) != NULL) + { + if (sscanf(attr->value, "%f%f", &lower, &upper) == 2) + cupsCMYKSetBlack(cmyk, lower, upper); + } + + /* + * Get the optional cupsBlackXY or cupsBlackGamma attributes... + */ + + if (num_channels != 3) + { + if ((attr = cupsFindAttr(ppd, "cupsBlackXY", colormodel, media, + resolution, spec, sizeof(spec))) != NULL) + { + for (num_xypoints = 0, xyptr = xypoints; + attr != NULL && attr->value != NULL && num_xypoints < 100; + attr = ppdFindNextAttr(ppd, "cupsBlackXY", spec)) + if (sscanf(attr->value, "%f%f", xyptr, xyptr + 1) == 2) + { + num_xypoints ++; + xyptr += 2; + } + + switch (num_channels) + { + case 1 : + case 2 : + cupsCMYKSetCurve(cmyk, 0, num_xypoints, xypoints); + break; + case 4 : + cupsCMYKSetCurve(cmyk, 3, num_xypoints, xypoints); + break; + case 6 : + case 7 : + cupsCMYKSetCurve(cmyk, 5, num_xypoints, xypoints); + break; + } + } + else if ((attr = cupsFindAttr(ppd, "cupsBlackGamma", colormodel, + media, resolution, spec, + sizeof(spec))) != NULL) + { + if (sscanf(attr->value, "%f%f", &gamval, &density) == 2) + switch (num_channels) + { + case 1 : + case 2 : + cupsCMYKSetGamma(cmyk, 0, gamval, density); + break; + case 4 : + cupsCMYKSetGamma(cmyk, 3, gamval, density); + break; + case 6 : + case 7 : + cupsCMYKSetGamma(cmyk, 5, gamval, density); + break; + } + } + else if ((attr = cupsFindAttr(ppd, "cupsAllXY", colormodel, media, + resolution, spec, sizeof(spec))) != NULL) + { + for (num_xypoints = 0, xyptr = xypoints; + attr != NULL && attr->value != NULL && num_xypoints < 100; + attr = ppdFindNextAttr(ppd, "cupsAllXY", spec)) + if (sscanf(attr->value, "%f%f", xyptr, xyptr + 1) == 2) + { + num_xypoints ++; + xyptr += 2; + } + + switch (num_channels) + { + case 1 : + case 2 : + cupsCMYKSetCurve(cmyk, 0, num_xypoints, xypoints); + break; + case 4 : + cupsCMYKSetCurve(cmyk, 3, num_xypoints, xypoints); + break; + case 6 : + case 7 : + cupsCMYKSetCurve(cmyk, 5, num_xypoints, xypoints); + break; + } + } + else if ((attr = cupsFindAttr(ppd, "cupsAllGamma", colormodel, + media, resolution, spec, + sizeof(spec))) != NULL && + num_channels != 3) + { + if (sscanf(attr->value, "%f%f", &gamval, &density) == 2) + switch (num_channels) + { + case 1 : + case 2 : + cupsCMYKSetGamma(cmyk, 0, gamval, density); + break; + case 4 : + cupsCMYKSetGamma(cmyk, 3, gamval, density); + break; + case 6 : + case 7 : + cupsCMYKSetGamma(cmyk, 5, gamval, density); + break; + } + } + } + + if (num_channels > 2) + { + /* + * Get the optional cupsCyanXY or cupsCyanGamma attributes... + */ + + if ((attr = cupsFindAttr(ppd, "cupsCyanXY", colormodel, media, + resolution, spec, sizeof(spec))) != NULL) + { + for (num_xypoints = 0, xyptr = xypoints; + attr != NULL && attr->value != NULL && num_xypoints < 100; + attr = ppdFindNextAttr(ppd, "cupsCyanXY", spec)) + if (sscanf(attr->value, "%f%f", xyptr, xyptr + 1) == 2) + { + num_xypoints ++; + xyptr += 2; + } + + cupsCMYKSetCurve(cmyk, 0, num_xypoints, xypoints); + } + else if ((attr = cupsFindAttr(ppd, "cupsCyanGamma", colormodel, media, + resolution, spec, sizeof(spec))) != NULL) + { + if (sscanf(attr->value, "%f%f", &gamval, &density) == 2) + cupsCMYKSetGamma(cmyk, 0, gamval, density); + } + else if ((attr = cupsFindAttr(ppd, "cupsAllXY", colormodel, media, + resolution, spec, sizeof(spec))) != NULL) + { + for (num_xypoints = 0, xyptr = xypoints; + attr != NULL && attr->value != NULL && num_xypoints < 100; + attr = ppdFindNextAttr(ppd, "cupsAllXY", spec)) + if (sscanf(attr->value, "%f%f", xyptr, xyptr + 1) == 2) + { + num_xypoints ++; + xyptr += 2; + } + + cupsCMYKSetCurve(cmyk, 0, num_xypoints, xypoints); + } + else if ((attr = cupsFindAttr(ppd, "cupsAllGamma", colormodel, media, + resolution, spec, sizeof(spec))) != NULL) + { + if (sscanf(attr->value, "%f%f", &gamval, &density) == 2) + cupsCMYKSetGamma(cmyk, 0, gamval, density); + } + + /* + * Get the optional cupsMagentaXY or cupsMagentaGamma attributes... + */ + + if ((attr = cupsFindAttr(ppd, "cupsMagentaXY", colormodel, media, + resolution, spec, sizeof(spec))) != NULL) + { + for (num_xypoints = 0, xyptr = xypoints; + attr != NULL && attr->value != NULL && num_xypoints < 100; + attr = ppdFindNextAttr(ppd, "cupsMagentaXY", spec)) + if (sscanf(attr->value, "%f%f", xyptr, xyptr + 1) == 2) + { + num_xypoints ++; + xyptr += 2; + } + + switch (num_channels) + { + case 3 : + case 4 : + cupsCMYKSetCurve(cmyk, 1, num_xypoints, xypoints); + break; + case 6 : + case 7 : + cupsCMYKSetCurve(cmyk, 2, num_xypoints, xypoints); + break; + } + } + else if ((attr = cupsFindAttr(ppd, "cupsMagentaGamma", colormodel, media, + resolution, spec, sizeof(spec))) != NULL) + { + if (sscanf(attr->value, "%f%f", &gamval, &density) == 2) + switch (num_channels) + { + case 3 : + case 4 : + cupsCMYKSetGamma(cmyk, 1, gamval, density); + break; + case 6 : + case 7 : + cupsCMYKSetGamma(cmyk, 2, gamval, density); + break; + } + } + else if ((attr = cupsFindAttr(ppd, "cupsAllXY", colormodel, media, + resolution, spec, sizeof(spec))) != NULL) + { + for (num_xypoints = 0, xyptr = xypoints; + attr != NULL && attr->value != NULL && num_xypoints < 100; + attr = ppdFindNextAttr(ppd, "cupsAllXY", spec)) + if (sscanf(attr->value, "%f%f", xyptr, xyptr + 1) == 2) + { + num_xypoints ++; + xyptr += 2; + } + + switch (num_channels) + { + case 3 : + case 4 : + cupsCMYKSetCurve(cmyk, 1, num_xypoints, xypoints); + break; + case 6 : + case 7 : + cupsCMYKSetCurve(cmyk, 2, num_xypoints, xypoints); + break; + } + } + else if ((attr = cupsFindAttr(ppd, "cupsAllGamma", colormodel, media, + resolution, spec, sizeof(spec))) != NULL) + { + if (sscanf(attr->value, "%f%f", &gamval, &density) == 2) + switch (num_channels) + { + case 3 : + case 4 : + cupsCMYKSetGamma(cmyk, 1, gamval, density); + break; + case 6 : + case 7 : + cupsCMYKSetGamma(cmyk, 2, gamval, density); + break; + } + } + + /* + * Get the optional cupsYellowXY or cupsYellowGamma attributes... + */ + + if ((attr = cupsFindAttr(ppd, "cupsYellowXY", colormodel, media, + resolution, spec, sizeof(spec))) != NULL) + { + for (num_xypoints = 0, xyptr = xypoints; + attr != NULL && attr->value != NULL && num_xypoints < 100; + attr = ppdFindNextAttr(ppd, "cupsYellowXY", spec)) + if (sscanf(attr->value, "%f%f", xyptr, xyptr + 1) == 2) + { + num_xypoints ++; + xyptr += 2; + } + + switch (num_channels) + { + case 3 : + case 4 : + cupsCMYKSetCurve(cmyk, 2, num_xypoints, xypoints); + break; + case 6 : + case 7 : + cupsCMYKSetCurve(cmyk, 4, num_xypoints, xypoints); + break; + } + } + else if ((attr = cupsFindAttr(ppd, "cupsYellowGamma", colormodel, media, + resolution, spec, sizeof(spec))) != NULL) + { + if (sscanf(attr->value, "%f%f", &gamval, &density) == 2) + switch (num_channels) + { + case 3 : + case 4 : + cupsCMYKSetGamma(cmyk, 2, gamval, density); + break; + case 6 : + case 7 : + cupsCMYKSetGamma(cmyk, 4, gamval, density); + break; + } + } + else if ((attr = cupsFindAttr(ppd, "cupsAllXY", colormodel, media, + resolution, spec, sizeof(spec))) != NULL) + { + for (num_xypoints = 0, xyptr = xypoints; + attr != NULL && attr->value != NULL && num_xypoints < 100; + attr = ppdFindNextAttr(ppd, "cupsAllXY", spec)) + if (sscanf(attr->value, "%f%f", xyptr, xyptr + 1) == 2) + { + num_xypoints ++; + xyptr += 2; + } + + switch (num_channels) + { + case 3 : + case 4 : + cupsCMYKSetCurve(cmyk, 2, num_xypoints, xypoints); + break; + case 6 : + case 7 : + cupsCMYKSetCurve(cmyk, 4, num_xypoints, xypoints); + break; + } + } + else if ((attr = cupsFindAttr(ppd, "cupsAllGamma", colormodel, media, + resolution, spec, sizeof(spec))) != NULL) + { + if (sscanf(attr->value, "%f%f", &gamval, &density) == 2) + switch (num_channels) + { + case 3 : + case 4 : + cupsCMYKSetGamma(cmyk, 2, gamval, density); + break; + case 6 : + case 7 : + cupsCMYKSetGamma(cmyk, 4, gamval, density); + break; + } + } + } + + /* + * Get the optional cupsLightBlackXY, cupsLightBlackGamma, or + * cupsBlackLtDk attributes... + */ + + if (num_channels == 2 || num_channels == 7) + { + if ((attr = cupsFindAttr(ppd, "cupsLightBlackXY", colormodel, media, + resolution, spec, sizeof(spec))) != NULL) + { + for (num_xypoints = 0, xyptr = xypoints; + attr != NULL && attr->value != NULL && num_xypoints < 100; + attr = ppdFindNextAttr(ppd, "cupsLightBlackXY", spec)) + if (sscanf(attr->value, "%f%f", xyptr, xyptr + 1) == 2) + { + num_xypoints ++; + xyptr += 2; + } + + switch (num_channels) + { + case 2 : + cupsCMYKSetCurve(cmyk, 1, num_xypoints, xypoints); + break; + case 7 : + cupsCMYKSetCurve(cmyk, 6, num_xypoints, xypoints); + break; + } + } + else if ((attr = cupsFindAttr(ppd, "cupsLightBlackGamma", colormodel, + media, resolution, spec, + sizeof(spec))) != NULL) + { + if (sscanf(attr->value, "%f%f", &gamval, &density) == 2) + switch (num_channels) + { + case 2 : + cupsCMYKSetGamma(cmyk, 1, gamval, density); + break; + case 7 : + cupsCMYKSetGamma(cmyk, 6, gamval, density); + break; + } + } + else if ((attr = cupsFindAttr(ppd, "cupsBlackLtDk", colormodel, media, + resolution, spec, sizeof(spec))) != NULL) + { + if (sscanf(attr->value, "%f%f", &light, &dark) == 2) + switch (num_channels) + { + case 2 : + cupsCMYKSetLtDk(cmyk, 0, light, dark); + break; + case 7 : + cupsCMYKSetLtDk(cmyk, 5, light, dark); + break; + } + else + fprintf(stderr, "ERROR: Bad cupsBlackLtDk value \"%s\"!\n", + attr->value); + } + else + fprintf(stderr, "WARNING: No light black attribute found for %s!\n", + spec); + } + + if (num_channels >= 6) + { + /* + * Get the optional cupsLightCyanXY, cupsLightCyanGamma, or + * cupsCyanLtDk attributes... + */ + + if ((attr = cupsFindAttr(ppd, "cupsLightCyanXY", colormodel, media, + resolution, spec, sizeof(spec))) != NULL) + { + for (num_xypoints = 0, xyptr = xypoints; + attr != NULL && attr->value != NULL && num_xypoints < 100; + attr = ppdFindNextAttr(ppd, "cupsLightCyanXY", spec)) + if (sscanf(attr->value, "%f%f", xyptr, xyptr + 1) == 2) + { + num_xypoints ++; + xyptr += 2; + } + + cupsCMYKSetCurve(cmyk, 1, num_xypoints, xypoints); + } + else if ((attr = cupsFindAttr(ppd, "cupsLightCyanGamma", colormodel, + media, resolution, spec, + sizeof(spec))) != NULL) + { + if (sscanf(attr->value, "%f%f", &gamval, &density) == 2) + cupsCMYKSetGamma(cmyk, 1, gamval, density); + } + else if ((attr = cupsFindAttr(ppd, "cupsCyanLtDk", colormodel, media, + resolution, spec, sizeof(spec))) != NULL) + { + if (sscanf(attr->value, "%f%f", &light, &dark) == 2) + cupsCMYKSetLtDk(cmyk, 0, light, dark); + else + fprintf(stderr, "ERROR: Bad cupsCyanLtDk value \"%s\"!\n", + attr->value); + } + else + fprintf(stderr, "WARNING: No light cyan attribute found for %s!\n", + spec); + + /* + * Get the optional cupsLightMagentaXY, cupsLightMagentaGamma, or + * cupsMagentaLtDk attributes... + */ + + if ((attr = cupsFindAttr(ppd, "cupsLightMagentaXY", colormodel, media, + resolution, spec, sizeof(spec))) != NULL) + { + for (num_xypoints = 0, xyptr = xypoints; + attr != NULL && attr->value != NULL && num_xypoints < 100; + attr = ppdFindNextAttr(ppd, "cupsLightMagentaXY", spec)) + if (sscanf(attr->value, "%f%f", xyptr, xyptr + 1) == 2) + { + num_xypoints ++; + xyptr += 2; + } + + cupsCMYKSetCurve(cmyk, 3, num_xypoints, xypoints); + } + else if ((attr = cupsFindAttr(ppd, "cupsLightMagentaGamma", colormodel, + media, resolution, spec, + sizeof(spec))) != NULL) + { + if (sscanf(attr->value, "%f%f", &gamval, &density) == 2) + cupsCMYKSetGamma(cmyk, 3, gamval, density); + } + else if ((attr = cupsFindAttr(ppd, "cupsMagentaLtDk", colormodel, media, + resolution, spec, sizeof(spec))) != NULL) + { + if (sscanf(attr->value, "%f%f", &light, &dark) == 2) + cupsCMYKSetLtDk(cmyk, 2, light, dark); + else + fprintf(stderr, "ERROR: Bad cupsMagentaLtDk value \"%s\"!\n", + attr->value); + } + else + fprintf(stderr, "WARNING: No light magenta attribute found for %s!\n", + spec); + } + + /* + * Return the new profile... + */ + + return (cmyk); +} + + +/* + * 'cupsCMYKNew()' - Create a new CMYK color separation. + */ + +cups_cmyk_t * /* O - New CMYK separation or NULL */ +cupsCMYKNew(int num_channels) /* I - Number of color components */ +{ + cups_cmyk_t *cmyk; /* New color separation */ + int i; /* Looping var */ + + + /* + * Range-check the input... + */ + + if (num_channels < 1) + return (NULL); + + /* + * Allocate memory for the separation... + */ + + if ((cmyk = calloc(1, sizeof(cups_cmyk_t))) == NULL) + return (NULL); + + /* + * Allocate memory for the LUTs... + */ + + cmyk->num_channels = num_channels; + + if ((cmyk->channels[0] = calloc(num_channels * 256, sizeof(short))) == NULL) + { + free(cmyk); + return (NULL); + } + + for (i = 1; i < num_channels; i ++) + cmyk->channels[i] = cmyk->channels[0] + i * 256; + + /* + * Fill in the LUTs with unity transitions... + */ + + for (i = 0; i < 256; i ++) + cmyk->black_lut[i] = i; + + switch (num_channels) + { + case 1 : /* K */ + case 2 : /* Kk */ + for (i = 0; i < 256; i ++) + { + cmyk->channels[0][i] = CUPS_MAX_LUT * i / 255; + } + break; + case 3 : /* CMY */ + for (i = 0; i < 256; i ++) + { + cmyk->channels[0][i] = CUPS_MAX_LUT * i / 255; + cmyk->channels[1][i] = CUPS_MAX_LUT * i / 255; + cmyk->channels[2][i] = CUPS_MAX_LUT * i / 255; + } + break; + case 4 : /* CMYK */ + for (i = 0; i < 256; i ++) + { + cmyk->channels[0][i] = CUPS_MAX_LUT * i / 255; + cmyk->channels[1][i] = CUPS_MAX_LUT * i / 255; + cmyk->channels[2][i] = CUPS_MAX_LUT * i / 255; + cmyk->channels[3][i] = CUPS_MAX_LUT * i / 255; + } + break; + case 6 : /* CcMmYK */ + case 7 : /* CcMmYKk */ + for (i = 0; i < 256; i ++) + { + cmyk->channels[0][i] = CUPS_MAX_LUT * i / 255; + cmyk->channels[2][i] = CUPS_MAX_LUT * i / 255; + cmyk->channels[4][i] = CUPS_MAX_LUT * i / 255; + cmyk->channels[5][i] = CUPS_MAX_LUT * i / 255; + } + break; + } + + /* + * Return the separation... + */ + + return (cmyk); +} + + +/* + * 'cupsCMYKSetBlack()' - Set the transition range for CMY to black. + */ + +void +cupsCMYKSetBlack(cups_cmyk_t *cmyk, /* I - CMYK color separation */ + float lower, /* I - No black ink */ + float upper) /* I - Only black ink */ +{ + int i, /* Looping var */ + delta, /* Difference between lower and upper */ + ilower, /* Lower level from 0 to 255 */ + iupper; /* Upper level from 0 to 255 */ + + + /* + * Range check input... + */ + + if (cmyk == NULL || lower < 0.0 || lower > 1.0 || upper < 0.0 || upper > 1.0 || + lower > upper) + return; + + /* + * Convert lower and upper to integers from 0 to 255... + */ + + ilower = (int)(255.0 * lower + 0.5); + iupper = (int)(255.0 * upper + 0.5); + delta = iupper - ilower; + + /* + * Generate the CMY-only data... + */ + + for (i = 0; i < ilower; i ++) + { + cmyk->black_lut[i] = 0; + cmyk->color_lut[i] = i; + } + + /* + * Then the transition data... + */ + + for (; i < iupper; i ++) + { + cmyk->black_lut[i] = iupper * (i - ilower) / delta; + cmyk->color_lut[i] = ilower - ilower * (i - ilower) / delta; + } + + /* + * Then the K-only data... + */ + + for (; i < 256; i ++) + { + cmyk->black_lut[i] = i; + cmyk->color_lut[i] = 0; + } + + fprintf(stderr, "DEBUG: cupsCMYKSetBlack(cmyk, lower=%.3f, upper=%.3f)\n", lower, upper); + + for (i = 0; i < 256; i += 17) + fprintf(stderr, "DEBUG: %3d = %3dk + %3dc\n", i, + cmyk->black_lut[i], cmyk->color_lut[i]); +} + + +/* + * 'cupsCMYKSetCurve()' - Set a color transform curve using points. + */ + +void +cupsCMYKSetCurve(cups_cmyk_t *cmyk, /* I - CMYK color separation */ + int channel, /* I - Color channel */ + int num_xypoints, + /* I - Number of X,Y points */ + const float *xypoints) /* I - X,Y points */ +{ + int i; /* Looping var */ + int xstart; /* Start position */ + int xend; /* End position */ + int xdelta; /* Difference in position */ + int ystart; /* Start value */ + int yend; /* End value */ + int ydelta; /* Difference in value */ + + + /* + * Range check input... + */ + + if (cmyk == NULL || channel < 0 || channel >= cmyk->num_channels || + num_xypoints < 1 || xypoints == NULL) + return; + + /* + * Initialize the lookup table for the specified channel... + */ + + for (xstart = xend = 0, ystart = yend = 0; + num_xypoints > 0; + num_xypoints --, xypoints += 2, xstart = xend, ystart = yend) + { + xend = (int)(255.0 * xypoints[1] + 0.5); + yend = (int)(CUPS_MAX_LUT * xypoints[0] + 0.5); + xdelta = xend - xstart; + ydelta = yend - ystart; + + for (i = xstart; i < xend; i ++) + cmyk->channels[channel][i] = ystart + ydelta * (i - xstart) / xdelta; + } + + /* + * Initialize any trailing values to the maximum of the last data point... + */ + + for (i = xend; i < 256; i ++) + cmyk->channels[channel][i] = yend; + + fprintf(stderr, "DEBUG: cupsCMYKSetXY(cmyk, channel=%d, num_xypoints=%d, " + "xypoints=[%.3f %.3f %.3f %.3f ...])\n", channel, + num_xypoints, xypoints[0], xypoints[1], xypoints[2], xypoints[3]); + + for (i = 0; i < 256; i += 17) + fprintf(stderr, "DEBUG: %3d = %4d\n", i, + cmyk->channels[channel + 0][i]); +} + + +/* + * 'cupsCMYKSetGamma()' - Set a color transform curve using gamma and density. + */ + +void +cupsCMYKSetGamma(cups_cmyk_t *cmyk, /* I - CMYK color separation */ + int channel, /* I - Ink channel */ + float gamval, /* I - Gamma correction */ + float density) /* I - Maximum density */ +{ + int i; /* Looping var */ + + + /* + * Range check input... + */ + + if (cmyk == NULL || channel < 0 || channel >= cmyk->num_channels || + gamval <= 0.0 || density <= 0.0 || density > 1.0) + return; + + /* + * Initialize the lookup table for the specified channel... + */ + + for (i = 0; i < 256; i ++) + cmyk->channels[channel][i] = (int)(density * CUPS_MAX_LUT * + pow((float)i / 255.0, gamval) + 0.5); + + fprintf(stderr, "DEBUG: cupsCMYKSetGamma(cmyk, channel=%d, gamval=%.3f, " + "density=%.3f)\n", channel, gamval, density); + + for (i = 0; i < 256; i += 17) + fprintf(stderr, "DEBUG: %3d = %4d\n", i, + cmyk->channels[channel + 0][i]); +} + + +/* + * 'cupsCMYKSetInkLimit()' - Set the limit on the amount of ink. + */ + +void +cupsCMYKSetInkLimit(cups_cmyk_t *cmyk, /* I - CMYK color separation */ + float limit) /* I - Limit of ink */ +{ + if (!cmyk || limit < 0.0) + return; + + cmyk->ink_limit = limit * CUPS_MAX_LUT; +} + + +/* + * 'cupsCMYKSetLtDk()' - Set light/dark ink transforms. + */ + +void +cupsCMYKSetLtDk(cups_cmyk_t *cmyk, /* I - CMYK color separation */ + int channel, /* I - Dark ink channel (+1 for light) */ + float light, /* I - Light ink only level */ + float dark) /* I - Dark ink only level */ +{ + int i, /* Looping var */ + delta, /* Difference between lower and upper */ + ilight, /* Light level from 0 to 255 */ + idark; /* Dark level from 0 to 255 */ + short lut[256]; /* Original LUT data */ + + + /* + * Range check input... + */ + + if (cmyk == NULL || light < 0.0 || light > 1.0 || dark < 0.0 || dark > 1.0 || + light > dark || channel < 0 || channel > (cmyk->num_channels - 2)) + return; + + /* + * Convert lower and upper to integers from 0 to 255... + */ + + ilight = (int)(255.0 * light + 0.5); + idark = (int)(255.0 * dark + 0.5); + delta = idark - ilight; + + /* + * Copy the dark ink LUT... + */ + + memcpy(lut, cmyk->channels[channel], sizeof(lut)); + + /* + * Generate the light-only data... + */ + + for (i = 0; i < ilight; i ++) + { + cmyk->channels[channel + 0][i] = 0; + cmyk->channels[channel + 1][i] = CUPS_MAX_LUT * i / ilight; + } + + /* + * Then the transition data... + */ + + for (; i < idark; i ++) + { + cmyk->channels[channel + 0][i] = CUPS_MAX_LUT * idark * (i - ilight) / + delta / 255; + cmyk->channels[channel + 1][i] = CUPS_MAX_LUT - CUPS_MAX_LUT * + (i - ilight) / delta; + } + + /* + * Then the K-only data... + */ + + for (; i < 256; i ++) + { + cmyk->channels[channel + 0][i] = CUPS_MAX_LUT * i / 255; + cmyk->channels[channel + 1][i] = 0; + } + + fprintf(stderr, "DEBUG: cupsCMYKSetLtDk(cmyk, channel=%d, light=%.3f, " + "dark=%.3f)\n", channel, light, dark); + + for (i = 0; i < 256; i += 17) + fprintf(stderr, "DEBUG: %3d = %4dlt + %4ddk\n", i, + cmyk->channels[channel + 0][i], cmyk->channels[channel + 1][i]); +} + + +/* + * End of "$Id: cmyk.c 9042 2010-03-24 00:45:34Z mike $". + */ |