pillow-heif
| Language | Python (C extension) |
|---|---|
| License | BSD-3-Clause (the wheels bundle libheif and codecs under LGPL-3.0, and x265 under GPL-2.0) |
| Repository | github.com/bigcat88/pillow_heif |
| Documentation | pillow-heif.readthedocs.io |
| Depends on | Pillow; libheif with libde265 and x265 (bundled in the wheels) |
| Read / write | yes / yes, 8/10/12-bit, alpha, multiple images, thumbnails, depth images, Exif/XMP |
pillow-heif is a Python binding of libheif that works as a Pillow plugin. After register_heif_opener(), Image.open("photo.heic") returns a normal Pillow image and image.save("x.heic") writes HEIC. Its own HeifFile API gives access to everything else in a file: all top-level images, thumbnails, depth images, and high bit depth data as NumPy arrays.
Binary wheels for Windows, macOS and Linux include libheif with the libde265 decoder and the x265 encoder, so nothing else needs to be installed. x265 is GPL-2.0; take that into account if you distribute the wheels with your application.
Installation#
Shell
pip install pillow-heif
Basic usage: convert HEIC to JPEG#
Python
from PIL import Image
from pillow_heif import register_heif_opener
register_heif_opener() # Image.open now understands HEIC/HEIF
with Image.open("IMG_0001.heic") as im:
print(im.size, im.mode)
im.save("IMG_0001.jpg", quality=90, exif=im.info.get("exif"))
The image is already rotated according to the HEIF irot/imir properties, so don’t apply the Exif orientation again.
How to save an image as HEIC#
Python
from PIL import Image
from pillow_heif import register_heif_opener
register_heif_opener()
with Image.open("photo.png") as im:
im.save("photo.heic", quality=80) # 0-100; quality=-1 means lossless
How to convert all HEIC files in a folder#
Python
from pathlib import Path
from PIL import Image
from pillow_heif import register_heif_opener
register_heif_opener()
for path in Path("photos").glob("*.heic"):
with Image.open(path) as im:
im.save(path.with_suffix(".jpg"), quality=90, exif=im.info.get("exif"))
How to read Exif and XMP metadata#
Python
with Image.open("IMG_0001.heic") as im:
exif = im.getexif()
print(exif.get(0x0110)) # camera model
xmp = im.info.get("xmp") # bytes or None
How to read all images, thumbnails and depth maps#
Python
import pillow_heif
heif_file = pillow_heif.open_heif("IMG_0001.heic")
print("images in file:", len(heif_file))
for img in heif_file:
print(img.size, img.mode, img.info.get("primary"))
if heif_file.info["thumbnails"]:
thumb = heif_file[0].get_thumbnail(0)
thumb.to_pillow().save("thumb.jpg")
if heif_file.info["depth_images"]:
depth = heif_file.info["depth_images"][0]
depth.to_pillow().save("depth.png")
How to get 10-bit pixels as a NumPy array#
Python
import numpy as np
import pillow_heif
heif_file = pillow_heif.open_heif("hdr.heic", convert_hdr_to_8bit=False)
arr = np.asarray(heif_file) # uint16 for 10/12-bit images
print(arr.shape, arr.dtype)
Tips#
pillow_heif.is_supported("file")checks the file signature without decoding.register_heif_opener()also enables saving;Image.opendecodes lazily, so the pixels are decoded only when you access them.- For AVIF use Pillow itself: current Pillow versions read and write AVIF natively.