Add jxl loader

This commit is contained in:
Kim Woelders 2022-03-25 22:21:25 +01:00
parent 63dccd46c5
commit 323a95cd4e
4 changed files with 190 additions and 0 deletions

View File

@ -196,6 +196,7 @@ loader_check_gif() {
EC_LOADER_CHECK(GIF, auto, , loader_check_gif)
EC_LOADER_CHECK(HEIF, auto, libheif)
EC_LOADER_CHECK(JPEG, auto, libjpeg)
EC_LOADER_CHECK(JXL, auto, libjxl libjxl_threads)
EC_LOADER_CHECK(PNG, auto, libpng)
EC_LOADER_CHECK(SVG, auto, librsvg-2.0 >= 2.46)
EC_LOADER_CHECK(TIFF, auto, libtiff-4)
@ -276,6 +277,7 @@ echo " Regular image loaders"
echo " GIF.....................: $gif_ok"
echo " HEIF....................: $heif_ok"
echo " JPEG....................: $jpeg_ok"
echo " JXL.....................: $jxl_ok"
echo " PNG.....................: $png_ok"
echo " SVG.....................: $svg_ok"
echo " TIFF....................: $tiff_ok"

View File

@ -36,6 +36,9 @@ static const char *const ext_ico[] = { "ico", NULL };
#ifdef BUILD_JPEG_LOADER
static const char *const ext_jpeg[] = { "jpg", "jpeg", "jfif", "jfi", NULL };
#endif
#ifdef BUILD_JXL_LOADER
static const char *const ext_jxl[] = { "uxl", NULL };
#endif
static const char *const ext_lbm[] = { "iff", "ilbm", "lbm", NULL };
#ifdef BUILD_PNG_LOADER
static const char *const ext_png[] = { "png", NULL };
@ -82,6 +85,9 @@ static const KnownLoader loaders_known[] = {
{"ico", ext_ico},
#ifdef BUILD_JPEG_LOADER
{"jpeg", ext_jpeg},
#endif
#ifdef BUILD_JXL_LOADER
{"jxl", ext_jxl},
#endif
{"lbm", ext_lbm},
#ifdef BUILD_PNG_LOADER

View File

@ -23,6 +23,9 @@ endif
if BUILD_JPEG_LOADER
pkg_LTLIBRARIES += jpeg.la
endif
if BUILD_JXL_LOADER
pkg_LTLIBRARIES += jxl.la
endif
if BUILD_PNG_LOADER
pkg_LTLIBRARIES += png.la
endif
@ -89,6 +92,12 @@ jpeg_la_LDFLAGS = -module -avoid-version
jpeg_la_LIBADD = $(JPEG_LIBS) $(top_builddir)/src/lib/libImlib2.la
jpeg_la_LIBTOOLFLAGS = --tag=disable-static
jxl_la_SOURCES = loader_jxl.c
jxl_la_CPPFLAGS = $(JXL_CFLAGS) $(AM_CPPFLAGS)
jxl_la_LDFLAGS = -module -avoid-version
jxl_la_LIBADD = $(JXL_LIBS) $(top_builddir)/src/lib/libImlib2.la
jxl_la_LIBTOOLFLAGS = --tag=disable-static
lbm_la_SOURCES = loader_lbm.c
lbm_la_LDFLAGS = -module -avoid-version
lbm_la_LIBADD = $(top_builddir)/src/lib/libImlib2.la

View File

@ -0,0 +1,173 @@
#include "loader_common.h"
#define MAX_RUNNERS 4 /* Maybe set to Ncpu/2? */
#include <jxl/decode.h>
#if MAX_RUNNERS > 0
#include <jxl/thread_parallel_runner.h>
#endif
#define DBG_PFX "LDR-jxl"
static void
_scanline_cb(void *opaque, size_t x, size_t y,
size_t num_pixels, const void *pixels)
{
ImlibImage *im = opaque;
const uint8_t *pix = pixels;
uint32_t *ptr;
size_t i;
DL("%s: x,y=%ld,%ld len=%lu\n", __func__, x, y, num_pixels);
ptr = im->data + (im->w * y) + x;
/* libjxl outputs ABGR pixels (stream order RGBA) - convert to ARGB */
for (i = 0; i < num_pixels; i++, pix += 4)
*ptr++ = PIXEL_ARGB(pix[3], pix[0], pix[1], pix[2]);
/* Due to possible multithreading it's probably best not do do
* progress calbacks here. */
}
int
load2(ImlibImage * im, int load_data)
{
static const JxlPixelFormat pbuf_fmt = {
.num_channels = 4,
.data_type = JXL_TYPE_UINT8,
.endianness = JXL_NATIVE_ENDIAN,
};
int rc;
void *fdata;
JxlDecoderStatus jst;
JxlDecoder *dec;
JxlBasicInfo info;
#if MAX_RUNNERS > 0
size_t n_runners;
JxlParallelRunner *runner = NULL;
#endif
fdata = mmap(NULL, im->fsize, PROT_READ, MAP_SHARED, fileno(im->fp), 0);
if (fdata == MAP_FAILED)
return LOAD_BADFILE;
rc = LOAD_FAIL;
dec = NULL;
switch (JxlSignatureCheck(fdata, 128))
{
default:
// case JXL_SIG_NOT_ENOUGH_BYTES:
// case JXL_SIG_INVALID:
goto quit;
case JXL_SIG_CODESTREAM:
case JXL_SIG_CONTAINER:
break;
}
rc = LOAD_BADIMAGE; /* Format accepted */
dec = JxlDecoderCreate(NULL);
if (!dec)
goto quit;
#if MAX_RUNNERS > 0
n_runners = JxlThreadParallelRunnerDefaultNumWorkerThreads();
if (n_runners > MAX_RUNNERS)
n_runners = MAX_RUNNERS;
D("n_runners = %ld\n", n_runners);
runner = JxlThreadParallelRunnerCreate(NULL, n_runners);
if (!runner)
goto quit;
jst = JxlDecoderSetParallelRunner(dec, JxlThreadParallelRunner, runner);
if (jst != JXL_DEC_SUCCESS)
goto quit;
#endif /* MAX_RUNNERS */
jst =
JxlDecoderSubscribeEvents(dec, JXL_DEC_BASIC_INFO | JXL_DEC_FULL_IMAGE);
if (jst != JXL_DEC_SUCCESS)
goto quit;
jst = JxlDecoderSetInput(dec, fdata, im->fsize);
if (jst != JXL_DEC_SUCCESS)
goto quit;
for (;;)
{
jst = JxlDecoderProcessInput(dec);
switch (jst)
{
default:
D("Unexpected status: %d\n", jst);
goto quit;
case JXL_DEC_BASIC_INFO:
jst = JxlDecoderGetBasicInfo(dec, &info);
if (jst != JXL_DEC_SUCCESS)
goto quit;
D("WxH=%dx%d alpha=%d bps=%d nc=%d+%d\n", info.xsize, info.ysize,
info.alpha_bits, info.bits_per_sample,
info.num_color_channels, info.num_extra_channels);
if (info.have_animation)
{
D("anim=%d loops=%u tps_num/den=%u/%u\n", info.have_animation,
info.animation.num_loops, info.animation.tps_numerator,
info.animation.tps_denominator);
}
if (!IMAGE_DIMENSIONS_OK(info.xsize, info.ysize))
goto quit;
im->w = info.xsize;
im->h = info.ysize;
IM_FLAG_UPDATE(im, F_HAS_ALPHA, info.alpha_bits > 0);
if (!load_data)
QUIT_WITH_RC(LOAD_SUCCESS);
break;
case JXL_DEC_NEED_IMAGE_OUT_BUFFER:
if (!__imlib_AllocateData(im))
QUIT_WITH_RC(LOAD_OOM);
jst = JxlDecoderSetImageOutCallback(dec, &pbuf_fmt,
_scanline_cb, im);
if (jst != JXL_DEC_SUCCESS)
goto quit;
break;
case JXL_DEC_FULL_IMAGE:
goto done;
}
}
done:
if (im->lc)
__imlib_LoadProgress(im, 0, 0, im->w, im->h);
rc = LOAD_SUCCESS;
quit:
#if MAX_RUNNERS > 0
if (runner)
JxlThreadParallelRunnerDestroy(runner);
#endif
if (dec)
JxlDecoderDestroy(dec);
munmap(fdata, im->fsize);
return rc;
}
void
formats(ImlibLoader * l)
{
static const char *const list_formats[] = { "jxl" };
__imlib_LoaderSetFormats(l, list_formats, ARRAY_SIZE(list_formats));
}