#include "driver.h"
#include <cups/language-private.h>
#include <cups/string-private.h>
#include "pcl-common.h"
#include <signal.h>
typedef enum
{
OUTPUT_BITMAP,
OUTPUT_INVERBIT,
OUTPUT_RGB,
OUTPUT_DITHERED
} pcl_output_t;
cups_rgb_t *RGB;
cups_cmyk_t *CMYK;
unsigned char *PixelBuffer,
*CMYKBuffer,
*OutputBuffers[6],
*DotBuffers[6],
*CompBuffer,
*SeedBuffer,
BlankValue;
short *InputBuffer;
cups_lut_t *DitherLuts[6];
cups_dither_t *DitherStates[6];
int PrinterPlanes,
SeedInvalid,
DotBits[6],
DotBufferSizes[6],
DotBufferSize,
OutputFeed,
Page;
pcl_output_t OutputMode;
const int ColorOrders[7][7] =
{
{ 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0 },
{ 0, 1, 2, 0, 0, 0, 0 },
{ 3, 0, 1, 2, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0 },
{ 5, 0, 1, 2, 3, 4, 0 },
{ 5, 0, 1, 2, 3, 4, 6 }
};
int Canceled;
void StartPage(ppd_file_t *ppd, cups_page_header2_t *header, int job_id,
const char *user, const char *title, int num_options,
cups_option_t *options);
void EndPage(ppd_file_t *ppd, cups_page_header2_t *header);
void Shutdown(ppd_file_t *ppd, int job_id, const char *user,
const char *title, int num_options, cups_option_t *options);
void CancelJob(int sig);
void CompressData(unsigned char *line, int length, int plane, int pend,
int type);
void OutputLine(ppd_file_t *ppd, cups_page_header2_t *header);
int ReadLine(cups_raster_t *ras, cups_page_header2_t *header);
void
StartPage(ppd_file_t *ppd,
cups_page_header2_t *header,
int job_id,
const char *user,
const char *title,
int num_options,
cups_option_t *options)
{
int i;
int plane;
char s[255];
const char *colormodel;
char resolution[PPD_MAX_NAME],
spec[PPD_MAX_NAME];
ppd_attr_t *attr;
ppd_choice_t *choice;
const int *order;
int xorigin,
yorigin;
static const float default_lut[2] =
{
0.0,
1.0
};
fprintf(stderr, "DEBUG: StartPage...\n");
fprintf(stderr, "DEBUG: MediaClass = \"%s\"\n", header->MediaClass);
fprintf(stderr, "DEBUG: MediaColor = \"%s\"\n", header->MediaColor);
fprintf(stderr, "DEBUG: MediaType = \"%s\"\n", header->MediaType);
fprintf(stderr, "DEBUG: OutputType = \"%s\"\n", header->OutputType);
fprintf(stderr, "DEBUG: AdvanceDistance = %d\n", header->AdvanceDistance);
fprintf(stderr, "DEBUG: AdvanceMedia = %d\n", header->AdvanceMedia);
fprintf(stderr, "DEBUG: Collate = %d\n", header->Collate);
fprintf(stderr, "DEBUG: CutMedia = %d\n", header->CutMedia);
fprintf(stderr, "DEBUG: Duplex = %d\n", header->Duplex);
fprintf(stderr, "DEBUG: HWResolution = [ %d %d ]\n", header->HWResolution[0],
header->HWResolution[1]);
fprintf(stderr, "DEBUG: ImagingBoundingBox = [ %d %d %d %d ]\n",
header->ImagingBoundingBox[0], header->ImagingBoundingBox[1],
header->ImagingBoundingBox[2], header->ImagingBoundingBox[3]);
fprintf(stderr, "DEBUG: InsertSheet = %d\n", header->InsertSheet);
fprintf(stderr, "DEBUG: Jog = %d\n", header->Jog);
fprintf(stderr, "DEBUG: LeadingEdge = %d\n", header->LeadingEdge);
fprintf(stderr, "DEBUG: Margins = [ %d %d ]\n", header->Margins[0],
header->Margins[1]);
fprintf(stderr, "DEBUG: ManualFeed = %d\n", header->ManualFeed);
fprintf(stderr, "DEBUG: MediaPosition = %d\n", header->MediaPosition);
fprintf(stderr, "DEBUG: MediaWeight = %d\n", header->MediaWeight);
fprintf(stderr, "DEBUG: MirrorPrint = %d\n", header->MirrorPrint);
fprintf(stderr, "DEBUG: NegativePrint = %d\n", header->NegativePrint);
fprintf(stderr, "DEBUG: NumCopies = %d\n", header->NumCopies);
fprintf(stderr, "DEBUG: Orientation = %d\n", header->Orientation);
fprintf(stderr, "DEBUG: OutputFaceUp = %d\n", header->OutputFaceUp);
fprintf(stderr, "DEBUG: PageSize = [ %d %d ]\n", header->PageSize[0],
header->PageSize[1]);
fprintf(stderr, "DEBUG: Separations = %d\n", header->Separations);
fprintf(stderr, "DEBUG: TraySwitch = %d\n", header->TraySwitch);
fprintf(stderr, "DEBUG: Tumble = %d\n", header->Tumble);
fprintf(stderr, "DEBUG: cupsWidth = %d\n", header->cupsWidth);
fprintf(stderr, "DEBUG: cupsHeight = %d\n", header->cupsHeight);
fprintf(stderr, "DEBUG: cupsMediaType = %d\n", header->cupsMediaType);
fprintf(stderr, "DEBUG: cupsBitsPerColor = %d\n", header->cupsBitsPerColor);
fprintf(stderr, "DEBUG: cupsBitsPerPixel = %d\n", header->cupsBitsPerPixel);
fprintf(stderr, "DEBUG: cupsBytesPerLine = %d\n", header->cupsBytesPerLine);
fprintf(stderr, "DEBUG: cupsColorOrder = %d\n", header->cupsColorOrder);
fprintf(stderr, "DEBUG: cupsColorSpace = %d\n", header->cupsColorSpace);
fprintf(stderr, "DEBUG: cupsCompression = %d\n", header->cupsCompression);
#ifdef __APPLE__
if (ppdIsMarked(ppd, "Duplex", "DuplexNoTumble"))
{
header->Duplex = CUPS_TRUE;
header->Tumble = CUPS_FALSE;
}
else if (ppdIsMarked(ppd, "Duplex", "DuplexTumble"))
{
header->Duplex = CUPS_TRUE;
header->Tumble = CUPS_TRUE;
}
fprintf(stderr, "DEBUG: num_options=%d\n", num_options);
for (i = 0; i < num_options; i ++)
fprintf(stderr, "DEBUG: options[%d]=[\"%s\" \"%s\"]\n", i,
options[i].name, options[i].value);
#endif
switch (header->cupsColorSpace)
{
case CUPS_CSPACE_K :
colormodel = "Black";
break;
case CUPS_CSPACE_W :
colormodel = "Gray";
break;
default :
case CUPS_CSPACE_RGB :
colormodel = "RGB";
break;
case CUPS_CSPACE_CMY :
colormodel = "CMY";
break;
case CUPS_CSPACE_CMYK :
colormodel = "CMYK";
break;
}
if (header->HWResolution[0] != header->HWResolution[1])
snprintf(resolution, sizeof(resolution), "%dx%ddpi",
header->HWResolution[0], header->HWResolution[1]);
else
snprintf(resolution, sizeof(resolution), "%ddpi",
header->HWResolution[0]);
if (!header->MediaType[0])
strcpy(header->MediaType, "PLAIN");
BlankValue = 0x00;
if (header->cupsBitsPerColor == 1)
{
switch (header->cupsColorSpace)
{
case CUPS_CSPACE_K :
OutputMode = OUTPUT_BITMAP;
PrinterPlanes = 1;
break;
case CUPS_CSPACE_W :
OutputMode = OUTPUT_INVERBIT;
PrinterPlanes = 1;
break;
default :
case CUPS_CSPACE_RGB :
OutputMode = OUTPUT_INVERBIT;
PrinterPlanes = 3;
break;
case CUPS_CSPACE_CMY :
OutputMode = OUTPUT_BITMAP;
PrinterPlanes = 3;
break;
case CUPS_CSPACE_CMYK :
OutputMode = OUTPUT_BITMAP;
PrinterPlanes = 4;
break;
}
if (OutputMode == OUTPUT_INVERBIT)
BlankValue = 0xff;
DotBufferSize = header->cupsBytesPerLine;
memset(DitherLuts, 0, sizeof(DitherLuts));
memset(DitherStates, 0, sizeof(DitherStates));
}
else if (header->cupsColorSpace == CUPS_CSPACE_RGB &&
(ppd->model_number & PCL_RASTER_RGB24))
{
OutputMode = OUTPUT_RGB;
PrinterPlanes = 3;
DotBufferSize = header->cupsBytesPerLine;
if (header->cupsCompression == 10)
BlankValue = 0xff;
memset(DitherLuts, 0, sizeof(DitherLuts));
memset(DitherStates, 0, sizeof(DitherStates));
}
else if ((header->cupsColorSpace == CUPS_CSPACE_K ||
header->cupsColorSpace == CUPS_CSPACE_W) &&
(ppd->model_number & PCL_RASTER_RGB24) &&
header->cupsCompression == 10)
{
OutputMode = OUTPUT_RGB;
PrinterPlanes = 1;
DotBufferSize = header->cupsBytesPerLine;
if (header->cupsColorSpace == CUPS_CSPACE_W)
BlankValue = 0xff;
memset(DitherLuts, 0, sizeof(DitherLuts));
memset(DitherStates, 0, sizeof(DitherStates));
}
else
{
OutputMode = OUTPUT_DITHERED;
RGB = NULL;
CMYK = NULL;
fputs("DEBUG: Attempting to load color profiles using the following values:\n", stderr);
fprintf(stderr, "DEBUG: ColorModel = %s\n", colormodel);
fprintf(stderr, "DEBUG: MediaType = %s\n", header->MediaType);
fprintf(stderr, "DEBUG: Resolution = %s\n", resolution);
if (header->cupsColorSpace == CUPS_CSPACE_RGB ||
header->cupsColorSpace == CUPS_CSPACE_W)
RGB = cupsRGBLoad(ppd, colormodel, header->MediaType, resolution);
CMYK = cupsCMYKLoad(ppd, colormodel, header->MediaType, resolution);
if (RGB)
fputs("DEBUG: Loaded RGB separation from PPD.\n", stderr);
if (CMYK)
fputs("DEBUG: Loaded CMYK separation from PPD.\n", stderr);
else
{
fputs("DEBUG: Loading default K separation.\n", stderr);
CMYK = cupsCMYKNew(1);
}
PrinterPlanes = CMYK->num_channels;
switch (PrinterPlanes)
{
case 1 :
DitherLuts[0] = cupsLutLoad(ppd, colormodel, header->MediaType,
resolution, "Black");
break;
case 3 :
DitherLuts[0] = cupsLutLoad(ppd, colormodel, header->MediaType,
resolution, "Cyan");
DitherLuts[1] = cupsLutLoad(ppd, colormodel, header->MediaType,
resolution, "Magenta");
DitherLuts[2] = cupsLutLoad(ppd, colormodel, header->MediaType,
resolution, "Yellow");
break;
case 4 :
DitherLuts[0] = cupsLutLoad(ppd, colormodel, header->MediaType,
resolution, "Cyan");
DitherLuts[1] = cupsLutLoad(ppd, colormodel, header->MediaType,
resolution, "Magenta");
DitherLuts[2] = cupsLutLoad(ppd, colormodel, header->MediaType,
resolution, "Yellow");
DitherLuts[3] = cupsLutLoad(ppd, colormodel, header->MediaType,
resolution, "Black");
break;
case 6 :
DitherLuts[0] = cupsLutLoad(ppd, colormodel, header->MediaType,
resolution, "Cyan");
DitherLuts[1] = cupsLutLoad(ppd, colormodel, header->MediaType,
resolution, "LightCyan");
DitherLuts[2] = cupsLutLoad(ppd, colormodel, header->MediaType,
resolution, "Magenta");
DitherLuts[3] = cupsLutLoad(ppd, colormodel, header->MediaType,
resolution, "LightMagenta");
DitherLuts[4] = cupsLutLoad(ppd, colormodel, header->MediaType,
resolution, "Yellow");
DitherLuts[5] = cupsLutLoad(ppd, colormodel, header->MediaType,
resolution, "Black");
break;
}
for (plane = 0; plane < PrinterPlanes; plane ++)
{
if (!DitherLuts[plane])
DitherLuts[plane] = cupsLutNew(2, default_lut);
if (DitherLuts[plane][4095].pixel > 1)
DotBits[plane] = 2;
else
DotBits[plane] = 1;
DitherStates[plane] = cupsDitherNew(header->cupsWidth);
if (!DitherLuts[plane])
DitherLuts[plane] = cupsLutNew(2, default_lut);
}
}
fprintf(stderr, "DEBUG: PrinterPlanes = %d\n", PrinterPlanes);
if ((attr = ppdFindAttr(ppd, "cupsInitialNulls", NULL)) != NULL)
for (i = atoi(attr->value); i > 0; i --)
putchar(0);
if (Page == 1 && (ppd->model_number & PCL_PJL))
{
pjl_escape();
pjl_set_job(job_id, user, title);
if ((attr = ppdFindAttr(ppd, "cupsPJL", "StartJob")) != NULL)
pjl_write(ppd, attr->value, NULL, job_id, user, title, num_options,
options);
snprintf(spec, sizeof(spec), "RENDERMODE.%s", colormodel);
if ((attr = ppdFindAttr(ppd, "cupsPJL", spec)) != NULL)
printf("@PJL SET RENDERMODE=%s\r\n", attr->value);
snprintf(spec, sizeof(spec), "COLORSPACE.%s", colormodel);
if ((attr = ppdFindAttr(ppd, "cupsPJL", spec)) != NULL)
printf("@PJL SET COLORSPACE=%s\r\n", attr->value);
snprintf(spec, sizeof(spec), "RENDERINTENT.%s", colormodel);
if ((attr = ppdFindAttr(ppd, "cupsPJL", spec)) != NULL)
printf("@PJL SET RENDERINTENT=%s\r\n", attr->value);
if ((attr = ppdFindAttr(ppd, "cupsPJL", "Duplex")) != NULL)
{
sprintf(s, "%d", header->Duplex);
pjl_write(ppd, attr->value, s, job_id, user, title, num_options, options);
}
if ((attr = ppdFindAttr(ppd, "cupsPJL", "Tumble")) != NULL)
{
sprintf(s, "%d", header->Tumble);
pjl_write(ppd, attr->value, s, job_id, user, title, num_options, options);
}
if ((attr = ppdFindAttr(ppd, "cupsPJL", "MediaClass")) != NULL)
pjl_write(ppd, attr->value, header->MediaClass, job_id, user, title,
num_options, options);
if ((attr = ppdFindAttr(ppd, "cupsPJL", "MediaColor")) != NULL)
pjl_write(ppd, attr->value, header->MediaColor, job_id, user, title,
num_options, options);
if ((attr = ppdFindAttr(ppd, "cupsPJL", "MediaType")) != NULL)
pjl_write(ppd, attr->value, header->MediaType, job_id, user, title,
num_options, options);
if ((attr = ppdFindAttr(ppd, "cupsPJL", "OutputType")) != NULL)
pjl_write(ppd, attr->value, header->OutputType, job_id, user, title,
num_options, options);
if ((attr = ppdFindAttr(ppd, "cupsPJL", "cupsBooklet")) != NULL &&
(choice = ppdFindMarkedChoice(ppd, "cupsBooklet")) != NULL)
pjl_write(ppd, attr->value, choice->choice, job_id, user, title,
num_options, options);
if ((attr = ppdFindAttr(ppd, "cupsPJL", "Jog")) != NULL)
{
sprintf(s, "%d", header->Jog);
pjl_write(ppd, attr->value, s, job_id, user, title, num_options, options);
}
if ((attr = ppdFindAttr(ppd, "cupsPJL", "cupsPunch")) != NULL &&
(choice = ppdFindMarkedChoice(ppd, "cupsPunch")) != NULL)
pjl_write(ppd, attr->value, choice->choice, job_id, user, title,
num_options, options);
if ((attr = ppdFindAttr(ppd, "cupsPJL", "cupsStaple")) != NULL &&
(choice = ppdFindMarkedChoice(ppd, "cupsStaple")) != NULL)
pjl_write(ppd, attr->value, choice->choice, job_id, user, title,
num_options, options);
if ((attr = ppdFindAttr(ppd, "cupsPJL", "cupsRET")) != NULL &&
(choice = ppdFindMarkedChoice(ppd, "cupsRET")) != NULL)
pjl_write(ppd, attr->value, choice->choice, job_id, user, title,
num_options, options);
if ((attr = ppdFindAttr(ppd, "cupsPJL", "cupsTonerSave")) != NULL &&
(choice = ppdFindMarkedChoice(ppd, "cupsTonerSave")) != NULL)
pjl_write(ppd, attr->value, choice->choice, job_id, user, title,
num_options, options);
if (ppd->model_number & PCL_PJL_PAPERWIDTH)
{
printf("@PJL SET PAPERLENGTH=%d\r\n", header->PageSize[1] * 10);
printf("@PJL SET PAPERWIDTH=%d\r\n", header->PageSize[0] * 10);
}
if (ppd->model_number & PCL_PJL_RESOLUTION)
printf("@PJL SET RESOLUTION=%d\r\n", header->HWResolution[0]);
if (ppd->model_number & PCL_PJL_HPGL2)
pjl_enter_language("HPGL2");
else if (ppd->model_number & PCL_PJL_PCL3GUI)
pjl_enter_language("PCL3GUI");
else
pjl_enter_language("PCL");
}
if (Page == 1)
{
pcl_reset();
}
if (ppd->model_number & PCL_PJL_HPGL2)
{
if (Page == 1)
{
printf("IN;");
printf("MG\"%d %s %s\";", job_id, user, title);
}
printf("BP5,0;");
printf("PS%.0f,%.0f;",
header->cupsHeight * 1016.0 / header->HWResolution[1],
header->cupsWidth * 1016.0 / header->HWResolution[0]);
printf("PU;");
printf("PA0,0");
printf("MT%d;", header->cupsMediaType);
if (header->CutMedia == CUPS_CUT_PAGE)
printf("EC;");
else
printf("EC0;");
pcl_set_pcl_mode(0);
pcl_set_negative_motion();
}
else
{
if (!header->Duplex || (Page & 1))
{
pcl_set_media_size(ppd, header->PageSize[0], header->PageSize[1]);
if (header->MediaPosition)
pcl_set_media_source(header->MediaPosition);
pcl_set_media_type(header->cupsMediaType);
if (ppdFindAttr(ppd, "cupsPJL", "Duplex") == NULL)
pcl_set_duplex(header->Duplex, header->Tumble);
if (!ppd->manual_copies)
pcl_set_copies(header->NumCopies);
if (ppdFindAttr(ppd, "cupsPJL", "Jog") == NULL && header->Jog)
printf("\033&l%dG", header->Jog);
}
else
{
printf("\033&a2G");
}
if (header->Duplex && (ppd->model_number & PCL_RASTER_CRD))
{
pcl_set_media_source(-2);
}
printf("\033&u%dD", header->HWResolution[0]);
printf("\033*p0Y\033*p0X");
}
if ((attr = cupsFindAttr(ppd, "cupsPCLQuality", colormodel,
header->MediaType, resolution, spec,
sizeof(spec))) != NULL)
{
if (ppd->model_number & PCL_PJL_HPGL2)
printf("QM%d", atoi(attr->value));
else
printf("\033*o%dM", atoi(attr->value));
}
if (ppd->model_number & PCL_RASTER_CRD)
{
if (OutputMode == OUTPUT_RGB)
{
if ((attr = cupsFindAttr(ppd, "cupsPCLCRDMode", colormodel,
header->MediaType, resolution, spec,
sizeof(spec))) != NULL)
i = atoi(attr->value);
else
i = 31;
printf("\033*g12W");
putchar(6);
putchar(i);
putchar(0x00);
putchar(0x01);
putchar(header->HWResolution[0] >> 8);
putchar(header->HWResolution[0]);
putchar(header->HWResolution[1] >> 8);
putchar(header->HWResolution[1]);
putchar(header->cupsCompression);
putchar(0x01);
putchar(0x20);
putchar(0x01);
}
else
{
printf("\033*g%dW", PrinterPlanes * 6 + 2);
putchar(2);
putchar(PrinterPlanes);
order = ColorOrders[PrinterPlanes - 1];
for (i = 0; i < PrinterPlanes; i ++)
{
plane = order[i];
putchar(header->HWResolution[0] >> 8);
putchar(header->HWResolution[0]);
putchar(header->HWResolution[1] >> 8);
putchar(header->HWResolution[1]);
putchar(0);
putchar(1 << DotBits[plane]);
}
}
}
else if ((ppd->model_number & PCL_RASTER_CID) && OutputMode == OUTPUT_RGB)
{
pcl_set_simple_resolution(header->HWResolution[0]);
cupsWritePrintData("\033*v6W\0\3\0\10\10\10", 11);
}
else
{
pcl_set_simple_resolution(header->HWResolution[0]);
if (PrinterPlanes == 3)
pcl_set_simple_cmy();
else if (PrinterPlanes == 4)
pcl_set_simple_kcmy();
}
if ((attr = ppdFindAttr(ppd, "cupsPCLOrigin", "X")) != NULL)
xorigin = atoi(attr->value);
else
xorigin = 0;
if ((attr = ppdFindAttr(ppd, "cupsPCLOrigin", "Y")) != NULL)
yorigin = atoi(attr->value);
else
yorigin = 120;
printf("\033&a%dH\033&a%dV", xorigin, yorigin);
printf("\033*r%dS", header->cupsWidth);
printf("\033*r%dT", header->cupsHeight);
printf("\033*r1A");
if (header->cupsCompression && header->cupsCompression != 10)
printf("\033*b%dM", header->cupsCompression);
OutputFeed = 0;
PixelBuffer = malloc(header->cupsBytesPerLine);
if (OutputMode == OUTPUT_DITHERED)
{
InputBuffer = malloc(header->cupsWidth * PrinterPlanes * 2);
OutputBuffers[0] = malloc(PrinterPlanes * header->cupsWidth);
for (i = 1; i < PrinterPlanes; i ++)
OutputBuffers[i] = OutputBuffers[0] + i * header->cupsWidth;
if (RGB)
CMYKBuffer = malloc(header->cupsWidth * PrinterPlanes);
for (plane = 0, DotBufferSize = 0; plane < PrinterPlanes; plane ++)
{
DotBufferSizes[plane] = (header->cupsWidth + 7) / 8 * DotBits[plane];
DotBufferSize += DotBufferSizes[plane];
}
DotBuffers[0] = malloc(DotBufferSize);
for (plane = 1; plane < PrinterPlanes; plane ++)
DotBuffers[plane] = DotBuffers[plane - 1] + DotBufferSizes[plane - 1];
}
if (header->cupsCompression)
CompBuffer = malloc(DotBufferSize * 4);
if (header->cupsCompression >= 3)
SeedBuffer = malloc(DotBufferSize);
SeedInvalid = 1;
fprintf(stderr, "BlankValue=%d\n", BlankValue);
}
void
EndPage(ppd_file_t *ppd,
cups_page_header2_t *header)
{
int plane;
if (ppd->model_number & PCL_RASTER_END_COLOR)
printf("\033*rC");
else
printf("\033*r0B");
if (ppd->model_number & PCL_PJL_HPGL2)
{
pcl_set_hpgl_mode(0);
printf("PG;");
}
else if (!(header->Duplex && (Page & 1)))
printf("\014");
free(PixelBuffer);
if (OutputMode == OUTPUT_DITHERED)
{
for (plane = 0; plane < PrinterPlanes; plane ++)
{
cupsDitherDelete(DitherStates[plane]);
cupsLutDelete(DitherLuts[plane]);
}
free(DotBuffers[0]);
free(InputBuffer);
free(OutputBuffers[0]);
cupsCMYKDelete(CMYK);
if (RGB)
{
cupsRGBDelete(RGB);
free(CMYKBuffer);
}
}
if (header->cupsCompression)
free(CompBuffer);
if (header->cupsCompression >= 3)
free(SeedBuffer);
}
void
Shutdown(ppd_file_t *ppd,
int job_id,
const char *user,
const char *title,
int num_options,
cups_option_t *options)
{
ppd_attr_t *attr;
if ((attr = ppdFindAttr(ppd, "cupsPCL", "EndJob")) != NULL)
{
putchar(0x1b);
printf(attr->value, Page);
}
else
{
pcl_reset();
}
if (ppd->model_number & PCL_PJL)
{
pjl_escape();
if ((attr = ppdFindAttr(ppd, "cupsPJL", "EndJob")) != NULL)
pjl_write(ppd, attr->value, NULL, job_id, user, title, num_options,
options);
else
printf("@PJL EOJ\r\n");
pjl_escape();
}
}
void
CancelJob(int sig)
{
(void)sig;
Canceled = 1;
}
void
CompressData(unsigned char *line,
int length,
int plane,
int pend,
int type)
{
unsigned char *line_ptr,
*line_end,
*comp_ptr,
*start,
*seed;
int count,
offset,
temp;
int r, g, b;
switch (type)
{
default :
line_ptr = line;
if (cupsCheckBytes(line, length))
line_end = line;
else
line_end = line + length;
break;
case 1 :
line_end = line + length;
for (line_ptr = line, comp_ptr = CompBuffer;
line_ptr < line_end;
comp_ptr += 2, line_ptr += count)
{
for (count = 1;
(line_ptr + count) < line_end &&
line_ptr[0] == line_ptr[count] &&
count < 256;
count ++);
comp_ptr[0] = count - 1;
comp_ptr[1] = line_ptr[0];
}
line_ptr = CompBuffer;
line_end = comp_ptr;
break;
case 2 :
line_ptr = line;
line_end = line + length;
comp_ptr = CompBuffer;
while (line_ptr < line_end)
{
if ((line_ptr + 1) >= line_end)
{
*comp_ptr++ = 0x00;
*comp_ptr++ = *line_ptr++;
}
else if (line_ptr[0] == line_ptr[1])
{
line_ptr ++;
count = 2;
while (line_ptr < (line_end - 1) &&
line_ptr[0] == line_ptr[1] &&
count < 127)
{
line_ptr ++;
count ++;
}
*comp_ptr++ = 257 - count;
*comp_ptr++ = *line_ptr++;
}
else
{
start = line_ptr;
line_ptr ++;
count = 1;
while (line_ptr < (line_end - 1) &&
line_ptr[0] != line_ptr[1] &&
count < 127)
{
line_ptr ++;
count ++;
}
*comp_ptr++ = count - 1;
memcpy(comp_ptr, start, count);
comp_ptr += count;
}
}
line_ptr = CompBuffer;
line_end = comp_ptr;
break;
case 3 :
line_ptr = line;
line_end = line + length;
comp_ptr = CompBuffer;
seed = SeedBuffer + plane * length;
while (line_ptr < line_end)
{
start = line_ptr;
if (SeedInvalid)
{
offset = 0;
if ((count = line_end - line_ptr) > 8)
count = 8;
line_ptr += count;
}
else
{
while (*line_ptr == *seed &&
line_ptr < line_end)
{
line_ptr ++;
seed ++;
}
if (line_ptr == line_end)
break;
offset = line_ptr - start;
start = line_ptr;
count = 0;
while (*line_ptr != *seed &&
line_ptr < line_end &&
count < 8)
{
line_ptr ++;
seed ++;
count ++;
}
}
if (offset >= 31)
{
*comp_ptr++ = ((count - 1) << 5) | 31;
offset -= 31;
while (offset >= 255)
{
*comp_ptr++ = 255;
offset -= 255;
}
*comp_ptr++ = offset;
}
else
{
*comp_ptr++ = ((count - 1) << 5) | offset;
}
memcpy(comp_ptr, start, count);
comp_ptr += count;
}
line_ptr = CompBuffer;
line_end = comp_ptr;
memcpy(SeedBuffer + plane * length, line, length);
break;
case 10 :
line_ptr = line;
line_end = line + length;
comp_ptr = CompBuffer;
seed = SeedBuffer;
if (PrinterPlanes == 1)
{
while (line_ptr < line_end)
{
start = line_ptr;
while (line_ptr < line_end &&
*line_ptr == *seed)
{
line_ptr ++;
seed ++;
}
if (line_ptr == line_end)
break;
offset = line_ptr - start;
start = line_ptr;
while (line_ptr < line_end &&
*line_ptr != *seed)
{
line_ptr ++;
seed ++;
}
count = line_ptr - start;
#if 0
fprintf(stderr, "DEBUG: offset=%d, count=%d, comp_ptr=%p(%d of %d)...\n",
offset, count, comp_ptr, comp_ptr - CompBuffer,
BytesPerLine * 5);
#endif
if (offset >= 3)
{
if (count > 7)
*comp_ptr++ = 0x1f;
else
*comp_ptr++ = 0x18 | (count - 1);
offset -= 3;
while (offset >= 255)
{
*comp_ptr++ = 255;
offset -= 255;
}
*comp_ptr++ = offset;
}
else
{
if (count > 7)
*comp_ptr++ = (offset << 3) | 0x07;
else
*comp_ptr++ = (offset << 3) | (count - 1);
}
temp = count - 8;
seed -= count;
while (count > 0)
{
if (count <= temp)
{
if (temp >= 255)
*comp_ptr++ = 255;
else
*comp_ptr++ = temp;
temp -= 255;
}
r = *start - *seed;
g = r;
b = ((*start & 0xfe) - (*seed & 0xfe)) / 2;
if (r < -16 || r > 15 || g < -16 || g > 15 || b < -16 || b > 15)
{
g = *start;
*comp_ptr++ = g >> 1;
if (g & 1)
*comp_ptr++ = 0x80 | (g >> 1);
else
*comp_ptr++ = g >> 1;
if (g & 1)
*comp_ptr++ = 0x80 | (g >> 1);
else
*comp_ptr++ = g >> 1;
}
else
{
*comp_ptr++ = 0x80 | ((r << 2) & 0x7c) | ((g >> 3) & 0x03);
*comp_ptr++ = ((g << 5) & 0xe0) | (b & 0x1f);
}
count --;
start ++;
seed ++;
}
if (temp == 0)
*comp_ptr++ = 0;
}
}
else
{
while (line_ptr < line_end)
{
start = line_ptr;
while (line_ptr[0] == seed[0] &&
line_ptr[1] == seed[1] &&
line_ptr[2] == seed[2] &&
(line_ptr + 2) < line_end)
{
line_ptr += 3;
seed += 3;
}
if (line_ptr == line_end)
break;
offset = (line_ptr - start) / 3;
start = line_ptr;
while ((line_ptr[0] != seed[0] ||
line_ptr[1] != seed[1] ||
line_ptr[2] != seed[2]) &&
(line_ptr + 2) < line_end)
{
line_ptr += 3;
seed += 3;
}
count = (line_ptr - start) / 3;
if (offset >= 3)
{
if (count > 7)
*comp_ptr++ = 0x1f;
else
*comp_ptr++ = 0x18 | (count - 1);
offset -= 3;
while (offset >= 255)
{
*comp_ptr++ = 255;
offset -= 255;
}
*comp_ptr++ = offset;
}
else
{
if (count > 7)
*comp_ptr++ = (offset << 3) | 0x07;
else
*comp_ptr++ = (offset << 3) | (count - 1);
}
temp = count - 8;
seed -= count * 3;
while (count > 0)
{
if (count <= temp)
{
if (temp >= 255)
*comp_ptr++ = 255;
else
*comp_ptr++ = temp;
temp -= 255;
}
r = start[0] - seed[0];
g = start[1] - seed[1];
b = ((start[2] & 0xfe) - (seed[2] & 0xfe)) / 2;
if (r < -16 || r > 15 || g < -16 || g > 15 || b < -16 || b > 15)
{
*comp_ptr++ = start[0] >> 1;
if (start[0] & 1)
*comp_ptr++ = 0x80 | (start[1] >> 1);
else
*comp_ptr++ = start[1] >> 1;
if (start[1] & 1)
*comp_ptr++ = 0x80 | (start[2] >> 1);
else
*comp_ptr++ = start[2] >> 1;
}
else
{
*comp_ptr++ = 0x80 | ((r << 2) & 0x7c) | ((g >> 3) & 0x03);
*comp_ptr++ = ((g << 5) & 0xe0) | (b & 0x1f);
}
count --;
start += 3;
seed += 3;
}
if (temp == 0)
*comp_ptr++ = 0;
}
}
line_ptr = CompBuffer;
line_end = comp_ptr;
memcpy(SeedBuffer, line, length);
break;
}
printf("\033*b%d%c", (int)(line_end - line_ptr), pend);
cupsWritePrintData(line_ptr, line_end - line_ptr);
}
void
OutputLine(ppd_file_t *ppd,
cups_page_header2_t *header)
{
int i, j;
int plane;
unsigned char bit;
int bytes;
int width;
const int *order;
unsigned char *ptr;
if (OutputFeed > 0)
{
if (header->cupsCompression < 3)
{
while (OutputFeed > 0)
{
printf("\033*b0W");
OutputFeed --;
}
}
else
{
printf("\033*b%dY", OutputFeed);
OutputFeed = 0;
SeedInvalid = 1;
}
}
switch (OutputMode)
{
case OUTPUT_BITMAP :
order = ColorOrders[PrinterPlanes - 1];
bytes = header->cupsBytesPerLine / PrinterPlanes;
for (i = 0; i < PrinterPlanes; i ++)
{
plane = order[i];
CompressData(PixelBuffer + i * bytes, bytes, plane,
(i < (PrinterPlanes - 1)) ? 'V' : 'W',
header->cupsCompression);
}
break;
case OUTPUT_INVERBIT :
order = ColorOrders[PrinterPlanes - 1];
bytes = header->cupsBytesPerLine / PrinterPlanes;
for (i = header->cupsBytesPerLine, ptr = PixelBuffer;
i > 0;
i --, ptr ++)
*ptr = ~*ptr;
for (i = 0; i < PrinterPlanes; i ++)
{
plane = order[i];
CompressData(PixelBuffer + i * bytes, bytes, plane,
(i < (PrinterPlanes - 1)) ? 'V' : 'W',
header->cupsCompression);
}
break;
case OUTPUT_RGB :
if (PrinterPlanes == 1 && !BlankValue)
{
for (i = header->cupsBytesPerLine, ptr = PixelBuffer;
i > 0;
i --, ptr ++)
*ptr = ~*ptr;
}
CompressData(PixelBuffer, header->cupsBytesPerLine, 0, 'W',
header->cupsCompression);
break;
default :
order = ColorOrders[PrinterPlanes - 1];
width = header->cupsWidth;
for (i = 0, j = 0; i < PrinterPlanes; i ++)
{
plane = order[i];
bytes = DotBufferSizes[plane] / DotBits[plane];
for (bit = 1, ptr = DotBuffers[plane];
bit <= DotBits[plane];
bit <<= 1, ptr += bytes, j ++)
{
cupsPackHorizontalBit(OutputBuffers[plane], DotBuffers[plane],
width, 0, bit);
CompressData(ptr, bytes, j,
i == (PrinterPlanes - 1) &&
bit == DotBits[plane] ? 'W' : 'V',
header->cupsCompression);
}
}
break;
}
SeedInvalid = 0;
}
int
ReadLine(cups_raster_t *ras,
cups_page_header2_t *header)
{
int plane,
width;
cupsRasterReadPixels(ras, PixelBuffer, header->cupsBytesPerLine);
if (cupsCheckValue(PixelBuffer, header->cupsBytesPerLine, BlankValue))
return (0);
if (OutputMode != OUTPUT_DITHERED)
return (1);
width = header->cupsWidth;
switch (header->cupsColorSpace)
{
case CUPS_CSPACE_W :
if (RGB)
{
cupsRGBDoGray(RGB, PixelBuffer, CMYKBuffer, width);
if (RGB->num_channels == 1)
cupsCMYKDoBlack(CMYK, CMYKBuffer, InputBuffer, width);
else
cupsCMYKDoCMYK(CMYK, CMYKBuffer, InputBuffer, width);
}
else
cupsCMYKDoGray(CMYK, PixelBuffer, InputBuffer, width);
break;
case CUPS_CSPACE_K :
cupsCMYKDoBlack(CMYK, PixelBuffer, InputBuffer, width);
break;
default :
case CUPS_CSPACE_RGB :
if (RGB)
{
cupsRGBDoRGB(RGB, PixelBuffer, CMYKBuffer, width);
if (RGB->num_channels == 1)
cupsCMYKDoBlack(CMYK, CMYKBuffer, InputBuffer, width);
else
cupsCMYKDoCMYK(CMYK, CMYKBuffer, InputBuffer, width);
}
else
cupsCMYKDoRGB(CMYK, PixelBuffer, InputBuffer, width);
break;
case CUPS_CSPACE_CMYK :
cupsCMYKDoCMYK(CMYK, PixelBuffer, InputBuffer, width);
break;
}
for (plane = 0; plane < PrinterPlanes; plane ++)
cupsDitherLine(DitherStates[plane], DitherLuts[plane], InputBuffer + plane,
PrinterPlanes, OutputBuffers[plane]);
return (1);
}
int
main(int argc,
char *argv[])
{
int fd;
cups_raster_t *ras;
cups_page_header2_t header;
int y;
ppd_file_t *ppd;
int job_id;
int num_options;
cups_option_t *options;
#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
struct sigaction action;
#endif
setbuf(stderr, NULL);
if (argc < 6 || argc > 7)
{
_cupsLangPrintFilter(stderr, "ERROR",
_("%s job-id user title copies options [file]"),
"rastertopclx");
return (1);
}
num_options = cupsParseOptions(argv[5], 0, &options);
ppd = ppdOpenFile(getenv("PPD"));
if (!ppd)
{
ppd_status_t status;
int linenum;
_cupsLangPrintFilter(stderr, "ERROR",
_("The PPD file could not be opened."));
status = ppdLastError(&linenum);
fprintf(stderr, "DEBUG: %s on line %d.\n", ppdErrorString(status), linenum);
return (1);
}
ppdMarkDefaults(ppd);
cupsMarkOptions(ppd, num_options, options);
if (argc == 7)
{
if ((fd = open(argv[6], O_RDONLY)) == -1)
{
_cupsLangPrintError("ERROR", _("Unable to open raster file"));
return (1);
}
}
else
fd = 0;
ras = cupsRasterOpen(fd, CUPS_RASTER_READ);
Canceled = 0;
#ifdef HAVE_SIGSET
sigset(SIGTERM, CancelJob);
#elif defined(HAVE_SIGACTION)
memset(&action, 0, sizeof(action));
sigemptyset(&action.sa_mask);
action.sa_handler = CancelJob;
sigaction(SIGTERM, &action, NULL);
#else
signal(SIGTERM, CancelJob);
#endif
job_id = atoi(argv[1]);
Page = 0;
while (cupsRasterReadHeader2(ras, &header))
{
if (Canceled)
break;
Page ++;
fprintf(stderr, "PAGE: %d %d\n", Page, header.NumCopies);
_cupsLangPrintFilter(stderr, "INFO", _("Starting page %d."), Page);
StartPage(ppd, &header, atoi(argv[1]), argv[2], argv[3],
num_options, options);
for (y = 0; y < (int)header.cupsHeight; y ++)
{
if (Canceled)
break;
if ((y & 127) == 0)
{
_cupsLangPrintFilter(stderr, "INFO",
_("Printing page %d, %d%% complete."),
Page, 100 * y / header.cupsHeight);
fprintf(stderr, "ATTR: job-media-progress=%d\n",
100 * y / header.cupsHeight);
}
if (ReadLine(ras, &header))
OutputLine(ppd, &header);
else
OutputFeed ++;
}
_cupsLangPrintFilter(stderr, "INFO", _("Finished page %d."), Page);
EndPage(ppd, &header);
if (Canceled)
break;
}
Shutdown(ppd, job_id, argv[2], argv[3], num_options, options);
cupsFreeOptions(num_options, options);
cupsRasterClose(ras);
if (fd != 0)
close(fd);
if (Page == 0)
{
_cupsLangPrintFilter(stderr, "ERROR", _("No pages were found."));
return (1);
}
else
{
_cupsLangPrintFilter(stderr, "INFO", _("Ready to print."));
return (0);
}
}