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

metadata-utilities.mddocs/

Metadata and Utilities

Helper functions for MIME type detection, orientation handling, library information, and plugin loading. These utilities provide essential support functionality for HEIF/AVIF processing and integration with the broader image processing ecosystem.

Capabilities

MIME Type Detection

Determines the MIME type of HEIF/AVIF files for proper content type handling and format identification.

def get_file_mimetype(fp) -> str:
    """
    Determine MIME type of HEIF/AVIF file.
    
    Parameters:
    - fp: file path (str) or file-like object
    
    Returns:
    str: MIME type string ('image/heif', 'image/avif', or empty string if not supported)
    
    Notes:
    - Fast detection based on file signature
    - Returns empty string for unsupported formats
    - Useful for web applications and content type headers
    """

Usage example:

import pillow_heif

# Check MIME type of various files
files = ["image.heic", "photo.avif", "unknown.jpg"]

for filepath in files:
    mimetype = pillow_heif.get_file_mimetype(filepath)
    if mimetype:
        print(f"{filepath}: {mimetype}")
    else:
        print(f"{filepath}: Not a HEIF/AVIF file")

# Web application usage
def get_content_type(filepath):
    """Get appropriate content type for web responses."""
    mimetype = pillow_heif.get_file_mimetype(filepath)
    return mimetype if mimetype else "application/octet-stream"

EXIF Orientation Handling

Resets EXIF orientation metadata to default value, useful for correcting orientation-related display issues.

def set_orientation(info: dict) -> int | None:
    """
    Reset EXIF orientation metadata to default (1).
    
    Parameters:
    - info: dict, image metadata dictionary containing EXIF data
    
    Returns:
    int | None: Previous orientation value, or None if no EXIF data present
    
    Notes:
    - Modifies the info dictionary in-place
    - Sets orientation to 1 (normal, no rotation)
    - Useful after applying rotation corrections
    """

Usage example:

import pillow_heif

# Open image and check orientation
heif_file = pillow_heif.open_heif("rotated_photo.heic")
print(f"Metadata keys: {list(heif_file.info.keys())}")

# Reset orientation if present
if 'exif' in heif_file.info:
    old_orientation = pillow_heif.set_orientation(heif_file.info)
    if old_orientation:
        print(f"Reset orientation from {old_orientation} to 1")
    
    # Save with corrected orientation
    heif_file.save("corrected_photo.heic")

# Function to auto-correct orientation
def correct_orientation(heif_file):
    """Auto-correct image orientation using EXIF data."""
    if 'exif' in heif_file.info:
        # Apply rotation based on EXIF before resetting
        pil_image = heif_file.to_pillow()
        
        # PIL automatically handles EXIF orientation
        # Reset EXIF to prevent double-correction
        pillow_heif.set_orientation(heif_file.info)
        
        return pillow_heif.from_pillow(pil_image)
    return heif_file

Library Information

Functions to retrieve version and capability information about the underlying libheif library.

def libheif_version() -> str:
    """
    Get version string of underlying libheif library.
    
    Returns:
    str: Version string (e.g., "1.17.6")
    
    Notes:
    - Returns the version of the C library, not the Python bindings
    - Useful for compatibility checking and debugging
    """

def libheif_info() -> dict:
    """
    Get comprehensive information about libheif capabilities.
    
    Returns:
    dict: Information dictionary with keys:
        - 'version': str, libheif version
        - 'encoders': list, available encoder names
        - 'decoders': list, available decoder names
        - 'builtin_encoders': list, built-in encoder names
        - 'builtin_decoders': list, built-in decoder names
    
    Notes:
    - Encoder/decoder availability depends on compile-time options
    - Plugin encoders/decoders loaded at runtime are included
    """

Usage example:

import pillow_heif
import json

# Check library version
version = pillow_heif.libheif_version()
print(f"libheif version: {version}")

# Get detailed capability information
info = pillow_heif.libheif_info()
print("Library capabilities:")
print(json.dumps(info, indent=2))

# Check for specific encoder support
if 'x265' in info.get('encoders', []):
    print("x265 HEIF encoder available")
if 'aom' in info.get('encoders', []):
    print("AOM AV1 encoder available for AVIF")

# Conditional functionality based on capabilities
def get_available_formats():
    """Get list of supported output formats."""
    info = pillow_heif.libheif_info()
    formats = []
    
    if any('heif' in enc.lower() for enc in info.get('encoders', [])):
        formats.append('HEIF')
    if any('av1' in enc.lower() or 'aom' in enc.lower() 
           for enc in info.get('encoders', [])):
        formats.append('AVIF')
    
    return formats

print(f"Available output formats: {get_available_formats()}")

Plugin Loading

Loads additional libheif plugins for extended format support and codec capabilities.

def load_libheif_plugin(plugin_path: str) -> None:
    """
    Load specified LibHeif plugin for extended format support.
    
    Parameters:
    - plugin_path: str, path to plugin library file
    
    Notes:
    - Extends encoder/decoder capabilities at runtime
    - Plugin path must point to valid libheif plugin library
    - Changes are reflected in libheif_info() output after loading
    
    Raises:
    OSError: If plugin cannot be loaded or is invalid
    """

Usage example:

import pillow_heif
import os

# Check capabilities before loading plugins
info_before = pillow_heif.libheif_info()
print(f"Encoders before: {info_before.get('encoders', [])}")

# Load additional plugin (example path)
plugin_path = "/usr/local/lib/libheif/plugins/libheif-x265.so"
if os.path.exists(plugin_path):
    try:
        pillow_heif.load_libheif_plugin(plugin_path)
        print(f"Successfully loaded plugin: {plugin_path}")
        
        # Check updated capabilities
        info_after = pillow_heif.libheif_info()
        new_encoders = set(info_after.get('encoders', [])) - set(info_before.get('encoders', []))
        if new_encoders:
            print(f"New encoders available: {list(new_encoders)}")
            
    except OSError as e:
        print(f"Failed to load plugin: {e}")

# Batch plugin loading
def load_available_plugins(plugin_dir="/usr/local/lib/libheif/plugins"):
    """Load all available plugins from directory."""
    if not os.path.exists(plugin_dir):
        return
    
    for filename in os.listdir(plugin_dir):
        if filename.endswith(('.so', '.dll', '.dylib')):
            plugin_path = os.path.join(plugin_dir, filename)
            try:
                pillow_heif.load_libheif_plugin(plugin_path)
                print(f"Loaded: {filename}")
            except OSError:
                print(f"Failed to load: {filename}")

Configuration Options Module

Runtime configuration variables that control library behavior, available in the pillow_heif.options module.

# Threading configuration
DECODE_THREADS = 4  # Maximum threads for image decoding

# Feature toggles
THUMBNAILS = True  # Enable/disable thumbnail support
DEPTH_IMAGES = True  # Enable/disable depth image support
AUX_IMAGES = True  # Enable/disable auxiliary image support

# Encoding defaults
QUALITY = None  # Default encoding quality (None, -1, or 0-100)
SAVE_HDR_TO_12_BIT = False  # Save 16-bit images as 12-bit vs 10-bit
SAVE_NCLX_PROFILE = True  # Save NCLX color profiles

# Codec preferences
PREFERRED_ENCODER = {"AVIF": "", "HEIF": ""}  # Preferred encoder IDs
PREFERRED_DECODER = {"AVIF": "", "HEIF": ""}  # Preferred decoder IDs

# Security and compatibility
ALLOW_INCORRECT_HEADERS = False  # Allow size mismatch in headers
DISABLE_SECURITY_LIMITS = False  # Disable libheif security limits

Usage example:

import pillow_heif

# Configure threading
pillow_heif.options.DECODE_THREADS = 8  # Use more threads for faster decoding

# Disable features for memory savings
pillow_heif.options.THUMBNAILS = False
pillow_heif.options.DEPTH_IMAGES = False

# Set default quality
pillow_heif.options.QUALITY = 85

# Configure HDR handling
pillow_heif.options.SAVE_HDR_TO_12_BIT = True

# Set encoder preferences
pillow_heif.options.PREFERRED_ENCODER["HEIF"] = "x265"
pillow_heif.options.PREFERRED_ENCODER["AVIF"] = "aom"

# Now all operations use these settings
heif_file = pillow_heif.open_heif("image.heic")  # Uses 8 decode threads
heif_file.save("output.heic")  # Uses quality=85, x265 encoder

Color Space Enumerations

Enumeration types for color space and metadata handling, extending Python's IntEnum.

class HeifColorPrimaries(IntEnum):
    """NCLX color primaries definitions for proper color reproduction."""
    ITU_R_BT_709_5 = 1
    UNSPECIFIED = 2
    ITU_R_BT_470_6_SYSTEM_M = 4
    ITU_R_BT_470_6_SYSTEM_B_G = 5
    ITU_R_BT_601_6 = 6
    SMPTE_240M = 7
    GENERIC_FILM = 8
    ITU_R_BT_2020_2_AND_2100_0 = 9
    SMPTE_ST_428_1 = 10
    SMPTE_RP_431_2 = 11
    SMPTE_EG_432_1 = 12
    EBU_TECH_3213_E = 22

class HeifTransferCharacteristics(IntEnum):
    """NCLX transfer characteristics for gamma/transfer functions."""
    ITU_R_BT_709_5 = 1
    UNSPECIFIED = 2
    ITU_R_BT_470_6_SYSTEM_M = 4
    ITU_R_BT_470_6_SYSTEM_B_G = 5
    ITU_R_BT_601_6 = 6
    SMPTE_240M = 7
    LINEAR = 8
    LOGARITHMIC_100 = 9
    LOGARITHMIC_100_SQRT10 = 10
    IEC_61966_2_4 = 11
    ITU_R_BT_1361 = 12
    IEC_61966_2_1 = 13
    ITU_R_BT_2020_2_10BIT = 14
    ITU_R_BT_2020_2_12BIT = 15
    ITU_R_BT_2100_0_PQ = 16
    SMPTE_ST_428_1 = 17
    ITU_R_BT_2100_0_HLG = 18

class HeifMatrixCoefficients(IntEnum):
    """NCLX matrix coefficients for color space conversion."""
    RGB_GBR = 0
    ITU_R_BT_709_5 = 1
    UNSPECIFIED = 2
    US_FCC_T47 = 4
    ITU_R_BT_470_6_SYSTEM_B_G = 5
    ITU_R_BT_601_6 = 6
    SMPTE_240M = 7
    YCGCO = 8
    ITU_R_BT_2020_2_NON_CONSTANT_LUMINANCE = 9
    ITU_R_BT_2020_2_CONSTANT_LUMINANCE = 10
    SMPTE_ST_2085 = 11
    CHROMATICITY_DERIVED_NON_CONSTANT_LUMINANCE = 12
    CHROMATICITY_DERIVED_CONSTANT_LUMINANCE = 13
    ICTCP = 14

class HeifDepthRepresentationType(IntEnum):
    """Depth image representation types."""
    UNIFORM_INVERSE_Z = 0
    UNIFORM_DISPARITY = 1
    UNIFORM_Z = 2
    NON_UNIFORM_DISPARITY = 3

Usage example:

import pillow_heif
from pillow_heif import HeifColorPrimaries, HeifTransferCharacteristics

# Working with color space metadata
heif_file = pillow_heif.open_heif("hdr_image.heic")

# Check color space information in metadata
if 'nclx_profile' in heif_file.info:
    nclx = heif_file.info['nclx_profile']
    
    # Use enums for color space interpretation
    if nclx.get('color_primaries') == HeifColorPrimaries.ITU_R_BT_2020_2_AND_2100_0:
        print("Image uses BT.2020 color primaries (wide color gamut)")
    
    if nclx.get('transfer_characteristics') == HeifTransferCharacteristics.ITU_R_BT_2100_0_PQ:
        print("Image uses PQ transfer characteristics (HDR)")

# Setting color space for encoding
encoding_options = {
    'nclx_profile': {
        'color_primaries': HeifColorPrimaries.ITU_R_BT_709_5,
        'transfer_characteristics': HeifTransferCharacteristics.ITU_R_BT_709_5,
        'matrix_coefficients': pillow_heif.HeifMatrixCoefficients.ITU_R_BT_709_5,
        'full_range': True
    }
}

heif_file.save("srgb_image.heic", **encoding_options)

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