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