Path: blob/master/3rdparty/openexr/IlmImf/ImfHeader.cpp
16337 views
///////////////////////////////////////////////////////////////////////////1//2// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas3// Digital Ltd. LLC4//5// All rights reserved.6//7// Redistribution and use in source and binary forms, with or without8// modification, are permitted provided that the following conditions are9// met:10// * Redistributions of source code must retain the above copyright11// notice, this list of conditions and the following disclaimer.12// * Redistributions in binary form must reproduce the above13// copyright notice, this list of conditions and the following disclaimer14// in the documentation and/or other materials provided with the15// distribution.16// * Neither the name of Industrial Light & Magic nor the names of17// its contributors may be used to endorse or promote products derived18// from this software without specific prior written permission.19//20// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS21// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT22// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR23// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT24// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,25// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT26// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,27// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY28// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT29// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE30// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.31//32///////////////////////////////////////////////////////////////////////////33343536//-----------------------------------------------------------------------------37//38// class Header39//40//-----------------------------------------------------------------------------4142#include <ImfHeader.h>43#include <ImfStdIO.h>44#include <ImfVersion.h>45#include <ImfCompressor.h>46#include <ImfMisc.h>47#include <ImfBoxAttribute.h>48#include <ImfChannelListAttribute.h>49#include <ImfChromaticitiesAttribute.h>50#include <ImfCompressionAttribute.h>51#include <ImfDoubleAttribute.h>52#include <ImfEnvmapAttribute.h>53#include <ImfFloatAttribute.h>54#include <ImfIntAttribute.h>55#include <ImfKeyCodeAttribute.h>56#include <ImfLineOrderAttribute.h>57#include <ImfMatrixAttribute.h>58#include <ImfOpaqueAttribute.h>59#include <ImfPreviewImageAttribute.h>60#include <ImfRationalAttribute.h>61#include <ImfStringAttribute.h>62#include <ImfStringVectorAttribute.h>63#include <ImfTileDescriptionAttribute.h>64#include <ImfTimeCodeAttribute.h>65#include <ImfVecAttribute.h>66#include "IlmThreadMutex.h"67#include "Iex.h"68#include <sstream>69#include <stdlib.h>70#include <time.h>717273namespace Imf {7475using namespace std;76using Imath::Box2i;77using Imath::V2i;78using Imath::V2f;79using IlmThread::Mutex;80using IlmThread::Lock;818283namespace {8485int maxImageWidth = 0;86int maxImageHeight = 0;87int maxTileWidth = 0;88int maxTileHeight = 0;899091void92initialize (Header &header,93const Box2i &displayWindow,94const Box2i &dataWindow,95float pixelAspectRatio,96const V2f &screenWindowCenter,97float screenWindowWidth,98LineOrder lineOrder,99Compression compression)100{101header.insert ("displayWindow", Box2iAttribute (displayWindow));102header.insert ("dataWindow", Box2iAttribute (dataWindow));103header.insert ("pixelAspectRatio", FloatAttribute (pixelAspectRatio));104header.insert ("screenWindowCenter", V2fAttribute (screenWindowCenter));105header.insert ("screenWindowWidth", FloatAttribute (screenWindowWidth));106header.insert ("lineOrder", LineOrderAttribute (lineOrder));107header.insert ("compression", CompressionAttribute (compression));108header.insert ("channels", ChannelListAttribute ());109}110111112bool113usesLongNames (const Header &header)114{115//116// If an OpenEXR file contains any attribute names, attribute type names117// or channel names longer than 31 characters, then the file cannot be118// read by older versions of the IlmImf library (up to OpenEXR 1.6.1).119// Before writing the file header, we check if the header contains120// any names longer than 31 characters; if it does, then we set the121// LONG_NAMES_FLAG in the file version number. Older versions of the122// IlmImf library will refuse to read files that have the LONG_NAMES_FLAG123// set. Without the flag, older versions of the library would mis-124// interpret the file as broken.125//126127for (Header::ConstIterator i = header.begin();128i != header.end();129++i)130{131if (strlen (i.name()) >= 32 || strlen (i.attribute().typeName()) >= 32)132return true;133}134135const ChannelList &channels = header.channels();136137for (ChannelList::ConstIterator i = channels.begin();138i != channels.end();139++i)140{141if (strlen (i.name()) >= 32)142return true;143}144145return false;146}147148template <size_t N>149void checkIsNullTerminated (const char (&str)[N], const char *what)150{151for (int i = 0; i < N; ++i) {152if (str[i] == '\0')153return;154}155std::stringstream s;156s << "Invalid " << what << ": it is more than " << (N - 1)157<< " characters long.";158throw Iex::InputExc(s);159}160161} // namespace162163164Header::Header (int width,165int height,166float pixelAspectRatio,167const V2f &screenWindowCenter,168float screenWindowWidth,169LineOrder lineOrder,170Compression compression)171:172_map()173{174staticInitialize();175176Box2i displayWindow (V2i (0, 0), V2i (width - 1, height - 1));177178initialize (*this,179displayWindow,180displayWindow,181pixelAspectRatio,182screenWindowCenter,183screenWindowWidth,184lineOrder,185compression);186}187188189Header::Header (int width,190int height,191const Box2i &dataWindow,192float pixelAspectRatio,193const V2f &screenWindowCenter,194float screenWindowWidth,195LineOrder lineOrder,196Compression compression)197:198_map()199{200staticInitialize();201202Box2i displayWindow (V2i (0, 0), V2i (width - 1, height - 1));203204initialize (*this,205displayWindow,206dataWindow,207pixelAspectRatio,208screenWindowCenter,209screenWindowWidth,210lineOrder,211compression);212}213214215Header::Header (const Box2i &displayWindow,216const Box2i &dataWindow,217float pixelAspectRatio,218const V2f &screenWindowCenter,219float screenWindowWidth,220LineOrder lineOrder,221Compression compression)222:223_map()224{225staticInitialize();226227initialize (*this,228displayWindow,229dataWindow,230pixelAspectRatio,231screenWindowCenter,232screenWindowWidth,233lineOrder,234compression);235}236237238Header::Header (const Header &other): _map()239{240for (AttributeMap::const_iterator i = other._map.begin();241i != other._map.end();242++i)243{244insert (*i->first, *i->second);245}246}247248249Header::~Header ()250{251for (AttributeMap::iterator i = _map.begin();252i != _map.end();253++i)254{255delete i->second;256}257}258259260Header &261Header::operator = (const Header &other)262{263if (this != &other)264{265for (AttributeMap::iterator i = _map.begin();266i != _map.end();267++i)268{269delete i->second;270}271272_map.erase (_map.begin(), _map.end());273274for (AttributeMap::const_iterator i = other._map.begin();275i != other._map.end();276++i)277{278insert (*i->first, *i->second);279}280}281282return *this;283}284285286void287Header::insert (const char name[], const Attribute &attribute)288{289if (name[0] == 0)290THROW (Iex::ArgExc, "Image attribute name cannot be an empty string.");291292AttributeMap::iterator i = _map.find (name);293294if (i == _map.end())295{296Attribute *tmp = attribute.copy();297298try299{300_map[name] = tmp;301}302catch (...)303{304delete tmp;305throw;306}307}308else309{310if (strcmp (i->second->typeName(), attribute.typeName()))311THROW (Iex::TypeExc, "Cannot assign a value of "312"type \"" << attribute.typeName() << "\" "313"to image attribute \"" << name << "\" of "314"type \"" << i->second->typeName() << "\".");315316Attribute *tmp = attribute.copy();317delete i->second;318i->second = tmp;319}320}321322323void324Header::insert (const string &name, const Attribute &attribute)325{326insert (name.c_str(), attribute);327}328329330Attribute &331Header::operator [] (const char name[])332{333AttributeMap::iterator i = _map.find (name);334335if (i == _map.end())336THROW (Iex::ArgExc, "Cannot find image attribute \"" << name << "\".");337338return *i->second;339}340341342const Attribute &343Header::operator [] (const char name[]) const344{345AttributeMap::const_iterator i = _map.find (name);346347if (i == _map.end())348THROW (Iex::ArgExc, "Cannot find image attribute \"" << name << "\".");349350return *i->second;351}352353354Attribute &355Header::operator [] (const string &name)356{357return this->operator[] (name.c_str());358}359360361const Attribute &362Header::operator [] (const string &name) const363{364return this->operator[] (name.c_str());365}366367368Header::Iterator369Header::begin ()370{371return _map.begin();372}373374375Header::ConstIterator376Header::begin () const377{378return _map.begin();379}380381382Header::Iterator383Header::end ()384{385return _map.end();386}387388389Header::ConstIterator390Header::end () const391{392return _map.end();393}394395396Header::Iterator397Header::find (const char name[])398{399return _map.find (name);400}401402403Header::ConstIterator404Header::find (const char name[]) const405{406return _map.find (name);407}408409410Header::Iterator411Header::find (const string &name)412{413return find (name.c_str());414}415416417Header::ConstIterator418Header::find (const string &name) const419{420return find (name.c_str());421}422423424Imath::Box2i &425Header::displayWindow ()426{427return static_cast <Box2iAttribute &>428((*this)["displayWindow"]).value();429}430431432const Imath::Box2i &433Header::displayWindow () const434{435return static_cast <const Box2iAttribute &>436((*this)["displayWindow"]).value();437}438439440Imath::Box2i &441Header::dataWindow ()442{443return static_cast <Box2iAttribute &>444((*this)["dataWindow"]).value();445}446447448const Imath::Box2i &449Header::dataWindow () const450{451return static_cast <const Box2iAttribute &>452((*this)["dataWindow"]).value();453}454455456float &457Header::pixelAspectRatio ()458{459return static_cast <FloatAttribute &>460((*this)["pixelAspectRatio"]).value();461}462463464const float &465Header::pixelAspectRatio () const466{467return static_cast <const FloatAttribute &>468((*this)["pixelAspectRatio"]).value();469}470471472Imath::V2f &473Header::screenWindowCenter ()474{475return static_cast <V2fAttribute &>476((*this)["screenWindowCenter"]).value();477}478479480const Imath::V2f &481Header::screenWindowCenter () const482{483return static_cast <const V2fAttribute &>484((*this)["screenWindowCenter"]).value();485}486487488float &489Header::screenWindowWidth ()490{491return static_cast <FloatAttribute &>492((*this)["screenWindowWidth"]).value();493}494495496const float &497Header::screenWindowWidth () const498{499return static_cast <const FloatAttribute &>500((*this)["screenWindowWidth"]).value();501}502503504ChannelList &505Header::channels ()506{507return static_cast <ChannelListAttribute &>508((*this)["channels"]).value();509}510511512const ChannelList &513Header::channels () const514{515return static_cast <const ChannelListAttribute &>516((*this)["channels"]).value();517}518519520LineOrder &521Header::lineOrder ()522{523return static_cast <LineOrderAttribute &>524((*this)["lineOrder"]).value();525}526527528const LineOrder &529Header::lineOrder () const530{531return static_cast <const LineOrderAttribute &>532((*this)["lineOrder"]).value();533}534535536Compression &537Header::compression ()538{539return static_cast <CompressionAttribute &>540((*this)["compression"]).value();541}542543544const Compression &545Header::compression () const546{547return static_cast <const CompressionAttribute &>548((*this)["compression"]).value();549}550551552void553Header::setTileDescription(const TileDescription& td)554{555insert ("tiles", TileDescriptionAttribute (td));556}557558559bool560Header::hasTileDescription() const561{562return findTypedAttribute <TileDescriptionAttribute> ("tiles") != 0;563}564565566TileDescription &567Header::tileDescription ()568{569return typedAttribute <TileDescriptionAttribute> ("tiles").value();570}571572573const TileDescription &574Header::tileDescription () const575{576return typedAttribute <TileDescriptionAttribute> ("tiles").value();577}578579void580Header::setPreviewImage (const PreviewImage &pi)581{582insert ("preview", PreviewImageAttribute (pi));583}584585586PreviewImage &587Header::previewImage ()588{589return typedAttribute <PreviewImageAttribute> ("preview").value();590}591592593const PreviewImage &594Header::previewImage () const595{596return typedAttribute <PreviewImageAttribute> ("preview").value();597}598599600bool601Header::hasPreviewImage () const602{603return findTypedAttribute <PreviewImageAttribute> ("preview") != 0;604}605606607void608Header::sanityCheck (bool isTiled) const609{610//611// The display window and the data window must each612// contain at least one pixel. In addition, the613// coordinates of the window corners must be small614// enough to keep expressions like max-min+1 or615// max+min from overflowing.616//617618const Box2i &displayWindow = this->displayWindow();619620if (displayWindow.min.x > displayWindow.max.x ||621displayWindow.min.y > displayWindow.max.y ||622displayWindow.min.x <= -(INT_MAX / 2) ||623displayWindow.min.y <= -(INT_MAX / 2) ||624displayWindow.max.x >= (INT_MAX / 2) ||625displayWindow.max.y >= (INT_MAX / 2))626{627throw Iex::ArgExc ("Invalid display window in image header.");628}629630const Box2i &dataWindow = this->dataWindow();631632if (dataWindow.min.x > dataWindow.max.x ||633dataWindow.min.y > dataWindow.max.y ||634dataWindow.min.x <= -(INT_MAX / 2) ||635dataWindow.min.y <= -(INT_MAX / 2) ||636dataWindow.max.x >= (INT_MAX / 2) ||637dataWindow.max.y >= (INT_MAX / 2))638{639throw Iex::ArgExc ("Invalid data window in image header.");640}641642if (maxImageWidth > 0 &&643maxImageWidth < dataWindow.max.x - dataWindow.min.x + 1)644{645THROW (Iex::ArgExc, "The width of the data window exceeds the "646"maximum width of " << maxImageWidth << "pixels.");647}648649if (maxImageHeight > 0 &&650maxImageHeight < dataWindow.max.y - dataWindow.min.y + 1)651{652THROW (Iex::ArgExc, "The width of the data window exceeds the "653"maximum width of " << maxImageHeight << "pixels.");654}655656//657// The pixel aspect ratio must be greater than 0.658// In applications, numbers like the the display or659// data window dimensions are likely to be multiplied660// or divided by the pixel aspect ratio; to avoid661// arithmetic exceptions, we limit the pixel aspect662// ratio to a range that is smaller than theoretically663// possible (real aspect ratios are likely to be close664// to 1.0 anyway).665//666667float pixelAspectRatio = this->pixelAspectRatio();668669const float MIN_PIXEL_ASPECT_RATIO = 1e-6f;670const float MAX_PIXEL_ASPECT_RATIO = 1e+6f;671672if (pixelAspectRatio < MIN_PIXEL_ASPECT_RATIO ||673pixelAspectRatio > MAX_PIXEL_ASPECT_RATIO)674{675throw Iex::ArgExc ("Invalid pixel aspect ratio in image header.");676}677678//679// The screen window width must not be less than 0.680// The size of the screen window can vary over a wide681// range (fish-eye lens to astronomical telescope),682// so we can't limit the screen window width to a683// small range.684//685686float screenWindowWidth = this->screenWindowWidth();687688if (screenWindowWidth < 0)689throw Iex::ArgExc ("Invalid screen window width in image header.");690691//692// If the file is tiled, verify that the tile description has resonable693// values and check to see if the lineOrder is one of the predefined 3.694// If the file is not tiled, then the lineOrder can only be INCREASING_Y695// or DECREASING_Y.696//697698LineOrder lineOrder = this->lineOrder();699700if (isTiled)701{702if (!hasTileDescription())703{704throw Iex::ArgExc ("Tiled image has no tile "705"description attribute.");706}707708const TileDescription &tileDesc = tileDescription();709710if (tileDesc.xSize <= 0 || tileDesc.ySize <= 0)711throw Iex::ArgExc ("Invalid tile size in image header.");712713if (maxTileWidth > 0 &&714maxTileWidth < tileDesc.xSize)715{716THROW (Iex::ArgExc, "The width of the tiles exceeds the maximum "717"width of " << maxTileWidth << "pixels.");718}719720if (maxTileHeight > 0 &&721maxTileHeight < tileDesc.ySize)722{723THROW (Iex::ArgExc, "The width of the tiles exceeds the maximum "724"width of " << maxTileHeight << "pixels.");725}726727if (tileDesc.mode != ONE_LEVEL &&728tileDesc.mode != MIPMAP_LEVELS &&729tileDesc.mode != RIPMAP_LEVELS)730throw Iex::ArgExc ("Invalid level mode in image header.");731732if (tileDesc.roundingMode != ROUND_UP &&733tileDesc.roundingMode != ROUND_DOWN)734throw Iex::ArgExc ("Invalid level rounding mode in image header.");735736if (lineOrder != INCREASING_Y &&737lineOrder != DECREASING_Y &&738lineOrder != RANDOM_Y)739throw Iex::ArgExc ("Invalid line order in image header.");740}741else742{743if (lineOrder != INCREASING_Y &&744lineOrder != DECREASING_Y)745throw Iex::ArgExc ("Invalid line order in image header.");746}747748//749// The compression method must be one of the predefined values.750//751752if (!isValidCompression (this->compression()))753throw Iex::ArgExc ("Unknown compression type in image header.");754755//756// Check the channel list:757//758// If the file is tiled then for each channel, the type must be one of the759// predefined values, and the x and y sampling must both be 1.760//761// If the file is not tiled then for each channel, the type must be one762// of the predefined values, the x and y coordinates of the data window's763// upper left corner must be divisible by the x and y subsampling factors,764// and the width and height of the data window must be divisible by the765// x and y subsampling factors.766//767768const ChannelList &channels = this->channels();769770if (isTiled)771{772for (ChannelList::ConstIterator i = channels.begin();773i != channels.end();774++i)775{776if (i.channel().type != UINT &&777i.channel().type != HALF &&778i.channel().type != FLOAT)779{780THROW (Iex::ArgExc, "Pixel type of \"" << i.name() << "\" "781"image channel is invalid.");782}783784if (i.channel().xSampling != 1)785{786THROW (Iex::ArgExc, "The x subsampling factor for the "787"\"" << i.name() << "\" channel "788"is not 1.");789}790791if (i.channel().ySampling != 1)792{793THROW (Iex::ArgExc, "The y subsampling factor for the "794"\"" << i.name() << "\" channel "795"is not 1.");796}797}798}799else800{801for (ChannelList::ConstIterator i = channels.begin();802i != channels.end();803++i)804{805if (i.channel().type != UINT &&806i.channel().type != HALF &&807i.channel().type != FLOAT)808{809THROW (Iex::ArgExc, "Pixel type of \"" << i.name() << "\" "810"image channel is invalid.");811}812813if (i.channel().xSampling < 1)814{815THROW (Iex::ArgExc, "The x subsampling factor for the "816"\"" << i.name() << "\" channel "817"is invalid.");818}819820if (i.channel().ySampling < 1)821{822THROW (Iex::ArgExc, "The y subsampling factor for the "823"\"" << i.name() << "\" channel "824"is invalid.");825}826827if (dataWindow.min.x % i.channel().xSampling)828{829THROW (Iex::ArgExc, "The minimum x coordinate of the "830"image's data window is not a multiple "831"of the x subsampling factor of "832"the \"" << i.name() << "\" channel.");833}834835if (dataWindow.min.y % i.channel().ySampling)836{837THROW (Iex::ArgExc, "The minimum y coordinate of the "838"image's data window is not a multiple "839"of the y subsampling factor of "840"the \"" << i.name() << "\" channel.");841}842843if ((dataWindow.max.x - dataWindow.min.x + 1) %844i.channel().xSampling)845{846THROW (Iex::ArgExc, "Number of pixels per row in the "847"image's data window is not a multiple "848"of the x subsampling factor of "849"the \"" << i.name() << "\" channel.");850}851852if ((dataWindow.max.y - dataWindow.min.y + 1) %853i.channel().ySampling)854{855THROW (Iex::ArgExc, "Number of pixels per column in the "856"image's data window is not a multiple "857"of the y subsampling factor of "858"the \"" << i.name() << "\" channel.");859}860}861}862}863864865void866Header::setMaxImageSize (int maxWidth, int maxHeight)867{868maxImageWidth = maxWidth;869maxImageHeight = maxHeight;870}871872873void874Header::setMaxTileSize (int maxWidth, int maxHeight)875{876maxTileWidth = maxWidth;877maxTileHeight = maxHeight;878}879880881Int64882Header::writeTo (OStream &os, bool isTiled) const883{884//885// Write a "magic number" to identify the file as an image file.886// Write the current file format version number.887//888889Xdr::write <StreamIO> (os, MAGIC);890891int version = EXR_VERSION;892893if (isTiled)894version |= TILED_FLAG;895896if (usesLongNames (*this))897version |= LONG_NAMES_FLAG;898899Xdr::write <StreamIO> (os, version);900901//902// Write all attributes. If we have a preview image attribute,903// keep track of its position in the file.904//905906Int64 previewPosition = 0;907908const Attribute *preview =909findTypedAttribute <PreviewImageAttribute> ("preview");910911for (ConstIterator i = begin(); i != end(); ++i)912{913//914// Write the attribute's name and type.915//916917Xdr::write <StreamIO> (os, i.name());918Xdr::write <StreamIO> (os, i.attribute().typeName());919920//921// Write the size of the attribute value,922// and the value itself.923//924925StdOSStream oss;926i.attribute().writeValueTo (oss, version);927928std::string s = oss.str();929Xdr::write <StreamIO> (os, (int) s.length());930931if (&i.attribute() == preview)932previewPosition = os.tellp();933934os.write (s.data(), s.length());935}936937//938// Write zero-length attribute name to mark the end of the header.939//940941Xdr::write <StreamIO> (os, "");942943return previewPosition;944}945946947void948Header::readFrom (IStream &is, int &version)949{950//951// Read the magic number and the file format version number.952// Then check if we can read the rest of this file.953//954955int magic;956957Xdr::read <StreamIO> (is, magic);958Xdr::read <StreamIO> (is, version);959960if (magic != MAGIC)961{962throw Iex::InputExc ("File is not an image file.");963}964965if (getVersion (version) != EXR_VERSION)966{967THROW (Iex::InputExc, "Cannot read "968"version " << getVersion (version) << " "969"image files. Current file format version "970"is " << EXR_VERSION << ".");971}972973if (!supportsFlags (getFlags (version)))974{975THROW (Iex::InputExc, "The file format version number's flag field "976"contains unrecognized flags.");977}978979//980// Read all attributes.981//982983while (true)984{985//986// Read the name of the attribute.987// A zero-length attribute name indicates the end of the header.988//989990char name[Name::SIZE];991Xdr::read <StreamIO> (is, Name::MAX_LENGTH, name);992993if (name[0] == 0)994break;995996checkIsNullTerminated (name, "attribute name");997998//999// Read the attribute type and the size of the attribute value.1000//10011002char typeName[Name::SIZE];1003int size;10041005Xdr::read <StreamIO> (is, Name::MAX_LENGTH, typeName);1006checkIsNullTerminated (typeName, "attribute type name");1007Xdr::read <StreamIO> (is, size);10081009AttributeMap::iterator i = _map.find (name);10101011if (i != _map.end())1012{1013//1014// The attribute already exists (for example,1015// because it is a predefined attribute).1016// Read the attribute's new value from the file.1017//10181019if (strncmp (i->second->typeName(), typeName, sizeof (typeName)))1020THROW (Iex::InputExc, "Unexpected type for image attribute "1021"\"" << name << "\".");10221023i->second->readValueFrom (is, size, version);1024}1025else1026{1027//1028// The new attribute does not exist yet.1029// If the attribute type is of a known type,1030// read the attribute value. If the attribute1031// is of an unknown type, read its value and1032// store it as an OpaqueAttribute.1033//10341035Attribute *attr;10361037if (Attribute::knownType (typeName))1038attr = Attribute::newAttribute (typeName);1039else1040attr = new OpaqueAttribute (typeName);10411042try1043{1044attr->readValueFrom (is, size, version);1045_map[name] = attr;1046}1047catch (...)1048{1049delete attr;1050throw;1051}1052}1053}1054}105510561057void1058staticInitialize ()1059{1060static Mutex criticalSection;1061Lock lock (criticalSection);10621063static bool initialized = false;10641065if (!initialized)1066{1067//1068// One-time initialization -- register1069// some predefined attribute types.1070//10711072Box2fAttribute::registerAttributeType();1073Box2iAttribute::registerAttributeType();1074ChannelListAttribute::registerAttributeType();1075CompressionAttribute::registerAttributeType();1076ChromaticitiesAttribute::registerAttributeType();1077DoubleAttribute::registerAttributeType();1078EnvmapAttribute::registerAttributeType();1079FloatAttribute::registerAttributeType();1080IntAttribute::registerAttributeType();1081KeyCodeAttribute::registerAttributeType();1082LineOrderAttribute::registerAttributeType();1083M33dAttribute::registerAttributeType();1084M33fAttribute::registerAttributeType();1085M44dAttribute::registerAttributeType();1086M44fAttribute::registerAttributeType();1087PreviewImageAttribute::registerAttributeType();1088RationalAttribute::registerAttributeType();1089StringAttribute::registerAttributeType();1090StringVectorAttribute::registerAttributeType();1091TileDescriptionAttribute::registerAttributeType();1092TimeCodeAttribute::registerAttributeType();1093V2dAttribute::registerAttributeType();1094V2fAttribute::registerAttributeType();1095V2iAttribute::registerAttributeType();1096V3dAttribute::registerAttributeType();1097V3fAttribute::registerAttributeType();1098V3iAttribute::registerAttributeType();10991100initialized = true;1101}1102}110311041105} // namespace Imf110611071108