/
IMG_lbm.c
405 lines (329 loc) · 8.73 KB
1
/*
2
3
SDL_image: An example image loading library for use with SDL
Copyright (C) 1999, 2000, 2001 Sam Lantinga
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Sam Lantinga
20
slouken@libsdl.org
21
*/
22
23
/* $Id$ */
24
25
26
/* This is a ILBM image file loading framework
Load IFF pictures, PBM & ILBM packing methods, with or without stencil
27
28
29
Written by Daniel Morais ( Daniel@Morais.com ) in September 2001.
24 bits ILBM files support added by Marc Le Douarain (mavati@club-internet.fr)
in December 2002.
30
31
32
33
*/
#include <stdio.h>
#include <stdlib.h>
34
#include <string.h>
35
36
37
38
39
40
41
42
43
#include "SDL_endian.h"
#include "SDL_image.h"
#ifdef LOAD_LBM
#define MAXCOLORS 256
44
/* Structure for an IFF picture ( BMHD = Bitmap Header ) */
45
46
47
typedef struct
{
48
49
50
51
52
53
54
55
Uint16 w, h; /* width & height of the bitmap in pixels */
Sint16 x, y; /* screen coordinates of the bitmap */
Uint8 planes; /* number of planes of the bitmap */
Uint8 mask; /* mask type ( 0 => no mask ) */
Uint8 tcomp; /* compression type */
Uint8 pad1; /* dummy value, for padding */
Uint16 tcolor; /* transparent color */
Uint8 xAspect, /* pixel aspect ratio */
56
yAspect;
57
58
Sint16 Lpage; /* width of the screen in pixels */
Sint16 Hpage; /* height of the screen in pixels */
59
60
61
62
63
64
65
66
} BMHD;
int IMG_isLBM( SDL_RWops *src )
{
int is_LBM;
Uint8 magic[4+4+4];
is_LBM = 0;
67
if ( SDL_RWread( src, magic, 4+4+4, 1 ) )
68
{
69
70
71
if ( !memcmp( magic, "FORM", 4 ) &&
( !memcmp( magic + 8, "PBM ", 4 ) ||
!memcmp( magic + 8, "ILBM", 4 ) ) )
72
73
74
75
76
77
78
79
80
81
82
{
is_LBM = 1;
}
}
return( is_LBM );
}
SDL_Surface *IMG_LoadLBM_RW( SDL_RWops *src )
{
SDL_Surface *Image;
Uint8 id[4], pbm, colormap[MAXCOLORS*3], *MiniBuf, *ptr, count, color, msk;
83
Uint32 size, bytesloaded, nbcolors;
84
85
86
87
88
89
90
91
92
93
94
95
96
97
Uint32 i, j, bytesperline, nbplanes, plane, h;
Uint32 remainingbytes;
int width;
BMHD bmhd;
char *error;
Image = NULL;
error = NULL;
MiniBuf = NULL;
if ( src == NULL ) goto done;
if ( !SDL_RWread( src, id, 4, 1 ) )
{
98
error="error reading IFF chunk";
99
100
101
goto done;
}
102
103
/* Should be the size of the file minus 4+4 ( 'FORM'+size ) */
if ( !SDL_RWread( src, &size, 4, 1 ) )
104
{
105
error="error reading IFF chunk size";
106
107
108
goto done;
}
109
/* As size is not used here, no need to swap it */
110
111
if ( memcmp( id, "FORM", 4 ) != 0 )
112
{
113
error="not a IFF file";
114
115
116
goto done;
}
117
if ( !SDL_RWread( src, id, 4, 1 ) )
118
{
119
error="error reading IFF chunk";
120
121
122
123
124
goto done;
}
pbm = 0;
125
126
/* File format : PBM=Packed Bitmap, ILBM=Interleaved Bitmap */
if ( !memcmp( id, "PBM ", 4 ) ) pbm = 1;
127
128
else if ( memcmp( id, "ILBM", 4 ) )
{
129
error="not a IFF picture";
130
131
132
133
134
135
136
goto done;
}
nbcolors = 0;
memset( &bmhd, 0, sizeof( BMHD ) );
137
while ( memcmp( id, "BODY", 4 ) != 0 )
138
139
140
{
if ( !SDL_RWread( src, id, 4, 1 ) )
{
141
error="error reading IFF chunk";
142
143
144
goto done;
}
145
if ( !SDL_RWread( src, &size, 4, 1 ) )
146
{
147
error="error reading IFF chunk size";
148
149
150
151
152
153
goto done;
}
bytesloaded = 0;
size = SDL_SwapBE32( size );
154
155
if ( !memcmp( id, "BMHD", 4 ) ) /* Bitmap header */
156
157
158
{
if ( !SDL_RWread( src, &bmhd, sizeof( BMHD ), 1 ) )
{
159
error="error reading BMHD chunk";
160
161
162
163
164
165
166
167
168
169
170
171
172
173
goto done;
}
bytesloaded = sizeof( BMHD );
bmhd.w = SDL_SwapBE16( bmhd.w );
bmhd.h = SDL_SwapBE16( bmhd.h );
bmhd.x = SDL_SwapBE16( bmhd.x );
bmhd.y = SDL_SwapBE16( bmhd.y );
bmhd.tcolor = SDL_SwapBE16( bmhd.tcolor );
bmhd.Lpage = SDL_SwapBE16( bmhd.Lpage );
bmhd.Hpage = SDL_SwapBE16( bmhd.Hpage );
}
174
if ( !memcmp( id, "CMAP", 4 ) ) /* palette ( Color Map ) */
175
176
177
{
if ( !SDL_RWread( src, &colormap, size, 1 ) )
{
178
error="error reading CMAP chunk";
179
180
181
182
183
184
185
186
187
goto done;
}
bytesloaded = size;
nbcolors = size / 3;
}
if ( memcmp( id, "BODY", 4 ) )
{
188
if ( size & 1 ) ++size; /* padding ! */
189
size -= bytesloaded;
190
191
/* skip the remaining bytes of this chunk */
if ( size ) SDL_RWseek( src, size, SEEK_CUR );
192
193
194
}
}
195
/* compute some usefull values, based on the bitmap header */
196
197
width = ( bmhd.w + 15 ) & 0xFFFFFFF0; /* Width in pixels modulo 16 */
198
199
bytesperline = ( ( bmhd.w + 15 ) / 16 ) * 2;
200
201
nbplanes = bmhd.planes;
202
203
if ( pbm ) /* File format : 'Packed Bitmap' */
204
{
205
bytesperline *= 8;
206
207
208
nbplanes = 1;
}
209
if ( bmhd.mask ) ++nbplanes; /* There is a mask ( 'stencil' ) */
210
211
212
/* Allocate memory for a temporary buffer ( used for
decompression/deinterleaving ) */
213
214
215
if ( ( MiniBuf = (void *)malloc( bytesperline * nbplanes ) ) == NULL )
{
216
error="no enough memory for temporary buffer";
217
218
219
goto done;
}
220
if ( ( Image = SDL_CreateRGBSurface( SDL_SWSURFACE, width, bmhd.h, bmhd.planes==24?24:8, 0, 0, 0, 0 ) ) == NULL )
221
222
goto done;
223
/* Update palette informations */
224
225
226
227
228
/* There is no palette in 24 bits ILBM file */
if ( nbcolors>0 )
{
Image->format->palette->ncolors = nbcolors;
229
230
ptr = &colormap[0];
231
232
233
234
235
236
237
for ( i=0; i<nbcolors; i++ )
{
Image->format->palette->colors[i].r = *ptr++;
Image->format->palette->colors[i].g = *ptr++;
Image->format->palette->colors[i].b = *ptr++;
}
238
239
}
240
/* Get the bitmap */
241
242
243
for ( h=0; h < bmhd.h; h++ )
{
244
245
246
/* uncompress the datas of each planes */
for ( plane=0; plane < nbplanes; plane++ )
247
{
248
249
ptr = MiniBuf + ( plane * bytesperline );
250
remainingbytes = bytesperline;
251
252
if ( bmhd.tcomp == 1 ) /* Datas are compressed */
253
{
254
do
255
{
256
if ( !SDL_RWread( src, &count, 1, 1 ) )
257
{
258
error="error reading BODY chunk";
259
260
goto done;
}
261
262
263
if ( count & 0x80 )
{
264
265
266
count ^= 0xFF;
count += 2; /* now it */
267
268
269
270
271
272
273
274
275
if ( !SDL_RWread( src, &color, 1, 1 ) )
{
error="error reading BODY chunk";
goto done;
}
memset( ptr, color, count );
}
else
{
276
++count;
277
278
279
280
281
282
283
if ( !SDL_RWread( src, ptr, count, 1 ) )
{
error="error reading BODY chunk";
goto done;
}
}
284
285
286
ptr += count;
remainingbytes -= count;
287
288
289
} while ( remainingbytes > 0 );
}
290
else
291
{
292
if ( !SDL_RWread( src, ptr, bytesperline, 1 ) )
293
{
294
error="error reading BODY chunk";
295
296
297
298
goto done;
}
}
}
299
300
/* One line has been read, store it ! */
301
302
ptr = Image->pixels;
303
304
305
306
307
if ( nbplanes==24 )
ptr += h * width * 3;
else
ptr += h * width;
308
if ( pbm ) /* File format : 'Packed Bitmap' */
309
310
311
{
memcpy( ptr, MiniBuf, width );
}
312
else /* We have to un-interlace the bits ! */
313
{
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
if ( nbplanes!=24 )
{
size = ( width + 7 ) / 8;
for ( i=0; i < size; i++ )
{
memset( ptr, 0, 8 );
for ( plane=0; plane < nbplanes; plane++ )
{
color = *( MiniBuf + i + ( plane * bytesperline ) );
msk = 0x80;
for ( j=0; j<8; j++ )
{
if ( ( plane + j ) <= 7 ) ptr[j] |= (Uint8)( color & msk ) >> ( 7 - plane - j );
else ptr[j] |= (Uint8)( color & msk ) << ( plane + j - 7 );
msk >>= 1;
}
}
ptr += 8;
}
}
else
339
{
340
341
342
size = ( width + 7 ) / 8;
/* 24 bitplanes ILBM : R0...R7,G0...G7,B0...B7 */
for ( i=0; i<width; i=i+8 )
343
{
344
Uint8 maskBit = 0x80;
345
346
for ( j=0; j<8; j++ )
{
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
Uint32 color24 = 0;
Uint32 maskColor24 = 1;
Uint8 dataBody;
for ( plane=0; plane < nbplanes; plane++ )
{
dataBody = MiniBuf[ plane*size+i/8 ];
if ( dataBody&maskBit )
color24 = color24 | maskColor24;
maskColor24 = maskColor24<<1;
}
if ( SDL_BYTEORDER == SDL_LIL_ENDIAN )
{
*ptr++ = color24>>16;
*ptr++ = color24>>8;
*ptr++ = color24;
}
else
{
*ptr++ = color24;
*ptr++ = color24>>8;
*ptr++ = color24>>16;
}
maskBit = maskBit>>1;
371
372
373
374
375
376
377
378
379
380
}
}
}
}
}
done:
if ( MiniBuf ) free( MiniBuf );
381
if ( error )
382
383
{
IMG_SetError( error );
384
SDL_FreeSurface( Image );
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
Image = NULL;
}
return( Image );
}
#else /* LOAD_LBM */
/* See if an image is contained in a data source */
int IMG_isLBM(SDL_RWops *src)
{
return(0);
}
/* Load an IFF type image from an SDL datasource */
SDL_Surface *IMG_LoadLBM_RW(SDL_RWops *src)
{
return(NULL);
}
#endif /* LOAD_LBM */