IMG_pcx.c
author Sam Lantinga <slouken@libsdl.org>
Sun, 04 Jan 2004 17:41:55 +0000
changeset 97 e1161bd417c4
parent 95 7fcb46931afc
child 98 9f94c4674cc9
permissions -rw-r--r--
Updated copyright information for 2004 (Happy New Year!)
     1 /*
     2     SDL_image:  An example image loading library for use with SDL
     3     Copyright (C) 1999-2004 Sam Lantinga
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Library General Public
     7     License as published by the Free Software Foundation; either
     8     version 2 of the License, or (at your option) any later version.
     9 
    10     This library is distributed in the hope that it will be useful,
    11     but WITHOUT ANY WARRANTY; without even the implied warranty of
    12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    13     Library General Public License for more details.
    14 
    15     You should have received a copy of the GNU Library General Public
    16     License along with this library; if not, write to the Free
    17     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    18 
    19     Sam Lantinga
    20     slouken@libsdl.org
    21 */
    22 
    23 /* $Id$ */
    24 
    25 /*
    26  * PCX file reader:
    27  * Supports:
    28  *  1..4 bits/pixel in multiplanar format (1 bit/plane/pixel)
    29  *  8 bits/pixel in single-planar format (8 bits/plane/pixel)
    30  *  24 bits/pixel in 3-plane format (8 bits/plane/pixel)
    31  *
    32  * (The <8bpp formats are expanded to 8bpp surfaces)
    33  *
    34  * Doesn't support:
    35  *  single-planar packed-pixel formats other than 8bpp
    36  *  4-plane 32bpp format with a fourth "intensity" plane
    37  */
    38 #include <stdio.h>
    39 #include <stdlib.h>
    40 
    41 #include "SDL_endian.h"
    42 
    43 #include "SDL_image.h"
    44 
    45 #ifdef LOAD_PCX
    46 
    47 struct PCXheader {
    48 	Uint8 Manufacturer;
    49 	Uint8 Version;
    50 	Uint8 Encoding;
    51 	Uint8 BitsPerPixel;
    52 	Sint16 Xmin, Ymin, Xmax, Ymax;
    53 	Sint16 HDpi, VDpi;
    54 	Uint8 Colormap[48];
    55 	Uint8 Reserved;
    56 	Uint8 NPlanes;
    57 	Sint16 BytesPerLine;
    58 	Sint16 PaletteInfo;
    59 	Sint16 HscreenSize;
    60 	Sint16 VscreenSize;
    61 	Uint8 Filler[54];
    62 };
    63 
    64 /* See if an image is contained in a data source */
    65 int IMG_isPCX(SDL_RWops *src)
    66 {
    67 	int is_PCX;
    68 	const int ZSoft_Manufacturer = 10;
    69 	const int PC_Paintbrush_Version = 5;
    70 	const int PCX_RunLength_Encoding = 1;
    71 	struct PCXheader pcxh;
    72 
    73 	is_PCX = 0;
    74 	if ( SDL_RWread(src, &pcxh, sizeof(pcxh), 1) == 1 ) {
    75 		if ( (pcxh.Manufacturer == ZSoft_Manufacturer) &&
    76 		     (pcxh.Version == PC_Paintbrush_Version) &&
    77 		     (pcxh.Encoding == PCX_RunLength_Encoding) ) {
    78 			is_PCX = 1;
    79 		}
    80 	}
    81 	return(is_PCX);
    82 }
    83 
    84 /* Load a PCX type image from an SDL datasource */
    85 SDL_Surface *IMG_LoadPCX_RW(SDL_RWops *src)
    86 {
    87 	struct PCXheader pcxh;
    88 	Uint32 Rmask;
    89 	Uint32 Gmask;
    90 	Uint32 Bmask;
    91 	Uint32 Amask;
    92 	SDL_Surface *surface = NULL;
    93 	int width, height;
    94 	int y, bpl;
    95 	Uint8 *row, *buf = NULL;
    96 	char *error = NULL;
    97 	int bits, src_bits;
    98 
    99 	if ( ! SDL_RWread(src, &pcxh, sizeof(pcxh), 1) ) {
   100 		error = "file truncated";
   101 		goto done;
   102 	}
   103 	pcxh.Xmin = SDL_SwapLE16(pcxh.Xmin);
   104 	pcxh.Ymin = SDL_SwapLE16(pcxh.Ymin);
   105 	pcxh.Xmax = SDL_SwapLE16(pcxh.Xmax);
   106 	pcxh.Ymax = SDL_SwapLE16(pcxh.Ymax);
   107 	pcxh.BytesPerLine = SDL_SwapLE16(pcxh.BytesPerLine);
   108 
   109 	/* Create the surface of the appropriate type */
   110 	width = (pcxh.Xmax - pcxh.Xmin) + 1;
   111 	height = (pcxh.Ymax - pcxh.Ymin) + 1;
   112 	Rmask = Gmask = Bmask = Amask = 0;
   113 	src_bits = pcxh.BitsPerPixel * pcxh.NPlanes;
   114 	if((pcxh.BitsPerPixel == 1 && pcxh.NPlanes >= 1 && pcxh.NPlanes <= 4)
   115 	   || (pcxh.BitsPerPixel == 8 && pcxh.NPlanes == 1)) {
   116 		bits = 8;
   117 	} else if(pcxh.BitsPerPixel == 8 && pcxh.NPlanes == 3) {
   118 		bits = 24;
   119 		if ( SDL_BYTEORDER == SDL_LIL_ENDIAN ) {
   120 			Rmask = 0x000000FF;
   121 			Gmask = 0x0000FF00;
   122 			Bmask = 0x00FF0000;
   123 		} else {
   124 			Rmask = 0xFF0000;
   125 			Gmask = 0x00FF00;
   126 			Bmask = 0x0000FF;
   127 		}
   128 	} else {
   129 		error = "unsupported PCX format";
   130 		goto done;
   131 	}
   132 	surface = SDL_AllocSurface(SDL_SWSURFACE, width, height,
   133 				   bits, Rmask, Gmask, Bmask, Amask);
   134 	if ( surface == NULL )
   135 		goto done;
   136 
   137 	bpl = pcxh.NPlanes * pcxh.BytesPerLine;
   138 	buf = malloc(bpl);
   139 	row = surface->pixels;
   140 	for ( y=0; y<surface->h; ++y ) {
   141 		/* decode a scan line to a temporary buffer first */
   142 		int i, count = 0;
   143 		Uint8 ch;
   144 		Uint8 *dst = (src_bits == 8) ? row : buf;
   145 		for(i = 0; i < bpl; i++) {
   146 			if(!count) {
   147 				if(!SDL_RWread(src, &ch, 1, 1)) {
   148 					error = "file truncated";
   149 					goto done;
   150 				}
   151 				if( (ch & 0xc0) == 0xc0) {
   152 					count = ch & 0x3f;
   153 					if(!SDL_RWread(src, &ch, 1, 1)) {
   154 						error = "file truncated";
   155 						goto done;
   156 					}
   157 				} else
   158 					count = 1;
   159 			}
   160 			dst[i] = ch;
   161 			count--;
   162 		}
   163 
   164 		if(src_bits <= 4) {
   165 			/* expand planes to 1 byte/pixel */
   166 			Uint8 *src = buf;
   167 			int plane;
   168 			for(plane = 0; plane < pcxh.NPlanes; plane++) {
   169 				int i, j, x = 0;
   170 				for(i = 0; i < pcxh.BytesPerLine; i++) {
   171 					Uint8 byte = *src++;
   172 					for(j = 7; j >= 0; j--) {
   173 						unsigned bit = (byte >> j) & 1;
   174 						/* skip padding bits */
   175 						if (i * 8 + j >= width)
   176 							continue;
   177 						row[x++] |= bit << plane;
   178 					}
   179 				}
   180 			}
   181  		} else if(src_bits == 24) {
   182 			/* de-interlace planes */
   183 			Uint8 *src = buf;
   184 			int plane;
   185 			for(plane = 0; plane < pcxh.NPlanes; plane++) {
   186 				int x;
   187 				dst = row + plane;
   188 				for(x = 0; x < width; x++) {
   189 					*dst = *src++;
   190 					dst += pcxh.NPlanes;
   191 				}
   192 			}
   193 		}
   194 
   195 		row += surface->pitch;
   196 	}
   197 
   198 	if(bits == 8) {
   199 		SDL_Color *colors = surface->format->palette->colors;
   200 		int nc = 1 << src_bits;
   201 		int i;
   202 
   203 		surface->format->palette->ncolors = nc;
   204 		if(src_bits == 8) {
   205 			Uint8 ch;
   206 			/* look for a 256-colour palette */
   207 			do {
   208 				if ( !SDL_RWread(src, &ch, 1, 1)) {
   209 					error = "file truncated";
   210 					goto done;
   211 				}
   212 			} while ( ch != 12 );
   213 
   214 			for(i = 0; i < 256; i++) {
   215 				SDL_RWread(src, &colors[i].r, 1, 1);
   216 				SDL_RWread(src, &colors[i].g, 1, 1);
   217 				SDL_RWread(src, &colors[i].b, 1, 1);
   218 			}
   219 		} else {
   220 			for(i = 0; i < nc; i++) {
   221 				colors[i].r = pcxh.Colormap[i * 3];
   222 				colors[i].g = pcxh.Colormap[i * 3 + 1];
   223 				colors[i].b = pcxh.Colormap[i * 3 + 2];
   224 			}
   225 		}
   226 	}
   227 
   228 done:
   229 	free(buf);
   230 	if ( error ) {
   231 		SDL_FreeSurface(surface);
   232 		IMG_SetError(error);
   233 		surface = NULL;
   234 	}
   235 	return(surface);
   236 }
   237 
   238 #else
   239 
   240 /* See if an image is contained in a data source */
   241 int IMG_isPCX(SDL_RWops *src)
   242 {
   243 	return(0);
   244 }
   245 
   246 /* Load a PCX type image from an SDL datasource */
   247 SDL_Surface *IMG_LoadPCX_RW(SDL_RWops *src)
   248 {
   249 	return(NULL);
   250 }
   251 
   252 #endif /* LOAD_PCX */