1 /*
2 * Advanced HP Page Control Language and Raster Transfer Language
3 * filter for CUPS.
4 *
5 * Copyright 2007-2011 by Apple Inc.
6 * Copyright 1993-2005 by Easy Software Products
7 *
8 * These coded instructions, statements, and computer programs are the
9 * property of Apple Inc. and are protected by Federal copyright
10 * law. Distribution and use rights are outlined in the file "COPYING"
11 * which should have been included with this file.
12 *
13 * Contents:
14 *
15 * StartPage() - Start a page of graphics.
16 * EndPage() - Finish a page of graphics.
17 * Shutdown() - Shutdown a printer.
18 * CancelJob() - Cancel the current job...
19 * CompressData() - Compress a line of graphics.
20 * OutputLine() - Output the specified number of lines of graphics.
21 * ReadLine() - Read graphics from the page stream.
22 * main() - Main entry and processing of driver.
23 */
24
25 /*
26 * Include necessary headers...
27 */
28
29 #include <cupsfilters/colormanager.h>
30 #include <cupsfilters/driver.h>
31 #include "pcl-common.h"
32 #include <signal.h>
33
34
35 /*
36 * Output modes...
37 */
38
39 typedef enum
40 {
41 OUTPUT_BITMAP, /* Output bitmap data from RIP */
42 OUTPUT_INVERBIT, /* Output inverted bitmap data */
43 OUTPUT_RGB, /* Output 24-bit RGB data from RIP */
44 OUTPUT_DITHERED /* Output dithered data */
45 } pcl_output_t;
46
47
48 /*
49 * Globals...
50 */
51
52 cups_rgb_t *RGB; /* RGB color separation data */
53 cups_cmyk_t *CMYK; /* CMYK color separation data */
54 unsigned char *PixelBuffer, /* Pixel buffer */
55 *CMYKBuffer, /* CMYK buffer */
56 *OutputBuffers[6], /* Output buffers */
57 *DotBuffers[6], /* Bit buffers */
58 *CompBuffer, /* Compression buffer */
59 *SeedBuffer, /* Mode 3 seed buffers */
60 BlankValue; /* The blank value */
61 short *InputBuffer; /* Color separation buffer */
62 cups_lut_t *DitherLuts[6]; /* Lookup tables for dithering */
63 cups_dither_t *DitherStates[6]; /* Dither state tables */
64 int PrinterPlanes, /* Number of color planes */
65 SeedInvalid, /* Contents of seed buffer invalid? */
66 DotBits[6], /* Number of bits per color */
67 DotBufferSizes[6], /* Size of one row of color dots */
68 DotBufferSize, /* Size of complete line */
69 OutputFeed, /* Number of lines to skip */
70 Page; /* Current page number */
71 pcl_output_t OutputMode; /* Output mode - see OUTPUT_ consts */
72 const int ColorOrders[7][7] = /* Order of color planes */
73 {
74 { 0, 0, 0, 0, 0, 0, 0 }, /* Black */
75 { 0, 0, 0, 0, 0, 0, 0 },
76 { 0, 1, 2, 0, 0, 0, 0 }, /* CMY */
77 { 3, 0, 1, 2, 0, 0, 0 }, /* KCMY */
78 { 0, 0, 0, 0, 0, 0, 0 },
79 { 5, 0, 1, 2, 3, 4, 0 }, /* KCMYcm */
80 { 5, 0, 1, 2, 3, 4, 6 } /* KCMYcmk */
81 };
82 int Canceled; /* Is the job canceled? */
83
84
85 /*
86 * Prototypes...
87 */
88
89 void StartPage(ppd_file_t *ppd, cups_page_header2_t *header, int job_id,
90 const char *user, const char *title, int num_options,
91 cups_option_t *options);
92 void EndPage(ppd_file_t *ppd, cups_page_header2_t *header);
93 void Shutdown(ppd_file_t *ppd, int job_id, const char *user,
94 const char *title, int num_options, cups_option_t *options);
95
96 void CancelJob(int sig);
97 void CompressData(unsigned char *line, int length, int plane, int pend,
98 int type);
99 void OutputLine(ppd_file_t *ppd, cups_page_header2_t *header);
100 int ReadLine(cups_raster_t *ras, cups_page_header2_t *header);
101
102
103 /*
104 * 'StartPage()' - Start a page of graphics.
105 */
106
107 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)108 StartPage(ppd_file_t *ppd, /* I - PPD file */
109 cups_page_header2_t *header, /* I - Page header */
110 int job_id, /* I - Job ID */
111 const char *user, /* I - User printing job */
112 const char *title, /* I - Title of job */
113 int num_options,
114 /* I - Number of command-line options */
115 cups_option_t *options) /* I - Command-line options */
116 {
117 int i; /* Temporary/looping var */
118 int plane; /* Current plane */
119 int cm_disabled; /* Device Color Inhibited */
120 char s[255]; /* Temporary value */
121 const char *colormodel; /* Color model string */
122 char resolution[PPD_MAX_NAME],
123 /* Resolution string */
124 spec[PPD_MAX_NAME]; /* PPD attribute name */
125 ppd_attr_t *attr; /* Attribute from PPD file */
126 ppd_choice_t *choice; /* Selected option */
127 const int *order; /* Order to use */
128 int xorigin, /* X origin of page */
129 yorigin; /* Y origin of page */
130 static const float default_lut[2] = /* Default dithering lookup table */
131 {
132 0.0,
133 1.0
134 };
135 cm_calibration_t cm_calibrate; /* Color calibration mode */
136
137 /*
138 * Debug info...
139 */
140
141 fprintf(stderr, "DEBUG: StartPage...\n");
142 fprintf(stderr, "DEBUG: MediaClass = \"%s\"\n", header->MediaClass);
143 fprintf(stderr, "DEBUG: MediaColor = \"%s\"\n", header->MediaColor);
144 fprintf(stderr, "DEBUG: MediaType = \"%s\"\n", header->MediaType);
145 fprintf(stderr, "DEBUG: OutputType = \"%s\"\n", header->OutputType);
146
147 fprintf(stderr, "DEBUG: AdvanceDistance = %d\n", header->AdvanceDistance);
148 fprintf(stderr, "DEBUG: AdvanceMedia = %d\n", header->AdvanceMedia);
149 fprintf(stderr, "DEBUG: Collate = %d\n", header->Collate);
150 fprintf(stderr, "DEBUG: CutMedia = %d\n", header->CutMedia);
151 fprintf(stderr, "DEBUG: Duplex = %d\n", header->Duplex);
152 fprintf(stderr, "DEBUG: HWResolution = [ %d %d ]\n", header->HWResolution[0],
153 header->HWResolution[1]);
154 fprintf(stderr, "DEBUG: ImagingBoundingBox = [ %d %d %d %d ]\n",
155 header->ImagingBoundingBox[0], header->ImagingBoundingBox[1],
156 header->ImagingBoundingBox[2], header->ImagingBoundingBox[3]);
157 fprintf(stderr, "DEBUG: InsertSheet = %d\n", header->InsertSheet);
158 fprintf(stderr, "DEBUG: Jog = %d\n", header->Jog);
159 fprintf(stderr, "DEBUG: LeadingEdge = %d\n", header->LeadingEdge);
160 fprintf(stderr, "DEBUG: Margins = [ %d %d ]\n", header->Margins[0],
161 header->Margins[1]);
162 fprintf(stderr, "DEBUG: ManualFeed = %d\n", header->ManualFeed);
163 fprintf(stderr, "DEBUG: MediaPosition = %d\n", header->MediaPosition);
164 fprintf(stderr, "DEBUG: MediaWeight = %d\n", header->MediaWeight);
165 fprintf(stderr, "DEBUG: MirrorPrint = %d\n", header->MirrorPrint);
166 fprintf(stderr, "DEBUG: NegativePrint = %d\n", header->NegativePrint);
167 fprintf(stderr, "DEBUG: NumCopies = %d\n", header->NumCopies);
168 fprintf(stderr, "DEBUG: Orientation = %d\n", header->Orientation);
169 fprintf(stderr, "DEBUG: OutputFaceUp = %d\n", header->OutputFaceUp);
170 fprintf(stderr, "DEBUG: PageSize = [ %d %d ]\n", header->PageSize[0],
171 header->PageSize[1]);
172 fprintf(stderr, "DEBUG: Separations = %d\n", header->Separations);
173 fprintf(stderr, "DEBUG: TraySwitch = %d\n", header->TraySwitch);
174 fprintf(stderr, "DEBUG: Tumble = %d\n", header->Tumble);
175 fprintf(stderr, "DEBUG: cupsWidth = %d\n", header->cupsWidth);
176 fprintf(stderr, "DEBUG: cupsHeight = %d\n", header->cupsHeight);
177 fprintf(stderr, "DEBUG: cupsMediaType = %d\n", header->cupsMediaType);
178 fprintf(stderr, "DEBUG: cupsBitsPerColor = %d\n", header->cupsBitsPerColor);
179 fprintf(stderr, "DEBUG: cupsBitsPerPixel = %d\n", header->cupsBitsPerPixel);
180 fprintf(stderr, "DEBUG: cupsBytesPerLine = %d\n", header->cupsBytesPerLine);
181 fprintf(stderr, "DEBUG: cupsColorOrder = %d\n", header->cupsColorOrder);
182 fprintf(stderr, "DEBUG: cupsColorSpace = %d\n", header->cupsColorSpace);
183 fprintf(stderr, "DEBUG: cupsCompression = %d\n", header->cupsCompression);
184
185 #ifdef __APPLE__
186 /*
187 * MacOS X 10.2.x doesn't set most of the page device attributes, so check
188 * the options and set them accordingly...
189 */
190
191 if (ppd && ppdIsMarked(ppd, "Duplex", "DuplexNoTumble"))
192 {
193 header->Duplex = CUPS_TRUE;
194 header->Tumble = CUPS_FALSE;
195 }
196 else if (ppd && ppdIsMarked(ppd, "Duplex", "DuplexTumble"))
197 {
198 header->Duplex = CUPS_TRUE;
199 header->Tumble = CUPS_TRUE;
200 }
201
202 fprintf(stderr, "DEBUG: num_options=%d\n", num_options);
203
204 for (i = 0; i < num_options; i ++)
205 fprintf(stderr, "DEBUG: options[%d]=[\"%s\" \"%s\"]\n", i,
206 options[i].name, options[i].value);
207 #endif /* __APPLE__ */
208
209 /*
210 * Figure out the color model and spec strings...
211 */
212
213 switch (header->cupsColorSpace)
214 {
215 case CUPS_CSPACE_K :
216 colormodel = "Black";
217 break;
218 case CUPS_CSPACE_W :
219 colormodel = "Gray";
220 break;
221 default :
222 case CUPS_CSPACE_RGB :
223 colormodel = "RGB";
224 break;
225 case CUPS_CSPACE_CMY :
226 colormodel = "CMY";
227 break;
228 case CUPS_CSPACE_CMYK :
229 colormodel = "CMYK";
230 break;
231 }
232
233 cm_disabled = 0;
234
235 if (header->HWResolution[0] != header->HWResolution[1])
236 snprintf(resolution, sizeof(resolution), "%dx%ddpi",
237 header->HWResolution[0], header->HWResolution[1]);
238 else
239 snprintf(resolution, sizeof(resolution), "%ddpi",
240 header->HWResolution[0]);
241
242 if (!header->MediaType[0])
243 strcpy(header->MediaType, "PLAIN");
244
245 /*
246 * Get the dithering parameters...
247 */
248
249 BlankValue = 0x00;
250
251 if (header->cupsBitsPerColor == 1)
252 {
253 /*
254 * Use raw bitmap mode...
255 */
256
257 switch (header->cupsColorSpace)
258 {
259 case CUPS_CSPACE_K :
260 OutputMode = OUTPUT_BITMAP;
261 PrinterPlanes = 1;
262 break;
263 case CUPS_CSPACE_W :
264 OutputMode = OUTPUT_INVERBIT;
265 PrinterPlanes = 1;
266 break;
267 default :
268 case CUPS_CSPACE_RGB :
269 OutputMode = OUTPUT_INVERBIT;
270 PrinterPlanes = 3;
271 break;
272 case CUPS_CSPACE_CMY :
273 OutputMode = OUTPUT_BITMAP;
274 PrinterPlanes = 3;
275 break;
276 case CUPS_CSPACE_CMYK :
277 OutputMode = OUTPUT_BITMAP;
278 PrinterPlanes = 4;
279 break;
280 }
281
282 if (OutputMode == OUTPUT_INVERBIT)
283 BlankValue = 0xff;
284
285 DotBufferSize = header->cupsBytesPerLine;
286
287 memset(DitherLuts, 0, sizeof(DitherLuts));
288 memset(DitherStates, 0, sizeof(DitherStates));
289 }
290 else if (header->cupsColorSpace == CUPS_CSPACE_RGB &&
291 (!ppd || (ppd->model_number & PCL_RASTER_RGB24)))
292 {
293 /*
294 * Use 24-bit RGB output mode...
295 */
296
297 OutputMode = OUTPUT_RGB;
298 PrinterPlanes = 3;
299 DotBufferSize = header->cupsBytesPerLine;
300
301 if (header->cupsCompression == 10)
302 BlankValue = 0xff;
303
304 memset(DitherLuts, 0, sizeof(DitherLuts));
305 memset(DitherStates, 0, sizeof(DitherStates));
306 }
307 else if ((header->cupsColorSpace == CUPS_CSPACE_K ||
308 header->cupsColorSpace == CUPS_CSPACE_W) &&
309 (ppd && (ppd->model_number & PCL_RASTER_RGB24)) &&
310 header->cupsCompression == 10)
311 {
312 /*
313 * Use 24-bit RGB output mode for grayscale/black output...
314 */
315
316 OutputMode = OUTPUT_RGB;
317 PrinterPlanes = 1;
318 DotBufferSize = header->cupsBytesPerLine;
319
320 if (header->cupsColorSpace == CUPS_CSPACE_W)
321 BlankValue = 0xff;
322
323 memset(DitherLuts, 0, sizeof(DitherLuts));
324 memset(DitherStates, 0, sizeof(DitherStates));
325 }
326 else
327 {
328 /*
329 * Use dithered output mode...
330 */
331
332 OutputMode = OUTPUT_DITHERED;
333
334 /*
335 * Load the appropriate color profiles...
336 */
337
338 RGB = NULL;
339 CMYK = NULL;
340
341 fputs("DEBUG: Attempting to load color profiles using the following values:\n", stderr);
342 fprintf(stderr, "DEBUG: ColorModel = %s\n", colormodel);
343 fprintf(stderr, "DEBUG: MediaType = %s\n", header->MediaType);
344 fprintf(stderr, "DEBUG: Resolution = %s\n", resolution);
345
346 /* support the "cm-calibration" option */
347 cm_calibrate = cmGetCupsColorCalibrateMode(options, num_options);
348
349 if (cm_calibrate == CM_CALIBRATION_ENABLED)
350 cm_disabled = 1;
351 else
352 cm_disabled = cmIsPrinterCmDisabled(getenv("PRINTER"));
353
354 if (ppd && !cm_disabled)
355 {
356 if (header->cupsColorSpace == CUPS_CSPACE_RGB ||
357 header->cupsColorSpace == CUPS_CSPACE_W)
358 RGB = cupsRGBLoad(ppd, colormodel, header->MediaType, resolution);
359
360 CMYK = cupsCMYKLoad(ppd, colormodel, header->MediaType, resolution);
361 }
362
363 if (RGB)
364 fputs("DEBUG: Loaded RGB separation from PPD.\n", stderr);
365
366 if (CMYK)
367 fputs("DEBUG: Loaded CMYK separation from PPD.\n", stderr);
368 else
369 {
370 if (header->cupsColorSpace == CUPS_CSPACE_KCMY ||
371 header->cupsColorSpace == CUPS_CSPACE_CMYK)
372 PrinterPlanes = 4;
373 else if (header->cupsColorSpace == CUPS_CSPACE_CMY)
374 PrinterPlanes = 3;
375 else
376 PrinterPlanes = 1;
377 /*fputs("DEBUG: Loading default K separation.\n", stderr);*/
378 fprintf(stderr, "DEBUG: Color Space: %d; Color Planes %d\n", header->cupsColorSpace, PrinterPlanes);
379 CMYK = cupsCMYKNew(PrinterPlanes);
380 }
381
382 PrinterPlanes = CMYK->num_channels;
383
384 /*
385 * Use dithered mode...
386 */
387
388 switch (PrinterPlanes)
389 {
390 case 1 : /* K */
391 DitherLuts[0] = cupsLutLoad(ppd, colormodel, header->MediaType,
392 resolution, "Black");
393 break;
394
395 case 3 : /* CMY */
396 DitherLuts[0] = cupsLutLoad(ppd, colormodel, header->MediaType,
397 resolution, "Cyan");
398 DitherLuts[1] = cupsLutLoad(ppd, colormodel, header->MediaType,
399 resolution, "Magenta");
400 DitherLuts[2] = cupsLutLoad(ppd, colormodel, header->MediaType,
401 resolution, "Yellow");
402 break;
403
404 case 4 : /* CMYK */
405 DitherLuts[0] = cupsLutLoad(ppd, colormodel, header->MediaType,
406 resolution, "Cyan");
407 DitherLuts[1] = cupsLutLoad(ppd, colormodel, header->MediaType,
408 resolution, "Magenta");
409 DitherLuts[2] = cupsLutLoad(ppd, colormodel, header->MediaType,
410 resolution, "Yellow");
411 DitherLuts[3] = cupsLutLoad(ppd, colormodel, header->MediaType,
412 resolution, "Black");
413 break;
414
415 case 6 : /* CcMmYK */
416 DitherLuts[0] = cupsLutLoad(ppd, colormodel, header->MediaType,
417 resolution, "Cyan");
418 DitherLuts[1] = cupsLutLoad(ppd, colormodel, header->MediaType,
419 resolution, "LightCyan");
420 DitherLuts[2] = cupsLutLoad(ppd, colormodel, header->MediaType,
421 resolution, "Magenta");
422 DitherLuts[3] = cupsLutLoad(ppd, colormodel, header->MediaType,
423 resolution, "LightMagenta");
424 DitherLuts[4] = cupsLutLoad(ppd, colormodel, header->MediaType,
425 resolution, "Yellow");
426 DitherLuts[5] = cupsLutLoad(ppd, colormodel, header->MediaType,
427 resolution, "Black");
428 break;
429 }
430
431 for (plane = 0; plane < PrinterPlanes; plane ++)
432 {
433 if (!DitherLuts[plane])
434 DitherLuts[plane] = cupsLutNew(2, default_lut);
435
436 if (DitherLuts[plane][4095].pixel > 1)
437 DotBits[plane] = 2;
438 else
439 DotBits[plane] = 1;
440
441 DitherStates[plane] = cupsDitherNew(header->cupsWidth);
442
443 if (!DitherLuts[plane])
444 DitherLuts[plane] = cupsLutNew(2, default_lut);
445 }
446 }
447
448 fprintf(stderr, "DEBUG: PrinterPlanes = %d\n", PrinterPlanes);
449
450 /*
451 * Initialize the printer...
452 */
453
454 if (ppd && ((attr = ppdFindAttr(ppd, "cupsInitialNulls", NULL)) != NULL))
455 for (i = atoi(attr->value); i > 0; i --)
456 putchar(0);
457
458 if (Page == 1 && (!ppd || ppd->model_number & PCL_PJL))
459 {
460 pjl_escape();
461
462 /*
463 * PJL job setup...
464 */
465
466 pjl_set_job(job_id, user, title);
467
468 if (ppd && ((attr = ppdFindAttr(ppd, "cupsPJL", "StartJob")) != NULL))
469 pjl_write(attr->value, NULL, job_id, user, title, num_options,
470 options);
471
472 snprintf(spec, sizeof(spec), "RENDERMODE.%s", colormodel);
473 if (ppd && ((attr = ppdFindAttr(ppd, "cupsPJL", spec)) != NULL))
474 printf("@PJL SET RENDERMODE=%s\r\n", attr->value);
475
476 snprintf(spec, sizeof(spec), "COLORSPACE.%s", colormodel);
477 if (ppd && ((attr = ppdFindAttr(ppd, "cupsPJL", spec)) != NULL))
478 printf("@PJL SET COLORSPACE=%s\r\n", attr->value);
479 if (!ppd)
480 printf("@PJL SET COLORSPACE=%s\r\n", colormodel);
481
482 snprintf(spec, sizeof(spec), "RENDERINTENT.%s", colormodel);
483 if (ppd && ((attr = ppdFindAttr(ppd, "cupsPJL", spec)) != NULL))
484 printf("@PJL SET RENDERINTENT=%s\r\n", attr->value);
485
486 if (ppd && ((attr = ppdFindAttr(ppd, "cupsPJL", "Duplex")) != NULL))
487 {
488 sprintf(s, "%d", header->Duplex);
489 pjl_write(attr->value, s, job_id, user, title, num_options, options);
490 }
491
492 if (ppd && ((attr = ppdFindAttr(ppd, "cupsPJL", "Tumble")) != NULL))
493 {
494 sprintf(s, "%d", header->Tumble);
495 pjl_write(attr->value, s, job_id, user, title, num_options, options);
496 }
497
498 if (ppd && ((attr = ppdFindAttr(ppd, "cupsPJL", "MediaClass")) != NULL))
499 pjl_write(attr->value, header->MediaClass, job_id, user, title,
500 num_options, options);
501
502 if (ppd && ((attr = ppdFindAttr(ppd, "cupsPJL", "MediaColor")) != NULL))
503 pjl_write(attr->value, header->MediaColor, job_id, user, title,
504 num_options, options);
505
506 if (ppd && ((attr = ppdFindAttr(ppd, "cupsPJL", "MediaType")) != NULL))
507 pjl_write(attr->value, header->MediaType, job_id, user, title,
508 num_options, options);
509
510 if (ppd && ((attr = ppdFindAttr(ppd, "cupsPJL", "OutputType")) != NULL))
511 pjl_write(attr->value, header->OutputType, job_id, user, title,
512 num_options, options);
513
514 if (ppd && ((attr = ppdFindAttr(ppd, "cupsPJL", "cupsBooklet")) != NULL &&
515 (choice = ppdFindMarkedChoice(ppd, "cupsBooklet")) != NULL))
516 pjl_write(attr->value, choice->choice, job_id, user, title,
517 num_options, options);
518
519 if (ppd && ((attr = ppdFindAttr(ppd, "cupsPJL", "Jog")) != NULL))
520 {
521 sprintf(s, "%d", header->Jog);
522 pjl_write(attr->value, s, job_id, user, title, num_options, options);
523 }
524
525 if (ppd && ((attr = ppdFindAttr(ppd, "cupsPJL", "cupsPunch")) != NULL &&
526 (choice = ppdFindMarkedChoice(ppd, "cupsPunch")) != NULL))
527 pjl_write(attr->value, choice->choice, job_id, user, title,
528 num_options, options);
529
530 if (ppd && ((attr = ppdFindAttr(ppd, "cupsPJL", "cupsStaple")) != NULL &&
531 (choice = ppdFindMarkedChoice(ppd, "cupsStaple")) != NULL))
532 pjl_write(attr->value, choice->choice, job_id, user, title,
533 num_options, options);
534
535 if (ppd && ((attr = ppdFindAttr(ppd, "cupsPJL", "cupsRET")) != NULL &&
536 (choice = ppdFindMarkedChoice(ppd, "cupsRET")) != NULL))
537 pjl_write(attr->value, choice->choice, job_id, user, title,
538 num_options, options);
539
540 if (ppd && ((attr = ppdFindAttr(ppd, "cupsPJL", "cupsTonerSave")) != NULL &&
541 (choice = ppdFindMarkedChoice(ppd, "cupsTonerSave")) != NULL))
542 pjl_write(attr->value, choice->choice, job_id, user, title,
543 num_options, options);
544
545 if (!ppd || ppd->model_number & PCL_PJL_PAPERWIDTH)
546 {
547 printf("@PJL SET PAPERLENGTH=%d\r\n", header->PageSize[1] * 10);
548 printf("@PJL SET PAPERWIDTH=%d\r\n", header->PageSize[0] * 10);
549 }
550
551 if (!ppd || ppd->model_number & PCL_PJL_RESOLUTION)
552 printf("@PJL SET RESOLUTION=%d\r\n", header->HWResolution[0]);
553
554 if (ppd)
555 ppdEmit(ppd, stdout, PPD_ORDER_JCL);
556 if (ppd && ppd->model_number & PCL_PJL_HPGL2)
557 pjl_enter_language("HPGL2");
558 else if (ppd && ppd->model_number & PCL_PJL_PCL3GUI)
559 pjl_enter_language("PCL3GUI");
560 else
561 pjl_enter_language("PCL");
562 }
563
564 if (Page == 1)
565 {
566 pcl_reset();
567 }
568
569 if (ppd && ppd->model_number & PCL_PJL_HPGL2)
570 {
571 if (Page == 1)
572 {
573 /*
574 * HP-GL/2 initialization...
575 */
576
577 printf("IN;");
578 printf("MG\"%d %s %s\";", job_id, user, title);
579 }
580
581 /*
582 * Set media size, position, type, etc...
583 */
584
585 printf("BP5,0;");
586 printf("PS%.0f,%.0f;",
587 header->cupsHeight * 1016.0 / header->HWResolution[1],
588 header->cupsWidth * 1016.0 / header->HWResolution[0]);
589 printf("PU;");
590 printf("PA0,0");
591
592 printf("MT%d;", header->cupsMediaType);
593
594 if (header->CutMedia == CUPS_CUT_PAGE)
595 printf("EC;");
596 else
597 printf("EC0;");
598
599 /*
600 * Set graphics mode...
601 */
602
603 pcl_set_pcl_mode(0);
604 pcl_set_negative_motion();
605 }
606 else
607 {
608 /*
609 * Set media size, position, type, etc...
610 */
611
612 if (!header->Duplex || (Page & 1))
613 {
614 pcl_set_media_size(ppd, header->PageSize[0], header->PageSize[1]);
615
616 if (header->MediaPosition)
617 pcl_set_media_source(header->MediaPosition);
618
619 pcl_set_media_type(header->cupsMediaType);
620
621 if (!ppd || ppdFindAttr(ppd, "cupsPJL", "Duplex") == NULL)
622 pcl_set_duplex(header->Duplex, header->Tumble);
623
624 /*
625 * Set the number of copies...
626 */
627
628 if (!ppd || !ppd->manual_copies)
629 pcl_set_copies(header->NumCopies);
630
631 /*
632 * Set the output order/bin...
633 */
634
635 if ((!ppd || ppdFindAttr(ppd, "cupsPJL", "Jog") == NULL) && header->Jog)
636 printf("\033&l%dG", header->Jog);
637 }
638 else
639 {
640 /*
641 * Print on the back side...
642 */
643
644 printf("\033&a2G");
645 }
646
647 if (header->Duplex && (ppd && (ppd->model_number & PCL_RASTER_CRD)))
648 {
649 /*
650 * Reload the media...
651 */
652
653 pcl_set_media_source(-2);
654 }
655
656 /*
657 * Set the units for cursor positioning and go to the top of the form.
658 */
659
660 printf("\033&u%dD", header->HWResolution[0]);
661 printf("\033*p0Y\033*p0X");
662 }
663
664 if (ppd && ((attr = cupsFindAttr(ppd, "cupsPCLQuality", colormodel,
665 header->MediaType, resolution, spec,
666 sizeof(spec))) != NULL))
667 {
668 /*
669 * Set the print quality...
670 */
671
672 if (ppd && (ppd->model_number & PCL_PJL_HPGL2))
673 printf("QM%d", atoi(attr->value));
674 else
675 printf("\033*o%dM", atoi(attr->value));
676 }
677
678 /*
679 * Enter graphics mode...
680 */
681
682 if (ppd && (ppd->model_number & PCL_RASTER_CRD))
683 {
684 /*
685 * Use configure raster data command...
686 */
687
688 if (OutputMode == OUTPUT_RGB)
689 {
690 /*
691 * Send 12-byte configure raster data command with horizontal and
692 * vertical resolutions as well as a color count...
693 */
694
695 if (ppd && ((attr = cupsFindAttr(ppd, "cupsPCLCRDMode", colormodel,
696 header->MediaType, resolution, spec,
697 sizeof(spec))) != NULL))
698 i = atoi(attr->value);
699 else
700 i = 31;
701
702 printf("\033*g12W");
703 putchar(6); /* Format 6 */
704 putchar(i); /* Set pen mode */
705 putchar(0x00); /* Number components */
706 putchar(0x01); /* (1 for RGB) */
707
708 putchar(header->HWResolution[0] >> 8);
709 putchar(header->HWResolution[0]);
710 putchar(header->HWResolution[1] >> 8);
711 putchar(header->HWResolution[1]);
712
713 putchar(header->cupsCompression); /* Compression mode 3 or 10 */
714 putchar(0x01); /* Portrait orientation */
715 putchar(0x20); /* Bits per pixel (32 = RGB) */
716 putchar(0x01); /* Planes per pixel (1 = chunky RGB) */
717 }
718 else
719 {
720 /*
721 * Send the configure raster data command with horizontal and
722 * vertical resolutions as well as a color count...
723 */
724
725 printf("\033*g%dW", PrinterPlanes * 6 + 2);
726 putchar(2); /* Format 2 */
727 putchar(PrinterPlanes); /* Output planes */
728
729 order = ColorOrders[PrinterPlanes - 1];
730
731 for (i = 0; i < PrinterPlanes; i ++)
732 {
733 plane = order[i];
734
735 putchar(header->HWResolution[0] >> 8);
736 putchar(header->HWResolution[0]);
737 putchar(header->HWResolution[1] >> 8);
738 putchar(header->HWResolution[1]);
739 putchar(0);
740 putchar(1 << DotBits[plane]);
741 }
742 }
743 }
744 else if ((!ppd || (ppd->model_number & PCL_RASTER_CID)) &&
745 OutputMode == OUTPUT_RGB)
746 {
747 /*
748 * Use configure image data command...
749 */
750
751 pcl_set_simple_resolution(header->HWResolution[0]);
752 /* Set output resolution */
753
754 cupsWritePrintData("\033*v6W\2\3\0\10\10\10", 11);
755 /* 24-bit sRGB */
756 }
757 else
758 {
759 /*
760 * Use simple raster commands...
761 */
762
763 pcl_set_simple_resolution(header->HWResolution[0]);
764 /* Set output resolution */
765
766 if (PrinterPlanes == 3)
767 pcl_set_simple_cmy();
768 else if (PrinterPlanes == 4)
769 pcl_set_simple_kcmy();
770 }
771
772 if (ppd && ((attr = ppdFindAttr(ppd, "cupsPCLOrigin", "X")) != NULL))
773 xorigin = atoi(attr->value);
774 else
775 xorigin = 0;
776
777 if (ppd && ((attr = ppdFindAttr(ppd, "cupsPCLOrigin", "Y")) != NULL))
778 yorigin = atoi(attr->value);
779 else
780 yorigin = 120;
781
782 printf("\033&a%dH\033&a%dV", xorigin, yorigin);
783 printf("\033*r%dS", header->cupsWidth);
784 printf("\033*r%dT", header->cupsHeight);
785 printf("\033*r1A");
786
787 if (header->cupsCompression && header->cupsCompression != 10)
788 printf("\033*b%dM", header->cupsCompression);
789
790 OutputFeed = 0;
791
792 /*
793 * Allocate memory for the page...
794 */
795
796 PixelBuffer = malloc(header->cupsBytesPerLine);
797
798 if (OutputMode == OUTPUT_DITHERED)
799 {
800 InputBuffer = malloc(header->cupsWidth * PrinterPlanes * 2);
801 OutputBuffers[0] = malloc(PrinterPlanes * header->cupsWidth);
802
803 for (i = 1; i < PrinterPlanes; i ++)
804 OutputBuffers[i] = OutputBuffers[0] + i * header->cupsWidth;
805
806 if (RGB)
807 CMYKBuffer = malloc(header->cupsWidth * PrinterPlanes);
808
809 for (plane = 0, DotBufferSize = 0; plane < PrinterPlanes; plane ++)
810 {
811 DotBufferSizes[plane] = (header->cupsWidth + 7) / 8 * DotBits[plane];
812 DotBufferSize += DotBufferSizes[plane];
813 }
814
815 DotBuffers[0] = malloc(DotBufferSize);
816 for (plane = 1; plane < PrinterPlanes; plane ++)
817 DotBuffers[plane] = DotBuffers[plane - 1] + DotBufferSizes[plane - 1];
818 }
819
820 if (header->cupsCompression)
821 CompBuffer = malloc(DotBufferSize * 4);
822
823 if (header->cupsCompression >= 3)
824 SeedBuffer = malloc(DotBufferSize);
825
826 SeedInvalid = 1;
827
828 fprintf(stderr, "BlankValue=%d\n", BlankValue);
829 }
830
831
832 /*
833 * 'EndPage()' - Finish a page of graphics.
834 */
835
836 void
EndPage(ppd_file_t * ppd,cups_page_header2_t * header)837 EndPage(ppd_file_t *ppd, /* I - PPD file */
838 cups_page_header2_t *header) /* I - Page header */
839 {
840 int plane; /* Current plane */
841
842
843 /*
844 * End graphics mode...
845 */
846
847 if (ppd && (ppd->model_number & PCL_RASTER_END_COLOR))
848 printf("\033*rC"); /* End color GFX */
849 else
850 printf("\033*r0B"); /* End B&W GFX */
851
852 /*
853 * Output a page eject sequence...
854 */
855
856 if (ppd && (ppd->model_number & PCL_PJL_HPGL2))
857 {
858 pcl_set_hpgl_mode(0); /* Back to HP-GL/2 mode */
859 printf("PG;"); /* Eject the current page */
860 }
861 else if (!(header->Duplex && (Page & 1)))
862 printf("\014"); /* Eject current page */
863
864 /*
865 * Free memory for the page...
866 */
867
868 free(PixelBuffer);
869
870 if (OutputMode == OUTPUT_DITHERED)
871 {
872 for (plane = 0; plane < PrinterPlanes; plane ++)
873 {
874 cupsDitherDelete(DitherStates[plane]);
875 cupsLutDelete(DitherLuts[plane]);
876 }
877
878 free(DotBuffers[0]);
879 free(InputBuffer);
880 free(OutputBuffers[0]);
881
882 cupsCMYKDelete(CMYK);
883
884 if (RGB)
885 {
886 cupsRGBDelete(RGB);
887 free(CMYKBuffer);
888 }
889 }
890
891 if (header->cupsCompression)
892 free(CompBuffer);
893
894 if (header->cupsCompression >= 3)
895 free(SeedBuffer);
896 }
897
898
899 /*
900 * 'Shutdown()' - Shutdown a printer.
901 */
902
903 void
Shutdown(ppd_file_t * ppd,int job_id,const char * user,const char * title,int num_options,cups_option_t * options)904 Shutdown(ppd_file_t *ppd, /* I - PPD file */
905 int job_id, /* I - Job ID */
906 const char *user, /* I - User printing job */
907 const char *title, /* I - Title of job */
908 int num_options,/* I - Number of command-line options */
909 cups_option_t *options) /* I - Command-line options */
910 {
911 ppd_attr_t *attr; /* Attribute from PPD file */
912
913
914 if (ppd && ((attr = ppdFindAttr(ppd, "cupsPCL", "EndJob")) != NULL))
915 {
916 /*
917 * Tell the printer how many pages were in the job...
918 */
919
920 putchar(0x1b);
921 printf(attr->value, Page);
922 }
923 else
924 {
925 /*
926 * Return the printer to the default state...
927 */
928
929 pcl_reset();
930 }
931
932 if (!ppd || (ppd->model_number & PCL_PJL))
933 {
934 pjl_escape();
935
936 if (ppd && ((attr = ppdFindAttr(ppd, "cupsPJL", "EndJob")) != NULL))
937 pjl_write(attr->value, NULL, job_id, user, title, num_options,
938 options);
939 else
940 printf("@PJL EOJ\r\n");
941
942 pjl_escape();
943 }
944 }
945
946
947 /*
948 * 'CancelJob()' - Cancel the current job...
949 */
950
951 void
CancelJob(int sig)952 CancelJob(int sig) /* I - Signal */
953 {
954 (void)sig;
955
956 Canceled = 1;
957 }
958
959
960 /*
961 * 'CompressData()' - Compress a line of graphics.
962 */
963
964 void
CompressData(unsigned char * line,int length,int plane,int pend,int type)965 CompressData(unsigned char *line, /* I - Data to compress */
966 int length, /* I - Number of bytes */
967 int plane, /* I - Color plane */
968 int pend, /* I - End character for data */
969 int type) /* I - Type of compression */
970 {
971 unsigned char *line_ptr, /* Current byte pointer */
972 *line_end, /* End-of-line byte pointer */
973 *comp_ptr, /* Pointer into compression buffer */
974 *start, /* Start of compression sequence */
975 *seed; /* Seed buffer pointer */
976 int count, /* Count of bytes for output */
977 offset, /* Offset of bytes for output */
978 temp; /* Temporary count */
979 int r, g, b; /* RGB deltas for mode 10 compression */
980
981
982 switch (type)
983 {
984 default :
985 /*
986 * Do no compression; with a mode-0 only printer, we can compress blank
987 * lines...
988 */
989
990 line_ptr = line;
991
992 if (cupsCheckBytes(line, length))
993 line_end = line; /* Blank line */
994 else
995 line_end = line + length; /* Non-blank line */
996 break;
997
998 case 1 :
999 /*
1000 * Do run-length encoding...
1001 */
1002
1003 line_end = line + length;
1004 for (line_ptr = line, comp_ptr = CompBuffer;
1005 line_ptr < line_end;
1006 comp_ptr += 2, line_ptr += count)
1007 {
1008 for (count = 1;
1009 (line_ptr + count) < line_end &&
1010 line_ptr[0] == line_ptr[count] &&
1011 count < 256;
1012 count ++);
1013
1014 comp_ptr[0] = count - 1;
1015 comp_ptr[1] = line_ptr[0];
1016 }
1017
1018 line_ptr = CompBuffer;
1019 line_end = comp_ptr;
1020 break;
1021
1022 case 2 :
1023 /*
1024 * Do TIFF pack-bits encoding...
1025 */
1026
1027 line_ptr = line;
1028 line_end = line + length;
1029 comp_ptr = CompBuffer;
1030
1031 while (line_ptr < line_end)
1032 {
1033 if ((line_ptr + 1) >= line_end)
1034 {
1035 /*
1036 * Single byte on the end...
1037 */
1038
1039 *comp_ptr++ = 0x00;
1040 *comp_ptr++ = *line_ptr++;
1041 }
1042 else if (line_ptr[0] == line_ptr[1])
1043 {
1044 /*
1045 * Repeated sequence...
1046 */
1047
1048 line_ptr ++;
1049 count = 2;
1050
1051 while (line_ptr < (line_end - 1) &&
1052 line_ptr[0] == line_ptr[1] &&
1053 count < 127)
1054 {
1055 line_ptr ++;
1056 count ++;
1057 }
1058
1059 *comp_ptr++ = 257 - count;
1060 *comp_ptr++ = *line_ptr++;
1061 }
1062 else
1063 {
1064 /*
1065 * Non-repeated sequence...
1066 */
1067
1068 start = line_ptr;
1069 line_ptr ++;
1070 count = 1;
1071
1072 while (line_ptr < (line_end - 1) &&
1073 line_ptr[0] != line_ptr[1] &&
1074 count < 127)
1075 {
1076 line_ptr ++;
1077 count ++;
1078 }
1079
1080 *comp_ptr++ = count - 1;
1081
1082 memcpy(comp_ptr, start, count);
1083 comp_ptr += count;
1084 }
1085 }
1086
1087 line_ptr = CompBuffer;
1088 line_end = comp_ptr;
1089 break;
1090
1091 case 3 :
1092 /*
1093 * Do delta-row compression...
1094 */
1095
1096 line_ptr = line;
1097 line_end = line + length;
1098
1099 comp_ptr = CompBuffer;
1100 seed = SeedBuffer + plane * length;
1101
1102 while (line_ptr < line_end)
1103 {
1104 /*
1105 * Find the next non-matching sequence...
1106 */
1107
1108 start = line_ptr;
1109
1110 if (SeedInvalid)
1111 {
1112 /*
1113 * The seed buffer is invalid, so do the next 8 bytes, max...
1114 */
1115
1116 offset = 0;
1117
1118 if ((count = line_end - line_ptr) > 8)
1119 count = 8;
1120
1121 line_ptr += count;
1122 }
1123 else
1124 {
1125 /*
1126 * The seed buffer is valid, so compare against it...
1127 */
1128
1129 while (*line_ptr == *seed &&
1130 line_ptr < line_end)
1131 {
1132 line_ptr ++;
1133 seed ++;
1134 }
1135
1136 if (line_ptr == line_end)
1137 break;
1138
1139 offset = line_ptr - start;
1140
1141 /*
1142 * Find up to 8 non-matching bytes...
1143 */
1144
1145 start = line_ptr;
1146 count = 0;
1147 while (*line_ptr != *seed &&
1148 line_ptr < line_end &&
1149 count < 8)
1150 {
1151 line_ptr ++;
1152 seed ++;
1153 count ++;
1154 }
1155 }
1156
1157 /*
1158 * Place mode 3 compression data in the buffer; see HP manuals
1159 * for details...
1160 */
1161
1162 if (offset >= 31)
1163 {
1164 /*
1165 * Output multi-byte offset...
1166 */
1167
1168 *comp_ptr++ = ((count - 1) << 5) | 31;
1169
1170 offset -= 31;
1171 while (offset >= 255)
1172 {
1173 *comp_ptr++ = 255;
1174 offset -= 255;
1175 }
1176
1177 *comp_ptr++ = offset;
1178 }
1179 else
1180 {
1181 /*
1182 * Output single-byte offset...
1183 */
1184
1185 *comp_ptr++ = ((count - 1) << 5) | offset;
1186 }
1187
1188 memcpy(comp_ptr, start, count);
1189 comp_ptr += count;
1190 }
1191
1192 line_ptr = CompBuffer;
1193 line_end = comp_ptr;
1194
1195 memcpy(SeedBuffer + plane * length, line, length);
1196 break;
1197
1198 case 10 :
1199 /*
1200 * Mode 10 "near lossless" RGB compression...
1201 */
1202
1203 line_ptr = line;
1204 line_end = line + length;
1205
1206 comp_ptr = CompBuffer;
1207 seed = SeedBuffer;
1208
1209 if (PrinterPlanes == 1)
1210 {
1211 /*
1212 * Do grayscale compression to RGB...
1213 */
1214
1215 while (line_ptr < line_end)
1216 {
1217 /*
1218 * Find the next non-matching sequence...
1219 */
1220
1221 start = line_ptr;
1222 while (line_ptr < line_end &&
1223 *line_ptr == *seed)
1224 {
1225 line_ptr ++;
1226 seed ++;
1227 }
1228
1229 if (line_ptr == line_end)
1230 break;
1231
1232 offset = line_ptr - start;
1233
1234 /*
1235 * Find non-matching grayscale pixels...
1236 */
1237
1238 start = line_ptr;
1239 while (line_ptr < line_end &&
1240 *line_ptr != *seed)
1241 {
1242 line_ptr ++;
1243 seed ++;
1244 }
1245
1246 count = line_ptr - start;
1247
1248 #if 0
1249 fprintf(stderr, "DEBUG: offset=%d, count=%d, comp_ptr=%p(%d of %d)...\n",
1250 offset, count, comp_ptr, comp_ptr - CompBuffer,
1251 BytesPerLine * 5);
1252 #endif /* 0 */
1253
1254 /*
1255 * Place mode 10 compression data in the buffer; each sequence
1256 * starts with a command byte that looks like:
1257 *
1258 * CMD SRC SRC OFF OFF CNT CNT CNT
1259 *
1260 * For the purpose of this driver, CMD and SRC are always 0.
1261 *
1262 * If the offset >= 3 then additional offset bytes follow the
1263 * first command byte, each byte == 255 until the last one.
1264 *
1265 * If the count >= 7, then additional count bytes follow each
1266 * group of pixels, each byte == 255 until the last one.
1267 *
1268 * The offset and count are in RGB tuples (not bytes, as for
1269 * Mode 3 and 9)...
1270 */
1271
1272 if (offset >= 3)
1273 {
1274 /*
1275 * Output multi-byte offset...
1276 */
1277
1278 if (count > 7)
1279 *comp_ptr++ = 0x1f;
1280 else
1281 *comp_ptr++ = 0x18 | (count - 1);
1282
1283 offset -= 3;
1284 while (offset >= 255)
1285 {
1286 *comp_ptr++ = 255;
1287 offset -= 255;
1288 }
1289
1290 *comp_ptr++ = offset;
1291 }
1292 else
1293 {
1294 /*
1295 * Output single-byte offset...
1296 */
1297
1298 if (count > 7)
1299 *comp_ptr++ = (offset << 3) | 0x07;
1300 else
1301 *comp_ptr++ = (offset << 3) | (count - 1);
1302 }
1303
1304 temp = count - 8;
1305 seed -= count;
1306
1307 while (count > 0)
1308 {
1309 if (count <= temp)
1310 {
1311 /*
1312 * This is exceedingly lame... The replacement counts
1313 * are intermingled with the data...
1314 */
1315
1316 if (temp >= 255)
1317 *comp_ptr++ = 255;
1318 else
1319 *comp_ptr++ = temp;
1320
1321 temp -= 255;
1322 }
1323
1324 /*
1325 * Get difference between current and see pixels...
1326 */
1327
1328 r = *start - *seed;
1329 g = r;
1330 b = ((*start & 0xfe) - (*seed & 0xfe)) / 2;
1331
1332 if (r < -16 || r > 15 || g < -16 || g > 15 || b < -16 || b > 15)
1333 {
1334 /*
1335 * Pack 24-bit RGB into 23 bits... Lame...
1336 */
1337
1338 g = *start;
1339
1340 *comp_ptr++ = g >> 1;
1341
1342 if (g & 1)
1343 *comp_ptr++ = 0x80 | (g >> 1);
1344 else
1345 *comp_ptr++ = g >> 1;
1346
1347 if (g & 1)
1348 *comp_ptr++ = 0x80 | (g >> 1);
1349 else
1350 *comp_ptr++ = g >> 1;
1351 }
1352 else
1353 {
1354 /*
1355 * Pack 15-bit RGB difference...
1356 */
1357
1358 *comp_ptr++ = 0x80 | ((r << 2) & 0x7c) | ((g >> 3) & 0x03);
1359 *comp_ptr++ = ((g << 5) & 0xe0) | (b & 0x1f);
1360 }
1361
1362 count --;
1363 start ++;
1364 seed ++;
1365 }
1366
1367 /*
1368 * Make sure we have the ending count if the replacement count
1369 * was exactly 8 + 255n...
1370 */
1371
1372 if (temp == 0)
1373 *comp_ptr++ = 0;
1374 }
1375 }
1376 else
1377 {
1378 /*
1379 * Do RGB compression...
1380 */
1381
1382 while (line_ptr < line_end)
1383 {
1384 /*
1385 * Find the next non-matching sequence...
1386 */
1387
1388 start = line_ptr;
1389 while (line_ptr[0] == seed[0] &&
1390 line_ptr[1] == seed[1] &&
1391 line_ptr[2] == seed[2] &&
1392 (line_ptr + 2) < line_end)
1393 {
1394 line_ptr += 3;
1395 seed += 3;
1396 }
1397
1398 if (line_ptr == line_end)
1399 break;
1400
1401 offset = (line_ptr - start) / 3;
1402
1403 /*
1404 * Find non-matching RGB tuples...
1405 */
1406
1407 start = line_ptr;
1408 while ((line_ptr[0] != seed[0] ||
1409 line_ptr[1] != seed[1] ||
1410 line_ptr[2] != seed[2]) &&
1411 (line_ptr + 2) < line_end)
1412 {
1413 line_ptr += 3;
1414 seed += 3;
1415 }
1416
1417 count = (line_ptr - start) / 3;
1418
1419 /*
1420 * Place mode 10 compression data in the buffer; each sequence
1421 * starts with a command byte that looks like:
1422 *
1423 * CMD SRC SRC OFF OFF CNT CNT CNT
1424 *
1425 * For the purpose of this driver, CMD and SRC are always 0.
1426 *
1427 * If the offset >= 3 then additional offset bytes follow the
1428 * first command byte, each byte == 255 until the last one.
1429 *
1430 * If the count >= 7, then additional count bytes follow each
1431 * group of pixels, each byte == 255 until the last one.
1432 *
1433 * The offset and count are in RGB tuples (not bytes, as for
1434 * Mode 3 and 9)...
1435 */
1436
1437 if (offset >= 3)
1438 {
1439 /*
1440 * Output multi-byte offset...
1441 */
1442
1443 if (count > 7)
1444 *comp_ptr++ = 0x1f;
1445 else
1446 *comp_ptr++ = 0x18 | (count - 1);
1447
1448 offset -= 3;
1449 while (offset >= 255)
1450 {
1451 *comp_ptr++ = 255;
1452 offset -= 255;
1453 }
1454
1455 *comp_ptr++ = offset;
1456 }
1457 else
1458 {
1459 /*
1460 * Output single-byte offset...
1461 */
1462
1463 if (count > 7)
1464 *comp_ptr++ = (offset << 3) | 0x07;
1465 else
1466 *comp_ptr++ = (offset << 3) | (count - 1);
1467 }
1468
1469 temp = count - 8;
1470 seed -= count * 3;
1471
1472 while (count > 0)
1473 {
1474 if (count <= temp)
1475 {
1476 /*
1477 * This is exceedingly lame... The replacement counts
1478 * are intermingled with the data...
1479 */
1480
1481 if (temp >= 255)
1482 *comp_ptr++ = 255;
1483 else
1484 *comp_ptr++ = temp;
1485
1486 temp -= 255;
1487 }
1488
1489 /*
1490 * Get difference between current and see pixels...
1491 */
1492
1493 r = start[0] - seed[0];
1494 g = start[1] - seed[1];
1495 b = ((start[2] & 0xfe) - (seed[2] & 0xfe)) / 2;
1496
1497 if (r < -16 || r > 15 || g < -16 || g > 15 || b < -16 || b > 15)
1498 {
1499 /*
1500 * Pack 24-bit RGB into 23 bits... Lame...
1501 */
1502
1503 *comp_ptr++ = start[0] >> 1;
1504
1505 if (start[0] & 1)
1506 *comp_ptr++ = 0x80 | (start[1] >> 1);
1507 else
1508 *comp_ptr++ = start[1] >> 1;
1509
1510 if (start[1] & 1)
1511 *comp_ptr++ = 0x80 | (start[2] >> 1);
1512 else
1513 *comp_ptr++ = start[2] >> 1;
1514 }
1515 else
1516 {
1517 /*
1518 * Pack 15-bit RGB difference...
1519 */
1520
1521 *comp_ptr++ = 0x80 | ((r << 2) & 0x7c) | ((g >> 3) & 0x03);
1522 *comp_ptr++ = ((g << 5) & 0xe0) | (b & 0x1f);
1523 }
1524
1525 count --;
1526 start += 3;
1527 seed += 3;
1528 }
1529
1530 /*
1531 * Make sure we have the ending count if the replacement count
1532 * was exactly 8 + 255n...
1533 */
1534
1535 if (temp == 0)
1536 *comp_ptr++ = 0;
1537 }
1538 }
1539
1540 line_ptr = CompBuffer;
1541 line_end = comp_ptr;
1542
1543 memcpy(SeedBuffer, line, length);
1544 break;
1545 }
1546
1547 /*
1548 * Set the length of the data and write a raster plane...
1549 */
1550
1551 printf("\033*b%d%c", (int)(line_end - line_ptr), pend);
1552 cupsWritePrintData(line_ptr, line_end - line_ptr);
1553 }
1554
1555
1556 /*
1557 * 'OutputLine()' - Output the specified number of lines of graphics.
1558 */
1559
1560 void
OutputLine(ppd_file_t * ppd,cups_page_header2_t * header)1561 OutputLine(ppd_file_t *ppd, /* I - PPD file */
1562 cups_page_header2_t *header) /* I - Page header */
1563 {
1564 int i, j; /* Looping vars */
1565 int plane; /* Current plane */
1566 unsigned char bit; /* Current bit */
1567 int bytes; /* Number of bytes/plane */
1568 int width; /* Width of line in pixels */
1569 const int *order; /* Order to use */
1570 unsigned char *ptr; /* Pointer into buffer */
1571
1572
1573 /*
1574 * Output whitespace as needed...
1575 */
1576
1577 if (OutputFeed > 0)
1578 {
1579 if (header->cupsCompression < 3)
1580 {
1581 /*
1582 * Send blank raster lines...
1583 */
1584
1585 while (OutputFeed > 0)
1586 {
1587 printf("\033*b0W");
1588 OutputFeed --;
1589 }
1590 }
1591 else
1592 {
1593 /*
1594 * Send Y offset command and invalidate the seed buffer...
1595 */
1596
1597 printf("\033*b%dY", OutputFeed);
1598 OutputFeed = 0;
1599 SeedInvalid = 1;
1600 }
1601 }
1602
1603 /*
1604 * Write bitmap data as needed...
1605 */
1606
1607 switch (OutputMode)
1608 {
1609 case OUTPUT_BITMAP : /* Send 1-bit bitmap data... */
1610 order = ColorOrders[PrinterPlanes - 1];
1611 bytes = header->cupsBytesPerLine / PrinterPlanes;
1612
1613 for (i = 0; i < PrinterPlanes; i ++)
1614 {
1615 plane = order[i];
1616
1617 CompressData(PixelBuffer + i * bytes, bytes, plane,
1618 (i < (PrinterPlanes - 1)) ? 'V' : 'W',
1619 header->cupsCompression);
1620 }
1621 break;
1622
1623 case OUTPUT_INVERBIT : /* Send inverted 1-bit bitmap data... */
1624 order = ColorOrders[PrinterPlanes - 1];
1625 bytes = header->cupsBytesPerLine / PrinterPlanes;
1626
1627 for (i = header->cupsBytesPerLine, ptr = PixelBuffer;
1628 i > 0;
1629 i --, ptr ++)
1630 *ptr = ~*ptr;
1631
1632 for (i = 0; i < PrinterPlanes; i ++)
1633 {
1634 plane = order[i];
1635
1636 CompressData(PixelBuffer + i * bytes, bytes, plane,
1637 (i < (PrinterPlanes - 1)) ? 'V' : 'W',
1638 header->cupsCompression);
1639 }
1640 break;
1641
1642 case OUTPUT_RGB : /* Send 24-bit RGB data... */
1643 if (PrinterPlanes == 1 && !BlankValue)
1644 {
1645 /*
1646 * Invert black to grayscale...
1647 */
1648
1649 for (i = header->cupsBytesPerLine, ptr = PixelBuffer;
1650 i > 0;
1651 i --, ptr ++)
1652 *ptr = ~*ptr;
1653 }
1654
1655 /*
1656 * Compress the output...
1657 */
1658
1659 CompressData(PixelBuffer, header->cupsBytesPerLine, 0, 'W',
1660 header->cupsCompression);
1661 break;
1662
1663 default :
1664 order = ColorOrders[PrinterPlanes - 1];
1665 width = header->cupsWidth;
1666
1667 for (i = 0, j = 0; i < PrinterPlanes; i ++)
1668 {
1669 plane = order[i];
1670 bytes = DotBufferSizes[plane] / DotBits[plane];
1671
1672 for (bit = 1, ptr = DotBuffers[plane];
1673 bit <= DotBits[plane];
1674 bit <<= 1, ptr += bytes, j ++)
1675 {
1676 cupsPackHorizontalBit(OutputBuffers[plane], DotBuffers[plane],
1677 width, 0, bit);
1678 CompressData(ptr, bytes, j,
1679 i == (PrinterPlanes - 1) &&
1680 bit == DotBits[plane] ? 'W' : 'V',
1681 header->cupsCompression);
1682 }
1683 }
1684 break;
1685 }
1686
1687 /*
1688 * The seed buffer, if any, now should contain valid data...
1689 */
1690
1691 SeedInvalid = 0;
1692 }
1693
1694
1695 /*
1696 * 'ReadLine()' - Read graphics from the page stream.
1697 */
1698
1699 int /* O - Number of lines (0 if blank) */
ReadLine(cups_raster_t * ras,cups_page_header2_t * header)1700 ReadLine(cups_raster_t *ras, /* I - Raster stream */
1701 cups_page_header2_t *header) /* I - Page header */
1702 {
1703 int plane, /* Current color plane */
1704 width; /* Width of line */
1705
1706
1707 /*
1708 * Read raster data...
1709 */
1710
1711 cupsRasterReadPixels(ras, PixelBuffer, header->cupsBytesPerLine);
1712
1713 /*
1714 * See if it is blank; if so, return right away...
1715 */
1716
1717 if (cupsCheckValue(PixelBuffer, header->cupsBytesPerLine, BlankValue))
1718 return (0);
1719
1720 /*
1721 * If we aren't dithering, return immediately...
1722 */
1723
1724 if (OutputMode != OUTPUT_DITHERED)
1725 return (1);
1726
1727 /*
1728 * Perform the color separation...
1729 */
1730
1731 width = header->cupsWidth;
1732
1733 switch (header->cupsColorSpace)
1734 {
1735 case CUPS_CSPACE_W :
1736 if (RGB)
1737 {
1738 cupsRGBDoGray(RGB, PixelBuffer, CMYKBuffer, width);
1739
1740 if (RGB->num_channels == 1)
1741 cupsCMYKDoBlack(CMYK, CMYKBuffer, InputBuffer, width);
1742 else
1743 cupsCMYKDoCMYK(CMYK, CMYKBuffer, InputBuffer, width);
1744 }
1745 else
1746 cupsCMYKDoGray(CMYK, PixelBuffer, InputBuffer, width);
1747 break;
1748
1749 case CUPS_CSPACE_K :
1750 cupsCMYKDoBlack(CMYK, PixelBuffer, InputBuffer, width);
1751 break;
1752
1753 default :
1754 case CUPS_CSPACE_RGB :
1755 if (RGB)
1756 {
1757 cupsRGBDoRGB(RGB, PixelBuffer, CMYKBuffer, width);
1758
1759 if (RGB->num_channels == 1)
1760 cupsCMYKDoBlack(CMYK, CMYKBuffer, InputBuffer, width);
1761 else
1762 cupsCMYKDoCMYK(CMYK, CMYKBuffer, InputBuffer, width);
1763 }
1764 else
1765 cupsCMYKDoRGB(CMYK, PixelBuffer, InputBuffer, width);
1766 break;
1767
1768 case CUPS_CSPACE_CMYK :
1769 cupsCMYKDoCMYK(CMYK, PixelBuffer, InputBuffer, width);
1770 break;
1771 }
1772
1773 /*
1774 * Dither the pixels...
1775 */
1776
1777 for (plane = 0; plane < PrinterPlanes; plane ++)
1778 cupsDitherLine(DitherStates[plane], DitherLuts[plane], InputBuffer + plane,
1779 PrinterPlanes, OutputBuffers[plane]);
1780
1781 /*
1782 * Return 1 to indicate that we have non-blank output...
1783 */
1784
1785 return (1);
1786 }
1787
1788
1789 /*
1790 * 'main()' - Main entry and processing of driver.
1791 */
1792
1793 int /* O - Exit status */
main(int argc,char * argv[])1794 main(int argc, /* I - Number of command-line arguments */
1795 char *argv[]) /* I - Command-line arguments */
1796 {
1797 int fd; /* File descriptor */
1798 int empty = 1;
1799 cups_raster_t *ras; /* Raster stream for printing */
1800 cups_page_header2_t header; /* Page header from file */
1801 int y; /* Current line */
1802 ppd_file_t *ppd; /* PPD file */
1803 int job_id; /* Job ID */
1804 int num_options; /* Number of options */
1805 cups_option_t *options; /* Options */
1806 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
1807 struct sigaction action; /* Actions for POSIX signals */
1808 #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
1809
1810
1811 /*
1812 * Make sure status messages are not buffered...
1813 */
1814
1815 setbuf(stderr, NULL);
1816
1817 /*
1818 * Check command-line...
1819 */
1820
1821 if (argc < 6 || argc > 7)
1822 {
1823 fprintf(stderr, "Usage: %s job-id user title copies options [file]\n",
1824 "rastertopclx");
1825 return (1);
1826 }
1827
1828 num_options = cupsParseOptions(argv[5], 0, &options);
1829
1830 /*
1831 * Open the PPD file...
1832 */
1833
1834 ppd = ppdOpenFile(getenv("PPD"));
1835
1836 if (ppd)
1837 {
1838 ppdMarkDefaults(ppd);
1839 cupsMarkOptions(ppd, num_options, options);
1840 }
1841 else
1842 {
1843 ppd_status_t status; /* PPD error */
1844 int linenum; /* Line number */
1845
1846 fputs("DEBUG: The PPD file could not be opened.\n", stderr);
1847
1848 status = ppdLastError(&linenum);
1849
1850 fprintf(stderr, "DEBUG: %s on line %d.\n", ppdErrorString(status), linenum);
1851 }
1852
1853 /*
1854 * Open the page stream...
1855 */
1856
1857 if (argc == 7)
1858 {
1859 if ((fd = open(argv[6], O_RDONLY)) == -1)
1860 {
1861 perror("ERROR: Unable to open raster file");
1862 return (1);
1863 }
1864 }
1865 else
1866 fd = 0;
1867
1868 ras = cupsRasterOpen(fd, CUPS_RASTER_READ);
1869
1870 /*
1871 * Register a signal handler to eject the current page if the
1872 * job is cancelled.
1873 */
1874
1875 Canceled = 0;
1876
1877 #ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
1878 sigset(SIGTERM, CancelJob);
1879 #elif defined(HAVE_SIGACTION)
1880 memset(&action, 0, sizeof(action));
1881
1882 sigemptyset(&action.sa_mask);
1883 action.sa_handler = CancelJob;
1884 sigaction(SIGTERM, &action, NULL);
1885 #else
1886 signal(SIGTERM, CancelJob);
1887 #endif /* HAVE_SIGSET */
1888
1889 /*
1890 * Process pages as needed...
1891 */
1892
1893 job_id = atoi(argv[1]);
1894
1895 Page = 0;
1896
1897 while (cupsRasterReadHeader2(ras, &header))
1898 {
1899 /*
1900 * Write a status message with the page number and number of copies.
1901 */
1902
1903 if (empty)
1904 empty = 0;
1905
1906 if (Canceled)
1907 break;
1908
1909 Page ++;
1910
1911 fprintf(stderr, "PAGE: %d %d\n", Page, header.NumCopies);
1912 fprintf(stderr, "INFO: Starting page %d.\n", Page);
1913
1914 StartPage(ppd, &header, atoi(argv[1]), argv[2], argv[3],
1915 num_options, options);
1916
1917 for (y = 0; y < (int)header.cupsHeight; y ++)
1918 {
1919 /*
1920 * Let the user know how far we have progressed...
1921 */
1922
1923 if (Canceled)
1924 break;
1925
1926 if ((y & 127) == 0)
1927 {
1928 fprintf(stderr, "INFO: Printing page %d, %d%% complete.\n",
1929 Page, 100 * y / header.cupsHeight);
1930 fprintf(stderr, "ATTR: job-media-progress=%d\n",
1931 100 * y / header.cupsHeight);
1932 }
1933
1934 /*
1935 * Read and write a line of graphics or whitespace...
1936 */
1937
1938 if (ReadLine(ras, &header))
1939 OutputLine(ppd, &header);
1940 else
1941 OutputFeed ++;
1942 }
1943
1944 /*
1945 * Eject the page...
1946 */
1947
1948 fprintf(stderr, "INFO: Finished page %d.\n", Page);
1949
1950 EndPage(ppd, &header);
1951
1952 if (Canceled)
1953 break;
1954 }
1955
1956 if (!empty)
1957 Shutdown(ppd, job_id, argv[2], argv[3], num_options, options);
1958
1959 cupsFreeOptions(num_options, options);
1960
1961 cupsRasterClose(ras);
1962
1963 if (fd != 0)
1964 close(fd);
1965
1966 if (empty)
1967 {
1968 fprintf(stderr, "DEBUG: Input is empty, outputting empty file.\n");
1969 return 0;
1970 }
1971 return (Page == 0);
1972 }
1973
1974