/
IMG_pnm.c
259 lines (230 loc) · 5.8 KB
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
11
12
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
Lesser General Public License for more details.
14
15
16
17
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
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
27
* Supports: PBM, PGM and PPM, ASCII and binary formats
* (PBM and PGM are loaded as 8bpp surfaces)
28
29
* Does not support: maximum component value > 255
*/
30
31
#include <stdio.h>
32
#include <stdlib.h>
33
34
35
36
37
#include <ctype.h>
#include <string.h>
#include "SDL_image.h"
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
44
int start;
int is_PNM;
45
46
char magic[2];
47
48
if ( !src )
return 0;
49
50
51
52
53
54
55
56
57
58
59
start = SDL_RWtell(src);
is_PNM = 0;
if ( SDL_RWread(src, magic, sizeof(magic), 1) ) {
/*
* PNM magic signatures:
* P1 PBM, ascii format
* P2 PGM, ascii format
* P3 PPM, ascii format
* P4 PBM, binary format
* P5 PGM, binary format
* P6 PPM, binary format
60
* P7 PAM, a general wrapper for PNM data
61
62
63
64
65
*/
if ( magic[0] == 'P' && magic[1] >= '1' && magic[1] <= '6' ) {
is_PNM = 1;
}
}
66
SDL_RWseek(src, start, RW_SEEK_SET);
67
return(is_PNM);
68
69
}
70
/* read a non-negative integer from the source. return -1 upon error */
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
static int ReadNumber(SDL_RWops *src)
{
int number;
unsigned char ch;
/* Initialize return value */
number = 0;
/* Skip leading whitespace */
do {
if ( ! SDL_RWread(src, &ch, 1, 1) ) {
return(0);
}
/* Eat comments as whitespace */
if ( ch == '#' ) { /* Comment is '#' to end of line */
do {
if ( ! SDL_RWread(src, &ch, 1, 1) ) {
88
return -1;
89
90
91
92
93
94
95
96
97
98
}
} while ( (ch != '\r') && (ch != '\n') );
}
} while ( isspace(ch) );
/* Add up the number */
do {
number *= 10;
number += ch-'0';
99
100
if ( !SDL_RWread(src, &ch, 1, 1) ) {
return -1;
101
102
103
104
105
}
} while ( isdigit(ch) );
return(number);
}
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
116
117
char *error = NULL;
Uint8 magic[2];
int ascii;
118
enum { PBM, PGM, PPM, PAM } kind;
119
120
121
#define ERROR(s) do { error = (s); goto done; } while(0)
122
123
124
125
if ( !src ) {
/* The error message has been set in SDL_RWFromFile */
return NULL;
}
126
start = SDL_RWtell(src);
127
128
SDL_RWread(src, magic, 2, 1);
129
130
131
132
133
134
kind = magic[1] - '1';
ascii = 1;
if(kind >= 3) {
ascii = 0;
kind -= 3;
}
135
136
137
width = ReadNumber(src);
height = ReadNumber(src);
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
if(width <= 0 || height <= 0)
ERROR("Unable to read image width and height");
if(kind != PBM) {
maxval = ReadNumber(src);
if(maxval <= 0 || maxval > 255)
ERROR("unsupported PNM format");
} else
maxval = 255; /* never scale PBMs */
/* binary PNM allows just a single character of whitespace after
the last parameter, and we've already consumed it */
if(kind == PPM) {
/* 24-bit surface in R,G,B byte order */
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
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
0);
} else {
/* load PBM/PGM as 8-bit indexed images */
surface = SDL_AllocSurface(SDL_SWSURFACE, width, height, 8,
0, 0, 0, 0);
}
if ( surface == NULL )
ERROR("Out of memory");
bpl = width * surface->format->BytesPerPixel;
if(kind == PGM) {
SDL_Color *c = surface->format->palette->colors;
int i;
for(i = 0; i < 256; i++)
c[i].r = c[i].g = c[i].b = i;
surface->format->palette->ncolors = 256;
} else if(kind == PBM) {
/* for some reason PBM has 1=black, 0=white */
SDL_Color *c = surface->format->palette->colors;
c[0].r = c[0].g = c[0].b = 255;
c[1].r = c[1].g = c[1].b = 0;
surface->format->palette->ncolors = 2;
bpl = (width + 7) >> 3;
buf = malloc(bpl);
if(buf == NULL)
ERROR("Out of memory");
184
185
186
}
/* Read the image into the surface */
187
188
189
190
row = surface->pixels;
for(y = 0; y < height; y++) {
if(ascii) {
int i;
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
if(kind == PBM) {
for(i = 0; i < width; i++) {
Uint8 ch;
do {
if(!SDL_RWread(src, &ch,
1, 1))
ERROR("file truncated");
ch -= '0';
} while(ch > 1);
row[i] = ch;
}
} else {
for(i = 0; i < bpl; i++) {
int c;
c = ReadNumber(src);
if(c < 0)
ERROR("file truncated");
row[i] = c;
209
210
211
}
}
} else {
212
213
214
215
216
217
218
219
220
221
Uint8 *dst = (kind == PBM) ? buf : row;
if(!SDL_RWread(src, dst, bpl, 1))
ERROR("file truncated");
if(kind == PBM) {
/* expand bitmap to 8bpp */
int i;
for(i = 0; i < width; i++) {
int bit = 7 - (i & 7);
row[i] = (buf[i >> 3] >> bit) & 1;
}
222
223
224
225
226
227
228
229
230
231
232
}
}
if(maxval < 255) {
/* scale up to full dynamic range (slow) */
int i;
for(i = 0; i < bpl; i++)
row[i] = row[i] * 255 / maxval;
}
row += surface->pitch;
}
done:
233
free(buf);
234
if(error) {
235
SDL_RWseek(src, start, RW_SEEK_SET);
236
237
238
239
if ( surface ) {
SDL_FreeSurface(surface);
surface = NULL;
}
240
IMG_SetError(error);
241
242
243
244
245
246
247
}
return(surface);
}
#else
/* See if an image is contained in a data source */
248
int IMG_isPNM(SDL_RWops *src)
249
250
251
252
{
return(0);
}
253
254
/* Load a PNM type image from an SDL datasource */
SDL_Surface *IMG_LoadPNM_RW(SDL_RWops *src)
255
256
257
258
{
return(NULL);
}
259
#endif /* LOAD_PNM */