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