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:
parent
1fc28278b5
commit
e1b851c488
|
@ -43,11 +43,11 @@ jobs:
|
|||
run: |
|
||||
brew update
|
||||
# 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
|
||||
run: |
|
||||
# libinotify-kqueue isn't available on homebrew
|
||||
make clean && make -s OPT_DEP_DEFAULT=1 HAVE_INOTIFY=0
|
||||
# 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
|
||||
|
|
10
Makefile
10
Makefile
|
@ -8,20 +8,14 @@ lib_fonts_0 =
|
|||
lib_fonts_1 = -lXft -lfontconfig
|
||||
lib_exif_0 =
|
||||
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 \
|
||||
-DHAVE_LIBGIF=$(HAVE_LIBGIF) -DHAVE_LIBEXIF=$(HAVE_LIBEXIF) \
|
||||
-DHAVE_LIBWEBP=$(HAVE_LIBWEBP) -DHAVE_LIBFONTS=$(HAVE_LIBFONTS) \
|
||||
-DHAVE_LIBEXIF=$(HAVE_LIBEXIF) -DHAVE_LIBFONTS=$(HAVE_LIBFONTS) \
|
||||
-DHAVE_INOTIFY=$(HAVE_INOTIFY) $(inc_fonts_$(HAVE_LIBFONTS)) \
|
||||
$(CPPFLAGS)
|
||||
|
||||
nsxiv_ldlibs = -lImlib2 -lX11 \
|
||||
$(lib_exif_$(HAVE_LIBEXIF)) $(lib_gif_$(HAVE_LIBGIF)) \
|
||||
$(lib_webp_$(HAVE_LIBWEBP)) $(lib_fonts_$(HAVE_LIBFONTS)) \
|
||||
$(lib_exif_$(HAVE_LIBEXIF)) $(lib_fonts_$(HAVE_LIBFONTS)) \
|
||||
$(LDLIBS)
|
||||
|
||||
objs = autoreload.o commands.o image.o main.o options.o \
|
||||
|
|
11
README.md
11
README.md
|
@ -25,7 +25,7 @@ Features
|
|||
--------
|
||||
|
||||
* 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
|
||||
* Ability to cache thumbnails for fast re-loading
|
||||
* Automatically refreshing modified images
|
||||
|
@ -76,15 +76,6 @@ The following dependencies are optional:
|
|||
* `libexif`: Used for auto-orientation and exif thumbnails.
|
||||
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
|
||||
you want to build nsxiv on a distribution with separate runtime and development
|
||||
packages (e.g. \*-dev on Debian).
|
||||
|
|
|
@ -16,11 +16,6 @@ HAVE_INOTIFY = $(OPT_DEP_DEFAULT)
|
|||
HAVE_LIBFONTS = $(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 = -Wall -pedantic -O2 -DNDEBUG
|
||||
# Uncomment for a debug build using gcc/clang
|
||||
|
|
|
@ -6,6 +6,6 @@ pipeline:
|
|||
commands: |
|
||||
apk add --no-cache build-base cppcheck clang-extra-tools git \
|
||||
imlib2-dev xorgproto \
|
||||
libxft-dev libexif-dev giflib-dev libwebp-dev >/dev/null
|
||||
libxft-dev libexif-dev >/dev/null
|
||||
make config.h version.h
|
||||
./etc/woodpecker/analysis.sh
|
||||
|
|
|
@ -9,7 +9,7 @@ pipeline:
|
|||
commands: |
|
||||
apk add --no-cache \
|
||||
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
|
||||
wget "https://github.com/TinyCC/tinycc/archive/$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 #
|
||||
build "1" "full"
|
||||
# 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"
|
||||
|
|
298
image.c
298
image.c
|
@ -33,18 +33,6 @@
|
|||
#include <libexif/exif-data.h>
|
||||
#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
|
||||
enum { DEF_ANIM_DELAY = 75 };
|
||||
#endif
|
||||
|
@ -144,7 +132,7 @@ void exif_auto_orientate(const fileinfo_t *file)
|
|||
}
|
||||
#endif
|
||||
|
||||
#if HAVE_LIBGIF || HAVE_LIBWEBP || HAVE_IMLIB2_MULTI_FRAME
|
||||
#if HAVE_IMLIB2_MULTI_FRAME
|
||||
static void img_multiframe_context_set(img_t *img)
|
||||
{
|
||||
if (img->multi.cnt > 1) {
|
||||
|
@ -157,283 +145,7 @@ static void img_multiframe_context_set(img_t *img)
|
|||
|
||||
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)
|
||||
{
|
||||
assert(x >= 0 && y >= 0);
|
||||
|
@ -596,14 +308,6 @@ bool img_load(img_t *img, const fileinfo_t *file)
|
|||
#endif
|
||||
|
||||
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 (!STREQ(fmt, "jpeg") && !STREQ(fmt, "jpg"))
|
||||
exif_auto_orientate(file);
|
||||
|
|
Loading…
Reference in New Issue