/
IMG_lbm.c
471 lines (393 loc) · 11 KB
1
/*
2
SDL_image: An example image loading library for use with SDL
3
Copyright (C) 1999-2004 Sam Lantinga
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Sam Lantinga
20
slouken@libsdl.org
21
*/
22
23
/* $Id$ */
24
25
26
/* This is a ILBM image file loading framework
Load IFF pictures, PBM & ILBM packing methods, with or without stencil
27
Written by Daniel Morais ( Daniel@Morais.com ) in September 2001.
28
29
30
31
24 bits ILBM files support added by Marc Le Douarain (mavati AT club-internet
POINT fr) in December 2002.
EHB and HAM (specific Amiga graphic chip modes) support added by Marc Le Douarain
(mavati AT club-internet POINT fr) in December 2003.
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
65
66
67
68
} BMHD;
int IMG_isLBM( SDL_RWops *src )
{
int is_LBM;
Uint8 magic[4+4+4];
is_LBM = 0;
69
if ( SDL_RWread( src, magic, 4+4+4, 1 ) )
70
{
71
72
73
if ( !memcmp( magic, "FORM", 4 ) &&
( !memcmp( magic + 8, "PBM ", 4 ) ||
!memcmp( magic + 8, "ILBM", 4 ) ) )
74
75
76
77
78
79
80
81
82
83
84
{
is_LBM = 1;
}
}
return( is_LBM );
}
SDL_Surface *IMG_LoadLBM_RW( SDL_RWops *src )
{
SDL_Surface *Image;
Uint8 id[4], pbm, colormap[MAXCOLORS*3], *MiniBuf, *ptr, count, color, msk;
85
Uint32 size, bytesloaded, nbcolors;
86
87
Uint32 i, j, bytesperline, nbplanes, plane, h;
Uint32 remainingbytes;
88
Uint32 width;
89
90
BMHD bmhd;
char *error;
91
Uint8 flagHAM,flagEHB;
92
93
94
95
96
Image = NULL;
error = NULL;
MiniBuf = NULL;
97
if ( !SDL_RWread( src, id, 4, 1 ) )
98
{
99
error="error reading IFF chunk";
100
101
102
goto done;
}
103
104
/* Should be the size of the file minus 4+4 ( 'FORM'+size ) */
if ( !SDL_RWread( src, &size, 4, 1 ) )
105
{
106
error="error reading IFF chunk size";
107
108
109
goto done;
}
110
/* As size is not used here, no need to swap it */
111
112
if ( memcmp( id, "FORM", 4 ) != 0 )
113
{
114
error="not a IFF file";
115
116
117
goto done;
}
118
if ( !SDL_RWread( src, id, 4, 1 ) )
119
{
120
error="error reading IFF chunk";
121
122
123
124
125
goto done;
}
pbm = 0;
126
127
/* File format : PBM=Packed Bitmap, ILBM=Interleaved Bitmap */
if ( !memcmp( id, "PBM ", 4 ) ) pbm = 1;
128
129
else if ( memcmp( id, "ILBM", 4 ) )
{
130
error="not a IFF picture";
131
132
133
134
135
136
goto done;
}
nbcolors = 0;
memset( &bmhd, 0, sizeof( BMHD ) );
137
138
flagHAM = 0;
flagEHB = 0;
139
140
while ( memcmp( id, "BODY", 4 ) != 0 )
141
142
143
{
if ( !SDL_RWread( src, id, 4, 1 ) )
{
144
error="error reading IFF chunk";
145
146
147
goto done;
}
148
if ( !SDL_RWread( src, &size, 4, 1 ) )
149
{
150
error="error reading IFF chunk size";
151
152
153
154
155
156
goto done;
}
bytesloaded = 0;
size = SDL_SwapBE32( size );
157
158
if ( !memcmp( id, "BMHD", 4 ) ) /* Bitmap header */
159
160
161
{
if ( !SDL_RWread( src, &bmhd, sizeof( BMHD ), 1 ) )
{
162
error="error reading BMHD chunk";
163
164
165
166
167
168
169
170
171
172
173
174
175
176
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 );
}
177
if ( !memcmp( id, "CMAP", 4 ) ) /* palette ( Color Map ) */
178
179
180
{
if ( !SDL_RWread( src, &colormap, size, 1 ) )
{
181
error="error reading CMAP chunk";
182
183
184
185
186
187
188
goto done;
}
bytesloaded = size;
nbcolors = size / 3;
}
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
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;
}
206
207
if ( memcmp( id, "BODY", 4 ) )
{
208
if ( size & 1 ) ++size; /* padding ! */
209
size -= bytesloaded;
210
211
/* skip the remaining bytes of this chunk */
if ( size ) SDL_RWseek( src, size, SEEK_CUR );
212
213
214
}
}
215
/* compute some usefull values, based on the bitmap header */
216
217
width = ( bmhd.w + 15 ) & 0xFFFFFFF0; /* Width in pixels modulo 16 */
218
219
bytesperline = ( ( bmhd.w + 15 ) / 16 ) * 2;
220
221
nbplanes = bmhd.planes;
222
223
if ( pbm ) /* File format : 'Packed Bitmap' */
224
{
225
bytesperline *= 8;
226
227
228
nbplanes = 1;
}
229
if ( bmhd.mask ) ++nbplanes; /* There is a mask ( 'stencil' ) */
230
231
232
/* Allocate memory for a temporary buffer ( used for
decompression/deinterleaving ) */
233
234
235
if ( ( MiniBuf = (void *)malloc( bytesperline * nbplanes ) ) == NULL )
{
236
error="no enough memory for temporary buffer";
237
238
239
goto done;
}
240
if ( ( Image = SDL_CreateRGBSurface( SDL_SWSURFACE, width, bmhd.h, (bmhd.planes==24 || flagHAM==1)?24:8, 0, 0, 0, 0 ) ) == NULL )
241
242
goto done;
243
/* Update palette informations */
244
245
/* There is no palette in 24 bits ILBM file */
246
if ( nbcolors>0 && flagHAM==0 )
247
248
{
Image->format->palette->ncolors = nbcolors;
249
250
ptr = &colormap[0];
251
252
253
254
255
256
257
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++;
}
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
/* 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 */
/* Some Amiga pictures save 64 colors with 32 last wrong colors,
/* they shouldn't !, and here we overwrite these 32 bad colors. */
if ( (nbcolors==32 || flagEHB ) && (1<<bmhd.planes)==64 )
{
Image->format->palette->ncolors = 64;
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;
}
}
275
276
}
277
/* Get the bitmap */
278
279
280
for ( h=0; h < bmhd.h; h++ )
{
281
282
283
/* uncompress the datas of each planes */
for ( plane=0; plane < nbplanes; plane++ )
284
{
285
286
ptr = MiniBuf + ( plane * bytesperline );
287
remainingbytes = bytesperline;
288
289
if ( bmhd.tcomp == 1 ) /* Datas are compressed */
290
{
291
do
292
{
293
if ( !SDL_RWread( src, &count, 1, 1 ) )
294
{
295
error="error reading BODY chunk";
296
297
goto done;
}
298
299
300
if ( count & 0x80 )
{
301
302
303
count ^= 0xFF;
count += 2; /* now it */
304
305
306
307
308
309
310
311
312
if ( !SDL_RWread( src, &color, 1, 1 ) )
{
error="error reading BODY chunk";
goto done;
}
memset( ptr, color, count );
}
else
{
313
++count;
314
315
316
317
318
319
320
if ( !SDL_RWread( src, ptr, count, 1 ) )
{
error="error reading BODY chunk";
goto done;
}
}
321
322
323
ptr += count;
remainingbytes -= count;
324
325
326
} while ( remainingbytes > 0 );
}
327
else
328
{
329
if ( !SDL_RWread( src, ptr, bytesperline, 1 ) )
330
{
331
error="error reading BODY chunk";
332
333
334
335
goto done;
}
}
}
336
337
/* One line has been read, store it ! */
338
339
ptr = Image->pixels;
340
if ( nbplanes==24 || flagHAM==1 )
341
342
343
344
ptr += h * width * 3;
else
ptr += h * width;
345
if ( pbm ) /* File format : 'Packed Bitmap' */
346
347
348
{
memcpy( ptr, MiniBuf, width );
}
349
else /* We have to un-interlace the bits ! */
350
{
351
if ( nbplanes!=24 && flagHAM==0 )
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
{
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
376
{
377
Uint32 finalcolor = 0;
378
379
size = ( width + 7 ) / 8;
/* 24 bitplanes ILBM : R0...R7,G0...G7,B0...B7 */
380
/* or HAM (6 bitplanes) or HAM8 (8 bitplanes) modes */
381
for ( i=0; i<width; i=i+8 )
382
{
383
Uint8 maskBit = 0x80;
384
385
for ( j=0; j<8; j++ )
{
386
387
Uint32 pixelcolor = 0;
Uint32 maskColor = 1;
388
389
390
391
392
Uint8 dataBody;
for ( plane=0; plane < nbplanes; plane++ )
{
dataBody = MiniBuf[ plane*size+i/8 ];
if ( dataBody&maskBit )
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
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;
422
423
424
}
if ( SDL_BYTEORDER == SDL_LIL_ENDIAN )
{
425
426
427
*ptr++ = finalcolor>>16;
*ptr++ = finalcolor>>8;
*ptr++ = finalcolor;
428
429
430
}
else
{
431
432
433
*ptr++ = finalcolor;
*ptr++ = finalcolor>>8;
*ptr++ = finalcolor>>16;
434
435
436
}
maskBit = maskBit>>1;
437
438
439
440
441
442
443
444
445
446
}
}
}
}
}
done:
if ( MiniBuf ) free( MiniBuf );
447
if ( error )
448
449
{
IMG_SetError( error );
450
SDL_FreeSurface( Image );
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
Image = NULL;
}
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 */