IMG_pcx.c
changeset 20 463951886af1
parent 7 e1b6443ffb6b
child 24 69f3d44d56da
     1.1 --- a/IMG_pcx.c	Sat Feb 17 01:46:37 2001 +0000
     1.2 +++ b/IMG_pcx.c	Tue Feb 27 20:45:58 2001 +0000
     1.3 @@ -22,9 +22,19 @@
     1.4      slouken@devolution.com
     1.5  */
     1.6  
     1.7 -/* This is a PCX image file loading framework */
     1.8 -
     1.9 +/*
    1.10 + * PCX file reader:
    1.11 + * Supports:
    1.12 + *  1..4 bits/pixel in multiplanar format (1 bit/plane/pixel)
    1.13 + *  8 bits/pixel in single-planar format (8 bits/plane/pixel)
    1.14 + *  24 bits/pixel in 3-plane format (8 bits/plane/pixel)
    1.15 + *
    1.16 + * Doesn't support:
    1.17 + *  single-planar packed-pixel formats other than 8bpp
    1.18 + *  4-plane 32bpp format with a fourth "intensity" plane
    1.19 + */
    1.20  #include <stdio.h>
    1.21 +#include <stdlib.h>
    1.22  
    1.23  #include "SDL_endian.h"
    1.24  
    1.25 @@ -77,24 +87,19 @@
    1.26  	Uint32 Gmask;
    1.27  	Uint32 Bmask;
    1.28  	Uint32 Amask;
    1.29 -	SDL_Surface *surface;
    1.30 +	SDL_Surface *surface = NULL;
    1.31  	int width, height;
    1.32 -	int i, index, x, y;
    1.33 -	int count;
    1.34 -	Uint8 *row, ch;
    1.35 -	int read_error;
    1.36 +	int y, bpl;
    1.37 +	Uint8 *row, *buf = NULL;
    1.38 +	char *error = NULL;
    1.39 +	int bits, src_bits;
    1.40  
    1.41 -	/* Initialize the data we will clean up when we're done */
    1.42 -	surface = NULL;
    1.43 -	read_error = 0;
    1.44 -
    1.45 -	/* Check to make sure we have something to do */
    1.46  	if ( ! src ) {
    1.47  		goto done;
    1.48  	}
    1.49  
    1.50 -	/* Read and convert the header */
    1.51  	if ( ! SDL_RWread(src, &pcxh, sizeof(pcxh), 1) ) {
    1.52 +		error = "file truncated";
    1.53  		goto done;
    1.54  	}
    1.55  	pcxh.Xmin = SDL_SwapLE16(pcxh.Xmin);
    1.56 @@ -106,8 +111,13 @@
    1.57  	/* Create the surface of the appropriate type */
    1.58  	width = (pcxh.Xmax - pcxh.Xmin) + 1;
    1.59  	height = (pcxh.Ymax - pcxh.Ymin) + 1;
    1.60 -	Rmask = Gmask = Bmask = Amask = 0 ; 
    1.61 -	if ( pcxh.BitsPerPixel * pcxh.NPlanes > 16 ) {
    1.62 +	Rmask = Gmask = Bmask = Amask = 0;
    1.63 +	src_bits = pcxh.BitsPerPixel * pcxh.NPlanes;
    1.64 +	if((pcxh.BitsPerPixel == 1 && pcxh.NPlanes >= 1 && pcxh.NPlanes <= 4)
    1.65 +	   || (pcxh.BitsPerPixel == 8 && pcxh.NPlanes == 1)) {
    1.66 +		bits = 8;
    1.67 +	} else if(pcxh.BitsPerPixel == 8 && pcxh.NPlanes == 3) {
    1.68 +		bits = 24;
    1.69  		if ( SDL_BYTEORDER == SDL_LIL_ENDIAN ) {
    1.70  			Rmask = 0x000000FF;
    1.71  			Gmask = 0x0000FF00;
    1.72 @@ -117,83 +127,108 @@
    1.73  			Gmask = 0x00FF00;
    1.74  			Bmask = 0x0000FF;
    1.75  		}
    1.76 +	} else {
    1.77 +		error = "unsupported PCX format";
    1.78 +		goto done;
    1.79  	}
    1.80  	surface = SDL_AllocSurface(SDL_SWSURFACE, width, height,
    1.81 -			pcxh.BitsPerPixel*pcxh.NPlanes,Rmask,Gmask,Bmask,Amask);
    1.82 -	if ( surface == NULL ) {
    1.83 -		IMG_SetError("Out of memory");
    1.84 +				   bits, Rmask, Gmask, Bmask, Amask);
    1.85 +	if ( surface == NULL )
    1.86  		goto done;
    1.87 +
    1.88 +	bpl = pcxh.NPlanes * pcxh.BytesPerLine;
    1.89 +	buf = malloc(bpl);
    1.90 +	row = surface->pixels;
    1.91 +	for ( y=0; y<surface->h; ++y ) {
    1.92 +		/* decode a scan line to a temporary buffer first */
    1.93 +		int i, count = 0;
    1.94 +		Uint8 ch;
    1.95 +		Uint8 *dst = (src_bits == 8) ? row : buf;
    1.96 +		for(i = 0; i < bpl; i++) {
    1.97 +			if(!count) {
    1.98 +				if(!SDL_RWread(src, &ch, 1, 1)) {
    1.99 +					error = "file truncated";
   1.100 +					goto done;
   1.101 +				}
   1.102 +				if( (ch & 0xc0) == 0xc0) {
   1.103 +					count = ch & 0x3f;
   1.104 +					if(!SDL_RWread(src, &ch, 1, 1)) {
   1.105 +						error = "file truncated";
   1.106 +						goto done;
   1.107 +					}
   1.108 +				} else
   1.109 +					count = 1;
   1.110 +			}
   1.111 +			dst[i] = ch;
   1.112 +			count--;
   1.113 +		}
   1.114 +
   1.115 +		if(src_bits <= 4) {
   1.116 +			/* expand planes to 1 byte/pixel */
   1.117 +			Uint8 *src = buf;
   1.118 +			int plane;
   1.119 +			for(plane = 0; plane < pcxh.NPlanes; plane++) {
   1.120 +				int i, j, x = 0;
   1.121 +				for(i = 0; i < pcxh.BytesPerLine; i++) {
   1.122 +					Uint8 byte = *src++;
   1.123 +					for(j = 7; j >= 0; j--) {
   1.124 +						unsigned bit = (byte >> j) & 1;
   1.125 +						row[x++] |= bit << plane;
   1.126 +					}
   1.127 +				}
   1.128 +			}
   1.129 + 		} else if(src_bits == 24) {
   1.130 +			/* de-interlace planes */
   1.131 +			Uint8 *src = buf;
   1.132 +			int plane;
   1.133 +			for(plane = 0; plane < pcxh.NPlanes; plane++) {
   1.134 +				int x;
   1.135 +				dst = row + plane;
   1.136 +				for(x = 0; x < width; x++) {
   1.137 +					*dst = *src++;
   1.138 +					dst += pcxh.NPlanes;
   1.139 +				}
   1.140 +			}
   1.141 +		}
   1.142 +
   1.143 +		row += surface->pitch;
   1.144  	}
   1.145  
   1.146 -	/* Decode the image to the surface */
   1.147 -	for ( y=0; y<surface->h; ++y ) {
   1.148 -		for ( i=0; i<pcxh.NPlanes; ++i ) {
   1.149 -			row = (Uint8 *)surface->pixels + y*surface->pitch;
   1.150 -			index = i;
   1.151 -			for ( x=0; x<pcxh.BytesPerLine; ) {
   1.152 -				if ( ! SDL_RWread(src, &ch, 1, 1) ) {
   1.153 -					read_error = 1;
   1.154 +	if(bits == 8) {
   1.155 +		SDL_Color *colors = surface->format->palette->colors;
   1.156 +		int nc = 1 << src_bits;
   1.157 +		int i;
   1.158 +
   1.159 +		surface->format->palette->ncolors = nc;
   1.160 +		if(src_bits == 8) {
   1.161 +			Uint8 ch;
   1.162 +			/* look for a 256-colour palette */
   1.163 +			do {
   1.164 +				if ( !SDL_RWread(src, &ch, 1, 1)) {
   1.165 +					error = "file truncated";
   1.166  					goto done;
   1.167  				}
   1.168 -				if ( (ch & 0xC0) == 0xC0 ) {
   1.169 -					count = ch & 0x3F;
   1.170 -					SDL_RWread(src, &ch, 1, 1);
   1.171 -				} else {
   1.172 -					count = 1;
   1.173 -				}
   1.174 -				while ( count-- ) {
   1.175 -					row[index] = ch;
   1.176 -					++x;
   1.177 -					index += pcxh.NPlanes;
   1.178 -				}
   1.179 +			} while ( ch != 12 );
   1.180 +
   1.181 +			for(i = 0; i < 256; i++) {
   1.182 +				SDL_RWread(src, &colors[i].r, 1, 1);
   1.183 +				SDL_RWread(src, &colors[i].g, 1, 1);
   1.184 +				SDL_RWread(src, &colors[i].b, 1, 1);
   1.185 +			}
   1.186 +		} else {
   1.187 +			for(i = 0; i < nc; i++) {
   1.188 +				colors[i].r = pcxh.Colormap[i * 3];
   1.189 +				colors[i].g = pcxh.Colormap[i * 3 + 1];
   1.190 +				colors[i].b = pcxh.Colormap[i * 3 + 2];
   1.191  			}
   1.192  		}
   1.193  	}
   1.194  
   1.195 -	/* Look for the palette, if necessary */
   1.196 -	switch (surface->format->BitsPerPixel) {
   1.197 -	    case 1: {
   1.198 -		SDL_Color *colors = surface->format->palette->colors;
   1.199 -
   1.200 -		colors[0].r = 0x00;
   1.201 -		colors[0].g = 0x00;
   1.202 -		colors[0].b = 0x00;
   1.203 -		colors[1].r = 0xFF;
   1.204 -		colors[1].g = 0xFF;
   1.205 -		colors[1].b = 0xFF;
   1.206 -	    }
   1.207 -	    break;
   1.208 -
   1.209 -	    case 8: {
   1.210 -		SDL_Color *colors = surface->format->palette->colors;
   1.211 -
   1.212 -		/* Look for the palette */
   1.213 -		do {
   1.214 -			if ( ! SDL_RWread(src, &ch, 1, 1) ) {
   1.215 -				read_error = 1;
   1.216 -				goto done;
   1.217 -			}
   1.218 -		} while ( ch != 12 );
   1.219 -
   1.220 -		/* Set the image surface palette */
   1.221 -		for ( i=0; i<256; ++i ) {
   1.222 -			SDL_RWread(src, &colors[i].r, 1, 1);
   1.223 -			SDL_RWread(src, &colors[i].g, 1, 1);
   1.224 -			SDL_RWread(src, &colors[i].b, 1, 1);
   1.225 -		}
   1.226 -	    }
   1.227 -	    break;
   1.228 -
   1.229 -	    default: {
   1.230 -		/* Don't do anything... */;
   1.231 -	    }
   1.232 -	    break;
   1.233 -	}
   1.234 -
   1.235  done:
   1.236 -	if ( read_error ) {
   1.237 +	free(buf);
   1.238 +	if ( error ) {
   1.239  		SDL_FreeSurface(surface);
   1.240 -		IMG_SetError("Error reading PCX data");
   1.241 +		IMG_SetError(error);
   1.242  		surface = NULL;
   1.243  	}
   1.244  	return(surface);