wagtail / Willow

A wrapper that combines the functionality of multiple Python image libraries into one API
https://willow.wagtail.org/
BSD 3-Clause "New" or "Revised" License
273 stars 53 forks source link

Inaccurate colors / broken WEBP/AVIF/HEIC images with specific image files #139

Closed Stormheg closed 8 months ago

Stormheg commented 8 months ago

A client uploaded some images to their Wagtail site and reported these images failed to load on the site or displayed with inaccurate colors.

The images in question all meet the following conditions:

Willow fails to handle images that meet the above conditions correctly.

I took me quite a while to figure out why this is happening, but here is what I believe to be happening:

The AVIF, HEIC and WEBP Pillow encoders don't support CMYK. Before the image can be saved in those formats, it has to be converted to RGB first. This conversion fails to take into account the color profile.

Screenshot 2023-12-13 at 2 28 56 PM

Here is a screenshot comparison of the color issue. On the left is the original image, on the right is the WEBP rendition created using Pillow 1.6.3. It is subtle, but if you pay close attention you can see the WEBP version has somewhat brighter colors. This is most noticable around the headlamp and the lens flare near the hand.

For AVIF and HEIC specifically, the resulting file fails to display at all. Something funky has happened corrupting the image. No error is thrown however.

I've been experimenting with my fork of Willow and have found that forcing a conversion to sRGB color space (and implicitly to RGB) using Pillows' ImageCms.profileToProfile before saving works very well. The result looks much, much, closer to the original image (if rendering_intent=perceptual is used). The aforementioned issue with AVIF and HEIC is also fixed by this.

transform_colorspace_to_srgb operation

As part of my fix, I've been working on a general transform_colorspace_to_srgb operation for Willow. The idea behind this is that most devices cannot display colors outside of sRGB and perform some sort of transformation to sRGB already when confronted with wide-gamut images (like DCI-P3 or Adobe RGB). This operation allows performing this transformation upfront which in turn allows the profile to be removed, resulting in a smaller image file.

I think it makes sense to make this functionality available in Willow. Maybe Wagtail could use this operation in the future to create even smaller image renditions.

The downside of course is that this is lossy operation, devices that can display color spaces like DCI-P3 get an image with less color but that seems like a reasonable trade-off for the majority which cannot. I guess there could always be a setting in Wagtail to disable this behaviour or make it a different kind of rendition filter or something.

Issue #114 relates to this.

PS: @andre-fuchs, reading #114, you seem to know a lot about this stuff. Feel free to chip in and correct any inaccuracies. Color profiles and color spaces are not my area of expertise. Though I certainly learned a lot in the past two weeks!


I'll submit a PR with my transform_colorspace_to_srgb operation and fix soon.

andre-fuchs commented 8 months ago

Forcing a conversion to sRGB for all CMYK images seems reasonable to me. It would be nice to have a warning message in the upload form as well to inform about this. Something like:

"Warning: CMYK color mode not supported. This image was converted to the RGB color mode with the sRGB color profile. Learn more"

On "Learn more" should be a link to the documentation with some background information. Many editors won’t know about these color models.

Stormheg commented 8 months ago

Thanks for taking the time to review and reply @andre-fuchs.

I agree it would be nice to warn editors that there may be 'gotchas' with their file, but I don't believe there is currently such a mechanism available for that in Wagtail / Willow. If there are more gotchas than just this instance I think the case for adding such a mechanism would be a lot stronger.

Stormheg commented 8 months ago

I've finally found the time to prepare a fix + tests, see #142!

zerolab commented 8 months ago

Fixed in #142