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