Skip to content

Latest commit

 

History

History
502 lines (423 loc) · 12.2 KB

IMG_lbm.c

File metadata and controls

502 lines (423 loc) · 12.2 KB
 
Dec 14, 2001
Dec 14, 2001
2
SDL_image: An example image loading library for use with SDL
Dec 8, 2008
Dec 8, 2008
3
Copyright (C) 1997-2009 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.
Jan 3, 2008
Jan 3, 2008
31
Buffer overflow fix in RLE decompression by David Raulo in January 2008.
32
33
34
35
*/
#include <stdio.h>
#include <stdlib.h>
Dec 17, 2001
Dec 17, 2001
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
Nov 20, 2001
Nov 20, 2001
46
/* Structure for an IFF picture ( BMHD = Bitmap Header ) */
47
48
49
typedef struct
{
Nov 20, 2001
Nov 20, 2001
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;
Nov 20, 2001
Nov 20, 2001
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 )
{
Feb 4, 2006
Feb 4, 2006
65
int start;
66
67
68
int is_LBM;
Uint8 magic[4+4+4];
Feb 13, 2007
Feb 13, 2007
69
70
if ( !src )
return 0;
Feb 4, 2006
Feb 4, 2006
71
start = SDL_RWtell(src);
72
is_LBM = 0;
Feb 4, 2006
Feb 4, 2006
73
if ( SDL_RWread( src, magic, sizeof(magic), 1 ) )
Jan 20, 2003
Jan 20, 2003
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;
}
}
Feb 4, 2006
Feb 4, 2006
82
SDL_RWseek(src, start, SEEK_SET);
83
84
85
86
87
return( is_LBM );
}
SDL_Surface *IMG_LoadLBM_RW( SDL_RWops *src )
{
Feb 4, 2006
Feb 4, 2006
88
int start;
89
90
SDL_Surface *Image;
Uint8 id[4], pbm, colormap[MAXCOLORS*3], *MiniBuf, *ptr, count, color, msk;
Jan 20, 2003
Jan 20, 2003
91
Uint32 size, bytesloaded, nbcolors;
92
93
Uint32 i, j, bytesperline, nbplanes, plane, h;
Uint32 remainingbytes;
Feb 26, 2003
Feb 26, 2003
94
Uint32 width;
95
96
BMHD bmhd;
char *error;
Jan 4, 2004
Jan 4, 2004
97
Uint8 flagHAM,flagEHB;
98
99
100
101
102
Image = NULL;
error = NULL;
MiniBuf = NULL;
Jan 4, 2004
Jan 4, 2004
103
104
105
106
if ( !src ) {
/* The error message has been set in SDL_RWFromFile */
return NULL;
}
Feb 4, 2006
Feb 4, 2006
107
108
start = SDL_RWtell(src);
Jan 4, 2004
Jan 4, 2004
109
if ( !SDL_RWread( src, id, 4, 1 ) )
Jan 20, 2003
Jan 20, 2003
111
error="error reading IFF chunk";
112
113
114
goto done;
}
Nov 20, 2001
Nov 20, 2001
115
116
/* 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
118
error="error reading IFF chunk size";
119
120
121
goto done;
}
Nov 20, 2001
Nov 20, 2001
122
/* As size is not used here, no need to swap it */
Jan 20, 2003
Jan 20, 2003
123
124
if ( memcmp( id, "FORM", 4 ) != 0 )
Jan 20, 2003
Jan 20, 2003
126
error="not a IFF file";
127
128
129
goto done;
}
Jan 20, 2003
Jan 20, 2003
130
if ( !SDL_RWread( src, id, 4, 1 ) )
Jan 20, 2003
Jan 20, 2003
132
error="error reading IFF chunk";
133
134
135
136
137
goto done;
}
pbm = 0;
Nov 20, 2001
Nov 20, 2001
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 ) )
{
Jan 20, 2003
Jan 20, 2003
142
error="not a IFF picture";
143
144
145
146
147
148
goto done;
}
nbcolors = 0;
memset( &bmhd, 0, sizeof( BMHD ) );
Jan 4, 2004
Jan 4, 2004
149
150
flagHAM = 0;
flagEHB = 0;
Jan 20, 2003
Jan 20, 2003
152
while ( memcmp( id, "BODY", 4 ) != 0 )
153
154
155
{
if ( !SDL_RWread( src, id, 4, 1 ) )
{
Jan 20, 2003
Jan 20, 2003
156
error="error reading IFF chunk";
157
158
159
goto done;
}
Jan 20, 2003
Jan 20, 2003
160
if ( !SDL_RWread( src, &size, 4, 1 ) )
Jan 20, 2003
Jan 20, 2003
162
error="error reading IFF chunk size";
163
164
165
166
167
168
goto done;
}
bytesloaded = 0;
size = SDL_SwapBE32( size );
Jan 20, 2003
Jan 20, 2003
169
Nov 20, 2001
Nov 20, 2001
170
if ( !memcmp( id, "BMHD", 4 ) ) /* Bitmap header */
171
172
173
{
if ( !SDL_RWread( src, &bmhd, sizeof( BMHD ), 1 ) )
{
Jan 20, 2003
Jan 20, 2003
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 );
}
Nov 20, 2001
Nov 20, 2001
189
if ( !memcmp( id, "CMAP", 4 ) ) /* palette ( Color Map ) */
190
191
192
{
if ( !SDL_RWread( src, &colormap, size, 1 ) )
{
Jan 20, 2003
Jan 20, 2003
193
error="error reading CMAP chunk";
194
195
196
197
198
199
200
goto done;
}
bytesloaded = size;
nbcolors = size / 3;
}
Jan 4, 2004
Jan 4, 2004
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 ) )
{
Jan 20, 2003
Jan 20, 2003
220
if ( size & 1 ) ++size; /* padding ! */
221
size -= bytesloaded;
Nov 20, 2001
Nov 20, 2001
222
223
/* skip the remaining bytes of this chunk */
if ( size ) SDL_RWseek( src, size, SEEK_CUR );
224
225
226
}
}
Nov 20, 2001
Nov 20, 2001
227
/* compute some usefull values, based on the bitmap header */
Nov 20, 2001
Nov 20, 2001
229
width = ( bmhd.w + 15 ) & 0xFFFFFFF0; /* Width in pixels modulo 16 */
Nov 20, 2001
Nov 20, 2001
231
bytesperline = ( ( bmhd.w + 15 ) / 16 ) * 2;
Nov 20, 2001
Nov 20, 2001
233
nbplanes = bmhd.planes;
Nov 20, 2001
Nov 20, 2001
235
if ( pbm ) /* File format : 'Packed Bitmap' */
Jan 20, 2003
Jan 20, 2003
237
bytesperline *= 8;
Jul 15, 2007
Jul 15, 2007
238
nbplanes = 1;
239
240
}
Feb 9, 2004
Feb 9, 2004
241
if ( bmhd.mask & 1 ) ++nbplanes; /* There is a mask ( 'stencil' ) */
Nov 20, 2001
Nov 20, 2001
243
244
/* Allocate memory for a temporary buffer ( used for
decompression/deinterleaving ) */
245
246
247
if ( ( MiniBuf = (void *)malloc( bytesperline * nbplanes ) ) == NULL )
{
Jan 20, 2003
Jan 20, 2003
248
error="no enough memory for temporary buffer";
249
250
251
goto done;
}
Jan 4, 2004
Jan 4, 2004
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;
Feb 9, 2004
Feb 9, 2004
255
256
257
if ( bmhd.mask & 2 ) /* There is a transparent color */
SDL_SetColorKey( Image, SDL_SRCCOLORKEY, bmhd.tcolor );
Nov 20, 2001
Nov 20, 2001
258
/* Update palette informations */
Jan 20, 2003
Jan 20, 2003
260
/* There is no palette in 24 bits ILBM file */
Jan 4, 2004
Jan 4, 2004
261
if ( nbcolors>0 && flagHAM==0 )
Jan 20, 2003
Jan 20, 2003
262
{
Sep 15, 2004
Sep 15, 2004
263
int nbrcolorsfinal = 1 << nbplanes;
Jan 20, 2003
Jan 20, 2003
264
ptr = &colormap[0];
Jan 20, 2003
Jan 20, 2003
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++;
}
Jan 4, 2004
Jan 4, 2004
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 */
Feb 9, 2004
Feb 9, 2004
276
/* Some Amiga pictures save 64 colors with 32 last wrong colors, */
Jan 4, 2004
Jan 4, 2004
277
278
279
/* 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
280
nbcolors = 64;
Jan 4, 2004
Jan 4, 2004
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;
}
}
Feb 9, 2004
Feb 9, 2004
289
290
291
/* If nbcolors < 2^nbplanes, repeat the colormap */
/* This happens when pictures have a stencil mask */
Sep 15, 2004
Sep 15, 2004
292
293
294
if ( nbrcolorsfinal > (1<<bmhd.planes) ) {
nbrcolorsfinal = (1<<bmhd.planes);
}
Nov 15, 2004
Nov 15, 2004
295
for ( i=nbcolors; i < (Uint32)nbrcolorsfinal; i++ )
Feb 9, 2004
Feb 9, 2004
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;
}
Jul 20, 2007
Jul 20, 2007
301
302
if ( !pbm )
Image->format->palette->ncolors = nbrcolorsfinal;
303
304
}
Nov 20, 2001
Nov 20, 2001
305
/* Get the bitmap */
306
307
308
for ( h=0; h < bmhd.h; h++ )
{
Jan 20, 2003
Jan 20, 2003
309
310
311
/* uncompress the datas of each planes */
for ( plane=0; plane < nbplanes; plane++ )
Jan 20, 2003
Jan 20, 2003
313
314
ptr = MiniBuf + ( plane * bytesperline );
315
remainingbytes = bytesperline;
Jan 20, 2003
Jan 20, 2003
316
Nov 20, 2001
Nov 20, 2001
317
if ( bmhd.tcomp == 1 ) /* Datas are compressed */
Jan 20, 2003
Jan 20, 2003
319
do
Jan 20, 2003
Jan 20, 2003
321
if ( !SDL_RWread( src, &count, 1, 1 ) )
Jan 20, 2003
Jan 20, 2003
323
error="error reading BODY chunk";
324
325
goto done;
}
Jan 20, 2003
Jan 20, 2003
326
327
328
if ( count & 0x80 )
{
Jan 20, 2003
Jan 20, 2003
329
330
331
count ^= 0xFF;
count += 2; /* now it */
Jan 3, 2008
Jan 3, 2008
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
{
Jan 20, 2003
Jan 20, 2003
341
++count;
Jan 3, 2008
Jan 3, 2008
343
if ( ( count > remainingbytes ) || !SDL_RWread( src, ptr, count, 1 ) )
344
345
346
347
348
{
error="error reading BODY chunk";
goto done;
}
}
Jan 20, 2003
Jan 20, 2003
349
350
351
ptr += count;
remainingbytes -= count;
Jan 20, 2003
Jan 20, 2003
352
353
354
} while ( remainingbytes > 0 );
}
Jan 20, 2003
Jan 20, 2003
355
else
Jan 20, 2003
Jan 20, 2003
357
if ( !SDL_RWread( src, ptr, bytesperline, 1 ) )
Jan 20, 2003
Jan 20, 2003
359
error="error reading BODY chunk";
360
361
362
363
goto done;
}
}
}
Jan 20, 2003
Jan 20, 2003
364
365
/* One line has been read, store it ! */
366
367
ptr = Image->pixels;
Jan 4, 2004
Jan 4, 2004
368
if ( nbplanes==24 || flagHAM==1 )
Jan 20, 2003
Jan 20, 2003
369
370
371
372
ptr += h * width * 3;
else
ptr += h * width;
Nov 20, 2001
Nov 20, 2001
373
if ( pbm ) /* File format : 'Packed Bitmap' */
374
375
376
{
memcpy( ptr, MiniBuf, width );
}
Nov 20, 2001
Nov 20, 2001
377
else /* We have to un-interlace the bits ! */
Jan 4, 2004
Jan 4, 2004
379
if ( nbplanes!=24 && flagHAM==0 )
Jan 20, 2003
Jan 20, 2003
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
Jan 4, 2004
Jan 4, 2004
405
Uint32 finalcolor = 0;
Jan 20, 2003
Jan 20, 2003
406
407
size = ( width + 7 ) / 8;
/* 24 bitplanes ILBM : R0...R7,G0...G7,B0...B7 */
Jan 4, 2004
Jan 4, 2004
408
/* or HAM (6 bitplanes) or HAM8 (8 bitplanes) modes */
Jan 20, 2003
Jan 20, 2003
409
for ( i=0; i<width; i=i+8 )
Jan 20, 2003
Jan 20, 2003
411
Uint8 maskBit = 0x80;
412
413
for ( j=0; j<8; j++ )
{
Jan 4, 2004
Jan 4, 2004
414
415
Uint32 pixelcolor = 0;
Uint32 maskColor = 1;
Jan 20, 2003
Jan 20, 2003
416
417
418
419
420
Uint8 dataBody;
for ( plane=0; plane < nbplanes; plane++ )
{
dataBody = MiniBuf[ plane*size+i/8 ];
if ( dataBody&maskBit )
Jan 4, 2004
Jan 4, 2004
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;
Jan 20, 2003
Jan 20, 2003
450
451
452
}
if ( SDL_BYTEORDER == SDL_LIL_ENDIAN )
{
May 11, 2006
May 11, 2006
453
454
455
*ptr++ = (Uint8)(finalcolor>>16);
*ptr++ = (Uint8)(finalcolor>>8);
*ptr++ = (Uint8)(finalcolor);
Jan 20, 2003
Jan 20, 2003
456
457
458
}
else
{
May 11, 2006
May 11, 2006
459
460
461
*ptr++ = (Uint8)(finalcolor);
*ptr++ = (Uint8)(finalcolor>>8);
*ptr++ = (Uint8)(finalcolor>>16);
Jan 20, 2003
Jan 20, 2003
462
463
464
}
maskBit = maskBit>>1;
465
466
467
468
469
470
471
472
473
474
}
}
}
}
}
done:
if ( MiniBuf ) free( MiniBuf );
Jan 20, 2003
Jan 20, 2003
475
if ( error )
Feb 4, 2006
Feb 4, 2006
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 */