JxlDecoderSetImageOutCallback cannot reliably convert the pixel data type
Describe the bug
One of the trials I did to support HDR in Krita involved asking libjxl to convert the pixels' data type, from whatever their original format, to JXL_TYPE_FLOAT. This saves me from having to convert the pixels myself before linearizing (our HDR machinery expect floating point images):
case JXL_TRANSFER_FUNCTION_PQ: {
dbgFile << "linearizing from PQ";
d.linearizePolicy = LinearizePolicy::LinearFromPQ;
d.m_pixelFormat.data_type = JXL_TYPE_FLOAT;
return TRC_LINEAR;
}
Widening conversions through this function seem to introduce denormal values at arbitrary locations; they are mostly invisible to the naked eye, until the resulting canvas is tonemapped with e.g. OpenColorIO, which will clamp those invalid pixels to black.
Narrowing conversions will instead turn the pixel data into garbage.
To Reproduce
Download image number 17 from https://people.csail.mit.edu/ericchan/hdr/hdr-jxl.php. This image is identified by jxlinfo as:
JPEG XL file format container (ISO/IEC 18181-2)
JPEG XL image, 2048x2048, lossy, 16-bit RGB
Color space: RGB, D65, Rec.2100 primaries, PQ transfer function, rendering intent: Perceptual
Uncompressed Exif metadata: 918 bytes
Brotli-compressed XML metadata: 6130 compressed bytes
unknown box: type: "hrgm" size: 75863
layer: full image size, name: "main"
Open it in a JXL compliant viewer, but beforehand, in the pixel format provided to libjxl set data_type to e.g. JXL_TYPE_FLOAT.
Expected behavior
Given that the original image has no NaN or infinite values, no NaN or infinite values should be found in the extracted bitmap.
Screenshots
JXL_TYPE_UINT16 to:
JXL_TYPE_FLOAT16 |
JXL_TYPE_FLOAT32 |
Manual conversion |
|---|---|---|
![]() |
![]() |
![]() |
Environment
- OS: Windows 10 21H2
- Compiler version: Microsoft (R) C/C++ Optimizing Compiler Version 19.34.31721 for x64
- CPU type: x86_64 znver1
- cjxl/djxl version string:
cjxl v0.7.0 0.7.0 [AVX2,SSE4,SSSE3,Unknown]
Additional context
Krita's HDR JXL support is not yet available except for floating point, linear gamma, ICC profile images. I'm working on it, hence why this bug report is being made.
One reason that this could happen is if the endianness is not set correctly in JxlDecoderSetImageOutCallback(). Could you try setting
d.m_pixelFormat.endianness = JXL_NATIVE_ENDIAN;
in the code snippet above and see if the problem persists?
@szabadka Already did that as I use a default-constructed JxlPixelFormat. Setting it to any option is of no use.
On further look, though, it's always the blue channels that come out wrong, Krita's reporting the libjxl values for affected pixels to be "Inf". Disabling the PQ conversion reveals libjxl returns very low or even negative values for them.


