2022-04-07 18:46:57 +02:00

538 lines
15 KiB
C++

///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2004-2012, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
///////////////////////////////////////////////////////////////////////////
#include <tmpDir.h>
#include <ImfOutputFile.h>
#include <ImfInputFile.h>
#include <ImfChannelList.h>
#include <ImfArray.h>
#include <ImfVersion.h>
#include <half.h>
#include <ImfBoxAttribute.h>
#include <ImfChannelListAttribute.h>
#include <ImfCompressionAttribute.h>
#include <ImfChromaticitiesAttribute.h>
#include <ImfFloatAttribute.h>
#include <ImfFloatVectorAttribute.h>
#include <ImfEnvmapAttribute.h>
#include <ImfDeepImageStateAttribute.h>
#include <ImfDoubleAttribute.h>
#include <ImfIntAttribute.h>
#include <ImfLineOrderAttribute.h>
#include <ImfMatrixAttribute.h>
#include <ImfOpaqueAttribute.h>
#include <ImfStringAttribute.h>
#include <ImfStringVectorAttribute.h>
#include <ImfVecAttribute.h>
#include <stdio.h>
#include <assert.h>
namespace IMF = OPENEXR_IMF_NAMESPACE;
using namespace IMF;
using namespace std;
using namespace IMATH_NAMESPACE;
namespace {
void
fillPixels (Array2D<float> &pf, int width, int height)
{
for (int y = 0; y < height; ++y)
for (int x = 0; x < width; ++x)
pf[y][x] = x % 10 + 10 * (y % 17);
}
void
writeReadAttr (const Array2D<float> &pf1,
const char fileName[],
int width,
int height)
{
//
// We don't test ChannelList, LineOrder, Compression and opaque
// attributes here; those types are covered by other tests.
//
Box2i a1 (V2i (1, 2), V2i (3, 4));
Box2f a2 (V2f (1.5, 2.5), V2f (3.5, 4.5));
float a3 (3.14159);
int a4 (17);
M33f a5 (11, 12, 13, 14, 15, 16, 17, 18, 19);
M44f a6 (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16);
string a7 ("extensive rebuilding by Nebuchadrezzar has left");
V2i a8 (27, 28);
V2f a9 (27.5, 28.5);
V3i a10 (37, 38, 39);
V3f a11 (37.5, 38.5, 39.5);
double a12 (7.12342341419);
Chromaticities a13 (V2f (1, 2), V2f (3, 4), V2f (5, 6), V2f (7, 8));
Envmap a14 (ENVMAP_CUBE);
StringVector a15;
a15.push_back ("who can spin");
a15.push_back ("");
a15.push_back ("straw into");
a15.push_back ("gold");
M33d a16 (12, 13, 14, 15, 16, 17, 18, 19, 20);
M44d a17 (2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17);
V2d a18 (27.51, 28.51);
V3d a19 (37.51, 38.51, 39.51);
StringVector a20;
DeepImageState a21 (DIS_TIDY);
FloatVector a22;
FloatVector a23;
a23.push_back (1.5f);
a23.push_back (-1.5f);
a23.push_back (15.0f);
a23.push_back (150.0f);
//
// Write an image file with extra attributes in the header
//
{
Header hdr (width, height);
hdr.insert ("a1", Box2iAttribute (a1));
hdr.insert ("a2", Box2fAttribute (a2));
hdr.insert ("a3", FloatAttribute (a3));
hdr.insert ("a4", IntAttribute (a4));
hdr.insert ("a5", M33fAttribute (a5));
hdr.insert ("a6", M44fAttribute (a6));
hdr.insert ("a7", StringAttribute (a7));
hdr.insert ("a8", V2iAttribute (a8));
hdr.insert ("a9", V2fAttribute (a9));
hdr.insert ("a10", V3iAttribute (a10));
hdr.insert ("a11", V3fAttribute (a11));
hdr.insert ("a12", DoubleAttribute (a12));
hdr.insert ("a13", ChromaticitiesAttribute (a13));
hdr.insert ("a14", EnvmapAttribute (a14));
hdr.insert ("a15", StringVectorAttribute (a15));
hdr.insert ("a16", M33dAttribute (a16));
hdr.insert ("a17", M44dAttribute (a17));
hdr.insert ("a18", V2dAttribute (a18));
hdr.insert ("a19", V3dAttribute (a19));
hdr.insert ("a20", StringVectorAttribute (a20));
hdr.insert ("a21", DeepImageStateAttribute (a21));
hdr.insert ("a22", FloatVectorAttribute (a22));
hdr.insert ("a23", FloatVectorAttribute (a23));
hdr.channels().insert ("F", // name
Channel (IMF::FLOAT, // type
1, // xSampling
1) // ySampling
);
FrameBuffer fb;
fb.insert ("F", // name
Slice (IMF::FLOAT, // type
(char *) &pf1[0][0], // base
sizeof (pf1[0][0]), // xStride
sizeof (pf1[0][0]) * width, // yStride
1, // xSampling
1) // ySampling
);
cout << "writing" << flush;
remove (fileName);
OutputFile out (fileName, hdr);
out.setFrameBuffer (fb);
out.writePixels (height);
}
//
// Read the header back from the file, and see if the
// values of the extra attributes come back correctly.
//
{
cout << " reading" << flush;
InputFile in (fileName);
cout << " (version " << in.version() << ")" << flush;
const Header &hdr = in.header();
assert (hdr.typedAttribute <Box2iAttribute> ("a1").value() == a1);
assert (hdr.typedAttribute <Box2fAttribute> ("a2").value() == a2);
assert (hdr.typedAttribute <FloatAttribute> ("a3").value() == a3);
assert (hdr.typedAttribute <IntAttribute> ("a4").value() == a4);
assert (hdr.typedAttribute <M33fAttribute> ("a5").value() == a5);
assert (hdr.typedAttribute <M44fAttribute> ("a6").value() == a6);
assert (hdr.typedAttribute <StringAttribute> ("a7").value() == a7);
assert (hdr.typedAttribute <V2iAttribute> ("a8").value() == a8);
assert (hdr.typedAttribute <V2fAttribute> ("a9").value() == a9);
assert (hdr.typedAttribute <V3iAttribute> ("a10").value() == a10);
assert (hdr.typedAttribute <V3fAttribute> ("a11").value() == a11);
assert (hdr.typedAttribute <DoubleAttribute> ("a12").value() == a12);
assert (hdr.typedAttribute <ChromaticitiesAttribute>
("a13").value().red == a13.red);
assert (hdr.typedAttribute <ChromaticitiesAttribute>
("a13").value().green == a13.green);
assert (hdr.typedAttribute <ChromaticitiesAttribute>
("a13").value().blue == a13.blue);
assert (hdr.typedAttribute <ChromaticitiesAttribute>
("a13").value().white == a13.white);
assert (hdr.typedAttribute <EnvmapAttribute> ("a14").value() == a14);
assert (hdr.typedAttribute <StringVectorAttribute>
("a15").value().size() == 4);
assert (hdr.typedAttribute <StringVectorAttribute>
("a15").value()[0] == "who can spin");
assert (hdr.typedAttribute <StringVectorAttribute>
("a15").value()[1] == "");
assert (hdr.typedAttribute <StringVectorAttribute>
("a15").value()[2] == "straw into");
assert (hdr.typedAttribute <StringVectorAttribute>
("a15").value()[3] == "gold");
assert (hdr.typedAttribute <M33dAttribute> ("a16").value() == a16);
assert (hdr.typedAttribute <M44dAttribute> ("a17").value() == a17);
assert (hdr.typedAttribute <V2dAttribute> ("a18").value() == a18);
assert (hdr.typedAttribute <V3dAttribute> ("a19").value() == a19);
assert (hdr.typedAttribute <StringVectorAttribute>
("a20").value() == a20);
assert (hdr.typedAttribute <DeepImageStateAttribute>
("a21").value() == a21);
assert (hdr.typedAttribute <FloatVectorAttribute>
("a22").value() == a22);
assert (hdr.typedAttribute <FloatVectorAttribute>
("a23").value() == a23);
}
remove (fileName);
cout << endl;
}
void
channelList ()
{
cout << "channel list" << endl;
{
// test channelsWithPrefix()
ChannelList channels;
channels.insert ("b0", Channel (IMF::HALF, 1, 1));
channels.insert ("b1", Channel (IMF::HALF, 1, 1));
channels.insert ("b2", Channel (IMF::HALF, 1, 1));
channels.insert ("d3", Channel (IMF::HALF, 1, 1));
channels.insert ("e4", Channel (IMF::HALF, 1, 1));
ChannelList::Iterator first;
ChannelList::Iterator last;
channels.channelsWithPrefix ("a", first, last);
assert (first != channels.end());
assert (first == last);
channels.channelsWithPrefix ("b", first, last);
assert (first != channels.end());
assert (first != last);
assert (first++.name() == Name ("b0"));
assert (first++.name() == Name ("b1"));
assert (first++.name() == Name ("b2"));
assert (first == last);
channels.channelsWithPrefix ("b1", first, last);
assert (first != channels.end());
assert (first != last);
assert (first++.name() == Name ("b1"));
assert (first == last);
channels.channelsWithPrefix ("b11", first, last);
assert (first != channels.end());
assert (first == last);
channels.channelsWithPrefix ("c", first, last);
assert (first != channels.end());
assert (first == last);
channels.channelsWithPrefix ("d", first, last);
assert (first != channels.end());
assert (first != last);
assert (first++.name() == Name ("d3"));
assert (first == last);
channels.channelsWithPrefix ("e", first, last);
assert (first != channels.end());
assert (first != last);
assert (first++.name() == Name ("e4"));
assert (first == last);
channels.channelsWithPrefix ("f", first, last);
assert (first == channels.end());
assert (first == last);
}
{
// Test support for layers
ChannelList channels;
channels.insert ("a", Channel (IMF::HALF, 1, 1));
channels.insert (".a", Channel (IMF::HALF, 1, 1));
channels.insert ("a.", Channel (IMF::HALF, 1, 1));
channels.insert ("layer1.R", Channel (IMF::HALF, 1, 1));
channels.insert ("layer1.G", Channel (IMF::HALF, 1, 1));
channels.insert ("layer1.B", Channel (IMF::HALF, 1, 1));
channels.insert ("layer1.sublayer1.AA", Channel (IMF::HALF, 1, 1));
channels.insert ("layer1.sublayer1.R", Channel (IMF::HALF, 1, 1));
channels.insert ("layer1.sublayer1.G", Channel (IMF::HALF, 1, 1));
channels.insert ("layer1.sublayer1.B", Channel (IMF::HALF, 1, 1));
channels.insert ("layer1.sublayer2.R", Channel (IMF::HALF, 1, 1));
channels.insert ("layer2.R", Channel (IMF::HALF, 1, 1));
channels.insert ("layer2.G", Channel (IMF::HALF, 1, 1));
channels.insert ("layer2.B", Channel (IMF::HALF, 1, 1));
set <string> layerNames;
channels.layers (layerNames);
set<string>::iterator i = layerNames.begin();
assert (*i++ == "layer1");
assert (*i++ == "layer1.sublayer1");
assert (*i++ == "layer1.sublayer2");
assert (*i++ == "layer2");
assert (i == layerNames.end());
ChannelList::ConstIterator first, last;
channels.channelsInLayer ("layer1.sublayer1", first, last);
assert (first != channels.end());
assert (first != last);
assert (first++.name() == Name ("layer1.sublayer1.AA"));
assert (first++.name() == Name ("layer1.sublayer1.B"));
assert (first++.name() == Name ("layer1.sublayer1.G"));
assert (first++.name() == Name ("layer1.sublayer1.R"));
assert (first == last);
channels.channelsInLayer ("layer2", first, last);
assert (first != channels.end());
assert (first != last);
assert (first++.name() == Name ("layer2.B"));
assert (first++.name() == Name ("layer2.G"));
assert (first++.name() == Name ("layer2.R"));
assert (first == last);
}
}
void
longNames (const Array2D<float> &pf1,
const char fileName[],
int width,
int height)
{
//
// Verify that long attibute or channel names in the header
// set the LONG_NAMES_FLAG in the file version number.
//
FrameBuffer fb;
fb.insert ("F", // name
Slice (IMF::FLOAT, // type
(char *) &pf1[0][0], // base
sizeof (pf1[0][0]), // xStride
sizeof (pf1[0][0]) * width, // yStride
1, // xSampling
1) // ySampling
);
cout << "only short names" << endl;
{
Header hdr (width, height);
hdr.channels().insert ("F", // name
Channel (IMF::FLOAT, // type
1, // xSampling
1) // ySampling
);
cout << "writing" << flush;
remove (fileName);
OutputFile out (fileName, hdr);
out.setFrameBuffer (fb);
out.writePixels (height);
}
{
cout << " reading" << endl;
InputFile in (fileName);
assert (!(in.version() & LONG_NAMES_FLAG));
}
static const char longName[] = "x2345678901234567890123456789012";
cout << "long attribute name" << endl;
{
Header hdr (width, height);
hdr.insert (longName, StringAttribute ("y"));
hdr.channels().insert ("F", // name
Channel (IMF::FLOAT, // type
1, // xSampling
1) // ySampling
);
cout << "writing" << flush;
remove (fileName);
OutputFile out (fileName, hdr);
out.setFrameBuffer (fb);
out.writePixels (height);
}
{
cout << " reading" << endl;
InputFile in (fileName);
assert (in.version() & LONG_NAMES_FLAG);
const Header &hdr = in.header();
assert (hdr.typedAttribute <StringAttribute> (longName).value() == "y");
}
cout << "long channel name" << endl;
{
Header hdr (width, height);
hdr.channels().insert (longName, // name
Channel (IMF::FLOAT, // type
1, // xSampling
1) // ySampling
);
cout << "writing" << flush;
remove (fileName);
OutputFile out (fileName, hdr);
out.setFrameBuffer (fb);
out.writePixels (height);
}
{
cout << " reading" << endl;
InputFile in (fileName);
assert (in.version() & LONG_NAMES_FLAG);
const Header &hdr = in.header();
assert (hdr.channels().findChannel (longName));
}
remove (fileName);
cout << endl;
}
} // namespace
template<class T> void
print_type(const OPENEXR_IMF_NAMESPACE::TypedAttribute<T> & object)
{
cout << object.typeName() << endl;
}
void
testAttributes (const std::string &tempDir)
{
try
{
cout << "Testing built-in attributes" << endl;
const int W = 217;
const int H = 197;
Array2D<float> pf (H, W);
fillPixels (pf, W, H);
std::string filename = tempDir + "imf_test_attr.exr";
writeReadAttr (pf, filename.c_str(), W, H);
channelList();
longNames(pf, filename.c_str(), W, H);
print_type(OPENEXR_IMF_NAMESPACE::TypedAttribute<int>());
cout << "ok\n" << endl;
}
catch (const std::exception &e)
{
cerr << "ERROR -- caught exception: " << e.what() << endl;
assert (false);
}
}