libjxl icon indicating copy to clipboard operation
libjxl copied to clipboard

JxlDecoderSetImageOutCallback cannot reliably convert the pixel data type

Open amyspark opened this issue 3 years ago • 2 comments

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
Captura de pantalla 2022-09-14 123956 Captura de pantalla 2022-09-14 124809 Captura de pantalla 2022-09-14 124523

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.

amyspark avatar Sep 14 '22 15:09 amyspark

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 avatar Sep 16 '22 15:09 szabadka

@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.

amyspark avatar Sep 21 '22 17:09 amyspark