update libnsgif from git master
though unfortunately libnsgif seems to have broken DISPOSE_PREVIOUS handling again
This commit is contained in:
parent
48d9c5d0d4
commit
68332663fb
@ -1,6 +1,8 @@
|
||||
EXTRA_DIST = \
|
||||
README-ns \
|
||||
README.md \
|
||||
patches \
|
||||
update.sh \
|
||||
utils
|
||||
|
||||
noinst_LTLIBRARIES = libnsgif.la
|
||||
|
@ -1,18 +1,16 @@
|
||||
# libnsgif
|
||||
|
||||
This is [libnsgif](https://www.netsurf-browser.org/projects/libnsgif/),
|
||||
but within the libviops build system.
|
||||
|
||||
Based on libnsgif-0.2.1, with one patch to prevent it modifying the input
|
||||
buffer on error.
|
||||
but within the libvips build system.
|
||||
|
||||
# To update
|
||||
|
||||
When netsurf release a new version:
|
||||
Run `./update.sh` to update this copy of libnsgif from the upstream repo. It
|
||||
will also patch libnsgif.c to prevent it modifying the input.
|
||||
|
||||
* copy in sources
|
||||
* reapply any patches from git, eg. no input modification
|
||||
Last updated 28 Feb 2021.
|
||||
|
||||
# To do
|
||||
|
||||
No attempt made to run tests or build docs.
|
||||
No attempt made to run tests or build docs. Though the gif loader is tested as
|
||||
part of the libvips test suite.
|
||||
|
@ -440,7 +440,7 @@ static gif_result gif_initialise_frame(gif_animation *gif)
|
||||
* There was code here to set a TRAILER tag. But this
|
||||
* wrote to the input buffer, which will not work for
|
||||
* libvips, where buffers can be mmaped read only files.
|
||||
*
|
||||
*
|
||||
* Instead, just signal insufficient frame data.
|
||||
*/
|
||||
return GIF_INSUFFICIENT_FRAME_DATA;
|
||||
@ -565,6 +565,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
|
||||
@ -578,6 +645,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;
|
||||
@ -607,6 +675,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;
|
||||
@ -783,34 +856,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;
|
||||
@ -918,6 +973,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;
|
||||
}
|
||||
|
||||
|
||||
@ -1159,6 +1215,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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
/**
|
||||
|
32
libvips/foreign/libnsgif/patches/no-input-modify.patch
Normal file
32
libvips/foreign/libnsgif/patches/no-input-modify.patch
Normal file
@ -0,0 +1,32 @@
|
||||
--- libnsgif-orig.c 2021-02-28 14:10:41.818557190 +0000
|
||||
+++ libnsgif.c 2021-02-28 14:11:55.942285930 +0000
|
||||
@@ -435,20 +435,15 @@
|
||||
block_size = gif_data[0] + 1;
|
||||
/* Check if the frame data runs off the end of the file */
|
||||
if ((int)(gif_bytes - block_size) < 0) {
|
||||
- /* Try to recover by signaling the end of the gif.
|
||||
- * Once we get garbage data, there is no logical way to
|
||||
- * determine where the next frame is. It's probably
|
||||
- * better to partially load the gif than not at all.
|
||||
- */
|
||||
- if (gif_bytes >= 2) {
|
||||
- gif_data[0] = 0;
|
||||
- gif_data[1] = GIF_TRAILER;
|
||||
- gif_bytes = 1;
|
||||
- ++gif_data;
|
||||
- break;
|
||||
- } else {
|
||||
- return GIF_INSUFFICIENT_FRAME_DATA;
|
||||
- }
|
||||
+ /* jcupitt 15/9/19
|
||||
+ *
|
||||
+ * There was code here to set a TRAILER tag. But this
|
||||
+ * wrote to the input buffer, which will not work for
|
||||
+ * libvips, where buffers can be mmaped read only files.
|
||||
+ *
|
||||
+ * Instead, just signal insufficient frame data.
|
||||
+ */
|
||||
+ return GIF_INSUFFICIENT_FRAME_DATA;
|
||||
} else {
|
||||
gif_bytes -= block_size;
|
||||
gif_data += block_size;
|
22
libvips/foreign/libnsgif/update.sh
Executable file
22
libvips/foreign/libnsgif/update.sh
Executable file
@ -0,0 +1,22 @@
|
||||
#!/bin/bash
|
||||
|
||||
# attempt to update our copy of libnsgif from the upstream repo
|
||||
|
||||
set -e
|
||||
|
||||
git clone git://git.netsurf-browser.org/libnsgif.git
|
||||
|
||||
echo copying out source files ...
|
||||
cp libnsgif/src/libnsgif.c .
|
||||
cp libnsgif/include/libnsgif.h .
|
||||
cp libnsgif/src/lzw.[ch] .
|
||||
cp libnsgif/src/utils/log.h utils
|
||||
|
||||
echo applying patches ...
|
||||
for patch in patches/*.patch; do
|
||||
patch -p0 <$patch
|
||||
done
|
||||
|
||||
echo cleaning up ...
|
||||
rm -rf libnsgif
|
||||
|
Loading…
Reference in New Issue
Block a user