]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/libsdl-image/contrib/IMG_pnm.c
6d54c56bf9d5f5b4758415d209d5fab4f97325af
[l4.git] / l4 / pkg / libsdl-image / contrib / IMG_pnm.c
1 /*
2     SDL_image:  An example image loading library for use with SDL
3     Copyright (C) 1997-2009 Sam Lantinga
4
5     This library is free software; you can redistribute it and/or
6     modify it under the terms of the GNU Lesser General Public
7     License as published by the Free Software Foundation; either
8     version 2.1 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     Lesser General Public License for more details.
14
15     You should have received a copy of the GNU Lesser General Public
16     License along with this library; if not, write to the Free Software
17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18
19     Sam Lantinga
20     slouken@libsdl.org
21 */
22
23 /*
24  * PNM (portable anymap) image loader:
25  *
26  * Supports: PBM, PGM and PPM, ASCII and binary formats
27  * (PBM and PGM are loaded as 8bpp surfaces)
28  * Does not support: maximum component value > 255
29  */
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <ctype.h>
34 #include <string.h>
35
36 #include "SDL_image.h"
37
38 #ifdef LOAD_PNM
39
40 /* See if an image is contained in a data source */
41 int IMG_isPNM(SDL_RWops *src)
42 {
43         int start;
44         int is_PNM;
45         char magic[2];
46
47         if ( !src )
48                 return 0;
49         start = SDL_RWtell(src);
50         is_PNM = 0;
51         if ( SDL_RWread(src, magic, sizeof(magic), 1) ) {
52                 /*
53                  * PNM magic signatures:
54                  * P1   PBM, ascii format
55                  * P2   PGM, ascii format
56                  * P3   PPM, ascii format
57                  * P4   PBM, binary format
58                  * P5   PGM, binary format
59                  * P6   PPM, binary format
60                  * P7   PAM, a general wrapper for PNM data
61                  */
62                 if ( magic[0] == 'P' && magic[1] >= '1' && magic[1] <= '6' ) {
63                         is_PNM = 1;
64                 }
65         }
66         SDL_RWseek(src, start, SEEK_SET);
67         return(is_PNM);
68 }
69
70 /* read a non-negative integer from the source. return -1 upon error */
71 static int ReadNumber(SDL_RWops *src)
72 {
73         int number;
74         unsigned char ch;
75
76         /* Initialize return value */
77         number = 0;
78
79         /* Skip leading whitespace */
80         do {
81                 if ( ! SDL_RWread(src, &ch, 1, 1) ) {
82                         return(0);
83                 }
84                 /* Eat comments as whitespace */
85                 if ( ch == '#' ) {  /* Comment is '#' to end of line */
86                         do {
87                                 if ( ! SDL_RWread(src, &ch, 1, 1) ) {
88                                         return -1;
89                                 }
90                         } while ( (ch != '\r') && (ch != '\n') );
91                 }
92         } while ( isspace(ch) );
93
94         /* Add up the number */
95         do {
96                 number *= 10;
97                 number += ch-'0';
98
99                 if ( !SDL_RWread(src, &ch, 1, 1) ) {
100                         return -1;
101                 }
102         } while ( isdigit(ch) );
103
104         return(number);
105 }
106
107 SDL_Surface *IMG_LoadPNM_RW(SDL_RWops *src)
108 {
109         int start;
110         SDL_Surface *surface = NULL;
111         int width, height;
112         int maxval, y, bpl;
113         Uint8 *row;
114         Uint8 *buf = NULL;
115         char *error = NULL;
116         Uint8 magic[2];
117         int ascii;
118         enum { PBM, PGM, PPM, PAM } kind;
119
120 #define ERROR(s) do { error = (s); goto done; } while(0)
121
122         if ( !src ) {
123                 /* The error message has been set in SDL_RWFromFile */
124                 return NULL;
125         }
126         start = SDL_RWtell(src);
127
128         SDL_RWread(src, magic, 2, 1);
129         kind = magic[1] - '1';
130         ascii = 1;
131         if(kind >= 3) {
132                 ascii = 0;
133                 kind -= 3;
134         }
135
136         width = ReadNumber(src);
137         height = ReadNumber(src);
138         if(width <= 0 || height <= 0)
139                 ERROR("Unable to read image width and height");
140
141         if(kind != PBM) {
142                 maxval = ReadNumber(src);
143                 if(maxval <= 0 || maxval > 255)
144                         ERROR("unsupported PNM format");
145         } else
146                 maxval = 255;   /* never scale PBMs */
147
148         /* binary PNM allows just a single character of whitespace after
149            the last parameter, and we've already consumed it */
150
151         if(kind == PPM) {
152                 /* 24-bit surface in R,G,B byte order */
153                 surface = SDL_AllocSurface(SDL_SWSURFACE, width, height, 24,
154 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
155                                            0x000000ff, 0x0000ff00, 0x00ff0000,
156 #else
157                                            0x00ff0000, 0x0000ff00, 0x000000ff,
158 #endif
159                                            0);
160         } else {
161                 /* load PBM/PGM as 8-bit indexed images */
162                 surface = SDL_AllocSurface(SDL_SWSURFACE, width, height, 8,
163                                            0, 0, 0, 0);
164         }
165         if ( surface == NULL )
166                 ERROR("Out of memory");
167         bpl = width * surface->format->BytesPerPixel;
168         if(kind == PGM) {
169                 SDL_Color *c = surface->format->palette->colors;
170                 int i;
171                 for(i = 0; i < 256; i++)
172                         c[i].r = c[i].g = c[i].b = i;
173                 surface->format->palette->ncolors = 256;
174         } else if(kind == PBM) {
175                 /* for some reason PBM has 1=black, 0=white */
176                 SDL_Color *c = surface->format->palette->colors;
177                 c[0].r = c[0].g = c[0].b = 255;
178                 c[1].r = c[1].g = c[1].b = 0;
179                 surface->format->palette->ncolors = 2;
180                 bpl = (width + 7) >> 3;
181                 buf = malloc(bpl);
182                 if(buf == NULL)
183                         ERROR("Out of memory");
184         }
185
186         /* Read the image into the surface */
187         row = surface->pixels;
188         for(y = 0; y < height; y++) {
189                 if(ascii) {
190                         int i;
191                         if(kind == PBM) {
192                                 for(i = 0; i < width; i++) {
193                                         Uint8 ch;
194                                         do {
195                                                 if(!SDL_RWread(src, &ch,
196                                                                1, 1))
197                                                        ERROR("file truncated");
198                                                 ch -= '0';
199                                         } while(ch > 1);
200                                         row[i] = ch;
201                                 }
202                         } else {
203                                 for(i = 0; i < bpl; i++) {
204                                         int c;
205                                         c = ReadNumber(src);
206                                         if(c < 0)
207                                                 ERROR("file truncated");
208                                         row[i] = c;
209                                 }
210                         }
211                 } else {
212                         Uint8 *dst = (kind == PBM) ? buf : row;
213                         if(!SDL_RWread(src, dst, bpl, 1))
214                                 ERROR("file truncated");
215                         if(kind == PBM) {
216                                 /* expand bitmap to 8bpp */
217                                 int i;
218                                 for(i = 0; i < width; i++) {
219                                         int bit = 7 - (i & 7);
220                                         row[i] = (buf[i >> 3] >> bit) & 1;
221                                 }
222                         }
223                 }
224                 if(maxval < 255) {
225                         /* scale up to full dynamic range (slow) */
226                         int i;
227                         for(i = 0; i < bpl; i++)
228                                 row[i] = row[i] * 255 / maxval;
229                 }
230                 row += surface->pitch;
231         }
232 done:
233         free(buf);
234         if(error) {
235                 SDL_RWseek(src, start, SEEK_SET);
236                 if ( surface ) {
237                         SDL_FreeSurface(surface);
238                         surface = NULL;
239                 }
240                 IMG_SetError(error);
241         }
242         return(surface);
243 }
244
245 #else
246
247 /* See if an image is contained in a data source */
248 int IMG_isPNM(SDL_RWops *src)
249 {
250         return(0);
251 }
252
253 /* Load a PNM type image from an SDL datasource */
254 SDL_Surface *IMG_LoadPNM_RW(SDL_RWops *src)
255 {
256         return(NULL);
257 }
258
259 #endif /* LOAD_PNM */