#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pcx.h>
static RGB egapal[16] = {
{0, 0, 0}, {0, 0, 170}, {0, 170, 0}, {0, 170, 170},
{170, 0, 0}, {170, 0, 170}, {170, 85, 0}, {170, 170, 170},
{85, 85, 85}, {85, 85, 255}, {85, 255, 85}, {85, 255, 255},
{255, 85, 85}, {255, 85, 255}, {255, 255, 85}, {255, 255, 255}
};
static RGB monopal[2] = {{0, 0, 0}, {255, 255, 255}};
static void planes_to_pixels(unsigned char *pixels, unsigned char *bitplanes,
int bytesperline, int planes, int bitsperpixel)
{
int i, j;
int npixels;
unsigned char *p;
/* truecolor */
if (bitsperpixel == 8) {
unsigned char *bp = bitplanes;
for (i = 0; i < 3; i++) {
p = pixels + i;
for (j = 0; j < bytesperline; j++, p += 3)
*p = *(bp++);
}
return;
}
/* clear the pixel buffer */
npixels = (bytesperline * 8) / bitsperpixel;
p = pixels;
while (--npixels >= 0)
*p++ = 0;
/* do the format conversion */
for (i = 0; i < planes; i++) {
int pixbit, bits, mask;
p = pixels;
pixbit = (1 << i);
for (j = 0; j < bytesperline; j++) {
bits = *bitplanes++;
for (mask = 0x80; mask != 0; mask >>= 1, p++) {
if (bits & mask)
*p |= pixbit;
}
}
}
}
static void unpack_pixels(unsigned char *pixels, unsigned char *bitplanes,
int bytesperline, int bitsperpixel)
{
register int bits;
if (bitsperpixel == 8) {
while (--bytesperline >= 0)
*pixels++ = *bitplanes++;
} else if (bitsperpixel == 4) {
while (--bytesperline >= 0) {
bits = *bitplanes++;
*pixels++ = (bits >> 4) & 0x0f;
*pixels++ = bits & 0x0f;
}
} else if (bitsperpixel == 2) {
while (--bytesperline >= 0) {
bits = *bitplanes++;
*pixels++ = (bits >> 6) & 0x03;
*pixels++ = (bits >> 4) & 0x03;
*pixels++ = (bits >> 2) & 0x03;
*pixels++ = bits & 0x03;
}
} else if (bitsperpixel == 1) {
while (--bytesperline >= 0) {
bits = *bitplanes++;
*pixels++ = ((bits & 0x80) != 0);
*pixels++ = ((bits & 0x40) != 0);
*pixels++ = ((bits & 0x20) != 0);
*pixels++ = ((bits & 0x10) != 0);
*pixels++ = ((bits & 0x08) != 0);
*pixels++ = ((bits & 0x04) != 0);
*pixels++ = ((bits & 0x02) != 0);
*pixels++ = ((bits & 0x01) != 0);
}
}
}
static unsigned char *read_image(FILE *fp, int totbytes)
{
unsigned char *buf, *bp;
int c, count;
buf = bp = (unsigned char *)malloc(totbytes);
while (totbytes > 0) {
if ((c = getc(fp)) == EOF) {
fprintf(stderr, "Premature end of file\n");
return NULL;
}
if ((c & 0xc0) != 0xc0) {
*(bp++) = c;
--totbytes;
continue;
}
count = c & 0x3f;
if ((c = getc(fp)) == EOF) {
fprintf(stderr, "Premature end of file\n");
return NULL;
}
if (count > totbytes) {
fprintf(stderr, "Repeat count spans end of image, "
"count = %d, totbytes = %d\n", count, totbytes);
return NULL;
}
totbytes -= count;
while (--count >= 0)
*(bp++) = c;
}
return buf;
}
RGB *read_pcx(char *filename, int *width, int *height)
{
FILE *f;
PCXHDR hdr;
int w, h;
RGB pal256[256], *pal = NULL;
int truecolor = 0;
unsigned char *image = NULL, *pixels = NULL;
int linebytes;
RGB *buf = NULL, *bp;
int x, y;
if (! (f = fopen(filename,"r")))
return (0);
if (fread(&hdr, 1, sizeof(PCXHDR), f) < sizeof(PCXHDR)) {
fprintf(stderr, "Premature end of file\n");
goto err;
}
switch (hdr.bitsperpixel) {
case 1:
if (hdr.planes > 4)
goto fail;
break;
case 2:
case 4:
if (hdr.planes != 1)
goto fail;
break;
case 8:
if (hdr.planes != 1) {
if (hdr.planes == 3 || hdr.planes == 4)
truecolor++;
else
goto fail;
}
break;
default:
fail:
fprintf(stderr, "Can't handle %d bits per pixel image with "
"%d planes\n", hdr.bitsperpixel, hdr.planes);
goto err;
}
if (! truecolor) {
if (hdr.bitsperpixel == 8) {
fseek(f, -(sizeof(pal256) + 1), SEEK_END);
if (getc(f) != 0x0c) {
fprintf(stderr, "Bad color map signature\n");
goto err;
}
fread(pal256, 1, sizeof(pal256), f);
fseek(f, sizeof(PCXHDR), SEEK_SET);
pal = pal256;
} else {
pal = (hdr.bitsperpixel == 1 && hdr.planes == 1 ? monopal :
(hdr.version == 0 || hdr.version == 3 ? egapal :
hdr.palette));
}
}
w = (hdr.xmax - hdr.xmin) + 1; h = (hdr.ymax - hdr.ymin) + 1;
linebytes = hdr.bytesperline * hdr.planes;
if (! (image = read_image(f, linebytes * h)))
goto err;
buf = bp = (RGB *)malloc(w * sizeof(RGB) * h);
pixels = (unsigned char *)malloc(truecolor ? hdr.bytesperline * 3 :
hdr.bytesperline * 8 / hdr.bitsperpixel);
for (y = 0; y < h; y++) {
if (hdr.planes == 1)
unpack_pixels(pixels, image + y * linebytes, hdr.bytesperline,
hdr.bitsperpixel);
else
planes_to_pixels(pixels, image + y * linebytes, hdr.bytesperline,
hdr.planes, hdr.bitsperpixel);
if (truecolor) {
RGB *p = (RGB *)pixels;
for (x = 0; x < w; x++)
*(bp++) = *(p++);
} else {
for (x = 0; x < w; x++)
*(bp++) = pal[pixels[x]];
}
}
*width = w; *height = h;
err:
if (image) free(image);
if (pixels) free(pixels);
fclose(f);
return buf;
}