IMG_pnm.c
changeset 368 8a61842d00ce
parent 367 b2aa197f6774
child 451 48116d511e5d
equal deleted inserted replaced
367:b2aa197f6774 368:8a61842d00ce
    37 #ifdef LOAD_PNM
    37 #ifdef LOAD_PNM
    38 
    38 
    39 /* See if an image is contained in a data source */
    39 /* See if an image is contained in a data source */
    40 int IMG_isPNM(SDL_RWops *src)
    40 int IMG_isPNM(SDL_RWops *src)
    41 {
    41 {
    42 	Sint64 start;
    42     Sint64 start;
    43 	int is_PNM;
    43     int is_PNM;
    44 	char magic[2];
    44     char magic[2];
    45 
    45 
    46 	if ( !src )
    46     if ( !src )
    47 		return 0;
    47         return 0;
    48 	start = SDL_RWtell(src);
    48     start = SDL_RWtell(src);
    49 	is_PNM = 0;
    49     is_PNM = 0;
    50 	if ( SDL_RWread(src, magic, sizeof(magic), 1) ) {
    50     if ( SDL_RWread(src, magic, sizeof(magic), 1) ) {
    51 		/*
    51         /*
    52 		 * PNM magic signatures:
    52          * PNM magic signatures:
    53 		 * P1	PBM, ascii format
    53          * P1   PBM, ascii format
    54 		 * P2	PGM, ascii format
    54          * P2   PGM, ascii format
    55 		 * P3	PPM, ascii format
    55          * P3   PPM, ascii format
    56 		 * P4	PBM, binary format
    56          * P4   PBM, binary format
    57 		 * P5	PGM, binary format
    57          * P5   PGM, binary format
    58 		 * P6	PPM, binary format
    58          * P6   PPM, binary format
    59 		 * P7	PAM, a general wrapper for PNM data
    59          * P7   PAM, a general wrapper for PNM data
    60 		 */
    60          */
    61 		if ( magic[0] == 'P' && magic[1] >= '1' && magic[1] <= '6' ) {
    61         if ( magic[0] == 'P' && magic[1] >= '1' && magic[1] <= '6' ) {
    62 			is_PNM = 1;
    62             is_PNM = 1;
    63 		}
    63         }
    64 	}
    64     }
    65 	SDL_RWseek(src, start, RW_SEEK_SET);
    65     SDL_RWseek(src, start, RW_SEEK_SET);
    66 	return(is_PNM);
    66     return(is_PNM);
    67 }
    67 }
    68 
    68 
    69 /* read a non-negative integer from the source. return -1 upon error */
    69 /* read a non-negative integer from the source. return -1 upon error */
    70 static int ReadNumber(SDL_RWops *src)
    70 static int ReadNumber(SDL_RWops *src)
    71 {
    71 {
    72 	int number;
    72     int number;
    73 	unsigned char ch;
    73     unsigned char ch;
    74 
    74 
    75 	/* Initialize return value */
    75     /* Initialize return value */
    76 	number = 0;
    76     number = 0;
    77 
    77 
    78 	/* Skip leading whitespace */
    78     /* Skip leading whitespace */
    79 	do {
    79     do {
    80 		if ( ! SDL_RWread(src, &ch, 1, 1) ) {
    80         if ( ! SDL_RWread(src, &ch, 1, 1) ) {
    81 			return(0);
    81             return(0);
    82 		}
    82         }
    83 		/* Eat comments as whitespace */
    83         /* Eat comments as whitespace */
    84 		if ( ch == '#' ) {  /* Comment is '#' to end of line */
    84         if ( ch == '#' ) {  /* Comment is '#' to end of line */
    85 			do {
    85             do {
    86 				if ( ! SDL_RWread(src, &ch, 1, 1) ) {
    86                 if ( ! SDL_RWread(src, &ch, 1, 1) ) {
    87 					return -1;
    87                     return -1;
    88 				}
    88                 }
    89 			} while ( (ch != '\r') && (ch != '\n') );
    89             } while ( (ch != '\r') && (ch != '\n') );
    90 		}
    90         }
    91 	} while ( isspace(ch) );
    91     } while ( isspace(ch) );
    92 
    92 
    93 	/* Add up the number */
    93     /* Add up the number */
    94 	do {
    94     do {
    95 		number *= 10;
    95         number *= 10;
    96 		number += ch-'0';
    96         number += ch-'0';
    97 
    97 
    98 		if ( !SDL_RWread(src, &ch, 1, 1) ) {
    98         if ( !SDL_RWread(src, &ch, 1, 1) ) {
    99 			return -1;
    99             return -1;
   100 		}
   100         }
   101 	} while ( isdigit(ch) );
   101     } while ( isdigit(ch) );
   102 
   102 
   103 	return(number);
   103     return(number);
   104 }
   104 }
   105 
   105 
   106 SDL_Surface *IMG_LoadPNM_RW(SDL_RWops *src)
   106 SDL_Surface *IMG_LoadPNM_RW(SDL_RWops *src)
   107 {
   107 {
   108 	Sint64 start;
   108     Sint64 start;
   109 	SDL_Surface *surface = NULL;
   109     SDL_Surface *surface = NULL;
   110 	int width, height;
   110     int width, height;
   111 	int maxval, y, bpl;
   111     int maxval, y, bpl;
   112 	Uint8 *row;
   112     Uint8 *row;
   113 	Uint8 *buf = NULL;
   113     Uint8 *buf = NULL;
   114 	char *error = NULL;
   114     char *error = NULL;
   115 	Uint8 magic[2];
   115     Uint8 magic[2];
   116 	int ascii;
   116     int ascii;
   117 	enum { PBM, PGM, PPM, PAM } kind;
   117     enum { PBM, PGM, PPM, PAM } kind;
   118 
   118 
   119 #define ERROR(s) do { error = (s); goto done; } while(0)
   119 #define ERROR(s) do { error = (s); goto done; } while(0)
   120 
   120 
   121 	if ( !src ) {
   121     if ( !src ) {
   122 		/* The error message has been set in SDL_RWFromFile */
   122         /* The error message has been set in SDL_RWFromFile */
   123 		return NULL;
   123         return NULL;
   124 	}
   124     }
   125 	start = SDL_RWtell(src);
   125     start = SDL_RWtell(src);
   126 
   126 
   127 	SDL_RWread(src, magic, 2, 1);
   127     SDL_RWread(src, magic, 2, 1);
   128 	kind = magic[1] - '1';
   128     kind = magic[1] - '1';
   129 	ascii = 1;
   129     ascii = 1;
   130 	if(kind >= 3) {
   130     if(kind >= 3) {
   131 		ascii = 0;
   131         ascii = 0;
   132 		kind -= 3;
   132         kind -= 3;
   133 	}
   133     }
   134 
   134 
   135 	width = ReadNumber(src);
   135     width = ReadNumber(src);
   136 	height = ReadNumber(src);
   136     height = ReadNumber(src);
   137 	if(width <= 0 || height <= 0)
   137     if(width <= 0 || height <= 0)
   138 		ERROR("Unable to read image width and height");
   138         ERROR("Unable to read image width and height");
   139 
   139 
   140 	if(kind != PBM) {
   140     if(kind != PBM) {
   141 		maxval = ReadNumber(src);
   141         maxval = ReadNumber(src);
   142 		if(maxval <= 0 || maxval > 255)
   142         if(maxval <= 0 || maxval > 255)
   143 			ERROR("unsupported PNM format");
   143             ERROR("unsupported PNM format");
   144 	} else
   144     } else
   145 		maxval = 255;	/* never scale PBMs */
   145         maxval = 255;   /* never scale PBMs */
   146 
   146 
   147 	/* binary PNM allows just a single character of whitespace after
   147     /* binary PNM allows just a single character of whitespace after
   148 	   the last parameter, and we've already consumed it */
   148        the last parameter, and we've already consumed it */
   149 
   149 
   150 	if(kind == PPM) {
   150     if(kind == PPM) {
   151 		/* 24-bit surface in R,G,B byte order */
   151         /* 24-bit surface in R,G,B byte order */
   152 		surface = SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, 24,
   152         surface = SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, 24,
   153 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
   153 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
   154 					   0x000000ff, 0x0000ff00, 0x00ff0000,
   154                        0x000000ff, 0x0000ff00, 0x00ff0000,
   155 #else
   155 #else
   156 					   0x00ff0000, 0x0000ff00, 0x000000ff,
   156                        0x00ff0000, 0x0000ff00, 0x000000ff,
   157 #endif
   157 #endif
   158 					   0);
   158                        0);
   159 	} else {
   159     } else {
   160 		/* load PBM/PGM as 8-bit indexed images */
   160         /* load PBM/PGM as 8-bit indexed images */
   161 		surface = SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, 8,
   161         surface = SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, 8,
   162 					   0, 0, 0, 0);
   162                        0, 0, 0, 0);
   163 	}
   163     }
   164 	if ( surface == NULL )
   164     if ( surface == NULL )
   165 		ERROR("Out of memory");
   165         ERROR("Out of memory");
   166 	bpl = width * surface->format->BytesPerPixel;
   166     bpl = width * surface->format->BytesPerPixel;
   167 	if(kind == PGM) {
   167     if(kind == PGM) {
   168 		SDL_Color *c = surface->format->palette->colors;
   168         SDL_Color *c = surface->format->palette->colors;
   169 		int i;
   169         int i;
   170 		for(i = 0; i < 256; i++)
   170         for(i = 0; i < 256; i++)
   171 			c[i].r = c[i].g = c[i].b = i;
   171             c[i].r = c[i].g = c[i].b = i;
   172 		surface->format->palette->ncolors = 256;
   172         surface->format->palette->ncolors = 256;
   173 	} else if(kind == PBM) {
   173     } else if(kind == PBM) {
   174 		/* for some reason PBM has 1=black, 0=white */
   174         /* for some reason PBM has 1=black, 0=white */
   175 		SDL_Color *c = surface->format->palette->colors;
   175         SDL_Color *c = surface->format->palette->colors;
   176 		c[0].r = c[0].g = c[0].b = 255;
   176         c[0].r = c[0].g = c[0].b = 255;
   177 		c[1].r = c[1].g = c[1].b = 0;
   177         c[1].r = c[1].g = c[1].b = 0;
   178 		surface->format->palette->ncolors = 2;
   178         surface->format->palette->ncolors = 2;
   179 		bpl = (width + 7) >> 3;
   179         bpl = (width + 7) >> 3;
   180 		buf = (Uint8 *)SDL_malloc(bpl);
   180         buf = (Uint8 *)SDL_malloc(bpl);
   181 		if(buf == NULL)
   181         if(buf == NULL)
   182 			ERROR("Out of memory");
   182             ERROR("Out of memory");
   183 	}
   183     }
   184 
   184 
   185 	/* Read the image into the surface */
   185     /* Read the image into the surface */
   186 	row = (Uint8 *)surface->pixels;
   186     row = (Uint8 *)surface->pixels;
   187 	for(y = 0; y < height; y++) {
   187     for(y = 0; y < height; y++) {
   188 		if(ascii) {
   188         if(ascii) {
   189 			int i;
   189             int i;
   190 			if(kind == PBM) {
   190             if(kind == PBM) {
   191 				for(i = 0; i < width; i++) {
   191                 for(i = 0; i < width; i++) {
   192 					Uint8 ch;
   192                     Uint8 ch;
   193 					do {
   193                     do {
   194 						if(!SDL_RWread(src, &ch,
   194                         if(!SDL_RWread(src, &ch,
   195 							       1, 1))
   195                                    1, 1))
   196 						       ERROR("file truncated");
   196                                ERROR("file truncated");
   197 						ch -= '0';
   197                         ch -= '0';
   198 					} while(ch > 1);
   198                     } while(ch > 1);
   199 					row[i] = ch;
   199                     row[i] = ch;
   200 				}
   200                 }
   201 			} else {
   201             } else {
   202 				for(i = 0; i < bpl; i++) {
   202                 for(i = 0; i < bpl; i++) {
   203 					int c;
   203                     int c;
   204 					c = ReadNumber(src);
   204                     c = ReadNumber(src);
   205 					if(c < 0)
   205                     if(c < 0)
   206 						ERROR("file truncated");
   206                         ERROR("file truncated");
   207 					row[i] = c;
   207                     row[i] = c;
   208 				}
   208                 }
   209 			}
   209             }
   210 		} else {
   210         } else {
   211 			Uint8 *dst = (kind == PBM) ? buf : row;
   211             Uint8 *dst = (kind == PBM) ? buf : row;
   212 			if(!SDL_RWread(src, dst, bpl, 1))
   212             if(!SDL_RWread(src, dst, bpl, 1))
   213 				ERROR("file truncated");
   213                 ERROR("file truncated");
   214 			if(kind == PBM) {
   214             if(kind == PBM) {
   215 				/* expand bitmap to 8bpp */
   215                 /* expand bitmap to 8bpp */
   216 				int i;
   216                 int i;
   217 				for(i = 0; i < width; i++) {
   217                 for(i = 0; i < width; i++) {
   218 					int bit = 7 - (i & 7);
   218                     int bit = 7 - (i & 7);
   219 					row[i] = (buf[i >> 3] >> bit) & 1;
   219                     row[i] = (buf[i >> 3] >> bit) & 1;
   220 				}
   220                 }
   221 			}
   221             }
   222 		}
   222         }
   223 		if(maxval < 255) {
   223         if(maxval < 255) {
   224 			/* scale up to full dynamic range (slow) */
   224             /* scale up to full dynamic range (slow) */
   225 			int i;
   225             int i;
   226 			for(i = 0; i < bpl; i++)
   226             for(i = 0; i < bpl; i++)
   227 				row[i] = row[i] * 255 / maxval;
   227                 row[i] = row[i] * 255 / maxval;
   228 		}
   228         }
   229 		row += surface->pitch;
   229         row += surface->pitch;
   230 	}
   230     }
   231 done:
   231 done:
   232 	SDL_free(buf);
   232     SDL_free(buf);
   233 	if(error) {
   233     if(error) {
   234 		SDL_RWseek(src, start, RW_SEEK_SET);
   234         SDL_RWseek(src, start, RW_SEEK_SET);
   235 		if ( surface ) {
   235         if ( surface ) {
   236 			SDL_FreeSurface(surface);
   236             SDL_FreeSurface(surface);
   237 			surface = NULL;
   237             surface = NULL;
   238 		}
   238         }
   239 		IMG_SetError(error);
   239         IMG_SetError(error);
   240 	}
   240     }
   241 	return(surface);
   241     return(surface);
   242 }
   242 }
   243 
   243 
   244 #else
   244 #else
   245 
   245 
   246 /* See if an image is contained in a data source */
   246 /* See if an image is contained in a data source */
   247 int IMG_isPNM(SDL_RWops *src)
   247 int IMG_isPNM(SDL_RWops *src)
   248 {
   248 {
   249 	return(0);
   249     return(0);
   250 }
   250 }
   251 
   251 
   252 /* Load a PNM type image from an SDL datasource */
   252 /* Load a PNM type image from an SDL datasource */
   253 SDL_Surface *IMG_LoadPNM_RW(SDL_RWops *src)
   253 SDL_Surface *IMG_LoadPNM_RW(SDL_RWops *src)
   254 {
   254 {
   255 	return(NULL);
   255     return(NULL);
   256 }
   256 }
   257 
   257 
   258 #endif /* LOAD_PNM */
   258 #endif /* LOAD_PNM */