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

Thumbnailing CMYK colorspace image gives Internal Server Error #10741

Open
matrixbot opened this issue Dec 19, 2023 · 1 comment · May be fixed by #17736
Open

Thumbnailing CMYK colorspace image gives Internal Server Error #10741

matrixbot opened this issue Dec 19, 2023 · 1 comment · May be fixed by #17736

Comments

@matrixbot
Copy link
Collaborator

matrixbot commented Dec 19, 2023

This issue has been migrated from #10741.


When a jpeg image using the CMYK colorspace is uploaded to synapse, any attempts to get a thumbnail with the /media/r0/thumbnail endpoint return Internal Server Error. The logs contain the following exception:

synapse.http.server - 93 - ERROR - GET-393903 - Failed handle request via 'ThumbnailResource': <XForwardedForRequest at 0xffff176a5e20 method='GET' uri='/_matrix/media/r0/thumbnail/alephc.xyz/onBfeogmWNGmprAkaswiXiOC?width=64&height=64&method=crop' clientproto='HTTP/1.1' site='8008'>
Traceback (most recent call last):
  File "/home/synapse/synapse/env/lib/python3.8/site-packages/PIL/PngImagePlugin.py", line 1230, in _save
    rawmode, mode = _OUTMODES[mode]
KeyError: 'CMYK'
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
  File "/home/synapse/synapse/env/lib/python3.8/site-packages/synapse/http/server.py", line 258, in _async_render_wrapper
    callback_return = await self._async_render(request)
  File "/home/synapse/synapse/env/lib/python3.8/site-packages/synapse/http/server.py", line 286, in _async_render
    callback_return = await raw_callback_return
  File "/home/synapse/synapse/env/lib/python3.8/site-packages/synapse/rest/media/v1/thumbnail_resource.py", line 69, in _async_render_GET
    await self._select_or_generate_local_thumbnail(
  File "/home/synapse/synapse/env/lib/python3.8/site-packages/synapse/rest/media/v1/thumbnail_resource.py", line 170, in _select_or_generate_local_thumbnail
    file_path = await self.media_repo.generate_local_exact_thumbnail(
  File "/home/synapse/synapse/env/lib/python3.8/site-packages/synapse/rest/media/v1/media_repository.py", line 535, in generate_local_exact_thumbnail
    t_byte_source = await defer_to_thread(
  File "/home/synapse/synapse/env/lib/python3.8/site-packages/twisted/python/threadpool.py", line 238, in inContext
    result = inContext.theWork()  # type: ignore[attr-defined]
  File "/home/synapse/synapse/env/lib/python3.8/site-packages/twisted/python/threadpool.py", line 254, in <lambda>
    inContext.theWork = lambda: context.call(  # type: ignore[attr-defined]
  File "/home/synapse/synapse/env/lib/python3.8/site-packages/twisted/python/context.py", line 118, in callWithContext
    return self.currentContext().callWithContext(ctx, func, *args, **kw)
  File "/home/synapse/synapse/env/lib/python3.8/site-packages/twisted/python/context.py", line 83, in callWithContext
    return func(*args, **kw)
  File "/home/synapse/synapse/env/lib/python3.8/site-packages/synapse/logging/context.py", line 902, in g
    return f(*args, **kwargs)
  File "/home/synapse/synapse/env/lib/python3.8/site-packages/synapse/rest/media/v1/media_repository.py", line 501, in _generate_thumbnail
    return thumbnailer.crop(t_width, t_height, t_type)
  File "/home/synapse/synapse/env/lib/python3.8/site-packages/synapse/rest/media/v1/thumbnailer.py", line 152, in crop
    return self._encode_image(cropped, output_type)
  File "/home/synapse/synapse/env/lib/python3.8/site-packages/synapse/rest/media/v1/thumbnailer.py", line 159, in _encode_image
    output_image.save(output_bytes_io, fmt, quality=80)
  File "/home/synapse/synapse/env/lib/python3.8/site-packages/PIL/Image.py", line 2235, in save
    save_handler(self, fp, filename)
  File "/home/synapse/synapse/env/lib/python3.8/site-packages/PIL/PngImagePlugin.py", line 1232, in _save
    raise OSError(f"cannot write mode {mode} as PNG") from e
OSError: cannot write mode CMYK as PNG

Accessing the image via the /media/r0/download endpoint does not have any issue.

I have attached a small image that exhibits the issue, otherwise one can be created by taking any jpeg and using image magick: convert in.jpg -colorspace cmyk.jpg

Version & Config Info

Synapse: 1.41.1, with dynamic_thumbnails: true
Python: 3.8.10
Pillow: 8.3.1
Running on Ubuntu 20.04

Test Image

cmyk

@matrixbot matrixbot changed the title Dummy issue Thumbnailing CMYK colorspace image gives Internal Server Error Dec 21, 2023
@matrixbot matrixbot reopened this Dec 21, 2023
@wolfspyre
Copy link

wolfspyre commented Jul 13, 2024

the related upstream library issue: python-pillow/Pillow#1380
the application-side solution to this (png doesn't support the cymk colorspace)
is to bolt this logic in:

if image_file.mode == "CMYK":
    image_file = image_file.convert("RGB")

which would resolve the problem within the mediaserver component.

mweinelt added a commit to mweinelt/synapse that referenced this issue Sep 20, 2024
The PNG format does not support non-RGB color spaces, which makes pillow
raise an exception when trying to save e.g. a CMYK image in PNG format.

Converting to RGB is recommended on the upstream issue, and as CMYK is a
print format transparency does not need to be considered.

Closes: element-hq#10741
@mweinelt mweinelt linked a pull request Sep 20, 2024 that will close this issue
3 tasks
mweinelt added a commit to mweinelt/synapse that referenced this issue Sep 20, 2024
The PNG format does not support non-RGB color spaces, which makes pillow
raise an exception when trying to save e.g. a CMYK image in PNG format.

Converting to RGB is recommended on the upstream issue, and as CMYK is a
print format transparency does not need to be considered.

Closes: element-hq#10741
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants