Detect if libjxl is installed, and build-in support in raster lib.
Feature can be disabled/enabled at configure time.
---
configure.ac | 13 +++
doc/build/Compilation.texi | 8 ++
m4/wm_imgfmt_check.m4 | 31 ++++++
wrlib/Makefile.am | 4 +
wrlib/imgformat.h | 9 +-
wrlib/load.c | 23 +++-
wrlib/load_jxl.c | 211 +++++++++++++++++++++++++++++++++++++
wrlib/po/Makefile.am | 1 +
8 files changed, 297 insertions(+), 3 deletions(-)
create mode 100644 wrlib/load_jxl.c
diff --git a/
configure.ac b/
configure.acindex 67d925a8..ad67fc91 100644
--- a/
configure.ac+++ b/
configure.ac@@ -766,6 +766,19 @@ m4_divert_pop([INIT_PREPARE])dnl
WM_IMGFMT_CHECK_JPEG
+dnl JXL Support
+dnl ============
+m4_divert_push([INIT_PREPARE])dnl
+AC_ARG_ENABLE([jxl],
+ [AS_HELP_STRING([--disable-jxl], [disable JXL support through libjxl])],
+ [AS_CASE(["$enableval"],
+ [yes|no], [],
+ [AC_MSG_ERROR([bad value $enableval for --enable-jxl])] )],
+ [enable_jxl=auto])
+m4_divert_pop([INIT_PREPARE])dnl
+WM_IMGFMT_CHECK_JXL
+
+
dnl GIF Support
dnl ============
m4_divert_push([INIT_PREPARE])dnl
diff --git a/doc/build/Compilation.texi b/doc/build/Compilation.texi
index 2265e4fd..0046384a 100644
--- a/doc/build/Compilation.texi
+++ b/doc/build/Compilation.texi
@@ -204,6 +204,11 @@ Note that if you don't have it, @command{configure} will issue a big warning in
this is because JPEG images are often used in themes and for background images
so you probably want this format supported.
+@item @emph{libjxl} 0.7.0 or newer
+
+For @emph{JXL} image support,
+@uref{
https://github.com/libjxl/libjxl}
+
@item @emph{libgif} 2.2 or @emph{libungif}
For @emph{GIF} image support,
@@ -477,6 +482,9 @@ Disable GIF support in @emph{WRaster} library; when enabled use @file{libgif} or
@item --disable-jpeg
Disable JPEG support in @emph{WRaster} library; when enabled use @file{libjpeg}.
+@item --disable-jxl
+Disable JPEG-XL support in @emph{WRaster} library; when enabled use @file{libjxl}.
+
@item --without-libbsd
Refuse use of the @file{libbsd} compatibility library in @emph{WINGs} utility library,
even if your system provides it.
diff --git a/m4/wm_imgfmt_check.m4 b/m4/wm_imgfmt_check.m4
index 88939f48..dce5b0d5 100644
--- a/m4/wm_imgfmt_check.m4
+++ b/m4/wm_imgfmt_check.m4
@@ -113,6 +113,37 @@ AC_DEFUN_ONCE([WM_IMGFMT_CHECK_JPEG],
]) dnl AC_DEFUN
+# WM_IMGFMT_CHECK_JXL
+# -------------------
+#
+# Check for JXL (JPEG XL) file support through 'libjxl'
+# The check depends on variable 'enable_jxl' being either:
+# yes - detect, fail if not found
+# no - do not detect, disable support
+# auto - detect, disable if not found
+#
+# When found, append appropriate stuff in GFXLIBS, and append info to
+# the variable 'supported_gfx'
+# When not found, append info to variable 'unsupported'
+AC_DEFUN_ONCE([WM_IMGFMT_CHECK_JXL],
+[WM_LIB_CHECK([JXL], [-ljxl], [JxlDecoderCreate], [$XLFLAGS $XLIBS],
+ [AC_COMPILE_IFELSE(
+ [AC_LANG_PROGRAM(
+ [@%:@include <stdlib.h>
+@%:@include <jxl/decode.h>],
+ [ JxlDecoder* dec = JxlDecoderCreate(NULL);
+ JxlDecoderDestroy(dec);])],
+ [],
+ [AS_ECHO([failed])
+ AS_ECHO(["$as_me: error: found $CACHEVAR but cannot compile header"])
+ AS_ECHO(["$as_me: error: - does header 'jxl/decode.h' exists? (is package 'libjxl-dev' missing?)"])
+ AS_ECHO(["$as_me: error: - version of header is not supported? (report to dev team)"])
+ AC_MSG_ERROR([JXL library is not usable, cannot continue])])
+ ],
+ [supported_gfx], [GFXLIBS])dnl
+]) dnl AC_DEFUN
+
+
# WM_IMGFMT_CHECK_PNG
# -------------------
#
diff --git a/wrlib/Makefile.am b/wrlib/Makefile.am
index a82bb9a0..68f045ce 100644
--- a/wrlib/Makefile.am
+++ b/wrlib/Makefile.am
@@ -58,6 +58,10 @@ libwraster_la_SOURCES += load_jpeg.c
libwraster_la_SOURCES += save_jpeg.c
endif
+if USE_JXL
+libwraster_la_SOURCES += load_jxl.c
+endif
+
if USE_PNG
libwraster_la_SOURCES += load_png.c
libwraster_la_SOURCES += save_png.c
diff --git a/wrlib/imgformat.h b/wrlib/imgformat.h
index ba2e2956..a903bc3f 100644
--- a/wrlib/imgformat.h
+++ b/wrlib/imgformat.h
@@ -38,12 +38,13 @@ typedef enum {
IM_PPM = 4,
IM_JPEG = 5,
IM_GIF = 6,
-
IM_WEBP = 7
+
IM_WEBP = 7,
+
IM_JXL = 8
} WRImgFormat;
/* How many image types we have. */
/* Increase this when adding new image types! */
-#define IM_TYPES 7
+#define IM_TYPES 8
/*
* Function for Loading in a specific format
@@ -64,6 +65,10 @@ RImage *RLoadPNG(RContext *context, const char *file);
RImage *RLoadJPEG(const char *file);
#endif
+#ifdef USE_JXL
+RImage *RLoadJXL(const char *file);
+#endif
+
#ifdef USE_GIF
RImage *RLoadGIF(const char *file, int index);
#endif
diff --git a/wrlib/load.c b/wrlib/load.c
index 0db123ca..0f824201 100644
--- a/wrlib/load.c
+++ b/wrlib/load.c
@@ -3,7 +3,7 @@
* Raster graphics library
*
* Copyright (c) 1997-2003 Alfredo K. Kojima
- * Copyright (c) 2014-2021 Window Maker Team
+ * Copyright (c) 2014-2025 Window Maker Team
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -93,6 +93,9 @@ char **RSupportedFileFormats(void)
#ifdef USE_JPEG
tmp[i++] = "JPEG";
#endif
+#ifdef USE_JXL
+
tmp[i++] = "JXL";
+#endif
#ifdef USE_GIF
tmp[i++] = "GIF";
#endif
@@ -224,6 +227,12 @@ RImage *RLoadImage(RContext *context, const char *file, int index)
break;
#endif
/* USE_JPEG */
+#ifdef USE_JXL
+
case IM_JXL:
+
image = RLoadJXL(file);
+
break;
+#endif
/* USE_JXL */
+
#ifdef USE_GIF
case IM_GIF:
image = RLoadGIF(file, index);
@@ -310,6 +319,11 @@ char *RGetImageFileFormat(const char *file)
return "JPEG";
#endif
/* USE_JPEG */
+#ifdef USE_JXL
+
case IM_JXL:
+
return "JXL";
+#endif
/* USE_JXL */
+
#ifdef USE_GIF
case IM_GIF:
return "GIF";
@@ -382,6 +396,13 @@ static WRImgFormat identFile(const char *path)
if (buffer[0] == 0xff && buffer[1] == 0xd8)
return IM_JPEG;
+
/* check for JXL */
+
if ((buffer[0] == 0xff && buffer[1] == 0x0a) || /* naked codestream */
+
(buffer[0] == 0x00 && buffer[1] == 0x00 && buffer[2] == 0x00 && buffer[3] == 0x0c && /* container format */
+
buffer[4] == 0x4a && buffer[5] == 0x58 && buffer[6] == 0x4c && buffer[7] == 0x20 &&
+
buffer[8] == 0x0d && buffer[9] == 0x0a && buffer[10] == 0x87 && buffer[11] == 0x0a))
+
return IM_JXL;
+
/* check for GIF */
if (buffer[0] == 'G' && buffer[1] == 'I' && buffer[2] == 'F' && buffer[3] == '8' &&
(buffer[4] == '7' || buffer[4] == '9') && buffer[5] == 'a')
diff --git a/wrlib/load_jxl.c b/wrlib/load_jxl.c
new file mode 100644
index 00000000..c62ad49e
--- /dev/null
+++ b/wrlib/load_jxl.c
@@ -0,0 +1,211 @@
+/* load_jxl.c - load JXL (JPEG XL) image from file
+ *
+ * Raster graphics library
+ *
+ * Copyright (c) 2025 Window Maker Team
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+
+#include <config.h>
+
+#ifdef USE_JXL
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+
+#include <jxl/decode.h>
+
+#include "wraster.h"
+#include "imgformat.h"
+#include "wr_i18n.h"
+
+static unsigned char *do_read_file(const char *filename, size_t *size)
+{
+
FILE *file;
+
struct stat st;
+
unsigned char *data;
+
+
if (stat(filename, &st) != 0) {
+
RErrorCode = RERR_OPEN;
+
return NULL;
+
}
+
+
file = fopen(filename, "rb");
+
if (!file) {
+
RErrorCode = RERR_OPEN;
+
return NULL;
+
}
+
+
*size = st.st_size;
+
data = malloc(*size);
+
if (!data) {
+
RErrorCode = RERR_NOMEMORY;
+
fclose(file);
+
return NULL;
+
}
+
+
if (fread(data, 1, *size, file) != *size) {
+
RErrorCode = RERR_READ;
+
free(data);
+
fclose(file);
+
return NULL;
+
}
+
+
fclose(file);
+
return data;
+}
+
+RImage *RLoadJXL(const char *file)
+{
+
RImage *image = NULL;
+
unsigned char *data = NULL, *pixels = NULL;
+
size_t size;
+
JxlDecoder *dec = NULL;
+
JxlDecoderStatus status;
+
JxlBasicInfo info;
+
JxlPixelFormat format;
+
size_t buffer_size;
+
int width = 0, height = 0;
+
int has_alpha = 0;
+
+
/* Load file data */
+
data = do_read_file(file, &size);
+
if (!data)
+
return NULL;
+
+
/* Create decoder */
+
dec = JxlDecoderCreate(NULL);
+
if (!dec) {
+
RErrorCode = RERR_NOMEMORY;
+
goto error;
+
}
+
+
/* Subscribe to basic info and full image */
+
if (JxlDecoderSubscribeEvents(dec, JXL_DEC_BASIC_INFO | JXL_DEC_FULL_IMAGE) != JXL_DEC_SUCCESS) {
+
RErrorCode = RERR_BADIMAGEFILE;
+
goto error;
+
}
+
+
/* Set input data */
+
if (JxlDecoderSetInput(dec, data, size) != JXL_DEC_SUCCESS) {
+
RErrorCode = RERR_BADIMAGEFILE;
+
goto error;
+
}
+
+
/* Process events */
+
for (;;) {
+
status = JxlDecoderProcessInput(dec);
+
+
if (status == JXL_DEC_ERROR) {
+
RErrorCode = RERR_BADIMAGEFILE;
+
goto error;
+
}
+
+
if (status == JXL_DEC_NEED_MORE_INPUT) {
+
RErrorCode = RERR_BADIMAGEFILE;
+
goto error;
+
}
+
+
if (status == JXL_DEC_BASIC_INFO) {
+
if (JxlDecoderGetBasicInfo(dec, &info) != JXL_DEC_SUCCESS) {
+
RErrorCode = RERR_BADIMAGEFILE;
+
goto error;
+
}
+
+
width = info.xsize;
+
height = info.ysize;
+
+
if (width < 1 || height < 1) {
+
RErrorCode = RERR_BADIMAGEFILE;
+
goto error;
+
}
+
+
/* Check if image has alpha channel */
+
has_alpha = (info.alpha_bits > 0);
+
+
/* Set pixel format based on alpha channel presence */
+
if (has_alpha) {
+
format.num_channels = 4; /* RGBA */
+
} else {
+
format.num_channels = 3; /* RGB */
+
}
+
format.data_type = JXL_TYPE_UINT8;
+
format.endianness = JXL_NATIVE_ENDIAN;
+
format.align = 0;
+
+
} else if (status == JXL_DEC_NEED_IMAGE_OUT_BUFFER) {
+
/* Allocate image with or without alpha */
+
image = RCreateImage(width, height, has_alpha ? True : False);
+
if (!image) {
+
RErrorCode = RERR_NOMEMORY;
+
goto error;
+
}
+
+
/* Determine buffer size */
+
if (JxlDecoderImageOutBufferSize(dec, &format, &buffer_size) != JXL_DEC_SUCCESS) {
+
RErrorCode = RERR_BADIMAGEFILE;
+
goto error;
+
}
+
+
/* Allocate buffer */
+
pixels = malloc(buffer_size);
+
if (!pixels) {
+
RErrorCode = RERR_NOMEMORY;
+
goto error;
+
}
+
+
/* Set output buffer */
+
if (JxlDecoderSetImageOutBuffer(dec, &format, pixels, buffer_size) != JXL_DEC_SUCCESS) {
+
RErrorCode = RERR_BADIMAGEFILE;
+
goto error;
+
}
+
} else if (status == JXL_DEC_FULL_IMAGE) {
+
/* Image is ready, copy data directly for RGB or RGBA */
+
if (has_alpha) {
+
/* RGBA format - copy directly */
+
memcpy(image->data, pixels, width * height * 4);
+
} else {
+
/* RGB format - copy directly */
+
memcpy(image->data, pixels, width * height * 3);
+
}
+
break;
+
} else if (status == JXL_DEC_SUCCESS) {
+
/* All done */
+
break;
+
}
+
}
+
+
free(data);
+
free(pixels);
+
JxlDecoderDestroy(dec);
+
return image;
+
+error:
+
if (data)
+
free(data);
+
if (pixels)
+
free(pixels);
+
if (image)
+
RReleaseImage(image);
+
if (dec)
+
JxlDecoderDestroy(dec);
+
return NULL;
+}
+
+#endif /* USE_JXL */
\ No newline at end of file
diff --git a/wrlib/po/Makefile.am b/wrlib/po/Makefile.am
index 4320e751..647294b6 100644
--- a/wrlib/po/Makefile.am
+++ b/wrlib/po/Makefile.am
@@ -29,6 +29,7 @@ POTFILES = \
$(top_srcdir)/wrlib/load_ppm.c
\
$(top_srcdir)/wrlib/load_gif.c
\
$(top_srcdir)/wrlib/load_jpeg.c
\
+
$(top_srcdir)/wrlib/load_jxl.c
\
$(top_srcdir)/wrlib/load_png.c
\
$(top_srcdir)/wrlib/load_tiff.c
\
$(top_srcdir)/wrlib/load_xpm.c
\
--
2.43.0