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_pcx.c: PCX converter part of project "hp2xx"
27  **
28  ** 91/01/19  V 1.00  HWW  Originating: Format accepted by MS-Paintbrush,
29  **                       but not by emTeX drivers
30  **                       Use MS-Paintbrush "load/save" for conversion
31  ** 91/02/15  V 1.01  HWW  VAX_C support added (not tested yet!)
32  ** 91/02/18  V 1.02  HWW  PCX format: no zero run length allowed
33  ** 91/02/20  V 1.03  HWW  Some VAX_C changes, debugged
34  ** 91/06/09  V 1.04  HWW  New options added
35  ** 91/06/16  V 1.05  HWW  Writing of PCX header now machine-independent
36  ** 91/10/15  V 1.06  HWW  ANSI_C
37  ** 91/10/25  V 1.07  HWW  VAX: fopen() augmentations used, open() removed
38  ** 92/05/17  V 1.07b HWW  Output to stdout if outfile == '-'
39  ** 92/05/19  V 1.07c HWW  Abort if color mode
40  ** 92/06/08  V 1.08a HWW  First color version
41  ** 93/11/22  V 1.10a HWW  Color version based on TO_PCL.C code. CLUT still
42  **                        inactive !?
43  ** 93/11/25  V 1.10b RF   PCX-Version set to 2: use palette info,
44  **                        colors corrected
45  ** 94/02/14  V 1.20a HWW  Adapted to changes in hp2xx.h
46  **
47  **           NOTE: According to my tests, setting of the
48  **                 color lookup table is ignored by other programs,
49  **                 so this code is *preliminary* when color is used.
50  **                 Correct colors appeared only if the color setting corresponded to
51  **                 PC conventions...
52  **
53  ** 00/03/05    3.4a  MK   Write PCX version 5 truecolor files in color mode,
54  **                        corrected(?) version 2 palette for b/w mode
55  **/
56 
57 
58 #include <stdio.h>
59 #include <stdlib.h>
60 #include "bresnham.h"
61 #include "pendef.h"
62 #include "hp2xx.h"
63 
64 
65 typedef enum { PCX_INIT, PCX_NORMAL, PCX_EXIT } PCXmode;
66 
67 
68 
69 
RLEcode_to_file(int c,int repeat,FILE * fd)70 static void RLEcode_to_file(int c, int repeat, FILE * fd)
71 {
72 	if ((repeat == 1) && ((c & 0xC0) != 0xC0)) {
73 		if (putc(c, fd) == EOF) {
74 			PError("RLEcode_to_file (1)");
75 			exit(ERROR);
76 		}
77 	} else {
78 		if (putc(repeat | 0xC0, fd) == EOF) {
79 			PError("RLEcode_to_file (2)");
80 			exit(ERROR);
81 		}
82 		if (putc(c, fd) == EOF) {
83 			PError("RLEcode_to_file (3)");
84 			exit(ERROR);
85 		}
86 	}
87 }
88 
89 
90 
91 
byte_to_PCX(Byte b,PCXmode mode,FILE * fd)92 static void byte_to_PCX(Byte b, PCXmode mode, FILE * fd)
93 {
94 	static Byte last_b;
95 	static int rept;
96 
97 	switch (mode) {
98 	case PCX_NORMAL:
99 		if (b == last_b) {
100 			if (++rept == 63) {
101 				RLEcode_to_file(last_b, rept, fd);
102 				rept = 0;
103 			}
104 		} else {
105 			if (rept)
106 				RLEcode_to_file(last_b, rept, fd);
107 			rept = 1;
108 			last_b = b;
109 		}
110 		break;
111 
112 	case PCX_INIT:
113 		rept = 0;
114 		last_b = -2;	/* Init to impossible value     */
115 		break;
116 
117 	case PCX_EXIT:
118 		if (rept) {
119 			RLEcode_to_file(last_b, rept, fd);
120 			rept = 0;
121 		}
122 		break;
123 	}
124 }
125 
126 
127 
128 
129 
130 typedef struct {
131 	char creator, version, encoding, bits;
132 	short xmin, ymin, xmax, ymax, hres, vres;
133 	unsigned char palette[16][3], vmode, planes;
134 	short byteperline, paletteinfo;
135 	short hscreensize, vscreensize;
136 	char dummy[54];
137 } PCXheader;
138 
139 
140 
start_PCX(const OUT_PAR * po,const GEN_PAR * pg,FILE * fd)141 static int start_PCX(const OUT_PAR * po, const GEN_PAR * pg, FILE * fd)
142 {
143 	PCXheader h;
144 	int i;
145 
146 	h.creator = 0x0A;	/* ZSoft label                  */
147 	if (po->picbuf->depth == 1)
148 		h.version = '\002';	/* V 2.8/3.0, with palette info */
149 	else
150 		h.version = '\005';	/* V5 24bit PCX                 */
151 	h.encoding = 1;		/* RLE                          */
152 	if (po->picbuf->depth == 1)
153 		h.bits = 1;	/* Bits per pixel               */
154 	else
155 		h.bits = 8;	/* Bits per pixel               */
156 	h.xmin = 0;		/* Range of bitmap              */
157 	h.ymin = 0;
158 	h.xmax = (short) (po->picbuf->nc - 1);
159 	h.ymax = (short) (po->picbuf->nr - 1);
160 	h.hres = (short) po->dpi_x;	/* Resolution                   */
161 	h.vres = (short) po->dpi_y;
162 
163 	if (po->picbuf->depth == 1) {
164 		h.palette[0][0] = 0;
165 		h.palette[0][1] = 0;
166 		h.palette[0][2] = 0;	/* white */
167 		h.palette[1][0] = 255;
168 		h.palette[1][1] = 255;
169 		h.palette[1][2] = 255;
170 		h.palette[2][0] = 0;
171 		h.palette[2][1] = 128;
172 		h.palette[2][2] = 0;
173 		h.palette[3][0] = 128;
174 		h.palette[3][1] = 128;
175 		h.palette[3][2] = 0;
176 		h.palette[4][0] = 0;
177 		h.palette[4][1] = 0;
178 		h.palette[4][2] = 128;
179 		h.palette[5][0] = 128;
180 		h.palette[5][1] = 0;
181 		h.palette[5][2] = 128;
182 		h.palette[6][0] = 0;
183 		h.palette[6][1] = 128;
184 		h.palette[6][2] = 128;
185 		h.palette[7][0] = 192;
186 		h.palette[7][1] = 192;
187 		h.palette[7][2] = 192;
188 		h.palette[8][0] = 0;
189 		h.palette[8][1] = 0;
190 		h.palette[8][2] = 0;	/*black */
191 		h.palette[9][0] = 255;
192 		h.palette[9][1] = 0;
193 		h.palette[9][2] = 0;	/* red */
194 		h.palette[10][0] = 0;
195 		h.palette[10][1] = 255;
196 		h.palette[10][2] = 0;	/* green */
197 		h.palette[11][0] = 255;
198 		h.palette[11][1] = 255;
199 		h.palette[11][2] = 0;
200 		h.palette[12][0] = 0;
201 		h.palette[12][1] = 0;
202 		h.palette[12][2] = 255;	/* blue */
203 		h.palette[13][0] = 255;
204 		h.palette[13][1] = 0;
205 		h.palette[13][2] = 255;
206 		h.palette[14][0] = 0;
207 		h.palette[14][1] = 255;
208 		h.palette[14][2] = 255;
209 		h.palette[15][0] = 255;
210 		h.palette[15][1] = 255;
211 		h.palette[15][2] = 255;
212 	} else
213 		for (i = 0; i < 16; i++) {
214 			h.palette[i][0] = 0;
215 			h.palette[i][1] = 0;
216 			h.palette[i][2] = 0;	/* white */
217 		}
218 
219 	h.vmode = 0;		/* Reserved                        */
220 /*  h.planes      = po->picbuf->depth; *//* Number of color planes         */
221 	if (po->picbuf->depth == 1) {
222 		h.planes = 1;
223 		h.byteperline = (short) po->picbuf->nb;
224 	} else {
225 		h.byteperline = (short) (8 * po->picbuf->nb);	/* Number of bytes per line   */
226 		h.planes = 3;
227 	}
228 	h.paletteinfo = 1;	/* 1 = color & b/w, 2 = gray scale */
229 	h.hscreensize = (short) (po->picbuf->nc - 1);	/* Horizontal screen size in pixels */
230 	h.vscreensize = (short) (po->picbuf->nr - 1);	/* Vertical screen size in pixels */
231 	for (i = 0; i < 54;) {	/* Filler for a max. of 128 bytes  */
232 		h.dummy[i++] = '\0';
233 		h.dummy[i++] = '\0';
234 	}
235 
236 /**
237  ** For complete machine independence, a bytewise writing of this header
238  ** is mandatory. Else, fill bytes or HIGH/LOW-endian machines must be
239  ** considered. A simple "fwrite(h,128,1,fd)" may not suffice!
240  **/
241 
242 	if (fputc(h.creator, fd) == EOF)
243 		goto ERROR_EXIT;
244 	if (fputc(h.version, fd) == EOF)
245 		goto ERROR_EXIT;
246 	if (fputc(h.encoding, fd) == EOF)
247 		goto ERROR_EXIT;
248 	if (fputc(h.bits, fd) == EOF)
249 		goto ERROR_EXIT;
250 	if (fputc((h.xmin & 0xff), fd) == EOF)
251 		goto ERROR_EXIT;
252 	if (fputc((h.xmin >> 8), fd) == EOF)
253 		goto ERROR_EXIT;
254 	if (fputc((h.ymin & 0xff), fd) == EOF)
255 		goto ERROR_EXIT;
256 	if (fputc((h.ymin >> 8), fd) == EOF)
257 		goto ERROR_EXIT;
258 	if (fputc((h.xmax & 0xff), fd) == EOF)
259 		goto ERROR_EXIT;
260 	if (fputc((h.xmax >> 8), fd) == EOF)
261 		goto ERROR_EXIT;
262 	if (fputc((h.ymax & 0xff), fd) == EOF)
263 		goto ERROR_EXIT;
264 	if (fputc((h.ymax >> 8), fd) == EOF)
265 		goto ERROR_EXIT;
266 	if (fputc((h.hres & 0xff), fd) == EOF)
267 		goto ERROR_EXIT;
268 	if (fputc((h.hres >> 8), fd) == EOF)
269 		goto ERROR_EXIT;
270 	if (fputc((h.vres & 0xff), fd) == EOF)
271 		goto ERROR_EXIT;
272 	if (fputc((h.vres >> 8), fd) == EOF)
273 		goto ERROR_EXIT;
274 	if (fwrite((VOID *) h.palette, 48, 1, fd) != 1)
275 		goto ERROR_EXIT;
276 	if (fputc(h.vmode, fd) == EOF)
277 		goto ERROR_EXIT;
278 	if (fputc(h.planes, fd) == EOF)
279 		goto ERROR_EXIT;
280 	if (fputc((h.byteperline & 0xff), fd) == EOF)
281 		goto ERROR_EXIT;
282 	if (fputc((h.byteperline >> 8), fd) == EOF)
283 		goto ERROR_EXIT;
284 	if (fputc((h.paletteinfo & 0xff), fd) == EOF)
285 		goto ERROR_EXIT;
286 	if (fputc((h.paletteinfo >> 8), fd) == EOF)
287 		goto ERROR_EXIT;
288 	if (fwrite((VOID *) h.dummy, 58, 1, fd) != 1)
289 		goto ERROR_EXIT;
290 	return 0;
291 
292       ERROR_EXIT:
293 	PError("start_PCX");
294 	return ERROR;
295 }
296 
297 
298 
Buf_to_PCX(Byte * pb,int nb,FILE * fd)299 static void Buf_to_PCX(Byte * pb, int nb, FILE * fd)
300 {
301 	int x;
302 
303 	byte_to_PCX(0, PCX_INIT, fd);
304 	for (x = 0; x < nb; x++)
305 		byte_to_PCX(~*pb++, PCX_NORMAL, fd);
306 	byte_to_PCX(0, PCX_EXIT, fd);	/* Flush        */
307 }
308 
309 
310 
PicBuf_to_PCX(const GEN_PAR * pg,const OUT_PAR * po)311 int PicBuf_to_PCX(const GEN_PAR * pg, const OUT_PAR * po)
312 {
313 	FILE *fd = NULL;
314 	RowBuf *row = NULL;
315 	int row_c, x, color_index, err;
316 	Byte *p_R = NULL, *p_G = NULL, *p_B = NULL, *p_I = NULL;
317 
318 	err = 0;
319 	if (!pg->quiet)
320 		Eprintf("\nWriting PCX output\n");
321 	if (*po->outfile != '-') {
322 #ifdef VAX
323 		if ((fd =
324 		     fopen(po->outfile, WRITE_BIN, "rfm=var",
325 			   "mrs=512")) == NULL) {
326 #else
327 		if ((fd = fopen(po->outfile, WRITE_BIN)) == NULL) {
328 #endif
329 			PError("hp2xx -- opening output file");
330 			return ERROR;
331 		}
332 	} else
333 		fd = stdout;
334 
335 	if (start_PCX(po, pg, fd)) {
336 		err = ERROR;
337 		goto PCX_exit;
338 	}
339 #if 0
340 	/* Backward since highest index is lowest line on screen! */
341 	for (row_c = po->picbuf->nr - 1; row_c >= 0; row_c--) {
342 		if ((!pg->quiet) && (row_c % 10 == 0))
343 			/* For the impatient among us ...     */
344 			Eprintf(".");
345 		row = get_RowBuf(po->picbuf, row_c);
346 		byte_to_PCX(0, PCX_INIT, fd);
347 		pb = row->buf;
348 /*	for (np=0; np < picbuf->depth; np++)*/
349 		for (np = 0; np < h.planes; np++)
350 			for (x = 0; x < po->picbuf->nb; x++)
351 				byte_to_PCX(~*pb++, PCX_NORMAL, fd);
352 		byte_to_PCX(0, PCX_EXIT, fd);	/* Flush        */
353 	}
354 #endif
355 
356   /**
357    ** Allocate buffers for temporary conversion
358    **/
359 	if (po->picbuf->depth > 1) {
360 		p_I = calloc((size_t) (po->picbuf->nb), 8 * sizeof(Byte));
361 		p_B = calloc((size_t) (po->picbuf->nb), 8 * sizeof(Byte));
362 		p_G = calloc((size_t) (po->picbuf->nb), 8 * sizeof(Byte));
363 		p_R = calloc((size_t) (po->picbuf->nb), 8 * sizeof(Byte));
364 		if (p_I == NULL || p_B == NULL || p_G == NULL
365 		    || p_R == NULL) {
366 			Eprintf
367 			    ("\nCannot 'calloc' color conversion memory -- sorry, use B/W!\n");
368 			err = ERROR;
369 			goto PCX_exit;
370 		}
371 	}
372   /**
373    ** Loop for all rows:
374    ** Counting back since highest index is lowest line on paper...
375    **/
376 
377 	for (row_c = po->picbuf->nr - 1; row_c >= 0; row_c--) {
378 		if ((!pg->quiet) && (row_c % 10 == 0))
379 			/* For the impatients among us ...    */
380 			Eprintf(".");
381 /*fprintf(stderr,"coverting row %d (%d bytes)\n",row_c,po->picbuf->nb);*/
382 		row = get_RowBuf(po->picbuf, row_c);
383 		byte_to_PCX(0, PCX_INIT, fd);
384 
385 		if (po->picbuf->depth == 1)
386 			Buf_to_PCX(row->buf, po->picbuf->nb, fd);
387 		else {
388 			for (x = 0; (x < po->picbuf->nb << 3); x++) {
389 				p_I[x] = p_R[x] = p_G[x] = p_B[x] = 0;
390 
391 				color_index =
392 				    index_from_RowBuf(row, x, po->picbuf);
393 /*fprintf(stderr,"color_index= %d\n",color_index);   */
394 				p_R[x] =
395 				    (Byte) (255 - pt.clut[color_index][0]);
396 				p_G[x] =
397 				    (Byte) (255 - pt.clut[color_index][1]);
398 				p_B[x] =
399 				    (Byte) (255 - pt.clut[color_index][2]);
400 /*
401 	p_R[x] = 255-pt.clut(color_index,R) ;
402 	p_G[x] = 255-pt.clut(color_index,G) ;
403 	p_B[x] = 255-pt.clut(color_index,B) ;
404 */
405 			}
406 /*
407 for (x=0; x < po->picbuf->nb; x++)fprintf(stderr,"%d%d%d\n",p_R[x],p_G[x],p_B[x]);
408 */
409 			Buf_to_PCX(p_R, 8 * po->picbuf->nb, fd);
410 			Buf_to_PCX(p_G, 8 * po->picbuf->nb, fd);
411 			Buf_to_PCX(p_B, 8 * po->picbuf->nb, fd);
412 /*		Buf_to_PCX (p_I, 8*po->picbuf->nb, fd);*/
413 		}
414 	}
415 	if (!pg->quiet)
416 		Eprintf("\n");
417 
418       PCX_exit:
419 	if (fd != stdout)
420 		fclose(fd);
421 
422 	if (p_R != NULL)
423 		free(p_R);
424 	if (p_G != NULL)
425 		free(p_G);
426 	if (p_B != NULL)
427 		free(p_B);
428 	if (p_I != NULL)
429 		free(p_I);
430 	return err;
431 }
432