[PATCH] WRaster: Add optional support to JPEG XL

1 view
Skip to first unread message

david.m...@gmail.com

unread,
Dec 27, 2025, 9:25:51 AM (6 days ago) 12/27/25
to Window Maker Development
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.ac
index 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

0001-WRaster-Add-optional-support-to-JPEG-XL.patch
Reply all
Reply to author
Forward
0 new messages