CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-openexr

Professional-grade EXR image format library for high-dynamic-range scene-linear image data with multi-part and deep compositing support

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

file-io.mddocs/

File I/O Operations

Comprehensive file reading and writing operations for EXR images, supporting scanline and tiled formats, multi-part files, and streaming operations with configurable threading.

Capabilities

Primary File Interface

The main interface for EXR file operations, providing context management and flexible construction for different use cases.

class File:
    def __init__(self, filename: str, separate_channels: bool = False, header_only: bool = False):
        """
        Open existing EXR file for reading.
        
        Args:
            filename: Path to EXR file
            separate_channels: Read channels as separate arrays
            header_only: Read only header information
        """
    
    def __init__(self, header: dict, channels: dict):
        """
        Create EXR file for writing with single part.
        
        Args:
            header: Image metadata and format settings
            channels: Channel data dictionary
        """
    
    def __init__(self, parts: list):
        """
        Create multi-part EXR file for writing.
        
        Args:
            parts: List of Part objects
        """
    
    def __enter__(self):
        """Context manager entry."""
    
    def __exit__(self, *args):
        """Context manager exit with cleanup."""
    
    def header(self, part_index: int = 0) -> dict:
        """
        Get header information for specified part.
        
        Args:
            part_index: Part index for multi-part files
            
        Returns:
            Header dictionary with metadata
        """
    
    def channels(self, part_index: int = 0) -> dict:
        """
        Get channel data for specified part.
        
        Args:
            part_index: Part index for multi-part files
            
        Returns:
            Dictionary mapping channel names to Channel objects
        """
    
    def write(self, filename: str) -> None:
        """
        Write EXR data to file.
        
        Args:
            filename: Output file path
        """
    
    def width(self) -> int:
        """Get image width in pixels."""
    
    def height(self) -> int:
        """Get image height in pixels."""

Part Management

Individual parts within multi-part EXR files, enabling complex compositing workflows with multiple image layers.

class Part:
    def __init__(self, header: dict, channels: dict, name: str):
        """
        Create image part for multi-part files.
        
        Args:
            header: Part-specific header information
            channels: Channel data for this part
            name: Human-readable part name
        """
    
    def name(self) -> str:
        """Get part name."""
    
    def shape(self) -> tuple:
        """Get image dimensions as (height, width)."""
    
    def width(self) -> int:
        """Get image width in pixels."""
    
    def height(self) -> int:
        """Get image height in pixels."""
    
    def compression(self):
        """Get compression method for this part."""
    
    def type(self):
        """Get image type (scanline/tiled/deep)."""
    
    def typeString(self) -> str:
        """Get human-readable image type string."""
    
    header: dict           # Header attributes
    channels: dict         # Channel data mapping
    part_index: int        # Zero-based part index

Channel Representation

Individual image channels with flexible pixel types and sampling parameters.

class Channel:
    def __init__(self, name: str = None, pixels = None, xSampling: int = 1, ySampling: int = 1, pLinear: bool = False):
        """
        Create image channel.
        
        Args:
            name: Channel identifier
            pixels: Pixel data as numpy array
            xSampling: Horizontal subsampling factor
            ySampling: Vertical subsampling factor  
            pLinear: Whether pixels are perceptually linear
        """
    
    def pixelType(self):
        """Get pixel data type (UINT/HALF/FLOAT)."""
    
    name: str              # Channel name
    xSampling: int         # Horizontal subsampling
    ySampling: int         # Vertical subsampling
    pLinear: bool          # Perceptual linearity flag
    pixels: numpy.ndarray  # Pixel data array

Usage Examples

Basic Reading Operations

import OpenEXR
import numpy as np

# Read complete EXR file
with OpenEXR.File("input.exr") as infile:
    header = infile.header()
    channels = infile.channels()
    
    # Access specific channels
    rgb_data = channels["RGB"].pixels
    alpha_data = channels["A"].pixels if "A" in channels else None
    
    print(f"Image: {infile.width()}x{infile.height()}")
    print(f"Channels: {list(channels.keys())}")
    print(f"Compression: {header['compression']}")

# Read header only for fast metadata access
with OpenEXR.File("input.exr", header_only=True) as infile:
    header = infile.header()
    print(f"Image type: {header['type']}")
    print(f"Data window: {header['dataWindow']}")

# Read with separate channel arrays
with OpenEXR.File("input.exr", separate_channels=True) as infile:
    channels = infile.channels()
    r_channel = channels["R"].pixels
    g_channel = channels["G"].pixels  
    b_channel = channels["B"].pixels

Basic Writing Operations

import OpenEXR
import numpy as np

# Create RGB image data
height, width = 1080, 1920
rgb_data = np.random.rand(height, width, 3).astype('f')

# Write single-part file
header = {
    "compression": OpenEXR.ZIP_COMPRESSION,
    "type": OpenEXR.scanlineimage,
    "pixelAspectRatio": 1.0
}
channels = {"RGB": rgb_data}

with OpenEXR.File(header, channels) as outfile:
    outfile.write("output.exr")

# Write separate channels
r_data = np.random.rand(height, width).astype('f')
g_data = np.random.rand(height, width).astype('f')
b_data = np.random.rand(height, width).astype('f')
a_data = np.ones((height, width), dtype='f')

channels = {
    "R": r_data,
    "G": g_data,
    "B": b_data,
    "A": a_data
}

with OpenEXR.File(header, channels) as outfile:
    outfile.write("rgba_output.exr")

Multi-Part File Operations

import OpenEXR
import numpy as np

# Create multiple image parts
height, width = 1080, 1920

# Beauty pass
beauty_data = np.random.rand(height, width, 3).astype('f')
beauty_header = {
    "compression": OpenEXR.DWAA_COMPRESSION,
    "type": OpenEXR.scanlineimage
}
beauty_channels = {"RGB": beauty_data}

# Depth pass  
depth_data = np.random.rand(height, width).astype('f')
depth_header = {
    "compression": OpenEXR.ZIP_COMPRESSION,
    "type": OpenEXR.scanlineimage
}
depth_channels = {"Z": depth_data}

# Motion vector pass
motion_data = np.random.rand(height, width, 2).astype('f')  
motion_header = {
    "compression": OpenEXR.ZIP_COMPRESSION,
    "type": OpenEXR.scanlineimage
}
motion_channels = {"motion": motion_data}

# Create multi-part file
parts = [
    OpenEXR.Part(beauty_header, beauty_channels, "beauty"),
    OpenEXR.Part(depth_header, depth_channels, "depth"),
    OpenEXR.Part(motion_header, motion_channels, "motion")
]

with OpenEXR.File(parts) as outfile:
    outfile.write("multipart_output.exr")

# Read multi-part file
with OpenEXR.File("multipart_output.exr") as infile:
    # Access different parts
    beauty_channels = infile.channels(0)  # Beauty pass
    depth_channels = infile.channels(1)   # Depth pass  
    motion_channels = infile.channels(2)  # Motion pass
    
    # Get part-specific headers
    beauty_header = infile.header(0)
    depth_header = infile.header(1)
    motion_header = infile.header(2)

High-Performance Streaming

import OpenEXR
import numpy as np

def process_large_exr(input_path, output_path):
    """Process large EXR files with memory efficiency."""
    
    with OpenEXR.File(input_path) as infile:
        header = infile.header()
        
        # Modify header for output
        output_header = header.copy()
        output_header["compression"] = OpenEXR.DWAA_COMPRESSION
        
        # Process in chunks for memory efficiency
        channels = infile.channels()
        
        # Apply processing to channel data
        processed_channels = {}
        for name, channel in channels.items():
            # Example: gamma correction
            processed_pixels = np.power(channel.pixels, 1.0/2.2)
            processed_channels[name] = processed_pixels
        
        # Write processed result
        with OpenEXR.File(output_header, processed_channels) as outfile:
            outfile.write(output_path)

# Process file
process_large_exr("large_input.exr", "processed_output.exr")

Error Handling

import OpenEXR

def safe_exr_read(filename):
    """Safely read EXR file with proper error handling."""
    
    try:
        with OpenEXR.File(filename) as infile:
            header = infile.header()
            channels = infile.channels()
            return header, channels
            
    except IOError as e:
        print(f"File I/O error: {e}")
        return None, None
        
    except Exception as e:
        print(f"EXR format error: {e}")
        return None, None

def safe_exr_write(filename, header, channels):
    """Safely write EXR file with validation."""
    
    # Validate header
    required_keys = ["compression", "type"]
    for key in required_keys:
        if key not in header:
            raise ValueError(f"Missing required header key: {key}")
    
    # Validate channels
    if not channels:
        raise ValueError("No channels provided")
    
    try:
        with OpenEXR.File(header, channels) as outfile:
            outfile.write(filename)
        print(f"Successfully wrote: {filename}")
        
    except Exception as e:
        print(f"Write error: {e}")
        raise

# Usage
header, channels = safe_exr_read("input.exr")
if header and channels:
    safe_exr_write("output.exr", header, channels)

Install with Tessl CLI

npx tessl i tessl/pypi-openexr

docs

advanced-features.md

cpp-api.md

file-io.md

image-data.md

index.md

metadata.md

tile.json