Skip to content

Commit

Permalink
Add support for AVIF
Browse files Browse the repository at this point in the history
  • Loading branch information
salty-ivy authored and zerolab committed Jul 8, 2023
1 parent 53dd5a4 commit 5b62f87
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 2 deletions.
2 changes: 2 additions & 0 deletions willow/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ def setup():
from xml.etree import ElementTree

from willow.image import (
AvifImageFile,
BMPImageFile,
GIFImageFile,
HeicImageFile,
Expand All @@ -31,6 +32,7 @@ def setup():
registry.register_image_class(RGBAImageBuffer)
registry.register_image_class(SvgImageFile)
registry.register_image_class(SvgImage)
registry.register_image_class(AvifImageFile)

registry.register_plugin(pillow)
registry.register_plugin(wand)
Expand Down
12 changes: 12 additions & 0 deletions willow/image.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ def save(self, image_format, output):
"webp",
"svg",
"heic",
"avif",
]:
raise ValueError("Unknown image format: %s" % image_format)

Expand Down Expand Up @@ -264,6 +265,16 @@ def mime_type(self):
return "image/heiс"


class AvifImageFile(ImageFile):
@property
def format_name(self):
return "avif"

@property
def mime_type(self):
return "image/avif"


INITIAL_IMAGE_CLASSES = {
# A mapping of image formats to their initial class
image_types.Jpeg().extension: JPEGImageFile,
Expand All @@ -274,4 +285,5 @@ def mime_type(self):
image_types.Webp().extension: WebPImageFile,
"svg": SvgImageFile,
image_types.Heic().extension: HeicImageFile,
image_types.Avif().extension: AvifImageFile,
}
12 changes: 11 additions & 1 deletion willow/plugins/pillow.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
try:
from pillow_heif import HeifImagePlugin # noqa: F401
from pillow_heif import AvifImagePlugin, HeifImagePlugin # noqa: F401
except ImportError:
pass

from willow.image import (
AvifImageFile,
BadImageOperationError,
BMPImageFile,
GIFImageFile,
Expand Down Expand Up @@ -227,6 +228,14 @@ def save_as_heic(self, f, quality=80, lossless=False):
self.image.save(f, "HEIF", quality=quality)
return HeicImageFile(f)

@Image.operation
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)
return AvifImageFile(f)

@Image.operation
def auto_orient(self):
# JPEG files can be orientated using an EXIF tag.
Expand Down Expand Up @@ -279,6 +288,7 @@ def get_pillow_image(self):
@Image.converter_from(TIFFImageFile)
@Image.converter_from(WebPImageFile)
@Image.converter_from(HeicImageFile)
@Image.converter_from(AvifImageFile)
def open(cls, image_file):
image_file.f.seek(0)
image = _PIL_Image().open(image_file.f)
Expand Down
23 changes: 22 additions & 1 deletion willow/plugins/wand.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from ctypes import c_char_p, c_void_p

from willow.image import (
AvifImageFile,
BadImageOperationError,
BMPImageFile,
GIFImageFile,
Expand Down Expand Up @@ -170,7 +171,6 @@ def save_as_gif(self, f):
@Image.operation
def save_as_webp(self, f, quality=80, lossless=False):
with self.image.convert("webp") as converted:
converted.compression_quality = quality
if lossless:
library = _wand_api().library
library.MagickSetOption.argtypes = [c_void_p, c_char_p, c_char_p]
Expand All @@ -179,10 +179,30 @@ def save_as_webp(self, f, quality=80, lossless=False):
b"webp:lossless",
b"true",
)
else:
converted.compression_quality = quality
converted.save(file=f)

return WebPImageFile(f)

@Image.operation
def save_as_avif(self, f, quality=80, lossless=False):
with self.image.convert("avif") as converted:
if lossless:
converted.compression_quality = 100
library = _wand_api().library
library.MagickSetOption.argtypes = [c_void_p, c_char_p, c_char_p]
library.MagickSetOption(
converted.wand,
b"heic:lossless",
b"true",
)
else:
converted.compression_quality = quality
converted.save(file=f)

return AvifImageFile(f)

@Image.operation
def auto_orient(self):
image = self.image
Expand Down Expand Up @@ -230,6 +250,7 @@ def get_wand_image(self):
@Image.converter_from(TIFFImageFile, cost=150)
@Image.converter_from(WebPImageFile, cost=150)
@Image.converter_from(HeicImageFile, cost=150)
@Image.converter_from(AvifImageFile, cost=150)
def open(cls, image_file):
image_file.f.seek(0)
image = _wand_image().Image(file=image_file.f)
Expand Down

0 comments on commit 5b62f87

Please sign in to comment.