Professional-grade EXR image format library for high-dynamic-range scene-linear image data with multi-part and deep compositing support
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Low-level C++ interface for maximum performance, custom integrations, and advanced use cases requiring direct control over encoding/decoding operations.
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_NAMESPACEHigh-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_NAMESPACEUnified 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_NAMESPACEAdvanced 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_NAMESPACEComprehensive 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_NAMESPACEEfficient 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_NAMESPACESimplified 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_NAMESPACEMulti-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#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;
}#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;
}#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