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