#include "driver.h"
#include <cups/string.h>
void
cupsCMYKDelete(cups_cmyk_t *cmyk)
{
if (cmyk == NULL)
return;
free(cmyk->channels[0]);
free(cmyk);
}
void
cupsCMYKDoBlack(const cups_cmyk_t *cmyk,
const unsigned char *input,
short *output,
int num_pixels)
{
int k;
const short **channels;
int ink,
ink_limit;
if (cmyk == NULL || input == NULL || output == NULL || num_pixels <= 0)
return;
channels = (const short **)cmyk->channels;
ink_limit = cmyk->ink_limit;
switch (cmyk->num_channels)
{
case 1 :
while (num_pixels > 0)
{
k = *input++;
*output++ = channels[0][k];
num_pixels --;
}
break;
case 2 :
while (num_pixels > 0)
{
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 :
while (num_pixels > 0)
{
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 :
while (num_pixels > 0)
{
k = *input++;
*output++ = 0;
*output++ = 0;
*output++ = 0;
*output++ = channels[3][k];
num_pixels --;
}
break;
case 6 :
while (num_pixels > 0)
{
k = *input++;
*output++ = 0;
*output++ = 0;
*output++ = 0;
*output++ = 0;
*output++ = 0;
*output++ = channels[5][k];
num_pixels --;
}
break;
case 7 :
while (num_pixels > 0)
{
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;
}
}
void
cupsCMYKDoCMYK(const cups_cmyk_t *cmyk,
const unsigned char *input,
short *output,
int num_pixels)
{
int c,
m,
y,
k;
const short **channels;
int ink,
ink_limit;
if (cmyk == NULL || input == NULL || output == NULL || num_pixels <= 0)
return;
channels = (const short **)cmyk->channels;
ink_limit = cmyk->ink_limit;
switch (cmyk->num_channels)
{
case 1 :
while (num_pixels > 0)
{
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 :
while (num_pixels > 0)
{
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 :
while (num_pixels > 0)
{
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 :
while (num_pixels > 0)
{
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 :
while (num_pixels > 0)
{
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 :
while (num_pixels > 0)
{
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;
}
}
void
cupsCMYKDoGray(const cups_cmyk_t *cmyk,
const unsigned char *input,
short *output,
int num_pixels)
{
int k,
kc;
const short **channels;
int ink,
ink_limit;
if (cmyk == NULL || input == NULL || output == NULL || num_pixels <= 0)
return;
channels = (const short **)cmyk->channels;
ink_limit = cmyk->ink_limit;
switch (cmyk->num_channels)
{
case 1 :
while (num_pixels > 0)
{
k = cups_scmy_lut[*input++];
*output++ = channels[0][k];
num_pixels --;
}
break;
case 2 :
while (num_pixels > 0)
{
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 :
while (num_pixels > 0)
{
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 :
while (num_pixels > 0)
{
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 :
while (num_pixels > 0)
{
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 :
while (num_pixels > 0)
{
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;
}
}
void
cupsCMYKDoRGB(const cups_cmyk_t *cmyk,
const unsigned char *input,
short *output,
int num_pixels)
{
int c,
m,
y,
k,
kc,
km;
const short **channels;
int ink,
ink_limit;
if (cmyk == NULL || input == NULL || output == NULL || num_pixels <= 0)
return;
channels = (const short **)cmyk->channels;
ink_limit = cmyk->ink_limit;
switch (cmyk->num_channels)
{
case 1 :
while (num_pixels > 0)
{
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 :
while (num_pixels > 0)
{
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 :
while (num_pixels > 0)
{
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 :
while (num_pixels > 0)
{
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 :
while (num_pixels > 0)
{
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 :
while (num_pixels > 0)
{
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;
}
}
cups_cmyk_t *
cupsCMYKLoad(ppd_file_t *ppd,
const char *colormodel,
const char *media,
const char *resolution)
{
cups_cmyk_t *cmyk;
char spec[PPD_MAX_NAME];
ppd_attr_t *attr;
int num_channels;
float gamval,
density,
light,
dark,
lower,
upper;
int num_xypoints;
float xypoints[100 * 2],
*xyptr;
if (ppd == NULL || colormodel == NULL || resolution == NULL || media == NULL)
return (NULL);
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);
if ((attr = cupsFindAttr(ppd, "cupsInkLimit", colormodel, media,
resolution, spec, sizeof(spec))) != NULL)
cupsCMYKSetInkLimit(cmyk, atof(attr->value));
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);
}
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)
{
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);
}
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;
}
}
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;
}
}
}
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)
{
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);
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 (cmyk);
}
cups_cmyk_t *
cupsCMYKNew(int num_channels)
{
cups_cmyk_t *cmyk;
int i;
if (num_channels < 1)
return (NULL);
if ((cmyk = calloc(1, sizeof(cups_cmyk_t))) == NULL)
return (NULL);
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;
for (i = 0; i < 256; i ++)
cmyk->black_lut[i] = i;
switch (num_channels)
{
case 1 :
case 2 :
for (i = 0; i < 256; i ++)
{
cmyk->channels[0][i] = CUPS_MAX_LUT * i / 255;
}
break;
case 3 :
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 :
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 :
case 7 :
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 (cmyk);
}
void
cupsCMYKSetBlack(cups_cmyk_t *cmyk,
float lower,
float upper)
{
int i,
delta,
ilower,
iupper;
if (cmyk == NULL || lower < 0.0 || lower > 1.0 || upper < 0.0 || upper > 1.0 ||
lower > upper)
return;
ilower = (int)(255.0 * lower + 0.5);
iupper = (int)(255.0 * upper + 0.5);
delta = iupper - ilower;
for (i = 0; i < ilower; i ++)
{
cmyk->black_lut[i] = 0;
cmyk->color_lut[i] = i;
}
for (; i < iupper; i ++)
{
cmyk->black_lut[i] = iupper * (i - ilower) / delta;
cmyk->color_lut[i] = ilower - ilower * (i - ilower) / delta;
}
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]);
}
void
cupsCMYKSetCurve(cups_cmyk_t *cmyk,
int channel,
int num_xypoints,
const float *xypoints)
{
int i;
int xstart;
int xend;
int xdelta;
int ystart;
int yend;
int ydelta;
if (cmyk == NULL || channel < 0 || channel >= cmyk->num_channels ||
num_xypoints < 1 || xypoints == NULL)
return;
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;
}
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]);
}
void
cupsCMYKSetGamma(cups_cmyk_t *cmyk,
int channel,
float gamval,
float density)
{
int i;
if (cmyk == NULL || channel < 0 || channel >= cmyk->num_channels ||
gamval <= 0.0 || density <= 0.0 || density > 1.0)
return;
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]);
}
void
cupsCMYKSetInkLimit(cups_cmyk_t *cmyk,
float limit)
{
if (!cmyk || limit < 0.0)
return;
cmyk->ink_limit = limit * CUPS_MAX_LUT;
}
void
cupsCMYKSetLtDk(cups_cmyk_t *cmyk,
int channel,
float light,
float dark)
{
int i,
delta,
ilight,
idark;
short lut[256];
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;
ilight = (int)(255.0 * light + 0.5);
idark = (int)(255.0 * dark + 0.5);
delta = idark - ilight;
memcpy(lut, cmyk->channels[channel], sizeof(lut));
for (i = 0; i < ilight; i ++)
{
cmyk->channels[channel + 0][i] = 0;
cmyk->channels[channel + 1][i] = CUPS_MAX_LUT * i / ilight;
}
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;
}
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]);
}