Python interface for libheif library providing HEIF/AVIF image processing with both standalone and Pillow plugin capabilities
Overall
score
94%
Main container and image classes for handling HEIF/AVIF data. These classes provide comprehensive access to image data, metadata, and specialized image types including depth images and auxiliary images.
Main container class for HEIF/AVIF files that can contain one or more images with metadata. Provides both container-like access and direct access to the primary image.
class HeifFile:
"""
Container for HEIF/AVIF images with metadata support.
Properties:
- size: tuple[int, int], dimensions of primary image (width, height)
- mode: str, color mode ('RGB', 'RGBA', 'L', etc.)
- data: bytes, raw image data of primary image
- stride: int, bytes per row of primary image
- info: dict, metadata dictionary with EXIF, XMP, IPTC data
- mimetype: str, MIME type of file ('image/heif' or 'image/avif')
- primary_index: int, index of primary image in multi-image file
- has_alpha: bool, True if primary image has alpha channel
- premultiplied_alpha: bool, True if alpha is premultiplied
"""
def __init__(self, fp, convert_hdr_to_8bit=True, bgr_mode=False, **kwargs):
"""
Initialize HeifFile from file path or file-like object.
Parameters:
- fp: file path (str) or file-like object
- convert_hdr_to_8bit: bool, convert HDR to 8-bit
- bgr_mode: bool, use BGR pixel order
- **kwargs: additional decoding options
"""
@property
def size(self) -> tuple[int, int]:
"""Dimensions of primary image (width, height)."""
@property
def mode(self) -> str:
"""Color mode of primary image ('RGB', 'RGBA', 'L', etc.)."""
@property
def data(self) -> bytes:
"""Raw image data of primary image."""
@property
def stride(self) -> int:
"""Bytes per row of primary image."""
@property
def info(self) -> dict:
"""Metadata dictionary with EXIF, XMP, IPTC data."""
@property
def mimetype(self) -> str:
"""MIME type of file ('image/heif' or 'image/avif')."""
@property
def primary_index(self) -> int:
"""Index of primary image in multi-image file."""
@property
def has_alpha(self) -> bool:
"""True if primary image has alpha channel."""
@property
def premultiplied_alpha(self) -> bool:
"""True if alpha is premultiplied."""
@premultiplied_alpha.setter
def premultiplied_alpha(self, value: bool):
"""Set premultiplied alpha state."""
@property
def __array_interface__(self):
"""NumPy array interface for direct array access."""
def save(self, fp, **kwargs):
"""
Save all images to HEIF/AVIF file.
Parameters:
- fp: output file path or file-like object
- **kwargs: encoding options (quality, etc.)
"""
def add_frombytes(self, mode, size, data, **kwargs):
"""
Add image from raw bytes data.
Parameters:
- mode: str, color mode ('RGB', 'RGBA', etc.)
- size: tuple[int, int], image dimensions
- data: bytes, raw image data
- **kwargs: additional options
"""
def add_from_heif(self, image):
"""
Add image from another HeifImage.
Parameters:
- image: HeifImage, source image to add
"""
def add_from_pillow(self, image):
"""
Add image from Pillow Image.
Parameters:
- image: PIL Image, source image to add
"""
def to_pillow(self) -> 'PIL.Image.Image':
"""
Convert primary image to Pillow Image.
Returns:
PIL.Image.Image: Pillow Image object with metadata preserved
"""
def get_aux_image(self, aux_id):
"""
Get auxiliary image by ID.
Parameters:
- aux_id: int, auxiliary image identifier
Returns:
HeifAuxImage: Auxiliary image object
"""
def __len__(self) -> int:
"""Return number of images in container."""
def __iter__(self):
"""Iterate over all images in container."""
def __getitem__(self, index) -> 'HeifImage':
"""Get image by index."""
def __delitem__(self, index):
"""Delete image by index."""Usage example:
import pillow_heif
# Create from file
heif_file = pillow_heif.open_heif("multi_image.heic")
# Access primary image properties
print(f"Primary image: {heif_file.size} {heif_file.mode}")
print(f"Has alpha: {heif_file.has_alpha}")
print(f"MIME type: {heif_file.mimetype}")
# Container operations
print(f"Total images: {len(heif_file)}")
for i, image in enumerate(heif_file):
print(f"Image {i}: {image.size}")
# Add new image
heif_file.add_frombytes("RGB", (100, 100), b"..." * 30000)
# Save modified file
heif_file.save("output.heic", quality=95)Represents a single image within a HeifFile with full access to image data, metadata, and associated auxiliary images.
class HeifImage:
"""
Individual image within a HEIF/AVIF container.
Properties:
- size: tuple[int, int], image dimensions (width, height)
- mode: str, color mode ('RGB', 'RGBA', 'L', etc.)
- data: bytes, raw image data
- stride: int, bytes per row of image data
- has_alpha: bool, True if image has alpha channel
- premultiplied_alpha: bool, True if alpha is premultiplied
- info: dict, image metadata dictionary
- __array_interface__: dict, NumPy array interface for direct array access
"""
@property
def size(self) -> tuple[int, int]:
"""Image dimensions (width, height)."""
@property
def mode(self) -> str:
"""Color mode ('RGB', 'RGBA', 'L', etc.)."""
@property
def data(self) -> bytes:
"""Raw image data."""
@property
def stride(self) -> int:
"""Bytes per row of image data."""
@property
def has_alpha(self) -> bool:
"""True if image has alpha channel."""
@property
def premultiplied_alpha(self) -> bool:
"""True if alpha is premultiplied."""
@premultiplied_alpha.setter
def premultiplied_alpha(self, value: bool):
"""Set premultiplied alpha state."""
@property
def info(self) -> dict:
"""Image metadata dictionary."""
@property
def __array_interface__(self):
"""NumPy array interface for direct array access."""
def to_pillow(self):
"""
Convert image to Pillow Image.
Returns:
PIL.Image: Pillow Image object with metadata preserved
"""
def get_aux_image(self, aux_id):
"""
Get auxiliary image associated with this image.
Parameters:
- aux_id: int, auxiliary image identifier
Returns:
HeifAuxImage: Associated auxiliary image
"""
def load(self):
"""
Decode image data if not already loaded.
Notes:
- Called automatically when accessing data property
- Useful for explicit control over decoding timing
"""Usage example:
import pillow_heif
import numpy as np
heif_file = pillow_heif.open_heif("image.heic")
# Access individual image
image = heif_file[0] # First image
print(f"Image size: {image.size}")
print(f"Color mode: {image.mode}")
# Convert to NumPy array using array interface
np_array = np.asarray(image)
print(f"Array shape: {np_array.shape}")
# Convert to Pillow for processing
pil_image = image.to_pillow()
pil_image.show()
# Access metadata
if 'exif' in image.info:
print("EXIF data present")Represents depth image data associated with a HeifImage, providing 3D depth information for effects and processing.
class HeifDepthImage:
"""
Depth image associated with a HeifImage.
Properties:
- size: tuple[int, int], depth image dimensions
- mode: str, depth data mode (typically 'L' for grayscale)
- data: bytes, raw depth data
- stride: int, bytes per row of depth data
- info: dict, depth-specific metadata
"""
@property
def size(self) -> tuple[int, int]:
"""Depth image dimensions."""
@property
def mode(self) -> str:
"""Depth data mode (typically 'L' for grayscale)."""
@property
def data(self) -> bytes:
"""Raw depth data."""
@property
def stride(self) -> int:
"""Bytes per row of depth data."""
@property
def info(self) -> dict:
"""Depth-specific metadata."""
def to_pillow(self):
"""
Convert depth image to Pillow Image.
Returns:
PIL.Image: Pillow Image containing depth information
"""
def load(self):
"""
Decode depth data if not already loaded.
"""Usage example:
import pillow_heif
heif_file = pillow_heif.open_heif("depth_image.heic")
image = heif_file[0]
# Check if image has depth information
if hasattr(image, 'depth_images') and image.depth_images:
depth_image = image.depth_images[0]
print(f"Depth image size: {depth_image.size}")
# Convert to Pillow for visualization
depth_pil = depth_image.to_pillow()
depth_pil.save("depth_map.png")Represents auxiliary images associated with a HeifImage, such as alpha masks, thumbnails, or other supplementary data.
class HeifAuxImage:
"""
Auxiliary image associated with a HeifImage.
Properties:
- size: tuple[int, int], auxiliary image dimensions
- mode: str, color mode of auxiliary data
- data: bytes, raw auxiliary image data
- stride: int, bytes per row of auxiliary data
"""
@property
def size(self) -> tuple[int, int]:
"""Auxiliary image dimensions."""
@property
def mode(self) -> str:
"""Color mode of auxiliary data."""
@property
def data(self) -> bytes:
"""Raw auxiliary image data."""
@property
def stride(self) -> int:
"""Bytes per row of auxiliary data."""
def to_pillow(self):
"""
Convert auxiliary image to Pillow Image.
Returns:
PIL.Image: Pillow Image containing auxiliary data
"""
def load(self):
"""
Decode auxiliary data if not already loaded.
"""Usage example:
import pillow_heif
heif_file = pillow_heif.open_heif("image_with_aux.heic")
image = heif_file[0]
# Access auxiliary images
aux_image = image.get_aux_image(1) # Get auxiliary image by ID
if aux_image:
print(f"Auxiliary image size: {aux_image.size}")
aux_pil = aux_image.to_pillow()
aux_pil.save("auxiliary_data.png")import pillow_heif
# Open multi-image HEIF file
heif_file = pillow_heif.open_heif("burst_photos.heic")
# Process each image
for i, image in enumerate(heif_file):
print(f"Processing image {i+1}/{len(heif_file)}")
pil_image = image.to_pillow()
pil_image.save(f"image_{i+1}.jpg", quality=95)
# Access specific images
primary_image = heif_file[heif_file.primary_index]
print(f"Primary image: {primary_image.size}")import pillow_heif
heif_file = pillow_heif.open_heif("image_with_metadata.heic")
# Access metadata from HeifFile
print("File metadata:")
for key, value in heif_file.info.items():
print(f" {key}: {type(value).__name__}")
# Access metadata from individual images
image = heif_file[0]
if 'exif' in image.info:
exif_data = image.info['exif']
print(f"EXIF data size: {len(exif_data)} bytes")import pillow_heif
import numpy as np
heif_file = pillow_heif.open_heif("image.heic")
image = heif_file[0]
# Direct NumPy array access
np_array = np.asarray(image)
print(f"Array shape: {np_array.shape}")
print(f"Data type: {np_array.dtype}")
# Process with NumPy
processed = np_array * 0.8 # Darken image
processed = processed.astype(np.uint8)
# Convert back to HeifFile
new_heif = pillow_heif.from_bytes(
mode=image.mode,
size=image.size,
data=processed.tobytes()
)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