CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-pillow-heif

Python interface for libheif library providing HEIF/AVIF image processing with both standalone and Pillow plugin capabilities

Overall
score

94%

Overview
Eval results
Files

encoding.mddocs/

Encoding

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.

Capabilities

Direct Encoding from Raw Data

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
)

Creating HeifFile from Pillow Images

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)

Creating HeifFile from Raw Bytes

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")

Encoding Options and Quality Control

Quality Settings

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)

Format Selection

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 AVIF

Advanced AVIF Options

import 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")

HDR and High Bit Depth Encoding

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)

Multi-Image Encoding

Creating Multi-Image Files

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)

Batch Processing

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)

OpenCV Integration

Encoding from OpenCV Arrays

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 swapping

Error Handling

import 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-heif

docs

encoding.md

file-operations.md

image-classes.md

index.md

metadata-utilities.md

pillow-integration.md

tile.json