Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package imv for openSUSE:Factory checked in at 2024-02-21 17:57:48 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/imv (Old) and /work/SRC/openSUSE:Factory/.imv.new.1706 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "imv" Wed Feb 21 17:57:48 2024 rev:8 rq:1148402 version:4.5.0 Changes: -------- --- /work/SRC/openSUSE:Factory/imv/imv.changes 2023-01-21 19:10:26.968917666 +0100 +++ /work/SRC/openSUSE:Factory/.imv.new.1706/imv.changes 2024-02-21 17:57:56.230602868 +0100 @@ -1,0 +2,13 @@ +Wed Feb 21 06:30:43 UTC 2024 - Michael Vetter <[email protected]> + +- Update to 4.5.0: + * Add new jpgxl backend + * Added -W and -H arguments to configure initial dimensions + * Fix utf8 in window titles + * Fix some animated gifs showing as still images + * Fix several crashes + * Fixed new build warnings + * Limit libnsgif to <1.0.0 to fix build + * Update mime types + +------------------------------------------------------------------- Old: ---- v4.4.0.tar.gz New: ---- v4.5.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ imv.spec ++++++ --- /var/tmp/diff_new_pack.Aox9qu/_old 2024-02-21 17:57:56.682619213 +0100 +++ /var/tmp/diff_new_pack.Aox9qu/_new 2024-02-21 17:57:56.682619213 +0100 @@ -1,7 +1,7 @@ # # spec file for package imv # -# Copyright (c) 2023 SUSE LLC +# Copyright (c) 2024 SUSE LLC # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -17,7 +17,7 @@ Name: imv -Version: 4.4.0 +Version: 4.5.0 Release: 0 Summary: Image viewer for X11/Wayland License: GPL-2.0-or-later AND MIT @@ -36,6 +36,7 @@ BuildRequires: pkgconfig(fontconfig) BuildRequires: pkgconfig(libheif) BuildRequires: pkgconfig(libjpeg) +BuildRequires: pkgconfig(libjxl) BuildRequires: pkgconfig(libpng16) BuildRequires: pkgconfig(librsvg-2.0) >= 2.44 BuildRequires: pkgconfig(libtiff-4) ++++++ v4.4.0.tar.gz -> v4.5.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/imv-v4.4.0/.builds/archlinux.yml new/imv-v4.5.0/.builds/archlinux.yml --- old/imv-v4.4.0/.builds/archlinux.yml 2023-01-18 23:20:52.000000000 +0100 +++ new/imv-v4.5.0/.builds/archlinux.yml 2024-02-20 23:30:06.000000000 +0100 @@ -10,7 +10,7 @@ - libheif - libinih - libjpeg-turbo - - libnsgif + - libjxl - libpng - librsvg - libtiff @@ -24,9 +24,10 @@ sources: - https://git.sr.ht/~exec64/imv tasks: + # arch ships libnsgif 1.0.0 which is too new - gcc: | - CC=gcc meson imv build_gcc -D auto_features=enabled + CC=gcc meson imv build_gcc -D auto_features=enabled -D libnsgif=disabled CC=gcc ninja -C build_gcc test - clang: | - CC=clang meson imv build_clang -D auto_features=enabled + CC=clang meson imv build_clang -D auto_features=enabled -D libnsgif=disabled CC=clang ninja -C build_clang test diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/imv-v4.4.0/.builds/debian.yml new/imv-v4.5.0/.builds/debian.yml --- old/imv-v4.4.0/.builds/debian.yml 2023-01-18 23:20:52.000000000 +0100 +++ new/imv-v4.5.0/.builds/debian.yml 2024-02-20 23:30:06.000000000 +0100 @@ -9,6 +9,7 @@ - libheif-dev - libicu-dev - libinih-dev + - libjxl-dev - libpango1.0-dev - libpng-dev - librsvg2-dev @@ -24,16 +25,10 @@ sources: - https://git.sr.ht/~exec64/imv tasks: - - dummy: | - true -#FIXME: -# the old meson package in debian has a bug and crashes with -# our meson.build; re-enable this once debian packages a version -# newer than 0.49.2 - # libnsgif isn't packaged by debian -# - gcc: | -# CC=gcc meson imv build_gcc -D auto_features=enabled -D libnsgif=disabled -# CC=gcc ninja -C build_gcc test -# - clang: | -# CC=clang meson imv build_clang -D auto_features=enabled -D libnsgif=disabled -# CC=clang ninja -C build_clang test + # libnsgif isn't packaged by debian + - gcc: | + CC=gcc meson imv build_gcc -D auto_features=enabled -D libnsgif=disabled + CC=gcc ninja -C build_gcc test + - clang: | + CC=clang meson imv build_clang -D auto_features=enabled -D libnsgif=disabled + CC=clang ninja -C build_clang test diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/imv-v4.4.0/.builds/fedora.yml new/imv-v4.5.0/.builds/fedora.yml --- old/imv-v4.4.0/.builds/fedora.yml 2023-01-18 23:20:52.000000000 +0100 +++ new/imv-v4.5.0/.builds/fedora.yml 2024-02-20 23:30:06.000000000 +0100 @@ -6,7 +6,9 @@ - inih - libX11-devel - libcmocka-devel + - libheif-devel - libicu-devel + - libjxl-devel - libpng-devel - librsvg2-devel - libtiff-devel @@ -23,11 +25,10 @@ sources: - https://git.sr.ht/~exec64/imv tasks: - # libheif ins't packaged by fedora # libnsgif isn't packaged by fedora - gcc: | - CC=gcc meson imv build_gcc -D auto_features=enabled -D libheif=disabled -D libnsgif=disabled + CC=gcc meson imv build_gcc -D auto_features=enabled -D libnsgif=disabled CC=gcc ninja -C build_gcc test - clang: | - CC=clang meson imv build_clang -D auto_features=enabled -D libheif=disabled -D libnsgif=disabled + CC=clang meson imv build_clang -D auto_features=enabled -D libnsgif=disabled CC=clang ninja -C build_clang test diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/imv-v4.4.0/.builds/freebsd.yml new/imv-v4.5.0/.builds/freebsd.yml --- old/imv-v4.4.0/.builds/freebsd.yml 2023-01-18 23:20:52.000000000 +0100 +++ new/imv-v4.5.0/.builds/freebsd.yml 2024-02-20 23:30:06.000000000 +0100 @@ -7,7 +7,7 @@ - graphics/libGLU - graphics/libheif - graphics/libjpeg-turbo - - graphics/libnsgif + - graphics/libjxl - graphics/librsvg2-rust - graphics/png - graphics/tiff @@ -19,6 +19,7 @@ sources: - https://git.sr.ht/~exec64/imv tasks: + # freebsd ships libnsgif 1.0.0 which is too new - meson: | - meson imv build -D auto_features=enabled -D c_link_args='-L/usr/local/lib' + meson imv build -D auto_features=enabled -D libnsgif=disabled -D c_link_args='-L/usr/local/lib' ninja -C build test diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/imv-v4.4.0/.builds/ubuntu.yml new/imv-v4.5.0/.builds/ubuntu.yml --- old/imv-v4.4.0/.builds/ubuntu.yml 2023-01-18 23:20:52.000000000 +0100 +++ new/imv-v4.5.0/.builds/ubuntu.yml 2024-02-20 23:30:06.000000000 +0100 @@ -25,9 +25,10 @@ - https://git.sr.ht/~exec64/imv tasks: # libnsgif isn't packaged by ubuntu + # libjxl-dev isn't packaged by ubuntu lts - gcc: | - CC=gcc meson imv build_gcc -D auto_features=enabled -D libnsgif=disabled + CC=gcc meson imv build_gcc -D auto_features=enabled -D libnsgif=disabled -D libjxl=disabled CC=gcc ninja -C build_gcc test - clang: | - CC=clang meson imv build_clang -D auto_features=enabled -D libnsgif=disabled + CC=clang meson imv build_clang -D auto_features=enabled -D libnsgif=disabled -D libjxl=disabled CC=clang ninja -C build_clang test diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/imv-v4.4.0/AUTHORS new/imv-v4.5.0/AUTHORS --- old/imv-v4.4.0/AUTHORS 2023-01-18 23:20:52.000000000 +0100 +++ new/imv-v4.5.0/AUTHORS 2024-02-20 23:30:06.000000000 +0100 @@ -8,6 +8,7 @@ * Jose Diez * Kenneth Hanley * Julian Heinzel + * Fabio Henrique * Hannes Körber * Aleksandra Kosiacka * Michal Koutenský diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/imv-v4.4.0/CHANGELOG new/imv-v4.5.0/CHANGELOG --- old/imv-v4.4.0/CHANGELOG 2023-01-18 23:20:52.000000000 +0100 +++ new/imv-v4.5.0/CHANGELOG 2024-02-20 23:30:06.000000000 +0100 @@ -1,6 +1,18 @@ imv Changelog ============= +v4.5.0 - 2024-02-20 +------------------- + +* Add new jpgxl backend +* Added -W and -H arguments to configure initial dimensions +* Fix utf8 in window titles +* Fix some animated gifs showing as still images +* Fix several crashes +* Fixed new build warnings +* Limit libnsgif to <1.0.0 to fix build +* Update mime types + v4.4.0 - 2023-01-18 ------------------- diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/imv-v4.4.0/README.md new/imv-v4.5.0/README.md --- old/imv-v4.4.0/README.md 2023-01-18 23:20:52.000000000 +0100 +++ new/imv-v4.5.0/README.md 2024-02-20 23:30:06.000000000 +0100 @@ -139,6 +139,7 @@ | librsvg | >=v2.44 | Optional. Provides SVG support. | | libnsgif | | Optional. Provides animated GIF support. | | libheif | | Optional. Provides HEIF support. | +| libjxl | | Optional. Provides JPEGXL support. | Dependencies are determined by which backends and window systems are enabled when building `imv`. You can find a summary of which backends are available diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/imv-v4.4.0/doc/imv.1.txt new/imv-v4.5.0/doc/imv.1.txt --- old/imv-v4.4.0/doc/imv.1.txt 2023-01-18 23:20:52.000000000 +0100 +++ new/imv-v4.5.0/doc/imv.1.txt 2024-02-20 23:30:06.000000000 +0100 @@ -76,6 +76,12 @@ *-x*:: Disable looping of input paths. +*-W* <width>:: + Initial width of window. + +*-H* <height>:: + Initial height of window. + Commands -------- diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/imv-v4.4.0/files/imv-dir.desktop new/imv-v4.5.0/files/imv-dir.desktop --- old/imv-v4.4.0/files/imv-dir.desktop 2023-01-18 23:20:52.000000000 +0100 +++ new/imv-v4.5.0/files/imv-dir.desktop 2024-02-20 23:30:06.000000000 +0100 @@ -9,6 +9,6 @@ Terminal=false Type=Application Categories=Graphics;2DGraphics;Viewer; -MimeType=image/bmp;image/gif;image/jpeg;image/jpg;image/pjpeg;image/png;image/tiff;image/x-bmp;image/x-pcx;image/x-png;image/x-portable-anymap;image/x-portable-bitmap;image/x-portable-graymap;image/x-portable-pixmap;image/x-tga;image/x-xbitmap; +MimeType=image/bmp;image/gif;image/jpeg;image/jpg;image/pjpeg;image/png;image/tiff;image/x-bmp;image/x-pcx;image/x-png;image/x-portable-anymap;image/x-portable-bitmap;image/x-portable-graymap;image/x-portable-pixmap;image/x-tga;image/x-xbitmap;image/heif;image/avif Icon=multimedia-photo-viewer Keywords=photo;picture; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/imv-v4.4.0/files/imv.desktop new/imv-v4.5.0/files/imv.desktop --- old/imv-v4.4.0/files/imv.desktop 2023-01-18 23:20:52.000000000 +0100 +++ new/imv-v4.5.0/files/imv.desktop 2024-02-20 23:30:06.000000000 +0100 @@ -8,7 +8,7 @@ Terminal=false Type=Application Categories=Graphics;2DGraphics;Viewer; -MimeType=image/bmp;image/gif;image/jpeg;image/jpg;image/pjpeg;image/png;image/tiff;image/x-bmp;image/x-pcx;image/x-png;image/x-portable-anymap;image/x-portable-bitmap;image/x-portable-graymap;image/x-portable-pixmap;image/x-tga;image/x-xbitmap;image/heif +MimeType=image/bmp;image/gif;image/jpeg;image/jpg;image/pjpeg;image/png;image/tiff;image/x-bmp;image/x-pcx;image/x-png;image/x-portable-anymap;image/x-portable-bitmap;image/x-portable-graymap;image/x-portable-pixmap;image/x-tga;image/x-xbitmap;image/heif;image/avif Name[en_US]=imv Icon=multimedia-photo-viewer Keywords=photo;picture; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/imv-v4.4.0/meson.build new/imv-v4.5.0/meson.build --- old/imv-v4.4.0/meson.build 2023-01-18 23:20:52.000000000 +0100 +++ new/imv-v4.5.0/meson.build 2024-02-20 23:30:06.000000000 +0100 @@ -1,7 +1,7 @@ project( 'imv', ['c'], - version: '4.4.0', + version: '4.5.0', license: 'MIT', meson_version: '>= 0.47', default_options: ['buildtype=debugoptimized', 'c_std=c99'], @@ -125,8 +125,9 @@ ['libpng', 'dependency', 'libpng', []], ['libjpeg', 'dependency', 'libturbojpeg', []], ['librsvg', 'dependency', 'librsvg-2.0', '>= 2.44'], - ['libnsgif', 'dependency', 'libnsgif', []], + ['libnsgif', 'dependency', 'libnsgif', '< 1.0.0'], ['libheif', 'dependency', 'libheif', []], + ['libjxl', 'dependency', 'libjxl', []], ] _backend_name = backend[0] _dep_type = backend[1] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/imv-v4.4.0/meson_options.txt new/imv-v4.5.0/meson_options.txt --- old/imv-v4.4.0/meson_options.txt 2023-01-18 23:20:52.000000000 +0100 +++ new/imv-v4.5.0/meson_options.txt 2024-02-20 23:30:06.000000000 +0100 @@ -89,3 +89,11 @@ type : 'feature', description : 'provides: heif' ) + +# libjxl https://jpeg.org/jpegxl/ +# depends: brotlidec, brotlienc, highway, lcms2 +# license: modified bsd +option('libjxl', + type : 'feature', + description : 'provides: jxl' +) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/imv-v4.4.0/src/backend_freeimage.c new/imv-v4.5.0/src/backend_freeimage.c --- old/imv-v4.4.0/src/backend_freeimage.c 2023-01-18 23:20:52.000000000 +0100 +++ new/imv-v4.5.0/src/backend_freeimage.c 2024-02-20 23:30:06.000000000 +0100 @@ -139,7 +139,8 @@ FreeImage_GetMetadata(FIMD_ANIMATION, frame, "FrameTime", &tag); if (FreeImage_GetTagValue(tag)) { *frametime = *(int*)FreeImage_GetTagValue(tag); - } else { + } + if (*frametime == 0) { *frametime = 100; /* default value for gifs */ } bmp = FreeImage_ConvertTo24Bits(frame); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/imv-v4.4.0/src/backend_libjxl.c new/imv-v4.5.0/src/backend_libjxl.c --- old/imv-v4.4.0/src/backend_libjxl.c 1970-01-01 01:00:00.000000000 +0100 +++ new/imv-v4.5.0/src/backend_libjxl.c 2024-02-20 23:30:06.000000000 +0100 @@ -0,0 +1,282 @@ +#include "backend.h" +#include "bitmap.h" +#include "image.h" +#include "log.h" +#include "source.h" +#include "source_private.h" + +#include <fcntl.h> +#include <stdlib.h> +#include <string.h> +#include <sys/mman.h> +#include <unistd.h> +#include <limits.h> + +#include <jxl/decode.h> + +#define BACKEND_NB_CHANNELS 4 +#define BACKEND_DEFAULT_FRAMETIME 100 +#define BACKEND_NB_ALLOC_FRAMES 64 + +struct jxl_frame { + void *data; + int frametime; +}; + +struct private { + void *data; + off_t data_len; + int owns_data; + + int width; + int height; + int is_animation; + + struct jxl_frame *frames; + int nb_allocd_frames; + int cur_frame; + int nb_frames; +}; + +static void free_private(void *raw_pvt) +{ + if (!raw_pvt) + return; + + struct private *pvt = raw_pvt; + + if (pvt->owns_data) { + if (pvt->data) + munmap(pvt->data, pvt->data_len); + } + + if (pvt->frames) { + for (int i = 0; i != pvt->nb_allocd_frames; ++i) + if (pvt->frames[i].data) + free(pvt->frames[i].data); + + free(pvt->frames); + } + + free(pvt); +} + +static void push_frame(struct private *pvt, struct imv_image **img, int *frametime) +{ + struct imv_bitmap *bmp = malloc(sizeof *bmp); + size_t sz = pvt->width * pvt->height * BACKEND_NB_CHANNELS; + + bmp->width = pvt->width; + bmp->height = pvt->height; + bmp->format = IMV_ABGR; + bmp->data = malloc(sz); + memcpy(bmp->data, pvt->frames[pvt->cur_frame].data, sz); + + *img = imv_image_create_from_bitmap(bmp); + *frametime = pvt->frames[pvt->cur_frame].frametime; +} + +static void first_frame(void *raw_pvt, struct imv_image **img, int *frametime) +{ + *img = NULL; + *frametime = 0; + + imv_log(IMV_DEBUG, "libjxl: first_frame called\n"); + + struct private *pvt = raw_pvt; + JxlDecoder *jxld = JxlDecoderCreate(NULL); + if (JxlDecoderSubscribeEvents(jxld, JXL_DEC_BASIC_INFO | JXL_DEC_FULL_IMAGE) != JXL_DEC_SUCCESS) { + imv_log(IMV_ERROR, "libjxl: decoder failed to subscribe to events\n"); + goto end; + } + + JxlBasicInfo info; + JxlDecoderStatus sts = JxlDecoderSetInput(jxld, pvt->data, pvt->data_len); + if (sts != JXL_DEC_SUCCESS) { + imv_log(IMV_ERROR, "libjxl: decoder failed to set input\n"); + goto end; + } + JxlDecoderCloseInput(jxld); + + pvt->nb_frames = 0; + pvt->cur_frame = 0; + + JxlPixelFormat fmt = { BACKEND_NB_CHANNELS, JXL_TYPE_UINT8, JXL_NATIVE_ENDIAN, 0 }; + pvt->nb_allocd_frames = BACKEND_NB_ALLOC_FRAMES; + pvt->frames = calloc(pvt->nb_allocd_frames, sizeof *pvt->frames); + do { + sts = JxlDecoderProcessInput(jxld); + + switch (sts) { + case JXL_DEC_SUCCESS: + break; + case JXL_DEC_ERROR: + imv_log(IMV_ERROR, "libjxl: decoder error\n"); + goto end; + case JXL_DEC_NEED_MORE_INPUT: + imv_log(IMV_ERROR, "libjxl: decoder needs more input\n"); + goto end; + case JXL_DEC_BASIC_INFO: + if (JxlDecoderGetBasicInfo(jxld, &info) != JXL_DEC_SUCCESS) { + imv_log(IMV_ERROR, "libjxl: decoder failed to get basic info\n"); + goto end; + } + pvt->width = info.xsize; + pvt->height = info.ysize; + pvt->is_animation = info.have_animation == JXL_TRUE ? 1 : 0; + break; + case JXL_DEC_NEED_IMAGE_OUT_BUFFER: + { + size_t buf_sz; + if (JxlDecoderImageOutBufferSize(jxld, &fmt, &buf_sz) != JXL_DEC_SUCCESS) { + imv_log(IMV_ERROR, "libjxl: decoder failed to get output buffer size\n"); + goto end; + } + + if (pvt->nb_frames == pvt->nb_allocd_frames) { + pvt->frames = realloc(pvt->frames, + sizeof(struct jxl_frame) * (pvt->nb_allocd_frames + BACKEND_NB_ALLOC_FRAMES)); + pvt->nb_allocd_frames += BACKEND_NB_ALLOC_FRAMES; + memset(&pvt->frames[pvt->nb_frames], 0, + (pvt->nb_allocd_frames * sizeof(struct jxl_frame)) - (pvt->nb_frames * sizeof(struct jxl_frame))); + } + + struct jxl_frame *cur_frame = &pvt->frames[pvt->nb_frames]; + cur_frame->data = malloc(buf_sz); + + if (pvt->is_animation) { + if (info.animation.tps_numerator && info.animation.tps_denominator) + cur_frame->frametime = info.animation.tps_numerator / info.animation.tps_denominator; + else { + imv_log(IMV_DEBUG, "libjxl: no frametime info for animation, using default\n"); + cur_frame->frametime = BACKEND_DEFAULT_FRAMETIME; + } + } else + cur_frame->frametime = 0; + + if (JxlDecoderSetImageOutBuffer(jxld, &fmt, cur_frame->data, buf_sz) != JXL_DEC_SUCCESS) { + imv_log(IMV_ERROR, "libjxl: JxlDecoderSetImageOutBuffer failed\n"); + goto end; + } + break; + } + case JXL_DEC_FULL_IMAGE: + ++pvt->nb_frames; + continue; + default: + imv_log(IMV_ERROR, "libjxl: unknown decoder status\n"); + goto end; + } + } while (sts != JXL_DEC_SUCCESS); + + push_frame(pvt, img, frametime); + +end: + if (jxld) + JxlDecoderDestroy(jxld); +} + +static void next_frame(void *raw_pvt, struct imv_image **img, int *frametime) +{ + *img = NULL; + *frametime = 0; + + imv_log(IMV_DEBUG, "libjxl: next_frame called\n"); + + struct private *pvt = raw_pvt; + + if (pvt->cur_frame == pvt->nb_frames - 1) + pvt->cur_frame = 0; + else + ++pvt->cur_frame; + + push_frame(pvt, img, frametime); +} + +static const struct imv_source_vtable vtable = { + .load_first_frame = first_frame, + .load_next_frame = next_frame, + .free = free_private, +}; + +static enum backend_result open_memory(void *data, size_t sz, struct imv_source **src) +{ + imv_log(IMV_DEBUG, "libjxl: open_memory called\n"); + + struct private *pvt = calloc(1, sizeof *pvt); + + switch (JxlSignatureCheck(data, sz)) { + case JXL_SIG_NOT_ENOUGH_BYTES: + imv_log(IMV_DEBUG, "libjxl: not enough bytes to read\n"); + case JXL_SIG_INVALID: + imv_log(IMV_DEBUG, "libjxl: valid jxl signature not found\n"); + return BACKEND_UNSUPPORTED; + default: + pvt->owns_data = 0; + pvt->data = data; + pvt->data_len = sz; + break; + } + + *src = imv_source_create(&vtable, pvt); + + return BACKEND_SUCCESS; +} + +static enum backend_result open_path(const char *path, struct imv_source **src) +{ + imv_log(IMV_DEBUG, "libjxl: open_path(%s)\n", path); + + enum backend_result ret = BACKEND_SUCCESS; + struct private *pvt = calloc(1, sizeof *pvt); + + int fd = open(path, O_RDONLY); + if (fd < 0) { + ret = BACKEND_BAD_PATH; + goto end; + } + + pvt->data_len = lseek(fd, 0, SEEK_END); + if (pvt->data_len < 0) { + ret = BACKEND_BAD_PATH; + goto end; + } + pvt->data = mmap(NULL, pvt->data_len, PROT_READ, MAP_PRIVATE, fd, 0); + if (!pvt->data || pvt->data == MAP_FAILED) { + imv_log(IMV_ERROR, "libjxl: failed to map file into memory\n"); + ret = BACKEND_BAD_PATH; + goto end; + } + + switch (JxlSignatureCheck(pvt->data, pvt->data_len)) { + case JXL_SIG_NOT_ENOUGH_BYTES: + imv_log(IMV_DEBUG, "libjxl: not enough bytes to read\n"); + case JXL_SIG_INVALID: + imv_log(IMV_DEBUG, "libjxl: valid jxl signature not found\n"); + munmap(pvt->data, pvt->data_len); + ret = BACKEND_UNSUPPORTED; + goto end; + default: + pvt->owns_data = 1; + break; + } + + *src = imv_source_create(&vtable, pvt); + +end: + if (fd >= 0) + close(fd); + + return ret; +} + +const struct imv_backend imv_backend_libjxl = { + .name = "libjxl", + .description = "The official JPEGXL reference implementation", + .website = "https://jpeg.org/jpegxl/", + .license = "The Modified BSD License", + .open_path = &open_path, + .open_memory = &open_memory, +}; + +/* vim:set ts=2 sts=2 sw=2 et: */ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/imv-v4.4.0/src/imv.c new/imv-v4.5.0/src/imv.c --- old/imv-v4.4.0/src/imv.c 2023-01-18 23:20:52.000000000 +0100 +++ new/imv-v4.5.0/src/imv.c 2024-02-20 23:30:06.000000000 +0100 @@ -1,6 +1,7 @@ #include "imv.h" #include <assert.h> +#include <fcntl.h> #include <ctype.h> #include <errno.h> #include <getopt.h> @@ -537,10 +538,6 @@ imv->commands = imv_commands_create(); imv->console = imv_console_create(); imv_console_set_command_callback(imv->console, &command_callback, imv); - imv->ipc = imv_ipc_create(); - if (imv->ipc) { - imv_ipc_set_command_callback(imv->ipc, &command_callback, imv); - } imv->title_text = strdup( "imv - [${imv_current_index}/${imv_file_count}]" " [${imv_width}x${imv_height}] [${imv_scale}%]" @@ -754,6 +751,39 @@ return true; } +static void set_cloexec(int fd) +{ + int flags = fcntl(fd, F_GETFD); + assert(flags != -1); + flags |= FD_CLOEXEC; + int rc = fcntl(fd, F_SETFD, flags); + assert(rc != -1); +} + +static bool parse_initial_width(struct imv *imv, const char *width_value) +{ + char *endptr; + errno = 0; + int val_x = strtol(width_value, &endptr, 10); + if(errno != 0 || *endptr != '\0' || endptr == width_value) { + return false; + } + imv->initial_width = val_x; + return true; +} + +static bool parse_initial_height(struct imv *imv, const char *height_value) +{ + char *endptr; + errno = 0; + int val_y = strtol(height_value, &endptr, 10); + if(errno != 0 || *endptr != '\0' || endptr == height_value) { + return false; + } + imv->initial_height = val_y; + return true; +} + static void *pipe_stdin(void *data) { int *fd = data; @@ -834,7 +864,7 @@ int o; /* TODO getopt_long */ - while ((o = getopt(argc, argv, "frdxhvlu:s:n:b:t:c:w:")) != -1) { + while ((o = getopt(argc, argv, "frdxhvlu:s:n:b:t:c:w:W:H:")) != -1) { switch(o) { case 'f': imv->start_fullscreen = true; break; case 'r': imv->recursive_load = true; break; @@ -874,6 +904,18 @@ return false; } break; + case 'W': + if(!parse_initial_width(imv, optarg)) { + imv_log(IMV_ERROR, "Invalid initial width value. Aborting.\n"); + return false; + } + break; + case 'H': + if(!parse_initial_height(imv, optarg)) { + imv_log(IMV_ERROR, "Invalid initial height value. Aborting.\n"); + return false; + } + break; case 'c': list_append(imv->startup_commands, optarg); break; case 'w': parse_window_title(imv, optarg); break; case '?': @@ -927,6 +969,11 @@ if (!setup_window(imv)) return 1; + imv->ipc = imv_ipc_create(); + if (imv->ipc) { + imv_ipc_set_command_callback(imv->ipc, &command_callback, imv); + } + /* if loading paths from stdin, kick off a thread to do that - we'll receive * events back via internal events */ int *stdin_pipe_fds = NULL; @@ -942,6 +989,9 @@ return 1; } + /* if a child process spawned by imv inherits the write part of the pipe, + * load_paths_from_stdin() will not exit until the child dies */ + set_cloexec(stdin_pipe_fds[1]); imv->stdin_pipe = fdopen(stdin_pipe_fds[0], "re"); if (pthread_create(&load_paths_thread, NULL, load_paths_from_stdin, imv) @@ -1048,6 +1098,11 @@ continue; } + if (!imv->stdin_image_data || !imv->stdin_image_data_len) { + /* Skip if image failed to load */ + continue; + } + result = backend->open_memory(imv->stdin_image_data, imv->stdin_image_data_len, &new_source); } else { @@ -2018,27 +2073,41 @@ size_t len = 0; ssize_t r; size_t step = 4096; /* Arbitrary value of 4 KiB */ - void *p; + void *new_buf; - errno = 0; /* clear errno */ + errno = 0; + *buffer = NULL; - for (*buffer = NULL; (*buffer = realloc((p = *buffer), len + step)); - len += (size_t)r) { - if ((r = read(STDIN_FILENO, (uint8_t *)*buffer + len, step)) == -1) { - perror(NULL); + while (1) { + new_buf = realloc(*buffer, len + step); + if (new_buf) { + *buffer = new_buf; + } else { + /* Failed to extend buffer */ + int save = errno; + free(*buffer); + errno = save; + *buffer = NULL; + len = 0; break; - } else if (r == 0) { + } + + r = read(STDIN_FILENO, (uint8_t *)*buffer + len, step); + if (r > 0) { + len += (size_t)r; + } else { + if (r < 0) { + /* Read error */ + int save = errno; + perror(NULL); + free(*buffer); + errno = save; + len = 0; + } break; } } - /* realloc(3) leaves old buffer allocated in case of error */ - if (*buffer == NULL && p != NULL) { - int save = errno; - free(p); - errno = save; - len = 0; - } return len; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/imv-v4.4.0/src/main.c new/imv-v4.5.0/src/main.c --- old/imv-v4.4.0/src/main.c 2023-01-18 23:20:52.000000000 +0100 +++ new/imv-v4.5.0/src/main.c 2024-02-20 23:30:06.000000000 +0100 @@ -9,6 +9,7 @@ extern const struct imv_backend imv_backend_libjpeg; extern const struct imv_backend imv_backend_libnsgif; extern const struct imv_backend imv_backend_libheif; +extern const struct imv_backend imv_backend_libjxl; int main(int argc, char **argv) { @@ -46,6 +47,10 @@ imv_install_backend(imv, &imv_backend_libheif); #endif +#ifdef IMV_BACKEND_LIBJXL + imv_install_backend(imv, &imv_backend_libjxl); +#endif + if (!imv_load_config(imv)) { imv_free(imv); return 1; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/imv-v4.4.0/src/wl_window.c new/imv-v4.5.0/src/wl_window.c --- old/imv-v4.4.0/src/wl_window.c 2023-01-18 23:20:52.000000000 +0100 +++ new/imv-v4.5.0/src/wl_window.c 2024-02-20 23:30:06.000000000 +0100 @@ -667,10 +667,12 @@ .close = toplevel_close }; -static void connect_to_wayland(struct imv_window *window) +static bool connect_to_wayland(struct imv_window *window) { window->wl_display = wl_display_connect(NULL); - assert(window->wl_display); + if (window->wl_display == NULL) { + return false; + } window->display_fd = wl_display_get_fd(window->wl_display); pipe(window->pipe_fds); set_nonblocking(window->pipe_fds[0]); @@ -687,6 +689,8 @@ window->egl_display = eglGetDisplay(window->wl_display); eglInitialize(window->egl_display, NULL, NULL); + + return true; } static void create_window(struct imv_window *window, int width, int height, @@ -789,7 +793,9 @@ window->keyboard = imv_keyboard_create(); assert(window->keyboard); window->wl_outputs = list_create(); - connect_to_wayland(window); + if (!connect_to_wayland(window)) { + return NULL; + } create_window(window, width, height, title); struct sigevent timer_handler = { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/imv-v4.4.0/src/x11_window.c new/imv-v4.5.0/src/x11_window.c --- old/imv-v4.4.0/src/x11_window.c 2023-01-18 23:20:52.000000000 +0100 +++ new/imv-v4.5.0/src/x11_window.c 2024-02-20 23:30:06.000000000 +0100 @@ -106,7 +106,9 @@ set_nonblocking(window->pipe_fds[1]); window->x_display = XOpenDisplay(NULL); - assert(window->x_display); + if (window->x_display == NULL) { + return NULL; + } Window root = DefaultRootWindow(window->x_display); assert(root); @@ -145,7 +147,7 @@ window->wm_protocols = XInternAtom(window->x_display, "WM_PROTOCOLS", false); window->wm_delete_window = XInternAtom(window->x_display, "WM_DELETE_WINDOW", false); XSetWMProtocols(window->x_display, window->x_window, &window->wm_delete_window, 1); - XStoreName(window->x_display, window->x_window, title); + imv_window_set_title(window, title); window->x_glc = glXCreateContext(window->x_display, vi, NULL, GL_TRUE); assert(window->x_glc); @@ -203,21 +205,28 @@ void imv_window_set_title(struct imv_window *window, const char *title) { + Atom atom_wm_name; + Atom atom_utf8; + XStoreName(window->x_display, window->x_window, title); + atom_wm_name = XInternAtom(window->x_display, "_NET_WM_NAME", False); + atom_utf8 = XInternAtom(window->x_display, "UTF8_STRING", False); + XChangeProperty(window->x_display, window->x_window, atom_wm_name, atom_utf8, + 8, PropModeReplace, (unsigned char*)title, strlen(title)); } bool imv_window_is_fullscreen(struct imv_window *window) { - size_t count = 0; + unsigned long count = 0; Atom type; int format; - size_t after; + unsigned long after; Atom *props = NULL; XGetWindowProperty(window->x_display, window->x_window, window->x_state, 0, 1024, False, XA_ATOM, &type, &format, &count, &after, (unsigned char**)&props); bool fullscreen = false; - for (size_t i = 0; i < count; ++i) { + for (unsigned long i = 0; i < count; ++i) { if (props[i] == window->x_fullscreen) { fullscreen = true; break;
