IMG_lbm.c
author Sam Lantinga <slouken@libsdl.org>
Mon, 20 Jan 2003 01:58:46 +0000
changeset 74 ab2b38e9a9e2
parent 58 46862ddd4577
child 84 b0beb6215ea2
permissions -rw-r--r--
Marc Le Douarain - Sun, 22 Dec 2002 22:59:51 +0100
* Added 24-bit support to the ILBM format loader
slouken@45
     1
/*
slouken@53
     2
    SDL_image:  An example image loading library for use with SDL
slouken@53
     3
    Copyright (C) 1999, 2000, 2001  Sam Lantinga
slouken@45
     4
slouken@45
     5
    This library is free software; you can redistribute it and/or
slouken@45
     6
    modify it under the terms of the GNU Library General Public
slouken@45
     7
    License as published by the Free Software Foundation; either
slouken@45
     8
    version 2 of the License, or (at your option) any later version.
slouken@45
     9
slouken@45
    10
    This library is distributed in the hope that it will be useful,
slouken@45
    11
    but WITHOUT ANY WARRANTY; without even the implied warranty of
slouken@45
    12
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
slouken@45
    13
    Library General Public License for more details.
slouken@45
    14
slouken@45
    15
    You should have received a copy of the GNU Library General Public
slouken@45
    16
    License along with this library; if not, write to the Free
slouken@45
    17
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
slouken@45
    18
slouken@45
    19
    Sam Lantinga
slouken@53
    20
    slouken@libsdl.org
slouken@45
    21
*/
slouken@53
    22
slouken@53
    23
/* $Id$ */
slouken@74
    24
slouken@45
    25
/* This is a ILBM image file loading framework
slouken@45
    26
   Load IFF pictures, PBM & ILBM packing methods, with or without stencil
slouken@74
    27
   Written by Daniel Morais ( Daniel@Morais.com ) in September 2001.
slouken@74
    28
   24 bits ILBM files support added by Marc Le Douarain (mavati@club-internet.fr)
slouken@74
    29
   in December 2002.
slouken@45
    30
*/
slouken@45
    31
slouken@45
    32
#include <stdio.h>
slouken@45
    33
#include <stdlib.h>
slouken@58
    34
#include <string.h>
slouken@45
    35
slouken@45
    36
#include "SDL_endian.h"
slouken@45
    37
#include "SDL_image.h"
slouken@45
    38
slouken@45
    39
#ifdef LOAD_LBM
slouken@45
    40
slouken@45
    41
slouken@45
    42
#define MAXCOLORS 256
slouken@45
    43
slouken@50
    44
/* Structure for an IFF picture ( BMHD = Bitmap Header ) */
slouken@45
    45
slouken@45
    46
typedef struct
slouken@45
    47
{
slouken@50
    48
    Uint16 w, h;		/* width & height of the bitmap in pixels */
slouken@50
    49
    Sint16 x, y;		/* screen coordinates of the bitmap */
slouken@50
    50
    Uint8 planes;		/* number of planes of the bitmap */
slouken@50
    51
    Uint8 mask;			/* mask type ( 0 => no mask ) */
slouken@50
    52
    Uint8 tcomp;		/* compression type */
slouken@50
    53
    Uint8 pad1;			/* dummy value, for padding */
slouken@50
    54
    Uint16 tcolor;		/* transparent color */
slouken@50
    55
    Uint8 xAspect,		/* pixel aspect ratio */
slouken@45
    56
         yAspect;
slouken@50
    57
    Sint16  Lpage;		/* width of the screen in pixels */
slouken@50
    58
    Sint16  Hpage;		/* height of the screen in pixels */
slouken@45
    59
} BMHD;
slouken@45
    60
slouken@45
    61
int IMG_isLBM( SDL_RWops *src )
slouken@45
    62
{
slouken@45
    63
	int   is_LBM;
slouken@45
    64
	Uint8 magic[4+4+4];
slouken@45
    65
slouken@45
    66
	is_LBM = 0;
slouken@74
    67
	if ( SDL_RWread( src, magic, 4+4+4, 1 ) )
slouken@45
    68
	{
slouken@74
    69
		if ( !memcmp( magic, "FORM", 4 ) &&
slouken@74
    70
			( !memcmp( magic + 8, "PBM ", 4 ) ||
slouken@74
    71
			  !memcmp( magic + 8, "ILBM", 4 ) ) )
slouken@45
    72
		{
slouken@45
    73
			is_LBM = 1;
slouken@45
    74
		}
slouken@45
    75
	}
slouken@45
    76
	return( is_LBM );
slouken@45
    77
}
slouken@45
    78
slouken@45
    79
SDL_Surface *IMG_LoadLBM_RW( SDL_RWops *src )
slouken@45
    80
{
slouken@45
    81
	SDL_Surface *Image;
slouken@45
    82
	Uint8       id[4], pbm, colormap[MAXCOLORS*3], *MiniBuf, *ptr, count, color, msk;
slouken@74
    83
	Uint32      size, bytesloaded, nbcolors;
slouken@45
    84
	Uint32      i, j, bytesperline, nbplanes, plane, h;
slouken@45
    85
	Uint32      remainingbytes;
slouken@45
    86
	int         width;
slouken@45
    87
	BMHD	      bmhd;
slouken@45
    88
	char        *error;
slouken@45
    89
slouken@45
    90
	Image   = NULL;
slouken@45
    91
	error   = NULL;
slouken@45
    92
	MiniBuf = NULL;
slouken@45
    93
slouken@45
    94
	if ( src == NULL ) goto done;
slouken@45
    95
slouken@45
    96
	if ( !SDL_RWread( src, id, 4, 1 ) ) 
slouken@45
    97
	{
slouken@74
    98
		error="error reading IFF chunk";
slouken@45
    99
		goto done;
slouken@45
   100
	}
slouken@45
   101
slouken@50
   102
	/* Should be the size of the file minus 4+4 ( 'FORM'+size ) */
slouken@50
   103
	if ( !SDL_RWread( src, &size, 4, 1 ) )
slouken@45
   104
	{
slouken@74
   105
		error="error reading IFF chunk size";
slouken@45
   106
		goto done;
slouken@45
   107
	}
slouken@45
   108
slouken@50
   109
	/* As size is not used here, no need to swap it */
slouken@74
   110
slouken@74
   111
	if ( memcmp( id, "FORM", 4 ) != 0 )
slouken@45
   112
	{
slouken@74
   113
		error="not a IFF file";
slouken@45
   114
		goto done;
slouken@45
   115
	}
slouken@45
   116
slouken@74
   117
	if ( !SDL_RWread( src, id, 4, 1 ) )
slouken@45
   118
	{
slouken@74
   119
		error="error reading IFF chunk";
slouken@45
   120
		goto done;
slouken@45
   121
	}
slouken@45
   122
slouken@45
   123
	pbm = 0;
slouken@45
   124
slouken@50
   125
	/* File format : PBM=Packed Bitmap, ILBM=Interleaved Bitmap */
slouken@50
   126
	if ( !memcmp( id, "PBM ", 4 ) ) pbm = 1;
slouken@45
   127
	else if ( memcmp( id, "ILBM", 4 ) )
slouken@45
   128
	{
slouken@74
   129
		error="not a IFF picture";
slouken@45
   130
		goto done;
slouken@45
   131
	}
slouken@45
   132
slouken@45
   133
	nbcolors = 0;
slouken@45
   134
slouken@45
   135
	memset( &bmhd, 0, sizeof( BMHD ) );
slouken@45
   136
slouken@74
   137
	while ( memcmp( id, "BODY", 4 ) != 0 )
slouken@45
   138
	{
slouken@45
   139
		if ( !SDL_RWread( src, id, 4, 1 ) ) 
slouken@45
   140
		{
slouken@74
   141
			error="error reading IFF chunk";
slouken@45
   142
			goto done;
slouken@45
   143
		}
slouken@45
   144
slouken@74
   145
		if ( !SDL_RWread( src, &size, 4, 1 ) )
slouken@45
   146
		{
slouken@74
   147
			error="error reading IFF chunk size";
slouken@45
   148
			goto done;
slouken@45
   149
		}
slouken@45
   150
slouken@45
   151
		bytesloaded = 0;
slouken@45
   152
slouken@45
   153
		size = SDL_SwapBE32( size );
slouken@74
   154
slouken@50
   155
		if ( !memcmp( id, "BMHD", 4 ) ) /* Bitmap header */
slouken@45
   156
		{
slouken@45
   157
			if ( !SDL_RWread( src, &bmhd, sizeof( BMHD ), 1 ) )
slouken@45
   158
			{
slouken@74
   159
				error="error reading BMHD chunk";
slouken@45
   160
				goto done;
slouken@45
   161
			}
slouken@45
   162
slouken@45
   163
			bytesloaded = sizeof( BMHD );
slouken@45
   164
slouken@45
   165
			bmhd.w 		= SDL_SwapBE16( bmhd.w );
slouken@45
   166
			bmhd.h 		= SDL_SwapBE16( bmhd.h );
slouken@45
   167
			bmhd.x 		= SDL_SwapBE16( bmhd.x );
slouken@45
   168
			bmhd.y 		= SDL_SwapBE16( bmhd.y );
slouken@45
   169
			bmhd.tcolor = SDL_SwapBE16( bmhd.tcolor );
slouken@45
   170
			bmhd.Lpage 	= SDL_SwapBE16( bmhd.Lpage );
slouken@45
   171
			bmhd.Hpage 	= SDL_SwapBE16( bmhd.Hpage );
slouken@45
   172
		}
slouken@45
   173
slouken@50
   174
		if ( !memcmp( id, "CMAP", 4 ) ) /* palette ( Color Map ) */
slouken@45
   175
		{
slouken@45
   176
			if ( !SDL_RWread( src, &colormap, size, 1 ) )
slouken@45
   177
			{
slouken@74
   178
				error="error reading CMAP chunk";
slouken@45
   179
				goto done;
slouken@45
   180
			}
slouken@45
   181
slouken@45
   182
			bytesloaded = size;
slouken@45
   183
			nbcolors = size / 3;
slouken@45
   184
		}
slouken@45
   185
slouken@45
   186
		if ( memcmp( id, "BODY", 4 ) )
slouken@45
   187
		{
slouken@74
   188
			if ( size & 1 )	++size;  	/* padding ! */
slouken@45
   189
			size -= bytesloaded;
slouken@50
   190
			/* skip the remaining bytes of this chunk */
slouken@50
   191
			if ( size )	SDL_RWseek( src, size, SEEK_CUR );
slouken@45
   192
		}
slouken@45
   193
	}
slouken@45
   194
slouken@50
   195
	/* compute some usefull values, based on the bitmap header */
slouken@45
   196
slouken@50
   197
	width = ( bmhd.w + 15 ) & 0xFFFFFFF0;  /* Width in pixels modulo 16 */
slouken@45
   198
slouken@50
   199
	bytesperline = ( ( bmhd.w + 15 ) / 16 ) * 2;
slouken@45
   200
slouken@50
   201
	nbplanes = bmhd.planes;
slouken@45
   202
slouken@50
   203
	if ( pbm )                         /* File format : 'Packed Bitmap' */
slouken@45
   204
	{
slouken@74
   205
		bytesperline *= 8;
slouken@45
   206
		nbplanes = 1;
slouken@45
   207
	}
slouken@45
   208
slouken@50
   209
	if ( bmhd.mask ) ++nbplanes;       /* There is a mask ( 'stencil' ) */
slouken@45
   210
slouken@50
   211
	/* Allocate memory for a temporary buffer ( used for
slouken@50
   212
           decompression/deinterleaving ) */
slouken@45
   213
slouken@45
   214
	if ( ( MiniBuf = (void *)malloc( bytesperline * nbplanes ) ) == NULL )
slouken@45
   215
	{
slouken@74
   216
		error="no enough memory for temporary buffer";
slouken@45
   217
		goto done;
slouken@45
   218
	}
slouken@45
   219
slouken@74
   220
	if ( ( Image = SDL_CreateRGBSurface( SDL_SWSURFACE, width, bmhd.h, bmhd.planes==24?24:8, 0, 0, 0, 0 ) ) == NULL )
slouken@45
   221
	   goto done;
slouken@45
   222
slouken@50
   223
	/* Update palette informations */
slouken@45
   224
slouken@74
   225
	/* There is no palette in 24 bits ILBM file */
slouken@74
   226
	if ( nbcolors>0 )
slouken@74
   227
	{
slouken@74
   228
		Image->format->palette->ncolors = nbcolors;
slouken@45
   229
slouken@74
   230
		ptr = &colormap[0];
slouken@45
   231
slouken@74
   232
		for ( i=0; i<nbcolors; i++ )
slouken@74
   233
		{
slouken@74
   234
			Image->format->palette->colors[i].r = *ptr++;
slouken@74
   235
			Image->format->palette->colors[i].g = *ptr++;
slouken@74
   236
			Image->format->palette->colors[i].b = *ptr++;
slouken@74
   237
		}
slouken@45
   238
	}
slouken@45
   239
slouken@50
   240
	/* Get the bitmap */
slouken@45
   241
slouken@45
   242
	for ( h=0; h < bmhd.h; h++ )
slouken@45
   243
	{
slouken@74
   244
		/* uncompress the datas of each planes */
slouken@74
   245
slouken@74
   246
		for ( plane=0; plane < nbplanes; plane++ )
slouken@45
   247
		{
slouken@74
   248
			ptr = MiniBuf + ( plane * bytesperline );
slouken@74
   249
slouken@45
   250
			remainingbytes = bytesperline;
slouken@74
   251
slouken@50
   252
			if ( bmhd.tcomp == 1 )	    /* Datas are compressed */
slouken@45
   253
			{
slouken@74
   254
				do
slouken@45
   255
				{
slouken@74
   256
					if ( !SDL_RWread( src, &count, 1, 1 ) )
slouken@45
   257
					{
slouken@74
   258
						error="error reading BODY chunk";
slouken@45
   259
						goto done;
slouken@45
   260
					}
slouken@74
   261
slouken@45
   262
					if ( count & 0x80 )
slouken@45
   263
					{
slouken@74
   264
						count ^= 0xFF;
slouken@74
   265
						count += 2; /* now it */
slouken@74
   266
slouken@45
   267
						if ( !SDL_RWread( src, &color, 1, 1 ) )
slouken@45
   268
						{
slouken@45
   269
						   error="error reading BODY chunk";
slouken@45
   270
							goto done;
slouken@45
   271
						}
slouken@45
   272
						memset( ptr, color, count );
slouken@45
   273
					}
slouken@45
   274
					else
slouken@45
   275
					{
slouken@74
   276
						++count;
slouken@45
   277
slouken@45
   278
						if ( !SDL_RWread( src, ptr, count, 1 ) )
slouken@45
   279
						{
slouken@45
   280
						   error="error reading BODY chunk";
slouken@45
   281
							goto done;
slouken@45
   282
						}
slouken@45
   283
					}
slouken@74
   284
slouken@45
   285
					ptr += count;
slouken@45
   286
					remainingbytes -= count;
slouken@74
   287
slouken@45
   288
				} while ( remainingbytes > 0 );
slouken@45
   289
			}
slouken@74
   290
			else
slouken@45
   291
			{
slouken@74
   292
				if ( !SDL_RWread( src, ptr, bytesperline, 1 ) )
slouken@45
   293
				{
slouken@74
   294
					error="error reading BODY chunk";
slouken@45
   295
					goto done;
slouken@45
   296
				}
slouken@45
   297
			}
slouken@45
   298
		}
slouken@74
   299
slouken@74
   300
		/* One line has been read, store it ! */
slouken@45
   301
slouken@45
   302
		ptr = Image->pixels;
slouken@74
   303
		if ( nbplanes==24 )
slouken@74
   304
			ptr += h * width * 3;
slouken@74
   305
		else
slouken@74
   306
			ptr += h * width;
slouken@74
   307
slouken@50
   308
		if ( pbm )                 /* File format : 'Packed Bitmap' */
slouken@45
   309
		{
slouken@45
   310
		   memcpy( ptr, MiniBuf, width );
slouken@45
   311
		}
slouken@50
   312
		else		/* We have to un-interlace the bits ! */
slouken@45
   313
		{
slouken@74
   314
			if ( nbplanes!=24 )
slouken@45
   315
			{
slouken@74
   316
				size = ( width + 7 ) / 8;
slouken@74
   317
slouken@74
   318
				for ( i=0; i < size; i++ )
slouken@45
   319
				{
slouken@74
   320
					memset( ptr, 0, 8 );
slouken@74
   321
slouken@74
   322
					for ( plane=0; plane < nbplanes; plane++ )
slouken@74
   323
					{
slouken@74
   324
						color = *( MiniBuf + i + ( plane * bytesperline ) );
slouken@74
   325
						msk = 0x80;
slouken@74
   326
slouken@74
   327
						for ( j=0; j<8; j++ )
slouken@74
   328
						{
slouken@74
   329
							if ( ( plane + j ) <= 7 ) ptr[j] |= (Uint8)( color & msk ) >> ( 7 - plane - j );
slouken@74
   330
							else 	                    ptr[j] |= (Uint8)( color & msk ) << ( plane + j - 7 );
slouken@74
   331
slouken@74
   332
							msk >>= 1;
slouken@74
   333
						}
slouken@74
   334
					}
slouken@74
   335
					ptr += 8;
slouken@74
   336
				}
slouken@74
   337
			}
slouken@74
   338
			else
slouken@74
   339
			{
slouken@74
   340
				size = ( width + 7 ) / 8;
slouken@74
   341
				/* 24 bitplanes ILBM : R0...R7,G0...G7,B0...B7 */
slouken@74
   342
				for ( i=0; i<width; i=i+8 )
slouken@74
   343
				{
slouken@74
   344
					Uint8 maskBit = 0x80;
slouken@45
   345
					for ( j=0; j<8; j++ )
slouken@45
   346
					{
slouken@74
   347
						Uint32 color24 = 0;
slouken@74
   348
						Uint32 maskColor24 = 1;
slouken@74
   349
						Uint8 dataBody;
slouken@74
   350
						for ( plane=0; plane < nbplanes; plane++ )
slouken@74
   351
						{
slouken@74
   352
							dataBody = MiniBuf[ plane*size+i/8 ];
slouken@74
   353
							if ( dataBody&maskBit )
slouken@74
   354
								color24 = color24 | maskColor24;
slouken@74
   355
							maskColor24 = maskColor24<<1;
slouken@74
   356
						}
slouken@74
   357
						if ( SDL_BYTEORDER == SDL_LIL_ENDIAN )
slouken@74
   358
						{
slouken@74
   359
							*ptr++ = color24>>16;
slouken@74
   360
							*ptr++ = color24>>8;
slouken@74
   361
							*ptr++ = color24;
slouken@74
   362
						}
slouken@74
   363
						else
slouken@74
   364
						{
slouken@74
   365
							*ptr++ = color24;
slouken@74
   366
							*ptr++ = color24>>8;
slouken@74
   367
							*ptr++ = color24>>16;
slouken@74
   368
						}
slouken@74
   369
slouken@74
   370
						maskBit = maskBit>>1;
slouken@45
   371
					}
slouken@45
   372
				}
slouken@45
   373
			}
slouken@45
   374
		}
slouken@45
   375
	}
slouken@45
   376
slouken@45
   377
done:
slouken@45
   378
slouken@45
   379
	if ( MiniBuf ) free( MiniBuf );
slouken@45
   380
slouken@74
   381
	if ( error )
slouken@45
   382
	{
slouken@45
   383
		IMG_SetError( error );
slouken@74
   384
		SDL_FreeSurface( Image );
slouken@45
   385
		Image = NULL;
slouken@45
   386
	}
slouken@45
   387
slouken@45
   388
	return( Image );
slouken@45
   389
}
slouken@45
   390
slouken@45
   391
#else /* LOAD_LBM */
slouken@45
   392
slouken@45
   393
/* See if an image is contained in a data source */
slouken@45
   394
int IMG_isLBM(SDL_RWops *src)
slouken@45
   395
{
slouken@45
   396
	return(0);
slouken@45
   397
}
slouken@45
   398
slouken@45
   399
/* Load an IFF type image from an SDL datasource */
slouken@45
   400
SDL_Surface *IMG_LoadLBM_RW(SDL_RWops *src)
slouken@45
   401
{
slouken@45
   402
	return(NULL);
slouken@45
   403
}
slouken@45
   404
slouken@45
   405
#endif /* LOAD_LBM */