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