All formats

JXLatte

LanguageJava
LicenseMIT
Repositorygithub.com/Traneptora/jxlatte
DocumentationREADME and source
Depends onnothing
Read / writeyes / no (decodes JXL, writes PNG and PFM)

JXLatte is a JPEG XL decoder written from scratch in Java, without libjxl. It decodes all static images: lossless and lossy Modular, VarDCT, and recompressed JPEGs. It can also write the result as PNG (8 or 16 bits, SDR or HDR) or PFM.

It doesn’t support animation, progressive decoding or region-of-interest decoding, and it is slower than libjxl. The project calls itself work in progress. Use it when you need to read JXL images on the JVM without native code.

Installation#

JXLatte is not published on Maven Central. Build it and install it into your local Maven repository:

Shell
git clone https://github.com/Traneptora/jxlatte.git
cd jxlatte
mvn clean install

Then add the dependency:

XML
<dependency>
  <groupId>com.traneptora</groupId>
  <artifactId>jxlatte</artifactId>
  <version>0.1.0</version>
</dependency>

It also builds with Meson (meson setup build && ninja -C build) into a runnable jxlatte.jar.

Basic usage: convert JXL to PNG#

Java
import com.traneptora.jxlatte.JXLDecoder;
import com.traneptora.jxlatte.JXLImage;
import com.traneptora.jxlatte.io.PNGWriter;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

public class JxlToPng {
    public static void main(String[] args) throws IOException {
        try (JXLDecoder decoder = new JXLDecoder("in.jxl");
             OutputStream out = new FileOutputStream("out.png")) {
            JXLImage image = decoder.decode();
            System.out.println(image.getWidth() + " x " + image.getHeight());
            new PNGWriter(image).write(out);
        }
    }
}

How to read image properties#

Java
JXLImage image = new JXLDecoder("in.jxl").decode();
int width = image.getWidth();
int height = image.getHeight();
boolean alpha = image.hasAlpha();
boolean hdr = image.isHDR();
int channels = image.getColorChannelCount();  // 1 gray, 3 color
if (image.hasICCProfile()) {
    byte[] icc = image.getICCProfile();
}

How to get the pixel values#

getBuffer returns one ImageBuffer per channel (color channels, then alpha and other extra channels). A buffer stores samples as int[y][x] or float[y][x]:

Java
import com.traneptora.jxlatte.util.ImageBuffer;

ImageBuffer[] channels = image.getBuffer(false);  // false: no copy
ImageBuffer red = channels[0];
if (red.isFloat()) {
    float[][] samples = red.getFloatBuffer();  // samples[y][x]
    System.out.println(samples[0][0]);
} else {
    int[][] samples = red.getIntBuffer();
    System.out.println(samples[0][0]);
}

How to write a 16-bit PNG#

Java
import com.traneptora.jxlatte.JXLOptions;

// bit depth 8 or 16, not HDR
new PNGWriter(image, 16, false, JXLOptions.PEAK_DETECT_AUTO).write(out);

Tips#