Python interface for libheif library providing HEIF/AVIF image processing with both standalone and Pillow plugin capabilities
Overall
score
94%
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.
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"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_fileFunctions 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()}")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}")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 limitsUsage 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 encoderEnumeration 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 = 3Usage 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-heifevals
scenario-1
scenario-2
scenario-3
scenario-4
scenario-5
scenario-6
scenario-7
scenario-8
scenario-9
scenario-10