Pillow Plugin¶
For using it as a Pillow plugin, refer to Pillow’s documentation:
Pillow Tutorial
and to examples started with pillow_
.
Here are described only some differences and peculiarities.
Registering plugin¶
There are two ways to register it as a plugin, here are both of them:
Automatic¶
from PIL import Image, ImageFilter
from pillow_heif import HeifImagePlugin
with Image.open("image.heic") as im:
im.filter(filter=ImageFilter.BLUR).save("blurred_image.heic")
Manual¶
from PIL import Image
from pillow_heif import register_heif_opener
register_heif_opener()
with Image.open("image.heic") as im:
im.rotate(45).save("rotated_image.heic")
AVIF plugin¶
AVIF
plugin can be registered the same way as HEIF
:
from pillow_heif import register_avif_opener
register_avif_opener()
AVIF
plugin should support all operations and work the same way as HEIF
plugin do.
Tips & Tricks¶
If you do not need HEIF thumbnails functionality, then it is a good idea to disable them during plugin registration:
register_heif_opener(thumbnails=False)
Remember, then you can pass multiply config values to register_heif_opener()
at once:
register_heif_opener(thumbnails=False, quality=-1)
Note
register_avif_opener()
works in the same way.
Image Modes¶
Currently all images are opened in RGB
or RGBA
8 bit modes.
There is a restriction in libheif
that we cant check before decoding if an image is monochrome
or not.
See Modes for a list of supported modes for saving.
Metadata¶
Available metadata are stored in info
dictionary as in other Pillow plugins.
It is the same as in HeifImage
class.
During saving operation all known metadata in info
dictionary are saved.
So it can be edited in place.
Removing EXIF and XMP information inside info
dictionary:
image = Image.open(Path("test.heic"))
image.info["exif"] = None
image.info["xmp"] = None
image.save("output.heic")
Removing EXIF and XMP specifying them when calling save
:
image = Image.open(Path("test.heic"))
image.save("output.heic", exif=None, xmp=None)
Limitations of second code variant is that when file has multiply images inside,
setting exif
or xmp
during save
affects only Primary(Main) image and not all images.
To edit metadata of all images in a file just iterate throw all images and change metadata in place.
Here are two ways as an example:
Edit info["exif"]
field of each copy of image:
heic_pillow = Image.open(Path("test.heic"))
output_wo_exif = []
for frame in ImageSequence.Iterator(heic_pillow):
copied_frame = frame.copy()
copied_frame.info["exif"] = None
output_wo_exif.append(copied_frame)
empty_pillow = Image.new("P", (0, 0))
empty_pillow.save("no_exif.heic", save_all=True, append_images=output_wo_exif)
Or editing info["exif"]
in place:
heic_pillow = Image.open(Path("test.heic"))
for frame in ImageSequence.Iterator(heic_pillow):
frame.info["exif"] = None
heic_pillow.save("no_exif.heic", save_all=True)
Save operation¶
For HEIF next extensions are registered: .heic
, .heics
, .heif
, .heifs
and .hif
For AVIF registered extensions are: .avif
Also images can be saved to memory, using format
parameter:
output_buffer = BytesIO()
with Image.open("image.heic") as im:
im.save(output_buffer, format="HEIF")
See here Save parameters for additional information.
Changing order of images¶
There is no such easy way to change order as for HeifFile usage, but the standard Pillow way to do so looks fine. Let’s create image where second image will be primary:
img1 = Image.open(Path("images/jpeg_gif_png/1.png"))
img2 = Image.open(Path("images/jpeg_gif_png/2.png"))
img3 = Image.open(Path("images/jpeg_gif_png/3.png"))
img1.save("1_2P_3.heic", append_images=[img2, img3], save_all=True, primary_index=1, quality=-1)
Now as example lets change primary image in a HEIC file:
img1 = Image.open(Path("1_2P_3.heic"))
img1.save("1_2_3P.heic", save_all=True, primary_index=-1, quality=-1)
Note
As a primary
field are in info dictionary, you can change it in a place like with metadata before.
And here is an example how we can change order of images in container:
src_img = Image.open(Path("1_2_3P.heic"))
img3 = ImageSequence.Iterator(src_img)[2].copy()
img2 = ImageSequence.Iterator(src_img)[1].copy()
img1 = ImageSequence.Iterator(src_img)[0].copy()
img3.save("3P_1_2.heic", save_all=True, append_images=[img1, img2], quality=-1)