-
Notifications
You must be signed in to change notification settings - Fork 53
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
AVIF support #115
AVIF support #115
Conversation
@thibaudcolas I have opened a draft, only tests are left although I am not sure about |
Thanks @salty-ivy 👏 It makes me very happy to see AVIF support added to Wagtail. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking really solid @salty-ivy! This is going to be such a big change for us 🥳 @zerolab could you review this as well as we discussed?
I gave it a try and it worked a treat. There are a few things to change in the code and as you noted documentation (README, reference.rst
).
I think we should additionally add save_as_heic
to the README – and mention for it and save_as_avif
that they’re only available in Pillow for people who install pillow-heif
.
Record of my trial for future ref, with walnuts.jpg
from our bakerydemo.
source = open('tests/images/walnuts.jpg', 'rb')
out_avif = open('walnuts.avif', 'wb')
out_webp = open('walnuts.webp', 'wb')
source_img = Image.open(source)
source_img.save_as_webp(out_webp)
source_img.save_as_avif(out_avif)
out_webp.close()
out_avif.close()
out_avif_40 = open('walnuts-40.avif', 'wb')
out_webp_40 = open('walnuts-40.webp', 'wb')
source_img.save_as_avif(out_avif_40, quality=40)
out_avif_40.close()
source_img.save_as_webp(out_webp_40, quality=40)
out_webp_40.close()
File sizes (rounded) for ref:
192K tests/images/walnuts.jpg
40K walnuts-40.avif
60K walnuts-40.webp
160K walnuts.avif
128K walnuts.webp
willow/image.py
Outdated
@@ -252,6 +252,7 @@ def __init__(self, f, dom=None): | |||
self.dom = ElementTree.parse(f) | |||
f.seek(0) | |||
else: | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should we go for chroma=420
default way? then.
willow/plugins/pillow.py
Outdated
def save_as_avif(self, f, quality=80, lossless=False): | ||
if lossless: | ||
self.image.save(f, 'AVIF', quality=-1, chroma=444) | ||
else: | ||
self.image.save(f, 'AVIF', quality=quality) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might be one for later but I’m surprised we’d not make the chroma subsampling configurable 🤔 I don’t know whether the default is 4:2:2
or 4:2:0
but I could imagine scenarios where we’d want to change it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
note to self: https://pillow-heif.readthedocs.io/en/latest/options.html mentions chroma=444 is to be using lossless encoding.
there's no stopping us from doing
@Image.operation
def save_as_avif(self, f, quality=80, lossless=False, chroma: int = 420):
if lossless:
self.image.save(f, 'AVIF', quality=-1, chroma=444)
else:
self.image.save(f, 'AVIF', quality=quality, chroma=chroma)
at the same time, we will want to document some best practices on chroma and to be honest this is not something I fully understand (yet)
Found https://github.com/bigcat88/pillow_heif/blob/891d3fcef08eb03066f557ccef8fdc2492fd1c40/CHANGELOG.md?plain=1#L191 which mentions 420 (4:2:0
) is the default
It would be good to document the quality kwarg, and what the different values mean (Possible values: None, -1, range(0-100). Set -1 for lossless quality or from 0 to 100, where 0 is lowest and 100 is highest.)
If we are to support pillow-avif-plugin as an alternative to pillow-heif, then this becomes more complicated - https://github.com/fdintino/pillow-avif-plugin/blob/master/src/pillow_avif/AvifImagePlugin.py#L130-L137. The latter plugin has a corresponding PR for Pillow - python-pillow/Pillow#5201
Also this considering this comment by @mrchrisadams wagtail/wagtail#10486 (comment) should we try to save them as |
We don't do this for any other types, so.. no. Only for the original rendition in Wagtail |
In addition, it would be good to add a note about lossless AVIF in Lines 49 to 58 in 4eac48a
|
@zerolab apologies if the question is too obvious but are we supporting |
That is what https://github.com/wagtail/Willow/pull/115/files#diff-a804be079e5771c0e82b11e493ad11d319d34d042b33871a729f5eb151ace339R228-R229 does, no? |
yup, I thought by default that Is default value.
Yes I thought of it as default( default argument to |
@zerolab @thibaudcolas Could you guys confirm or have any idea.
seems to be originating from |
@Image.operation | ||
def save_as_avif(self, f, quality=80, lossless=False): | ||
if lossless: | ||
self.image.save(f, "AVIF", quality=-1, chroma=444) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nitpick: since we're basing this on pillow-heif, it would be great to document what these magic values mean
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
also, we need an entry about lossless AVIF at https://github.com/wagtail/Willow/blob/main/docs/guide/save.rst?plain=1#L49
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the lossless save test for Avif is failing for some reason need to look at that as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking at pillow_heif, they admit a small variation of about 1%
https://github.com/bigcat88/pillow_heif/blob/master/tests/write_test.py#L415-L422 and https://github.com/bigcat88/pillow_heif/blob/3798f0df6b12c19dfa8fd76dd6259b329bf88029/tests/helpers.py#L39-L48
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is so close, needs a bit more documentation and I think we're good
@zerolabn both |
@salty-ivy will have a look later today and advise on next steps |
Few finale questions....
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added further suggestions.
I am not sure why the webp test fails locally yet, but will check and get to you later
docs/guide/save.rst
Outdated
----------------- | ||
|
||
You can encode the image to WebP without any loss by setting the | ||
You can encode the image to Avif, Heic (only pillow) and WebP without any loss by setting the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can encode the image to Avif, Heic (only pillow) and WebP without any loss by setting the | |
You can encode the image to AVIF, HEIC (Pillow-only) and WebP without any loss by setting the |
note that ImageMagick (thus Wand) supports HEIC via libheif since version 7.1.0. Opened #119
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we can change the docs further in that PR, would you mind if I take up that issue as well?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Happy for you to take it on, once this and the Wagtail continuation are done
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @salty-ivy as discussed, I've had a quick look over this - I only saw a few small typos, but I had one qn - if one of the benefits of the AVIF support is that the files are smaller, do you think it might be worth having a test to demontrate this?
I know it's venturing into testing the properties of format rather than the library implementing it, but it may be useufl to demonstrating the benefits it's supposed to bring,.
@mrchrisadams That's a great idea! How about having a test where where we open one format and check the size and then save as Avif and assert the new size to be smaller ? Or something like that if I have understood it correctly? |
hi @salty-ivy - yes, that was what I was thinking. I was a bit wary that it might go outside the scope of adding support, so I would defer to the maintainers. Hope that helps! |
Co-Authored-By: zerolab <[email protected]>
A few notes on avif/webp conversion using ImageMagick: convert tests/images/transparent.png -define heic:lossless=true tests/images/lossless.avif
magick compare tests/images/transparent.png tests/images/lossless.avif -compose Src tests/images/compare-avif.png
convert tests/images/tree.avif -define heic:lossless=true tests/images/lossless.avif
magick compare tests/images/tree.avif tests/images/lossless.avif -compose Src tests/images/compare.avif and convert tests/images/transparent.png -define webp:lossless=true tests/images/lossless.webp
# or
convert tests/images/transparent.png -define webp:lossless=true -define webp:exact=true tests/images/lossless.webp
magick compare tests/images/transparent.png tests/images/lossless.webp -compose Src tests/images/compare-webp.png
convert tests/images/tree.avif -define heic:lossless=true tests/images/lossless.avif
magick compare tests/images/tree.avif tests/images/lossless.avif -compose Src tests/images/compare.avif will show some artifacts, depending on the ImageMagick version. Which explain the test failures. Anyhow, this now looks good. Thank you for all your work, @salty-ivy! And everyone for your inputs |
Yay! Thanks all for your work! ❤️ |
Fixed #111
Before
After