jxlpy
jxlpy copied to clipboard
Pillow ValueError
Hi! First of all, thank you for this project! I was trying to get this to work with Pillow using the encode-decode example.
from PIL import Image
from jxlpy import JXLImagePlugin
im = Image.open('1.jxl')
im = im.resize((im.width*2, im.height*2))
im.save('test_2x.jxl', lossless=True, effort=7)
but I get the following error:
/usr/bin/python3.12 /home/barney/Documents/Programming/Random/Pillow jxl.py
Traceback (most recent call last):
File "/home/barney/Documents/Programming/Random/Pillow jxl.py", line 5, in <module>
im = im.resize((im.width*2, im.height*2))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/barney/.local/lib/python3.12/site-packages/PIL/Image.py", line 2164, in resize
self.load()
File "/home/barney/.local/lib/python3.12/site-packages/jxlpy/JXLImagePlugin.py", line 63, in load
return super().load()
^^^^^^^^^^^^^^
File "/home/barney/.local/lib/python3.12/site-packages/PIL/ImageFile.py", line 227, in load
self.im = Image.core.map_buffer(
^^^^^^^^^^^^^^^^^^^^^^
ValueError: buffer is not large enough
then I tried
from PIL import Image
from jxlpy import JXLImagePlugin
with open("1.jxl", "rb") as f:
with Image.open(f) as im:
im.show()
which results in
/usr/bin/python3.12 /home/barney/Documents/Programming/Random/Pillow jxl.py
Traceback (most recent call last):
File "/home/barney/Documents/Programming/Random/Pillow jxl.py", line 6, in <module>
im.show()
File "/home/barney/.local/lib/python3.12/site-packages/PIL/Image.py", line 2494, in show
_show(self, title=title)
File "/home/barney/.local/lib/python3.12/site-packages/PIL/Image.py", line 3539, in _show
ImageShow.show(image, **options)
File "/home/barney/.local/lib/python3.12/site-packages/PIL/ImageShow.py", line 62, in show
if viewer.show(image, title=title, **options):
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/barney/.local/lib/python3.12/site-packages/PIL/ImageShow.py", line 86, in show
return self.show_image(image, **options)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/barney/.local/lib/python3.12/site-packages/PIL/ImageShow.py", line 113, in show_image
return self.show_file(self.save_image(image), **options)
^^^^^^^^^^^^^^^^^^^^^^
File "/home/barney/.local/lib/python3.12/site-packages/PIL/ImageShow.py", line 109, in save_image
return image._dump(format=self.get_format(image), **self.options)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/barney/.local/lib/python3.12/site-packages/PIL/Image.py", line 604, in _dump
self.save(filename, format, **options)
File "/home/barney/.local/lib/python3.12/site-packages/PIL/Image.py", line 2439, in save
save_handler(self, fp, filename)
File "/home/barney/.local/lib/python3.12/site-packages/PIL/PngImagePlugin.py", line 1224, in _save_all
_save(im, fp, filename, save_all=True)
File "/home/barney/.local/lib/python3.12/site-packages/PIL/PngImagePlugin.py", line 1237, in _save
for im_frame in ImageSequence.Iterator(im_seq):
File "/home/barney/.local/lib/python3.12/site-packages/PIL/ImageSequence.py", line 56, in __next__
self.im.seek(self.position)
File "/home/barney/.local/lib/python3.12/site-packages/jxlpy/JXLImagePlugin.py", line 41, in seek
raise NotImplementedError(
NotImplementedError: Seeking more than one frame forward is currently not supported.
Any help would be appreciated! Thanks!
Hello, Thank you for reporting this issue. The first part about the buffer error seems to be more related to Pillow itself. see here Could you please try doing the same with non-jxl image to verify that?
I was able to replicate your second issue. It seems to be a bug in jxlpy
Pillow integration.
This line in JXLImagePlugin
obviously should also take into consideration user seeking to the same frame. I changed that but from what I can tell, Pillow for some reason tries to seek to next frame which doesn't exist when calling im.show()
. This confuses jxlpy
as it doesn't know how many frames does a jxl image have until its fully decoded. I've also ran into issues where Pillow is getting stuck in a loop seeking frame by frame up to infinity.
When calling im.save()
everything seems fine and Pillow doesn't issue unnecessary seeks.
I will probably take a look at it tomorrow.
Thank you for taking a look!
Using .png
instead of .jxl
from PIL import Image
from jxlpy import JXLImagePlugin
im = Image.open('1.png')
im = im.resize((im.width*2, im.height*2))
im.save('test_2x.jxl', lossless=True, effort=7)
the above works as intended^ :D
Hi again,
Sorry for my late response. I am still not sure what's going on with this ValueError: buffer is not large enough
issue.
However I discovered that Pillow tries to seek back to the first frame when doing .show()
. If the image was opened before this means it needs to go backwards to the beginning of already loaded image. .show()
tries to save the image with save_all=True
which is why all frames are being saved.
I'm currently in a process of getting jxl
support into Pillow via libjxl and Python C API. I was successful in implementing frame seeking there. There's JxlDecoderRewind
method in libjxl which makes it easy. However a bigger problem is to know the number of frames in the picture in advance. It isn't specified in libjxl bitstream however it's possible to know that image is animated (JxlBasicInfo.have_animation
). Without knowing how many frames there are Pillow will just hang iterating over non-existent frames when save
is called with save_all
.
Probably the best solution would be to count all JXL_DEC_FRAME
events when opening the image and then set n_frames
accordingly.
In jxlpy
it would probably be necessary to decode all frames first, then rewind and set number of frames for Pillow to work with.
I'm pretty sure save_all
was working before so maybe there was a change in how Pillow handles it now (it doesn't call ImageFile.load()
, only seeking).
Hi! Please try the most recent version of jxlpy. I think I figured out the issue.
Hi! Thanks for looking into it I tried it with jxlpy version 0.9.4, and Pillow no longer recognises jxl images. for both
from PIL import Image
from jxlpy import JXLImagePlugin
with open("1.jxl", "rb") as f:
with Image.open(f) as im:
im.show()
and
from PIL import Image
from jxlpy import JXLImagePlugin
im = Image.open('1.jxl')
im = im.resize((im.width*2, im.height*2))
im.save('test_2x.jxl', lossless=True, effort=7)
I get the following error:
/usr/bin/python3.12 /home/barney/Documents/Programming/Random/Pillow jxl.py
Traceback (most recent call last):
File "/home/barney/Documents/Programming/Random/Pillow jxl.py", line 5, in <module>
with Image.open(f) as im:
^^^^^^^^^^^^^
File "/home/barney/.local/lib/python3.12/site-packages/PIL/Image.py", line 3298, in open
raise UnidentifiedImageError(msg)
PIL.UnidentifiedImageError: cannot identify image file <_io.BufferedReader name='1.jxl'>
Hi, I honestly have no idea what might be going on now. I've tested jxlpy from PyPI on Python 3.12 and it seems to work fine with Pillow. Could you tell me what OS are you using? Maybe also what's your input image? Could you please test once again on different set of images for example from jpegxl.info.
I'm using Linux (fedora 39), and I tested it on 3 different images, same error on all of them. However, after updating Pillow as well (from 9.5.0 to 10.2.0), it now works 🥳
I have no idea why 9.5.0 didn't recognise the image, maybe there's something in the plugin that's not compatible? In any case, it might be worth noting in the readme that if somebody encounters that error, they should make sure that Pillow is up to date.
Thank you for the fix!