1 /*
2 Copyright (c) 1991 - 1994 Heinz W. Werntges. All rights reserved.
3 Parts Copyright (c) 1999 Martin Kroeker All rights reserved.
4
5 Distributed by Free Software Foundation, Inc.
6
7 This file is part of HP2xx.
8
9 HP2xx is distributed in the hope that it will be useful, but
10 WITHOUT ANY WARRANTY. No author or distributor accepts responsibility
11 to anyone for the consequences of using it or for whether it serves any
12 particular purpose or works at all, unless he says so in writing. Refer
13 to the GNU General Public License, Version 2 or later, for full details.
14
15 Everyone is granted permission to copy, modify and redistribute
16 HP2xx, but only under the conditions described in the GNU General Public
17 License. A copy of this license is supposed to have been
18 given to you along with HP2xx so you can know your rights and
19 responsibilities. It should be in a file named COPYING. Among other
20 things, the copyright notice and this notice must be preserved on all
21 copies.
22
23 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
24 */
25
26 /** to_pcl.c: PCL converter part of project "hp2xx"
27 **
28 ** 91/01/19 V 1.00 HWW Reorganized
29 ** 91/01/29 V 1.01 HWW Tested on SUN
30 ** 91/02/01 V 1.02 HWW Deskjet specials acknowledged
31 ** 91/02/15 V 1.03 HWW VAX_C support added
32 ** 91/02/20 V 1.04b HWW x & y positioning: Now absolute!
33 ** Some VAX_C changes
34 ** 91/06/09 V 1.05 HWW New options added
35 ** 91/10/15 V 1.06 HWW ANSI_C
36 ** 91/10/25 V 1.07 HWW VAX: fopen() augmentations used, open() removed
37 ** 92/05/17 V 1.07b HWW Output to stdout if outfile == '-'
38 ** 92/05/19 V 1.07c HWW Abort if color mode
39 ** 92/12/23 V 1.08a HWW Color for Deskjet (beginning)
40 ** 93/04/02 V 1.08b HWW DotBlock --> Byte
41 ** 93/04/13 V 1.09a HWW CMYK supported
42 ** 93/04/25 V 1.09b HWW End-of-raster-graphics code fixed: now ESC*rbC
43 ** This conforms with DJ550C doc. I hope it is
44 ** still compatible with other DJ models.
45 ** Please tell me if not -- I don't have all doc's.
46 ** 93/07/18 V 1.10a HWW TIFF compression
47 ** 94/01/01 V 1.10b HWW init_printer(), start_graphmode():
48 ** L. Lowe's modifications
49 ** 94/02/14 V 1.20a HWW Adapted to changes in hp2xx.h
50 ** 97/12/1 MK add initialization code for A3 paper size
51 ** 99/05/10 RS/MK autoselect A4/A3/A2 paper, reduce margins
52 **/
53
54 #include <stdio.h>
55 #include <stdlib.h>
56 #include "bresnham.h"
57 #include "pendef.h"
58 #include "hp2xx.h"
59
60
61
62 #define PCL_FIRST 1 /* Bit mask! */
63 #define PCL_LAST 2 /* Bit mask! */
64
65
66 /**
67 ** Used for compression ON/off switch:
68 **/
69 static int Deskjet_specials = FALSE;
70
71
72 /**
73 ** Buffers for color treatment
74 **/
75 static Byte *p_K, *p_C, *p_M, *p_Y; /* Buffer ptrs (CMYK bits) */
76
77
78
79 /**
80 ** Data & functions for (TIFF) compression:
81 **
82 ** Note: Usually, the buffer p_B receives less data than the
83 ** original (i.e., < nb). However, "temporary" increases
84 ** are possible. To allow for them, we allocate a few extra bytes.
85 ** If the buffer eventually really grows, we won't use compression!
86 ** "n_B" keeps track of the amount of extra buffer space left.
87 **/
88 #define B_EXTRASPACE 16
89 static Byte *p_B; /* Buffer for compression */
90 static int n_B; /* Counter for extra space */
91
92
93
94
TIFF_n_repeats(Byte * p1,int nb)95 static int TIFF_n_repeats(Byte * p1, int nb)
96 /**
97 ** There are "nb" bytes in buffer "p1"
98 ** Return number of identical bytes in a sequence (0, 2 ... nb)
99 **/
100 {
101 int i;
102 Byte *p2;
103
104 p2 = p1 + 1;
105 if (nb < 2 || *p2 != *p1)
106 return 0;
107 for (i = 1; i < nb && *p1 == *p2; p1++, p2++)
108 i++;
109 return i;
110 }
111
112
113
TIFF_n_irregs(Byte * p1,int nb)114 static int TIFF_n_irregs(Byte * p1, int nb)
115 /**
116 ** There are "nb" bytes in buffer "p1"
117 ** Return number of irregular (non-identical) bytes
118 ** in a sequence (0, 1, 2 ... nb)
119 **/
120 {
121 int i;
122 Byte *p2;
123
124 if (nb < 2)
125 return nb; /* 0 or 1 */
126 p2 = p1 + 1;
127 for (i = 1; i < nb && *p1 != *p2; p1++, p2++)
128 i++;
129 return (i == nb) ? nb : i - 1;
130 }
131
132
133
TIFF_compress(Byte * src,Byte * dst,int nb)134 static int TIFF_compress(Byte * src, Byte * dst, int nb)
135 {
136 /**
137 ** Either there is a block of repetitions or non-repeating bytes
138 ** at the buffer start. If repetitions, compress them. If not,
139 ** buffer them and compress next block of repetitions.
140 **/
141 int i, l, count = 0;
142
143 l = TIFF_n_repeats(src, nb); /* l == 0 or l >= 2 */
144 while (l > 128) {
145 *dst++ = (-127); /* 128 repetitions */
146 *dst++ = *src;
147 count += 2;
148 l -= 128;
149 nb -= 128;
150 src += 128;
151 n_B += 126; /* 128 bytes coded as 2 */
152
153 }
154 if (l > 0) {
155 *dst++ = (Byte) (1 - l); /* l repetitions */
156 *dst++ = *src;
157 count += 2;
158 src += l;
159 nb -= l;
160 n_B += (l - 2); /* l bytes coded as 2 */
161 }
162
163 if (nb < 0)
164 return -1; /* should never happen */
165 if (nb == 0)
166 return count; /* "count" bytes buffered */
167
168
169 /* Irregular sequence */
170
171 l = TIFF_n_irregs(src, nb); /* l == 0 or l >= 2 */
172 while (l > 128) {
173 n_B -= 1;
174 if (n_B < 0)
175 return -1; /* Buffer overflow! */
176
177 *dst++ = 127; /* 128 repetitions */
178 for (i = 0; i < 128; i++)
179 *dst++ = *src++;
180 count += 129;
181 l -= 128;
182 nb -= 128;
183
184 }
185 if (l > 0) {
186 n_B -= 1;
187 if (n_B < 0)
188 return -1; /* Buffer overflow! */
189
190 *dst++ = (Byte) (l - 1); /* l repetitions */
191 for (i = 0; i < l; i++)
192 *dst++ = *src++;
193 count += (l + 1);
194 nb -= l;
195 }
196
197 if (nb < 0)
198 return -1; /* should never happen */
199
200 if (nb == 0) { /* At end-of-buffer: evaluate */
201 if (n_B > B_EXTRASPACE) /* Regular exit: Return */
202 return count; /* number of compressed bytes */
203 else
204 return -1; /* Nothing gained ! */
205 }
206 i = TIFF_compress(src, dst, nb); /* Recursion for rest */
207 return (i == -1) ? -1 : i + count;
208 }
209
210
211
212 /**
213 ** PCL data compression method #2 (TIFF)
214 **
215 ** Compress data in buf; leave compressed data there.
216 ** Return number of valid bytes in buf of OK.
217 ** Return -1 if no compression done.
218 **/
219
compress_buf_TIFF(Byte * buf,int nb)220 static int compress_buf_TIFF(Byte * buf, int nb)
221 {
222 if (Deskjet_specials == FALSE)
223 return -1; /* Plain PLC L3 does not support compression! */
224
225 if (p_B == NULL) /* No buffer for compression! */
226 return -1;
227
228 n_B = B_EXTRASPACE; /* Init. extra space counter */
229 return TIFF_compress(buf, p_B, nb); /* Recursive function! */
230 }
231
232
233
234
Buf_to_PCL(Byte * buf,int nb,int mode,FILE * fd)235 static void Buf_to_PCL(Byte * buf, int nb, int mode, FILE * fd)
236 /**
237 ** Output the raw bit stream
238 ** (This should be an ideal place for data compression)
239 **/
240 {
241 int ncb; /* Number of compressed bytes */
242 Byte *p; /* Buffer pointer */
243
244 if (mode & PCL_FIRST)
245 fprintf(fd, "\033*b");
246
247 ncb = compress_buf_TIFF(buf, nb);
248 if (ncb == -1) {
249 ncb = nb;
250 p = buf; /* Use original buffer & length */
251 fprintf(fd, "0m"); /* No compression */
252 } else {
253 p = p_B; /* Use compression buffer */
254 fprintf(fd, "2m"); /* Compression method 2 (TIFF) */
255 }
256
257 if (mode & PCL_LAST)
258 fprintf(fd, "%dW", ncb);
259 else
260 fprintf(fd, "%dv", ncb);
261
262 /* Following change keeps the VAX people happy: */
263 /*fwrite (p, 1, ncb, fd); */
264 (void) fwrite(p, (size_t) ncb, 1, fd);
265 }
266
267
268
269
KCMY_Buf_to_PCL(int nb,int is_KCMY,FILE * fd)270 static void KCMY_Buf_to_PCL(int nb, int is_KCMY, FILE * fd)
271 {
272 if (is_KCMY) {
273 Buf_to_PCL(p_K, nb, PCL_FIRST, fd);
274 Buf_to_PCL(p_C, nb, 0, fd);
275 } else /* is only CMY: */
276 Buf_to_PCL(p_C, nb, PCL_FIRST, fd);
277
278 Buf_to_PCL(p_M, nb, 0, fd);
279 Buf_to_PCL(p_Y, nb, PCL_LAST, fd);
280 }
281
282
283
284
KCMY_to_K(int nb)285 static void KCMY_to_K(int nb)
286 /**
287 ** Color -> B/W conversion:
288 ** Any set bit will show up black
289 **/
290 {
291 int i;
292 Byte *pK = p_K, *pC = p_C, *pM = p_M, *pY = p_Y;
293
294 for (i = 0; i < nb; i++)
295 *pK++ |= ((*pC++ | *pM++) | *pY++);
296 }
297
298
299
300
K_to_CMY(int nb)301 static void K_to_CMY(int nb)
302 /**
303 ** CMYK-to-CMY conversion:
304 ** Any set bit in the "black" layer sets all C,M,Y bits to emulate "black"
305 **/
306 {
307 int i;
308 Byte *pK = p_K, *pC = p_C, *pM = p_M, *pY = p_Y;
309
310 for (i = 0; i < nb; i++, pK++) {
311 *pC++ |= *pK;
312 *pM++ |= *pK;
313 *pY++ |= *pK;
314 }
315 }
316
317
318
319
init_printer(const OUT_PAR * po,FILE * fd)320 static void init_printer(const OUT_PAR * po, FILE * fd)
321 {
322 int size;
323
324
325 size = 26; /* default to A4 paper */
326
327 if ((po->width >= po->height
328 && (po->width > 297. || po->height > 210.))
329 || (po->width < po->height
330 && (po->height > 297. || po->width > 210.)))
331 size = 27; /* A3 format */
332
333 if ((po->width >= po->height
334 && (po->width > 420. || po->height > 297.))
335 || (po->width < po->height
336 && (po->height > 420. || po->width > 297.)))
337 size = 28; /* A2 format */
338
339 if ((po->width >= po->height
340 && (po->width > 584. || po->height > 420.))
341 || (po->width < po->height
342 && (po->height > 584. || po->width > 420.)))
343 size = 29; /* A1 format */
344
345
346 if ((po->width >= po->height
347 && (po->width > 820. || po->height > 584.))
348 || (po->width < po->height
349 && (po->height > 820. || po->width > 584.)))
350 size = 30; /* A0 format :-) */
351
352
353 /* \033E reset printer */
354 /* \033&l26A select paper size */
355 /* \033&l0L perforation skip off */
356 /* \033&l0E no top margin */
357 /* \0339 no side margins */
358 /* \033&a0V vertical position 0 */
359 if (po->init_p3gui) {
360 fprintf(fd, "%crbC%cE", ESC, ESC);
361 fprintf(fd, "%c%%-12345X@PJL ENTER LANGUAGE=PCL3GUI\n",
362 ESC);
363
364 fprintf(fd, "%c&l%dA%c&l0L%c&l0E%c*o0M%c*o2D", ESC, size,
365 ESC, ESC, ESC, ESC);
366 } else
367 fprintf(fd, "%cE%c&l%dA%c&l0L%c&l0E%c9%c&a0V", ESC, ESC,
368 size, ESC, ESC, ESC, ESC);
369 }
370
371
372
373
374
start_graphmode(const OUT_PAR * po,FILE * fd)375 static void start_graphmode(const OUT_PAR * po, FILE * fd)
376 {
377 typedef struct init_s {
378 unsigned char a[26];
379 } init_t;
380 init_t init = { {0x02, 0x04, 0x01, 0x2c, 0x01, 0x2c, 0x00, 0x02,
381 0x01, 0x2c, 0x01, 0x2c, 0x00, 0x02,
382 0x01, 0x2c, 0x01, 0x2c, 0x00, 0x02,
383 0x01, 0x2c, 0x01, 0x2c, 0x00, 0x02}
384 };
385 typedef struct init_bw {
386 unsigned char a[8];
387 } init_tb;
388 init_tb init_bw =
389 { {0x02, 0x04, 0x01, 0x2c, 0x01, 0x2c, 0x00, 0x02} };
390
391 /**
392 ** X & Y offsets: Use "decipoints" as unit to stick to PCL level 3
393 ** 1 dpt = 0.1 pt = 1/720 in
394 **/
395 if (po->yoff != 0.0)
396 fprintf(fd, "\033&a+%dV", (int) (po->yoff * 720.0 / 25.4));
397 if (po->xoff != 0.0)
398 fprintf(fd, "\033&a+%dH", (int) (po->xoff * 720.0 / 25.4));
399 /**
400 ** Set Graphics Resolution (300 / 150 / 100 / 75):
401 ** This is NO PCL level 3 feature, but LaserjetII and compatibles
402 ** seem to accept it.
403 **/
404 fprintf(fd, "\033*t%dR", po->dpi_x);
405
406 /**
407 ** Set Raster Width (in dots)
408 ** Deskjet feature, good for saving internal memory!
409 **/
410 if (po->specials) {
411 fprintf(fd, "\033*r%dS", po->picbuf->nc);
412 if (po->init_p3gui)
413 fprintf(fd, "\033*r%dT", po->picbuf->nr);
414
415 switch (po->specials) {
416 case 4: /* KCMY */
417 if (po->init_p3gui) {
418 if (po->dpi_x == 600) { /* update resolution info in colorplane data */
419 init.a[2] = 0x02;
420 init.a[3] = 0x58;
421 init.a[4] = 0x02;
422 init.a[5] = 0x58;
423 init.a[8] = 0x02;
424 init.a[9] = 0x58;
425 init.a[10] = 0x02;
426 init.a[11] = 0x58;
427 init.a[14] = 0x02;
428 init.a[15] = 0x58;
429 init.a[16] = 0x02;
430 init.a[17] = 0x58;
431 init.a[20] = 0x02;
432 init.a[21] = 0x58;
433 init.a[22] = 0x02;
434 init.a[23] = 0x58;
435 }
436 fprintf(fd, "\033*g%dW",
437 (int) sizeof(init));
438 (void) fwrite(init.a,
439 sizeof(unsigned char),
440 sizeof(init.a), fd);
441 }
442 fprintf(fd, "\033*r-4U");
443 break;
444 case 3: /* CMY */
445 fprintf(fd, "\033*r-3U");
446 break;
447 default: /* Single color plane */
448 if (po->init_p3gui) {
449 if (po->dpi_x == 600) { /* update resolution info in colorplane data */
450 init_bw.a[2] = 0x02;
451 init_bw.a[3] = 0x58;
452 init_bw.a[4] = 0x02;
453 init_bw.a[5] = 0x58;
454 }
455 fprintf(fd, "\033*g%dW",
456 (int) sizeof(init_bw));
457 (void) fwrite(init_bw.a,
458 sizeof(unsigned char),
459 sizeof(init_bw.a), fd);
460 }
461 fprintf(fd, "\033*r1U");
462 break;
463 }
464 }
465
466 if (po->init_p3gui) {
467 fprintf(fd, "\033*p%ddY", 0);
468 fprintf(fd, "\033*p%ddX", 0);
469 }
470 /**
471 ** Start Raster Graphics at current position
472 ** This is NO PCL level 3 feature, but LaserjetII and compatibles
473 ** seem to accept it.
474 **/
475 fprintf(fd, "\033*r1A");
476 }
477
478
479
480
end_graphmode(FILE * fd)481 static void end_graphmode(FILE * fd)
482 {
483 /**
484 ** End Raster Graphics
485 **/
486 fprintf(fd, "\033*rbC");
487 }
488
489
490
491
492
PicBuf_to_PCL(const GEN_PAR * pg,const OUT_PAR * po)493 int PicBuf_to_PCL(const GEN_PAR * pg, const OUT_PAR * po)
494 /**
495 ** Main interface routine
496 **/
497 {
498 FILE *fd = stdout;
499 RowBuf *row;
500 int row_c, i, x, color_index, offset, err;
501 Byte mask;
502
503 err = 0;
504 if (!pg->quiet)
505 Eprintf("\nWriting PCL output\n");
506
507 if (po->picbuf->depth > 1 && po->specials < 3)
508 Eprintf
509 ("\nWARNING: Monochrome output despite active colors selected!\n");
510
511 Deskjet_specials = (po->specials != 0) ? TRUE : FALSE;
512
513 /**
514 ** Allocate buffers for CMYK conversion
515 **/
516 if (po->picbuf->depth > 1) {
517 p_K = calloc((size_t) po->picbuf->nb, sizeof(Byte));
518 p_C = calloc((size_t) po->picbuf->nb, sizeof(Byte));
519 p_M = calloc((size_t) po->picbuf->nb, sizeof(Byte));
520 p_Y = calloc((size_t) po->picbuf->nb, sizeof(Byte));
521 if (p_K == NULL || p_C == NULL || p_M == NULL
522 || p_Y == NULL) {
523 Eprintf
524 ("\nCannot 'calloc' CMYK memory -- sorry, use B/W!\n");
525 goto PCL_exit;
526 }
527 }
528 /**
529 ** Optional memory; for compression
530 **/
531 n_B = B_EXTRASPACE;
532 p_B = calloc((size_t) (po->picbuf->nb + n_B), sizeof(Byte));
533
534
535 if (*po->outfile != '-') {
536 #ifdef VAX
537 if ((fd =
538 fopen(po->outfile, WRITE_BIN, "rfm=var",
539 "mrs=512")) == NULL) {
540 #else
541 if ((fd = fopen(po->outfile, WRITE_BIN)) == NULL) {
542 #endif
543 PError("hp2xx -- opening output file");
544 goto PCL_exit;
545 }
546 }
547
548 if (po->init_p)
549 init_printer(po, fd);
550
551 start_graphmode(po, fd);
552
553 /**
554 ** Loop for all rows:
555 ** Counting back since highest index is lowest line on paper...
556 **/
557
558 for (row_c = po->picbuf->nr - 1; row_c >= 0; row_c--) {
559 if ((!pg->quiet) && (row_c % 10 == 0))
560 /* For the impatients among us ... */
561 Eprintf(".");
562
563 row = get_RowBuf(po->picbuf, row_c);
564
565 if (po->picbuf->depth == 1)
566 Buf_to_PCL(row->buf, po->picbuf->nb,
567 PCL_FIRST | PCL_LAST, fd);
568 else {
569 for (x = 0; x < po->picbuf->nb; x++)
570 p_K[x] = p_C[x] = p_M[x] = p_Y[x] = 0;
571
572 for (x = offset = 0; x < (po->picbuf->nb << 3);
573 x++, offset = (x >> 3)) {
574 color_index =
575 index_from_RowBuf(row, x, po->picbuf);
576
577 if (color_index == xxBackground)
578 continue;
579 else {
580 mask = 0x80;
581 if ((i = x & 0x07) != 0)
582 mask >>= i;
583
584 if (pt.clut[color_index][0] +
585 pt.clut[color_index][1] +
586 pt.clut[color_index][2] == 0) {
587 *(p_K + offset) |= mask;
588 } else {
589 *(p_C + offset) |=
590 (mask ^
591 (pt.
592 clut[color_index][0]
593 & mask));
594 *(p_M + offset) |=
595 (mask ^
596 (pt.
597 clut[color_index][1]
598 & mask));
599 *(p_Y + offset) |=
600 (mask ^
601 (pt.
602 clut[color_index][2]
603 & mask));
604 }
605 /*
606 switch (color_index)
607 {
608 case xxForeground:
609 *(p_K + offset) |= mask;
610 break;
611 case xxRed:
612 *(p_M + offset) |= mask;
613 *(p_Y + offset) |= mask;
614 break;
615 case xxGreen:
616 *(p_C + offset) |= mask;
617 *(p_Y + offset) |= mask;
618 break;
619 case xxBlue:
620 *(p_C + offset) |= mask;
621 *(p_M + offset) |= mask;
622 break;
623 case xxCyan:
624 *(p_C + offset) |= mask;
625 break;
626 case xxMagenta:
627 *(p_M + offset) |= mask;
628 break;
629 case xxYellow:
630 *(p_Y + offset) |= mask;
631 break;
632 default:
633 break;
634 }
635 */
636 }
637 }
638
639 switch (po->specials) {
640 case 3:
641 K_to_CMY(po->picbuf->nb);
642 /* drop thru */
643 case 4:
644 KCMY_Buf_to_PCL(po->picbuf->nb,
645 (po->specials == 4), fd);
646 break;
647 default:
648 KCMY_to_K(po->picbuf->nb);
649 Buf_to_PCL(p_K, po->picbuf->nb,
650 PCL_FIRST | PCL_LAST, fd);
651 break;
652 }
653 }
654 }
655
656 end_graphmode(fd);
657 if (po->formfeed)
658 putc(FF, fd);
659 if (!pg->quiet)
660 Eprintf("\n");
661 if (fd != stdout)
662 fclose(fd);
663
664 PCL_exit:
665 if (p_Y != NULL)
666 free(p_Y);
667 if (p_M != NULL)
668 free(p_M);
669 if (p_C != NULL)
670 free(p_C);
671 if (p_K != NULL)
672 free(p_K);
673
674 if (p_B != NULL)
675 free(p_B);
676
677 p_K = p_C = p_M = p_Y = NULL;
678 return err;
679 }
680