remove legacy multi-frame loaders

this removes the legacy gif and webp loaders. moving forward
multi-frame/animated images will be loaded by imlib2 itself.

Closes: https://codeberg.org/nsxiv/nsxiv/issues/397
This commit is contained in:
NRK 2023-08-27 23:20:39 +06:00
parent 1fc28278b5
commit e1b851c488
8 changed files with 9 additions and 332 deletions

View file

@ -43,11 +43,11 @@ jobs:
run: | run: |
brew update brew update
# see: https://github.com/actions/setup-python/issues/577 # see: https://github.com/actions/setup-python/issues/577
brew install imlib2 libx11 libxft libexif giflib webp || true brew install imlib2 libx11 libxft libexif || true
- name: build - name: build
run: | run: |
# libinotify-kqueue isn't available on homebrew # libinotify-kqueue isn't available on homebrew
make clean && make -s OPT_DEP_DEFAULT=1 HAVE_INOTIFY=0 make clean && make -s OPT_DEP_DEFAULT=1 HAVE_INOTIFY=0
# force uninstallation with --ignore-dependencies # force uninstallation with --ignore-dependencies
brew uninstall --ignore-dependencies libxft libexif giflib webp brew uninstall --ignore-dependencies libxft libexif
make clean && make -s OPT_DEP_DEFAULT=0 make clean && make -s OPT_DEP_DEFAULT=0

View file

@ -8,20 +8,14 @@ lib_fonts_0 =
lib_fonts_1 = -lXft -lfontconfig lib_fonts_1 = -lXft -lfontconfig
lib_exif_0 = lib_exif_0 =
lib_exif_1 = -lexif lib_exif_1 = -lexif
lib_gif_0 =
lib_gif_1 = -lgif
lib_webp_0 =
lib_webp_1 = -lwebpdemux -lwebp
nsxiv_cppflags = -D_XOPEN_SOURCE=700 \ nsxiv_cppflags = -D_XOPEN_SOURCE=700 \
-DHAVE_LIBGIF=$(HAVE_LIBGIF) -DHAVE_LIBEXIF=$(HAVE_LIBEXIF) \ -DHAVE_LIBEXIF=$(HAVE_LIBEXIF) -DHAVE_LIBFONTS=$(HAVE_LIBFONTS) \
-DHAVE_LIBWEBP=$(HAVE_LIBWEBP) -DHAVE_LIBFONTS=$(HAVE_LIBFONTS) \
-DHAVE_INOTIFY=$(HAVE_INOTIFY) $(inc_fonts_$(HAVE_LIBFONTS)) \ -DHAVE_INOTIFY=$(HAVE_INOTIFY) $(inc_fonts_$(HAVE_LIBFONTS)) \
$(CPPFLAGS) $(CPPFLAGS)
nsxiv_ldlibs = -lImlib2 -lX11 \ nsxiv_ldlibs = -lImlib2 -lX11 \
$(lib_exif_$(HAVE_LIBEXIF)) $(lib_gif_$(HAVE_LIBGIF)) \ $(lib_exif_$(HAVE_LIBEXIF)) $(lib_fonts_$(HAVE_LIBFONTS)) \
$(lib_webp_$(HAVE_LIBWEBP)) $(lib_fonts_$(HAVE_LIBFONTS)) \
$(LDLIBS) $(LDLIBS)
objs = autoreload.o commands.o image.o main.o options.o \ objs = autoreload.o commands.o image.o main.o options.o \

View file

@ -25,7 +25,7 @@ Features
-------- --------
* Basic image operations like zooming, panning, rotating * Basic image operations like zooming, panning, rotating
* Basic support for animated/multi-frame images * Basic support for animated/multi-frame images (**requires Imlib2 v1.8.0 or above**)
* Thumbnail mode: grid of selectable previews of all images * Thumbnail mode: grid of selectable previews of all images
* Ability to cache thumbnails for fast re-loading * Ability to cache thumbnails for fast re-loading
* Automatically refreshing modified images * Automatically refreshing modified images
@ -76,15 +76,6 @@ The following dependencies are optional:
* `libexif`: Used for auto-orientation and exif thumbnails. * `libexif`: Used for auto-orientation and exif thumbnails.
Disable via `HAVE_LIBEXIF=0`. Disable via `HAVE_LIBEXIF=0`.
The following dependencies are only used if your imlib2 version is lower than
v1.8.0. If your imlib2 version is v1.8.0 (or above) then the following
dependencies are unused and won't be built (even if you enable it explicitly).
* `giflib`: Used for animated gif playback. Disabled via `HAVE_LIBGIF=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 Please make sure to install the corresponding development packages in case that
you want to build nsxiv on a distribution with separate runtime and development you want to build nsxiv on a distribution with separate runtime and development
packages (e.g. \*-dev on Debian). packages (e.g. \*-dev on Debian).

View file

@ -16,11 +16,6 @@ HAVE_INOTIFY = $(OPT_DEP_DEFAULT)
HAVE_LIBFONTS = $(OPT_DEP_DEFAULT) HAVE_LIBFONTS = $(OPT_DEP_DEFAULT)
HAVE_LIBEXIF = $(OPT_DEP_DEFAULT) HAVE_LIBEXIF = $(OPT_DEP_DEFAULT)
# unused if imlib2 version is 1.8.0 or higher.
# these options will be removed eventually.
HAVE_LIBGIF = $(OPT_DEP_DEFAULT)
HAVE_LIBWEBP = $(OPT_DEP_DEFAULT)
# CFLAGS, any additional compiler flags goes here # CFLAGS, any additional compiler flags goes here
CFLAGS = -Wall -pedantic -O2 -DNDEBUG CFLAGS = -Wall -pedantic -O2 -DNDEBUG
# Uncomment for a debug build using gcc/clang # Uncomment for a debug build using gcc/clang

View file

@ -6,6 +6,6 @@ pipeline:
commands: | commands: |
apk add --no-cache build-base cppcheck clang-extra-tools git \ apk add --no-cache build-base cppcheck clang-extra-tools git \
imlib2-dev xorgproto \ imlib2-dev xorgproto \
libxft-dev libexif-dev giflib-dev libwebp-dev >/dev/null libxft-dev libexif-dev >/dev/null
make config.h version.h make config.h version.h
./etc/woodpecker/analysis.sh ./etc/woodpecker/analysis.sh

View file

@ -9,7 +9,7 @@ pipeline:
commands: | commands: |
apk add --no-cache \ apk add --no-cache \
imlib2 imlib2-dev xorgproto \ imlib2 imlib2-dev xorgproto \
libxft libxft-dev libexif libexif-dev giflib giflib-dev libwebp libwebp-dev \ libxft libxft-dev libexif libexif-dev \
gcc clang llvm llvm-dev build-base wget ca-certificates bc >/dev/null gcc clang llvm llvm-dev build-base wget ca-certificates bc >/dev/null
wget "https://github.com/TinyCC/tinycc/archive/$TCC_SHA.tar.gz" >/dev/null wget "https://github.com/TinyCC/tinycc/archive/$TCC_SHA.tar.gz" >/dev/null
tar xzf "$TCC_SHA.tar.gz" >/dev/null tar xzf "$TCC_SHA.tar.gz" >/dev/null
@ -26,5 +26,5 @@ pipeline:
# full-build with gcc and clang # # full-build with gcc and clang #
build "1" "full" build "1" "full"
# ensure minimal-build works without opt deps installed # ensure minimal-build works without opt deps installed
apk del libxft libxft-dev libexif libexif-dev giflib giflib-dev libwebp libwebp-dev >/dev/null apk del libxft libxft-dev libexif libexif-dev >/dev/null
build "0" "minimal" build "0" "minimal"

298
image.c
View file

@ -33,18 +33,6 @@
#include <libexif/exif-data.h> #include <libexif/exif-data.h>
#endif #endif
#if HAVE_LIBGIF && !HAVE_IMLIB2_MULTI_FRAME
#include <gif_lib.h>
enum { DEF_GIF_DELAY = 75 };
#endif
#if HAVE_LIBWEBP && !HAVE_IMLIB2_MULTI_FRAME
#include <stdio.h>
#include <webp/decode.h>
#include <webp/demux.h>
enum { DEF_WEBP_DELAY = 75 };
#endif
#if HAVE_IMLIB2_MULTI_FRAME #if HAVE_IMLIB2_MULTI_FRAME
enum { DEF_ANIM_DELAY = 75 }; enum { DEF_ANIM_DELAY = 75 };
#endif #endif
@ -144,7 +132,7 @@ void exif_auto_orientate(const fileinfo_t *file)
} }
#endif #endif
#if HAVE_LIBGIF || HAVE_LIBWEBP || HAVE_IMLIB2_MULTI_FRAME #if HAVE_IMLIB2_MULTI_FRAME
static void img_multiframe_context_set(img_t *img) static void img_multiframe_context_set(img_t *img)
{ {
if (img->multi.cnt > 1) { if (img->multi.cnt > 1) {
@ -157,283 +145,7 @@ static void img_multiframe_context_set(img_t *img)
imlib_context_set_image(img->im); imlib_context_set_image(img->im);
} }
#endif
#if (HAVE_LIBGIF || HAVE_LIBWEBP) && !HAVE_IMLIB2_MULTI_FRAME
static void img_multiframe_deprecation_notice(void)
{
static bool warned;
if (!warned) {
error(0, 0, "\n"
"################################################################\n"
"# DEPRECATION NOTICE #\n"
"################################################################\n"
"# Internal multi-frame gif and webp loaders are deprecated and #\n"
"# will be removed soon. Please upgrade to Imlib2 v1.8.0 for #\n"
"# multi-frame/animated image support. #\n"
"################################################################");
warned = true;
}
}
#endif
#if HAVE_LIBGIF && !HAVE_IMLIB2_MULTI_FRAME
static bool img_load_gif(img_t *img, const fileinfo_t *file)
{
GifFileType *gif;
GifRowType *rows = NULL;
GifRecordType rec;
ColorMapObject *cmap;
uint32_t bgpixel = 0, *data, *ptr;
uint32_t *prev_frame = NULL;
Imlib_Image im;
int i, j, bg, r, g, b;
int x, y, w, h, sw, sh;
int px, py, pw, ph;
int intoffset[] = { 0, 4, 2, 1 };
int intjump[] = { 8, 8, 4, 2 };
int transp = -1;
unsigned int disposal = 0, prev_disposal = 0;
unsigned int delay = 0;
bool err = false;
multi_img_t *m = &img->multi;
img_multiframe_deprecation_notice();
#if defined(GIFLIB_MAJOR) && GIFLIB_MAJOR >= 5
gif = DGifOpenFileName(file->path, NULL);
#else
gif = DGifOpenFileName(file->path);
#endif
if (gif == NULL) {
error(0, 0, "%s: Error opening gif image", file->name);
return false;
}
bg = gif->SBackGroundColor;
sw = gif->SWidth;
sh = gif->SHeight;
px = py = pw = ph = 0;
m->length = m->cnt = m->sel = 0;
do {
if (DGifGetRecordType(gif, &rec) == GIF_ERROR) {
err = true;
break;
}
if (rec == EXTENSION_RECORD_TYPE) {
int ext_code;
GifByteType *ext = NULL;
DGifGetExtension(gif, &ext_code, &ext);
while (ext) {
if (ext_code == GRAPHICS_EXT_FUNC_CODE) {
if (ext[1] & 1)
transp = (int)ext[4];
else
transp = -1;
delay = 10 * ((unsigned int)ext[3] << 8 | (unsigned int)ext[2]);
disposal = (unsigned int)ext[1] >> 2 & 0x7;
}
ext = NULL;
DGifGetExtensionNext(gif, &ext);
}
} else if (rec == IMAGE_DESC_RECORD_TYPE) {
if (DGifGetImageDesc(gif) == GIF_ERROR) {
err = true;
break;
}
x = gif->Image.Left;
y = gif->Image.Top;
w = gif->Image.Width;
h = gif->Image.Height;
rows = emalloc(h * sizeof(*rows));
for (i = 0; i < h; i++)
rows[i] = emalloc(w * sizeof(*rows[i]));
if (gif->Image.Interlace) {
for (i = 0; i < 4; i++) {
for (j = intoffset[i]; j < h; j += intjump[i])
DGifGetLine(gif, rows[j], w);
}
} else {
for (i = 0; i < h; i++)
DGifGetLine(gif, rows[i], w);
}
ptr = data = emalloc(sw * sh * sizeof(*data));
cmap = gif->Image.ColorMap ? gif->Image.ColorMap : gif->SColorMap;
/* if bg > cmap->ColorCount, it is transparent black already */
if (cmap && bg >= 0 && bg < cmap->ColorCount) {
r = cmap->Colors[bg].Red;
g = cmap->Colors[bg].Green;
b = cmap->Colors[bg].Blue;
bgpixel = 0x00ffffff & (r << 16 | g << 8 | b);
}
for (i = 0; i < sh; i++) {
for (j = 0; j < sw; j++) {
if (i < y || i >= y + h || j < x || j >= x + w ||
rows[i - y][j - x] == transp)
{
if (prev_frame != NULL &&
(prev_disposal != 2 || i < py || i >= py + ph ||
j < px || j >= px + pw))
{
*ptr = prev_frame[i * sw + j];
} else {
*ptr = bgpixel;
}
} else {
assert(cmap != NULL);
r = cmap->Colors[rows[i - y][j - x]].Red;
g = cmap->Colors[rows[i - y][j - x]].Green;
b = cmap->Colors[rows[i - y][j - x]].Blue;
*ptr = 0xffu << 24 | r << 16 | g << 8 | b;
}
ptr++;
}
}
im = imlib_create_image_using_copied_data(sw, sh, data);
for (i = 0; i < h; i++)
free(rows[i]);
free(rows);
free(data);
if (im == NULL) {
err = true;
break;
}
imlib_context_set_image(im);
imlib_image_set_format("gif");
if (transp >= 0)
imlib_image_set_has_alpha(1);
if (disposal != 3)
prev_frame = imlib_image_get_data_for_reading_only();
prev_disposal = disposal;
px = x, py = y, pw = w, ph = h;
assert(m->cnt <= m->cap);
if (m->cnt == m->cap) {
m->cap = m->cap == 0 ? 16 : (m->cap * 2);
m->frames = erealloc(m->frames, m->cap * sizeof(*m->frames));
}
m->frames[m->cnt].im = im;
delay = m->framedelay > 0 ? m->framedelay : delay;
m->frames[m->cnt].delay = delay > 0 ? delay : DEF_GIF_DELAY;
m->length += m->frames[m->cnt].delay;
m->cnt++;
}
} while (rec != TERMINATE_RECORD_TYPE);
#if defined(GIFLIB_MAJOR) && GIFLIB_MAJOR >= 5 && GIFLIB_MINOR >= 1
DGifCloseFile(gif, NULL);
#else
DGifCloseFile(gif);
#endif
if (err && (file->flags & FF_WARN))
error(0, 0, "%s: Corrupted gif file", file->name);
img_multiframe_context_set(img);
return !err;
}
#endif /* HAVE_LIBGIF */
#if HAVE_LIBWEBP && !HAVE_IMLIB2_MULTI_FRAME
static bool img_load_webp(img_t *img, const fileinfo_t *file)
{
FILE *webp_file;
WebPData data;
Imlib_Image im = NULL;
struct WebPAnimDecoderOptions opts;
WebPAnimDecoder *dec = NULL;
struct WebPAnimInfo info;
unsigned char *buf = NULL, *bytes = NULL;
int ts;
const WebPDemuxer *demux;
WebPIterator iter;
unsigned long flags;
unsigned int delay;
bool err = false;
multi_img_t *m = &img->multi;
img_multiframe_deprecation_notice();
if ((webp_file = fopen(file->path, "rb")) == NULL) {
error(0, errno, "%s: Error opening webp image", file->name);
return false;
}
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)) {
error(0, 0, "%s: Error reading webp image", file->name);
goto fail;
}
data.bytes = bytes;
/* Setup the WebP Animation Decoder */
if ((err = !WebPAnimDecoderOptionsInit(&opts))) {
error(0, 0, "%s: WebP library version mismatch", file->name);
goto fail;
}
opts.color_mode = MODE_BGRA;
/* NOTE: Multi-threaded decoding may cause problems on some system */
opts.use_threads = true;
dec = WebPAnimDecoderNew(&data, &opts);
if ((err = (dec == NULL) || !WebPAnimDecoderGetInfo(dec, &info))) {
error(0, 0, "%s: WebP parsing or memory error (file is corrupt?)", file->name);
goto fail;
}
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 (info.frame_count > m->cap) {
m->cap = info.frame_count;
m->frames = erealloc(m->frames, m->cap * sizeof(*m->frames));
}
/* Load and decode frames (also works on images with only 1 frame) */
m->length = m->cnt = m->sel = 0;
while (WebPAnimDecoderGetNext(dec, &buf, &ts)) {
im = imlib_create_image_using_copied_data(info.canvas_width, info.canvas_height,
(uint32_t *)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, m->cnt + 1, &iter);
imlib_image_set_has_alpha((flags & ALPHA_FLAG) == ALPHA_FLAG);
/* Store info for this frame */
m->frames[m->cnt].im = im;
delay = iter.duration > 0 ? iter.duration : DEF_WEBP_DELAY;
m->frames[m->cnt].delay = delay;
m->length += m->frames[m->cnt].delay;
m->cnt++;
}
WebPDemuxReleaseIterator(&iter);
img_multiframe_context_set(img);
fail:
if (dec != NULL)
WebPAnimDecoderDelete(dec);
free(bytes);
fclose(webp_file);
return !err;
}
#endif /* HAVE_LIBWEBP */
#if HAVE_IMLIB2_MULTI_FRAME
static void img_area_clear(int x, int y, int w, int h) static void img_area_clear(int x, int y, int w, int h)
{ {
assert(x >= 0 && y >= 0); assert(x >= 0 && y >= 0);
@ -596,14 +308,6 @@ bool img_load(img_t *img, const fileinfo_t *file)
#endif #endif
if ((fmt = imlib_image_format()) != NULL) { /* NOLINT: fmt might be unused, not worth fixing */ if ((fmt = imlib_image_format()) != NULL) { /* NOLINT: fmt might be unused, not worth fixing */
#if HAVE_LIBGIF && !HAVE_IMLIB2_MULTI_FRAME
if (STREQ(fmt, "gif"))
img_load_gif(img, file);
#endif
#if HAVE_LIBWEBP && !HAVE_IMLIB2_MULTI_FRAME
if (STREQ(fmt, "webp"))
img_load_webp(img, file);
#endif
#if HAVE_LIBEXIF && defined(IMLIB2_VERSION) #if HAVE_LIBEXIF && defined(IMLIB2_VERSION)
if (!STREQ(fmt, "jpeg") && !STREQ(fmt, "jpg")) if (!STREQ(fmt, "jpeg") && !STREQ(fmt, "jpg"))
exif_auto_orientate(file); exif_auto_orientate(file);

View file

@ -62,13 +62,6 @@ static void print_version(void)
#endif #endif
#if HAVE_IMLIB2_MULTI_FRAME #if HAVE_IMLIB2_MULTI_FRAME
"+multiframe " "+multiframe "
#else
#if HAVE_LIBGIF
"+giflib "
#endif
#if HAVE_LIBWEBP
"+libwebp "
#endif
#endif #endif
"\n", stdout); "\n", stdout);
} }