1 /*
2 ** pcx.c - load a ZSoft PC Paintbrush (PCX) file for use inside xloadimage
3 **
4 ** Tim Northrup <tim@BRS.Com>
5 ** Adapted from code by Jef Poskanzer (see Copyright below).
6 **
7 ** Version 0.1 -- 4/25/91 -- Initial cut
8 **
9 ** Copyright (c) 1991 Tim Northrup
10 ** (see file "tgncpyrght.h" for complete copyright information)
11 */
12 /*
13 ** Copyright (C) 1988 by Jef Poskanzer.
14 **
15 ** Permission to use, copy, modify, and distribute this software and its
16 ** documentation for any purpose and without fee is hereby granted, provided
17 ** that the above copyright notice appear in all copies and that both that
18 ** copyright notice and this permission notice appear in supporting
19 ** documentation. This software is provided "as is" without express or
20 ** implied warranty.
21 **
22 ** This program (pcxtopbm) is based on the pcx2rf program by:
23 ** Mike Macgirvin
24 ** Stanford Relativity Gyro Program GP-B
25 ** Stanford, Calif. 94503
26 ** ARPA: mike@relgyro.stanford.edu
27 */
28
29 #include <stdio.h>
30 #include "image.h"
31 #include "tgncpyrght.h"
32 #include "pcx.h"
33
34 /*
35 ** pcxIdent
36 **
37 ** Identify passed file as a PC Paintbrush image or not
38 **
39 ** Returns 1 if file is a PCX file, 0 otherwise
40 */
41
42
pcxIdent(fullname,name)43 unsigned int pcxIdent ( fullname, name )
44 char *fullname, *name;
45 {
46 ZFILE *zf;
47 unsigned int ret;
48 int xmin;
49 int xmax;
50 int ymin;
51 int ymax;
52 int colors;
53 char *type;
54
55 ret = 0;
56 if (! (zf = zopen ( fullname )))
57 return ( 0 );
58 PCXH = (PCXHeader *) lmalloc ( PCXHsize );
59 if (zread ( zf, (byte *)PCXH, PCXHsize ) == PCXHsize) {
60 if ((PCXH->Zid == PCX_MAGIC) && (PCXH->Zver <= 5)) {
61 xmin = Word ( PCXH->Zxminlo, PCXH->Zxminhi);
62 xmax = Word ( PCXH->Zxmaxlo, PCXH->Zxmaxhi);
63 ymin = Word ( PCXH->Zyminlo, PCXH->Zyminhi);
64 ymax = Word ( PCXH->Zymaxlo, PCXH->Zymaxhi);
65 xmax = xmax - xmin + 1;
66 ymax = ymax - ymin + 1;
67 colors = 1 << (PCXH->Zbpp * PCXH->Znplanes);
68 type = " PC Paintbrush image\n";
69 if (colors == 2)
70 printf ( "%s is a %dx%d monochrome%s",
71 name, xmax, ymax, type );
72 else printf ( "%s is a %dx%d %d color%s",
73 name, xmax, ymax, colors, type );
74 ret = 1;
75 }
76 }
77 zclose ( zf );
78 lfree ( (byte *)PCXH );
79 return ( ret );
80 }
81
82
83 /*
84 ** PCX_Load_Raster
85 **
86 ** Load raster image data into passed image structure. Raster Data
87 **
88 ** means : Every bit is a pixel (if depth is 1) or every byte is a
89 **
90 ** pixel (if depth is 8).
91 **
92 ** Returns no value (void function)
93 */
94
PCX_Load_Raster(zf,image,depth)95 static void PCX_Load_Raster ( zf, image, depth )
96 ZFILE *zf;
97 Image *image;
98 int depth;
99 /* Assertion : depth is 1 or 8 */
100 {
101 byte *ptr = &(image->data[0]);
102 int row = 0;
103 int by_this_row = 0;
104 int by_per_row;
105 int linelen;
106 int corrector;
107 int i, b, cnt;
108
109 by_per_row = Word ( PCXH->Zbprlo, PCXH->Zbprhi);
110 if (depth == 1)
111 linelen = (image->width / 8) + (image->width % 8 ? 1 : 0);
112 else linelen = image->width;
113 corrector = by_per_row - linelen;
114 /* bytes per row is always even, which means that there is an */
115 /* excess byte if an odd nr of bytes would be sufficient. */
116 /* As newBitImage allocated memory without this excess, we have */
117 /* to read one less. But as there are two cases of reading, */
118 /* inside and outside of a run, I correct it afterwards, when */
119 /* the line is complete. */
120 while ((b = zgetc(zf)) != EOF) { /* Are we done ? */
121 if ((b & 0xC0) == 0xC0) { /* have a rep. count */
122 cnt = b & 0x3F; /* mask rep. bits out */
123 b = zgetc ( zf ); /* get real bits */
124 if (b == EOF) { /* Shouldn't happen ! */
125 printf ( "Unexpected EOF\n" );
126 return;
127 }
128 }
129 else cnt = 1; /* no repeating this one*/
130 if (depth ==1) b = 255 - b; /* Have to invert */
131 for ( i = 0; i < cnt; i++ ) { /* store count times */
132 *ptr++ = (byte) b;
133 if (++by_this_row == by_per_row) {
134 row++; /* start of a new line */
135 by_this_row = 0; /* reset counter */
136 if (corrector) ptr--; /*evtlly correct pointer*/
137 if ( row >= image->height ) {
138 #if 0
139 /* happens a lot on valid images - jimf 10.28.91 */
140 if (depth == 1) /* Color : Map follows */
141 printf ("Warning: excess data ignored\n");
142 #endif
143 return;
144 }
145 }
146 }
147 }
148 }
149
150 /*
151 ** PCX_Planes
152 **
153 ** Load plane image data into passed image structure. Plane data
154 **
155 ** means : There are N planes, each containing M bits of a pixel
156 **
157 ** byte, where N * M is not greater than 8 and M divides 8. (The
158 **
159 ** cases M = 1 or 8, N = 1 are covered by PCX_Load_Raster).
160 **
161 ** Returns no value (void function)
162 */
163
164
PCX_Planes(zf,image,bpp,nr_pl)165 static void PCX_Planes ( zf, image, bpp, nr_pl )
166 ZFILE *zf;
167 Image *image;
168 int bpp, nr_pl;
169 /* Assertion : */
170 /* bpp is 1, 2 or 4 only, dividing 8 without remainder anyways, */
171 /* bpp * nr_pl <= 8 */
172 {
173 byte *ptr, *sptr;
174 register byte *tptr;
175 int row = 0;
176 int by_this_row = 0;
177 int by_per_row;
178 int this_plane = 0;
179 int shifter = 0;
180 register int j;
181 int i, b, cnt;
182
183 ptr = &(image->data[0]);
184 by_per_row = Word ( PCXH->Zbprlo, PCXH->Zbprhi);
185 sptr = tptr = (byte *) lcalloc ( by_per_row*8 );
186 /* We can't correct as easy as above, because we handle several */
187 /* bit planes simultaneously, and we must not load beyond row */
188 /* limits. So we load into a temporary row and copy it into */
189 /* image structure when the row is completed. */
190 while ((b = zgetc(zf)) != EOF) {
191 if ((b & 0xC0) == 0xC0) { /* Get count and data as above */
192 cnt = b & 0x3F;
193 b = zgetc ( zf );
194 if (b == EOF) {
195 printf ( "Unexpected EOF\n" );
196 return;
197 }
198 }
199 else cnt = 1;
200 for ( i = 0; i < cnt; i++ ) { /* Load data into temp. */
201 switch (bpp) {
202 case 1 :
203 *tptr++ |= (byte) (((b & 0x80 ) >> 7) << shifter);
204 *tptr++ |= (byte) (((b & 0x40 ) >> 6) << shifter);
205 *tptr++ |= (byte) (((b & 0x20 ) >> 5) << shifter);
206 *tptr++ |= (byte) (((b & 0x10 ) >> 4) << shifter);
207 *tptr++ |= (byte) (((b & 0x08 ) >> 3) << shifter);
208 *tptr++ |= (byte) (((b & 0x04 ) >> 2) << shifter);
209 *tptr++ |= (byte) (((b & 0x02 ) >> 1) << shifter);
210 *tptr++ |= (byte) ((b & 0x01 ) << shifter);
211 /* This is not a loop for performance reasons. */
212 /* Can't write e.g. ">> 2 - shifter", because */
213 /* that expression would get negative. */
214 break;
215 case 2 :
216 *tptr++ |= (byte) (((b & 0xC0 ) >> 6) << shifter);
217 *tptr++ |= (byte) (((b & 0x30 ) >> 4) << shifter);
218 *tptr++ |= (byte) (((b & 0x0C ) >> 2) << shifter);
219 *tptr++ |= (byte) ((b & 0x03 ) << shifter);
220 break;
221 case 4 :
222 *tptr++ |= (byte) (((b & 0xF0) >> 4) << shifter);
223 *tptr++ |= (byte) ((b & 0x0F) << shifter);
224 break;
225 default :; /* Can't happen if assertion holds */
226 }
227 if (++by_this_row == by_per_row) { /* Row done ? */
228 by_this_row = 0; /* reset counter */
229 if (++this_plane == nr_pl) { /* was it last plane ? */
230 row++; /* inc counter */
231 tptr = sptr; /* get saved ptr */
232 this_plane = shifter = 0;/* reset plane Nr */
233 for (j = 0; j < image->width; j++) {
234 *ptr++ = *tptr; /* store final data */
235 *tptr++ = 0; /* clear temp data */
236 }
237 if ( row >= image->height )
238 return; /* Done with image ? */
239 }
240 else /* Prepare next plane */
241 shifter = this_plane * bpp;
242 tptr = sptr; /* Get saved ptr */
243 }
244 }
245 }
246 }
247
248
249 /*
250 ** PCX_LoadImage
251 **
252 ** Load PC Paintbrush file into the passed Image structure.
253 **
254 ** Returns no value (void function)
255 */
256
257
PCX_LoadImage(zf,image)258 static void PCX_LoadImage ( zf ,image )
259 ZFILE *zf;
260 Image *image;
261 {
262 switch (PCXH->Zbpp) { /* What kind of plane do we have ? */
263 case 1 : /* Bit planes */
264 if (PCXH->Znplanes == 1) /* Only one : Read it */
265 PCX_Load_Raster ( zf, image, 1 );
266 else PCX_Planes ( zf, image, 1, PCXH->Znplanes );
267 break;
268 case 2 : /* Two or four bits per plane */
269 case 4 : /* are read plane by plane */
270 PCX_Planes ( zf, image, PCXH->Zbpp, PCXH->Znplanes );
271 break;
272 case 8 : /* Byte planes */
273 if (PCXH->Znplanes == 1) /* Only one : Read it */
274 PCX_Load_Raster ( zf, image, 8 );
275 else { /* More not allowed */
276 printf ("Only 1 plane allowed if 8 bits per plane\n");
277 exit (1);
278 }
279 break;
280 default : /* Neither case found */
281 printf ("%d bits per plane not supported\n", PCXH->Zbpp );
282 exit (1);
283 }
284 }
285
286
287 /*
288 ** pcxLoad
289 **
290 ** Load PCX Paintbrush file into an Image structure.
291 **
292 ** Returns pointer to allocated struct if successful, NULL otherwise
293 */
294
pcxLoad(fullname,name,verbose)295 Image *pcxLoad ( fullname, name, verbose )
296 char *fullname, *name;
297 unsigned int verbose;
298 {
299 ZFILE *zf;
300 unsigned int i;
301 int xmin;
302 int xmax;
303 int ymin;
304 int ymax;
305 int colors;
306 PCXcolor *cmap;
307 int clen;
308 Image *image;
309
310 if ( ! (zf = zopen ( fullname ))) /* Open input file */
311 return ( (Image *) NULL);
312 PCXH = (PCXHeader *) lmalloc ( PCXHsize );
313 if (zread ( zf, (byte *)PCXH, PCXHsize ) != PCXHsize) { /* Read header */
314 zclose ( zf );
315 return ( (Image *) NULL );
316 }
317 if ((PCXH->Zid != PCX_MAGIC) || (PCXH->Zver > 5)) {
318 zclose ( zf ); /* Is it PCX, Version less 5 ? */
319 return ( (Image *) NULL );
320 }
321 znocache(zf); /* don't need caching anymore */
322 xmin = Word ( PCXH->Zxminlo, PCXH->Zxminhi); /* Calculate sizes */
323 xmax = Word ( PCXH->Zxmaxlo, PCXH->Zxmaxhi);
324 ymin = Word ( PCXH->Zyminlo, PCXH->Zyminhi);
325 ymax = Word ( PCXH->Zymaxlo, PCXH->Zymaxhi);
326 xmax = xmax - xmin + 1;
327 ymax = ymax - ymin + 1;
328 colors = 1 << (PCXH->Zbpp * PCXH->Znplanes); /* Calculate colors*/
329 if (verbose) { /* Print Information */
330 if (colors == 2)
331 printf ( "%s is a %dx%d monochrome PC Paintbrush image\n",
332 name, xmax, ymax );
333 else printf ( "%s is a %dx%d %d color PC Paintbrush image\n",
334 name, xmax, ymax, colors );
335 }
336 if (colors > 256) {
337 printf ( "No more than 256 colors allowed in PCX format\n" );
338 exit (1);
339 }
340 if (PCXH->Zenc == 0) {
341 printf ( "Unencoded PCX format not yet supported. Please" );
342 printf ( " email the uuencoded image\n to erueg@cfgauss." );
343 printf ( "uni-math.gwdg.de\n" );
344 exit (1);
345 }
346 if (colors == 2) /* Allocate appropriate pbm array */
347 image = newBitImage ( xmax, ymax );
348 else {
349 image = newRGBImage ( xmax, ymax, 8 );
350 }
351 PCX_LoadImage ( zf, image );
352 if (colors > 16) { /* Handle external colormap */
353 while ((i = zgetc(zf)) != PCX_MAPSTART);
354 clen = colors * 3;
355 cmap = (PCXcolor *) lmalloc ( clen );
356 if (zread ( zf, (byte *)cmap, clen ) != clen) {
357 printf ( "EOF while reading colormap" );
358 exit (1);
359 }
360 for ( i = 0; i < colors; i++) {
361 *(image->rgb.red + i) = (cmap [i].Zred << 8);
362 *(image->rgb.green + i) = (cmap [i].Zgreen << 8);
363 *(image->rgb.blue + i) = (cmap [i].Zblue << 8);
364 }
365 image->rgb.used = colors;
366 lfree ( (byte *)cmap );
367 }
368 else if (colors > 2) { /* Handle internal colormap */
369 for ( i = 0; i < colors; i++) {
370 *(image->rgb.red + i) = (PCXH->Zcmap [i].Zred << 8);
371 *(image->rgb.green + i) = (PCXH->Zcmap [i].Zgreen << 8);
372 *(image->rgb.blue + i) = (PCXH->Zcmap [i].Zblue << 8);
373 }
374 image->rgb.used = colors;
375 }
376 zclose ( zf );
377 lfree ( (byte *)PCXH );
378 image->title = dupString(name);
379 return ( image );
380 }
381