0
# C++ API Reference
1
2
Low-level C++ interface for maximum performance, custom integrations, and advanced use cases requiring direct control over encoding/decoding operations.
3
4
## Capabilities
5
6
### Core File I/O Classes
7
8
Primary interfaces for reading and writing EXR files with full control over threading, memory management, and format options.
9
10
```cpp { .api }
11
#include <OpenEXR/ImfInputFile.h>
12
#include <OpenEXR/ImfOutputFile.h>
13
#include <OpenEXR/ImfHeader.h>
14
#include <OpenEXR/ImfFrameBuffer.h>
15
16
namespace OPENEXR_IMF_NAMESPACE {
17
18
class InputFile {
19
public:
20
// Constructors
21
InputFile(const char filename[], int numThreads = globalThreadCount());
22
InputFile(IStream& is, int numThreads = globalThreadCount());
23
24
// File information
25
const Header& header() const;
26
const char* fileName() const;
27
int version() const;
28
bool isComplete() const;
29
30
// Reading operations
31
void setFrameBuffer(const FrameBuffer& frameBuffer);
32
void readPixels(int scanLine1, int scanLine2);
33
void readPixels(int scanLine);
34
35
// Destructor
36
~InputFile();
37
};
38
39
class OutputFile {
40
public:
41
// Constructors
42
OutputFile(const char name[], const Header& header, int numThreads = globalThreadCount());
43
OutputFile(OStream& os, const Header& header, int numThreads = globalThreadCount());
44
45
// File information
46
const Header& header() const;
47
const FrameBuffer& frameBuffer() const;
48
int currentScanLine() const;
49
50
// Writing operations
51
void setFrameBuffer(const FrameBuffer& frameBuffer);
52
void writePixels(int numScanLines = 1);
53
54
// Destructor
55
~OutputFile();
56
};
57
58
} // namespace OPENEXR_IMF_NAMESPACE
59
```
60
61
### Tiled Image Support
62
63
High-performance tiled image access for random access patterns and multi-resolution workflows.
64
65
```cpp { .api }
66
#include <OpenEXR/ImfTiledInputFile.h>
67
#include <OpenEXR/ImfTiledOutputFile.h>
68
#include <OpenEXR/ImfTileDescription.h>
69
70
namespace OPENEXR_IMF_NAMESPACE {
71
72
class TiledInputFile {
73
public:
74
// Constructors
75
TiledInputFile(const char name[], int numThreads = globalThreadCount());
76
TiledInputFile(IStream& is, int numThreads = globalThreadCount());
77
78
// File information
79
const Header& header() const;
80
const char* fileName() const;
81
int version() const;
82
83
// Tile information
84
unsigned int tileXSize() const;
85
unsigned int tileYSize() const;
86
LevelMode levelMode() const;
87
LevelRoundingMode levelRoundingMode() const;
88
int numXLevels() const;
89
int numYLevels() const;
90
int numXTiles(int lx = 0) const;
91
int numYTiles(int ly = 0) const;
92
93
// Reading operations
94
void setFrameBuffer(const FrameBuffer& frameBuffer);
95
void readTile(int dx, int dy, int lx = 0, int ly = 0);
96
void readTiles(int dxMin, int dxMax, int dyMin, int dyMax, int lx = 0, int ly = 0);
97
void readAllTiles(int lx = 0, int ly = 0);
98
99
// Destructor
100
~TiledInputFile();
101
};
102
103
class TiledOutputFile {
104
public:
105
// Constructors
106
TiledOutputFile(const char name[], const Header& header, int numThreads = globalThreadCount());
107
TiledOutputFile(OStream& os, const Header& header, int numThreads = globalThreadCount());
108
109
// File information
110
const Header& header() const;
111
const FrameBuffer& frameBuffer() const;
112
113
// Tile information
114
unsigned int tileXSize() const;
115
unsigned int tileYSize() const;
116
LevelMode levelMode() const;
117
LevelRoundingMode levelRoundingMode() const;
118
int numXLevels() const;
119
int numYLevels() const;
120
int numXTiles(int lx = 0) const;
121
int numYTiles(int ly = 0) const;
122
123
// Writing operations
124
void setFrameBuffer(const FrameBuffer& frameBuffer);
125
void writeTile(int dx, int dy, int lx = 0, int ly = 0);
126
void writeTiles(int dxMin, int dxMax, int dyMin, int dyMax, int lx = 0, int ly = 0);
127
void writeTiles(int dx1, int dx2, int dy1, int dy2, int l);
128
129
// Destructor
130
~TiledOutputFile();
131
};
132
133
} // namespace OPENEXR_IMF_NAMESPACE
134
```
135
136
### Multi-Part File Access
137
138
Unified access to multi-part EXR files with support for different part types and efficient part switching.
139
140
```cpp { .api }
141
#include <OpenEXR/ImfMultiPartInputFile.h>
142
#include <OpenEXR/ImfMultiPartOutputFile.h>
143
#include <OpenEXR/ImfInputPart.h>
144
#include <OpenEXR/ImfOutputPart.h>
145
146
namespace OPENEXR_IMF_NAMESPACE {
147
148
class MultiPartInputFile {
149
public:
150
// Constructors
151
MultiPartInputFile(const char name[], int numThreads = globalThreadCount());
152
MultiPartInputFile(IStream& is, int numThreads = globalThreadCount());
153
154
// File information
155
int parts() const;
156
const Header& header(int n) const;
157
const char* fileName() const;
158
int version() const;
159
160
// Destructor
161
~MultiPartInputFile();
162
};
163
164
class MultiPartOutputFile {
165
public:
166
// Constructors
167
MultiPartOutputFile(const char name[], int numParts, const Header headers[],
168
int numThreads = globalThreadCount());
169
MultiPartOutputFile(OStream& os, int numParts, const Header headers[],
170
int numThreads = globalThreadCount());
171
172
// File information
173
int parts() const;
174
const Header& header(int n) const;
175
176
// Destructor
177
~MultiPartOutputFile();
178
};
179
180
// Part-based access classes
181
class InputPart {
182
public:
183
InputPart(MultiPartInputFile& multiPartFile, int partNumber);
184
185
// File information
186
const Header& header() const;
187
int version() const;
188
bool isComplete() const;
189
190
// Reading operations (scanline)
191
void setFrameBuffer(const FrameBuffer& frameBuffer);
192
void readPixels(int scanLine1, int scanLine2);
193
void readPixels(int scanLine);
194
};
195
196
class OutputPart {
197
public:
198
OutputPart(MultiPartOutputFile& multiPartFile, int partNumber);
199
200
// File information
201
const Header& header() const;
202
const FrameBuffer& frameBuffer() const;
203
int currentScanLine() const;
204
205
// Writing operations (scanline)
206
void setFrameBuffer(const FrameBuffer& frameBuffer);
207
void writePixels(int numScanLines = 1);
208
};
209
210
class TiledInputPart {
211
public:
212
TiledInputPart(MultiPartInputFile& multiPartFile, int partNumber);
213
214
// Tiled operations
215
void setFrameBuffer(const FrameBuffer& frameBuffer);
216
void readTile(int dx, int dy, int lx = 0, int ly = 0);
217
void readTiles(int dxMin, int dxMax, int dyMin, int dyMax, int lx = 0, int ly = 0);
218
219
// Tile information
220
unsigned int tileXSize() const;
221
unsigned int tileYSize() const;
222
LevelMode levelMode() const;
223
LevelRoundingMode levelRoundingMode() const;
224
};
225
226
class TiledOutputPart {
227
public:
228
TiledOutputPart(MultiPartOutputFile& multiPartFile, int partNumber);
229
230
// Tiled operations
231
void setFrameBuffer(const FrameBuffer& frameBuffer);
232
void writeTile(int dx, int dy, int lx = 0, int ly = 0);
233
void writeTiles(int dxMin, int dxMax, int dyMin, int dyMax, int lx = 0, int ly = 0);
234
235
// Tile information
236
unsigned int tileXSize() const;
237
unsigned int tileYSize() const;
238
LevelMode levelMode() const;
239
LevelRoundingMode levelRoundingMode() const;
240
};
241
242
} // namespace OPENEXR_IMF_NAMESPACE
243
```
244
245
### Deep Image Support
246
247
Advanced deep compositing support with variable sample counts per pixel.
248
249
```cpp { .api }
250
#include <OpenEXR/ImfDeepScanLineInputFile.h>
251
#include <OpenEXR/ImfDeepScanLineOutputFile.h>
252
#include <OpenEXR/ImfDeepTiledInputFile.h>
253
#include <OpenEXR/ImfDeepTiledOutputFile.h>
254
#include <OpenEXR/ImfDeepFrameBuffer.h>
255
256
namespace OPENEXR_IMF_NAMESPACE {
257
258
class DeepScanLineInputFile {
259
public:
260
DeepScanLineInputFile(const char name[], int numThreads = globalThreadCount());
261
DeepScanLineInputFile(IStream& is, int numThreads = globalThreadCount());
262
263
// File information
264
const Header& header() const;
265
const char* fileName() const;
266
int version() const;
267
268
// Deep reading operations
269
void setFrameBuffer(const DeepFrameBuffer& frameBuffer);
270
void readPixelSampleCounts(int scanline1, int scanline2);
271
void readPixelSampleCounts(int scanline);
272
void readPixels(int scanline1, int scanline2);
273
void readPixels(int scanline);
274
275
// Sample count access
276
int firstScanLineInChunk(int y) const;
277
int lastScanLineInChunk(int y) const;
278
};
279
280
class DeepScanLineOutputFile {
281
public:
282
DeepScanLineOutputFile(const char name[], const Header& header,
283
int numThreads = globalThreadCount());
284
DeepScanLineOutputFile(OStream& os, const Header& header,
285
int numThreads = globalThreadCount());
286
287
// File information
288
const Header& header() const;
289
const DeepFrameBuffer& frameBuffer() const;
290
int currentScanLine() const;
291
292
// Deep writing operations
293
void setFrameBuffer(const DeepFrameBuffer& frameBuffer);
294
void writePixels(int numScanLines = 1);
295
};
296
297
// Deep frame buffer structures
298
struct DeepSlice {
299
PixelType type; // Pixel data type
300
char* base; // Base pointer to sample data
301
size_t xStride; // Stride between pixels
302
size_t yStride; // Stride between scanlines
303
size_t sampleStride; // Stride between samples
304
int xSampling; // Horizontal subsampling
305
int ySampling; // Vertical subsampling
306
bool fillValue; // Fill value for missing data
307
bool xTileCoords; // Use tile coordinates
308
bool yTileCoords; // Use tile coordinates
309
310
DeepSlice(PixelType type = HALF,
311
char* base = 0,
312
size_t xStride = 0,
313
size_t yStride = 0,
314
size_t sampleStride = 0,
315
int xSampling = 1,
316
int ySampling = 1,
317
double fillValue = 0.0,
318
bool xTileCoords = false,
319
bool yTileCoords = false);
320
};
321
322
class DeepFrameBuffer {
323
public:
324
void insert(const char name[], const DeepSlice& slice);
325
void insert(const std::string& name, const DeepSlice& slice);
326
327
DeepSlice& operator[](const char name[]);
328
const DeepSlice& operator[](const char name[]) const;
329
DeepSlice& operator[](const std::string& name);
330
const DeepSlice& operator[](const std::string& name) const;
331
332
DeepSlice* findSlice(const char name[]);
333
const DeepSlice* findSlice(const char name[]) const;
334
DeepSlice* findSlice(const std::string& name);
335
const DeepSlice* findSlice(const std::string& name) const;
336
337
typedef std::map<Name, DeepSlice> SliceMap;
338
339
typedef SliceMap::iterator Iterator;
340
typedef SliceMap::const_iterator ConstIterator;
341
342
Iterator begin();
343
ConstIterator begin() const;
344
Iterator end();
345
ConstIterator end() const;
346
Iterator find(const char name[]);
347
ConstIterator find(const char name[]) const;
348
Iterator find(const std::string& name);
349
ConstIterator find(const std::string& name) const;
350
};
351
352
} // namespace OPENEXR_IMF_NAMESPACE
353
```
354
355
### Header and Metadata Management
356
357
Comprehensive header and attribute management for custom metadata and format configuration.
358
359
```cpp { .api }
360
#include <OpenEXR/ImfHeader.h>
361
#include <OpenEXR/ImfAttribute.h>
362
#include <OpenEXR/ImfStandardAttributes.h>
363
#include <OpenEXR/ImfChannelList.h>
364
365
namespace OPENEXR_IMF_NAMESPACE {
366
367
class Header {
368
public:
369
// Constructors
370
Header(int width = 64, int height = 64,
371
float pixelAspectRatio = 1,
372
const IMATH_NAMESPACE::V2f& screenWindowCenter = IMATH_NAMESPACE::V2f(0, 0),
373
float screenWindowWidth = 1,
374
LineOrder lineOrder = INCREASING_Y,
375
Compression compression = ZIP_COMPRESSION);
376
377
Header(const IMATH_NAMESPACE::Box2i& displayWindow,
378
const IMATH_NAMESPACE::Box2i& dataWindow,
379
float pixelAspectRatio = 1,
380
const IMATH_NAMESPACE::V2f& screenWindowCenter = IMATH_NAMESPACE::V2f(0, 0),
381
float screenWindowWidth = 1,
382
LineOrder lineOrder = INCREASING_Y,
383
Compression compression = ZIP_COMPRESSION);
384
385
// Copy constructor and assignment
386
Header(const Header& other);
387
Header& operator=(const Header& other);
388
389
// Attribute management
390
void insert(const char name[], const Attribute& attribute);
391
void insert(const std::string& name, const Attribute& attribute);
392
void erase(const char name[]);
393
void erase(const std::string& name);
394
395
Attribute& operator[](const char name[]);
396
const Attribute& operator[](const char name[]) const;
397
Attribute& operator[](const std::string& name);
398
const Attribute& operator[](const std::string& name) const;
399
400
// Attribute lookup
401
Iterator find(const char name[]);
402
ConstIterator find(const char name[]) const;
403
Iterator find(const std::string& name);
404
ConstIterator find(const std::string& name) const;
405
406
// Standard attribute accessors
407
IMATH_NAMESPACE::Box2i& displayWindow();
408
const IMATH_NAMESPACE::Box2i& displayWindow() const;
409
IMATH_NAMESPACE::Box2i& dataWindow();
410
const IMATH_NAMESPACE::Box2i& dataWindow() const;
411
float& pixelAspectRatio();
412
const float& pixelAspectRatio() const;
413
IMATH_NAMESPACE::V2f& screenWindowCenter();
414
const IMATH_NAMESPACE::V2f& screenWindowCenter() const;
415
float& screenWindowWidth();
416
const float& screenWindowWidth() const;
417
ChannelList& channels();
418
const ChannelList& channels() const;
419
LineOrder& lineOrder();
420
const LineOrder& lineOrder() const;
421
Compression& compression();
422
const Compression& compression() const;
423
424
// Type checking for different file types
425
bool hasType() const;
426
void setType(const std::string& type);
427
bool isTiled() const;
428
bool isComplete() const;
429
430
// Multi-part support
431
bool hasName() const;
432
void setName(const std::string& name);
433
434
// Validation
435
void sanityCheck(bool isTiled = false, bool isMultipartFile = false) const;
436
437
// Iterator support
438
typedef std::map<Name, Attribute*> AttributeMap;
439
typedef AttributeMap::iterator Iterator;
440
typedef AttributeMap::const_iterator ConstIterator;
441
442
Iterator begin();
443
ConstIterator begin() const;
444
Iterator end();
445
ConstIterator end() const;
446
};
447
448
// Typed attribute template
449
template <class T>
450
class TypedAttribute : public Attribute {
451
public:
452
typedef T ValueType;
453
454
TypedAttribute();
455
TypedAttribute(const T& value);
456
TypedAttribute(const TypedAttribute<T>& other);
457
virtual ~TypedAttribute();
458
459
virtual const char* typeName() const;
460
virtual Attribute* copy() const;
461
virtual void writeValueTo(OStream& os, int version) const;
462
virtual void readValueFrom(IStream& is, int size, int version);
463
virtual void copyValueFrom(const Attribute& other);
464
465
T& value();
466
const T& value() const;
467
468
TypedAttribute& operator=(const TypedAttribute<T>& other);
469
};
470
471
// Channel list management
472
class ChannelList {
473
public:
474
// Channel insertion and removal
475
void insert(const char name[], const Channel& channel);
476
void insert(const std::string& name, const Channel& channel);
477
void erase(const char name[]);
478
void erase(const std::string& name);
479
480
// Channel access
481
Channel& operator[](const char name[]);
482
const Channel& operator[](const char name[]) const;
483
Channel& operator[](const std::string& name);
484
const Channel& operator[](const std::string& name) const;
485
486
// Channel lookup
487
Iterator find(const char name[]);
488
ConstIterator find(const char name[]) const;
489
Iterator find(const std::string& name);
490
ConstIterator find(const std::string& name) const;
491
492
// Utilities
493
bool operator==(const ChannelList& other) const;
494
bool operator!=(const ChannelList& other) const;
495
496
// Iteration support
497
typedef std::map<Name, Channel> ChannelMap;
498
typedef ChannelMap::iterator Iterator;
499
typedef ChannelMap::const_iterator ConstIterator;
500
501
Iterator begin();
502
ConstIterator begin() const;
503
Iterator end();
504
ConstIterator end() const;
505
};
506
507
struct Channel {
508
PixelType type; // Data type (UINT, HALF, FLOAT)
509
int xSampling; // Horizontal subsampling factor
510
int ySampling; // Vertical subsampling factor
511
bool pLinear; // Perceptually linear flag
512
513
Channel(PixelType type = HALF,
514
int xSampling = 1,
515
int ySampling = 1,
516
bool pLinear = false);
517
518
bool operator==(const Channel& other) const;
519
bool operator!=(const Channel& other) const;
520
};
521
522
} // namespace OPENEXR_IMF_NAMESPACE
523
```
524
525
### Frame Buffer Management
526
527
Efficient pixel data management with support for different layouts and zero-copy operations.
528
529
```cpp { .api }
530
#include <OpenEXR/ImfFrameBuffer.h>
531
#include <OpenEXR/ImfPixelType.h>
532
533
namespace OPENEXR_IMF_NAMESPACE {
534
535
struct Slice {
536
PixelType type; // Pixel data type
537
char* base; // Base pointer to pixel data
538
size_t xStride; // Bytes between horizontally adjacent pixels
539
size_t yStride; // Bytes between vertically adjacent pixels
540
int xSampling; // Horizontal subsampling factor
541
int ySampling; // Vertical subsampling factor
542
double fillValue; // Fill value for missing pixels
543
bool xTileCoords; // Use tile coordinates for addressing
544
bool yTileCoords; // Use tile coordinates for addressing
545
546
Slice(PixelType type = HALF,
547
char* base = 0,
548
size_t xStride = 0,
549
size_t yStride = 0,
550
int xSampling = 1,
551
int ySampling = 1,
552
double fillValue = 0.0,
553
bool xTileCoords = false,
554
bool yTileCoords = false);
555
};
556
557
class FrameBuffer {
558
public:
559
// Slice management
560
void insert(const char name[], const Slice& slice);
561
void insert(const std::string& name, const Slice& slice);
562
563
Slice& operator[](const char name[]);
564
const Slice& operator[](const char name[]) const;
565
Slice& operator[](const std::string& name);
566
const Slice& operator[](const std::string& name) const;
567
568
// Slice lookup
569
Iterator find(const char name[]);
570
ConstIterator find(const char name[]) const;
571
Iterator find(const std::string& name);
572
ConstIterator find(const std::string& name) const;
573
574
Slice* findSlice(const char name[]);
575
const Slice* findSlice(const char name[]) const;
576
Slice* findSlice(const std::string& name);
577
const Slice* findSlice(const std::string& name) const;
578
579
// Iteration support
580
typedef std::map<Name, Slice> SliceMap;
581
typedef SliceMap::iterator Iterator;
582
typedef SliceMap::const_iterator ConstIterator;
583
584
Iterator begin();
585
ConstIterator begin() const;
586
Iterator end();
587
ConstIterator end() const;
588
};
589
590
// Pixel type enumeration
591
enum PixelType {
592
UINT = 0, // 32-bit unsigned integer
593
HALF = 1, // 16-bit floating point (half precision)
594
FLOAT = 2, // 32-bit floating point (single precision)
595
NUM_PIXELTYPES
596
};
597
598
// Pixel type utilities
599
int pixelTypeSize(PixelType type);
600
const char* pixelTypeToString(PixelType type);
601
602
} // namespace OPENEXR_IMF_NAMESPACE
603
```
604
605
### RGBA Convenience Interface
606
607
Simplified high-level interface for common RGBA workflows with automatic format conversions.
608
609
```cpp { .api }
610
#include <OpenEXR/ImfRgbaFile.h>
611
#include <OpenEXR/ImfRgba.h>
612
#include <OpenEXR/ImfArray.h>
613
614
namespace OPENEXR_IMF_NAMESPACE {
615
616
struct Rgba {
617
half r, g, b, a;
618
619
Rgba();
620
Rgba(half r, half g, half b, half a = 1.f);
621
Rgba(float r, float g, float b, float a = 1.f);
622
};
623
624
enum RgbaChannels {
625
WRITE_R = 0x01, // Red channel
626
WRITE_G = 0x02, // Green channel
627
WRITE_B = 0x04, // Blue channel
628
WRITE_A = 0x08, // Alpha channel
629
WRITE_Y = 0x10, // Luminance channel
630
WRITE_C = 0x20, // Chroma channels
631
WRITE_RGB = 0x07, // Red, green, blue
632
WRITE_RGBA = 0x0f, // Red, green, blue, alpha
633
WRITE_YC = 0x30, // Luminance, chroma
634
WRITE_YA = 0x18, // Luminance, alpha
635
WRITE_YCA = 0x38 // Luminance, chroma, alpha
636
};
637
638
class RgbaOutputFile {
639
public:
640
// Constructors
641
RgbaOutputFile(const char name[], const Header& header, RgbaChannels rgbaChannels = WRITE_RGBA,
642
int numThreads = globalThreadCount());
643
RgbaOutputFile(const char name[], int width, int height, RgbaChannels rgbaChannels = WRITE_RGBA,
644
float pixelAspectRatio = 1, const IMATH_NAMESPACE::V2f& screenWindowCenter = IMATH_NAMESPACE::V2f(0, 0),
645
float screenWindowWidth = 1, LineOrder lineOrder = INCREASING_Y,
646
Compression compression = ZIP_COMPRESSION, int numThreads = globalThreadCount());
647
RgbaOutputFile(OStream& os, const Header& header, RgbaChannels rgbaChannels = WRITE_RGBA,
648
int numThreads = globalThreadCount());
649
RgbaOutputFile(OStream& os, int width, int height, RgbaChannels rgbaChannels = WRITE_RGBA,
650
float pixelAspectRatio = 1, const IMATH_NAMESPACE::V2f& screenWindowCenter = IMATH_NAMESPACE::V2f(0, 0),
651
float screenWindowWidth = 1, LineOrder lineOrder = INCREASING_Y,
652
Compression compression = ZIP_COMPRESSION, int numThreads = globalThreadCount());
653
654
// File operations
655
void setFrameBuffer(const Rgba* base, size_t xStride, size_t yStride);
656
void writePixels(int numScanLines = 1);
657
void writePixels(const Rgba* base, int scanLine1, int scanLine2);
658
659
// File information
660
const Header& header() const;
661
const FrameBuffer& frameBuffer() const;
662
const IMATH_NAMESPACE::Box2i& displayWindow() const;
663
const IMATH_NAMESPACE::Box2i& dataWindow() const;
664
float pixelAspectRatio() const;
665
const IMATH_NAMESPACE::V2f& screenWindowCenter() const;
666
float screenWindowWidth() const;
667
LineOrder lineOrder() const;
668
Compression compression() const;
669
RgbaChannels channels() const;
670
671
// Utilities
672
int currentScanLine() const;
673
674
// Destructor
675
~RgbaOutputFile();
676
};
677
678
class RgbaInputFile {
679
public:
680
// Constructors
681
RgbaInputFile(const char name[], int numThreads = globalThreadCount());
682
RgbaInputFile(IStream& is, int numThreads = globalThreadCount());
683
684
// File operations
685
void setFrameBuffer(const Rgba* base, size_t xStride, size_t yStride);
686
void readPixels(int scanLine1, int scanLine2);
687
void readPixels(int scanLine);
688
void readPixels(Rgba* base, int scanLine1, int scanLine2);
689
690
// File information
691
const Header& header() const;
692
const FrameBuffer& frameBuffer() const;
693
const IMATH_NAMESPACE::Box2i& displayWindow() const;
694
const IMATH_NAMESPACE::Box2i& dataWindow() const;
695
float pixelAspectRatio() const;
696
const IMATH_NAMESPACE::V2f& screenWindowCenter() const;
697
float screenWindowWidth() const;
698
LineOrder lineOrder() const;
699
Compression compression() const;
700
RgbaChannels channels() const;
701
const char* fileName() const;
702
int version() const;
703
bool isComplete() const;
704
705
// Destructor
706
~RgbaInputFile();
707
};
708
709
// Array template for managing RGBA pixel arrays
710
template <class T>
711
class Array {
712
public:
713
typedef T value_type;
714
715
// Constructors
716
Array();
717
Array(long size);
718
Array(long size, bool initialize, const T& value = T());
719
Array(const Array& other);
720
721
// Assignment
722
Array& operator=(const Array& other);
723
724
// Access
725
T& operator[](long i);
726
const T& operator[](long i) const;
727
728
// Size management
729
void resizeErase(long size);
730
void resizeEraseUnsafe(long size);
731
void resizeNoErase(long size);
732
long size() const;
733
734
// Destructor
735
~Array();
736
};
737
738
typedef Array<Rgba> Array2D;
739
740
} // namespace OPENEXR_IMF_NAMESPACE
741
```
742
743
### Threading and Performance
744
745
Multi-threading support and performance optimization utilities.
746
747
```cpp { .api }
748
#include <OpenEXR/ImfThreading.h>
749
#include <IlmThread/IlmThread.h>
750
#include <IlmThread/IlmThreadPool.h>
751
752
namespace OPENEXR_IMF_NAMESPACE {
753
754
// Global threading control
755
void setGlobalThreadCount(int count);
756
int globalThreadCount();
757
758
} // namespace OPENEXR_IMF_NAMESPACE
759
760
namespace ILMTHREAD_NAMESPACE {
761
762
class Thread {
763
public:
764
Thread();
765
virtual ~Thread();
766
767
void start();
768
void join();
769
bool joinable() const;
770
771
protected:
772
virtual void run() = 0;
773
774
private:
775
// Implementation details hidden
776
struct Data;
777
Data* _data;
778
};
779
780
class Mutex {
781
public:
782
Mutex();
783
~Mutex();
784
785
void lock();
786
void unlock();
787
788
private:
789
// Implementation details hidden
790
struct Data;
791
Data* _data;
792
};
793
794
class Lock {
795
public:
796
Lock(const Mutex& m, bool autoLock = true);
797
~Lock();
798
799
void acquire();
800
void release();
801
bool locked() const;
802
803
private:
804
const Mutex* _mutex;
805
bool _locked;
806
};
807
808
class Semaphore {
809
public:
810
Semaphore(unsigned int value = 0);
811
virtual ~Semaphore();
812
813
void wait();
814
bool tryWait();
815
void post();
816
int value() const;
817
818
private:
819
// Implementation details hidden
820
struct Data;
821
Data* _data;
822
};
823
824
class Task {
825
public:
826
Task(TaskGroup* g);
827
virtual ~Task();
828
829
virtual void execute() = 0;
830
831
TaskGroup* group();
832
833
private:
834
TaskGroup* _group;
835
};
836
837
class TaskGroup {
838
public:
839
TaskGroup();
840
~TaskGroup();
841
842
void addTask(Task* task);
843
void executeAndDestroy();
844
845
private:
846
// Implementation details hidden
847
struct Data;
848
Data* _data;
849
};
850
851
class ThreadPool {
852
public:
853
ThreadPool(unsigned int nthreads = 0);
854
virtual ~ThreadPool();
855
856
int numThreads() const;
857
void setNumThreads(int count);
858
859
void addTask(Task* task);
860
void addGlobalTask(Task* task);
861
862
static ThreadPool& globalThreadPool();
863
static void addGlobalTask(Task* task);
864
865
private:
866
// Implementation details hidden
867
struct Data;
868
Data* _data;
869
};
870
871
} // namespace ILMTHREAD_NAMESPACE
872
```
873
874
## Usage Examples
875
876
### Basic C++ Reading and Writing
877
878
```cpp
879
#include <OpenEXR/ImfInputFile.h>
880
#include <OpenEXR/ImfOutputFile.h>
881
#include <OpenEXR/ImfChannelList.h>
882
#include <OpenEXR/ImfFrameBuffer.h>
883
#include <OpenEXR/ImfHeader.h>
884
#include <OpenEXR/ImfArray.h>
885
#include <iostream>
886
887
using namespace OPENEXR_IMF_NAMESPACE;
888
using namespace IMATH_NAMESPACE;
889
890
void writeBasicEXR(const char* filename, int width, int height) {
891
// Create pixel data arrays
892
Array2D<float> rPixels(height, width);
893
Array2D<float> gPixels(height, width);
894
Array2D<float> bPixels(height, width);
895
Array2D<float> aPixels(height, width);
896
897
// Fill with sample data
898
for (int y = 0; y < height; ++y) {
899
for (int x = 0; x < width; ++x) {
900
rPixels[y][x] = float(x) / width;
901
gPixels[y][x] = float(y) / height;
902
bPixels[y][x] = 0.5f;
903
aPixels[y][x] = 1.0f;
904
}
905
}
906
907
// Create header
908
Header header(width, height);
909
header.channels().insert("R", Channel(FLOAT));
910
header.channels().insert("G", Channel(FLOAT));
911
header.channels().insert("B", Channel(FLOAT));
912
header.channels().insert("A", Channel(FLOAT));
913
header.compression() = ZIP_COMPRESSION;
914
915
// Custom attributes
916
header.insert("software", StringAttribute("C++ Example v1.0"));
917
header.insert("comments", StringAttribute("Basic RGB+A image"));
918
919
// Create output file
920
OutputFile file(filename, header);
921
922
// Set up frame buffer
923
FrameBuffer frameBuffer;
924
frameBuffer.insert("R", Slice(FLOAT, (char*)&rPixels[0][0],
925
sizeof(float), sizeof(float) * width));
926
frameBuffer.insert("G", Slice(FLOAT, (char*)&gPixels[0][0],
927
sizeof(float), sizeof(float) * width));
928
frameBuffer.insert("B", Slice(FLOAT, (char*)&bPixels[0][0],
929
sizeof(float), sizeof(float) * width));
930
frameBuffer.insert("A", Slice(FLOAT, (char*)&aPixels[0][0],
931
sizeof(float), sizeof(float) * width));
932
933
file.setFrameBuffer(frameBuffer);
934
file.writePixels(height);
935
936
std::cout << "Wrote " << filename << " (" << width << "x" << height << ")\n";
937
}
938
939
void readBasicEXR(const char* filename) {
940
// Open file for reading
941
InputFile file(filename);
942
943
// Get file information
944
const Header& header = file.header();
945
Box2i dw = header.dataWindow();
946
int width = dw.max.x - dw.min.x + 1;
947
int height = dw.max.y - dw.min.y + 1;
948
949
std::cout << "Reading " << filename << " (" << width << "x" << height << ")\n";
950
std::cout << "Compression: " << header.compression() << std::endl;
951
952
// Check available channels
953
const ChannelList& channels = header.channels();
954
for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i) {
955
const char* name = i.name();
956
const Channel& channel = i.channel();
957
std::cout << "Channel: " << name << " (type=" << channel.type << ")\n";
958
}
959
960
// Allocate pixel arrays
961
Array2D<float> rPixels(height, width);
962
Array2D<float> gPixels(height, width);
963
Array2D<float> bPixels(height, width);
964
965
// Set up frame buffer for reading
966
FrameBuffer frameBuffer;
967
frameBuffer.insert("R", Slice(FLOAT, (char*)&rPixels[0][0] - dw.min.x - dw.min.y * width,
968
sizeof(float), sizeof(float) * width, 1, 1, 0.0));
969
frameBuffer.insert("G", Slice(FLOAT, (char*)&gPixels[0][0] - dw.min.x - dw.min.y * width,
970
sizeof(float), sizeof(float) * width, 1, 1, 0.0));
971
frameBuffer.insert("B", Slice(FLOAT, (char*)&bPixels[0][0] - dw.min.x - dw.min.y * width,
972
sizeof(float), sizeof(float) * width, 1, 1, 0.0));
973
974
file.setFrameBuffer(frameBuffer);
975
file.readPixels(dw.min.y, dw.max.y);
976
977
// Print sample values
978
std::cout << "Sample pixel values at (100, 100):\n";
979
if (100 < height && 100 < width) {
980
std::cout << " R=" << rPixels[100][100]
981
<< " G=" << gPixels[100][100]
982
<< " B=" << bPixels[100][100] << std::endl;
983
}
984
}
985
986
int main() {
987
writeBasicEXR("basic_cpp.exr", 1920, 1080);
988
readBasicEXR("basic_cpp.exr");
989
return 0;
990
}
991
```
992
993
### Multi-Part C++ Implementation
994
995
```cpp
996
#include <OpenEXR/ImfMultiPartInputFile.h>
997
#include <OpenEXR/ImfMultiPartOutputFile.h>
998
#include <OpenEXR/ImfInputPart.h>
999
#include <OpenEXR/ImfOutputPart.h>
1000
#include <OpenEXR/ImfPartType.h>
1001
#include <OpenEXR/ImfArray.h>
1002
#include <vector>
1003
1004
using namespace OPENEXR_IMF_NAMESPACE;
1005
using namespace IMATH_NAMESPACE;
1006
1007
void createMultiPartEXR(const char* filename, int width, int height) {
1008
// Create headers for different parts
1009
std::vector<Header> headers(3);
1010
1011
// Beauty pass header
1012
headers[0] = Header(width, height);
1013
headers[0].setName("beauty");
1014
headers[0].setType(SCANLINEIMAGE);
1015
headers[0].channels().insert("R", Channel(HALF));
1016
headers[0].channels().insert("G", Channel(HALF));
1017
headers[0].channels().insert("B", Channel(HALF));
1018
headers[0].channels().insert("A", Channel(HALF));
1019
headers[0].compression() = DWAA_COMPRESSION;
1020
headers[0].insert("renderPass", StringAttribute("beauty"));
1021
1022
// Depth pass header
1023
headers[1] = Header(width, height);
1024
headers[1].setName("depth");
1025
headers[1].setType(SCANLINEIMAGE);
1026
headers[1].channels().insert("Z", Channel(FLOAT));
1027
headers[1].compression() = ZIP_COMPRESSION;
1028
headers[1].insert("renderPass", StringAttribute("depth"));
1029
1030
// Normal pass header
1031
headers[2] = Header(width, height);
1032
headers[2].setName("normal");
1033
headers[2].setType(SCANLINEIMAGE);
1034
headers[2].channels().insert("N.X", Channel(HALF));
1035
headers[2].channels().insert("N.Y", Channel(HALF));
1036
headers[2].channels().insert("N.Z", Channel(HALF));
1037
headers[2].compression() = ZIP_COMPRESSION;
1038
headers[2].insert("renderPass", StringAttribute("normal"));
1039
1040
// Create multi-part output file
1041
MultiPartOutputFile file(filename, 3, &headers[0]);
1042
1043
// Create pixel data
1044
Array2D<half> beautyR(height, width), beautyG(height, width),
1045
beautyB(height, width), beautyA(height, width);
1046
Array2D<float> depth(height, width);
1047
Array2D<half> normalX(height, width), normalY(height, width), normalZ(height, width);
1048
1049
// Fill sample data
1050
for (int y = 0; y < height; ++y) {
1051
for (int x = 0; x < width; ++x) {
1052
// Beauty data
1053
beautyR[y][x] = half(float(x) / width);
1054
beautyG[y][x] = half(float(y) / height);
1055
beautyB[y][x] = half(0.5f);
1056
beautyA[y][x] = half(1.0f);
1057
1058
// Depth data
1059
depth[y][x] = 10.0f + float(x + y) * 0.01f;
1060
1061
// Normal data (pointing toward camera)
1062
normalX[y][x] = half(0.0f);
1063
normalY[y][x] = half(0.0f);
1064
normalZ[y][x] = half(1.0f);
1065
}
1066
}
1067
1068
// Write beauty pass (Part 0)
1069
{
1070
OutputPart part(file, 0);
1071
FrameBuffer frameBuffer;
1072
1073
frameBuffer.insert("R", Slice(HALF, (char*)&beautyR[0][0],
1074
sizeof(half), sizeof(half) * width));
1075
frameBuffer.insert("G", Slice(HALF, (char*)&beautyG[0][0],
1076
sizeof(half), sizeof(half) * width));
1077
frameBuffer.insert("B", Slice(HALF, (char*)&beautyB[0][0],
1078
sizeof(half), sizeof(half) * width));
1079
frameBuffer.insert("A", Slice(HALF, (char*)&beautyA[0][0],
1080
sizeof(half), sizeof(half) * width));
1081
1082
part.setFrameBuffer(frameBuffer);
1083
part.writePixels(height);
1084
}
1085
1086
// Write depth pass (Part 1)
1087
{
1088
OutputPart part(file, 1);
1089
FrameBuffer frameBuffer;
1090
1091
frameBuffer.insert("Z", Slice(FLOAT, (char*)&depth[0][0],
1092
sizeof(float), sizeof(float) * width));
1093
1094
part.setFrameBuffer(frameBuffer);
1095
part.writePixels(height);
1096
}
1097
1098
// Write normal pass (Part 2)
1099
{
1100
OutputPart part(file, 2);
1101
FrameBuffer frameBuffer;
1102
1103
frameBuffer.insert("N.X", Slice(HALF, (char*)&normalX[0][0],
1104
sizeof(half), sizeof(half) * width));
1105
frameBuffer.insert("N.Y", Slice(HALF, (char*)&normalY[0][0],
1106
sizeof(half), sizeof(half) * width));
1107
frameBuffer.insert("N.Z", Slice(HALF, (char*)&normalZ[0][0],
1108
sizeof(half), sizeof(half) * width));
1109
1110
part.setFrameBuffer(frameBuffer);
1111
part.writePixels(height);
1112
}
1113
1114
std::cout << "Created multi-part EXR: " << filename << std::endl;
1115
}
1116
1117
void readMultiPartEXR(const char* filename) {
1118
// Open multi-part file
1119
MultiPartInputFile file(filename);
1120
1121
int numParts = file.parts();
1122
std::cout << "Multi-part file has " << numParts << " parts:\n";
1123
1124
// Examine each part
1125
for (int partNum = 0; partNum < numParts; ++partNum) {
1126
const Header& header = file.header(partNum);
1127
1128
// Get part information
1129
std::string partName = "unnamed";
1130
if (header.hasName()) {
1131
partName = header.typedAttribute<StringAttribute>("name").value();
1132
}
1133
1134
std::string renderPass = "unknown";
1135
try {
1136
renderPass = header.typedAttribute<StringAttribute>("renderPass").value();
1137
} catch (...) {}
1138
1139
std::cout << "Part " << partNum << ": " << partName
1140
<< " (pass: " << renderPass << ")\n";
1141
1142
// List channels
1143
const ChannelList& channels = header.channels();
1144
std::cout << " Channels: ";
1145
for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i) {
1146
std::cout << i.name() << " ";
1147
}
1148
std::cout << std::endl;
1149
1150
// Get dimensions
1151
Box2i dw = header.dataWindow();
1152
int width = dw.max.x - dw.min.x + 1;
1153
int height = dw.max.y - dw.min.y + 1;
1154
std::cout << " Size: " << width << "x" << height << std::endl;
1155
std::cout << " Compression: " << header.compression() << std::endl;
1156
1157
// Read sample data from first channel
1158
InputPart part(file, partNum);
1159
ChannelList::ConstIterator firstChannel = channels.begin();
1160
if (firstChannel != channels.end()) {
1161
const char* channelName = firstChannel.name();
1162
const Channel& channel = firstChannel.channel();
1163
1164
if (channel.type == HALF) {
1165
Array2D<half> pixels(height, width);
1166
FrameBuffer frameBuffer;
1167
frameBuffer.insert(channelName,
1168
Slice(HALF, (char*)&pixels[0][0] - dw.min.x - dw.min.y * width,
1169
sizeof(half), sizeof(half) * width));
1170
1171
part.setFrameBuffer(frameBuffer);
1172
part.readPixels(dw.min.y, dw.max.y);
1173
1174
std::cout << " Sample " << channelName << " value at (100,100): "
1175
<< float(pixels[100][100]) << std::endl;
1176
}
1177
else if (channel.type == FLOAT) {
1178
Array2D<float> pixels(height, width);
1179
FrameBuffer frameBuffer;
1180
frameBuffer.insert(channelName,
1181
Slice(FLOAT, (char*)&pixels[0][0] - dw.min.x - dw.min.y * width,
1182
sizeof(float), sizeof(float) * width));
1183
1184
part.setFrameBuffer(frameBuffer);
1185
part.readPixels(dw.min.y, dw.max.y);
1186
1187
std::cout << " Sample " << channelName << " value at (100,100): "
1188
<< pixels[100][100] << std::endl;
1189
}
1190
}
1191
1192
std::cout << std::endl;
1193
}
1194
}
1195
1196
int main() {
1197
createMultiPartEXR("multipart_cpp.exr", 1920, 1080);
1198
readMultiPartEXR("multipart_cpp.exr");
1199
return 0;
1200
}
1201
```
1202
1203
### High-Performance Tiled Access
1204
1205
```cpp
1206
#include <OpenEXR/ImfTiledInputFile.h>
1207
#include <OpenEXR/ImfTiledOutputFile.h>
1208
#include <OpenEXR/ImfTileDescription.h>
1209
#include <OpenEXR/ImfArray.h>
1210
#include <OpenEXR/ImfThreading.h>
1211
#include <chrono>
1212
1213
using namespace OPENEXR_IMF_NAMESPACE;
1214
using namespace IMATH_NAMESPACE;
1215
1216
void createTiledEXR(const char* filename, int width, int height,
1217
int tileWidth = 64, int tileHeight = 64) {
1218
// Create tiled header
1219
Header header(width, height);
1220
header.setType(TILEDIMAGE);
1221
header.channels().insert("R", Channel(HALF));
1222
header.channels().insert("G", Channel(HALF));
1223
header.channels().insert("B", Channel(HALF));
1224
header.compression() = ZIP_COMPRESSION;
1225
1226
// Configure tiling with mipmaps
1227
header.setTileDescription(TileDescription(tileWidth, tileHeight, MIPMAP_LEVELS));
1228
1229
// Add metadata
1230
header.insert("software", StringAttribute("Tiled C++ Example"));
1231
header.insert("tileOptimized", IntAttribute(1));
1232
1233
// Enable multi-threading for better performance
1234
setGlobalThreadCount(8);
1235
1236
TiledOutputFile file(filename, header);
1237
1238
// Create pixel data
1239
Array2D<half> rPixels(height, width);
1240
Array2D<half> gPixels(height, width);
1241
Array2D<half> bPixels(height, width);
1242
1243
// Generate test pattern
1244
for (int y = 0; y < height; ++y) {
1245
for (int x = 0; x < width; ++x) {
1246
float fx = float(x) / width;
1247
float fy = float(y) / height;
1248
1249
rPixels[y][x] = half(fx * fy);
1250
gPixels[y][x] = half(fx * (1.0f - fy));
1251
bPixels[y][x] = half((1.0f - fx) * fy);
1252
}
1253
}
1254
1255
// Set up frame buffer
1256
FrameBuffer frameBuffer;
1257
frameBuffer.insert("R", Slice(HALF, (char*)&rPixels[0][0],
1258
sizeof(half), sizeof(half) * width));
1259
frameBuffer.insert("G", Slice(HALF, (char*)&gPixels[0][0],
1260
sizeof(half), sizeof(half) * width));
1261
frameBuffer.insert("B", Slice(HALF, (char*)&bPixels[0][0],
1262
sizeof(half), sizeof(half) * width));
1263
1264
file.setFrameBuffer(frameBuffer);
1265
1266
// Write all tiles at base level (level 0)
1267
auto start = std::chrono::high_resolution_clock::now();
1268
1269
int numXTiles = file.numXTiles(0);
1270
int numYTiles = file.numYTiles(0);
1271
1272
file.writeTiles(0, numXTiles - 1, 0, numYTiles - 1, 0);
1273
1274
auto end = std::chrono::high_resolution_clock::now();
1275
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
1276
1277
std::cout << "Created tiled EXR: " << filename << std::endl;
1278
std::cout << "Image size: " << width << "x" << height << std::endl;
1279
std::cout << "Tile size: " << tileWidth << "x" << tileHeight << std::endl;
1280
std::cout << "Number of tiles: " << numXTiles << "x" << numYTiles
1281
<< " = " << (numXTiles * numYTiles) << std::endl;
1282
std::cout << "Write time: " << duration.count() << "ms" << std::endl;
1283
std::cout << "Mipmap levels: " << file.numXLevels() << std::endl;
1284
}
1285
1286
void readTiledEXRRandomAccess(const char* filename) {
1287
TiledInputFile file(filename);
1288
1289
const Header& header = file.header();
1290
Box2i dw = header.dataWindow();
1291
int width = dw.max.x - dw.min.x + 1;
1292
int height = dw.max.y - dw.min.y + 1;
1293
1294
std::cout << "\nReading tiled file: " << filename << std::endl;
1295
std::cout << "Tile size: " << file.tileXSize() << "x" << file.tileYSize() << std::endl;
1296
std::cout << "Level mode: " << file.levelMode() << std::endl;
1297
1298
// Allocate memory for one tile
1299
int tileWidth = file.tileXSize();
1300
int tileHeight = file.tileYSize();
1301
Array2D<half> tileR(tileHeight, tileWidth);
1302
Array2D<half> tileG(tileHeight, tileWidth);
1303
Array2D<half> tileB(tileHeight, tileWidth);
1304
1305
// Set up frame buffer for tile reading
1306
FrameBuffer frameBuffer;
1307
frameBuffer.insert("R", Slice(HALF, (char*)&tileR[0][0] - dw.min.x - dw.min.y * tileWidth,
1308
sizeof(half), sizeof(half) * tileWidth, 1, 1, 0.0, true, true));
1309
frameBuffer.insert("G", Slice(HALF, (char*)&tileG[0][0] - dw.min.x - dw.min.y * tileWidth,
1310
sizeof(half), sizeof(half) * tileWidth, 1, 1, 0.0, true, true));
1311
frameBuffer.insert("B", Slice(HALF, (char*)&tileB[0][0] - dw.min.x - dw.min.y * tileWidth,
1312
sizeof(half), sizeof(half) * tileWidth, 1, 1, 0.0, true, true));
1313
1314
file.setFrameBuffer(frameBuffer);
1315
1316
// Random access pattern - read specific tiles
1317
auto start = std::chrono::high_resolution_clock::now();
1318
1319
int numXTiles = file.numXTiles(0);
1320
int numYTiles = file.numYTiles(0);
1321
1322
// Read every 4th tile in a pattern
1323
for (int ty = 0; ty < numYTiles; ty += 4) {
1324
for (int tx = 0; tx < numXTiles; tx += 4) {
1325
file.readTile(tx, ty, 0); // Read single tile at level 0
1326
1327
// Process tile data (example: compute average)
1328
float avgR = 0, avgG = 0, avgB = 0;
1329
for (int y = 0; y < tileHeight; ++y) {
1330
for (int x = 0; x < tileWidth; ++x) {
1331
avgR += float(tileR[y][x]);
1332
avgG += float(tileG[y][x]);
1333
avgB += float(tileB[y][x]);
1334
}
1335
}
1336
int pixels = tileWidth * tileHeight;
1337
avgR /= pixels;
1338
avgG /= pixels;
1339
avgB /= pixels;
1340
1341
std::cout << "Tile (" << tx << "," << ty << ") average RGB: "
1342
<< avgR << ", " << avgG << ", " << avgB << std::endl;
1343
}
1344
}
1345
1346
auto end = std::chrono::high_resolution_clock::now();
1347
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
1348
1349
int tilesRead = ((numXTiles + 3) / 4) * ((numYTiles + 3) / 4);
1350
std::cout << "Random access read " << tilesRead << " tiles in "
1351
<< duration.count() << "ms" << std::endl;
1352
}
1353
1354
int main() {
1355
// Create large tiled image
1356
createTiledEXR("tiled_cpp.exr", 4096, 4096, 128, 128);
1357
1358
// Demonstrate random access
1359
readTiledEXRRandomAccess("tiled_cpp.exr");
1360
1361
return 0;
1362
}
1363
```