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