Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Tetragramm
GitHub Repository: Tetragramm/opencv
Path: blob/master/3rdparty/openexr/IlmImf/ImfHeader.cpp
16337 views
1
///////////////////////////////////////////////////////////////////////////
2
//
3
// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
4
// Digital Ltd. LLC
5
//
6
// All rights reserved.
7
//
8
// Redistribution and use in source and binary forms, with or without
9
// modification, are permitted provided that the following conditions are
10
// met:
11
// * Redistributions of source code must retain the above copyright
12
// notice, this list of conditions and the following disclaimer.
13
// * Redistributions in binary form must reproduce the above
14
// copyright notice, this list of conditions and the following disclaimer
15
// in the documentation and/or other materials provided with the
16
// distribution.
17
// * Neither the name of Industrial Light & Magic nor the names of
18
// its contributors may be used to endorse or promote products derived
19
// from this software without specific prior written permission.
20
//
21
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32
//
33
///////////////////////////////////////////////////////////////////////////
34
35
36
37
//-----------------------------------------------------------------------------
38
//
39
// class Header
40
//
41
//-----------------------------------------------------------------------------
42
43
#include <ImfHeader.h>
44
#include <ImfStdIO.h>
45
#include <ImfVersion.h>
46
#include <ImfCompressor.h>
47
#include <ImfMisc.h>
48
#include <ImfBoxAttribute.h>
49
#include <ImfChannelListAttribute.h>
50
#include <ImfChromaticitiesAttribute.h>
51
#include <ImfCompressionAttribute.h>
52
#include <ImfDoubleAttribute.h>
53
#include <ImfEnvmapAttribute.h>
54
#include <ImfFloatAttribute.h>
55
#include <ImfIntAttribute.h>
56
#include <ImfKeyCodeAttribute.h>
57
#include <ImfLineOrderAttribute.h>
58
#include <ImfMatrixAttribute.h>
59
#include <ImfOpaqueAttribute.h>
60
#include <ImfPreviewImageAttribute.h>
61
#include <ImfRationalAttribute.h>
62
#include <ImfStringAttribute.h>
63
#include <ImfStringVectorAttribute.h>
64
#include <ImfTileDescriptionAttribute.h>
65
#include <ImfTimeCodeAttribute.h>
66
#include <ImfVecAttribute.h>
67
#include "IlmThreadMutex.h"
68
#include "Iex.h"
69
#include <sstream>
70
#include <stdlib.h>
71
#include <time.h>
72
73
74
namespace Imf {
75
76
using namespace std;
77
using Imath::Box2i;
78
using Imath::V2i;
79
using Imath::V2f;
80
using IlmThread::Mutex;
81
using IlmThread::Lock;
82
83
84
namespace {
85
86
int maxImageWidth = 0;
87
int maxImageHeight = 0;
88
int maxTileWidth = 0;
89
int maxTileHeight = 0;
90
91
92
void
93
initialize (Header &header,
94
const Box2i &displayWindow,
95
const Box2i &dataWindow,
96
float pixelAspectRatio,
97
const V2f &screenWindowCenter,
98
float screenWindowWidth,
99
LineOrder lineOrder,
100
Compression compression)
101
{
102
header.insert ("displayWindow", Box2iAttribute (displayWindow));
103
header.insert ("dataWindow", Box2iAttribute (dataWindow));
104
header.insert ("pixelAspectRatio", FloatAttribute (pixelAspectRatio));
105
header.insert ("screenWindowCenter", V2fAttribute (screenWindowCenter));
106
header.insert ("screenWindowWidth", FloatAttribute (screenWindowWidth));
107
header.insert ("lineOrder", LineOrderAttribute (lineOrder));
108
header.insert ("compression", CompressionAttribute (compression));
109
header.insert ("channels", ChannelListAttribute ());
110
}
111
112
113
bool
114
usesLongNames (const Header &header)
115
{
116
//
117
// If an OpenEXR file contains any attribute names, attribute type names
118
// or channel names longer than 31 characters, then the file cannot be
119
// read by older versions of the IlmImf library (up to OpenEXR 1.6.1).
120
// Before writing the file header, we check if the header contains
121
// any names longer than 31 characters; if it does, then we set the
122
// LONG_NAMES_FLAG in the file version number. Older versions of the
123
// IlmImf library will refuse to read files that have the LONG_NAMES_FLAG
124
// set. Without the flag, older versions of the library would mis-
125
// interpret the file as broken.
126
//
127
128
for (Header::ConstIterator i = header.begin();
129
i != header.end();
130
++i)
131
{
132
if (strlen (i.name()) >= 32 || strlen (i.attribute().typeName()) >= 32)
133
return true;
134
}
135
136
const ChannelList &channels = header.channels();
137
138
for (ChannelList::ConstIterator i = channels.begin();
139
i != channels.end();
140
++i)
141
{
142
if (strlen (i.name()) >= 32)
143
return true;
144
}
145
146
return false;
147
}
148
149
template <size_t N>
150
void checkIsNullTerminated (const char (&str)[N], const char *what)
151
{
152
for (int i = 0; i < N; ++i) {
153
if (str[i] == '\0')
154
return;
155
}
156
std::stringstream s;
157
s << "Invalid " << what << ": it is more than " << (N - 1)
158
<< " characters long.";
159
throw Iex::InputExc(s);
160
}
161
162
} // namespace
163
164
165
Header::Header (int width,
166
int height,
167
float pixelAspectRatio,
168
const V2f &screenWindowCenter,
169
float screenWindowWidth,
170
LineOrder lineOrder,
171
Compression compression)
172
:
173
_map()
174
{
175
staticInitialize();
176
177
Box2i displayWindow (V2i (0, 0), V2i (width - 1, height - 1));
178
179
initialize (*this,
180
displayWindow,
181
displayWindow,
182
pixelAspectRatio,
183
screenWindowCenter,
184
screenWindowWidth,
185
lineOrder,
186
compression);
187
}
188
189
190
Header::Header (int width,
191
int height,
192
const Box2i &dataWindow,
193
float pixelAspectRatio,
194
const V2f &screenWindowCenter,
195
float screenWindowWidth,
196
LineOrder lineOrder,
197
Compression compression)
198
:
199
_map()
200
{
201
staticInitialize();
202
203
Box2i displayWindow (V2i (0, 0), V2i (width - 1, height - 1));
204
205
initialize (*this,
206
displayWindow,
207
dataWindow,
208
pixelAspectRatio,
209
screenWindowCenter,
210
screenWindowWidth,
211
lineOrder,
212
compression);
213
}
214
215
216
Header::Header (const Box2i &displayWindow,
217
const Box2i &dataWindow,
218
float pixelAspectRatio,
219
const V2f &screenWindowCenter,
220
float screenWindowWidth,
221
LineOrder lineOrder,
222
Compression compression)
223
:
224
_map()
225
{
226
staticInitialize();
227
228
initialize (*this,
229
displayWindow,
230
dataWindow,
231
pixelAspectRatio,
232
screenWindowCenter,
233
screenWindowWidth,
234
lineOrder,
235
compression);
236
}
237
238
239
Header::Header (const Header &other): _map()
240
{
241
for (AttributeMap::const_iterator i = other._map.begin();
242
i != other._map.end();
243
++i)
244
{
245
insert (*i->first, *i->second);
246
}
247
}
248
249
250
Header::~Header ()
251
{
252
for (AttributeMap::iterator i = _map.begin();
253
i != _map.end();
254
++i)
255
{
256
delete i->second;
257
}
258
}
259
260
261
Header &
262
Header::operator = (const Header &other)
263
{
264
if (this != &other)
265
{
266
for (AttributeMap::iterator i = _map.begin();
267
i != _map.end();
268
++i)
269
{
270
delete i->second;
271
}
272
273
_map.erase (_map.begin(), _map.end());
274
275
for (AttributeMap::const_iterator i = other._map.begin();
276
i != other._map.end();
277
++i)
278
{
279
insert (*i->first, *i->second);
280
}
281
}
282
283
return *this;
284
}
285
286
287
void
288
Header::insert (const char name[], const Attribute &attribute)
289
{
290
if (name[0] == 0)
291
THROW (Iex::ArgExc, "Image attribute name cannot be an empty string.");
292
293
AttributeMap::iterator i = _map.find (name);
294
295
if (i == _map.end())
296
{
297
Attribute *tmp = attribute.copy();
298
299
try
300
{
301
_map[name] = tmp;
302
}
303
catch (...)
304
{
305
delete tmp;
306
throw;
307
}
308
}
309
else
310
{
311
if (strcmp (i->second->typeName(), attribute.typeName()))
312
THROW (Iex::TypeExc, "Cannot assign a value of "
313
"type \"" << attribute.typeName() << "\" "
314
"to image attribute \"" << name << "\" of "
315
"type \"" << i->second->typeName() << "\".");
316
317
Attribute *tmp = attribute.copy();
318
delete i->second;
319
i->second = tmp;
320
}
321
}
322
323
324
void
325
Header::insert (const string &name, const Attribute &attribute)
326
{
327
insert (name.c_str(), attribute);
328
}
329
330
331
Attribute &
332
Header::operator [] (const char name[])
333
{
334
AttributeMap::iterator i = _map.find (name);
335
336
if (i == _map.end())
337
THROW (Iex::ArgExc, "Cannot find image attribute \"" << name << "\".");
338
339
return *i->second;
340
}
341
342
343
const Attribute &
344
Header::operator [] (const char name[]) const
345
{
346
AttributeMap::const_iterator i = _map.find (name);
347
348
if (i == _map.end())
349
THROW (Iex::ArgExc, "Cannot find image attribute \"" << name << "\".");
350
351
return *i->second;
352
}
353
354
355
Attribute &
356
Header::operator [] (const string &name)
357
{
358
return this->operator[] (name.c_str());
359
}
360
361
362
const Attribute &
363
Header::operator [] (const string &name) const
364
{
365
return this->operator[] (name.c_str());
366
}
367
368
369
Header::Iterator
370
Header::begin ()
371
{
372
return _map.begin();
373
}
374
375
376
Header::ConstIterator
377
Header::begin () const
378
{
379
return _map.begin();
380
}
381
382
383
Header::Iterator
384
Header::end ()
385
{
386
return _map.end();
387
}
388
389
390
Header::ConstIterator
391
Header::end () const
392
{
393
return _map.end();
394
}
395
396
397
Header::Iterator
398
Header::find (const char name[])
399
{
400
return _map.find (name);
401
}
402
403
404
Header::ConstIterator
405
Header::find (const char name[]) const
406
{
407
return _map.find (name);
408
}
409
410
411
Header::Iterator
412
Header::find (const string &name)
413
{
414
return find (name.c_str());
415
}
416
417
418
Header::ConstIterator
419
Header::find (const string &name) const
420
{
421
return find (name.c_str());
422
}
423
424
425
Imath::Box2i &
426
Header::displayWindow ()
427
{
428
return static_cast <Box2iAttribute &>
429
((*this)["displayWindow"]).value();
430
}
431
432
433
const Imath::Box2i &
434
Header::displayWindow () const
435
{
436
return static_cast <const Box2iAttribute &>
437
((*this)["displayWindow"]).value();
438
}
439
440
441
Imath::Box2i &
442
Header::dataWindow ()
443
{
444
return static_cast <Box2iAttribute &>
445
((*this)["dataWindow"]).value();
446
}
447
448
449
const Imath::Box2i &
450
Header::dataWindow () const
451
{
452
return static_cast <const Box2iAttribute &>
453
((*this)["dataWindow"]).value();
454
}
455
456
457
float &
458
Header::pixelAspectRatio ()
459
{
460
return static_cast <FloatAttribute &>
461
((*this)["pixelAspectRatio"]).value();
462
}
463
464
465
const float &
466
Header::pixelAspectRatio () const
467
{
468
return static_cast <const FloatAttribute &>
469
((*this)["pixelAspectRatio"]).value();
470
}
471
472
473
Imath::V2f &
474
Header::screenWindowCenter ()
475
{
476
return static_cast <V2fAttribute &>
477
((*this)["screenWindowCenter"]).value();
478
}
479
480
481
const Imath::V2f &
482
Header::screenWindowCenter () const
483
{
484
return static_cast <const V2fAttribute &>
485
((*this)["screenWindowCenter"]).value();
486
}
487
488
489
float &
490
Header::screenWindowWidth ()
491
{
492
return static_cast <FloatAttribute &>
493
((*this)["screenWindowWidth"]).value();
494
}
495
496
497
const float &
498
Header::screenWindowWidth () const
499
{
500
return static_cast <const FloatAttribute &>
501
((*this)["screenWindowWidth"]).value();
502
}
503
504
505
ChannelList &
506
Header::channels ()
507
{
508
return static_cast <ChannelListAttribute &>
509
((*this)["channels"]).value();
510
}
511
512
513
const ChannelList &
514
Header::channels () const
515
{
516
return static_cast <const ChannelListAttribute &>
517
((*this)["channels"]).value();
518
}
519
520
521
LineOrder &
522
Header::lineOrder ()
523
{
524
return static_cast <LineOrderAttribute &>
525
((*this)["lineOrder"]).value();
526
}
527
528
529
const LineOrder &
530
Header::lineOrder () const
531
{
532
return static_cast <const LineOrderAttribute &>
533
((*this)["lineOrder"]).value();
534
}
535
536
537
Compression &
538
Header::compression ()
539
{
540
return static_cast <CompressionAttribute &>
541
((*this)["compression"]).value();
542
}
543
544
545
const Compression &
546
Header::compression () const
547
{
548
return static_cast <const CompressionAttribute &>
549
((*this)["compression"]).value();
550
}
551
552
553
void
554
Header::setTileDescription(const TileDescription& td)
555
{
556
insert ("tiles", TileDescriptionAttribute (td));
557
}
558
559
560
bool
561
Header::hasTileDescription() const
562
{
563
return findTypedAttribute <TileDescriptionAttribute> ("tiles") != 0;
564
}
565
566
567
TileDescription &
568
Header::tileDescription ()
569
{
570
return typedAttribute <TileDescriptionAttribute> ("tiles").value();
571
}
572
573
574
const TileDescription &
575
Header::tileDescription () const
576
{
577
return typedAttribute <TileDescriptionAttribute> ("tiles").value();
578
}
579
580
void
581
Header::setPreviewImage (const PreviewImage &pi)
582
{
583
insert ("preview", PreviewImageAttribute (pi));
584
}
585
586
587
PreviewImage &
588
Header::previewImage ()
589
{
590
return typedAttribute <PreviewImageAttribute> ("preview").value();
591
}
592
593
594
const PreviewImage &
595
Header::previewImage () const
596
{
597
return typedAttribute <PreviewImageAttribute> ("preview").value();
598
}
599
600
601
bool
602
Header::hasPreviewImage () const
603
{
604
return findTypedAttribute <PreviewImageAttribute> ("preview") != 0;
605
}
606
607
608
void
609
Header::sanityCheck (bool isTiled) const
610
{
611
//
612
// The display window and the data window must each
613
// contain at least one pixel. In addition, the
614
// coordinates of the window corners must be small
615
// enough to keep expressions like max-min+1 or
616
// max+min from overflowing.
617
//
618
619
const Box2i &displayWindow = this->displayWindow();
620
621
if (displayWindow.min.x > displayWindow.max.x ||
622
displayWindow.min.y > displayWindow.max.y ||
623
displayWindow.min.x <= -(INT_MAX / 2) ||
624
displayWindow.min.y <= -(INT_MAX / 2) ||
625
displayWindow.max.x >= (INT_MAX / 2) ||
626
displayWindow.max.y >= (INT_MAX / 2))
627
{
628
throw Iex::ArgExc ("Invalid display window in image header.");
629
}
630
631
const Box2i &dataWindow = this->dataWindow();
632
633
if (dataWindow.min.x > dataWindow.max.x ||
634
dataWindow.min.y > dataWindow.max.y ||
635
dataWindow.min.x <= -(INT_MAX / 2) ||
636
dataWindow.min.y <= -(INT_MAX / 2) ||
637
dataWindow.max.x >= (INT_MAX / 2) ||
638
dataWindow.max.y >= (INT_MAX / 2))
639
{
640
throw Iex::ArgExc ("Invalid data window in image header.");
641
}
642
643
if (maxImageWidth > 0 &&
644
maxImageWidth < dataWindow.max.x - dataWindow.min.x + 1)
645
{
646
THROW (Iex::ArgExc, "The width of the data window exceeds the "
647
"maximum width of " << maxImageWidth << "pixels.");
648
}
649
650
if (maxImageHeight > 0 &&
651
maxImageHeight < dataWindow.max.y - dataWindow.min.y + 1)
652
{
653
THROW (Iex::ArgExc, "The width of the data window exceeds the "
654
"maximum width of " << maxImageHeight << "pixels.");
655
}
656
657
//
658
// The pixel aspect ratio must be greater than 0.
659
// In applications, numbers like the the display or
660
// data window dimensions are likely to be multiplied
661
// or divided by the pixel aspect ratio; to avoid
662
// arithmetic exceptions, we limit the pixel aspect
663
// ratio to a range that is smaller than theoretically
664
// possible (real aspect ratios are likely to be close
665
// to 1.0 anyway).
666
//
667
668
float pixelAspectRatio = this->pixelAspectRatio();
669
670
const float MIN_PIXEL_ASPECT_RATIO = 1e-6f;
671
const float MAX_PIXEL_ASPECT_RATIO = 1e+6f;
672
673
if (pixelAspectRatio < MIN_PIXEL_ASPECT_RATIO ||
674
pixelAspectRatio > MAX_PIXEL_ASPECT_RATIO)
675
{
676
throw Iex::ArgExc ("Invalid pixel aspect ratio in image header.");
677
}
678
679
//
680
// The screen window width must not be less than 0.
681
// The size of the screen window can vary over a wide
682
// range (fish-eye lens to astronomical telescope),
683
// so we can't limit the screen window width to a
684
// small range.
685
//
686
687
float screenWindowWidth = this->screenWindowWidth();
688
689
if (screenWindowWidth < 0)
690
throw Iex::ArgExc ("Invalid screen window width in image header.");
691
692
//
693
// If the file is tiled, verify that the tile description has resonable
694
// values and check to see if the lineOrder is one of the predefined 3.
695
// If the file is not tiled, then the lineOrder can only be INCREASING_Y
696
// or DECREASING_Y.
697
//
698
699
LineOrder lineOrder = this->lineOrder();
700
701
if (isTiled)
702
{
703
if (!hasTileDescription())
704
{
705
throw Iex::ArgExc ("Tiled image has no tile "
706
"description attribute.");
707
}
708
709
const TileDescription &tileDesc = tileDescription();
710
711
if (tileDesc.xSize <= 0 || tileDesc.ySize <= 0)
712
throw Iex::ArgExc ("Invalid tile size in image header.");
713
714
if (maxTileWidth > 0 &&
715
maxTileWidth < tileDesc.xSize)
716
{
717
THROW (Iex::ArgExc, "The width of the tiles exceeds the maximum "
718
"width of " << maxTileWidth << "pixels.");
719
}
720
721
if (maxTileHeight > 0 &&
722
maxTileHeight < tileDesc.ySize)
723
{
724
THROW (Iex::ArgExc, "The width of the tiles exceeds the maximum "
725
"width of " << maxTileHeight << "pixels.");
726
}
727
728
if (tileDesc.mode != ONE_LEVEL &&
729
tileDesc.mode != MIPMAP_LEVELS &&
730
tileDesc.mode != RIPMAP_LEVELS)
731
throw Iex::ArgExc ("Invalid level mode in image header.");
732
733
if (tileDesc.roundingMode != ROUND_UP &&
734
tileDesc.roundingMode != ROUND_DOWN)
735
throw Iex::ArgExc ("Invalid level rounding mode in image header.");
736
737
if (lineOrder != INCREASING_Y &&
738
lineOrder != DECREASING_Y &&
739
lineOrder != RANDOM_Y)
740
throw Iex::ArgExc ("Invalid line order in image header.");
741
}
742
else
743
{
744
if (lineOrder != INCREASING_Y &&
745
lineOrder != DECREASING_Y)
746
throw Iex::ArgExc ("Invalid line order in image header.");
747
}
748
749
//
750
// The compression method must be one of the predefined values.
751
//
752
753
if (!isValidCompression (this->compression()))
754
throw Iex::ArgExc ("Unknown compression type in image header.");
755
756
//
757
// Check the channel list:
758
//
759
// If the file is tiled then for each channel, the type must be one of the
760
// predefined values, and the x and y sampling must both be 1.
761
//
762
// If the file is not tiled then for each channel, the type must be one
763
// of the predefined values, the x and y coordinates of the data window's
764
// upper left corner must be divisible by the x and y subsampling factors,
765
// and the width and height of the data window must be divisible by the
766
// x and y subsampling factors.
767
//
768
769
const ChannelList &channels = this->channels();
770
771
if (isTiled)
772
{
773
for (ChannelList::ConstIterator i = channels.begin();
774
i != channels.end();
775
++i)
776
{
777
if (i.channel().type != UINT &&
778
i.channel().type != HALF &&
779
i.channel().type != FLOAT)
780
{
781
THROW (Iex::ArgExc, "Pixel type of \"" << i.name() << "\" "
782
"image channel is invalid.");
783
}
784
785
if (i.channel().xSampling != 1)
786
{
787
THROW (Iex::ArgExc, "The x subsampling factor for the "
788
"\"" << i.name() << "\" channel "
789
"is not 1.");
790
}
791
792
if (i.channel().ySampling != 1)
793
{
794
THROW (Iex::ArgExc, "The y subsampling factor for the "
795
"\"" << i.name() << "\" channel "
796
"is not 1.");
797
}
798
}
799
}
800
else
801
{
802
for (ChannelList::ConstIterator i = channels.begin();
803
i != channels.end();
804
++i)
805
{
806
if (i.channel().type != UINT &&
807
i.channel().type != HALF &&
808
i.channel().type != FLOAT)
809
{
810
THROW (Iex::ArgExc, "Pixel type of \"" << i.name() << "\" "
811
"image channel is invalid.");
812
}
813
814
if (i.channel().xSampling < 1)
815
{
816
THROW (Iex::ArgExc, "The x subsampling factor for the "
817
"\"" << i.name() << "\" channel "
818
"is invalid.");
819
}
820
821
if (i.channel().ySampling < 1)
822
{
823
THROW (Iex::ArgExc, "The y subsampling factor for the "
824
"\"" << i.name() << "\" channel "
825
"is invalid.");
826
}
827
828
if (dataWindow.min.x % i.channel().xSampling)
829
{
830
THROW (Iex::ArgExc, "The minimum x coordinate of the "
831
"image's data window is not a multiple "
832
"of the x subsampling factor of "
833
"the \"" << i.name() << "\" channel.");
834
}
835
836
if (dataWindow.min.y % i.channel().ySampling)
837
{
838
THROW (Iex::ArgExc, "The minimum y coordinate of the "
839
"image's data window is not a multiple "
840
"of the y subsampling factor of "
841
"the \"" << i.name() << "\" channel.");
842
}
843
844
if ((dataWindow.max.x - dataWindow.min.x + 1) %
845
i.channel().xSampling)
846
{
847
THROW (Iex::ArgExc, "Number of pixels per row in the "
848
"image's data window is not a multiple "
849
"of the x subsampling factor of "
850
"the \"" << i.name() << "\" channel.");
851
}
852
853
if ((dataWindow.max.y - dataWindow.min.y + 1) %
854
i.channel().ySampling)
855
{
856
THROW (Iex::ArgExc, "Number of pixels per column in the "
857
"image's data window is not a multiple "
858
"of the y subsampling factor of "
859
"the \"" << i.name() << "\" channel.");
860
}
861
}
862
}
863
}
864
865
866
void
867
Header::setMaxImageSize (int maxWidth, int maxHeight)
868
{
869
maxImageWidth = maxWidth;
870
maxImageHeight = maxHeight;
871
}
872
873
874
void
875
Header::setMaxTileSize (int maxWidth, int maxHeight)
876
{
877
maxTileWidth = maxWidth;
878
maxTileHeight = maxHeight;
879
}
880
881
882
Int64
883
Header::writeTo (OStream &os, bool isTiled) const
884
{
885
//
886
// Write a "magic number" to identify the file as an image file.
887
// Write the current file format version number.
888
//
889
890
Xdr::write <StreamIO> (os, MAGIC);
891
892
int version = EXR_VERSION;
893
894
if (isTiled)
895
version |= TILED_FLAG;
896
897
if (usesLongNames (*this))
898
version |= LONG_NAMES_FLAG;
899
900
Xdr::write <StreamIO> (os, version);
901
902
//
903
// Write all attributes. If we have a preview image attribute,
904
// keep track of its position in the file.
905
//
906
907
Int64 previewPosition = 0;
908
909
const Attribute *preview =
910
findTypedAttribute <PreviewImageAttribute> ("preview");
911
912
for (ConstIterator i = begin(); i != end(); ++i)
913
{
914
//
915
// Write the attribute's name and type.
916
//
917
918
Xdr::write <StreamIO> (os, i.name());
919
Xdr::write <StreamIO> (os, i.attribute().typeName());
920
921
//
922
// Write the size of the attribute value,
923
// and the value itself.
924
//
925
926
StdOSStream oss;
927
i.attribute().writeValueTo (oss, version);
928
929
std::string s = oss.str();
930
Xdr::write <StreamIO> (os, (int) s.length());
931
932
if (&i.attribute() == preview)
933
previewPosition = os.tellp();
934
935
os.write (s.data(), s.length());
936
}
937
938
//
939
// Write zero-length attribute name to mark the end of the header.
940
//
941
942
Xdr::write <StreamIO> (os, "");
943
944
return previewPosition;
945
}
946
947
948
void
949
Header::readFrom (IStream &is, int &version)
950
{
951
//
952
// Read the magic number and the file format version number.
953
// Then check if we can read the rest of this file.
954
//
955
956
int magic;
957
958
Xdr::read <StreamIO> (is, magic);
959
Xdr::read <StreamIO> (is, version);
960
961
if (magic != MAGIC)
962
{
963
throw Iex::InputExc ("File is not an image file.");
964
}
965
966
if (getVersion (version) != EXR_VERSION)
967
{
968
THROW (Iex::InputExc, "Cannot read "
969
"version " << getVersion (version) << " "
970
"image files. Current file format version "
971
"is " << EXR_VERSION << ".");
972
}
973
974
if (!supportsFlags (getFlags (version)))
975
{
976
THROW (Iex::InputExc, "The file format version number's flag field "
977
"contains unrecognized flags.");
978
}
979
980
//
981
// Read all attributes.
982
//
983
984
while (true)
985
{
986
//
987
// Read the name of the attribute.
988
// A zero-length attribute name indicates the end of the header.
989
//
990
991
char name[Name::SIZE];
992
Xdr::read <StreamIO> (is, Name::MAX_LENGTH, name);
993
994
if (name[0] == 0)
995
break;
996
997
checkIsNullTerminated (name, "attribute name");
998
999
//
1000
// Read the attribute type and the size of the attribute value.
1001
//
1002
1003
char typeName[Name::SIZE];
1004
int size;
1005
1006
Xdr::read <StreamIO> (is, Name::MAX_LENGTH, typeName);
1007
checkIsNullTerminated (typeName, "attribute type name");
1008
Xdr::read <StreamIO> (is, size);
1009
1010
AttributeMap::iterator i = _map.find (name);
1011
1012
if (i != _map.end())
1013
{
1014
//
1015
// The attribute already exists (for example,
1016
// because it is a predefined attribute).
1017
// Read the attribute's new value from the file.
1018
//
1019
1020
if (strncmp (i->second->typeName(), typeName, sizeof (typeName)))
1021
THROW (Iex::InputExc, "Unexpected type for image attribute "
1022
"\"" << name << "\".");
1023
1024
i->second->readValueFrom (is, size, version);
1025
}
1026
else
1027
{
1028
//
1029
// The new attribute does not exist yet.
1030
// If the attribute type is of a known type,
1031
// read the attribute value. If the attribute
1032
// is of an unknown type, read its value and
1033
// store it as an OpaqueAttribute.
1034
//
1035
1036
Attribute *attr;
1037
1038
if (Attribute::knownType (typeName))
1039
attr = Attribute::newAttribute (typeName);
1040
else
1041
attr = new OpaqueAttribute (typeName);
1042
1043
try
1044
{
1045
attr->readValueFrom (is, size, version);
1046
_map[name] = attr;
1047
}
1048
catch (...)
1049
{
1050
delete attr;
1051
throw;
1052
}
1053
}
1054
}
1055
}
1056
1057
1058
void
1059
staticInitialize ()
1060
{
1061
static Mutex criticalSection;
1062
Lock lock (criticalSection);
1063
1064
static bool initialized = false;
1065
1066
if (!initialized)
1067
{
1068
//
1069
// One-time initialization -- register
1070
// some predefined attribute types.
1071
//
1072
1073
Box2fAttribute::registerAttributeType();
1074
Box2iAttribute::registerAttributeType();
1075
ChannelListAttribute::registerAttributeType();
1076
CompressionAttribute::registerAttributeType();
1077
ChromaticitiesAttribute::registerAttributeType();
1078
DoubleAttribute::registerAttributeType();
1079
EnvmapAttribute::registerAttributeType();
1080
FloatAttribute::registerAttributeType();
1081
IntAttribute::registerAttributeType();
1082
KeyCodeAttribute::registerAttributeType();
1083
LineOrderAttribute::registerAttributeType();
1084
M33dAttribute::registerAttributeType();
1085
M33fAttribute::registerAttributeType();
1086
M44dAttribute::registerAttributeType();
1087
M44fAttribute::registerAttributeType();
1088
PreviewImageAttribute::registerAttributeType();
1089
RationalAttribute::registerAttributeType();
1090
StringAttribute::registerAttributeType();
1091
StringVectorAttribute::registerAttributeType();
1092
TileDescriptionAttribute::registerAttributeType();
1093
TimeCodeAttribute::registerAttributeType();
1094
V2dAttribute::registerAttributeType();
1095
V2fAttribute::registerAttributeType();
1096
V2iAttribute::registerAttributeType();
1097
V3dAttribute::registerAttributeType();
1098
V3fAttribute::registerAttributeType();
1099
V3iAttribute::registerAttributeType();
1100
1101
initialized = true;
1102
}
1103
}
1104
1105
1106
} // namespace Imf
1107
1108