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
54
55 #include <stdio.h>
56 #include <stdlib.h>
57 #include "bresnham.h"
58 #include "hp2xx.h"
59
60
61 typedef enum {PCX_INIT, PCX_NORMAL, PCX_EXIT}
62 PCXmode;
63
64
65
66
67 static void
RLEcode_to_file(int c,int repeat,FILE * fd)68 RLEcode_to_file (int c, int repeat, FILE *fd)
69 {
70 if ((repeat==1) && ((c & 0xC0) != 0xC0))
71 {
72 if (putc (c, fd) == EOF)
73 {
74 PError("RLEcode_to_file (1)");
75 exit (ERROR);
76 }
77 }
78 else
79 {
80 if (putc (repeat | 0xC0, fd) == EOF)
81 {
82 PError("RLEcode_to_file (2)");
83 exit (ERROR);
84 }
85 if (putc (c, fd) == EOF)
86 {
87 PError("RLEcode_to_file (3)");
88 exit (ERROR);
89 }
90 }
91 }
92
93
94
95
96 static void
byte_to_PCX(Byte b,PCXmode mode,FILE * fd)97 byte_to_PCX (Byte b, PCXmode mode, FILE *fd)
98 {
99 static int last_b, rept;
100
101 switch (mode)
102 {
103 case PCX_NORMAL:
104 if (b == last_b)
105 {
106 if (++rept == 63)
107 {
108 RLEcode_to_file (last_b, rept, fd);
109 rept = 0;
110 }
111 }
112 else
113 {
114 if (rept)
115 RLEcode_to_file (last_b, rept, fd);
116 rept = 1;
117 last_b = b;
118 }
119 break;
120
121 case PCX_INIT:
122 rept = 0;
123 last_b = -2; /* Init to impossible value */
124 break;
125
126 case PCX_EXIT:
127 if (rept)
128 {
129 RLEcode_to_file (last_b, rept, fd);
130 rept = 0;
131 }
132 break;
133 }
134 }
135
136
137
138
139
140 typedef struct {
141 char creator, version, encoding, bits;
142 short xmin, ymin, xmax, ymax, hres, vres;
143 char palette[16][3], vmode, planes;
144 short byteperline, paletteinfo;
145 char dummy[58];
146 } PCXheader;
147
148
149
150 static int
start_PCX(const OUT_PAR * po,const GEN_PAR * pg,FILE * fd)151 start_PCX (const OUT_PAR *po, const GEN_PAR *pg, FILE *fd)
152 {
153 PCXheader h;
154 int i , j ;
155
156 h.creator = 0x0A; /* ZSoft label */
157 h.version = '\002'; /* V 2.8/3.0, with palette info */
158 h.encoding = 1; /* RLE */
159 h.bits = 1; /* Bits per pixel */
160 h.xmin = 0; /* Range of bitmap */
161 h.ymin = 0;
162 h.xmax = po->picbuf->nc - 1;
163 h.ymax = po->picbuf->nr - 1;
164 h.hres = po->dpi_x; /* Resolution */
165 h.vres = po->dpi_y;
166
167 /** for (i=0; i<8; i++)
168 for (j=0; j<3; j++)
169 {
170 h.palette[i ][j] = 255-p->Clut[i][j];
171 h.palette[i+8][j] = 255-p->Clut[i][j];
172 } RF **/
173
174 h.palette[ 0][0] = 0; h.palette[ 0][1] = 0; h.palette[ 0][2] = 0; /* white */
175 /* h.palette[ 1][0] = 128; h.palette[ 1][1] = 0; h.palette[ 1][2] = 0;
176 gave an ugly red background in b/w mode ? */
177 h.palette[ 1][0] = 255; h.palette[ 1][1] = 255; h.palette[ 1][2] = 255;
178 h.palette[ 2][0] = 0; h.palette[ 2][1] = 128; h.palette[ 2][2] = 0;
179 h.palette[ 3][0] = 128; h.palette[ 3][1] = 128; h.palette[ 3][2] = 0;
180 h.palette[ 4][0] = 0; h.palette[ 4][1] = 0; h.palette[ 4][2] = 128;
181 h.palette[ 5][0] = 128; h.palette[ 5][1] = 0; h.palette[ 5][2] = 128;
182 h.palette[ 6][0] = 0; h.palette[ 6][1] = 128; h.palette[ 6][2] = 128;
183 h.palette[ 7][0] = 192; h.palette[ 7][1] = 192; h.palette[ 7][2] = 192;
184 /* h.palette[ 8][0] = 128; h.palette[ 8][1] = 128; h.palette[ 8][2] = 128; gray*/
185 h.palette[ 8][0] = 0; h.palette[ 8][1] = 0; h.palette[ 8][2] = 0; /*black*/
186 h.palette[ 9][0] = 255; h.palette[ 9][1] = 0; h.palette[ 9][2] = 0; /* red*/
187 h.palette[10][0] = 0; h.palette[10][1] = 255; h.palette[10][2] = 0; /* green */
188 h.palette[11][0] = 255; h.palette[11][1] = 255; h.palette[11][2] = 0;
189 h.palette[12][0] = 0; h.palette[12][1] = 0; h.palette[12][2] = 255; /* blue */
190 h.palette[13][0] = 255; h.palette[13][1] = 0; h.palette[13][2] = 255;
191 h.palette[14][0] = 0; h.palette[14][1] = 255; h.palette[14][2] = 255;
192 h.palette[15][0] = 255; h.palette[15][1] = 255; h.palette[15][2] = 255;
193
194 /****************************************************************
195 for (i=0; i<16; i++)
196 for (j=0; j<3; j++)
197 {
198 h.palette[i ][j] = pg->Clut[ pg->pencolor[i] ][j];
199 }
200 ******************************* MK *****************/
201
202 h.vmode = 0; /* Reserved */
203 h.planes = po->picbuf->depth; /* Number of color planes */
204 h.byteperline = po->picbuf->nb; /* Number of bytes per line */
205 h.paletteinfo = 1; /* 1 = color & b/w, 2 = gray scale */
206 for (i=0; i<58; ) /* Filler for a max. of 128 bytes */
207 {
208 h.dummy[i++] = 'H';
209 h.dummy[i++] = 'W';
210 }
211
212 /**
213 ** For complete machine independence, a bytewise writing of this header
214 ** is mandatory. Else, fill bytes or HIGH/LOW-endian machines must be
215 ** considered. A simple "fwrite(h,128,1,fd)" may not suffice!
216 **/
217
218 if (fputc (h.creator, fd) == EOF) goto ERROR_EXIT;
219 if (fputc (h.version, fd) == EOF) goto ERROR_EXIT;
220 if (fputc (h.encoding,fd) == EOF) goto ERROR_EXIT;
221 if (fputc (h.bits, fd) == EOF) goto ERROR_EXIT;
222 if (fputc ((h.xmin & 0xff), fd) == EOF) goto ERROR_EXIT;
223 if (fputc ((h.xmin >> 8), fd) == EOF) goto ERROR_EXIT;
224 if (fputc ((h.ymin & 0xff), fd) == EOF) goto ERROR_EXIT;
225 if (fputc ((h.ymin >> 8), fd) == EOF) goto ERROR_EXIT;
226 if (fputc ((h.xmax & 0xff), fd) == EOF) goto ERROR_EXIT;
227 if (fputc ((h.xmax >> 8), fd) == EOF) goto ERROR_EXIT;
228 if (fputc ((h.ymax & 0xff), fd) == EOF) goto ERROR_EXIT;
229 if (fputc ((h.ymax >> 8), fd) == EOF) goto ERROR_EXIT;
230 if (fputc ((h.hres & 0xff), fd) == EOF) goto ERROR_EXIT;
231 if (fputc ((h.hres >> 8), fd) == EOF) goto ERROR_EXIT;
232 if (fputc ((h.vres & 0xff), fd) == EOF) goto ERROR_EXIT;
233 if (fputc ((h.vres >> 8), fd) == EOF) goto ERROR_EXIT;
234 if (fwrite((VOID *) h.palette,48,1,fd) != 1) goto ERROR_EXIT;
235 if (fputc (h.vmode, fd) == EOF) goto ERROR_EXIT;
236 if (fputc (h.planes, fd) == EOF) goto ERROR_EXIT;
237 if (fputc ((h.byteperline & 0xff),fd) == EOF) goto ERROR_EXIT;
238 if (fputc ((h.byteperline >> 8), fd) == EOF) goto ERROR_EXIT;
239 if (fputc ((h.paletteinfo & 0xff),fd) == EOF) goto ERROR_EXIT;
240 if (fputc ((h.paletteinfo >> 8), fd) == EOF) goto ERROR_EXIT;
241 if (fwrite((VOID *) h.dummy,58,1,fd) != 1) goto ERROR_EXIT;
242 return 0;
243
244 ERROR_EXIT:
245 PError ("start_PCX");
246 return ERROR;
247 }
248
249
250
251 static void
Buf_to_PCX(Byte * pb,int nb,FILE * fd)252 Buf_to_PCX(Byte* pb, int nb, FILE* fd)
253 {
254 int x;
255
256 byte_to_PCX (0, PCX_INIT, fd);
257 for (x=0; x < nb; x++)
258 byte_to_PCX (~*pb++, PCX_NORMAL, fd);
259 byte_to_PCX (0, PCX_EXIT, fd); /* Flush */
260 }
261
262
263
264 int
PicBuf_to_PCX(const GEN_PAR * pg,const OUT_PAR * po)265 PicBuf_to_PCX (const GEN_PAR *pg, const OUT_PAR *po)
266 {
267 FILE *fd=NULL;
268 RowBuf *row=NULL;
269 int row_c, i, x, color_index, offset, err;
270 Byte mask, *p_R=NULL, *p_G=NULL, *p_B=NULL, *p_I=NULL;
271
272 err = 0;
273 if (!pg->quiet)
274 Eprintf ("\nWriting PCX output\n");
275 if (*po->outfile != '-')
276 {
277 #ifdef VAX
278 if ((fd = fopen(po->outfile, WRITE_BIN, "rfm=var","mrs=512")) == NULL)
279 {
280 #else
281 if ((fd = fopen(po->outfile, WRITE_BIN)) == NULL)
282 {
283 #endif
284 PError ("hp2xx -- opening output file");
285 return ERROR;
286 }
287 }
288 else fd = stdout;
289
290 if (start_PCX (po, pg, fd))
291 {
292 err = ERROR;
293 goto PCX_exit;
294 }
295
296 #if 0
297 /* Backward since highest index is lowest line on screen! */
298 for (row_c = po->picbuf->nr - 1; row_c >= 0; row_c--)
299 {
300 if ((!pg->quiet) && (row_c % 10 == 0))
301 /* For the impatient among us ... */
302 Eprintf(".");
303 row = get_RowBuf (po->picbuf, row_c);
304 byte_to_PCX (0, PCX_INIT, fd);
305 pb = row->buf;
306 for (np=0; np < picbuf->depth; np++)
307 for (x=0; x < po->picbuf->nb; x++)
308 byte_to_PCX (~*pb++, PCX_NORMAL, fd);
309 byte_to_PCX (0, PCX_EXIT, fd); /* Flush */
310 }
311 #endif
312
313 /**
314 ** Allocate buffers for temporary conversion
315 **/
316 if (po->picbuf->depth > 1)
317 {
318 p_I = calloc (po->picbuf->nb, sizeof(Byte));
319 p_B = calloc (po->picbuf->nb, sizeof(Byte));
320 p_G = calloc (po->picbuf->nb, sizeof(Byte));
321 p_R = calloc (po->picbuf->nb, sizeof(Byte));
322 if (p_I == NULL || p_B == NULL || p_G == NULL || p_R == NULL)
323 {
324 Eprintf(
325 "\nCannot 'calloc' color conversion memory -- sorry, use B/W!\n");
326 err = ERROR;
327 goto PCX_exit;
328 }
329 }
330 /**
331 ** Loop for all rows:
332 ** Counting back since highest index is lowest line on paper...
333 **/
334
335 for (row_c = po->picbuf->nr - 1; row_c >= 0; row_c--)
336 {
337 if ((!pg->quiet) && (row_c % 10 == 0))
338 /* For the impatients among us ... */
339 Eprintf(".");
340
341 row = get_RowBuf(po->picbuf, row_c);
342 byte_to_PCX (0, PCX_INIT, fd);
343
344 if (po->picbuf->depth == 1)
345 Buf_to_PCX (row->buf, po->picbuf->nb, fd);
346 else
347 {
348 for (x=0; x < po->picbuf->nb; x++)
349 p_I[x] = p_R[x] = p_G[x] = p_B[x] = 0;
350
351 for (x=offset=0; x < (po->picbuf->nb << 3); x++, offset = (x >> 3))
352 {
353 color_index = index_from_RowBuf(row, x, po->picbuf);
354
355 mask = 0x80;
356 if ((i = x & 0x07) != 0)
357 mask >>= i;
358
359 /**** *(p_R + offset ) |= ( mask ^ ( pg->Clut[color_index][0] & mask ) );
360 *(p_G + offset ) |= ( mask ^ ( pg->Clut[color_index][1] & mask ) );
361 *(p_B + offset ) |= ( mask ^ ( pg->Clut[color_index][2] & mask ) );
362 ****/
363
364
365
366 switch (color_index)
367 {
368 case xxForeground:
369 *(p_I + offset) |= mask;
370 *(p_R + offset) |= mask;
371 *(p_G + offset) |= mask;
372 *(p_B + offset) |= mask;
373 break;
374 case xxRed:
375 *(p_G + offset) |= mask;
376 *(p_B + offset) |= mask;
377 break;
378 case xxGreen:
379 *(p_R + offset) |= mask;
380 *(p_B + offset) |= mask;
381 break;
382 case xxBlue:
383 *(p_G + offset) |= mask;
384 *(p_R + offset) |= mask;
385 break;
386 case xxCyan:
387 *(p_R + offset) |= mask;
388 break;
389 case xxMagenta:
390 *(p_G + offset) |= mask;
391 break;
392 case xxYellow:
393 *(p_B + offset) |= mask;
394 break;
395 default:
396 break;
397 }
398 }
399 Buf_to_PCX (p_R, po->picbuf->nb, fd);
400 Buf_to_PCX (p_G, po->picbuf->nb, fd);
401 Buf_to_PCX (p_B, po->picbuf->nb, fd);
402 Buf_to_PCX (p_I, po->picbuf->nb, fd);
403 }
404 }
405 if (pg->is_color && !pg->quiet)
406 Eprintf ("\nWARNING: PCX colors should be OK now!\n"); /* RF */
407
408 if (!pg->quiet)
409 Eprintf("\n");
410
411 PCX_exit:
412 if (fd != stdout)
413 fclose (fd);
414
415 if (p_R != NULL) free(p_R);
416 if (p_G != NULL) free(p_G);
417 if (p_B != NULL) free(p_B);
418 if (p_I != NULL) free(p_I);
419 return err;
420 }
421
422
423