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