IMG_pnm.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  * 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 	SDL_RWread(src, magic, 2, 1);
   112 	kind = magic[1] - '1';
   113 	ascii = 1;
   114 	if(kind >= 3) {
   115 		ascii = 0;
   116 		kind -= 3;
   117 	}
   118 
   119 	width = ReadNumber(src);
   120 	height = ReadNumber(src);
   121 	if(width <= 0 || height <= 0)
   122 		ERROR("Unable to read image width and height");
   123 
   124 	if(kind != PBM) {
   125 		maxval = ReadNumber(src);
   126 		if(maxval <= 0 || maxval > 255)
   127 			ERROR("unsupported PNM format");
   128 	} else
   129 		maxval = 255;	/* never scale PBMs */
   130 
   131 	/* binary PNM allows just a single character of whitespace after
   132 	   the last parameter, and we've already consumed it */
   133 
   134 	if(kind == PPM) {
   135 		/* 24-bit surface in R,G,B byte order */
   136 		surface = SDL_AllocSurface(SDL_SWSURFACE, width, height, 24,
   137 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
   138 					   0x000000ff, 0x0000ff00, 0x00ff0000,
   139 #else
   140 					   0x00ff0000, 0x0000ff00, 0x000000ff,
   141 #endif
   142 					   0);
   143 	} else {
   144 		/* load PBM/PGM as 8-bit indexed images */
   145 		surface = SDL_AllocSurface(SDL_SWSURFACE, width, height, 8,
   146 					   0, 0, 0, 0);
   147 	}
   148 	if ( surface == NULL )
   149 		ERROR("Out of memory");
   150 	bpl = width * surface->format->BytesPerPixel;
   151 	if(kind == PGM) {
   152 		SDL_Color *c = surface->format->palette->colors;
   153 		int i;
   154 		for(i = 0; i < 256; i++)
   155 			c[i].r = c[i].g = c[i].b = i;
   156 		surface->format->palette->ncolors = 256;
   157 	} else if(kind == PBM) {
   158 		/* for some reason PBM has 1=black, 0=white */
   159 		SDL_Color *c = surface->format->palette->colors;
   160 		c[0].r = c[0].g = c[0].b = 255;
   161 		c[1].r = c[1].g = c[1].b = 0;
   162 		surface->format->palette->ncolors = 2;
   163 		bpl = (width + 7) >> 3;
   164 		buf = malloc(bpl);
   165 		if(buf == NULL)
   166 			ERROR("Out of memory");
   167 	}
   168 
   169 	/* Read the image into the surface */
   170 	row = surface->pixels;
   171 	for(y = 0; y < height; y++) {
   172 		if(ascii) {
   173 			int i;
   174 			if(kind == PBM) {
   175 				for(i = 0; i < width; i++) {
   176 					Uint8 ch;
   177 					do {
   178 						if(!SDL_RWread(src, &ch,
   179 							       1, 1))
   180 						       ERROR("file truncated");
   181 						ch -= '0';
   182 					} while(ch > 1);
   183 					row[i] = ch;
   184 				}
   185 			} else {
   186 				for(i = 0; i < bpl; i++) {
   187 					int c;
   188 					c = ReadNumber(src);
   189 					if(c < 0)
   190 						ERROR("file truncated");
   191 					row[i] = c;
   192 				}
   193 			}
   194 		} else {
   195 			Uint8 *dst = (kind == PBM) ? buf : row;
   196 			if(!SDL_RWread(src, dst, bpl, 1))
   197 				ERROR("file truncated");
   198 			if(kind == PBM) {
   199 				/* expand bitmap to 8bpp */
   200 				int i;
   201 				for(i = 0; i < width; i++) {
   202 					int bit = 7 - (i & 7);
   203 					row[i] = (buf[i >> 3] >> bit) & 1;
   204 				}
   205 			}
   206 		}
   207 		if(maxval < 255) {
   208 			/* scale up to full dynamic range (slow) */
   209 			int i;
   210 			for(i = 0; i < bpl; i++)
   211 				row[i] = row[i] * 255 / maxval;
   212 		}
   213 		row += surface->pitch;
   214 	}
   215 done:
   216 	free(buf);
   217 	if(error) {
   218 		SDL_FreeSurface(surface);
   219 		IMG_SetError(error);
   220 		surface = NULL;
   221 	}
   222 	return(surface);
   223 }
   224 
   225 #else
   226 
   227 /* See if an image is contained in a data source */
   228 int IMG_isPNM(SDL_RWops *src)
   229 {
   230 	return(0);
   231 }
   232 
   233 /* Load a PNM type image from an SDL datasource */
   234 SDL_Surface *IMG_LoadPNM_RW(SDL_RWops *src)
   235 {
   236 	return(NULL);
   237 }
   238 
   239 #endif /* LOAD_PNM */