Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pillow ValueError #22

Open
BigBoyBarney opened this issue Feb 18, 2024 · 7 comments
Open

Pillow ValueError #22

BigBoyBarney opened this issue Feb 18, 2024 · 7 comments

Comments

@BigBoyBarney
Copy link

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!

@olokelo
Copy link
Owner

olokelo commented Feb 18, 2024

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.

@BigBoyBarney
Copy link
Author

BigBoyBarney commented Feb 18, 2024

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

@olokelo
Copy link
Owner

olokelo commented Feb 21, 2024

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

@olokelo
Copy link
Owner

olokelo commented Mar 2, 2024

Hi!
Please try the most recent version of jxlpy. I think I figured out the issue.

@BigBoyBarney
Copy link
Author

BigBoyBarney commented Mar 2, 2024

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'>

@olokelo
Copy link
Owner

olokelo commented Mar 2, 2024

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.

@BigBoyBarney
Copy link
Author

BigBoyBarney commented Mar 2, 2024

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!

This was referenced May 2, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants