/* SDL_image: An example image loading library for use with SDL Copyright (C) 1999-2004 Sam Lantinga This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Sam Lantinga slouken@libsdl.org */ /* $Id$ */ /* * PCX file reader: * Supports: * 1..4 bits/pixel in multiplanar format (1 bit/plane/pixel) * 8 bits/pixel in single-planar format (8 bits/plane/pixel) * 24 bits/pixel in 3-plane format (8 bits/plane/pixel) * * (The <8bpp formats are expanded to 8bpp surfaces) * * Doesn't support: * single-planar packed-pixel formats other than 8bpp * 4-plane 32bpp format with a fourth "intensity" plane */ #include #include #include "SDL_endian.h" #include "SDL_image.h" #ifdef LOAD_PCX struct PCXheader { Uint8 Manufacturer; Uint8 Version; Uint8 Encoding; Uint8 BitsPerPixel; Sint16 Xmin, Ymin, Xmax, Ymax; Sint16 HDpi, VDpi; Uint8 Colormap[48]; Uint8 Reserved; Uint8 NPlanes; Sint16 BytesPerLine; Sint16 PaletteInfo; Sint16 HscreenSize; Sint16 VscreenSize; Uint8 Filler[54]; }; /* See if an image is contained in a data source */ int IMG_isPCX(SDL_RWops *src) { int is_PCX; const int ZSoft_Manufacturer = 10; const int PC_Paintbrush_Version = 5; const int PCX_RunLength_Encoding = 1; struct PCXheader pcxh; is_PCX = 0; if ( SDL_RWread(src, &pcxh, sizeof(pcxh), 1) == 1 ) { if ( (pcxh.Manufacturer == ZSoft_Manufacturer) && (pcxh.Version == PC_Paintbrush_Version) && (pcxh.Encoding == PCX_RunLength_Encoding) ) { is_PCX = 1; } } return(is_PCX); } /* Load a PCX type image from an SDL datasource */ SDL_Surface *IMG_LoadPCX_RW(SDL_RWops *src) { struct PCXheader pcxh; Uint32 Rmask; Uint32 Gmask; Uint32 Bmask; Uint32 Amask; SDL_Surface *surface = NULL; int width, height; int y, bpl; Uint8 *row, *buf = NULL; char *error = NULL; int bits, src_bits; if ( !src ) { /* The error message has been set in SDL_RWFromFile */ return NULL; } if ( ! SDL_RWread(src, &pcxh, sizeof(pcxh), 1) ) { error = "file truncated"; goto done; } pcxh.Xmin = SDL_SwapLE16(pcxh.Xmin); pcxh.Ymin = SDL_SwapLE16(pcxh.Ymin); pcxh.Xmax = SDL_SwapLE16(pcxh.Xmax); pcxh.Ymax = SDL_SwapLE16(pcxh.Ymax); pcxh.BytesPerLine = SDL_SwapLE16(pcxh.BytesPerLine); /* Create the surface of the appropriate type */ width = (pcxh.Xmax - pcxh.Xmin) + 1; height = (pcxh.Ymax - pcxh.Ymin) + 1; Rmask = Gmask = Bmask = Amask = 0; src_bits = pcxh.BitsPerPixel * pcxh.NPlanes; if((pcxh.BitsPerPixel == 1 && pcxh.NPlanes >= 1 && pcxh.NPlanes <= 4) || (pcxh.BitsPerPixel == 8 && pcxh.NPlanes == 1)) { bits = 8; } else if(pcxh.BitsPerPixel == 8 && pcxh.NPlanes == 3) { bits = 24; if ( SDL_BYTEORDER == SDL_LIL_ENDIAN ) { Rmask = 0x000000FF; Gmask = 0x0000FF00; Bmask = 0x00FF0000; } else { Rmask = 0xFF0000; Gmask = 0x00FF00; Bmask = 0x0000FF; } } else { error = "unsupported PCX format"; goto done; } surface = SDL_AllocSurface(SDL_SWSURFACE, width, height, bits, Rmask, Gmask, Bmask, Amask); if ( surface == NULL ) goto done; bpl = pcxh.NPlanes * pcxh.BytesPerLine; buf = malloc(bpl); row = surface->pixels; for ( y=0; yh; ++y ) { /* decode a scan line to a temporary buffer first */ int i, count = 0; Uint8 ch; Uint8 *dst = (src_bits == 8) ? row : buf; for(i = 0; i < bpl; i++) { if(!count) { if(!SDL_RWread(src, &ch, 1, 1)) { error = "file truncated"; goto done; } if( (ch & 0xc0) == 0xc0) { count = ch & 0x3f; if(!SDL_RWread(src, &ch, 1, 1)) { error = "file truncated"; goto done; } } else count = 1; } dst[i] = ch; count--; } if(src_bits <= 4) { /* expand planes to 1 byte/pixel */ Uint8 *src = buf; int plane; for(plane = 0; plane < pcxh.NPlanes; plane++) { int i, j, x = 0; for(i = 0; i < pcxh.BytesPerLine; i++) { Uint8 byte = *src++; for(j = 7; j >= 0; j--) { unsigned bit = (byte >> j) & 1; /* skip padding bits */ if (i * 8 + j >= width) continue; row[x++] |= bit << plane; } } } } else if(src_bits == 24) { /* de-interlace planes */ Uint8 *src = buf; int plane; for(plane = 0; plane < pcxh.NPlanes; plane++) { int x; dst = row + plane; for(x = 0; x < width; x++) { *dst = *src++; dst += pcxh.NPlanes; } } } row += surface->pitch; } if(bits == 8) { SDL_Color *colors = surface->format->palette->colors; int nc = 1 << src_bits; int i; surface->format->palette->ncolors = nc; if(src_bits == 8) { Uint8 ch; /* look for a 256-colour palette */ do { if ( !SDL_RWread(src, &ch, 1, 1)) { error = "file truncated"; goto done; } } while ( ch != 12 ); for(i = 0; i < 256; i++) { SDL_RWread(src, &colors[i].r, 1, 1); SDL_RWread(src, &colors[i].g, 1, 1); SDL_RWread(src, &colors[i].b, 1, 1); } } else { for(i = 0; i < nc; i++) { colors[i].r = pcxh.Colormap[i * 3]; colors[i].g = pcxh.Colormap[i * 3 + 1]; colors[i].b = pcxh.Colormap[i * 3 + 2]; } } } done: free(buf); if ( error ) { SDL_FreeSurface(surface); IMG_SetError(error); surface = NULL; } return(surface); } #else /* See if an image is contained in a data source */ int IMG_isPCX(SDL_RWops *src) { return(0); } /* Load a PCX type image from an SDL datasource */ SDL_Surface *IMG_LoadPCX_RW(SDL_RWops *src) { return(NULL); } #endif /* LOAD_PCX */