This source file includes following definitions.
- initialize
- usesLongNames
- checkIsNullTerminated
- insert
- insert
- begin
- begin
- end
- end
- find
- find
- find
- find
- displayWindow
- displayWindow
- dataWindow
- dataWindow
- pixelAspectRatio
- pixelAspectRatio
- screenWindowCenter
- screenWindowCenter
- screenWindowWidth
- screenWindowWidth
- channels
- channels
- lineOrder
- lineOrder
- compression
- compression
- setTileDescription
- hasTileDescription
- tileDescription
- tileDescription
- setPreviewImage
- previewImage
- previewImage
- hasPreviewImage
- sanityCheck
- setMaxImageSize
- setMaxTileSize
- writeTo
- readFrom
- staticInitialize
#include <ImfHeader.h>
#include <ImfStdIO.h>
#include <ImfVersion.h>
#include <ImfCompressor.h>
#include <ImfMisc.h>
#include <ImfBoxAttribute.h>
#include <ImfChannelListAttribute.h>
#include <ImfChromaticitiesAttribute.h>
#include <ImfCompressionAttribute.h>
#include <ImfDoubleAttribute.h>
#include <ImfEnvmapAttribute.h>
#include <ImfFloatAttribute.h>
#include <ImfIntAttribute.h>
#include <ImfKeyCodeAttribute.h>
#include <ImfLineOrderAttribute.h>
#include <ImfMatrixAttribute.h>
#include <ImfOpaqueAttribute.h>
#include <ImfPreviewImageAttribute.h>
#include <ImfRationalAttribute.h>
#include <ImfStringAttribute.h>
#include <ImfStringVectorAttribute.h>
#include <ImfTileDescriptionAttribute.h>
#include <ImfTimeCodeAttribute.h>
#include <ImfVecAttribute.h>
#include "IlmThreadMutex.h"
#include "Iex.h"
#include <sstream>
#include <stdlib.h>
#include <time.h>
namespace Imf {
using namespace std;
using Imath::Box2i;
using Imath::V2i;
using Imath::V2f;
using IlmThread::Mutex;
using IlmThread::Lock;
namespace {
int maxImageWidth = 0;
int maxImageHeight = 0;
int maxTileWidth = 0;
int maxTileHeight = 0;
void
initialize (Header &header,
const Box2i &displayWindow,
const Box2i &dataWindow,
float pixelAspectRatio,
const V2f &screenWindowCenter,
float screenWindowWidth,
LineOrder lineOrder,
Compression compression)
{
header.insert ("displayWindow", Box2iAttribute (displayWindow));
header.insert ("dataWindow", Box2iAttribute (dataWindow));
header.insert ("pixelAspectRatio", FloatAttribute (pixelAspectRatio));
header.insert ("screenWindowCenter", V2fAttribute (screenWindowCenter));
header.insert ("screenWindowWidth", FloatAttribute (screenWindowWidth));
header.insert ("lineOrder", LineOrderAttribute (lineOrder));
header.insert ("compression", CompressionAttribute (compression));
header.insert ("channels", ChannelListAttribute ());
}
bool
usesLongNames (const Header &header)
{
for (Header::ConstIterator i = header.begin();
i != header.end();
++i)
{
if (strlen (i.name()) >= 32 || strlen (i.attribute().typeName()) >= 32)
return true;
}
const ChannelList &channels = header.channels();
for (ChannelList::ConstIterator i = channels.begin();
i != channels.end();
++i)
{
if (strlen (i.name()) >= 32)
return true;
}
return false;
}
template <size_t N>
void checkIsNullTerminated (const char (&str)[N], const char *what)
{
for (int i = 0; i < N; ++i) {
if (str[i] == '\0')
return;
}
std::stringstream s;
s << "Invalid " << what << ": it is more than " << (N - 1)
<< " characters long.";
throw Iex::InputExc(s);
}
}
Header::Header (int width,
int height,
float pixelAspectRatio,
const V2f &screenWindowCenter,
float screenWindowWidth,
LineOrder lineOrder,
Compression compression)
:
_map()
{
staticInitialize();
Box2i displayWindow (V2i (0, 0), V2i (width - 1, height - 1));
initialize (*this,
displayWindow,
displayWindow,
pixelAspectRatio,
screenWindowCenter,
screenWindowWidth,
lineOrder,
compression);
}
Header::Header (int width,
int height,
const Box2i &dataWindow,
float pixelAspectRatio,
const V2f &screenWindowCenter,
float screenWindowWidth,
LineOrder lineOrder,
Compression compression)
:
_map()
{
staticInitialize();
Box2i displayWindow (V2i (0, 0), V2i (width - 1, height - 1));
initialize (*this,
displayWindow,
dataWindow,
pixelAspectRatio,
screenWindowCenter,
screenWindowWidth,
lineOrder,
compression);
}
Header::Header (const Box2i &displayWindow,
const Box2i &dataWindow,
float pixelAspectRatio,
const V2f &screenWindowCenter,
float screenWindowWidth,
LineOrder lineOrder,
Compression compression)
:
_map()
{
staticInitialize();
initialize (*this,
displayWindow,
dataWindow,
pixelAspectRatio,
screenWindowCenter,
screenWindowWidth,
lineOrder,
compression);
}
Header::Header (const Header &other): _map()
{
for (AttributeMap::const_iterator i = other._map.begin();
i != other._map.end();
++i)
{
insert (*i->first, *i->second);
}
}
Header::~Header ()
{
for (AttributeMap::iterator i = _map.begin();
i != _map.end();
++i)
{
delete i->second;
}
}
Header &
Header::operator = (const Header &other)
{
if (this != &other)
{
for (AttributeMap::iterator i = _map.begin();
i != _map.end();
++i)
{
delete i->second;
}
_map.erase (_map.begin(), _map.end());
for (AttributeMap::const_iterator i = other._map.begin();
i != other._map.end();
++i)
{
insert (*i->first, *i->second);
}
}
return *this;
}
void
Header::insert (const char name[], const Attribute &attribute)
{
if (name[0] == 0)
THROW (Iex::ArgExc, "Image attribute name cannot be an empty string.");
AttributeMap::iterator i = _map.find (name);
if (i == _map.end())
{
Attribute *tmp = attribute.copy();
try
{
_map[name] = tmp;
}
catch (...)
{
delete tmp;
throw;
}
}
else
{
if (strcmp (i->second->typeName(), attribute.typeName()))
THROW (Iex::TypeExc, "Cannot assign a value of "
"type \"" << attribute.typeName() << "\" "
"to image attribute \"" << name << "\" of "
"type \"" << i->second->typeName() << "\".");
Attribute *tmp = attribute.copy();
delete i->second;
i->second = tmp;
}
}
void
Header::insert (const string &name, const Attribute &attribute)
{
insert (name.c_str(), attribute);
}
Attribute &
Header::operator [] (const char name[])
{
AttributeMap::iterator i = _map.find (name);
if (i == _map.end())
THROW (Iex::ArgExc, "Cannot find image attribute \"" << name << "\".");
return *i->second;
}
const Attribute &
Header::operator [] (const char name[]) const
{
AttributeMap::const_iterator i = _map.find (name);
if (i == _map.end())
THROW (Iex::ArgExc, "Cannot find image attribute \"" << name << "\".");
return *i->second;
}
Attribute &
Header::operator [] (const string &name)
{
return this->operator[] (name.c_str());
}
const Attribute &
Header::operator [] (const string &name) const
{
return this->operator[] (name.c_str());
}
Header::Iterator
Header::begin ()
{
return _map.begin();
}
Header::ConstIterator
Header::begin () const
{
return _map.begin();
}
Header::Iterator
Header::end ()
{
return _map.end();
}
Header::ConstIterator
Header::end () const
{
return _map.end();
}
Header::Iterator
Header::find (const char name[])
{
return _map.find (name);
}
Header::ConstIterator
Header::find (const char name[]) const
{
return _map.find (name);
}
Header::Iterator
Header::find (const string &name)
{
return find (name.c_str());
}
Header::ConstIterator
Header::find (const string &name) const
{
return find (name.c_str());
}
Imath::Box2i &
Header::displayWindow ()
{
return static_cast <Box2iAttribute &>
((*this)["displayWindow"]).value();
}
const Imath::Box2i &
Header::displayWindow () const
{
return static_cast <const Box2iAttribute &>
((*this)["displayWindow"]).value();
}
Imath::Box2i &
Header::dataWindow ()
{
return static_cast <Box2iAttribute &>
((*this)["dataWindow"]).value();
}
const Imath::Box2i &
Header::dataWindow () const
{
return static_cast <const Box2iAttribute &>
((*this)["dataWindow"]).value();
}
float &
Header::pixelAspectRatio ()
{
return static_cast <FloatAttribute &>
((*this)["pixelAspectRatio"]).value();
}
const float &
Header::pixelAspectRatio () const
{
return static_cast <const FloatAttribute &>
((*this)["pixelAspectRatio"]).value();
}
Imath::V2f &
Header::screenWindowCenter ()
{
return static_cast <V2fAttribute &>
((*this)["screenWindowCenter"]).value();
}
const Imath::V2f &
Header::screenWindowCenter () const
{
return static_cast <const V2fAttribute &>
((*this)["screenWindowCenter"]).value();
}
float &
Header::screenWindowWidth ()
{
return static_cast <FloatAttribute &>
((*this)["screenWindowWidth"]).value();
}
const float &
Header::screenWindowWidth () const
{
return static_cast <const FloatAttribute &>
((*this)["screenWindowWidth"]).value();
}
ChannelList &
Header::channels ()
{
return static_cast <ChannelListAttribute &>
((*this)["channels"]).value();
}
const ChannelList &
Header::channels () const
{
return static_cast <const ChannelListAttribute &>
((*this)["channels"]).value();
}
LineOrder &
Header::lineOrder ()
{
return static_cast <LineOrderAttribute &>
((*this)["lineOrder"]).value();
}
const LineOrder &
Header::lineOrder () const
{
return static_cast <const LineOrderAttribute &>
((*this)["lineOrder"]).value();
}
Compression &
Header::compression ()
{
return static_cast <CompressionAttribute &>
((*this)["compression"]).value();
}
const Compression &
Header::compression () const
{
return static_cast <const CompressionAttribute &>
((*this)["compression"]).value();
}
void
Header::setTileDescription(const TileDescription& td)
{
insert ("tiles", TileDescriptionAttribute (td));
}
bool
Header::hasTileDescription() const
{
return findTypedAttribute <TileDescriptionAttribute> ("tiles") != 0;
}
TileDescription &
Header::tileDescription ()
{
return typedAttribute <TileDescriptionAttribute> ("tiles").value();
}
const TileDescription &
Header::tileDescription () const
{
return typedAttribute <TileDescriptionAttribute> ("tiles").value();
}
void
Header::setPreviewImage (const PreviewImage &pi)
{
insert ("preview", PreviewImageAttribute (pi));
}
PreviewImage &
Header::previewImage ()
{
return typedAttribute <PreviewImageAttribute> ("preview").value();
}
const PreviewImage &
Header::previewImage () const
{
return typedAttribute <PreviewImageAttribute> ("preview").value();
}
bool
Header::hasPreviewImage () const
{
return findTypedAttribute <PreviewImageAttribute> ("preview") != 0;
}
void
Header::sanityCheck (bool isTiled) const
{
const Box2i &displayWindow = this->displayWindow();
if (displayWindow.min.x > displayWindow.max.x ||
displayWindow.min.y > displayWindow.max.y ||
displayWindow.min.x <= -(INT_MAX / 2) ||
displayWindow.min.y <= -(INT_MAX / 2) ||
displayWindow.max.x >= (INT_MAX / 2) ||
displayWindow.max.y >= (INT_MAX / 2))
{
throw Iex::ArgExc ("Invalid display window in image header.");
}
const Box2i &dataWindow = this->dataWindow();
if (dataWindow.min.x > dataWindow.max.x ||
dataWindow.min.y > dataWindow.max.y ||
dataWindow.min.x <= -(INT_MAX / 2) ||
dataWindow.min.y <= -(INT_MAX / 2) ||
dataWindow.max.x >= (INT_MAX / 2) ||
dataWindow.max.y >= (INT_MAX / 2))
{
throw Iex::ArgExc ("Invalid data window in image header.");
}
if (maxImageWidth > 0 &&
maxImageWidth < dataWindow.max.x - dataWindow.min.x + 1)
{
THROW (Iex::ArgExc, "The width of the data window exceeds the "
"maximum width of " << maxImageWidth << "pixels.");
}
if (maxImageHeight > 0 &&
maxImageHeight < dataWindow.max.y - dataWindow.min.y + 1)
{
THROW (Iex::ArgExc, "The width of the data window exceeds the "
"maximum width of " << maxImageHeight << "pixels.");
}
float pixelAspectRatio = this->pixelAspectRatio();
const float MIN_PIXEL_ASPECT_RATIO = 1e-6f;
const float MAX_PIXEL_ASPECT_RATIO = 1e+6f;
if (pixelAspectRatio < MIN_PIXEL_ASPECT_RATIO ||
pixelAspectRatio > MAX_PIXEL_ASPECT_RATIO)
{
throw Iex::ArgExc ("Invalid pixel aspect ratio in image header.");
}
float screenWindowWidth = this->screenWindowWidth();
if (screenWindowWidth < 0)
throw Iex::ArgExc ("Invalid screen window width in image header.");
LineOrder lineOrder = this->lineOrder();
if (isTiled)
{
if (!hasTileDescription())
{
throw Iex::ArgExc ("Tiled image has no tile "
"description attribute.");
}
const TileDescription &tileDesc = tileDescription();
if (tileDesc.xSize <= 0 || tileDesc.ySize <= 0)
throw Iex::ArgExc ("Invalid tile size in image header.");
if (maxTileWidth > 0 &&
maxTileWidth < tileDesc.xSize)
{
THROW (Iex::ArgExc, "The width of the tiles exceeds the maximum "
"width of " << maxTileWidth << "pixels.");
}
if (maxTileHeight > 0 &&
maxTileHeight < tileDesc.ySize)
{
THROW (Iex::ArgExc, "The width of the tiles exceeds the maximum "
"width of " << maxTileHeight << "pixels.");
}
if (tileDesc.mode != ONE_LEVEL &&
tileDesc.mode != MIPMAP_LEVELS &&
tileDesc.mode != RIPMAP_LEVELS)
throw Iex::ArgExc ("Invalid level mode in image header.");
if (tileDesc.roundingMode != ROUND_UP &&
tileDesc.roundingMode != ROUND_DOWN)
throw Iex::ArgExc ("Invalid level rounding mode in image header.");
if (lineOrder != INCREASING_Y &&
lineOrder != DECREASING_Y &&
lineOrder != RANDOM_Y)
throw Iex::ArgExc ("Invalid line order in image header.");
}
else
{
if (lineOrder != INCREASING_Y &&
lineOrder != DECREASING_Y)
throw Iex::ArgExc ("Invalid line order in image header.");
}
if (!isValidCompression (this->compression()))
throw Iex::ArgExc ("Unknown compression type in image header.");
const ChannelList &channels = this->channels();
if (isTiled)
{
for (ChannelList::ConstIterator i = channels.begin();
i != channels.end();
++i)
{
if (i.channel().type != UINT &&
i.channel().type != HALF &&
i.channel().type != FLOAT)
{
THROW (Iex::ArgExc, "Pixel type of \"" << i.name() << "\" "
"image channel is invalid.");
}
if (i.channel().xSampling != 1)
{
THROW (Iex::ArgExc, "The x subsampling factor for the "
"\"" << i.name() << "\" channel "
"is not 1.");
}
if (i.channel().ySampling != 1)
{
THROW (Iex::ArgExc, "The y subsampling factor for the "
"\"" << i.name() << "\" channel "
"is not 1.");
}
}
}
else
{
for (ChannelList::ConstIterator i = channels.begin();
i != channels.end();
++i)
{
if (i.channel().type != UINT &&
i.channel().type != HALF &&
i.channel().type != FLOAT)
{
THROW (Iex::ArgExc, "Pixel type of \"" << i.name() << "\" "
"image channel is invalid.");
}
if (i.channel().xSampling < 1)
{
THROW (Iex::ArgExc, "The x subsampling factor for the "
"\"" << i.name() << "\" channel "
"is invalid.");
}
if (i.channel().ySampling < 1)
{
THROW (Iex::ArgExc, "The y subsampling factor for the "
"\"" << i.name() << "\" channel "
"is invalid.");
}
if (dataWindow.min.x % i.channel().xSampling)
{
THROW (Iex::ArgExc, "The minimum x coordinate of the "
"image's data window is not a multiple "
"of the x subsampling factor of "
"the \"" << i.name() << "\" channel.");
}
if (dataWindow.min.y % i.channel().ySampling)
{
THROW (Iex::ArgExc, "The minimum y coordinate of the "
"image's data window is not a multiple "
"of the y subsampling factor of "
"the \"" << i.name() << "\" channel.");
}
if ((dataWindow.max.x - dataWindow.min.x + 1) %
i.channel().xSampling)
{
THROW (Iex::ArgExc, "Number of pixels per row in the "
"image's data window is not a multiple "
"of the x subsampling factor of "
"the \"" << i.name() << "\" channel.");
}
if ((dataWindow.max.y - dataWindow.min.y + 1) %
i.channel().ySampling)
{
THROW (Iex::ArgExc, "Number of pixels per column in the "
"image's data window is not a multiple "
"of the y subsampling factor of "
"the \"" << i.name() << "\" channel.");
}
}
}
}
void
Header::setMaxImageSize (int maxWidth, int maxHeight)
{
maxImageWidth = maxWidth;
maxImageHeight = maxHeight;
}
void
Header::setMaxTileSize (int maxWidth, int maxHeight)
{
maxTileWidth = maxWidth;
maxTileHeight = maxHeight;
}
Int64
Header::writeTo (OStream &os, bool isTiled) const
{
Xdr::write <StreamIO> (os, MAGIC);
int version = EXR_VERSION;
if (isTiled)
version |= TILED_FLAG;
if (usesLongNames (*this))
version |= LONG_NAMES_FLAG;
Xdr::write <StreamIO> (os, version);
Int64 previewPosition = 0;
const Attribute *preview =
findTypedAttribute <PreviewImageAttribute> ("preview");
for (ConstIterator i = begin(); i != end(); ++i)
{
Xdr::write <StreamIO> (os, i.name());
Xdr::write <StreamIO> (os, i.attribute().typeName());
StdOSStream oss;
i.attribute().writeValueTo (oss, version);
std::string s = oss.str();
Xdr::write <StreamIO> (os, (int) s.length());
if (&i.attribute() == preview)
previewPosition = os.tellp();
os.write (s.data(), s.length());
}
Xdr::write <StreamIO> (os, "");
return previewPosition;
}
void
Header::readFrom (IStream &is, int &version)
{
int magic;
Xdr::read <StreamIO> (is, magic);
Xdr::read <StreamIO> (is, version);
if (magic != MAGIC)
{
throw Iex::InputExc ("File is not an image file.");
}
if (getVersion (version) != EXR_VERSION)
{
THROW (Iex::InputExc, "Cannot read "
"version " << getVersion (version) << " "
"image files. Current file format version "
"is " << EXR_VERSION << ".");
}
if (!supportsFlags (getFlags (version)))
{
THROW (Iex::InputExc, "The file format version number's flag field "
"contains unrecognized flags.");
}
while (true)
{
char name[Name::SIZE];
Xdr::read <StreamIO> (is, Name::MAX_LENGTH, name);
if (name[0] == 0)
break;
checkIsNullTerminated (name, "attribute name");
char typeName[Name::SIZE];
int size;
Xdr::read <StreamIO> (is, Name::MAX_LENGTH, typeName);
checkIsNullTerminated (typeName, "attribute type name");
Xdr::read <StreamIO> (is, size);
AttributeMap::iterator i = _map.find (name);
if (i != _map.end())
{
if (strncmp (i->second->typeName(), typeName, sizeof (typeName)))
THROW (Iex::InputExc, "Unexpected type for image attribute "
"\"" << name << "\".");
i->second->readValueFrom (is, size, version);
}
else
{
Attribute *attr;
if (Attribute::knownType (typeName))
attr = Attribute::newAttribute (typeName);
else
attr = new OpaqueAttribute (typeName);
try
{
attr->readValueFrom (is, size, version);
_map[name] = attr;
}
catch (...)
{
delete attr;
throw;
}
}
}
}
void
staticInitialize ()
{
static Mutex criticalSection;
Lock lock (criticalSection);
static bool initialized = false;
if (!initialized)
{
Box2fAttribute::registerAttributeType();
Box2iAttribute::registerAttributeType();
ChannelListAttribute::registerAttributeType();
CompressionAttribute::registerAttributeType();
ChromaticitiesAttribute::registerAttributeType();
DoubleAttribute::registerAttributeType();
EnvmapAttribute::registerAttributeType();
FloatAttribute::registerAttributeType();
IntAttribute::registerAttributeType();
KeyCodeAttribute::registerAttributeType();
LineOrderAttribute::registerAttributeType();
M33dAttribute::registerAttributeType();
M33fAttribute::registerAttributeType();
M44dAttribute::registerAttributeType();
M44fAttribute::registerAttributeType();
PreviewImageAttribute::registerAttributeType();
RationalAttribute::registerAttributeType();
StringAttribute::registerAttributeType();
StringVectorAttribute::registerAttributeType();
TileDescriptionAttribute::registerAttributeType();
TimeCodeAttribute::registerAttributeType();
V2dAttribute::registerAttributeType();
V2fAttribute::registerAttributeType();
V2iAttribute::registerAttributeType();
V3dAttribute::registerAttributeType();
V3fAttribute::registerAttributeType();
V3iAttribute::registerAttributeType();
initialized = true;
}
}
}