Package: nsxiv Version: 29-2 Severity: normal Tags: patch
First of all thanks for packaging nsxiv for debian. as the subject indicates, nsxiv fails to even load animated webp images this is intended as v29 depends on imlib2 1.7.5 for animated webp support, this reverts the webp function to the older version that works with 1.7.1, in the future the plan for nsxiv is to depend on 1.8.0 to handle multi frame images, altho the change was intended for v30 it is currenlty on hold as it causes performance regressions. i tested and the patch works as expected. >From 407052d02f01ac2a345edc651dc5a791e81eb5fc Mon Sep 17 00:00:00 2001 From: eylles <ed.ylles1...@gmail.com> Date: Thu, 21 Apr 2022 03:12:24 -0600 Subject: [PATCH] Restore old webp loading Use webp loading function for imlib2 1.7.1 (and possibly 1.6.9) This reverts upstream commits: 61da0a8ca9f2a39042f7ef9af63a2dd48057c927 b0b16f1d0ffa550a8358206de844c9cf13f94ada 22ca3b567dd08c0086399221cb1413fa4eb74e2e 3b6db44267438fb0f9d67b3783d3bc6713c3c07f eccd7de532b09fb738638095675eefc7be96ecc3 --- README.md | 1 - image.c | 162 +++++++++++++++++++++++++++++++++++------------------- 2 files changed, 104 insertions(+), 59 deletions(-) diff --git a/README.md b/README.md index c5028ac..b939366 100644 --- a/README.md +++ b/README.md @@ -76,7 +76,6 @@ The following dependencies are optional. * libexif : Used for auto-orientation and exif thumbnails. Disable via `HAVE_LIBEXIF=0` * libwebp : Used for animated webp playback. - (NOTE: animated webp also requires Imlib2 v1.7.5 or above) Disabled via `HAVE_LIBWEBP=0`. Please make sure to install the corresponding development packages in case that diff --git a/image.c b/image.c index 1c57d27..ade5d1b 100644 --- a/image.c +++ b/image.c @@ -135,23 +135,6 @@ void exif_auto_orientate(const fileinfo_t *file) } #endif -#if HAVE_LIBGIF || HAVE_LIBWEBP -static void img_multiframe_context_set(img_t *img) -{ - if (img->multi.cnt > 1) { - imlib_context_set_image(img->im); - imlib_free_image(); - img->im = img->multi.frames[0].im; - } else if (img->multi.cnt == 1) { - imlib_context_set_image(img->multi.frames[0].im); - imlib_free_image(); - img->multi.cnt = 0; - } - - imlib_context_set_image(img->im); -} -#endif - #if HAVE_LIBGIF static bool img_load_gif(img_t *img, const fileinfo_t *file) { @@ -315,7 +298,17 @@ static bool img_load_gif(img_t *img, const fileinfo_t *file) if (err && (file->flags & FF_WARN)) error(0, 0, "%s: Corrupted gif file", file->name); - img_multiframe_context_set(img); + if (img->multi.cnt > 1) { + imlib_context_set_image(img->im); + imlib_free_image(); + img->im = img->multi.frames[0].im; + } else if (img->multi.cnt == 1) { + imlib_context_set_image(img->multi.frames[0].im); + imlib_free_image(); + img->multi.cnt = 0; + } + + imlib_context_set_image(img->im); return !err; } @@ -323,35 +316,60 @@ static bool img_load_gif(img_t *img, const fileinfo_t *file) #if HAVE_LIBWEBP -static bool img_load_webp(img_t *img, const fileinfo_t *file) +static bool is_webp(const char *path) +{ + /* The size (in bytes) of the largest amount of data required to verify a WebP image. */ + enum { max = 30 }; + const unsigned char fmt[max]; + bool ret = false; + FILE *f; + + if ((f = fopen(path, "rb")) != NULL) { + if (fread((unsigned char *) fmt, 1, max, f) == max) + ret = WebPGetInfo(fmt, max, NULL, NULL); + fclose(f); + } + return ret; +} + +/* fframe img + * NULL NULL = do nothing + * x NULL = load the first frame as an Imlib_Image + * NULL x = load all frames into img->multi. + */ +static bool img_load_webp(const fileinfo_t *file, Imlib_Image *fframe, img_t *img) { FILE *webp_file; WebPData data; + Imlib_Image im = NULL; struct WebPAnimDecoderOptions opts; WebPAnimDecoder *dec = NULL; struct WebPAnimInfo info; - unsigned char *buf = NULL, *bytes = NULL; + unsigned char *buf = NULL; int ts; const WebPDemuxer *demux; WebPIterator iter; unsigned long flags; unsigned int delay; bool err = false; + data.bytes = NULL; - if ((webp_file = fopen(file->path, "rb")) == NULL) { - error(0, errno, "%s: Error opening webp image", file->name); - return false; + if ((err = fframe == NULL && img == NULL)) + goto fail; + + if ((err = (webp_file = fopen(file->path, "rb")) == NULL)) { + error(0, 0, "%s: Error opening webp image", file->name); + goto fail; } fseek(webp_file, 0L, SEEK_END); data.size = ftell(webp_file); rewind(webp_file); - bytes = emalloc(data.size); - if ((err = fread(bytes, 1, data.size, webp_file) != data.size)) { + data.bytes = emalloc(data.size); + if ((err = fread((unsigned char *)data.bytes, 1, data.size, webp_file) != data.size)) { error(0, 0, "%s: Error reading webp image", file->name); goto fail; } - data.bytes = bytes; /* Setup the WebP Animation Decoder */ if ((err = !WebPAnimDecoderOptionsInit(&opts))) { @@ -368,42 +386,65 @@ static bool img_load_webp(img_t *img, const fileinfo_t *file) } demux = WebPAnimDecoderGetDemuxer(dec); - /* Get global information for the image */ - flags = WebPDemuxGetI(demux, WEBP_FF_FORMAT_FLAGS); - img->w = WebPDemuxGetI(demux, WEBP_FF_CANVAS_WIDTH); - img->h = WebPDemuxGetI(demux, WEBP_FF_CANVAS_HEIGHT); + if (img == NULL) { /* Only get the first frame and put it into fframe. */ + if ((err = !WebPAnimDecoderGetNext(dec, &buf, &ts))) { + error(0, 0, "%s: Error loading first frame", file->name); + goto fail; + } + *fframe = imlib_create_image_using_copied_data( + info.canvas_width, info.canvas_height, (DATA32*)buf); + imlib_context_set_image(*fframe); + imlib_image_set_has_alpha(WebPDemuxGetI(demux, WEBP_FF_FORMAT_FLAGS) & ALPHA_FLAG); + } else { + /* Get global information for the image */ + flags = WebPDemuxGetI(demux, WEBP_FF_FORMAT_FLAGS); + img->w = WebPDemuxGetI(demux, WEBP_FF_CANVAS_WIDTH); + img->h = WebPDemuxGetI(demux, WEBP_FF_CANVAS_HEIGHT); + + if (img->multi.cap == 0) { + img->multi.cap = info.frame_count; + img->multi.frames = emalloc(img->multi.cap * sizeof(img_frame_t)); + } else if (info.frame_count > img->multi.cap) { + img->multi.cap = info.frame_count; + img->multi.frames = erealloc(img->multi.frames, + img->multi.cap * sizeof(img_frame_t)); + } - if (info.frame_count > img->multi.cap) { - img->multi.cap = info.frame_count; - img->multi.frames = erealloc(img->multi.frames, - img->multi.cap * sizeof(img_frame_t)); - } + /* Load and decode frames (also works on images with only 1 frame) */ + img->multi.cnt = img->multi.sel = 0; + while (WebPAnimDecoderGetNext(dec, &buf, &ts)) { + im = imlib_create_image_using_copied_data( + info.canvas_width, info.canvas_height, (DATA32*)buf); + imlib_context_set_image(im); + imlib_image_set_format("webp"); + /* Get an iterator of this frame - used for frame info (duration, etc.) */ + WebPDemuxGetFrame(demux, img->multi.cnt+1, &iter); + imlib_image_set_has_alpha((flags & ALPHA_FLAG) == ALPHA_FLAG); + /* Store info for this frame */ + img->multi.frames[img->multi.cnt].im = im; + delay = iter.duration > 0 ? iter.duration : DEF_WEBP_DELAY; + img->multi.frames[img->multi.cnt].delay = delay; + img->multi.length += img->multi.frames[img->multi.cnt].delay; + img->multi.cnt++; + } + WebPDemuxReleaseIterator(&iter); - /* Load and decode frames (also works on images with only 1 frame) */ - img->multi.cnt = img->multi.sel = 0; - while (WebPAnimDecoderGetNext(dec, &buf, &ts)) { - im = imlib_create_image_using_copied_data( - info.canvas_width, info.canvas_height, (DATA32*)buf); - imlib_context_set_image(im); - imlib_image_set_format("webp"); - /* Get an iterator of this frame - used for frame info (duration, etc.) */ - WebPDemuxGetFrame(demux, img->multi.cnt+1, &iter); - imlib_image_set_has_alpha((flags & ALPHA_FLAG) == ALPHA_FLAG); - /* Store info for this frame */ - img->multi.frames[img->multi.cnt].im = im; - delay = iter.duration > 0 ? iter.duration : DEF_WEBP_DELAY; - img->multi.frames[img->multi.cnt].delay = delay; - img->multi.length += img->multi.frames[img->multi.cnt].delay; - img->multi.cnt++; + if (img->multi.cnt > 1) { + imlib_context_set_image(img->im); + imlib_free_image(); + img->im = img->multi.frames[0].im; + } else if (img->multi.cnt == 1) { + imlib_context_set_image(img->multi.frames[0].im); + imlib_free_image(); + img->multi.cnt = 0; + } + imlib_context_set_image(img->im); } - WebPDemuxReleaseIterator(&iter); - - img_multiframe_context_set(img); + imlib_image_set_format("webp"); fail: if (dec != NULL) WebPAnimDecoderDelete(dec); - free(bytes); - fclose(webp_file); + free((unsigned char *)data.bytes); return !err; } #endif /* HAVE_LIBWEBP */ @@ -416,7 +457,12 @@ Imlib_Image img_open(const fileinfo_t *file) if (access(file->path, R_OK) == 0 && stat(file->path, &st) == 0 && S_ISREG(st.st_mode)) { - im = imlib_load_image(file->path); +#if HAVE_LIBWEBP + if (is_webp(file->path)) + img_load_webp(file, &im, NULL); + else +#endif + im = imlib_load_image(file->path); if (im != NULL) { imlib_context_set_image(im); if (imlib_image_get_data_for_reading_only() == NULL) { @@ -454,7 +500,7 @@ bool img_load(img_t *img, const fileinfo_t *file) #endif #if HAVE_LIBWEBP if (STREQ(fmt, "webp")) - img_load_webp(img, file); + img_load_webp(file, NULL, img); #endif #if HAVE_LIBEXIF && defined(IMLIB2_VERSION) if (!STREQ(fmt, "jpeg") && !STREQ(fmt, "jpg")) -- System Information: Debian Release: bookworm/sid Architecture: amd64 (x86_64) Foreign Architectures: i386 Kernel: Linux 5.16.0-6-amd64 (SMP w/8 CPU threads; PREEMPT) Kernel taint flags: TAINT_WARN Locale: LANG=en_US.UTF-8, LC_CTYPE=en_US.UTF-8 (charmap=UTF-8), LANGUAGE=en_US:en Shell: /bin/sh linked to /bin/dash Init: sysvinit (via /sbin/init) LSM: AppArmor: enabled Versions of packages nsxiv depends on: ii libc6 2.33-7 ii libexif12 0.6.24-1 ii libfontconfig1 2.13.1-4.4 ii libgif7 5.1.9-2 ii libimlib2 1.7.4-2 ii libwebpdemux2 1.2.2-2+b1 ii libx11-6 2:1.7.5-1 ii libxft2 2.3.4-1 nsxiv recommends no packages. Versions of packages nsxiv suggests: ii graphicsmagick-imagemagick-compat [imagemagick] 1.4+really1.3.38-1 pn libjpeg-progs <none> pn rawtherapee <none> ii xclip 0.13-2 -- no debconf information