/
IMG_lbm.c
502 lines (423 loc) · 12.2 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
/* This is a ILBM image file loading framework
Load IFF pictures, PBM & ILBM packing methods, with or without stencil
25
26
27
Written by Daniel Morais ( Daniel AT Morais DOT com ) in September 2001.
24 bits ILBM files support added by Marc Le Douarain (http://www.multimania.com/mavati)
in December 2002.
28
EHB and HAM (specific Amiga graphic chip modes) support added by Marc Le Douarain
29
30
(http://www.multimania.com/mavati) in December 2003.
Stencil and colorkey fixes by David Raulo (david.raulo AT free DOT fr) in February 2004.
31
Buffer overflow fix in RLE decompression by David Raulo in January 2008.
32
33
34
35
*/
#include <stdio.h>
#include <stdlib.h>
36
#include <string.h>
37
38
39
40
41
42
43
44
45
#include "SDL_endian.h"
#include "SDL_image.h"
#ifdef LOAD_LBM
#define MAXCOLORS 256
46
/* Structure for an IFF picture ( BMHD = Bitmap Header ) */
47
48
49
typedef struct
{
50
51
52
53
54
55
56
57
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 */
58
yAspect;
59
60
Sint16 Lpage; /* width of the screen in pixels */
Sint16 Hpage; /* height of the screen in pixels */
61
62
63
64
} BMHD;
int IMG_isLBM( SDL_RWops *src )
{
65
int start;
66
67
68
int is_LBM;
Uint8 magic[4+4+4];
69
70
if ( !src )
return 0;
71
start = SDL_RWtell(src);
72
is_LBM = 0;
73
if ( SDL_RWread( src, magic, sizeof(magic), 1 ) )
74
{
75
76
77
if ( !memcmp( magic, "FORM", 4 ) &&
( !memcmp( magic + 8, "PBM ", 4 ) ||
!memcmp( magic + 8, "ILBM", 4 ) ) )
78
79
80
81
{
is_LBM = 1;
}
}
82
SDL_RWseek(src, start, SEEK_SET);
83
84
85
86
87
return( is_LBM );
}
SDL_Surface *IMG_LoadLBM_RW( SDL_RWops *src )
{
88
int start;
89
90
SDL_Surface *Image;
Uint8 id[4], pbm, colormap[MAXCOLORS*3], *MiniBuf, *ptr, count, color, msk;
91
Uint32 size, bytesloaded, nbcolors;
92
93
Uint32 i, j, bytesperline, nbplanes, plane, h;
Uint32 remainingbytes;
94
Uint32 width;
95
96
BMHD bmhd;
char *error;
97
Uint8 flagHAM,flagEHB;
98
99
100
101
102
Image = NULL;
error = NULL;
MiniBuf = NULL;
103
104
105
106
if ( !src ) {
/* The error message has been set in SDL_RWFromFile */
return NULL;
}
107
108
start = SDL_RWtell(src);
109
if ( !SDL_RWread( src, id, 4, 1 ) )
110
{
111
error="error reading IFF chunk";
112
113
114
goto done;
}
115
116
/* Should be the size of the file minus 4+4 ( 'FORM'+size ) */
if ( !SDL_RWread( src, &size, 4, 1 ) )
117
{
118
error="error reading IFF chunk size";
119
120
121
goto done;
}
122
/* As size is not used here, no need to swap it */
123
124
if ( memcmp( id, "FORM", 4 ) != 0 )
125
{
126
error="not a IFF file";
127
128
129
goto done;
}
130
if ( !SDL_RWread( src, id, 4, 1 ) )
131
{
132
error="error reading IFF chunk";
133
134
135
136
137
goto done;
}
pbm = 0;
138
139
/* File format : PBM=Packed Bitmap, ILBM=Interleaved Bitmap */
if ( !memcmp( id, "PBM ", 4 ) ) pbm = 1;
140
141
else if ( memcmp( id, "ILBM", 4 ) )
{
142
error="not a IFF picture";
143
144
145
146
147
148
goto done;
}
nbcolors = 0;
memset( &bmhd, 0, sizeof( BMHD ) );
149
150
flagHAM = 0;
flagEHB = 0;
151
152
while ( memcmp( id, "BODY", 4 ) != 0 )
153
154
155
{
if ( !SDL_RWread( src, id, 4, 1 ) )
{
156
error="error reading IFF chunk";
157
158
159
goto done;
}
160
if ( !SDL_RWread( src, &size, 4, 1 ) )
161
{
162
error="error reading IFF chunk size";
163
164
165
166
167
168
goto done;
}
bytesloaded = 0;
size = SDL_SwapBE32( size );
169
170
if ( !memcmp( id, "BMHD", 4 ) ) /* Bitmap header */
171
172
173
{
if ( !SDL_RWread( src, &bmhd, sizeof( BMHD ), 1 ) )
{
174
error="error reading BMHD chunk";
175
176
177
178
179
180
181
182
183
184
185
186
187
188
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 );
}
189
if ( !memcmp( id, "CMAP", 4 ) ) /* palette ( Color Map ) */
190
191
192
{
if ( !SDL_RWread( src, &colormap, size, 1 ) )
{
193
error="error reading CMAP chunk";
194
195
196
197
198
199
200
goto done;
}
bytesloaded = size;
nbcolors = size / 3;
}
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
if ( !memcmp( id, "CAMG", 4 ) ) /* Amiga ViewMode */
{
Uint32 viewmodes;
if ( !SDL_RWread( src, &viewmodes, sizeof(viewmodes), 1 ) )
{
error="error reading CAMG chunk";
goto done;
}
bytesloaded = size;
viewmodes = SDL_SwapBE32( viewmodes );
if ( viewmodes & 0x0800 )
flagHAM = 1;
if ( viewmodes & 0x0080 )
flagEHB = 1;
}
218
219
if ( memcmp( id, "BODY", 4 ) )
{
220
if ( size & 1 ) ++size; /* padding ! */
221
size -= bytesloaded;
222
223
/* skip the remaining bytes of this chunk */
if ( size ) SDL_RWseek( src, size, SEEK_CUR );
224
225
226
}
}
227
/* compute some usefull values, based on the bitmap header */
228
229
width = ( bmhd.w + 15 ) & 0xFFFFFFF0; /* Width in pixels modulo 16 */
230
231
bytesperline = ( ( bmhd.w + 15 ) / 16 ) * 2;
232
233
nbplanes = bmhd.planes;
234
235
if ( pbm ) /* File format : 'Packed Bitmap' */
236
{
237
bytesperline *= 8;
238
nbplanes = 1;
239
240
}
241
if ( bmhd.mask & 1 ) ++nbplanes; /* There is a mask ( 'stencil' ) */
242
243
244
/* Allocate memory for a temporary buffer ( used for
decompression/deinterleaving ) */
245
246
247
if ( ( MiniBuf = (void *)malloc( bytesperline * nbplanes ) ) == NULL )
{
248
error="no enough memory for temporary buffer";
249
250
251
goto done;
}
252
if ( ( Image = SDL_CreateRGBSurface( SDL_SWSURFACE, width, bmhd.h, (bmhd.planes==24 || flagHAM==1)?24:8, 0, 0, 0, 0 ) ) == NULL )
253
254
goto done;
255
256
257
if ( bmhd.mask & 2 ) /* There is a transparent color */
SDL_SetColorKey( Image, SDL_SRCCOLORKEY, bmhd.tcolor );
258
/* Update palette informations */
259
260
/* There is no palette in 24 bits ILBM file */
261
if ( nbcolors>0 && flagHAM==0 )
262
{
263
int nbrcolorsfinal = 1 << nbplanes;
264
ptr = &colormap[0];
265
266
267
268
269
270
271
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++;
}
272
273
274
275
/* Amiga EHB mode (Extra-Half-Bright) */
/* 6 bitplanes mode with a 32 colors palette */
/* The 32 last colors are the same but divided by 2 */
276
/* Some Amiga pictures save 64 colors with 32 last wrong colors, */
277
278
279
/* they shouldn't !, and here we overwrite these 32 bad colors. */
if ( (nbcolors==32 || flagEHB ) && (1<<bmhd.planes)==64 )
{
280
nbcolors = 64;
281
282
283
284
285
286
287
288
ptr = &colormap[0];
for ( i=32; i<64; i++ )
{
Image->format->palette->colors[i].r = (*ptr++)/2;
Image->format->palette->colors[i].g = (*ptr++)/2;
Image->format->palette->colors[i].b = (*ptr++)/2;
}
}
289
290
291
/* If nbcolors < 2^nbplanes, repeat the colormap */
/* This happens when pictures have a stencil mask */
292
293
294
if ( nbrcolorsfinal > (1<<bmhd.planes) ) {
nbrcolorsfinal = (1<<bmhd.planes);
}
295
for ( i=nbcolors; i < (Uint32)nbrcolorsfinal; i++ )
296
297
298
299
300
{
Image->format->palette->colors[i].r = Image->format->palette->colors[i%nbcolors].r;
Image->format->palette->colors[i].g = Image->format->palette->colors[i%nbcolors].g;
Image->format->palette->colors[i].b = Image->format->palette->colors[i%nbcolors].b;
}
301
302
if ( !pbm )
Image->format->palette->ncolors = nbrcolorsfinal;
303
304
}
305
/* Get the bitmap */
306
307
308
for ( h=0; h < bmhd.h; h++ )
{
309
310
311
/* uncompress the datas of each planes */
for ( plane=0; plane < nbplanes; plane++ )
312
{
313
314
ptr = MiniBuf + ( plane * bytesperline );
315
remainingbytes = bytesperline;
316
317
if ( bmhd.tcomp == 1 ) /* Datas are compressed */
318
{
319
do
320
{
321
if ( !SDL_RWread( src, &count, 1, 1 ) )
322
{
323
error="error reading BODY chunk";
324
325
goto done;
}
326
327
328
if ( count & 0x80 )
{
329
330
331
count ^= 0xFF;
count += 2; /* now it */
332
if ( ( count > remainingbytes ) || !SDL_RWread( src, &color, 1, 1 ) )
333
334
335
336
337
338
339
340
{
error="error reading BODY chunk";
goto done;
}
memset( ptr, color, count );
}
else
{
341
++count;
342
343
if ( ( count > remainingbytes ) || !SDL_RWread( src, ptr, count, 1 ) )
344
345
346
347
348
{
error="error reading BODY chunk";
goto done;
}
}
349
350
351
ptr += count;
remainingbytes -= count;
352
353
354
} while ( remainingbytes > 0 );
}
355
else
356
{
357
if ( !SDL_RWread( src, ptr, bytesperline, 1 ) )
358
{
359
error="error reading BODY chunk";
360
361
362
363
goto done;
}
}
}
364
365
/* One line has been read, store it ! */
366
367
ptr = Image->pixels;
368
if ( nbplanes==24 || flagHAM==1 )
369
370
371
372
ptr += h * width * 3;
else
ptr += h * width;
373
if ( pbm ) /* File format : 'Packed Bitmap' */
374
375
376
{
memcpy( ptr, MiniBuf, width );
}
377
else /* We have to un-interlace the bits ! */
378
{
379
if ( nbplanes!=24 && flagHAM==0 )
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
{
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
404
{
405
Uint32 finalcolor = 0;
406
407
size = ( width + 7 ) / 8;
/* 24 bitplanes ILBM : R0...R7,G0...G7,B0...B7 */
408
/* or HAM (6 bitplanes) or HAM8 (8 bitplanes) modes */
409
for ( i=0; i<width; i=i+8 )
410
{
411
Uint8 maskBit = 0x80;
412
413
for ( j=0; j<8; j++ )
{
414
415
Uint32 pixelcolor = 0;
Uint32 maskColor = 1;
416
417
418
419
420
Uint8 dataBody;
for ( plane=0; plane < nbplanes; plane++ )
{
dataBody = MiniBuf[ plane*size+i/8 ];
if ( dataBody&maskBit )
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
pixelcolor = pixelcolor | maskColor;
maskColor = maskColor<<1;
}
/* HAM : 12 bits RGB image (4 bits per color component) */
/* HAM8 : 18 bits RGB image (6 bits per color component) */
if ( flagHAM )
{
switch( pixelcolor>>(nbplanes-2) )
{
case 0: /* take direct color from palette */
finalcolor = colormap[ pixelcolor*3 ] + (colormap[ pixelcolor*3+1 ]<<8) + (colormap[ pixelcolor*3+2 ]<<16);
break;
case 1: /* modify only blue component */
finalcolor = finalcolor&0x00FFFF;
finalcolor = finalcolor | (pixelcolor<<(16+(10-nbplanes)));
break;
case 2: /* modify only red component */
finalcolor = finalcolor&0xFFFF00;
finalcolor = finalcolor | pixelcolor<<(10-nbplanes);
break;
case 3: /* modify only green component */
finalcolor = finalcolor&0xFF00FF;
finalcolor = finalcolor | (pixelcolor<<(8+(10-nbplanes)));
break;
}
}
else
{
finalcolor = pixelcolor;
450
451
452
}
if ( SDL_BYTEORDER == SDL_LIL_ENDIAN )
{
453
454
455
*ptr++ = (Uint8)(finalcolor>>16);
*ptr++ = (Uint8)(finalcolor>>8);
*ptr++ = (Uint8)(finalcolor);
456
457
458
}
else
{
459
460
461
*ptr++ = (Uint8)(finalcolor);
*ptr++ = (Uint8)(finalcolor>>8);
*ptr++ = (Uint8)(finalcolor>>16);
462
463
464
}
maskBit = maskBit>>1;
465
466
467
468
469
470
471
472
473
474
}
}
}
}
}
done:
if ( MiniBuf ) free( MiniBuf );
475
if ( error )
476
{
477
478
479
480
481
SDL_RWseek(src, start, SEEK_SET);
if ( Image ) {
SDL_FreeSurface( Image );
Image = NULL;
}
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
IMG_SetError( error );
}
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 */