Skip to content

Latest commit

 

History

History
498 lines (419 loc) · 12 KB

IMG_lbm.c

File metadata and controls

498 lines (419 loc) · 12 KB
 
Dec 14, 2001
Dec 14, 2001
2
SDL_image: An example image loading library for use with SDL
Feb 4, 2006
Feb 4, 2006
3
Copyright (C) 1997-2006 Sam Lantinga
4
5
This library is free software; you can redistribute it and/or
Feb 4, 2006
Feb 4, 2006
6
modify it under the terms of the GNU Lesser General Public
7
License as published by the Free Software Foundation; either
Feb 4, 2006
Feb 4, 2006
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
Feb 4, 2006
Feb 4, 2006
13
Lesser General Public License for more details.
Feb 4, 2006
Feb 4, 2006
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
Dec 14, 2001
Dec 14, 2001
20
slouken@libsdl.org
Dec 14, 2001
Dec 14, 2001
22
23
24
/* This is a ILBM image file loading framework
Load IFF pictures, PBM & ILBM packing methods, with or without stencil
Sep 15, 2004
Sep 15, 2004
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.
Jan 4, 2004
Jan 4, 2004
28
EHB and HAM (specific Amiga graphic chip modes) support added by Marc Le Douarain
Sep 15, 2004
Sep 15, 2004
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>
Dec 17, 2001
Dec 17, 2001
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
Nov 20, 2001
Nov 20, 2001
45
/* Structure for an IFF picture ( BMHD = Bitmap Header ) */
46
47
48
typedef struct
{
Nov 20, 2001
Nov 20, 2001
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;
Nov 20, 2001
Nov 20, 2001
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 )
{
Feb 4, 2006
Feb 4, 2006
64
int start;
65
66
67
int is_LBM;
Uint8 magic[4+4+4];
Feb 4, 2006
Feb 4, 2006
68
start = SDL_RWtell(src);
69
is_LBM = 0;
Feb 4, 2006
Feb 4, 2006
70
if ( SDL_RWread( src, magic, sizeof(magic), 1 ) )
Jan 20, 2003
Jan 20, 2003
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;
}
}
Feb 4, 2006
Feb 4, 2006
79
SDL_RWseek(src, start, SEEK_SET);
80
81
82
83
84
return( is_LBM );
}
SDL_Surface *IMG_LoadLBM_RW( SDL_RWops *src )
{
Feb 4, 2006
Feb 4, 2006
85
int start;
86
87
SDL_Surface *Image;
Uint8 id[4], pbm, colormap[MAXCOLORS*3], *MiniBuf, *ptr, count, color, msk;
Jan 20, 2003
Jan 20, 2003
88
Uint32 size, bytesloaded, nbcolors;
89
90
Uint32 i, j, bytesperline, nbplanes, plane, h;
Uint32 remainingbytes;
Feb 26, 2003
Feb 26, 2003
91
Uint32 width;
92
93
BMHD bmhd;
char *error;
Jan 4, 2004
Jan 4, 2004
94
Uint8 flagHAM,flagEHB;
95
96
97
98
99
Image = NULL;
error = NULL;
MiniBuf = NULL;
Jan 4, 2004
Jan 4, 2004
100
101
102
103
if ( !src ) {
/* The error message has been set in SDL_RWFromFile */
return NULL;
}
Feb 4, 2006
Feb 4, 2006
104
105
start = SDL_RWtell(src);
Jan 4, 2004
Jan 4, 2004
106
if ( !SDL_RWread( src, id, 4, 1 ) )
Jan 20, 2003
Jan 20, 2003
108
error="error reading IFF chunk";
109
110
111
goto done;
}
Nov 20, 2001
Nov 20, 2001
112
113
/* Should be the size of the file minus 4+4 ( 'FORM'+size ) */
if ( !SDL_RWread( src, &size, 4, 1 ) )
Jan 20, 2003
Jan 20, 2003
115
error="error reading IFF chunk size";
116
117
118
goto done;
}
Nov 20, 2001
Nov 20, 2001
119
/* As size is not used here, no need to swap it */
Jan 20, 2003
Jan 20, 2003
120
121
if ( memcmp( id, "FORM", 4 ) != 0 )
Jan 20, 2003
Jan 20, 2003
123
error="not a IFF file";
124
125
126
goto done;
}
Jan 20, 2003
Jan 20, 2003
127
if ( !SDL_RWread( src, id, 4, 1 ) )
Jan 20, 2003
Jan 20, 2003
129
error="error reading IFF chunk";
130
131
132
133
134
goto done;
}
pbm = 0;
Nov 20, 2001
Nov 20, 2001
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 ) )
{
Jan 20, 2003
Jan 20, 2003
139
error="not a IFF picture";
140
141
142
143
144
145
goto done;
}
nbcolors = 0;
memset( &bmhd, 0, sizeof( BMHD ) );
Jan 4, 2004
Jan 4, 2004
146
147
flagHAM = 0;
flagEHB = 0;
Jan 20, 2003
Jan 20, 2003
149
while ( memcmp( id, "BODY", 4 ) != 0 )
150
151
152
{
if ( !SDL_RWread( src, id, 4, 1 ) )
{
Jan 20, 2003
Jan 20, 2003
153
error="error reading IFF chunk";
154
155
156
goto done;
}
Jan 20, 2003
Jan 20, 2003
157
if ( !SDL_RWread( src, &size, 4, 1 ) )
Jan 20, 2003
Jan 20, 2003
159
error="error reading IFF chunk size";
160
161
162
163
164
165
goto done;
}
bytesloaded = 0;
size = SDL_SwapBE32( size );
Jan 20, 2003
Jan 20, 2003
166
Nov 20, 2001
Nov 20, 2001
167
if ( !memcmp( id, "BMHD", 4 ) ) /* Bitmap header */
168
169
170
{
if ( !SDL_RWread( src, &bmhd, sizeof( BMHD ), 1 ) )
{
Jan 20, 2003
Jan 20, 2003
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 );
}
Nov 20, 2001
Nov 20, 2001
186
if ( !memcmp( id, "CMAP", 4 ) ) /* palette ( Color Map ) */
187
188
189
{
if ( !SDL_RWread( src, &colormap, size, 1 ) )
{
Jan 20, 2003
Jan 20, 2003
190
error="error reading CMAP chunk";
191
192
193
194
195
196
197
goto done;
}
bytesloaded = size;
nbcolors = size / 3;
}
Jan 4, 2004
Jan 4, 2004
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 ) )
{
Jan 20, 2003
Jan 20, 2003
217
if ( size & 1 ) ++size; /* padding ! */
218
size -= bytesloaded;
Nov 20, 2001
Nov 20, 2001
219
220
/* skip the remaining bytes of this chunk */
if ( size ) SDL_RWseek( src, size, SEEK_CUR );
221
222
223
}
}
Nov 20, 2001
Nov 20, 2001
224
/* compute some usefull values, based on the bitmap header */
Nov 20, 2001
Nov 20, 2001
226
width = ( bmhd.w + 15 ) & 0xFFFFFFF0; /* Width in pixels modulo 16 */
Nov 20, 2001
Nov 20, 2001
228
bytesperline = ( ( bmhd.w + 15 ) / 16 ) * 2;
Nov 20, 2001
Nov 20, 2001
230
nbplanes = bmhd.planes;
Nov 20, 2001
Nov 20, 2001
232
if ( pbm ) /* File format : 'Packed Bitmap' */
Jan 20, 2003
Jan 20, 2003
234
bytesperline *= 8;
235
236
237
nbplanes = 1;
}
Feb 9, 2004
Feb 9, 2004
238
if ( bmhd.mask & 1 ) ++nbplanes; /* There is a mask ( 'stencil' ) */
Nov 20, 2001
Nov 20, 2001
240
241
/* Allocate memory for a temporary buffer ( used for
decompression/deinterleaving ) */
242
243
244
if ( ( MiniBuf = (void *)malloc( bytesperline * nbplanes ) ) == NULL )
{
Jan 20, 2003
Jan 20, 2003
245
error="no enough memory for temporary buffer";
246
247
248
goto done;
}
Jan 4, 2004
Jan 4, 2004
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;
Feb 9, 2004
Feb 9, 2004
252
253
254
if ( bmhd.mask & 2 ) /* There is a transparent color */
SDL_SetColorKey( Image, SDL_SRCCOLORKEY, bmhd.tcolor );
Nov 20, 2001
Nov 20, 2001
255
/* Update palette informations */
Jan 20, 2003
Jan 20, 2003
257
/* There is no palette in 24 bits ILBM file */
Jan 4, 2004
Jan 4, 2004
258
if ( nbcolors>0 && flagHAM==0 )
Jan 20, 2003
Jan 20, 2003
259
{
Sep 15, 2004
Sep 15, 2004
260
int nbrcolorsfinal = 1 << nbplanes;
Jan 20, 2003
Jan 20, 2003
261
ptr = &colormap[0];
Jan 20, 2003
Jan 20, 2003
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++;
}
Jan 4, 2004
Jan 4, 2004
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 */
Feb 9, 2004
Feb 9, 2004
273
/* Some Amiga pictures save 64 colors with 32 last wrong colors, */
Jan 4, 2004
Jan 4, 2004
274
275
276
/* they shouldn't !, and here we overwrite these 32 bad colors. */
if ( (nbcolors==32 || flagEHB ) && (1<<bmhd.planes)==64 )
{
Feb 9, 2004
Feb 9, 2004
277
nbcolors = 64;
Jan 4, 2004
Jan 4, 2004
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;
}
}
Feb 9, 2004
Feb 9, 2004
286
287
288
/* If nbcolors < 2^nbplanes, repeat the colormap */
/* This happens when pictures have a stencil mask */
Sep 15, 2004
Sep 15, 2004
289
290
291
if ( nbrcolorsfinal > (1<<bmhd.planes) ) {
nbrcolorsfinal = (1<<bmhd.planes);
}
Nov 15, 2004
Nov 15, 2004
292
for ( i=nbcolors; i < (Uint32)nbrcolorsfinal; i++ )
Feb 9, 2004
Feb 9, 2004
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;
}
Sep 15, 2004
Sep 15, 2004
298
Image->format->palette->ncolors = nbrcolorsfinal;
299
300
}
Nov 20, 2001
Nov 20, 2001
301
/* Get the bitmap */
302
303
304
for ( h=0; h < bmhd.h; h++ )
{
Jan 20, 2003
Jan 20, 2003
305
306
307
/* uncompress the datas of each planes */
for ( plane=0; plane < nbplanes; plane++ )
Jan 20, 2003
Jan 20, 2003
309
310
ptr = MiniBuf + ( plane * bytesperline );
311
remainingbytes = bytesperline;
Jan 20, 2003
Jan 20, 2003
312
Nov 20, 2001
Nov 20, 2001
313
if ( bmhd.tcomp == 1 ) /* Datas are compressed */
Jan 20, 2003
Jan 20, 2003
315
do
Jan 20, 2003
Jan 20, 2003
317
if ( !SDL_RWread( src, &count, 1, 1 ) )
Jan 20, 2003
Jan 20, 2003
319
error="error reading BODY chunk";
320
321
goto done;
}
Jan 20, 2003
Jan 20, 2003
322
323
324
if ( count & 0x80 )
{
Jan 20, 2003
Jan 20, 2003
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
{
Jan 20, 2003
Jan 20, 2003
337
++count;
338
339
340
341
342
343
344
if ( !SDL_RWread( src, ptr, count, 1 ) )
{
error="error reading BODY chunk";
goto done;
}
}
Jan 20, 2003
Jan 20, 2003
345
346
347
ptr += count;
remainingbytes -= count;
Jan 20, 2003
Jan 20, 2003
348
349
350
} while ( remainingbytes > 0 );
}
Jan 20, 2003
Jan 20, 2003
351
else
Jan 20, 2003
Jan 20, 2003
353
if ( !SDL_RWread( src, ptr, bytesperline, 1 ) )
Jan 20, 2003
Jan 20, 2003
355
error="error reading BODY chunk";
356
357
358
359
goto done;
}
}
}
Jan 20, 2003
Jan 20, 2003
360
361
/* One line has been read, store it ! */
362
363
ptr = Image->pixels;
Jan 4, 2004
Jan 4, 2004
364
if ( nbplanes==24 || flagHAM==1 )
Jan 20, 2003
Jan 20, 2003
365
366
367
368
ptr += h * width * 3;
else
ptr += h * width;
Nov 20, 2001
Nov 20, 2001
369
if ( pbm ) /* File format : 'Packed Bitmap' */
370
371
372
{
memcpy( ptr, MiniBuf, width );
}
Nov 20, 2001
Nov 20, 2001
373
else /* We have to un-interlace the bits ! */
Jan 4, 2004
Jan 4, 2004
375
if ( nbplanes!=24 && flagHAM==0 )
Jan 20, 2003
Jan 20, 2003
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
Jan 4, 2004
Jan 4, 2004
401
Uint32 finalcolor = 0;
Jan 20, 2003
Jan 20, 2003
402
403
size = ( width + 7 ) / 8;
/* 24 bitplanes ILBM : R0...R7,G0...G7,B0...B7 */
Jan 4, 2004
Jan 4, 2004
404
/* or HAM (6 bitplanes) or HAM8 (8 bitplanes) modes */
Jan 20, 2003
Jan 20, 2003
405
for ( i=0; i<width; i=i+8 )
Jan 20, 2003
Jan 20, 2003
407
Uint8 maskBit = 0x80;
408
409
for ( j=0; j<8; j++ )
{
Jan 4, 2004
Jan 4, 2004
410
411
Uint32 pixelcolor = 0;
Uint32 maskColor = 1;
Jan 20, 2003
Jan 20, 2003
412
413
414
415
416
Uint8 dataBody;
for ( plane=0; plane < nbplanes; plane++ )
{
dataBody = MiniBuf[ plane*size+i/8 ];
if ( dataBody&maskBit )
Jan 4, 2004
Jan 4, 2004
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;
Jan 20, 2003
Jan 20, 2003
446
447
448
}
if ( SDL_BYTEORDER == SDL_LIL_ENDIAN )
{
Jan 4, 2004
Jan 4, 2004
449
450
451
*ptr++ = finalcolor>>16;
*ptr++ = finalcolor>>8;
*ptr++ = finalcolor;
Jan 20, 2003
Jan 20, 2003
452
453
454
}
else
{
Jan 4, 2004
Jan 4, 2004
455
456
457
*ptr++ = finalcolor;
*ptr++ = finalcolor>>8;
*ptr++ = finalcolor>>16;
Jan 20, 2003
Jan 20, 2003
458
459
460
}
maskBit = maskBit>>1;
461
462
463
464
465
466
467
468
469
470
}
}
}
}
}
done:
if ( MiniBuf ) free( MiniBuf );
Jan 20, 2003
Jan 20, 2003
471
if ( error )
Feb 4, 2006
Feb 4, 2006
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 */