IMG_pnm.c
changeset 25 c9117619e2af
child 53 96b084473b47
equal deleted inserted replaced
24:69f3d44d56da 25:c9117619e2af
       
     1 /*
       
     2     IMGLIB:  An example image loading library for use with SDL
       
     3     Copyright (C) 1999  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     5635-34 Springhouse Dr.
       
    21     Pleasanton, CA 94588 (USA)
       
    22     slouken@devolution.com
       
    23 */
       
    24 
       
    25 /*
       
    26  * PNM (portable anymap) image loader:
       
    27  *
       
    28  * Supports: PBM, PGM and PPM, ASCII and binary formats
       
    29  * (PBM and PGM are loaded as 8bpp surfaces)
       
    30  * Does not support: maximum component value > 255
       
    31  */
       
    32 
       
    33 #include <stdio.h>
       
    34 #include <stdlib.h>
       
    35 #include <ctype.h>
       
    36 #include <string.h>
       
    37 
       
    38 #include "SDL_image.h"
       
    39 
       
    40 #ifdef LOAD_PNM
       
    41 
       
    42 /* See if an image is contained in a data source */
       
    43 int IMG_isPNM(SDL_RWops *src)
       
    44 {
       
    45 	char magic[2];
       
    46 
       
    47 	/*
       
    48 	 * PNM magic signatures:
       
    49 	 * P1	PBM, ascii format
       
    50 	 * P2	PGM, ascii format
       
    51 	 * P3	PPM, ascii format
       
    52 	 * P4	PBM, binary format
       
    53 	 * P5	PGM, binary format
       
    54 	 * P6	PPM, binary format
       
    55 	 */
       
    56 	return (SDL_RWread(src, magic, 2, 1)
       
    57 		&& magic[0] == 'P' && magic[1] >= '1' && magic[1] <= '6');
       
    58 }
       
    59 
       
    60 /* read a non-negative integer from the source. return -1 upon error */
       
    61 static int ReadNumber(SDL_RWops *src)
       
    62 {
       
    63 	int number;
       
    64 	unsigned char ch;
       
    65 
       
    66 	/* Initialize return value */
       
    67 	number = 0;
       
    68 
       
    69 	/* Skip leading whitespace */
       
    70 	do {
       
    71 		if ( ! SDL_RWread(src, &ch, 1, 1) ) {
       
    72 			return(0);
       
    73 		}
       
    74 		/* Eat comments as whitespace */
       
    75 		if ( ch == '#' ) {  /* Comment is '#' to end of line */
       
    76 			do {
       
    77 				if ( ! SDL_RWread(src, &ch, 1, 1) ) {
       
    78 					return -1;
       
    79 				}
       
    80 			} while ( (ch != '\r') && (ch != '\n') );
       
    81 		}
       
    82 	} while ( isspace(ch) );
       
    83 
       
    84 	/* Add up the number */
       
    85 	do {
       
    86 		number *= 10;
       
    87 		number += ch-'0';
       
    88 
       
    89 		if ( !SDL_RWread(src, &ch, 1, 1) ) {
       
    90 			return -1;
       
    91 		}
       
    92 	} while ( isdigit(ch) );
       
    93 
       
    94 	return(number);
       
    95 }
       
    96 
       
    97 SDL_Surface *IMG_LoadPNM_RW(SDL_RWops *src)
       
    98 {
       
    99 	SDL_Surface *surface = NULL;
       
   100 	int width, height;
       
   101 	int maxval, y, bpl;
       
   102 	Uint8 *row;
       
   103 	Uint8 *buf = NULL;
       
   104 	char *error = NULL;
       
   105 	Uint8 magic[2];
       
   106 	int ascii;
       
   107 	enum { PBM, PGM, PPM } kind;
       
   108 
       
   109 #define ERROR(s) do { error = (s); goto done; } while(0)
       
   110 
       
   111 	if(!src)
       
   112 		return NULL;
       
   113 
       
   114 	SDL_RWread(src, magic, 2, 1);
       
   115 	kind = magic[1] - '1';
       
   116 	ascii = 1;
       
   117 	if(kind >= 3) {
       
   118 		ascii = 0;
       
   119 		kind -= 3;
       
   120 	}
       
   121 
       
   122 	width = ReadNumber(src);
       
   123 	height = ReadNumber(src);
       
   124 	if(width <= 0 || height <= 0)
       
   125 		ERROR("Unable to read image width and height");
       
   126 
       
   127 	if(kind != PBM) {
       
   128 		maxval = ReadNumber(src);
       
   129 		if(maxval <= 0 || maxval > 255)
       
   130 			ERROR("unsupported PNM format");
       
   131 	} else
       
   132 		maxval = 255;	/* never scale PBMs */
       
   133 
       
   134 	/* binary PNM allows just a single character of whitespace after
       
   135 	   the last parameter, and we've already consumed it */
       
   136 
       
   137 	if(kind == PPM) {
       
   138 		/* 24-bit surface in R,G,B byte order */
       
   139 		surface = SDL_AllocSurface(SDL_SWSURFACE, width, height, 24,
       
   140 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
       
   141 					   0x000000ff, 0x0000ff00, 0x00ff0000,
       
   142 #else
       
   143 					   0x00ff0000, 0x0000ff00, 0x000000ff,
       
   144 #endif
       
   145 					   0);
       
   146 	} else {
       
   147 		/* load PBM/PGM as 8-bit indexed images */
       
   148 		surface = SDL_AllocSurface(SDL_SWSURFACE, width, height, 8,
       
   149 					   0, 0, 0, 0);
       
   150 	}
       
   151 	if ( surface == NULL )
       
   152 		ERROR("Out of memory");
       
   153 	bpl = width * surface->format->BytesPerPixel;
       
   154 	if(kind == PGM) {
       
   155 		SDL_Color *c = surface->format->palette->colors;
       
   156 		int i;
       
   157 		for(i = 0; i < 256; i++)
       
   158 			c[i].r = c[i].g = c[i].b = i;
       
   159 		surface->format->palette->ncolors = 256;
       
   160 	} else if(kind == PBM) {
       
   161 		/* for some reason PBM has 1=black, 0=white */
       
   162 		SDL_Color *c = surface->format->palette->colors;
       
   163 		c[0].r = c[0].g = c[0].b = 255;
       
   164 		c[1].r = c[1].g = c[1].b = 0;
       
   165 		surface->format->palette->ncolors = 2;
       
   166 		bpl = (width + 7) >> 3;
       
   167 		buf = malloc(bpl);
       
   168 		if(buf == NULL)
       
   169 			ERROR("Out of memory");
       
   170 	}
       
   171 
       
   172 	/* Read the image into the surface */
       
   173 	row = surface->pixels;
       
   174 	for(y = 0; y < height; y++) {
       
   175 		if(ascii) {
       
   176 			int i;
       
   177 			if(kind == PBM) {
       
   178 				for(i = 0; i < width; i++) {
       
   179 					Uint8 ch;
       
   180 					do {
       
   181 						if(!SDL_RWread(src, &ch,
       
   182 							       1, 1))
       
   183 						       ERROR("file truncated");
       
   184 						ch -= '0';
       
   185 					} while(ch > 1);
       
   186 					row[i] = ch;
       
   187 				}
       
   188 			} else {
       
   189 				for(i = 0; i < bpl; i++) {
       
   190 					int c;
       
   191 					c = ReadNumber(src);
       
   192 					if(c < 0)
       
   193 						ERROR("file truncated");
       
   194 					row[i] = c;
       
   195 				}
       
   196 			}
       
   197 		} else {
       
   198 			Uint8 *dst = (kind == PBM) ? buf : row;
       
   199 			if(!SDL_RWread(src, dst, bpl, 1))
       
   200 				ERROR("file truncated");
       
   201 			if(kind == PBM) {
       
   202 				/* expand bitmap to 8bpp */
       
   203 				int i;
       
   204 				for(i = 0; i < width; i++) {
       
   205 					int bit = 7 - (i & 7);
       
   206 					row[i] = (buf[i >> 3] >> bit) & 1;
       
   207 				}
       
   208 			}
       
   209 		}
       
   210 		if(maxval < 255) {
       
   211 			/* scale up to full dynamic range (slow) */
       
   212 			int i;
       
   213 			for(i = 0; i < bpl; i++)
       
   214 				row[i] = row[i] * 255 / maxval;
       
   215 		}
       
   216 		row += surface->pitch;
       
   217 	}
       
   218 done:
       
   219 	free(buf);
       
   220 	if(error) {
       
   221 		SDL_FreeSurface(surface);
       
   222 		IMG_SetError(error);
       
   223 		surface = NULL;
       
   224 	}
       
   225 	return(surface);
       
   226 }
       
   227 
       
   228 #else
       
   229 
       
   230 /* See if an image is contained in a data source */
       
   231 int IMG_isPNM(SDL_RWops *src)
       
   232 {
       
   233 	return(0);
       
   234 }
       
   235 
       
   236 /* Load a PNM type image from an SDL datasource */
       
   237 SDL_Surface *IMG_LoadPNM_RW(SDL_RWops *src)
       
   238 {
       
   239 	return(NULL);
       
   240 }
       
   241 
       
   242 #endif /* LOAD_PNM */