Gitweb links:
...log
http://git.netsurf-browser.org/libnsgif.git/shortlog/8442a27c2bb8df48029ceea6e64c4930106a57fc
...commit
http://git.netsurf-browser.org/libnsgif.git/commit/8442a27c2bb8df48029ceea6e64c4930106a57fc
...tree
http://git.netsurf-browser.org/libnsgif.git/tree/8442a27c2bb8df48029ceea6e64c4930106a57fc
The branch, master has been updated
via 8442a27c2bb8df48029ceea6e64c4930106a57fc (commit)
from a937d161f6787ecc1c1bef9bad6039925ff13d72 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commitdiff
http://git.netsurf-browser.org/libnsgif.git/commit/?id=8442a27c2bb8df48029ceea6e64c4930106a57fc
commit 8442a27c2bb8df48029ceea6e64c4930106a57fc
Author: Michael Drake <[email protected]>
Commit: Michael Drake <[email protected]>
Disposal Method: Handle Restore to previous with saved image.
Previously we decoded a previous frame over the current frame data
to handle resoration. However, the previous frame depended on its
own previous frame state for correct decode.
Now we just make a copy of the previous frame data and copy it
back to handle the GIF_FRAME_RESTORE case.
See: https://github.com/libvips/libvips/issues/1084#issuecomment-653497200
diff --git a/include/libnsgif.h b/include/libnsgif.h
index a819fec..50dc688 100644
--- a/include/libnsgif.h
+++ b/include/libnsgif.h
@@ -136,6 +136,15 @@ typedef struct gif_animation {
unsigned int *global_colour_table;
/** local colour table */
unsigned int *local_colour_table;
+
+ /** previous frame for GIF_FRAME_RESTORE */
+ void *prev_frame;
+ /** previous frame index */
+ int prev_index;
+ /** previous frame width */
+ unsigned prev_width;
+ /** previous frame height */
+ unsigned prev_height;
} gif_animation;
/**
diff --git a/src/libnsgif.c b/src/libnsgif.c
index 6bf9956..95bbbfb 100644
--- a/src/libnsgif.c
+++ b/src/libnsgif.c
@@ -570,6 +570,73 @@ static gif_result gif_error_from_lzw(lzw_result l_res)
return g_res[l_res];
}
+static void gif__record_previous_frame(gif_animation *gif)
+{
+ bool need_alloc = gif->prev_frame == NULL;
+ const uint32_t *frame_data;
+ uint32_t *prev_frame;
+
+ if (gif->decoded_frame == GIF_INVALID_FRAME ||
+ gif->decoded_frame == gif->prev_index) {
+ /* No frame to copy, or already have this frame recorded. */
+ return;
+ }
+
+ assert(gif->bitmap_callbacks.bitmap_get_buffer);
+ frame_data = (void
*)gif->bitmap_callbacks.bitmap_get_buffer(gif->frame_image);
+ if (!frame_data) {
+ return;
+ }
+
+ if (gif->prev_frame != NULL &&
+ gif->width * gif->height < gif->prev_width * gif->prev_height) {
+ need_alloc = true;
+ }
+
+ if (need_alloc) {
+ prev_frame = realloc(gif->prev_frame,
+ gif->width * gif->height * 4);
+ if (prev_frame == NULL) {
+ return;
+ }
+ } else {
+ prev_frame = gif->prev_frame;
+ }
+
+ memcpy(prev_frame, frame_data, gif->width * gif->height * 4);
+
+ gif->prev_frame = prev_frame;
+ gif->prev_width = gif->width;
+ gif->prev_height = gif->height;
+ gif->prev_index = gif->decoded_frame;
+}
+
+static gif_result gif__recover_previous_frame(const gif_animation *gif)
+{
+ const uint32_t *prev_frame = gif->prev_frame;
+ unsigned height = gif->height < gif->prev_height ? gif->height :
gif->prev_height;
+ unsigned width = gif->width < gif->prev_width ? gif->width :
gif->prev_width;
+ uint32_t *frame_data;
+
+ if (prev_frame == NULL) {
+ return GIF_FRAME_DATA_ERROR;
+ }
+
+ assert(gif->bitmap_callbacks.bitmap_get_buffer);
+ frame_data = (void
*)gif->bitmap_callbacks.bitmap_get_buffer(gif->frame_image);
+ if (!frame_data) {
+ return GIF_INSUFFICIENT_MEMORY;
+ }
+
+ for (unsigned y = 0; y < height; y++) {
+ memcpy(frame_data, prev_frame, width * 4);
+
+ frame_data += gif->width;
+ prev_frame += gif->prev_width;
+ }
+
+ return GIF_OK;
+}
/**
* decode a gif frame
@@ -583,6 +650,7 @@ gif_internal_decode_frame(gif_animation *gif,
unsigned int frame,
bool clear_image)
{
+ gif_result err;
unsigned int index = 0;
unsigned char *gif_data, *gif_end;
int gif_bytes;
@@ -612,6 +680,11 @@ gif_internal_decode_frame(gif_animation *gif,
return GIF_OK;
}
+ if (gif->frames[frame].disposal_method == GIF_FRAME_RESTORE) {
+ /* Store the previous frame for later restoration */
+ gif__record_previous_frame(gif);
+ }
+
/* Get the start of our frame data and the end of the GIF data */
gif_data = gif->gif_data + gif->frames[frame].frame_pointer;
gif_end = gif->gif_data + gif->buffer_size;
@@ -788,34 +861,16 @@ gif_internal_decode_frame(gif_animation *gif,
(gif->frames[frame - 1].disposal_method ==
GIF_FRAME_RESTORE)) {
/*
* If the previous frame's disposal method requires we
- * restore the previous image, find the last image set
- * to "do not dispose" and get that frame data
+ * restore the previous image, restore our saved image.
*/
- int last_undisposed_frame = frame - 2;
- while ((last_undisposed_frame >= 0) &&
-
(gif->frames[last_undisposed_frame].disposal_method == GIF_FRAME_RESTORE)) {
- last_undisposed_frame--;
- }
-
- /* If we don't find one, clear the frame data */
- if (last_undisposed_frame == -1) {
+ err = gif__recover_previous_frame(gif);
+ if (err != GIF_OK) {
/* see notes above on transparency
* vs. background color
*/
memset((char*)frame_data,
GIF_TRANSPARENT_COLOUR,
gif->width * gif->height * sizeof(int));
- } else {
- return_value = gif_internal_decode_frame(gif,
last_undisposed_frame, false);
- if (return_value != GIF_OK) {
- goto gif_decode_frame_exit;
- }
- /* Get this frame's data */
-
assert(gif->bitmap_callbacks.bitmap_get_buffer);
- frame_data = (void
*)gif->bitmap_callbacks.bitmap_get_buffer(gif->frame_image);
- if (!frame_data) {
- return GIF_INSUFFICIENT_MEMORY;
- }
}
}
gif->decoded_frame = frame;
@@ -923,6 +978,7 @@ void gif_create(gif_animation *gif, gif_bitmap_callback_vt
*bitmap_callbacks)
memset(gif, 0, sizeof(gif_animation));
gif->bitmap_callbacks = *bitmap_callbacks;
gif->decoded_frame = GIF_INVALID_FRAME;
+ gif->prev_index = GIF_INVALID_FRAME;
}
@@ -1164,6 +1220,9 @@ void gif_finalise(gif_animation *gif)
free(gif->global_colour_table);
gif->global_colour_table = NULL;
+ free(gif->prev_frame);
+ gif->prev_frame = NULL;
+
lzw_context_destroy(gif->lzw_ctx);
gif->lzw_ctx = NULL;
}
-----------------------------------------------------------------------
Summary of changes:
include/libnsgif.h | 9 +++++
src/libnsgif.c | 101 +++++++++++++++++++++++++++++++++++++++++-----------
2 files changed, 89 insertions(+), 21 deletions(-)
diff --git a/include/libnsgif.h b/include/libnsgif.h
index a819fec..50dc688 100644
--- a/include/libnsgif.h
+++ b/include/libnsgif.h
@@ -136,6 +136,15 @@ typedef struct gif_animation {
unsigned int *global_colour_table;
/** local colour table */
unsigned int *local_colour_table;
+
+ /** previous frame for GIF_FRAME_RESTORE */
+ void *prev_frame;
+ /** previous frame index */
+ int prev_index;
+ /** previous frame width */
+ unsigned prev_width;
+ /** previous frame height */
+ unsigned prev_height;
} gif_animation;
/**
diff --git a/src/libnsgif.c b/src/libnsgif.c
index 6bf9956..95bbbfb 100644
--- a/src/libnsgif.c
+++ b/src/libnsgif.c
@@ -570,6 +570,73 @@ static gif_result gif_error_from_lzw(lzw_result l_res)
return g_res[l_res];
}
+static void gif__record_previous_frame(gif_animation *gif)
+{
+ bool need_alloc = gif->prev_frame == NULL;
+ const uint32_t *frame_data;
+ uint32_t *prev_frame;
+
+ if (gif->decoded_frame == GIF_INVALID_FRAME ||
+ gif->decoded_frame == gif->prev_index) {
+ /* No frame to copy, or already have this frame recorded. */
+ return;
+ }
+
+ assert(gif->bitmap_callbacks.bitmap_get_buffer);
+ frame_data = (void
*)gif->bitmap_callbacks.bitmap_get_buffer(gif->frame_image);
+ if (!frame_data) {
+ return;
+ }
+
+ if (gif->prev_frame != NULL &&
+ gif->width * gif->height < gif->prev_width * gif->prev_height) {
+ need_alloc = true;
+ }
+
+ if (need_alloc) {
+ prev_frame = realloc(gif->prev_frame,
+ gif->width * gif->height * 4);
+ if (prev_frame == NULL) {
+ return;
+ }
+ } else {
+ prev_frame = gif->prev_frame;
+ }
+
+ memcpy(prev_frame, frame_data, gif->width * gif->height * 4);
+
+ gif->prev_frame = prev_frame;
+ gif->prev_width = gif->width;
+ gif->prev_height = gif->height;
+ gif->prev_index = gif->decoded_frame;
+}
+
+static gif_result gif__recover_previous_frame(const gif_animation *gif)
+{
+ const uint32_t *prev_frame = gif->prev_frame;
+ unsigned height = gif->height < gif->prev_height ? gif->height :
gif->prev_height;
+ unsigned width = gif->width < gif->prev_width ? gif->width :
gif->prev_width;
+ uint32_t *frame_data;
+
+ if (prev_frame == NULL) {
+ return GIF_FRAME_DATA_ERROR;
+ }
+
+ assert(gif->bitmap_callbacks.bitmap_get_buffer);
+ frame_data = (void
*)gif->bitmap_callbacks.bitmap_get_buffer(gif->frame_image);
+ if (!frame_data) {
+ return GIF_INSUFFICIENT_MEMORY;
+ }
+
+ for (unsigned y = 0; y < height; y++) {
+ memcpy(frame_data, prev_frame, width * 4);
+
+ frame_data += gif->width;
+ prev_frame += gif->prev_width;
+ }
+
+ return GIF_OK;
+}
/**
* decode a gif frame
@@ -583,6 +650,7 @@ gif_internal_decode_frame(gif_animation *gif,
unsigned int frame,
bool clear_image)
{
+ gif_result err;
unsigned int index = 0;
unsigned char *gif_data, *gif_end;
int gif_bytes;
@@ -612,6 +680,11 @@ gif_internal_decode_frame(gif_animation *gif,
return GIF_OK;
}
+ if (gif->frames[frame].disposal_method == GIF_FRAME_RESTORE) {
+ /* Store the previous frame for later restoration */
+ gif__record_previous_frame(gif);
+ }
+
/* Get the start of our frame data and the end of the GIF data */
gif_data = gif->gif_data + gif->frames[frame].frame_pointer;
gif_end = gif->gif_data + gif->buffer_size;
@@ -788,34 +861,16 @@ gif_internal_decode_frame(gif_animation *gif,
(gif->frames[frame - 1].disposal_method ==
GIF_FRAME_RESTORE)) {
/*
* If the previous frame's disposal method requires we
- * restore the previous image, find the last image set
- * to "do not dispose" and get that frame data
+ * restore the previous image, restore our saved image.
*/
- int last_undisposed_frame = frame - 2;
- while ((last_undisposed_frame >= 0) &&
-
(gif->frames[last_undisposed_frame].disposal_method == GIF_FRAME_RESTORE)) {
- last_undisposed_frame--;
- }
-
- /* If we don't find one, clear the frame data */
- if (last_undisposed_frame == -1) {
+ err = gif__recover_previous_frame(gif);
+ if (err != GIF_OK) {
/* see notes above on transparency
* vs. background color
*/
memset((char*)frame_data,
GIF_TRANSPARENT_COLOUR,
gif->width * gif->height * sizeof(int));
- } else {
- return_value = gif_internal_decode_frame(gif,
last_undisposed_frame, false);
- if (return_value != GIF_OK) {
- goto gif_decode_frame_exit;
- }
- /* Get this frame's data */
-
assert(gif->bitmap_callbacks.bitmap_get_buffer);
- frame_data = (void
*)gif->bitmap_callbacks.bitmap_get_buffer(gif->frame_image);
- if (!frame_data) {
- return GIF_INSUFFICIENT_MEMORY;
- }
}
}
gif->decoded_frame = frame;
@@ -923,6 +978,7 @@ void gif_create(gif_animation *gif, gif_bitmap_callback_vt
*bitmap_callbacks)
memset(gif, 0, sizeof(gif_animation));
gif->bitmap_callbacks = *bitmap_callbacks;
gif->decoded_frame = GIF_INVALID_FRAME;
+ gif->prev_index = GIF_INVALID_FRAME;
}
@@ -1164,6 +1220,9 @@ void gif_finalise(gif_animation *gif)
free(gif->global_colour_table);
gif->global_colour_table = NULL;
+ free(gif->prev_frame);
+ gif->prev_frame = NULL;
+
lzw_context_destroy(gif->lzw_ctx);
gif->lzw_ctx = NULL;
}
--
NetSurf GIF Decoder
_______________________________________________
netsurf-commits mailing list -- [email protected]
To unsubscribe send an email to [email protected]