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

cpp-api.mddocs/

C++ API Reference

Low-level C++ interface for maximum performance, custom integrations, and advanced use cases requiring direct control over encoding/decoding operations.

Capabilities

Core File I/O Classes

Primary interfaces for reading and writing EXR files with full control over threading, memory management, and format options.

#include <OpenEXR/ImfInputFile.h>
#include <OpenEXR/ImfOutputFile.h>
#include <OpenEXR/ImfHeader.h>
#include <OpenEXR/ImfFrameBuffer.h>

namespace OPENEXR_IMF_NAMESPACE {

class InputFile {
public:
    // Constructors
    InputFile(const char filename[], int numThreads = globalThreadCount());
    InputFile(IStream& is, int numThreads = globalThreadCount());
    
    // File information
    const Header& header() const;
    const char* fileName() const;
    int version() const;
    bool isComplete() const;
    
    // Reading operations
    void setFrameBuffer(const FrameBuffer& frameBuffer);
    void readPixels(int scanLine1, int scanLine2);
    void readPixels(int scanLine);
    
    // Destructor
    ~InputFile();
};

class OutputFile {
public:
    // Constructors
    OutputFile(const char name[], const Header& header, int numThreads = globalThreadCount());
    OutputFile(OStream& os, const Header& header, int numThreads = globalThreadCount());
    
    // File information
    const Header& header() const;
    const FrameBuffer& frameBuffer() const;
    int currentScanLine() const;
    
    // Writing operations
    void setFrameBuffer(const FrameBuffer& frameBuffer);
    void writePixels(int numScanLines = 1);
    
    // Destructor
    ~OutputFile();
};

} // namespace OPENEXR_IMF_NAMESPACE

Tiled Image Support

High-performance tiled image access for random access patterns and multi-resolution workflows.

#include <OpenEXR/ImfTiledInputFile.h>
#include <OpenEXR/ImfTiledOutputFile.h>
#include <OpenEXR/ImfTileDescription.h>

namespace OPENEXR_IMF_NAMESPACE {

class TiledInputFile {
public:
    // Constructors
    TiledInputFile(const char name[], int numThreads = globalThreadCount());
    TiledInputFile(IStream& is, int numThreads = globalThreadCount());
    
    // File information
    const Header& header() const;
    const char* fileName() const;
    int version() const;
    
    // Tile information
    unsigned int tileXSize() const;
    unsigned int tileYSize() const;
    LevelMode levelMode() const;
    LevelRoundingMode levelRoundingMode() const;
    int numXLevels() const;
    int numYLevels() const;
    int numXTiles(int lx = 0) const;
    int numYTiles(int ly = 0) const;
    
    // Reading operations
    void setFrameBuffer(const FrameBuffer& frameBuffer);
    void readTile(int dx, int dy, int lx = 0, int ly = 0);
    void readTiles(int dxMin, int dxMax, int dyMin, int dyMax, int lx = 0, int ly = 0);
    void readAllTiles(int lx = 0, int ly = 0);
    
    // Destructor
    ~TiledInputFile();
};

class TiledOutputFile {
public:
    // Constructors
    TiledOutputFile(const char name[], const Header& header, int numThreads = globalThreadCount());
    TiledOutputFile(OStream& os, const Header& header, int numThreads = globalThreadCount());
    
    // File information
    const Header& header() const;
    const FrameBuffer& frameBuffer() const;
    
    // Tile information
    unsigned int tileXSize() const;
    unsigned int tileYSize() const;
    LevelMode levelMode() const;
    LevelRoundingMode levelRoundingMode() const;
    int numXLevels() const;
    int numYLevels() const;
    int numXTiles(int lx = 0) const;
    int numYTiles(int ly = 0) const;
    
    // Writing operations
    void setFrameBuffer(const FrameBuffer& frameBuffer);
    void writeTile(int dx, int dy, int lx = 0, int ly = 0);
    void writeTiles(int dxMin, int dxMax, int dyMin, int dyMax, int lx = 0, int ly = 0);
    void writeTiles(int dx1, int dx2, int dy1, int dy2, int l);
    
    // Destructor
    ~TiledOutputFile();
};

} // namespace OPENEXR_IMF_NAMESPACE

Multi-Part File Access

Unified access to multi-part EXR files with support for different part types and efficient part switching.

#include <OpenEXR/ImfMultiPartInputFile.h>
#include <OpenEXR/ImfMultiPartOutputFile.h>
#include <OpenEXR/ImfInputPart.h>
#include <OpenEXR/ImfOutputPart.h>

namespace OPENEXR_IMF_NAMESPACE {

class MultiPartInputFile {
public:
    // Constructors
    MultiPartInputFile(const char name[], int numThreads = globalThreadCount());
    MultiPartInputFile(IStream& is, int numThreads = globalThreadCount());
    
    // File information
    int parts() const;
    const Header& header(int n) const;
    const char* fileName() const;
    int version() const;
    
    // Destructor
    ~MultiPartInputFile();
};

class MultiPartOutputFile {
public:
    // Constructors
    MultiPartOutputFile(const char name[], int numParts, const Header headers[], 
                       int numThreads = globalThreadCount());
    MultiPartOutputFile(OStream& os, int numParts, const Header headers[],
                       int numThreads = globalThreadCount());
    
    // File information
    int parts() const;
    const Header& header(int n) const;
    
    // Destructor
    ~MultiPartOutputFile();
};

// Part-based access classes
class InputPart {
public:
    InputPart(MultiPartInputFile& multiPartFile, int partNumber);
    
    // File information
    const Header& header() const;
    int version() const;
    bool isComplete() const;
    
    // Reading operations (scanline)
    void setFrameBuffer(const FrameBuffer& frameBuffer);
    void readPixels(int scanLine1, int scanLine2);
    void readPixels(int scanLine);
};

class OutputPart {
public:
    OutputPart(MultiPartOutputFile& multiPartFile, int partNumber);
    
    // File information
    const Header& header() const;
    const FrameBuffer& frameBuffer() const;
    int currentScanLine() const;
    
    // Writing operations (scanline)
    void setFrameBuffer(const FrameBuffer& frameBuffer);
    void writePixels(int numScanLines = 1);
};

class TiledInputPart {
public:
    TiledInputPart(MultiPartInputFile& multiPartFile, int partNumber);
    
    // Tiled operations
    void setFrameBuffer(const FrameBuffer& frameBuffer);
    void readTile(int dx, int dy, int lx = 0, int ly = 0);
    void readTiles(int dxMin, int dxMax, int dyMin, int dyMax, int lx = 0, int ly = 0);
    
    // Tile information
    unsigned int tileXSize() const;
    unsigned int tileYSize() const;
    LevelMode levelMode() const;
    LevelRoundingMode levelRoundingMode() const;
};

class TiledOutputPart {
public:
    TiledOutputPart(MultiPartOutputFile& multiPartFile, int partNumber);
    
    // Tiled operations  
    void setFrameBuffer(const FrameBuffer& frameBuffer);
    void writeTile(int dx, int dy, int lx = 0, int ly = 0);
    void writeTiles(int dxMin, int dxMax, int dyMin, int dyMax, int lx = 0, int ly = 0);
    
    // Tile information
    unsigned int tileXSize() const;
    unsigned int tileYSize() const;
    LevelMode levelMode() const;
    LevelRoundingMode levelRoundingMode() const;
};

} // namespace OPENEXR_IMF_NAMESPACE

Deep Image Support

Advanced deep compositing support with variable sample counts per pixel.

#include <OpenEXR/ImfDeepScanLineInputFile.h>
#include <OpenEXR/ImfDeepScanLineOutputFile.h>
#include <OpenEXR/ImfDeepTiledInputFile.h>
#include <OpenEXR/ImfDeepTiledOutputFile.h>
#include <OpenEXR/ImfDeepFrameBuffer.h>

namespace OPENEXR_IMF_NAMESPACE {

class DeepScanLineInputFile {
public:
    DeepScanLineInputFile(const char name[], int numThreads = globalThreadCount());
    DeepScanLineInputFile(IStream& is, int numThreads = globalThreadCount());
    
    // File information
    const Header& header() const;
    const char* fileName() const;
    int version() const;
    
    // Deep reading operations
    void setFrameBuffer(const DeepFrameBuffer& frameBuffer);
    void readPixelSampleCounts(int scanline1, int scanline2);
    void readPixelSampleCounts(int scanline);
    void readPixels(int scanline1, int scanline2);
    void readPixels(int scanline);
    
    // Sample count access
    int firstScanLineInChunk(int y) const;
    int lastScanLineInChunk(int y) const;
};

class DeepScanLineOutputFile {
public:
    DeepScanLineOutputFile(const char name[], const Header& header, 
                          int numThreads = globalThreadCount());
    DeepScanLineOutputFile(OStream& os, const Header& header,
                          int numThreads = globalThreadCount());
    
    // File information
    const Header& header() const;
    const DeepFrameBuffer& frameBuffer() const;
    int currentScanLine() const;
    
    // Deep writing operations
    void setFrameBuffer(const DeepFrameBuffer& frameBuffer);
    void writePixels(int numScanLines = 1);
};

// Deep frame buffer structures
struct DeepSlice {
    PixelType type;           // Pixel data type
    char* base;              // Base pointer to sample data
    size_t xStride;          // Stride between pixels
    size_t yStride;          // Stride between scanlines  
    size_t sampleStride;     // Stride between samples
    int xSampling;           // Horizontal subsampling
    int ySampling;           // Vertical subsampling
    bool fillValue;          // Fill value for missing data
    bool xTileCoords;        // Use tile coordinates
    bool yTileCoords;        // Use tile coordinates
    
    DeepSlice(PixelType type = HALF,
              char* base = 0,
              size_t xStride = 0,
              size_t yStride = 0,
              size_t sampleStride = 0,
              int xSampling = 1,
              int ySampling = 1,
              double fillValue = 0.0,
              bool xTileCoords = false,
              bool yTileCoords = false);
};

class DeepFrameBuffer {
public:
    void insert(const char name[], const DeepSlice& slice);
    void insert(const std::string& name, const DeepSlice& slice);
    
    DeepSlice& operator[](const char name[]);
    const DeepSlice& operator[](const char name[]) const;
    DeepSlice& operator[](const std::string& name);
    const DeepSlice& operator[](const std::string& name) const;
    
    DeepSlice* findSlice(const char name[]);
    const DeepSlice* findSlice(const char name[]) const;
    DeepSlice* findSlice(const std::string& name);
    const DeepSlice* findSlice(const std::string& name) const;
    
    typedef std::map<Name, DeepSlice> SliceMap;
    
    typedef SliceMap::iterator Iterator;
    typedef SliceMap::const_iterator ConstIterator;
    
    Iterator begin();
    ConstIterator begin() const;
    Iterator end();
    ConstIterator end() const;
    Iterator find(const char name[]);
    ConstIterator find(const char name[]) const;
    Iterator find(const std::string& name);
    ConstIterator find(const std::string& name) const;
};

} // namespace OPENEXR_IMF_NAMESPACE

Header and Metadata Management

Comprehensive header and attribute management for custom metadata and format configuration.

#include <OpenEXR/ImfHeader.h>
#include <OpenEXR/ImfAttribute.h>
#include <OpenEXR/ImfStandardAttributes.h>
#include <OpenEXR/ImfChannelList.h>

namespace OPENEXR_IMF_NAMESPACE {

class Header {
public:
    // Constructors
    Header(int width = 64, int height = 64,
           float pixelAspectRatio = 1,
           const IMATH_NAMESPACE::V2f& screenWindowCenter = IMATH_NAMESPACE::V2f(0, 0),
           float screenWindowWidth = 1,
           LineOrder lineOrder = INCREASING_Y,
           Compression compression = ZIP_COMPRESSION);
    
    Header(const IMATH_NAMESPACE::Box2i& displayWindow,
           const IMATH_NAMESPACE::Box2i& dataWindow,
           float pixelAspectRatio = 1,
           const IMATH_NAMESPACE::V2f& screenWindowCenter = IMATH_NAMESPACE::V2f(0, 0),
           float screenWindowWidth = 1,
           LineOrder lineOrder = INCREASING_Y,
           Compression compression = ZIP_COMPRESSION);
    
    // Copy constructor and assignment
    Header(const Header& other);
    Header& operator=(const Header& other);
    
    // Attribute management
    void insert(const char name[], const Attribute& attribute);
    void insert(const std::string& name, const Attribute& attribute);
    void erase(const char name[]);
    void erase(const std::string& name);
    
    Attribute& operator[](const char name[]);
    const Attribute& operator[](const char name[]) const;
    Attribute& operator[](const std::string& name);
    const Attribute& operator[](const std::string& name) const;
    
    // Attribute lookup
    Iterator find(const char name[]);
    ConstIterator find(const char name[]) const;
    Iterator find(const std::string& name);
    ConstIterator find(const std::string& name) const;
    
    // Standard attribute accessors
    IMATH_NAMESPACE::Box2i& displayWindow();
    const IMATH_NAMESPACE::Box2i& displayWindow() const;
    IMATH_NAMESPACE::Box2i& dataWindow();
    const IMATH_NAMESPACE::Box2i& dataWindow() const;
    float& pixelAspectRatio();
    const float& pixelAspectRatio() const;
    IMATH_NAMESPACE::V2f& screenWindowCenter();
    const IMATH_NAMESPACE::V2f& screenWindowCenter() const;
    float& screenWindowWidth();
    const float& screenWindowWidth() const;
    ChannelList& channels();
    const ChannelList& channels() const;
    LineOrder& lineOrder();
    const LineOrder& lineOrder() const;
    Compression& compression();
    const Compression& compression() const;
    
    // Type checking for different file types
    bool hasType() const;
    void setType(const std::string& type);
    bool isTiled() const;
    bool isComplete() const;
    
    // Multi-part support
    bool hasName() const;
    void setName(const std::string& name);
    
    // Validation
    void sanityCheck(bool isTiled = false, bool isMultipartFile = false) const;
    
    // Iterator support
    typedef std::map<Name, Attribute*> AttributeMap;
    typedef AttributeMap::iterator Iterator;
    typedef AttributeMap::const_iterator ConstIterator;
    
    Iterator begin();
    ConstIterator begin() const;
    Iterator end();  
    ConstIterator end() const;
};

// Typed attribute template
template <class T>
class TypedAttribute : public Attribute {
public:
    typedef T ValueType;
    
    TypedAttribute();
    TypedAttribute(const T& value);
    TypedAttribute(const TypedAttribute<T>& other);
    virtual ~TypedAttribute();
    
    virtual const char* typeName() const;
    virtual Attribute* copy() const;
    virtual void writeValueTo(OStream& os, int version) const;
    virtual void readValueFrom(IStream& is, int size, int version);
    virtual void copyValueFrom(const Attribute& other);
    
    T& value();
    const T& value() const;
    
    TypedAttribute& operator=(const TypedAttribute<T>& other);
};

// Channel list management
class ChannelList {
public:
    // Channel insertion and removal
    void insert(const char name[], const Channel& channel);
    void insert(const std::string& name, const Channel& channel);
    void erase(const char name[]);
    void erase(const std::string& name);
    
    // Channel access
    Channel& operator[](const char name[]);
    const Channel& operator[](const char name[]) const;
    Channel& operator[](const std::string& name);
    const Channel& operator[](const std::string& name) const;
    
    // Channel lookup
    Iterator find(const char name[]);
    ConstIterator find(const char name[]) const;
    Iterator find(const std::string& name);
    ConstIterator find(const std::string& name) const;
    
    // Utilities
    bool operator==(const ChannelList& other) const;
    bool operator!=(const ChannelList& other) const;
    
    // Iteration support
    typedef std::map<Name, Channel> ChannelMap;
    typedef ChannelMap::iterator Iterator;
    typedef ChannelMap::const_iterator ConstIterator;
    
    Iterator begin();
    ConstIterator begin() const;
    Iterator end();
    ConstIterator end() const;
};

struct Channel {
    PixelType type;         // Data type (UINT, HALF, FLOAT)
    int xSampling;          // Horizontal subsampling factor
    int ySampling;          // Vertical subsampling factor
    bool pLinear;           // Perceptually linear flag
    
    Channel(PixelType type = HALF,
            int xSampling = 1,
            int ySampling = 1, 
            bool pLinear = false);
    
    bool operator==(const Channel& other) const;
    bool operator!=(const Channel& other) const;
};

} // namespace OPENEXR_IMF_NAMESPACE

Frame Buffer Management

Efficient pixel data management with support for different layouts and zero-copy operations.

#include <OpenEXR/ImfFrameBuffer.h>
#include <OpenEXR/ImfPixelType.h>

namespace OPENEXR_IMF_NAMESPACE {

struct Slice {
    PixelType type;           // Pixel data type
    char* base;               // Base pointer to pixel data
    size_t xStride;           // Bytes between horizontally adjacent pixels
    size_t yStride;           // Bytes between vertically adjacent pixels
    int xSampling;            // Horizontal subsampling factor
    int ySampling;            // Vertical subsampling factor
    double fillValue;         // Fill value for missing pixels
    bool xTileCoords;         // Use tile coordinates for addressing
    bool yTileCoords;         // Use tile coordinates for addressing
    
    Slice(PixelType type = HALF,
          char* base = 0,
          size_t xStride = 0,
          size_t yStride = 0,
          int xSampling = 1,
          int ySampling = 1,
          double fillValue = 0.0,
          bool xTileCoords = false,
          bool yTileCoords = false);
};

class FrameBuffer {
public:
    // Slice management
    void insert(const char name[], const Slice& slice);
    void insert(const std::string& name, const Slice& slice);
    
    Slice& operator[](const char name[]);
    const Slice& operator[](const char name[]) const;
    Slice& operator[](const std::string& name);
    const Slice& operator[](const std::string& name) const;
    
    // Slice lookup
    Iterator find(const char name[]);
    ConstIterator find(const char name[]) const;
    Iterator find(const std::string& name);
    ConstIterator find(const std::string& name) const;
    
    Slice* findSlice(const char name[]);
    const Slice* findSlice(const char name[]) const;
    Slice* findSlice(const std::string& name);
    const Slice* findSlice(const std::string& name) const;
    
    // Iteration support
    typedef std::map<Name, Slice> SliceMap;
    typedef SliceMap::iterator Iterator;
    typedef SliceMap::const_iterator ConstIterator;
    
    Iterator begin();
    ConstIterator begin() const;
    Iterator end();
    ConstIterator end() const;
};

// Pixel type enumeration
enum PixelType {
    UINT = 0,   // 32-bit unsigned integer
    HALF = 1,   // 16-bit floating point (half precision)
    FLOAT = 2,  // 32-bit floating point (single precision)
    NUM_PIXELTYPES
};

// Pixel type utilities
int pixelTypeSize(PixelType type);
const char* pixelTypeToString(PixelType type);

} // namespace OPENEXR_IMF_NAMESPACE

RGBA Convenience Interface

Simplified high-level interface for common RGBA workflows with automatic format conversions.

#include <OpenEXR/ImfRgbaFile.h>
#include <OpenEXR/ImfRgba.h>
#include <OpenEXR/ImfArray.h>

namespace OPENEXR_IMF_NAMESPACE {

struct Rgba {
    half r, g, b, a;
    
    Rgba();
    Rgba(half r, half g, half b, half a = 1.f);
    Rgba(float r, float g, float b, float a = 1.f);
};

enum RgbaChannels {
    WRITE_R = 0x01,     // Red channel
    WRITE_G = 0x02,     // Green channel
    WRITE_B = 0x04,     // Blue channel
    WRITE_A = 0x08,     // Alpha channel
    WRITE_Y = 0x10,     // Luminance channel
    WRITE_C = 0x20,     // Chroma channels
    WRITE_RGB = 0x07,   // Red, green, blue
    WRITE_RGBA = 0x0f,  // Red, green, blue, alpha
    WRITE_YC = 0x30,    // Luminance, chroma
    WRITE_YA = 0x18,    // Luminance, alpha
    WRITE_YCA = 0x38    // Luminance, chroma, alpha
};

class RgbaOutputFile {
public:
    // Constructors
    RgbaOutputFile(const char name[], const Header& header, RgbaChannels rgbaChannels = WRITE_RGBA,
                   int numThreads = globalThreadCount());
    RgbaOutputFile(const char name[], int width, int height, RgbaChannels rgbaChannels = WRITE_RGBA,
                   float pixelAspectRatio = 1, const IMATH_NAMESPACE::V2f& screenWindowCenter = IMATH_NAMESPACE::V2f(0, 0),
                   float screenWindowWidth = 1, LineOrder lineOrder = INCREASING_Y,
                   Compression compression = ZIP_COMPRESSION, int numThreads = globalThreadCount());
    RgbaOutputFile(OStream& os, const Header& header, RgbaChannels rgbaChannels = WRITE_RGBA,
                   int numThreads = globalThreadCount());
    RgbaOutputFile(OStream& os, int width, int height, RgbaChannels rgbaChannels = WRITE_RGBA,
                   float pixelAspectRatio = 1, const IMATH_NAMESPACE::V2f& screenWindowCenter = IMATH_NAMESPACE::V2f(0, 0),
                   float screenWindowWidth = 1, LineOrder lineOrder = INCREASING_Y,
                   Compression compression = ZIP_COMPRESSION, int numThreads = globalThreadCount());
    
    // File operations
    void setFrameBuffer(const Rgba* base, size_t xStride, size_t yStride);
    void writePixels(int numScanLines = 1);
    void writePixels(const Rgba* base, int scanLine1, int scanLine2);
    
    // File information
    const Header& header() const;
    const FrameBuffer& frameBuffer() const;
    const IMATH_NAMESPACE::Box2i& displayWindow() const;
    const IMATH_NAMESPACE::Box2i& dataWindow() const;
    float pixelAspectRatio() const;
    const IMATH_NAMESPACE::V2f& screenWindowCenter() const;
    float screenWindowWidth() const;
    LineOrder lineOrder() const;
    Compression compression() const;
    RgbaChannels channels() const;
    
    // Utilities
    int currentScanLine() const;
    
    // Destructor
    ~RgbaOutputFile();
};

class RgbaInputFile {
public:
    // Constructors
    RgbaInputFile(const char name[], int numThreads = globalThreadCount());
    RgbaInputFile(IStream& is, int numThreads = globalThreadCount());
    
    // File operations
    void setFrameBuffer(const Rgba* base, size_t xStride, size_t yStride);
    void readPixels(int scanLine1, int scanLine2);
    void readPixels(int scanLine);
    void readPixels(Rgba* base, int scanLine1, int scanLine2);
    
    // File information
    const Header& header() const;
    const FrameBuffer& frameBuffer() const;
    const IMATH_NAMESPACE::Box2i& displayWindow() const;
    const IMATH_NAMESPACE::Box2i& dataWindow() const;
    float pixelAspectRatio() const;
    const IMATH_NAMESPACE::V2f& screenWindowCenter() const;
    float screenWindowWidth() const;
    LineOrder lineOrder() const;
    Compression compression() const;
    RgbaChannels channels() const;
    const char* fileName() const;
    int version() const;
    bool isComplete() const;
    
    // Destructor
    ~RgbaInputFile();
};

// Array template for managing RGBA pixel arrays
template <class T>
class Array {
public:
    typedef T value_type;
    
    // Constructors
    Array();
    Array(long size);
    Array(long size, bool initialize, const T& value = T());
    Array(const Array& other);
    
    // Assignment
    Array& operator=(const Array& other);
    
    // Access
    T& operator[](long i);
    const T& operator[](long i) const;
    
    // Size management
    void resizeErase(long size);
    void resizeEraseUnsafe(long size);
    void resizeNoErase(long size);
    long size() const;
    
    // Destructor
    ~Array();
};

typedef Array<Rgba> Array2D;

} // namespace OPENEXR_IMF_NAMESPACE

Threading and Performance

Multi-threading support and performance optimization utilities.

#include <OpenEXR/ImfThreading.h>
#include <IlmThread/IlmThread.h>
#include <IlmThread/IlmThreadPool.h>

namespace OPENEXR_IMF_NAMESPACE {

// Global threading control
void setGlobalThreadCount(int count);
int globalThreadCount();

} // namespace OPENEXR_IMF_NAMESPACE

namespace ILMTHREAD_NAMESPACE {

class Thread {
public:
    Thread();
    virtual ~Thread();
    
    void start();
    void join();
    bool joinable() const;
    
protected:
    virtual void run() = 0;
    
private:
    // Implementation details hidden
    struct Data;
    Data* _data;
};

class Mutex {
public:
    Mutex();
    ~Mutex();
    
    void lock();
    void unlock();
    
private:
    // Implementation details hidden  
    struct Data;
    Data* _data;
};

class Lock {
public:
    Lock(const Mutex& m, bool autoLock = true);
    ~Lock();
    
    void acquire();
    void release();
    bool locked() const;
    
private:
    const Mutex* _mutex;
    bool _locked;
};

class Semaphore {
public:
    Semaphore(unsigned int value = 0);
    virtual ~Semaphore();
    
    void wait();
    bool tryWait();
    void post();
    int value() const;
    
private:
    // Implementation details hidden
    struct Data;
    Data* _data;
};

class Task {
public:
    Task(TaskGroup* g);
    virtual ~Task();
    
    virtual void execute() = 0;
    
    TaskGroup* group();
    
private:
    TaskGroup* _group;
};

class TaskGroup {
public:
    TaskGroup();
    ~TaskGroup();
    
    void addTask(Task* task);
    void executeAndDestroy();
    
private:
    // Implementation details hidden
    struct Data;
    Data* _data;
};

class ThreadPool {
public:
    ThreadPool(unsigned int nthreads = 0);
    virtual ~ThreadPool();
    
    int numThreads() const;
    void setNumThreads(int count);
    
    void addTask(Task* task);
    void addGlobalTask(Task* task);
    
    static ThreadPool& globalThreadPool();
    static void addGlobalTask(Task* task);
    
private:
    // Implementation details hidden
    struct Data;
    Data* _data;
};

} // namespace ILMTHREAD_NAMESPACE

Usage Examples

Basic C++ Reading and Writing

#include <OpenEXR/ImfInputFile.h>
#include <OpenEXR/ImfOutputFile.h>
#include <OpenEXR/ImfChannelList.h>
#include <OpenEXR/ImfFrameBuffer.h>
#include <OpenEXR/ImfHeader.h>
#include <OpenEXR/ImfArray.h>
#include <iostream>

using namespace OPENEXR_IMF_NAMESPACE;
using namespace IMATH_NAMESPACE;

void writeBasicEXR(const char* filename, int width, int height) {
    // Create pixel data arrays
    Array2D<float> rPixels(height, width);
    Array2D<float> gPixels(height, width);
    Array2D<float> bPixels(height, width);
    Array2D<float> aPixels(height, width);
    
    // Fill with sample data
    for (int y = 0; y < height; ++y) {
        for (int x = 0; x < width; ++x) {
            rPixels[y][x] = float(x) / width;
            gPixels[y][x] = float(y) / height;
            bPixels[y][x] = 0.5f;
            aPixels[y][x] = 1.0f;
        }
    }
    
    // Create header
    Header header(width, height);
    header.channels().insert("R", Channel(FLOAT));
    header.channels().insert("G", Channel(FLOAT));
    header.channels().insert("B", Channel(FLOAT));
    header.channels().insert("A", Channel(FLOAT));
    header.compression() = ZIP_COMPRESSION;
    
    // Custom attributes
    header.insert("software", StringAttribute("C++ Example v1.0"));
    header.insert("comments", StringAttribute("Basic RGB+A image"));
    
    // Create output file
    OutputFile file(filename, header);
    
    // Set up frame buffer
    FrameBuffer frameBuffer;
    frameBuffer.insert("R", Slice(FLOAT, (char*)&rPixels[0][0], 
                                 sizeof(float), sizeof(float) * width));
    frameBuffer.insert("G", Slice(FLOAT, (char*)&gPixels[0][0],
                                 sizeof(float), sizeof(float) * width));
    frameBuffer.insert("B", Slice(FLOAT, (char*)&bPixels[0][0],
                                 sizeof(float), sizeof(float) * width));
    frameBuffer.insert("A", Slice(FLOAT, (char*)&aPixels[0][0],
                                 sizeof(float), sizeof(float) * width));
    
    file.setFrameBuffer(frameBuffer);
    file.writePixels(height);
    
    std::cout << "Wrote " << filename << " (" << width << "x" << height << ")\n";
}

void readBasicEXR(const char* filename) {
    // Open file for reading
    InputFile file(filename);
    
    // Get file information
    const Header& header = file.header();
    Box2i dw = header.dataWindow();
    int width = dw.max.x - dw.min.x + 1;
    int height = dw.max.y - dw.min.y + 1;
    
    std::cout << "Reading " << filename << " (" << width << "x" << height << ")\n";
    std::cout << "Compression: " << header.compression() << std::endl;
    
    // Check available channels
    const ChannelList& channels = header.channels();
    for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i) {
        const char* name = i.name();
        const Channel& channel = i.channel();
        std::cout << "Channel: " << name << " (type=" << channel.type << ")\n";
    }
    
    // Allocate pixel arrays
    Array2D<float> rPixels(height, width);
    Array2D<float> gPixels(height, width);
    Array2D<float> bPixels(height, width);
    
    // Set up frame buffer for reading
    FrameBuffer frameBuffer;
    frameBuffer.insert("R", Slice(FLOAT, (char*)&rPixels[0][0] - dw.min.x - dw.min.y * width,
                                 sizeof(float), sizeof(float) * width, 1, 1, 0.0));
    frameBuffer.insert("G", Slice(FLOAT, (char*)&gPixels[0][0] - dw.min.x - dw.min.y * width,
                                 sizeof(float), sizeof(float) * width, 1, 1, 0.0));
    frameBuffer.insert("B", Slice(FLOAT, (char*)&bPixels[0][0] - dw.min.x - dw.min.y * width,
                                 sizeof(float), sizeof(float) * width, 1, 1, 0.0));
    
    file.setFrameBuffer(frameBuffer);
    file.readPixels(dw.min.y, dw.max.y);
    
    // Print sample values
    std::cout << "Sample pixel values at (100, 100):\n";
    if (100 < height && 100 < width) {
        std::cout << "  R=" << rPixels[100][100] 
                  << " G=" << gPixels[100][100]
                  << " B=" << bPixels[100][100] << std::endl;
    }
}

int main() {
    writeBasicEXR("basic_cpp.exr", 1920, 1080);
    readBasicEXR("basic_cpp.exr");
    return 0;
}

Multi-Part C++ Implementation

#include <OpenEXR/ImfMultiPartInputFile.h>
#include <OpenEXR/ImfMultiPartOutputFile.h>
#include <OpenEXR/ImfInputPart.h>
#include <OpenEXR/ImfOutputPart.h>
#include <OpenEXR/ImfPartType.h>
#include <OpenEXR/ImfArray.h>
#include <vector>

using namespace OPENEXR_IMF_NAMESPACE;
using namespace IMATH_NAMESPACE;

void createMultiPartEXR(const char* filename, int width, int height) {
    // Create headers for different parts
    std::vector<Header> headers(3);
    
    // Beauty pass header
    headers[0] = Header(width, height);
    headers[0].setName("beauty");
    headers[0].setType(SCANLINEIMAGE);
    headers[0].channels().insert("R", Channel(HALF));
    headers[0].channels().insert("G", Channel(HALF));
    headers[0].channels().insert("B", Channel(HALF));
    headers[0].channels().insert("A", Channel(HALF));
    headers[0].compression() = DWAA_COMPRESSION;
    headers[0].insert("renderPass", StringAttribute("beauty"));
    
    // Depth pass header
    headers[1] = Header(width, height);
    headers[1].setName("depth");
    headers[1].setType(SCANLINEIMAGE);
    headers[1].channels().insert("Z", Channel(FLOAT));
    headers[1].compression() = ZIP_COMPRESSION;
    headers[1].insert("renderPass", StringAttribute("depth"));
    
    // Normal pass header  
    headers[2] = Header(width, height);
    headers[2].setName("normal");
    headers[2].setType(SCANLINEIMAGE);
    headers[2].channels().insert("N.X", Channel(HALF));
    headers[2].channels().insert("N.Y", Channel(HALF));
    headers[2].channels().insert("N.Z", Channel(HALF));
    headers[2].compression() = ZIP_COMPRESSION;
    headers[2].insert("renderPass", StringAttribute("normal"));
    
    // Create multi-part output file
    MultiPartOutputFile file(filename, 3, &headers[0]);
    
    // Create pixel data
    Array2D<half> beautyR(height, width), beautyG(height, width), 
                  beautyB(height, width), beautyA(height, width);
    Array2D<float> depth(height, width);
    Array2D<half> normalX(height, width), normalY(height, width), normalZ(height, width);
    
    // Fill sample data
    for (int y = 0; y < height; ++y) {
        for (int x = 0; x < width; ++x) {
            // Beauty data
            beautyR[y][x] = half(float(x) / width);
            beautyG[y][x] = half(float(y) / height);
            beautyB[y][x] = half(0.5f);
            beautyA[y][x] = half(1.0f);
            
            // Depth data
            depth[y][x] = 10.0f + float(x + y) * 0.01f;
            
            // Normal data (pointing toward camera)
            normalX[y][x] = half(0.0f);
            normalY[y][x] = half(0.0f);
            normalZ[y][x] = half(1.0f);
        }
    }
    
    // Write beauty pass (Part 0)
    {
        OutputPart part(file, 0);
        FrameBuffer frameBuffer;
        
        frameBuffer.insert("R", Slice(HALF, (char*)&beautyR[0][0], 
                                     sizeof(half), sizeof(half) * width));
        frameBuffer.insert("G", Slice(HALF, (char*)&beautyG[0][0],
                                     sizeof(half), sizeof(half) * width));
        frameBuffer.insert("B", Slice(HALF, (char*)&beautyB[0][0],
                                     sizeof(half), sizeof(half) * width));
        frameBuffer.insert("A", Slice(HALF, (char*)&beautyA[0][0],
                                     sizeof(half), sizeof(half) * width));
        
        part.setFrameBuffer(frameBuffer);
        part.writePixels(height);
    }
    
    // Write depth pass (Part 1)
    {
        OutputPart part(file, 1);
        FrameBuffer frameBuffer;
        
        frameBuffer.insert("Z", Slice(FLOAT, (char*)&depth[0][0],
                                     sizeof(float), sizeof(float) * width));
        
        part.setFrameBuffer(frameBuffer);
        part.writePixels(height);
    }
    
    // Write normal pass (Part 2)
    {
        OutputPart part(file, 2);
        FrameBuffer frameBuffer;
        
        frameBuffer.insert("N.X", Slice(HALF, (char*)&normalX[0][0],
                                       sizeof(half), sizeof(half) * width));
        frameBuffer.insert("N.Y", Slice(HALF, (char*)&normalY[0][0],
                                       sizeof(half), sizeof(half) * width));
        frameBuffer.insert("N.Z", Slice(HALF, (char*)&normalZ[0][0],
                                       sizeof(half), sizeof(half) * width));
        
        part.setFrameBuffer(frameBuffer);
        part.writePixels(height);
    }
    
    std::cout << "Created multi-part EXR: " << filename << std::endl;
}

void readMultiPartEXR(const char* filename) {
    // Open multi-part file
    MultiPartInputFile file(filename);
    
    int numParts = file.parts();
    std::cout << "Multi-part file has " << numParts << " parts:\n";
    
    // Examine each part
    for (int partNum = 0; partNum < numParts; ++partNum) {
        const Header& header = file.header(partNum);
        
        // Get part information
        std::string partName = "unnamed";
        if (header.hasName()) {
            partName = header.typedAttribute<StringAttribute>("name").value();
        }
        
        std::string renderPass = "unknown";
        try {
            renderPass = header.typedAttribute<StringAttribute>("renderPass").value();
        } catch (...) {}
        
        std::cout << "Part " << partNum << ": " << partName 
                  << " (pass: " << renderPass << ")\n";
        
        // List channels
        const ChannelList& channels = header.channels();
        std::cout << "  Channels: ";
        for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i) {
            std::cout << i.name() << " ";
        }
        std::cout << std::endl;
        
        // Get dimensions
        Box2i dw = header.dataWindow();
        int width = dw.max.x - dw.min.x + 1;
        int height = dw.max.y - dw.min.y + 1;
        std::cout << "  Size: " << width << "x" << height << std::endl;
        std::cout << "  Compression: " << header.compression() << std::endl;
        
        // Read sample data from first channel
        InputPart part(file, partNum);
        ChannelList::ConstIterator firstChannel = channels.begin();
        if (firstChannel != channels.end()) {
            const char* channelName = firstChannel.name();
            const Channel& channel = firstChannel.channel();
            
            if (channel.type == HALF) {
                Array2D<half> pixels(height, width);
                FrameBuffer frameBuffer;
                frameBuffer.insert(channelName, 
                    Slice(HALF, (char*)&pixels[0][0] - dw.min.x - dw.min.y * width,
                          sizeof(half), sizeof(half) * width));
                
                part.setFrameBuffer(frameBuffer);
                part.readPixels(dw.min.y, dw.max.y);
                
                std::cout << "  Sample " << channelName << " value at (100,100): " 
                          << float(pixels[100][100]) << std::endl;
            }
            else if (channel.type == FLOAT) {
                Array2D<float> pixels(height, width);
                FrameBuffer frameBuffer;
                frameBuffer.insert(channelName,
                    Slice(FLOAT, (char*)&pixels[0][0] - dw.min.x - dw.min.y * width,
                          sizeof(float), sizeof(float) * width));
                
                part.setFrameBuffer(frameBuffer);
                part.readPixels(dw.min.y, dw.max.y);
                
                std::cout << "  Sample " << channelName << " value at (100,100): " 
                          << pixels[100][100] << std::endl;
            }
        }
        
        std::cout << std::endl;
    }
}

int main() {
    createMultiPartEXR("multipart_cpp.exr", 1920, 1080);
    readMultiPartEXR("multipart_cpp.exr");
    return 0;
}

High-Performance Tiled Access

#include <OpenEXR/ImfTiledInputFile.h>
#include <OpenEXR/ImfTiledOutputFile.h>
#include <OpenEXR/ImfTileDescription.h>
#include <OpenEXR/ImfArray.h>
#include <OpenEXR/ImfThreading.h>
#include <chrono>

using namespace OPENEXR_IMF_NAMESPACE;
using namespace IMATH_NAMESPACE;

void createTiledEXR(const char* filename, int width, int height, 
                    int tileWidth = 64, int tileHeight = 64) {
    // Create tiled header
    Header header(width, height);
    header.setType(TILEDIMAGE);
    header.channels().insert("R", Channel(HALF));
    header.channels().insert("G", Channel(HALF)); 
    header.channels().insert("B", Channel(HALF));
    header.compression() = ZIP_COMPRESSION;
    
    // Configure tiling with mipmaps
    header.setTileDescription(TileDescription(tileWidth, tileHeight, MIPMAP_LEVELS));
    
    // Add metadata
    header.insert("software", StringAttribute("Tiled C++ Example"));
    header.insert("tileOptimized", IntAttribute(1));
    
    // Enable multi-threading for better performance
    setGlobalThreadCount(8);
    
    TiledOutputFile file(filename, header);
    
    // Create pixel data
    Array2D<half> rPixels(height, width);
    Array2D<half> gPixels(height, width);
    Array2D<half> bPixels(height, width);
    
    // Generate test pattern
    for (int y = 0; y < height; ++y) {
        for (int x = 0; x < width; ++x) {
            float fx = float(x) / width;
            float fy = float(y) / height;
            
            rPixels[y][x] = half(fx * fy);
            gPixels[y][x] = half(fx * (1.0f - fy));
            bPixels[y][x] = half((1.0f - fx) * fy);
        }
    }
    
    // Set up frame buffer
    FrameBuffer frameBuffer;
    frameBuffer.insert("R", Slice(HALF, (char*)&rPixels[0][0],
                                 sizeof(half), sizeof(half) * width));
    frameBuffer.insert("G", Slice(HALF, (char*)&gPixels[0][0],
                                 sizeof(half), sizeof(half) * width));
    frameBuffer.insert("B", Slice(HALF, (char*)&bPixels[0][0],
                                 sizeof(half), sizeof(half) * width));
    
    file.setFrameBuffer(frameBuffer);
    
    // Write all tiles at base level (level 0)
    auto start = std::chrono::high_resolution_clock::now();
    
    int numXTiles = file.numXTiles(0);
    int numYTiles = file.numYTiles(0);
    
    file.writeTiles(0, numXTiles - 1, 0, numYTiles - 1, 0);
    
    auto end = std::chrono::high_resolution_clock::now();
    auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
    
    std::cout << "Created tiled EXR: " << filename << std::endl;
    std::cout << "Image size: " << width << "x" << height << std::endl;
    std::cout << "Tile size: " << tileWidth << "x" << tileHeight << std::endl;
    std::cout << "Number of tiles: " << numXTiles << "x" << numYTiles 
              << " = " << (numXTiles * numYTiles) << std::endl;
    std::cout << "Write time: " << duration.count() << "ms" << std::endl;
    std::cout << "Mipmap levels: " << file.numXLevels() << std::endl;
}

void readTiledEXRRandomAccess(const char* filename) {
    TiledInputFile file(filename);
    
    const Header& header = file.header();
    Box2i dw = header.dataWindow();
    int width = dw.max.x - dw.min.x + 1;
    int height = dw.max.y - dw.min.y + 1;
    
    std::cout << "\nReading tiled file: " << filename << std::endl;
    std::cout << "Tile size: " << file.tileXSize() << "x" << file.tileYSize() << std::endl;
    std::cout << "Level mode: " << file.levelMode() << std::endl;
    
    // Allocate memory for one tile
    int tileWidth = file.tileXSize();
    int tileHeight = file.tileYSize();
    Array2D<half> tileR(tileHeight, tileWidth);
    Array2D<half> tileG(tileHeight, tileWidth);
    Array2D<half> tileB(tileHeight, tileWidth);
    
    // Set up frame buffer for tile reading
    FrameBuffer frameBuffer;
    frameBuffer.insert("R", Slice(HALF, (char*)&tileR[0][0] - dw.min.x - dw.min.y * tileWidth,
                                 sizeof(half), sizeof(half) * tileWidth, 1, 1, 0.0, true, true));
    frameBuffer.insert("G", Slice(HALF, (char*)&tileG[0][0] - dw.min.x - dw.min.y * tileWidth,
                                 sizeof(half), sizeof(half) * tileWidth, 1, 1, 0.0, true, true));
    frameBuffer.insert("B", Slice(HALF, (char*)&tileB[0][0] - dw.min.x - dw.min.y * tileWidth,
                                 sizeof(half), sizeof(half) * tileWidth, 1, 1, 0.0, true, true));
    
    file.setFrameBuffer(frameBuffer);
    
    // Random access pattern - read specific tiles
    auto start = std::chrono::high_resolution_clock::now();
    
    int numXTiles = file.numXTiles(0);
    int numYTiles = file.numYTiles(0);
    
    // Read every 4th tile in a pattern
    for (int ty = 0; ty < numYTiles; ty += 4) {
        for (int tx = 0; tx < numXTiles; tx += 4) {
            file.readTile(tx, ty, 0);  // Read single tile at level 0
            
            // Process tile data (example: compute average)
            float avgR = 0, avgG = 0, avgB = 0;
            for (int y = 0; y < tileHeight; ++y) {
                for (int x = 0; x < tileWidth; ++x) {
                    avgR += float(tileR[y][x]);
                    avgG += float(tileG[y][x]);
                    avgB += float(tileB[y][x]);
                }
            }
            int pixels = tileWidth * tileHeight;
            avgR /= pixels;
            avgG /= pixels;
            avgB /= pixels;
            
            std::cout << "Tile (" << tx << "," << ty << ") average RGB: "
                      << avgR << ", " << avgG << ", " << avgB << std::endl;
        }
    }
    
    auto end = std::chrono::high_resolution_clock::now();
    auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
    
    int tilesRead = ((numXTiles + 3) / 4) * ((numYTiles + 3) / 4);
    std::cout << "Random access read " << tilesRead << " tiles in " 
              << duration.count() << "ms" << std::endl;
}

int main() {
    // Create large tiled image
    createTiledEXR("tiled_cpp.exr", 4096, 4096, 128, 128);
    
    // Demonstrate random access
    readTiledEXRRandomAccess("tiled_cpp.exr");
    
    return 0;
}

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