Added general PNM (PPM/PGM/PBM) support
authorSam Lantinga <slouken@lokigames.com>
Wed, 07 Mar 2001 16:59:28 +0000
changeset 2469f3d44d56da
parent 23 234c77dda0d2
child 25 c9117619e2af
Added general PNM (PPM/PGM/PBM) support
CHANGES
IMG.c
IMG_pcx.c
IMG_ppm.c
README
SDL_image.h
configure.in
     1.1 --- a/CHANGES	Sun Mar 04 22:22:57 2001 +0000
     1.2 +++ b/CHANGES	Wed Mar 07 16:59:28 2001 +0000
     1.3 @@ -1,5 +1,7 @@
     1.4  
     1.5  1.1.1:
     1.6 +Mattias Engdegård - Wed Mar  7 09:01:49 PST 2001
     1.7 + * Added general PNM (PPM/PGM/PBM) support
     1.8  Mattias Engdegård - Sun Mar  4 14:23:42 PST 2001
     1.9   * Fixed bugs in PPM support, added ASCII PPM support
    1.10  Mattias Engdegård - Fri Mar  2 14:48:09 PST 2001
     2.1 --- a/IMG.c	Sun Mar 04 22:22:57 2001 +0000
     2.2 +++ b/IMG.c	Wed Mar 07 16:59:28 2001 +0000
     2.3 @@ -38,10 +38,10 @@
     2.4  	int (*is)(SDL_RWops *src);
     2.5  	SDL_Surface *(*load)(SDL_RWops *src);
     2.6  } supported[] = {
     2.7 -        /* keep magicless formats first (denoted by is==NULL) */
     2.8 -	{ "TGA", NULL,      IMG_LoadTGA_RW },
     2.9 +	/* keep magicless formats first */
    2.10 +	{ "TGA", 0,         IMG_LoadTGA_RW },
    2.11  	{ "BMP", IMG_isBMP, IMG_LoadBMP_RW },
    2.12 -	{ "PPM", IMG_isPPM, IMG_LoadPPM_RW },
    2.13 +	{ "PNM", IMG_isPNM, IMG_LoadPNM_RW }, /* P[BGP]M share code */
    2.14  	{ "XPM", IMG_isXPM, IMG_LoadXPM_RW },
    2.15  	{ "PCX", IMG_isPCX, IMG_LoadPCX_RW },
    2.16  	{ "GIF", IMG_isGIF, IMG_LoadGIF_RW },
     3.1 --- a/IMG_pcx.c	Sun Mar 04 22:22:57 2001 +0000
     3.2 +++ b/IMG_pcx.c	Wed Mar 07 16:59:28 2001 +0000
     3.3 @@ -29,6 +29,8 @@
     3.4   *  8 bits/pixel in single-planar format (8 bits/plane/pixel)
     3.5   *  24 bits/pixel in 3-plane format (8 bits/plane/pixel)
     3.6   *
     3.7 + * (The <8bpp formats are expanded to 8bpp surfaces)
     3.8 + *
     3.9   * Doesn't support:
    3.10   *  single-planar packed-pixel formats other than 8bpp
    3.11   *  4-plane 32bpp format with a fourth "intensity" plane
     4.1 --- a/IMG_ppm.c	Sun Mar 04 22:22:57 2001 +0000
     4.2 +++ b/IMG_ppm.c	Wed Mar 07 16:59:28 2001 +0000
     4.3 @@ -23,31 +23,38 @@
     4.4  */
     4.5  
     4.6  /*
     4.7 - * PPM (portable pixmap) image loader:
     4.8 + * PNM (portable anymap) image loader:
     4.9   *
    4.10 - * Supports: ASCII (P3) and binary (P6) formats
    4.11 + * Supports: PBM, PGM and PPM, ASCII and binary formats
    4.12 + * (PBM and PGM are loaded as 8bpp surfaces)
    4.13   * Does not support: maximum component value > 255
    4.14 - *
    4.15 - * TODO: add PGM (greyscale) and PBM (monochrome bitmap) support.
    4.16 - *       Should be easy since almost all code is already in place
    4.17   */
    4.18  
    4.19  #include <stdio.h>
    4.20 +#include <stdlib.h>
    4.21  #include <ctype.h>
    4.22  #include <string.h>
    4.23  
    4.24  #include "SDL_image.h"
    4.25  
    4.26 -#ifdef LOAD_PPM
    4.27 +#ifdef LOAD_PNM
    4.28  
    4.29  /* See if an image is contained in a data source */
    4.30 -int IMG_isPPM(SDL_RWops *src)
    4.31 +int IMG_isPNM(SDL_RWops *src)
    4.32  {
    4.33  	char magic[2];
    4.34  
    4.35 -	/* "P3" is the ASCII PPM format, "P6" the binary PPM format */
    4.36 +	/*
    4.37 +	 * PNM magic signatures:
    4.38 +	 * P1	PBM, ascii format
    4.39 +	 * P2	PGM, ascii format
    4.40 +	 * P3	PPM, ascii format
    4.41 +	 * P4	PBM, binary format
    4.42 +	 * P5	PGM, binary format
    4.43 +	 * P6	PPM, binary format
    4.44 +	 */
    4.45  	return (SDL_RWread(src, magic, 2, 1)
    4.46 -		&& magic[0] == 'P' && (magic[1] == '3' || magic[1] == '6'));
    4.47 +		&& magic[0] == 'P' && magic[1] >= '1' && magic[1] <= '6');
    4.48  }
    4.49  
    4.50  /* read a non-negative integer from the source. return -1 upon error */
    4.51 @@ -87,70 +94,117 @@
    4.52  	return(number);
    4.53  }
    4.54  
    4.55 -SDL_Surface *IMG_LoadPPM_RW(SDL_RWops *src)
    4.56 +SDL_Surface *IMG_LoadPNM_RW(SDL_RWops *src)
    4.57  {
    4.58  	SDL_Surface *surface = NULL;
    4.59  	int width, height;
    4.60  	int maxval, y, bpl;
    4.61  	Uint8 *row;
    4.62 +	Uint8 *buf = NULL;
    4.63  	char *error = NULL;
    4.64  	Uint8 magic[2];
    4.65  	int ascii;
    4.66 +	enum { PBM, PGM, PPM } kind;
    4.67  
    4.68 -	if ( ! src ) {
    4.69 -		goto done;
    4.70 -	}
    4.71 +#define ERROR(s) do { error = (s); goto done; } while(0)
    4.72 +
    4.73 +	if(!src)
    4.74 +		return NULL;
    4.75  
    4.76  	SDL_RWread(src, magic, 2, 1);
    4.77 -	ascii = (magic[1] == '3');
    4.78 +	kind = magic[1] - '1';
    4.79 +	ascii = 1;
    4.80 +	if(kind >= 3) {
    4.81 +		ascii = 0;
    4.82 +		kind -= 3;
    4.83 +	}
    4.84  
    4.85  	width = ReadNumber(src);
    4.86  	height = ReadNumber(src);
    4.87 -	if(width <= 0 || height <= 0) {
    4.88 -		error = "Unable to read image width and height";
    4.89 -		goto done;
    4.90 +	if(width <= 0 || height <= 0)
    4.91 +		ERROR("Unable to read image width and height");
    4.92 +
    4.93 +	if(kind != PBM) {
    4.94 +		maxval = ReadNumber(src);
    4.95 +		if(maxval <= 0 || maxval > 255)
    4.96 +			ERROR("unsupported PNM format");
    4.97 +	} else
    4.98 +		maxval = 255;	/* never scale PBMs */
    4.99 +
   4.100 +	/* binary PNM allows just a single character of whitespace after
   4.101 +	   the last parameter, and we've already consumed it */
   4.102 +
   4.103 +	if(kind == PPM) {
   4.104 +		/* 24-bit surface in R,G,B byte order */
   4.105 +		surface = SDL_AllocSurface(SDL_SWSURFACE, width, height, 24,
   4.106 +#if SDL_BYTEORDER == SDL_LIL_ENDIAN
   4.107 +					   0x000000ff, 0x0000ff00, 0x00ff0000,
   4.108 +#else
   4.109 +					   0x00ff0000, 0x0000ff00, 0x000000ff,
   4.110 +#endif
   4.111 +					   0);
   4.112 +	} else {
   4.113 +		/* load PBM/PGM as 8-bit indexed images */
   4.114 +		surface = SDL_AllocSurface(SDL_SWSURFACE, width, height, 8,
   4.115 +					   0, 0, 0, 0);
   4.116  	}
   4.117 -
   4.118 -	maxval = ReadNumber(src);
   4.119 -	if(maxval <= 0 || maxval > 255) {
   4.120 -		error = "unsupported ppm format";
   4.121 -		goto done;
   4.122 -	}
   4.123 -	/* binary PPM allows just a single character of whitespace after
   4.124 -	   the maxval, and we've already consumed it */
   4.125 -
   4.126 -	/* 24-bit surface in R,G,B byte order */
   4.127 -	surface = SDL_AllocSurface(SDL_SWSURFACE, width, height, 24,
   4.128 -#if SDL_BYTEORDER == SDL_LIL_ENDIAN
   4.129 -				   0x000000ff, 0x0000ff00, 0x00ff0000,
   4.130 -#else
   4.131 -				   0x00ff0000, 0x0000ff00, 0x000000ff,
   4.132 -#endif
   4.133 -				   0);
   4.134 -	if ( surface == NULL ) {
   4.135 -		error = "Out of memory";
   4.136 -		goto done;
   4.137 +	if ( surface == NULL )
   4.138 +		ERROR("Out of memory");
   4.139 +	bpl = width * surface->format->BytesPerPixel;
   4.140 +	if(kind == PGM) {
   4.141 +		SDL_Color *c = surface->format->palette->colors;
   4.142 +		int i;
   4.143 +		for(i = 0; i < 256; i++)
   4.144 +			c[i].r = c[i].g = c[i].b = i;
   4.145 +		surface->format->palette->ncolors = 256;
   4.146 +	} else if(kind == PBM) {
   4.147 +		/* for some reason PBM has 1=black, 0=white */
   4.148 +		SDL_Color *c = surface->format->palette->colors;
   4.149 +		c[0].r = c[0].g = c[0].b = 255;
   4.150 +		c[1].r = c[1].g = c[1].b = 0;
   4.151 +		surface->format->palette->ncolors = 2;
   4.152 +		bpl = (width + 7) >> 3;
   4.153 +		buf = malloc(bpl);
   4.154 +		if(buf == NULL)
   4.155 +			ERROR("Out of memory");
   4.156  	}
   4.157  
   4.158  	/* Read the image into the surface */
   4.159  	row = surface->pixels;
   4.160 -	bpl = width * 3;
   4.161  	for(y = 0; y < height; y++) {
   4.162  		if(ascii) {
   4.163  			int i;
   4.164 -			for(i = 0; i < bpl; i++) {
   4.165 -				int c;
   4.166 -				c = ReadNumber(src);
   4.167 -				if(c < 0) {
   4.168 -					error = "file truncated";
   4.169 -					goto done;
   4.170 +			if(kind == PBM) {
   4.171 +				for(i = 0; i < width; i++) {
   4.172 +					Uint8 ch;
   4.173 +					do {
   4.174 +						if(!SDL_RWread(src, &ch,
   4.175 +							       1, 1))
   4.176 +						       ERROR("file truncated");
   4.177 +						ch -= '0';
   4.178 +					} while(ch > 1);
   4.179 +					row[i] = ch;
   4.180  				}
   4.181 -				row[i] = c;
   4.182 +			} else {
   4.183 +				for(i = 0; i < bpl; i++) {
   4.184 +					int c;
   4.185 +					c = ReadNumber(src);
   4.186 +					if(c < 0)
   4.187 +						ERROR("file truncated");
   4.188 +					row[i] = c;
   4.189 +				}
   4.190  			}
   4.191  		} else {
   4.192 -			if(!SDL_RWread(src, row, bpl, 1)) {
   4.193 -				error = "file truncated";
   4.194 -				goto done;
   4.195 +			Uint8 *dst = (kind == PBM) ? buf : row;
   4.196 +			if(!SDL_RWread(src, dst, bpl, 1))
   4.197 +				ERROR("file truncated");
   4.198 +			if(kind == PBM) {
   4.199 +				/* expand bitmap to 8bpp */
   4.200 +				int i;
   4.201 +				for(i = 0; i < width; i++) {
   4.202 +					int bit = 7 - (i & 7);
   4.203 +					row[i] = (buf[i >> 3] >> bit) & 1;
   4.204 +				}
   4.205  			}
   4.206  		}
   4.207  		if(maxval < 255) {
   4.208 @@ -162,6 +216,7 @@
   4.209  		row += surface->pitch;
   4.210  	}
   4.211  done:
   4.212 +	free(buf);
   4.213  	if(error) {
   4.214  		SDL_FreeSurface(surface);
   4.215  		IMG_SetError(error);
   4.216 @@ -173,15 +228,15 @@
   4.217  #else
   4.218  
   4.219  /* See if an image is contained in a data source */
   4.220 -int IMG_isPPM(SDL_RWops *src)
   4.221 +int IMG_isPNM(SDL_RWops *src)
   4.222  {
   4.223  	return(0);
   4.224  }
   4.225  
   4.226 -/* Load a PPM type image from an SDL datasource */
   4.227 -SDL_Surface *IMG_LoadPPM_RW(SDL_RWops *src)
   4.228 +/* Load a PNM type image from an SDL datasource */
   4.229 +SDL_Surface *IMG_LoadPNM_RW(SDL_RWops *src)
   4.230  {
   4.231  	return(NULL);
   4.232  }
   4.233  
   4.234 -#endif /* LOAD_PPM */
   4.235 +#endif /* LOAD_PNM */
     5.1 --- a/README	Sun Mar 04 22:22:57 2001 +0000
     5.2 +++ b/README	Wed Mar 07 16:59:28 2001 +0000
     5.3 @@ -5,7 +5,8 @@
     5.4  http://www.devolution.com/~slouken/SDL/projects/SDL_image/
     5.5  
     5.6  This is a simple library to load images of various formats as SDL surfaces.
     5.7 -This library supports BMP, PPM, XPM, PCX, GIF, JPEG, PNG, TGA, and TIFF formats.
     5.8 +This library supports BMP, PNM (PPM/PGM/PBM), XPM, PCX, GIF, JPEG, PNG,
     5.9 +TGA, and TIFF formats.
    5.10  
    5.11  API:
    5.12  #include "SDL_image.h"
     6.1 --- a/SDL_image.h	Sun Mar 04 22:22:57 2001 +0000
     6.2 +++ b/SDL_image.h	Wed Mar 07 16:59:28 2001 +0000
     6.3 @@ -56,7 +56,7 @@
     6.4  
     6.5  /* Functions to detect a file type, given a seekable source */
     6.6  extern DECLSPEC int IMG_isBMP(SDL_RWops *src);
     6.7 -extern DECLSPEC int IMG_isPPM(SDL_RWops *src);
     6.8 +extern DECLSPEC int IMG_isPNM(SDL_RWops *src);
     6.9  extern DECLSPEC int IMG_isXPM(SDL_RWops *src);
    6.10  extern DECLSPEC int IMG_isPCX(SDL_RWops *src);
    6.11  extern DECLSPEC int IMG_isGIF(SDL_RWops *src);
    6.12 @@ -66,7 +66,7 @@
    6.13  
    6.14  /* Individual loading functions */
    6.15  extern DECLSPEC SDL_Surface *IMG_LoadBMP_RW(SDL_RWops *src);
    6.16 -extern DECLSPEC SDL_Surface *IMG_LoadPPM_RW(SDL_RWops *src);
    6.17 +extern DECLSPEC SDL_Surface *IMG_LoadPNM_RW(SDL_RWops *src);
    6.18  extern DECLSPEC SDL_Surface *IMG_LoadXPM_RW(SDL_RWops *src);
    6.19  extern DECLSPEC SDL_Surface *IMG_LoadPCX_RW(SDL_RWops *src);
    6.20  extern DECLSPEC SDL_Surface *IMG_LoadGIF_RW(SDL_RWops *src);
     7.1 --- a/configure.in	Sun Mar 04 22:22:57 2001 +0000
     7.2 +++ b/configure.in	Wed Mar 07 16:59:28 2001 +0000
     7.3 @@ -131,11 +131,11 @@
     7.4          AC_MSG_WARN([PNG image loading disabled])
     7.5      fi
     7.6  fi
     7.7 -AC_ARG_ENABLE(ppm,
     7.8 -[  --enable-ppm            support loading PPM images [default=yes]],
     7.9 -              , enable_ppm=yes)
    7.10 -if test x$enable_ppm = xyes; then
    7.11 -    CFLAGS="$CFLAGS -DLOAD_PPM"
    7.12 +AC_ARG_ENABLE(pnm,
    7.13 +[  --enable-pnm            support loading PNM images [default=yes]],
    7.14 +              , enable_pnm=yes)
    7.15 +if test x$enable_pnm = xyes; then
    7.16 +    CFLAGS="$CFLAGS -DLOAD_PNM"
    7.17  fi
    7.18  AC_ARG_ENABLE(tga,
    7.19  [  --enable-tga            support loading TGA images [default=yes]],