📄 imfheader.cpp
字号:
}
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
{
//
// The display window and the data window must each
// contain at least one pixel. In addition, the
// coordinates of the window corners must be small
// enough to keep expressions like max-min+1 or
// max+min from overflowing.
//
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.");
}
//
// The pixel aspect ratio must be greater than 0.
// In applications, numbers like the the display or
// data window dimensions are likely to be multiplied
// or divided by the pixel aspect ratio; to avoid
// arithmetic exceptions, we limit the pixel aspect
// ratio to a range that is smaller than theoretically
// possible (real aspect ratios are likely to be close
// to 1.0 anyway).
//
float pixelAspectRatio = this->pixelAspectRatio();
const float MIN_PIXEL_ASPECT_RATIO = 1e-6;
const float MAX_PIXEL_ASPECT_RATIO = 1e+6;
if (pixelAspectRatio < MIN_PIXEL_ASPECT_RATIO ||
pixelAspectRatio > MAX_PIXEL_ASPECT_RATIO)
{
throw Iex::ArgExc ("Invalid pixel aspect ratio in image header.");
}
//
// The screen window width must not be less than 0.
// The size of the screen window can vary over a wide
// range (fish-eye lens to astronomical telescope),
// so we can't limit the screen window width to a
// small range.
//
float screenWindowWidth = this->screenWindowWidth();
if (screenWindowWidth < 0)
throw Iex::ArgExc ("Invalid screen window width in image header.");
//
// If the file is tiled, verify that the tile description has resonable
// values and check to see if the lineOrder is one of the predefined 3.
// If the file is not tiled, then the lineOrder can only be INCREASING_Y
// or DECREASING_Y.
//
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.");
}
//
// The compression method must be one of the predefined values.
//
if (!isValidCompression (this->compression()))
throw Iex::ArgExc ("Unknown compression type in image header.");
//
// Check the channel list:
//
// If the file is tiled then for each channel, the type must be one of the
// predefined values, and the x and y sampling must both be 1.
//
// If the file is not tiled then for each channel, the type must be one
// of the predefined values, the x and y coordinates of the data window's
// upper left corner must be divisible by the x and y subsampling factors,
// and the width and height of the data window must be divisible by the
// x and y subsampling factors.
//
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
{
//
// Write a "magic number" to identify the file as an image file.
// Write the current file format version number.
//
Xdr::write <StreamIO> (os, MAGIC);
int version = isTiled ? makeTiled (EXR_VERSION) : EXR_VERSION;
Xdr::write <StreamIO> (os, version);
//
// Write all attributes. If we have a preview image attribute,
// keep track of its position in the file.
//
Int64 previewPosition = 0;
const Attribute *preview =
findTypedAttribute <PreviewImageAttribute> ("preview");
for (ConstIterator i = begin(); i != end(); ++i)
{
//
// Write the attribute's name and type.
//
Xdr::write <StreamIO> (os, i.name());
Xdr::write <StreamIO> (os, i.attribute().typeName());
//
// Write the size of the attribute value,
// and the value itself.
//
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());
}
//
// Write zero-length attribute name to mark the end of the header.
//
Xdr::write <StreamIO> (os, "");
return previewPosition;
}
void
Header::readFrom (IStream &is, int &version)
{
//
// Read the magic number and the file format version number.
// Then check if we can read the rest of this file.
//
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.");
}
//
// Read all attributes.
//
while (true)
{
//
// Read the name of the attribute.
// A zero-length attribute name indicates the end of the header.
//
char name[100];
Xdr::read <StreamIO> (is, sizeof (name), name);
if (name[0] == 0)
break;
//
// Read the attribute type and the size of the attribute value.
//
char typeName[100];
int size;
Xdr::read <StreamIO> (is, sizeof (typeName), typeName);
Xdr::read <StreamIO> (is, size);
AttributeMap::iterator i = _map.find (name);
if (i != _map.end())
{
//
// The attribute already exists (for example,
// because it is a predefined attribute).
// Read the attribute's new value from the file.
//
if (strncmp (i->second->typeName(), typeName, sizeof (typeName)))
THROW (Iex::InputExc, "Unexpected type for image attribute "
"\"" << name << "\".");
i->second->readValueFrom (is, size, version);
}
else
{
//
// The new attribute does not exist yet.
// If the attribute type is of a known type,
// read the attribute value. If the attribute
// is of an unknown type, read its value and
// store it as an OpaqueAttribute.
//
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)
{
//
// One-time initialization -- register
// some predefined attribute types.
//
Box2fAttribute::registerAttributeType();
Box2iAttribute::registerAttributeType();
ChannelListAttribute::registerAttributeType();
CompressionAttribute::registerAttributeType();
ChromaticitiesAttribute::registerAttributeType();
DoubleAttribute::registerAttributeType();
EnvmapAttribute::registerAttributeType();
FloatAttribute::registerAttributeType();
IntAttribute::registerAttributeType();
KeyCodeAttribute::registerAttributeType();
LineOrderAttribute::registerAttributeType();
M33fAttribute::registerAttributeType();
M44fAttribute::registerAttributeType();
PreviewImageAttribute::registerAttributeType();
RationalAttribute::registerAttributeType();
StringAttribute::registerAttributeType();
TileDescriptionAttribute::registerAttributeType();
TimeCodeAttribute::registerAttributeType();
V2fAttribute::registerAttributeType();
V2iAttribute::registerAttributeType();
V3fAttribute::registerAttributeType();
V3iAttribute::registerAttributeType();
initialized = true;
}
}
} // namespace Imf
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -