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