From b6353efe0ab2e05b8d3f7e809b55ba1606036bba Mon Sep 17 00:00:00 2001 From: Sean Fox Date: Thu, 26 Jun 2008 06:30:44 +0000 Subject: Arranged gif_animation and gif_frame members, moved bitmap callbacks into gif_animation, and added gif_create() function svn path=/branches/dynis/libnsgif/; revision=4449 --- examples/decode_gif.c | 45 +++++++++++----------- libnsgif.c | 101 ++++++++++++++++++++++++++++++-------------------- libnsgif.h | 58 ++++++++++++++++------------- 3 files changed, 115 insertions(+), 89 deletions(-) diff --git a/examples/decode_gif.c b/examples/decode_gif.c index 744b38b..08f8a21 100644 --- a/examples/decode_gif.c +++ b/examples/decode_gif.c @@ -26,7 +26,7 @@ #include #include -char *load_file(const char *path, size_t *data_size); +unsigned char *load_file(const char *path, size_t *data_size); void warning(const char *context, int code); void *bitmap_create(int width, int height); void bitmap_set_opaque(void *bitmap, bool opaque); @@ -36,19 +36,18 @@ void bitmap_destroy(void *bitmap); void bitmap_modified(void *bitmap); -gif_bitmap_callback_vt bitmap_callbacks = { - bitmap_create, - bitmap_destroy, - bitmap_get_buffer, - bitmap_set_opaque, - bitmap_test_opaque, - bitmap_modified -}; - - int main(int argc, char *argv[]) { - struct gif_animation gif; + gif_animation gif = { + .bitmap_callbacks = { + bitmap_create, + bitmap_destroy, + bitmap_get_buffer, + bitmap_set_opaque, + bitmap_test_opaque, + bitmap_modified + } + }; size_t size; int code; unsigned int i; @@ -58,17 +57,15 @@ int main(int argc, char *argv[]) return 1; } - /* load file into memory */ - char *data = load_file(argv[1], &size); + /* create our gif animation */ + gif_create(&gif); - /* initialise gif_animation structure */ - gif.buffer_size = size; - gif.gif_data = (unsigned char *) data; - gif.buffer_position = 0; + /* load file into memory */ + unsigned char *data = load_file(argv[1], &size); /* begin decoding */ do { - code = gif_initialise(&gif, &bitmap_callbacks); + code = gif_initialise(&gif, size, data); if (code != GIF_OK && code != GIF_WORKING) { warning("gif_initialise", code); exit(1); @@ -81,7 +78,6 @@ int main(int argc, char *argv[]) printf("# height %u \n", gif.height); printf("# frame_count %u \n", gif.frame_count); printf("# frame_count_partial %u \n", gif.frame_count_partial); - printf("# background_colour %x \n", gif.background_colour); printf("# loop_count %u \n", gif.loop_count); printf("%u %u 256\n", gif.width, gif.height * gif.frame_count); @@ -90,7 +86,7 @@ int main(int argc, char *argv[]) unsigned int row, col; char *image; - code = gif_decode_frame(&gif, i, &bitmap_callbacks); + code = gif_decode_frame(&gif, i); if (code != GIF_OK) warning("gif_decode_frame", code); @@ -108,15 +104,18 @@ int main(int argc, char *argv[]) } } + /* clean up */ + gif_finalise(&gif); + return 0; } -char *load_file(const char *path, size_t *data_size) +unsigned char *load_file(const char *path, size_t *data_size) { FILE *fd; struct stat sb; - char *buffer; + unsigned char *buffer; size_t size; size_t n; diff --git a/libnsgif.c b/libnsgif.c index 1580e5e..925da90 100644 --- a/libnsgif.c +++ b/libnsgif.c @@ -110,19 +110,19 @@ /* Internal GIF routines */ -static gif_result gif_initialise_sprite(struct gif_animation *gif, unsigned int width, unsigned int height, gif_bitmap_callback_vt *bitmap_callbacks); -static gif_result gif_initialise_frame(struct gif_animation *gif, gif_bitmap_callback_vt *bitmap_callbacks); -static gif_result gif_initialise_frame_extensions(struct gif_animation *gif, const int frame); -static gif_result gif_skip_frame_extensions(struct gif_animation *gif); +static gif_result gif_initialise_sprite(gif_animation *gif, unsigned int width, unsigned int height); +static gif_result gif_initialise_frame(gif_animation *gif); +static gif_result gif_initialise_frame_extensions(gif_animation *gif, const int frame); +static gif_result gif_skip_frame_extensions(gif_animation *gif); static unsigned int gif_interlaced_line(int height, int y); /* Internal LZW routines */ -static void gif_init_LZW(struct gif_animation *gif); -static bool gif_next_LZW(struct gif_animation *gif); -static int gif_next_code(struct gif_animation *gif, int code_size); +static void gif_init_LZW(gif_animation *gif); +static bool gif_next_LZW(gif_animation *gif); +static int gif_next_code(gif_animation *gif, int code_size); /* General LZW values. They are shared for all GIFs being decoded, and thus we can't handle progressive decoding efficiently without having @@ -147,6 +147,20 @@ static bool get_done; */ static bool clear_image = false; +/** Initialises necessary gif_animation members. +*/ +void gif_create(gif_animation *gif) { + gif->gif_data = NULL; + gif->frame_image = NULL; + gif->frames = NULL; + gif->local_colour_table = NULL; + gif->global_colour_table = NULL; + gif->buffer_position = 0; + gif->frame_count = 0; + gif->frame_count_partial = 0; + gif->decoded_frame = GIF_INVALID_FRAME; +} + /** Initialises any workspace held by the animation and attempts to decode any information that hasn't already been decoded. If an error occurs, all previously decoded frames are retained. @@ -160,15 +174,20 @@ static bool clear_image = false; GIF_OK for successful decoding GIF_WORKING for successful decoding if more frames are expected */ -gif_result gif_initialise(struct gif_animation *gif, gif_bitmap_callback_vt *bitmap_callbacks) { +gif_result gif_initialise(gif_animation *gif, size_t size, unsigned char *data) { unsigned char *gif_data; unsigned int index; gif_result return_value; - /* The GIF format is thoroughly documented; a full description - * can be found at http://www.w3.org/Graphics/GIF/spec-gif89a.txt - */ + /* The GIF format is thoroughly documented; a full description + * can be found at http://www.w3.org/Graphics/GIF/spec-gif89a.txt + */ + /* Initialize values + */ + gif->buffer_size = size; + gif->gif_data = data; + /* Check for sufficient data to be a GIF (6-byte header + 7-byte logical screen descriptor) */ if (gif->buffer_size < 13) return GIF_INSUFFICIENT_DATA; @@ -227,7 +246,7 @@ gif_result gif_initialise(struct gif_animation *gif, gif_bitmap_callback_vt *bit gif->height = gif_data[2] | (gif_data[3] << 8); gif->global_colours = (gif_data[4] & GIF_COLOUR_TABLE_MASK); gif->colour_table_size = (2 << (gif_data[4] & GIF_COLOUR_TABLE_SIZE_MASK)); - gif->background_colour = gif_data[5]; + gif->background_index = gif_data[5]; gif->aspect_ratio = gif_data[6]; gif->loop_count = 1; gif_data += 7; @@ -255,7 +274,7 @@ gif_result gif_initialise(struct gif_animation *gif, gif_bitmap_callback_vt *bit gif->global_colour_table = (unsigned int *)calloc(GIF_MAX_COLOURS, sizeof(int)); gif->local_colour_table = (unsigned int *)calloc(GIF_MAX_COLOURS, sizeof(int)); if ((gif->global_colour_table == NULL) || (gif->local_colour_table == NULL)) { - gif_finalise(gif, bitmap_callbacks); + gif_finalise(gif); return GIF_INSUFFICIENT_MEMORY; } @@ -277,15 +296,15 @@ gif_result gif_initialise(struct gif_animation *gif, gif_bitmap_callback_vt *bit /* Initialise enough workspace for 4 frames initially */ if ((gif->frames = (gif_frame *)malloc(sizeof(gif_frame))) == NULL) { - gif_finalise(gif, bitmap_callbacks); + gif_finalise(gif); return GIF_INSUFFICIENT_MEMORY; } gif->frame_holders = 1; /* Initialise the sprite header */ - if ((gif->frame_image = bitmap_callbacks->bitmap_create(gif->width, gif->height)) == NULL) { - gif_finalise(gif, bitmap_callbacks); + if ((gif->frame_image = gif->bitmap_callbacks.bitmap_create(gif->width, gif->height)) == NULL) { + gif_finalise(gif); return GIF_INSUFFICIENT_MEMORY; } @@ -320,7 +339,7 @@ gif_result gif_initialise(struct gif_animation *gif, gif_bitmap_callback_vt *bit /* Repeatedly try to initialise frames */ - while ((return_value = gif_initialise_frame(gif, bitmap_callbacks)) == GIF_WORKING); + while ((return_value = gif_initialise_frame(gif)) == GIF_WORKING); /* If there was a memory error tell the caller */ @@ -346,7 +365,7 @@ gif_result gif_initialise(struct gif_animation *gif, gif_bitmap_callback_vt *bit @return GIF_INSUFFICIENT_MEMORY for a memory error GIF_OK for success */ -static gif_result gif_initialise_sprite(struct gif_animation *gif, unsigned int width, unsigned int height, gif_bitmap_callback_vt *bitmap_callbacks) { +static gif_result gif_initialise_sprite(gif_animation *gif, unsigned int width, unsigned int height) { unsigned int max_width; unsigned int max_height; struct bitmap *buffer; @@ -363,9 +382,9 @@ static gif_result gif_initialise_sprite(struct gif_animation *gif, unsigned int /* Allocate some more memory */ - if ((buffer = bitmap_callbacks->bitmap_create(max_width, max_height)) == NULL) + if ((buffer = gif->bitmap_callbacks.bitmap_create(max_width, max_height)) == NULL) return GIF_INSUFFICIENT_MEMORY; - bitmap_callbacks->bitmap_destroy(gif->frame_image); + gif->bitmap_callbacks.bitmap_destroy(gif->frame_image); gif->frame_image = buffer; gif->width = max_width; gif->height = max_height; @@ -387,7 +406,7 @@ static gif_result gif_initialise_sprite(struct gif_animation *gif, unsigned int GIF_OK for successful decoding GIF_WORKING for successful decoding if more frames are expected */ -static gif_result gif_initialise_frame(struct gif_animation *gif, gif_bitmap_callback_vt *bitmap_callbacks) { +static gif_result gif_initialise_frame(gif_animation *gif) { int frame; gif_frame *temp_buf; @@ -517,7 +536,7 @@ static gif_result gif_initialise_frame(struct gif_animation *gif, gif_bitmap_cal /* Boundary checking - shouldn't ever happen except with junk data */ - if (gif_initialise_sprite(gif, (offset_x + width), (offset_y + height), bitmap_callbacks)) + if (gif_initialise_sprite(gif, (offset_x + width), (offset_y + height))) return GIF_INSUFFICIENT_MEMORY; /* Decode the flags @@ -581,7 +600,7 @@ static gif_result gif_initialise_frame(struct gif_animation *gif, gif_bitmap_cal @return GIF_INSUFFICIENT_FRAME_DATA for insufficient data to complete the frame GIF_OK for successful initialisation */ -static gif_result gif_initialise_frame_extensions(struct gif_animation *gif, const int frame) { +static gif_result gif_initialise_frame_extensions(gif_animation *gif, const int frame) { unsigned char *gif_data, *gif_end; int gif_bytes; unsigned int block_size; @@ -695,7 +714,7 @@ static gif_result gif_initialise_frame_extensions(struct gif_animation *gif, con If a frame does not contain any image data, GIF_OK is returned and gif->current_error is set to GIF_FRAME_NO_DISPLAY */ -gif_result gif_decode_frame(struct gif_animation *gif, unsigned int frame, gif_bitmap_callback_vt *bitmap_callbacks) { +gif_result gif_decode_frame(gif_animation *gif, unsigned int frame) { unsigned int index = 0; unsigned char *gif_data, *gif_end; int gif_bytes; @@ -831,7 +850,7 @@ gif_result gif_decode_frame(struct gif_animation *gif, unsigned int frame, gif_b /* Get the frame data */ - frame_data = (unsigned int *)bitmap_callbacks->bitmap_get_buffer(gif->frame_image); + frame_data = (unsigned int *)gif->bitmap_callbacks.bitmap_get_buffer(gif->frame_image); if (!frame_data) return GIF_INSUFFICIENT_MEMORY; @@ -854,10 +873,10 @@ gif_result gif_decode_frame(struct gif_animation *gif, unsigned int frame, gif_b * colour or this is the first frame, clear the frame data */ if ((frame == 0) || (gif->decoded_frame == GIF_INVALID_FRAME)) { - memset((char*)frame_data, colour_table[gif->background_colour], gif->width * gif->height * sizeof(int)); + memset((char*)frame_data, colour_table[gif->background_index], gif->width * gif->height * sizeof(int)); } else if ((frame != 0) && (gif->frames[frame - 1].disposal_method == GIF_FRAME_CLEAR)) { clear_image = true; - if ((return_value = gif_decode_frame(gif, (frame - 1), bitmap_callbacks)) != GIF_OK) + if ((return_value = gif_decode_frame(gif, (frame - 1))) != GIF_OK) goto gif_decode_frame_exit; clear_image = false; /* If the previous frame's disposal method requires we restore the previous @@ -868,13 +887,13 @@ gif_result gif_decode_frame(struct gif_animation *gif, unsigned int frame, gif_b /* If we don't find one, clear the frame data */ if (last_undisposed_frame == -1) { - memset((char*)frame_data, colour_table[gif->background_colour], gif->width * gif->height * sizeof(int)); + memset((char*)frame_data, colour_table[gif->background_index], gif->width * gif->height * sizeof(int)); } else { - if ((return_value = gif_decode_frame(gif, last_undisposed_frame, bitmap_callbacks)) != GIF_OK) + if ((return_value = gif_decode_frame(gif, last_undisposed_frame)) != GIF_OK) goto gif_decode_frame_exit; /* Get this frame's data */ - frame_data = (unsigned int *)bitmap_callbacks->bitmap_get_buffer(gif->frame_image); + frame_data = (unsigned int *)gif->bitmap_callbacks.bitmap_get_buffer(gif->frame_image); if (!frame_data) return GIF_INSUFFICIENT_MEMORY; } @@ -940,7 +959,7 @@ gif_result gif_decode_frame(struct gif_animation *gif, unsigned int frame, gif_b if (gif->frames[frame].disposal_method == GIF_FRAME_CLEAR) { for (y = 0; y < height; y++) { frame_scanline = frame_data + offset_x + ((offset_y + y) * gif->width); - memset(frame_scanline, colour_table[gif->background_colour], width * 4); + memset(frame_scanline, colour_table[gif->background_index], width * 4); } } @@ -968,11 +987,11 @@ gif_decode_frame_exit: /* Check if we should test for optimisation */ if (gif->frames[frame].virgin) { - gif->frames[frame].opaque = bitmap_callbacks->bitmap_test_opaque(gif->frame_image); + gif->frames[frame].opaque = gif->bitmap_callbacks.bitmap_test_opaque(gif->frame_image); gif->frames[frame].virgin = false; } - bitmap_callbacks->bitmap_set_opaque(gif->frame_image, gif->frames[frame].opaque); - bitmap_callbacks->bitmap_modified(gif->frame_image); + gif->bitmap_callbacks.bitmap_set_opaque(gif->frame_image, gif->frames[frame].opaque); + gif->bitmap_callbacks.bitmap_modified(gif->frame_image); /* Restore the buffer position */ @@ -989,7 +1008,7 @@ gif_decode_frame_exit: @return GIF_INSUFFICIENT_FRAME_DATA for insufficient data to complete the frame GIF_OK for successful decoding */ -static gif_result gif_skip_frame_extensions(struct gif_animation *gif) { +static gif_result gif_skip_frame_extensions(gif_animation *gif) { unsigned char *gif_data, *gif_end; int gif_bytes; unsigned int block_size; @@ -1054,11 +1073,11 @@ static unsigned int gif_interlaced_line(int height, int y) { /* Releases any workspace held by the animation */ -void gif_finalise(struct gif_animation *gif, gif_bitmap_callback_vt *bitmap_callbacks) { +void gif_finalise(gif_animation *gif) { /* Release all our memory blocks */ if (gif->frame_image) - bitmap_callbacks->bitmap_destroy(gif->frame_image); + gif->bitmap_callbacks.bitmap_destroy(gif->frame_image); gif->frame_image = NULL; free(gif->frames); gif->frames = NULL; @@ -1066,12 +1085,14 @@ void gif_finalise(struct gif_animation *gif, gif_bitmap_callback_vt *bitmap_call gif->local_colour_table = NULL; free(gif->global_colour_table); gif->global_colour_table = NULL; + free(gif->gif_data); + gif->gif_data = NULL; } /** * Initialise LZW decoding */ -void gif_init_LZW(struct gif_animation *gif) { +void gif_init_LZW(gif_animation *gif) { int i; gif->current_error = 0; @@ -1098,7 +1119,7 @@ void gif_init_LZW(struct gif_animation *gif) { } -static bool gif_next_LZW(struct gif_animation *gif) { +static bool gif_next_LZW(gif_animation *gif) { int code, incode; int block_size; int new_code; @@ -1165,7 +1186,7 @@ static bool gif_next_LZW(struct gif_animation *gif) { return true; } -static int gif_next_code(struct gif_animation *gif, int code_size) { +static int gif_next_code(gif_animation *gif, int code_size) { int i, j, end, count, ret; unsigned char *b; diff --git a/libnsgif.h b/libnsgif.h index b018c20..8564b12 100644 --- a/libnsgif.h +++ b/libnsgif.h @@ -42,9 +42,11 @@ typedef enum { /* The GIF frame data */ typedef struct gif_frame { - unsigned int frame_pointer; /**< offset (in bytes) to the GIF frame data */ - unsigned int frame_delay; /**< delay (in cs) before animating the frame */ bool display; /**< whether the frame should be displayed/animated */ + unsigned int frame_delay; /**< delay (in cs) before animating the frame */ + /** Internal members are listed below + */ + unsigned int frame_pointer; /**< offset (in bytes) to the GIF frame data */ bool virgin; /**< whether the frame has previously been used */ bool opaque; /**< whether the frame is totally opaque */ bool redraw_required; /**< whether a forcable screen redraw is required */ @@ -68,41 +70,45 @@ typedef void (*gif_bitmap_cb_modified)(void *bitmap); /* The Bitmap callbacks function table */ -typedef struct gif_bitmap_callback_vt_s { +typedef struct gif_bitmap_callback_vt { gif_bitmap_cb_create bitmap_create; /**< Create a bitmap. */ gif_bitmap_cb_destroy bitmap_destroy; /**< Free a bitmap. */ gif_bitmap_cb_get_buffer bitmap_get_buffer; /**< Return a pointer to the pixel data in a bitmap. */ gif_bitmap_cb_set_opaque bitmap_set_opaque; /**< Sets whether a bitmap should be plotted opaque. */ gif_bitmap_cb_test_opaque bitmap_test_opaque; /**< Tests whether a bitmap has an opaque alpha channel. */ - gif_bitmap_cb_modified bitmap_modified; /**< The bitmap image has changed, so flush any persistant cache. */ + gif_bitmap_cb_modified bitmap_modified; /**< The bitmap image has changed, so flush any persistant cache. */ } gif_bitmap_callback_vt; /* The GIF animation data */ typedef struct gif_animation { - unsigned char *gif_data; /**< pointer to GIF data */ - unsigned int buffer_position; /**< current index into GIF data */ - unsigned int buffer_size; /**< total number of bytes of GIF data available */ - unsigned int frame_holders; /**< current number of frame holders */ - int decoded_frame; /**< current frame decoded to bitmap */ - int loop_count; /**< number of times to loop animation */ - gif_frame *frames; /**< decoded frames */ - unsigned int width; /**< width of GIF (may increase during decoding) */ - unsigned int height; /**< heigth of GIF (may increase during decoding) */ - unsigned int frame_count; /**< number of frames decoded */ - unsigned int frame_count_partial; /**< number of frames partially decoded */ - unsigned int background_colour; /**< image background colour */ - unsigned int aspect_ratio; /**< image aspect ratio (ignored) */ - unsigned int colour_table_size; /**< size of colour table (in entries) */ - bool global_colours; /**< whether the GIF has a global colour table */ - unsigned int *global_colour_table; /**< global colour table */ - unsigned int *local_colour_table; /**< local colour table */ - void *frame_image; /**< currently decoded image; stored as bitmap from bitmap_create callback */ - gif_result current_error; /**< current error type, or 0 for none*/ + gif_bitmap_callback_vt bitmap_callbacks; /**< callbacks for bitmap functions */ + unsigned char *gif_data; /**< pointer to GIF data */ + unsigned int width; /**< width of GIF (may increase during decoding) */ + unsigned int height; /**< heigth of GIF (may increase during decoding) */ + unsigned int frame_count; /**< number of frames decoded */ + unsigned int frame_count_partial; /**< number of frames partially decoded */ + gif_frame *frames; /**< decoded frames */ + int decoded_frame; /**< current frame decoded to bitmap */ + void *frame_image; /**< currently decoded image; stored as bitmap from bitmap_create callback */ + int loop_count; /**< number of times to loop animation */ + gif_result current_error; /**< current error type, or 0 for none*/ + /** Internal members are listed below + */ + unsigned int buffer_position; /**< current index into GIF data */ + unsigned int buffer_size; /**< total number of bytes of GIF data available */ + unsigned int frame_holders; /**< current number of frame holders */ + unsigned int background_index; /**< index in the colour table for the background colour */ + unsigned int aspect_ratio; /**< image aspect ratio (ignored) */ + unsigned int colour_table_size; /**< size of colour table (in entries) */ + bool global_colours; /**< whether the GIF has a global colour table */ + unsigned int *global_colour_table; /**< global colour table */ + unsigned int *local_colour_table; /**< local colour table */ } gif_animation; -gif_result gif_initialise(struct gif_animation *gif, gif_bitmap_callback_vt *bitmap_callbacks); -gif_result gif_decode_frame(struct gif_animation *gif, unsigned int frame, gif_bitmap_callback_vt *bitmap_callbacks); -void gif_finalise(struct gif_animation *gif, gif_bitmap_callback_vt *bitmap_callbacks); +void gif_create(gif_animation *gif); +gif_result gif_initialise(gif_animation *gif, size_t size, unsigned char *data); +gif_result gif_decode_frame(gif_animation *gif, unsigned int frame); +void gif_finalise(gif_animation *gif); #endif -- cgit v1.2.3