summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--examples/decode_gif.c45
-rw-r--r--libnsgif.c101
-rw-r--r--libnsgif.h58
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 <sys/stat.h>
#include <libnsgif.h>
-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