Pillow icon indicating copy to clipboard operation
Pillow copied to clipboard

Add JPEG XL Open/Read support via libjxl

Open olokelo opened this issue 1 year ago • 19 comments
trafficstars

Helps #4247

This PR enables opening and reading JPEG XL images and animations. Supported image modes are: RGB, RGBA, RGBa, L, LA, La. A relatively recent libjxl version is needed to compile Pillow with libjxl support. The main changes are the addition of _jxl.c and JxlImagePlugin.py. I'm also the author of jxlpy so this PR was influenced by the work of contributors there. This PR is also largely based on WebPImagePlugin.py which had similar implementation.

Why? JPEG XL has recently seen increased adoption especially in Apple ecosystem. A lot of users are requesting Pillow support for JPEG XL as their products use Pillow and need to be able to handle jxl files.

I'm open to suggestions and comments. I understand such change would need a lot of testing and probably changes. After all Pillow would need to become somewhat dependent on libjxl. Creating documentation will not be a big problem however I decided to wait for feedback from Pillow core developers.

olokelo avatar Mar 02 '24 00:03 olokelo

May you please commit the images as LFS?

brunoais avatar Mar 02 '24 14:03 brunoais

May you please commit the images as LFS?

Do you mean those .jxl files under Tests/images I've committed? I'm not really sure how to do that.

olokelo avatar Mar 02 '24 18:03 olokelo

~~The explanation is outlined here: https://docs.github.com/en/repositories/working-with-files/managing-large-files/configuring-git-large-file-storage~~ Nevermind. I just noticed they are not putting the test images as lfs: image

They already setup lfs and they only use for other larger stuff. Let it stay as you did.

brunoais avatar Mar 03 '24 08:03 brunoais

Mac OS builds were failing because clang complained about goto labels being declared before variables in scope. I also merged @radarhere's commits that remove the jxl feature which was causing troubles before. Now it should be fine. Almost all checks pass except codecov.

olokelo avatar Mar 11 '24 12:03 olokelo

I've merged in main to include https://github.com/python-pillow/Pillow/pull/7827 to fix a lot of the warnings I'm seeing on macOS 14.4 Sonoma with CommandLineTools installed.

And this is failing to build for me with:

      src/_jxl.c:174:12: error: incompatible integer to pointer conversion returning 'int' from a function with result type 'void *' [-Wint-conversion]
          return true;
                 ^~~~
      /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/15.0.0/include/stdbool.h:21:14: note: expanded from macro 'true'
      #define true 1
                   ^

Full log: log2.txt

hugovk avatar Mar 19 '24 09:03 hugovk

I've merged in main to include #7827 to fix a lot of the warnings I'm seeing on macOS 14.4 Sonoma with CommandLineTools installed.

And this is failing to build for me with:

      src/_jxl.c:174:12: error: incompatible integer to pointer conversion returning 'int' from a function with result type 'void *' [-Wint-conversion]
          return true;
                 ^~~~
      /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/15.0.0/include/stdbool.h:21:14: note: expanded from macro 'true'
      #define true 1
                   ^

Full log: log2.txt

Thanks for reporting. The _jxl_decoder_count_frames function was declared to return void * instead of bool. That was an obvious mistake and I'm even not sure why it worked under gcc.

olokelo avatar Mar 19 '24 12:03 olokelo

It would be excellent to see some progress in this area. I am currently working on introducing JPEG XL support to https://immich.app for previews and thumbnails (as Python is used for ML). However, an additional plugin pillow-jpegxl-plugin complicates the deployment process.

develar avatar Apr 23 '24 19:04 develar

Could you still add support for 16 bit single channel files? Such images are commonly used in fluorescent microscopy, and storing them in jxl instead of tiff or png would lead to substantial storage savings. Pillow is used by various relevant software including imageio and CellProfiler.

In _pil_jxl_get_mode you would have to add:

    if(bi->bits_per_sample == 16 && bi->num_color_channels == 1 && bi->alpha_bits == 0 && !bi->alpha_premultiplied) {
        return "I;16";
    }

and in _jxl_decoder_new, the line

if (decp->pixel_format.data_type != JXL_TYPE_UINT8) {

should be changed into:

if (decp->pixel_format.data_type != JXL_TYPE_UINT8 && decp->pixel_format.data_type != JXL_TYPE_UINT16) {

bgorissen avatar Apr 24 '24 16:04 bgorissen

Any relation-to or overlap-with #1888 here? 🤔

aclark4life avatar Apr 24 '24 16:04 aclark4life

Any relation-to or overlap-with #1888 here? 🤔

Not quite, fluorescent microscopy images are often stored in a single channel while #1888 is about multichannel files. Pillow already supports single channel images (as #1888 points out), so it makes sense that this JPEG XL reader supports them too.

bgorissen avatar Apr 24 '24 16:04 bgorissen

It would be excellent to see some progress in this area. I am currently working on introducing JPEG XL support to https://immich.app for previews and thumbnails (as Python is used for ML). However, an additional plugin pillow-jpegxl-plugin complicates the deployment process.

@develar Sounds awesome, thank you for working on JPEG XL support in Immich. I presume that merging this PR is now up to Pillow core developers since all checks have passed. However by now we would probably need to resolve some merge conflicts.

Could you still add support for 16 bit single channel files? Such images are commonly used in fluorescent microscopy, and storing them in jxl instead of tiff or png would lead to substantial storage savings.

@bgorissen Yes, of course it's possible. Thank you for detailed description of changes. Could you provide some image(s) to test this mode?

olokelo avatar Apr 27 '24 09:04 olokelo

@olokelo I 2nd @bgorissen request around 16 bit single channel support. I work with imaging systems that produce 16 bit single channel images, like thermal and depth, and the JXL format provides some significant cost savings storage-wise compared to our 16 bit single channel PNG format we are currently using. I would love to see the JXL ecosystem mature and this plugin would go a long way towards our adoption of the format

j99ca avatar May 07 '24 17:05 j99ca

@olokelo I've attached a 16-bits grayscale jxl file (zipped because Github does not support jxl). You could crop it to create a smaller test file. The file was converted from a public tiff image from the dataset cpg0011 (Laber et al., 2023), available from the Cell Painting Gallery on the Registry of Open Data on AWS (https://registry.opendata.aws/cellpainting-gallery/), and released under CC0 1.0 Universal (which puts it in the public domain).

subcutaneous__D14__45adb24f-23b7-43f8-9612-0a7ecaa22ada__BR00101077__r02c03f01p01-ch1sk1fk1fl1.zip

bgorissen avatar May 08 '24 13:05 bgorissen

This is very good work @olokelo! Is there any plan to add support for writing to JXL from Pillow?

j99ca avatar May 24 '24 13:05 j99ca

@j99ca Yes of course, I just wanted to add reading support first to see what Pillow maintainers think about it. For now you can create JXL images using jxlpy.

olokelo avatar May 24 '24 14:05 olokelo

@hugovk: It certainly would be nice to have this as feature in Pillow 11, wouldn't it? Maybe you can sketch out the required steps?

cmahnke avatar Aug 08 '24 21:08 cmahnke

The iPhone 16 Pro models will support the JPEG-XL file format, according to code found in iOS 18.

I really hope this will be the next standard in photography, I would really like to see support for this in Pillow 11 by default.

bigcat88 avatar Sep 12 '24 21:09 bigcat88