/////////////////////////////////////////////////////////////////////////// // // Copyright (c) 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 "testBackwardCompatibility.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef WIN32 #include #endif // WIN32 #ifndef ILM_IMF_TEST_IMAGEDIR #define ILM_IMF_TEST_IMAGEDIR #endif namespace IMF = OPENEXR_IMF_NAMESPACE; using namespace IMF; using namespace IMATH_NAMESPACE; using namespace ILMTHREAD_NAMESPACE; using namespace std; namespace { // // Make this true if you wish to generate images when building // the v1.7 code base. // const int generateImagesOnly = false; const int W = 217; const int H = 197; void diffImageFiles (const char * fn1, const char * fn2) { ifstream i1 (fn1, ios::binary); ifstream i2 (fn2, ios::binary); if(!i1.good()){THROW (IEX_NAMESPACE::BaseExc, string("cannot open ") + string(fn1));} if(!i2.good()){THROW (IEX_NAMESPACE::BaseExc, string("cannot open ") + string(fn2));} while (!i1.eof() && !i2.eof()) { if (i1.get() != i2.get()) { string e = string ("v1.7 and current differences between '") + string (fn1) + string ("' & '") + string (fn2) + string ("'"); THROW (IEX_NAMESPACE::BaseExc, e); } } } void addPreviewImageToHeader (OPENEXR_IMF_NAMESPACE::Header & hdr) { size_t pW = 32; size_t pH = 32; OPENEXR_IMF_NAMESPACE::Array2D previewPixels (pW, pH); for (size_t h=0; h pf (H, W); pf.resizeErase(H, W); Array2D ph (H, W); ph.resizeErase(H, W); for (int i = 0; i < H; i++) { for (int j = 0; j < W; j++) { pf[i][j] = (float)((i * W + j) / (float(W*H))); ph[i][j] = (half)(pf[i][j]); } } IMATH_NAMESPACE::Box2i dod (IMATH_NAMESPACE::V2f(20), IMATH_NAMESPACE::V2f(W-20, H-23)); OPENEXR_IMF_NAMESPACE::Header header = Header (W, H, dod); header.channels().insert("Z", Channel(IMF::FLOAT)); header.channels().insert("R", Channel(IMF::HALF)); header.channels().insert("G", Channel(IMF::HALF)); header.channels().insert("B", Channel(IMF::HALF)); addUserAttributesToHeader (header); FrameBuffer fb; fb.insert ("Z", Slice (IMF::FLOAT, (char *) &pf[0][0], sizeof (pf[0][0]), sizeof (pf[0][0]) * W)); fb.insert ("R", Slice (IMF::HALF, (char *) &ph[0][0], sizeof (ph[0][0]), sizeof (ph[0][0]) * W)); fb.insert ("G", Slice (IMF::HALF, (char *) &ph[0][0], sizeof (ph[0][0]), sizeof (ph[0][0]) * W)); fb.insert ("B", Slice (IMF::HALF, (char *) &ph[0][0], sizeof (ph[0][0]), sizeof (ph[0][0]) * W)); OutputFile file (fn, header); file.setFrameBuffer (fb); file.writePixels (H-40); } struct RZ { float z; half g; }; void generateScanlineInterleavedImage (const char * fn) { // generate a v 1.7 image and check against ground truth on disk Array2D rz (H, W); rz.resizeErase(H, W); for (int i = 0; i < H; i++) { for (int j = 0; j < W; j++) { rz[i][j].z = (float)((i * W + j) / (float(W*H))); rz[i][j].g = (half)(rz[i][j].z); } } IMATH_NAMESPACE::Box2i dod (IMATH_NAMESPACE::V2f(20), IMATH_NAMESPACE::V2f(W-20, H-23)); OPENEXR_IMF_NAMESPACE::Header header = Header (W, H, dod); header.channels().insert("Z", Channel(IMF::FLOAT)); header.channels().insert("R", Channel(IMF::HALF)); addUserAttributesToHeader (header); FrameBuffer fb; fb.insert ("Z", Slice (IMF::FLOAT, (char *) &(rz[0][0].z), sizeof (rz[0][0]), sizeof (rz[0][0]) * W)); fb.insert ("G", Slice (IMF::HALF, (char *) &(rz[0][0].g), sizeof (rz[0][0]), sizeof (rz[0][0]) * W)); OutputFile file (fn, header); file.setFrameBuffer (fb); file.writePixels (H-40); } void diffScanlineImages (const std::string & planarScanlineName, const std::string & interleavedScanlineName) { // Planar Images generateScanlinePlanarImage (planarScanlineName.c_str()); diffImageFiles (planarScanlineName.c_str(), ILM_IMF_TEST_IMAGEDIR "v1.7.test.planar.exr"); // Interleaved Images generateScanlineInterleavedImage (interleavedScanlineName.c_str()); diffImageFiles (interleavedScanlineName.c_str(), ILM_IMF_TEST_IMAGEDIR "v1.7.test.interleaved.exr"); } void generateTiledImage (const char * fn) { Array2D rz (H, W); rz.resizeErase(H, W); for (int i = 0; i < H; i++) { for (int j = 0; j < W; j++) { rz[i][j].z = (float)((i * W + j) / (float(W*H))); rz[i][j].g = (half)(rz[i][j].z); } } Header header (W, H); header.channels().insert ("G", Channel (IMF::HALF)); header.channels().insert ("Z", Channel (IMF::FLOAT)); int tileW = 12; int tileH = 24; header.setTileDescription (TileDescription (tileW, tileH, ONE_LEVEL)); OPENEXR_IMF_NAMESPACE::TiledOutputFile out (fn, header); OPENEXR_IMF_NAMESPACE::FrameBuffer frameBuffer; // 6 frameBuffer.insert ("G", Slice (IMF::HALF, (char *) &rz[0][0].g, sizeof (rz[0][0]) * 1, sizeof (rz[0][0]) * W)); frameBuffer.insert ("Z", Slice (IMF::FLOAT, (char *) &rz[0][0].z, sizeof (rz[0][0]) * 1, sizeof (rz[0][0]) * W)); out.setFrameBuffer (frameBuffer); out.writeTiles (0, out.numXTiles() - 1, 0, out.numYTiles() - 1); } void diffTiledImages (const std::string & fn) { // Planar Images generateTiledImage (fn.c_str()); diffImageFiles (fn.c_str(), ILM_IMF_TEST_IMAGEDIR "v1.7.test.tiled.exr"); } } // namespace void testBackwardCompatibility (const std::string & tempDir) { try { cout << "Testing backward compatibility" << endl; // Run this code with the 1.7 code base to generate the // images used in the test. if (generateImagesOnly) { generateScanlinePlanarImage ("v1.7.test.planar.exr"); generateScanlineInterleavedImage ("v1.7.test.interleaved.exr"); generateTiledImage ("v1.7.test.tiled.exr"); } else { std::string planarFn = tempDir + "v1.7.test.planar.exr"; std::string interleavedFn = tempDir + "v1.7.test.interleaved.exr"; diffScanlineImages (planarFn, interleavedFn); std::string fn = tempDir + "v1.7.test.tiled.exr"; diffTiledImages (fn); } cout << "ok\n" << endl; } catch (const std::exception &e) { cerr << "ERROR -- caught exception: " << e.what() << endl; assert (false); } }