Python interface for libheif library providing HEIF/AVIF image processing with both standalone and Pillow plugin capabilities
Overall
score
94%
Functions for creating HEIF/AVIF files from raw data, Pillow images, or other sources. These functions provide comprehensive encoding capabilities with quality control, format selection, and advanced compression options.
Encodes raw image data directly to a HEIF/AVIF file with full control over encoding parameters.
def encode(mode: str, size: tuple[int, int], data: bytes, fp, **kwargs) -> None:
"""
Encode raw image data to HEIF/AVIF format.
Parameters:
- mode: str, color mode ('RGB', 'RGBA', 'L', etc.)
- size: tuple[int, int], image dimensions (width, height)
- data: bytes, raw image data
- fp: output file path or file-like object
- **kwargs: encoding options
Encoding Options:
- quality: int, compression quality 0-100 (default: 50)
- format: str, output format 'HEIF' or 'AVIF' (auto-detected from extension)
- compression_format: str, specific compression format
- lossless: bool, enable lossless compression
- effort: int, encoding effort 0-9 for AVIF (higher = smaller file)
- chroma_subsampling: str, chroma subsampling mode
- save_all: bool, save all provided images
Raises:
IOError: If encoding fails or parameters are invalid
"""Usage example:
import pillow_heif
import numpy as np
# Create sample RGB data
width, height = 640, 480
rgb_data = np.random.randint(0, 255, (height, width, 3), dtype=np.uint8)
# Encode to HEIF
pillow_heif.encode(
mode="RGB",
size=(width, height),
data=rgb_data.tobytes(),
fp="encoded_image.heic",
quality=90
)
# Encode to AVIF with high effort
pillow_heif.encode(
mode="RGB",
size=(width, height),
data=rgb_data.tobytes(),
fp="encoded_image.avif",
quality=80,
effort=9
)Converts Pillow Image objects to HeifFile containers, preserving metadata and supporting various Pillow image modes.
def from_pillow(pil_image: 'PIL.Image.Image') -> HeifFile:
"""
Create HeifFile from Pillow Image.
Parameters:
- pil_image: PIL.Image, source Pillow image
Returns:
HeifFile: Container with converted image data
Notes:
- Preserves image metadata (EXIF, etc.) when present
- Supports all Pillow color modes
- Handles transparency in RGBA images
"""Usage example:
import pillow_heif
from PIL import Image
# Create or load Pillow image
pil_image = Image.open("source.jpg")
pil_image = pil_image.convert("RGB")
# Convert to HeifFile
heif_file = pillow_heif.from_pillow(pil_image)
# Save with specific quality
heif_file.save("converted.heic", quality=85)
# Work with transparency
rgba_image = Image.open("transparent.png").convert("RGBA")
heif_file = pillow_heif.from_pillow(rgba_image)
heif_file.save("transparent.heic", quality=90)Creates HeifFile containers from raw image data with specified format parameters.
def from_bytes(mode: str, size: tuple[int, int], data: bytes, **kwargs) -> HeifFile:
"""
Create HeifFile from raw image bytes.
Parameters:
- mode: str, color mode ('RGB', 'RGBA', 'L', etc.)
- size: tuple[int, int], image dimensions (width, height)
- data: bytes, raw image data
- **kwargs: additional options for image creation
Additional Options:
- stride: int, bytes per row (calculated automatically if not provided)
- info: dict, metadata to attach to image
Returns:
HeifFile: Container with image data ready for processing or saving
"""Usage example:
import pillow_heif
import numpy as np
# Create image data
width, height = 400, 300
rgb_array = np.random.randint(0, 255, (height, width, 3), dtype=np.uint8)
# Create HeifFile from raw bytes
heif_file = pillow_heif.from_bytes(
mode="RGB",
size=(width, height),
data=rgb_array.tobytes()
)
# Add metadata
heif_file.info['description'] = "Generated test image"
# Save to file
heif_file.save("from_bytes.heic", quality=75)
# Create RGBA image with transparency
rgba_array = np.random.randint(0, 255, (height, width, 4), dtype=np.uint8)
rgba_array[:, :, 3] = 128 # Semi-transparent
heif_file = pillow_heif.from_bytes(
mode="RGBA",
size=(width, height),
data=rgba_array.tobytes()
)
heif_file.save("transparent_from_bytes.heic")import pillow_heif
# High quality (larger file)
heif_file.save("high_quality.heic", quality=95)
# Medium quality (balanced)
heif_file.save("medium_quality.heic", quality=75)
# Low quality (smaller file)
heif_file.save("low_quality.heic", quality=50)
# Lossless compression
heif_file.save("lossless.heic", lossless=True)
# Auto quality (let encoder decide)
heif_file.save("auto_quality.heic", quality=-1)import pillow_heif
# Force HEIF format
heif_file.save("image.heic", format="HEIF")
# Force AVIF format
heif_file.save("image.avif", format="AVIF")
# Auto-detect from extension
heif_file.save("image.heic") # Uses HEIF
heif_file.save("image.avif") # Uses AVIFimport pillow_heif
# High effort encoding (slower but smaller)
heif_file.save("high_effort.avif", effort=9, quality=80)
# Fast encoding
heif_file.save("fast.avif", effort=0, quality=80)
# Custom chroma subsampling
heif_file.save("custom_chroma.avif", chroma_subsampling="4:2:0")import pillow_heif
import numpy as np
# Create 10-bit HDR data
width, height = 1920, 1080
hdr_data = np.random.randint(0, 1023, (height, width, 3), dtype=np.uint16)
# Encode as 10-bit HEIF
heif_file = pillow_heif.from_bytes(
mode="RGB;10",
size=(width, height),
data=hdr_data.tobytes()
)
heif_file.save("hdr_10bit.heic", quality=-1) # Preserve bit depth
# 12-bit encoding
pillow_heif.options.SAVE_HDR_TO_12_BIT = True
heif_file.save("hdr_12bit.heic", quality=-1)import pillow_heif
from PIL import Image
# Create empty HeifFile
heif_file = pillow_heif.HeifFile()
# Add multiple images
for i in range(3):
pil_image = Image.new("RGB", (640, 480), color=(i*80, 0, 0))
heif_file.add_from_pillow(pil_image)
# Set primary image
heif_file.primary_index = 0
# Save multi-image file
heif_file.save("multi_image.heic", save_all=True, quality=85)import pillow_heif
from PIL import Image
import os
def batch_convert_to_heif(input_dir, output_dir, quality=80):
"""Convert all images in directory to HEIF format."""
os.makedirs(output_dir, exist_ok=True)
for filename in os.listdir(input_dir):
if filename.lower().endswith(('.jpg', '.jpeg', '.png')):
input_path = os.path.join(input_dir, filename)
output_path = os.path.join(output_dir,
os.path.splitext(filename)[0] + '.heic')
try:
pil_image = Image.open(input_path)
heif_file = pillow_heif.from_pillow(pil_image)
heif_file.save(output_path, quality=quality)
print(f"Converted: {filename}")
except Exception as e:
print(f"Error converting {filename}: {e}")
# Usage
batch_convert_to_heif("input_images/", "output_heif/", quality=85)import pillow_heif
import cv2
import numpy as np
# Load image with OpenCV
cv_image = cv2.imread("input.jpg", cv2.IMREAD_COLOR) # BGR format
# Convert BGR to RGB for standard encoding
rgb_image = cv2.cvtColor(cv_image, cv2.COLOR_BGR2RGB)
# Create HeifFile from OpenCV array
heif_file = pillow_heif.from_bytes(
mode="RGB",
size=(cv_image.shape[1], cv_image.shape[0]), # width, height
data=rgb_image.tobytes()
)
# Save as HEIF
heif_file.save("opencv_to_heif.heic", quality=90)
# Alternative: Use BGR mode directly
heif_file = pillow_heif.from_bytes(
mode="RGB", # Still RGB mode
size=(cv_image.shape[1], cv_image.shape[0]),
data=cv_image.tobytes() # BGR data
)
# Note: This may result in color channel swappingimport pillow_heif
try:
# Attempt encoding with invalid parameters
pillow_heif.encode(
mode="INVALID_MODE",
size=(100, 100),
data=b"invalid data",
fp="output.heic"
)
except ValueError as e:
print(f"Invalid parameters: {e}")
except IOError as e:
print(f"Encoding failed: {e}")
except Exception as e:
print(f"Unexpected error: {e}")
# Safe encoding with validation
def safe_encode(mode, size, data, fp, **kwargs):
"""Safely encode with parameter validation."""
valid_modes = ['RGB', 'RGBA', 'L', 'LA']
if mode not in valid_modes:
raise ValueError(f"Mode must be one of {valid_modes}")
expected_size = size[0] * size[1] * len(mode)
if len(data) != expected_size:
raise ValueError(f"Data size mismatch: expected {expected_size}, got {len(data)}")
return pillow_heif.encode(mode, size, data, fp, **kwargs)Install with Tessl CLI
npx tessl i tessl/pypi-pillow-heifevals
scenario-1
scenario-2
scenario-3
scenario-4
scenario-5
scenario-6
scenario-7
scenario-8
scenario-9
scenario-10