Arch Linux recently updated libnsgif from 0.2.1 to 1.0.0 and having read the header files the 1.0.0 is not backwards compatible. This project will eventually have to be updated.
Animated gifs are disabled on NixOS until this issue is resolved.
See here for more info: https://github.com/NixOS/nixpkgs/blob/194846768975b7ad2c4988bdb82572c00222c0d7/pkgs/applications/graphics/imv/default.nix#L19
I've written a patch for v4.5.0 that bumps the libnsgif version to 1.0.0 as well as some required adjustments. I'm by no means well-versed in C so this patch requires some careful scrutiny I am not able to provide myself.
Apparently using attachments doesn't work, so here's the diff:
Edit: fixed a memory leak
diff --git a/meson.build b/meson.build index ea3a653..69127f8 100644 --- a/meson.build +++ b/meson.build @@ -125,7 +125,7 @@ foreach backend : [ ['libpng', 'dependency', 'libpng', []], ['libjpeg', 'dependency', 'libturbojpeg', []], ['librsvg', 'dependency', 'librsvg-2.0', '>= 2.44'], - ['libnsgif', 'dependency', 'libnsgif', '< 1.0.0'], + ['libnsgif', 'dependency', 'libnsgif', '>= 1.0.0'], ['libheif', 'dependency', 'libheif', []], ['libjxl', 'dependency', 'libjxl', []], ] diff --git a/src/backend_libnsgif.c b/src/backend_libnsgif.c index 5c5995b..f02f34a 100644 --- a/src/backend_libnsgif.c +++ b/src/backend_libnsgif.c @@ -6,7 +6,7 @@ #include "source_private.h" #include <fcntl.h> -#include <libnsgif.h> +#include <nsgif.h> #include <stdlib.h> #include <string.h> #include <sys/mman.h> @@ -14,7 +14,7 @@ struct private { int current_frame; - gif_animation gif; + nsgif_t *gif; void *data; size_t len; }; @@ -52,7 +52,7 @@ static void bitmap_mark_modified(void *bitmap) (void)bitmap; } -static gif_bitmap_callback_vt bitmap_callbacks = { +static nsgif_bitmap_cb_vt bitmap_callbacks = { bitmap_create, bitmap_destroy, bitmap_get_buffer, @@ -69,7 +69,7 @@ static void free_private(void *raw_private) } struct private *private = raw_private; - gif_finalise(&private->gif); + nsgif_destroy(private->gif); munmap(private->data, private->len); free(private); } @@ -78,15 +78,28 @@ static void push_current_image(struct private *private, struct imv_image **image, int *frametime) { struct imv_bitmap *bmp = malloc(sizeof *bmp); - bmp->width = private->gif.width; - bmp->height = private->gif.height; + bmp->width = nsgif_get_info(private->gif)->width; + bmp->height = nsgif_get_info(private->gif)->height; bmp->format = IMV_ABGR; size_t len = 4 * bmp->width * bmp->height; bmp->data = malloc(len); - memcpy(bmp->data, private->gif.frame_image, len); + + nsgif_bitmap_t *frame = 0; + + nsgif_error code = + nsgif_frame_decode(private->gif, private->current_frame, &frame); + + if (code != NSGIF_OK) { + imv_log(IMV_DEBUG, "libnsgif: failed to decode frame %d\n", + private->current_frame); + return; + } + + memcpy(bmp->data, frame, len); *image = imv_image_create_from_bitmap(bmp); - *frametime = private->gif.frames[private->current_frame].frame_delay * 10.0; + *frametime = + nsgif_get_frame_info(private->gif, private->current_frame)->delay * 10.0; } static void first_frame(void *raw_private, struct imv_image **image, int *frametime) @@ -97,12 +110,6 @@ static void first_frame(void *raw_private, struct imv_image **image, int *framet struct private *private = raw_private; private->current_frame = 0; - gif_result code = gif_decode_frame(&private->gif, private->current_frame); - if (code != GIF_OK) { - imv_log(IMV_DEBUG, "libnsgif: failed to decode first frame\n"); - return; - } - push_current_image(private, image, frametime); } @@ -114,13 +121,7 @@ static void next_frame(void *raw_private, struct imv_image **image, int *frameti struct private *private = raw_private; private->current_frame++; - private->current_frame %= private->gif.frame_count; - - gif_result code = gif_decode_frame(&private->gif, private->current_frame); - if (code != GIF_OK) { - imv_log(IMV_DEBUG, "libnsgif: failed to decode a frame\n"); - return; - } + private->current_frame %= nsgif_get_info(private->gif)->frame_count; push_current_image(private, image, frametime); } @@ -134,20 +135,19 @@ static const struct imv_source_vtable vtable = { static enum backend_result open_memory(void *data, size_t len, struct imv_source **src) { struct private *private = calloc(1, sizeof *private); - gif_create(&private->gif, &bitmap_callbacks); + nsgif_create(&bitmap_callbacks, 0, &private->gif); - gif_result code; - do { - code = gif_initialise(&private->gif, len, data); - } while (code == GIF_WORKING); + nsgif_error code = nsgif_data_scan(private->gif, len, data); - if (code != GIF_OK) { - gif_finalise(&private->gif); + if (code != NSGIF_OK) { + nsgif_destroy(private->gif); free(private); imv_log(IMV_DEBUG, "libsngif: unsupported file\n"); return BACKEND_UNSUPPORTED; } + nsgif_data_complete(private->gif); + *src = imv_source_create(&vtable, private); return BACKEND_SUCCESS; } @@ -176,24 +176,26 @@ static enum backend_result open_path(const char *path, struct imv_source **src) struct private *private = calloc(1, sizeof *private); private->data = data; private->len = len; - gif_create(&private->gif, &bitmap_callbacks); + nsgif_create(&bitmap_callbacks, NSGIF_BITMAP_FMT_R8G8B8A8, &private->gif); - gif_result code; - do { - code = gif_initialise(&private->gif, private->len, private->data); - } while (code == GIF_WORKING); + nsgif_error code = nsgif_data_scan(private->gif, private->len, private->data); - if (code != GIF_OK) { - gif_finalise(&private->gif); + if (code != NSGIF_OK) { + nsgif_destroy(private->gif); munmap(private->data, private->len); free(private); imv_log(IMV_DEBUG, "libsngif: unsupported file\n"); return BACKEND_UNSUPPORTED; } - imv_log(IMV_DEBUG, "libnsgif: num_frames=%d\n", private->gif.frame_count); - imv_log(IMV_DEBUG, "libnsgif: width=%d\n", private->gif.width); - imv_log(IMV_DEBUG, "libnsgif: height=%d\n", private->gif.height); + nsgif_data_complete(private->gif); + + imv_log(IMV_DEBUG, "libnsgif: num_frames=%d\n", + nsgif_get_info(private->gif)->frame_count); + imv_log(IMV_DEBUG, "libnsgif: width=%d\n", + nsgif_get_info(private->gif)->width); + imv_log(IMV_DEBUG, "libnsgif: height=%d\n", + nsgif_get_info(private->gif)->height); *src = imv_source_create(&vtable, private); return BACKEND_SUCCESS;