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 = \
|
EXTRA_DIST = \
|
||||||
README-ns \
|
README-ns \
|
||||||
README.md \
|
README.md \
|
||||||
|
patches \
|
||||||
|
update.sh \
|
||||||
utils
|
utils
|
||||||
|
|
||||||
noinst_LTLIBRARIES = libnsgif.la
|
noinst_LTLIBRARIES = libnsgif.la
|
||||||
|
@ -1,18 +1,16 @@
|
|||||||
# libnsgif
|
# libnsgif
|
||||||
|
|
||||||
This is [libnsgif](https://www.netsurf-browser.org/projects/libnsgif/),
|
This is [libnsgif](https://www.netsurf-browser.org/projects/libnsgif/),
|
||||||
but within the libviops build system.
|
but within the libvips build system.
|
||||||
|
|
||||||
Based on libnsgif-0.2.1, with one patch to prevent it modifying the input
|
|
||||||
buffer on error.
|
|
||||||
|
|
||||||
# To update
|
# 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
|
Last updated 28 Feb 2021.
|
||||||
* reapply any patches from git, eg. no input modification
|
|
||||||
|
|
||||||
# To do
|
# 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.
|
||||||
|
@ -565,6 +565,73 @@ static gif_result gif_error_from_lzw(lzw_result l_res)
|
|||||||
return g_res[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
|
* decode a gif frame
|
||||||
@ -578,6 +645,7 @@ gif_internal_decode_frame(gif_animation *gif,
|
|||||||
unsigned int frame,
|
unsigned int frame,
|
||||||
bool clear_image)
|
bool clear_image)
|
||||||
{
|
{
|
||||||
|
gif_result err;
|
||||||
unsigned int index = 0;
|
unsigned int index = 0;
|
||||||
unsigned char *gif_data, *gif_end;
|
unsigned char *gif_data, *gif_end;
|
||||||
int gif_bytes;
|
int gif_bytes;
|
||||||
@ -607,6 +675,11 @@ gif_internal_decode_frame(gif_animation *gif,
|
|||||||
return GIF_OK;
|
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 */
|
/* 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_data = gif->gif_data + gif->frames[frame].frame_pointer;
|
||||||
gif_end = gif->gif_data + gif->buffer_size;
|
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)) {
|
(gif->frames[frame - 1].disposal_method == GIF_FRAME_RESTORE)) {
|
||||||
/*
|
/*
|
||||||
* If the previous frame's disposal method requires we
|
* If the previous frame's disposal method requires we
|
||||||
* restore the previous image, find the last image set
|
* restore the previous image, restore our saved image.
|
||||||
* to "do not dispose" and get that frame data
|
|
||||||
*/
|
*/
|
||||||
int last_undisposed_frame = frame - 2;
|
err = gif__recover_previous_frame(gif);
|
||||||
while ((last_undisposed_frame >= 0) &&
|
if (err != GIF_OK) {
|
||||||
(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) {
|
|
||||||
/* see notes above on transparency
|
/* see notes above on transparency
|
||||||
* vs. background color
|
* vs. background color
|
||||||
*/
|
*/
|
||||||
memset((char*)frame_data,
|
memset((char*)frame_data,
|
||||||
GIF_TRANSPARENT_COLOUR,
|
GIF_TRANSPARENT_COLOUR,
|
||||||
gif->width * gif->height * sizeof(int));
|
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;
|
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));
|
memset(gif, 0, sizeof(gif_animation));
|
||||||
gif->bitmap_callbacks = *bitmap_callbacks;
|
gif->bitmap_callbacks = *bitmap_callbacks;
|
||||||
gif->decoded_frame = GIF_INVALID_FRAME;
|
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);
|
free(gif->global_colour_table);
|
||||||
gif->global_colour_table = NULL;
|
gif->global_colour_table = NULL;
|
||||||
|
|
||||||
|
free(gif->prev_frame);
|
||||||
|
gif->prev_frame = NULL;
|
||||||
|
|
||||||
lzw_context_destroy(gif->lzw_ctx);
|
lzw_context_destroy(gif->lzw_ctx);
|
||||||
gif->lzw_ctx = NULL;
|
gif->lzw_ctx = NULL;
|
||||||
}
|
}
|
||||||
|
@ -136,6 +136,15 @@ typedef struct gif_animation {
|
|||||||
unsigned int *global_colour_table;
|
unsigned int *global_colour_table;
|
||||||
/** local colour table */
|
/** local colour table */
|
||||||
unsigned int *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;
|
} 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