Skip to content

Conversation

@olokelo
Copy link

@olokelo olokelo commented Mar 2, 2024

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 olokelo mentioned this pull request Mar 2, 2024
@brunoais
Copy link

brunoais commented Mar 2, 2024

May you please commit the images as LFS?

@olokelo
Copy link
Author

olokelo commented Mar 2, 2024

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

@brunoais
Copy link

brunoais commented Mar 3, 2024

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.

@radarhere radarhere added the JPEG label Mar 11, 2024
@olokelo
Copy link
Author

olokelo commented Mar 11, 2024

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.

"IptcImagePlugin",
"JpegImagePlugin",
"Jpeg2KImagePlugin",
"JxlImagePlugin",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Naming things: like other plugins, shall we use the name of the format rather than the extension?

Suggested change
"JxlImagePlugin",
"JpegXlImagePlugin",

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a good point. Not sure why I decided to go with "jxl" from the beginning.
Would you want me to change all the references to jxl (including tests, function/class names, feature.jxl) or only plugin and .c extension filename?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think let's just use jxl for the filename extension (so the Tests/images/jxl/) dir is fine too) and of course the MIME type, and change the rest.

# jpeg xl does some weird shenanigans when storing exif
# it omits first 6 bytes of tiff header but adds 4 byte offset instead
if len(exif) <= 4:
return None
Copy link
Member

@hugovk hugovk Mar 19, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add a test case for this and _getexif?

@hugovk
Copy link
Member

hugovk commented Mar 19, 2024

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

@olokelo
Copy link
Author

olokelo commented Mar 19, 2024

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.

@j99ca
Copy link

j99ca commented Jun 25, 2025

@radarhere couple of questions:

  1. Will this decoding allow us to decode float32 JXL images? This is important for us as JXL files are great for scientific data (depth, thermal, etc)
  2. Is there any chance that PIL will be able to extract the metadata that might be included in the JXL image, like XMP?

@radarhere
Copy link
Member

  1. The first commit here left a comment in the C file that 'PIL doesn't support high bit depth images'. I don't know what the thinking was there - in general, Pillow does support single channel 32-bit float images. Perhaps that specific depth just wasn't added.

  2. EXIF and XMP data can be extracted with this PR, yes.

@j99ca
Copy link

j99ca commented Nov 19, 2025

@radarhere is there any movement on this PR?

Currently a Rust version of the libjxl library is being implemented and looks like it's going to end up in Firefox, and Adobe is planning on adding support for JXL for PDFs as well (see the this interop discussion)

@radarhere
Copy link
Member

Mostly, lack of movement is just due to not having an overabundance of time. I have asked some questions in comments here, and have asked a question about this at libjxl/libjxl#4400, but haven't received useful advice. Sooner or later, I will probably just move things along anyway though.


jpegxl = feature.get("jpegxl")
if isinstance(jpegxl, str):
# jxl and jxl_threads are required
Copy link
Member

@radarhere radarhere Nov 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would have thought that jxl_threads should be an optional extra, not a requirement? If it's only purpose is to speed things up, then if a user has jxl present on their system but not jxl_threads, then that doesn't sound like we should stop them from using the jxl library.

@radarhere radarhere force-pushed the jxl-support2 branch 3 times, most recently from 16264dd to 4d60d9c Compare November 26, 2025 12:08
@hyperion4
Copy link

@radarhere is there any movement on this PR?

Currently a Rust version of the libjxl library is being implemented and looks like it's going to end up in Firefox, and Adobe is planning on adding support for JXL for PDFs as well (see the this interop discussion)

Not only that, Google seems now to "consider" to add JXL back to Chrome.

https://groups.google.com/a/chromium.org/g/blink-dev/c/WjCKcBw219k/m/NmOyvMCCBAAJ

They will add it, they just try to save face right now by talking nonsense about now seeing "developer signals".
With Apple and now Adobe also supporting it they have no choice anymore and we all know why they tried to bury JXL.
I hope JXL to be added to PIL as soon as possible.

@radarhere radarhere force-pushed the jxl-support2 branch 2 times, most recently from 42a1b66 to 285c9ad Compare December 6, 2025 12:03
@radarhere radarhere force-pushed the jxl-support2 branch 2 times, most recently from d39ea8d to 6219234 Compare December 13, 2025 05:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.