1 /***********************************************************
2 * Artsoft Retro-Game Library *
3 *----------------------------------------------------------*
4 * (c) 1994-2000 Artsoft Entertainment *
6 * Detmolder Strasse 189 *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
12 ***********************************************************/
22 #define PCX_DEBUG FALSE
24 #define PCX_MAGIC 0x0a /* first byte in a PCX image file */
25 #define PCX_LAST_VERSION 5 /* last acceptable version number */
26 #define PCX_ENCODING 1 /* PCX encoding method */
27 #define PCX_256COLORS_MAGIC 0x0c /* first byte of a PCX 256 color map */
28 #define PCX_MAXDEPTH 8 /* supports up to 8 bits per pixel */
29 #define PCX_MAXCOLORS 256 /* maximum number of colors */
31 #define PCX_HEADER_SIZE 128
32 #define PCX_COLORMAP_SIZE (3 * PCX_MAXCOLORS)
36 unsigned char signature; /* PCX file identifier */
37 unsigned char version; /* version compatibility level */
38 unsigned char encoding; /* encoding method */
39 unsigned char bits_per_pixel; /* bits per pixel, or depth */
40 unsigned short xmin; /* X position of left edge */
41 unsigned short ymin; /* Y position of top edge */
42 unsigned short xmax; /* X position of right edge */
43 unsigned short ymax; /* Y position of bottom edge */
44 unsigned short hres; /* X screen resolution of source image */
45 unsigned short vres; /* Y screen resolution of source image */
46 unsigned char palette[16][3]; /* PCX color map */
47 unsigned char reserved; /* should be 0, 1 if std res fax */
48 unsigned char color_planes; /* bit planes in image */
49 unsigned short bytes_per_line;/* byte delta between scanlines */
50 unsigned short palette_type; /* 0 = undef, 1 = color, 2 = grayscale */
51 unsigned char filler[58]; /* fill to struct size of 128 */
54 /* global PCX error value */
55 int errno_pcx = PCX_Success;
57 static byte *PCX_ReadBitmap(Image *image, byte *buffer_ptr, byte *buffer_last)
59 /* Run Length Encoding: If the two high bits are set,
60 * then the low 6 bits contain a repeat count, and the byte to
61 * repeat is the next byte in the file. If the two high bits are
62 * not set, then this is the byte to write.
65 unsigned int bytes_per_pixel = (image->depth + 7) / 8;
66 register byte *bitmap_ptr, *bitmap_last;
67 register byte value, count;
69 bitmap_ptr = image->data;
70 bitmap_last = bitmap_ptr + (image->width * image->height * bytes_per_pixel);
72 while (bitmap_ptr < bitmap_last && buffer_ptr < buffer_last)
74 value = *buffer_ptr++;
76 if ((value & 0xc0) == 0xc0) /* this is a repeat count byte */
78 count = value & 0x3f; /* extract repeat count from byte */
79 value = *buffer_ptr++; /* next byte is value to repeat */
81 for (; count && bitmap_ptr < bitmap_last; count--)
82 *bitmap_ptr++ = value;
84 if (count) /* repeat count spans end of bitmap */
88 *bitmap_ptr++ = value;
90 image->rgb.color_used[value] = TRUE;
93 /* check if end of buffer was reached before end of bitmap */
94 if (bitmap_ptr < bitmap_last)
97 /* return current buffer position for next decoding function */
101 static byte *PCX_ReadColormap(Image *image,byte *buffer_ptr, byte *buffer_last)
105 /* read colormap magic byte */
106 magic = *buffer_ptr++;
108 /* check magic colormap header byte */
109 if (magic != PCX_256COLORS_MAGIC)
112 /* check if enough bytes left for a complete colormap */
113 if (buffer_ptr + PCX_COLORMAP_SIZE > buffer_last)
116 /* read 256 colors from PCX colormap */
117 for (i=0; i<PCX_MAXCOLORS; i++)
119 image->rgb.red[i] = *buffer_ptr++ << 8;
120 image->rgb.green[i] = *buffer_ptr++ << 8;
121 image->rgb.blue[i] = *buffer_ptr++ << 8;
124 /* return current buffer position for next decoding function */
128 Image *Read_PCX_to_Image(char *filename)
132 byte *buffer_ptr, *buffer_last;
133 unsigned int file_length;
134 struct PCX_Header pcx;
136 int width, height, depth;
139 errno_pcx = PCX_Success;
141 if (!(file = fopen(filename, MODE_READ)))
143 errno_pcx = PCX_OpenFailed;
147 if (fseek(file, 0, SEEK_END) == -1)
150 errno_pcx = PCX_ReadFailed;
154 file_length = ftell(file);
157 if (file_length < PCX_HEADER_SIZE)
159 /* PCX file is too short to contain a valid PCX header */
162 errno_pcx = PCX_FileInvalid;
166 file_buffer = checked_malloc(file_length);
168 if (fread(file_buffer, 1, file_length, file) != file_length)
171 errno_pcx = PCX_ReadFailed;
177 pcx.signature = file_buffer[0];
178 pcx.version = file_buffer[1];
179 pcx.encoding = file_buffer[2];
180 pcx.bits_per_pixel = file_buffer[3];
181 pcx.xmin = file_buffer[4] + 256 * file_buffer[5];
182 pcx.ymin = file_buffer[6] + 256 * file_buffer[7];
183 pcx.xmax = file_buffer[8] + 256 * file_buffer[9];
184 pcx.ymax = file_buffer[10] + 256 * file_buffer[11];
185 pcx.color_planes = file_buffer[65];
186 pcx.bytes_per_line = file_buffer[66] + 256 * file_buffer[67];
187 pcx.palette_type = file_buffer[68] + 256 * file_buffer[69];
189 width = pcx.xmax - pcx.xmin + 1;
190 height = pcx.ymax - pcx.ymin + 1;
191 depth = pcx.bits_per_pixel;
193 if (pcx.signature != PCX_MAGIC || pcx.version > PCX_LAST_VERSION ||
194 pcx.encoding != PCX_ENCODING || pcx.color_planes > PCX_MAXDEPTH ||
195 width < 0 || height < 0)
199 errno_pcx = PCX_FileInvalid;
206 printf("%s is a %dx%d PC Paintbrush image with %d bitplanes\n",
207 filename, width, height,
209 printf("depth: %d\n", pcx.bits_per_pixel);
210 printf("color_planes: %d\n", pcx.color_planes);
211 printf("bytes_per_line: %d\n", pcx.bytes_per_line);
212 printf("palette type: %s\n",
213 (pcx.palette_type == 1 ? "color" :
214 pcx.palette_type == 2 ? "grayscale" : "undefined"));
218 /* allocate new image structure */
219 image = newImage(width, height, depth);
221 buffer_ptr = file_buffer + PCX_HEADER_SIZE;
222 buffer_last = file_buffer + file_length;
224 /* read compressed bitmap data */
225 if ((buffer_ptr = PCX_ReadBitmap(image, buffer_ptr, buffer_last)) == NULL)
230 errno_pcx = PCX_FileInvalid;
234 if (file_length < PCX_HEADER_SIZE + PCX_COLORMAP_SIZE)
236 /* PCX file is too short to contain a valid 256 colors colormap */
238 errno_pcx = PCX_ColorFailed;
242 /* read colormap data */
243 if (!PCX_ReadColormap(image, buffer_ptr, buffer_last))
247 errno_pcx = PCX_ColorFailed;
253 /* determine number of used colormap entries */
255 for (i=0; i<PCX_MAXCOLORS; i++)
256 if (image->rgb.color_used[i])
261 printf("Read_PCX_to_Image: %d colors found\n", image->rgb.used);
267 #endif /* !TARGET_SDL */