pyvips
| Language | Python |
|---|---|
| License | MIT (libvips: LGPL-2.1) |
| Repository | github.com/libvips/pyvips |
| Documentation | pyvips docs, heifsave options |
| Depends on | libvips built with libheif; libheif with libde265 (decode) and x265 (encode) |
| Read / write | yes / yes, 8/10/12-bit, alpha, multiple images, thumbnails |
pyvips is the Python binding of libvips, which processes images in a streaming way: fast, low memory, and good for converting many phone photos or generating thumbnails on a server. HEIC goes through libheif.
HEIC support depends on how libvips and libheif were built. The prebuilt pyvips-binary wheels and the Windows libvips builds include libheif without an HEVC decoder (only AV1, for AVIF), so they can’t open HEIC. Use a system libvips: Homebrew’s vips and Linux packages with the libheif HEVC plugins work. Check with vips heifload IMG_0001.heic x.jpg.
Installation#
# Debian / Ubuntu
sudo apt install libvips-dev libheif-plugin-libde265 libheif-plugin-x265
pip install pyvips
# macOS
brew install vips && pip install pyvips
Basic usage: convert HEIC to JPEG#
import pyvips
image = pyvips.Image.new_from_file("IMG_0001.heic")
print(image.width, image.height, image.bands)
image.write_to_file("IMG_0001.jpg", Q=90)
libheif applies the rotation stored in the file, so the result is already upright.
How to make a thumbnail from a HEIC photo#
thumbnail can use the small preview image stored in the file when it is big enough, which is much faster than decoding the full photo:
thumb = pyvips.Image.thumbnail("IMG_0001.heic", 400) # fit in 400 x 400
thumb.write_to_file("thumb.jpg", Q=85)
How to save an image as HEIC#
image = pyvips.Image.new_from_file("photo.png")
image.heifsave("photo.heic", Q=50, compression="hevc") # Q 50 is about JPEG Q 90
Other options: lossless=True, bitdepth=10, and subsample_mode="off" for 4:4:4 chroma. compression="av1" (or a .avif file name) writes AVIF.
How to read Exif data#
image = pyvips.Image.new_from_file("IMG_0001.heic")
if image.get_typeof("exif-data") != 0:
exif = image.get("exif-data") # raw Exif bytes
print(image.get("exif-ifd0-Model")) # parsed fields are also available
How to read all images in a file#
first = pyvips.Image.new_from_file("burst.heic")
n = first.get("n-pages")
for page in range(n):
img = pyvips.Image.new_from_file("burst.heic", page=page)
print(page, img.width, img.height)
Tips#
- Pass
access="sequential"when you convert a file once from top to bottom; it lowers memory use. pyvips.Image.new_from_buffer(data, "")decodes HEIC bytes from memory, e.g. an upload.