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