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

sqlalchemy-media crashed when trying to process a PNG image when the format is set to "jpeg" #136

Open
MoralCode opened this issue Dec 11, 2022 · 1 comment · May be fixed by #137
Open

Comments

@MoralCode
Copy link

MoralCode commented Dec 11, 2022

I have observed this behavior on both the demo app in the README and also the example in examples/flask (using python 3.8.X or so).

when processing a PNG (seemingly, ones that support transparency, which is probably most PNGs that exist), using an ImageProcessor that is set for fmt="jpeg", PIL is complaining that it doesnt know how to handle this without losing the transparency data.

when this happens a stack trace like this is printed:

Traceback (most recent call last):
  File "/home/ace/.local/share/virtualenvs/flask-OlzCv1Bp/lib/python3.8/site-packages/PIL/JpegImagePlugin.py", line 630, in _save
    rawmode = RAWMODE[im.mode]
KeyError: 'RGBA'

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/home/ace/.local/share/virtualenvs/flask-OlzCv1Bp/lib/python3.8/site-packages/flask/app.py", line 2525, in wsgi_app
    response = self.full_dispatch_request()
  File "/home/ace/.local/share/virtualenvs/flask-OlzCv1Bp/lib/python3.8/site-packages/flask/app.py", line 1822, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/home/ace/.local/share/virtualenvs/flask-OlzCv1Bp/lib/python3.8/site-packages/flask/app.py", line 1820, in full_dispatch_request
    rv = self.dispatch_request()
  File "/home/ace/.local/share/virtualenvs/flask-OlzCv1Bp/lib/python3.8/site-packages/flask/app.py", line 1796, in dispatch_request
    return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args)
  File "./flask_sam.py", line 105, in index
    new_person = Person(name=request.form['name'], avatar=request.files['avatar'])
  File "<string>", line 4, in __init__
  File "/home/ace/.local/share/virtualenvs/flask-OlzCv1Bp/lib/python3.8/site-packages/sqlalchemy/orm/state.py", line 576, in _initialize_instance
    manager.dispatch.init_failure(self, args, kwargs)
  File "/home/ace/.local/share/virtualenvs/flask-OlzCv1Bp/lib/python3.8/site-packages/sqlalchemy/util/langhelpers.py", line 148, in __exit__
    raise exc_value.with_traceback(exc_tb)
  File "/home/ace/.local/share/virtualenvs/flask-OlzCv1Bp/lib/python3.8/site-packages/sqlalchemy/orm/state.py", line 573, in _initialize_instance
    manager.original_init(*mixed[1:], **kwargs)
  File "/home/ace/.local/share/virtualenvs/flask-OlzCv1Bp/lib/python3.8/site-packages/sqlalchemy/orm/decl_base.py", line 1947, in _declarative_constructor
    setattr(self, k, kwargs[k])
  File "/home/ace/.local/share/virtualenvs/flask-OlzCv1Bp/lib/python3.8/site-packages/sqlalchemy/orm/attributes.py", line 531, in __set__
    self.impl.set(
  File "/home/ace/.local/share/virtualenvs/flask-OlzCv1Bp/lib/python3.8/site-packages/sqlalchemy/orm/attributes.py", line 1264, in set
    value = self.fire_replace_event(
  File "/home/ace/.local/share/virtualenvs/flask-OlzCv1Bp/lib/python3.8/site-packages/sqlalchemy/orm/attributes.py", line 1279, in fire_replace_event
    value = fn(
  File "/home/ace/.local/share/virtualenvs/flask-OlzCv1Bp/lib/python3.8/site-packages/sqlalchemy/orm/events.py", line 2348, in wrap
    return fn(target, *arg)
  File "/home/ace/.local/share/virtualenvs/flask-OlzCv1Bp/lib/python3.8/site-packages/sqlalchemy/ext/mutable.py", line 536, in set_
    value = cls.coerce(key, value)
  File "/home/ace/.local/share/virtualenvs/flask-OlzCv1Bp/lib/python3.8/site-packages/sqlalchemy_media/attachments.py", line 97, in coerce
    return cls.create_from(*value)
  File "/home/ace/.local/share/virtualenvs/flask-OlzCv1Bp/lib/python3.8/site-packages/sqlalchemy_media/attachments.py", line 115, in create_from
    return instance.attach(*args, **kwargs)
  File "/home/ace/.local/share/virtualenvs/flask-OlzCv1Bp/lib/python3.8/site-packages/sqlalchemy_media/attachments.py", line 724, in attach
    return super().attach(*args, **kwargs)
  File "/home/ace/.local/share/virtualenvs/flask-OlzCv1Bp/lib/python3.8/site-packages/sqlalchemy_media/attachments.py", line 424, in attach
    processor.process(descriptor, attachment_info)
  File "/home/ace/.local/share/virtualenvs/flask-OlzCv1Bp/lib/python3.8/site-packages/sqlalchemy_media/processors.py", line 335, in process
    img.save(output_buffer, format=format_)
  File "/home/ace/.local/share/virtualenvs/flask-OlzCv1Bp/lib/python3.8/site-packages/PIL/Image.py", line 2353, in save
    save_handler(self, fp, filename)
  File "/home/ace/.local/share/virtualenvs/flask-OlzCv1Bp/lib/python3.8/site-packages/PIL/JpegImagePlugin.py", line 632, in _save
    raise OSError(f"cannot write mode {im.mode} as JPEG") from e
OSError: cannot write mode RGBA as JPEG

the best/easiest workaround seems to be to remove the fmt parameter from the instantiation of ImageProcessor. This will keep the existing format of whatever image is uploaded by the user (assuming it wasn't rejected by the validation).

Longer term it may be better to either:

  • catch this exception and throw something more informative to the user to tell them that, for example, a non-jpeg was uploaded to an image processor that they specified as jpeg and that they should either remove this, or change their validator to catch it sooner
  • allow the ImageProcessor to handle conversion to that format (seems like there may be a bug with this, potentially related to changes in pillow). This seems to have been the initially intended behavior
@MoralCode
Copy link
Author

it seems like the unit tests, especially test_resize_reformat arent catching this because all the test images are only RGB not RGBA formatted (i.e. they dont support transparency, presumably because they may have been converted from the jpegs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
1 participant