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