Ongoing GIF implementation
This commit is contained in:
@@ -81,6 +81,7 @@
|
||||
<ItemGroup>
|
||||
<ClCompile Include="bola.cpp" />
|
||||
<ClCompile Include="engendro.cpp" />
|
||||
<ClCompile Include="gif.c" />
|
||||
<ClCompile Include="jdraw8.cpp" />
|
||||
<ClCompile Include="jfile.cpp" />
|
||||
<ClCompile Include="jgame.cpp" />
|
||||
|
||||
@@ -60,6 +60,9 @@
|
||||
<ClCompile Include="sprite.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="gif.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="bola.h">
|
||||
|
||||
97
gif.c
97
gif.c
@@ -12,6 +12,7 @@
|
||||
#define COMMENT_EXTENSION 0xFE
|
||||
#define PLAINTEXT_EXTENSION 0x01
|
||||
|
||||
#define READ(dst, size) memcpy(dst, buffer, size); buffer += size
|
||||
typedef struct
|
||||
{
|
||||
unsigned short width;
|
||||
@@ -254,7 +255,7 @@ void uncompress( int code_length,
|
||||
}
|
||||
}
|
||||
|
||||
static int read_sub_blocks( FILE* gif_file, unsigned char **data )
|
||||
static int read_sub_blocks( unsigned char* buffer, unsigned char **data )
|
||||
{
|
||||
int data_length;
|
||||
int index;
|
||||
@@ -268,11 +269,7 @@ static int read_sub_blocks( FILE* gif_file, unsigned char **data )
|
||||
|
||||
while ( 1 )
|
||||
{
|
||||
if ( fread( &block_size, 1, 1, gif_file ) < 1 )
|
||||
{
|
||||
perror( "Invalid GIF file (too short): " );
|
||||
return -1;
|
||||
}
|
||||
READ(&block_size, 1);
|
||||
|
||||
if ( block_size == 0 ) // end of sub-blocks
|
||||
{
|
||||
@@ -283,12 +280,7 @@ static int read_sub_blocks( FILE* gif_file, unsigned char **data )
|
||||
*data = realloc( *data, data_length );
|
||||
|
||||
// TODO this could be split across block size boundaries
|
||||
if ( fread( *data + index, 1, block_size, gif_file ) <
|
||||
block_size )
|
||||
{
|
||||
perror( "Invalid GIF file (too short): " );
|
||||
return -1;
|
||||
}
|
||||
READ(*data + index, block_size);
|
||||
|
||||
index += block_size;
|
||||
}
|
||||
@@ -296,7 +288,7 @@ static int read_sub_blocks( FILE* gif_file, unsigned char **data )
|
||||
return data_length;
|
||||
}
|
||||
|
||||
static int process_image_descriptor( FILE* gif_file,
|
||||
static int process_image_descriptor( unsigned char* buffer,
|
||||
rgb *gct,
|
||||
int gct_size,
|
||||
int resolution_bits )
|
||||
@@ -310,25 +302,15 @@ static int process_image_descriptor( FILE* gif_file,
|
||||
//unsigned char *uncompressed_data = NULL;
|
||||
|
||||
// TODO there could actually be lots of these
|
||||
if ( fread( &image_descriptor, 1, 9, gif_file ) < 9 )
|
||||
{
|
||||
perror( "Invalid GIF file (too short)" );
|
||||
disposition = 0;
|
||||
goto done;
|
||||
}
|
||||
READ(&image_descriptor, 9);
|
||||
|
||||
// TODO if LCT = true, read the LCT
|
||||
|
||||
disposition = 1;
|
||||
|
||||
if ( fread( &lzw_code_size, 1, 1, gif_file ) < 1 )
|
||||
{
|
||||
perror( "Invalid GIF file (too short): " );
|
||||
disposition = 0;
|
||||
goto done;
|
||||
}
|
||||
READ(&lzw_code_size, 1);
|
||||
|
||||
compressed_data_length = read_sub_blocks( gif_file, &compressed_data );
|
||||
compressed_data_length = read_sub_blocks( buffer, &compressed_data );
|
||||
|
||||
width = image_descriptor.image_width;
|
||||
height = image_descriptor.image_height;
|
||||
@@ -349,7 +331,7 @@ done:
|
||||
return disposition;
|
||||
}
|
||||
|
||||
static int process_extension( FILE* gif_file )
|
||||
static int process_extension( unsigned char* buffer )
|
||||
{
|
||||
extension_t extension;
|
||||
graphic_control_extension_t gce;
|
||||
@@ -358,39 +340,23 @@ static int process_extension( FILE* gif_file )
|
||||
unsigned char *extension_data = NULL;
|
||||
int extension_data_length;
|
||||
|
||||
if ( fread( &extension, 1, 2, gif_file ) < 2 )
|
||||
{
|
||||
perror( "Invalid GIF file (too short): " );
|
||||
return 0;
|
||||
}
|
||||
READ(&extension, 2);
|
||||
|
||||
switch ( extension.extension_code )
|
||||
{
|
||||
case GRAPHIC_CONTROL:
|
||||
if ( fread( &gce, 1, 4, gif_file ) < 4 )
|
||||
{
|
||||
perror( "Invalid GIF file (too short): " );
|
||||
return 0;
|
||||
}
|
||||
READ(&gce, 4);
|
||||
|
||||
break;
|
||||
case APPLICATION_EXTENSION:
|
||||
if ( fread( &application, 1, 11, gif_file ) < 11 )
|
||||
{
|
||||
perror( "Invalid GIF file (too short): " );
|
||||
return 0;
|
||||
}
|
||||
READ(&application, 11);
|
||||
break;
|
||||
case 0xFE:
|
||||
// comment extension; do nothing - all the data is in the
|
||||
// sub-blocks that follow.
|
||||
break;
|
||||
case 0x01:
|
||||
if ( fread( &plaintext, 1, 12, gif_file ) < 12 )
|
||||
{
|
||||
perror( "Invalid GIF file (too short): " );
|
||||
return 0;
|
||||
}
|
||||
READ(&plaintext, 12);
|
||||
break;
|
||||
default:
|
||||
fprintf( stderr, "Unrecognized extension code.\n" );
|
||||
@@ -399,7 +365,7 @@ static int process_extension( FILE* gif_file )
|
||||
|
||||
// All extensions are followed by data sub-blocks; even if it's
|
||||
// just a single data sub-block of length 0
|
||||
extension_data_length = read_sub_blocks( gif_file, &extension_data );
|
||||
extension_data_length = read_sub_blocks( buffer, &extension_data );
|
||||
|
||||
if ( extension_data != NULL )
|
||||
free( extension_data );
|
||||
@@ -412,7 +378,7 @@ static int process_extension( FILE* gif_file )
|
||||
* GIF-encoded file. This should point to the first byte in
|
||||
* the file when invoked.
|
||||
*/
|
||||
static void process_gif_stream( FILE* gif_file )
|
||||
static unsigned char* process_gif_stream(unsigned char *buffer, unsigned short* w, unsigned short* h)
|
||||
{
|
||||
unsigned char header[ 7 ];
|
||||
screen_descriptor_t screen_descriptor;
|
||||
@@ -424,11 +390,7 @@ static void process_gif_stream( FILE* gif_file )
|
||||
unsigned char block_type = 0x0;
|
||||
|
||||
// A GIF file starts with a Header (section 17)
|
||||
if ( fread( header, 1, 6, gif_file ) != 6 )
|
||||
{
|
||||
perror( "Invalid GIF file (too short)" );
|
||||
return;
|
||||
}
|
||||
READ(header, 6);
|
||||
header[ 6 ] = 0x0;
|
||||
|
||||
// XXX there's another format, GIF87a, that you may still find
|
||||
@@ -447,11 +409,7 @@ static void process_gif_stream( FILE* gif_file )
|
||||
|
||||
// Can't use sizeof here since GCC does byte alignment;
|
||||
// sizeof( screen_descriptor_t ) = 8!
|
||||
if ( fread( &screen_descriptor, 1, 7, gif_file ) < 7 )
|
||||
{
|
||||
perror( "Invalid GIF file (too short)" );
|
||||
return;
|
||||
}
|
||||
READ(&screen_descriptor, 7);
|
||||
|
||||
color_resolution_bits = ( ( screen_descriptor.fields & 0x70 ) >> 4 ) + 1;
|
||||
|
||||
@@ -465,26 +423,17 @@ static void process_gif_stream( FILE* gif_file )
|
||||
global_color_table = ( rgb * ) malloc( 3 * global_color_table_size );
|
||||
|
||||
// XXX this could conceivably return a short count...
|
||||
if ( fread( global_color_table, 1, 3 * global_color_table_size, gif_file ) <
|
||||
3 * global_color_table_size )
|
||||
{
|
||||
perror( "Unable to read global color table" );
|
||||
return;
|
||||
}
|
||||
READ(global_color_table, 3 * global_color_table_size);
|
||||
}
|
||||
|
||||
while ( block_type != TRAILER )
|
||||
{
|
||||
if ( fread( &block_type, 1, 1, gif_file ) < 1 )
|
||||
{
|
||||
perror( "Invalid GIF file (too short)" );
|
||||
return;
|
||||
}
|
||||
READ(&block_type, 1);
|
||||
|
||||
switch ( block_type )
|
||||
{
|
||||
case IMAGE_DESCRIPTOR:
|
||||
if ( !process_image_descriptor( gif_file,
|
||||
if ( !process_image_descriptor( buffer,
|
||||
global_color_table,
|
||||
global_color_table_size,
|
||||
color_resolution_bits ) )
|
||||
@@ -493,7 +442,7 @@ static void process_gif_stream( FILE* gif_file )
|
||||
}
|
||||
break;
|
||||
case EXTENSION_INTRODUCER:
|
||||
if ( !process_extension( gif_file ) )
|
||||
if ( !process_extension( buffer ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -509,6 +458,10 @@ static void process_gif_stream( FILE* gif_file )
|
||||
}
|
||||
|
||||
|
||||
unsigned char* LoadGif(unsigned char *buffer, unsigned short* w, unsigned short* h) {
|
||||
return process_gif_stream(buffer, w, h);
|
||||
}
|
||||
|
||||
int main( int argc, char *argv[] )
|
||||
{
|
||||
FILE* gif_file;
|
||||
|
||||
Reference in New Issue
Block a user