Disabled external gits

This commit is contained in:
2022-04-07 18:46:57 +02:00
parent 88cb3426ad
commit 15e7120d6d
5316 changed files with 4563444 additions and 6 deletions

View File

@ -0,0 +1,16 @@
Makefile
Makefile.in
config.h.in
config.h
config.log
config.status
configure
libtool
stamp-h
aclocal.m4
OpenEXR.pc
autom4te.cache
ltmain.sh
stamp-h.in
depcomp
.deps

View File

@ -0,0 +1,74 @@
# yue.nicholas@gmail.com
# IlmImfTest
ADD_EXECUTABLE ( IlmImfTest
compareB44.cpp
compareDwa.cpp
compareFloat.cpp
main.cpp
testAttributes.cpp
testBackwardCompatibility.cpp
testBadTypeAttributes.cpp
testChannels.cpp
testCompositeDeepScanLine.cpp
testCompression.cpp
testConversion.cpp
testCopyDeepScanLine.cpp
testCopyDeepTiled.cpp
testCopyMultiPartFile.cpp
testCopyPixels.cpp
testCustomAttributes.cpp
testDeepScanLineBasic.cpp
testDeepScanLineHuge.cpp
testDeepScanLineMultipleRead.cpp
testDeepTiledBasic.cpp
testDwaCompressorSimd.cpp
testExistingStreams.cpp
testFutureProofing.cpp
testHuf.cpp
testInputPart.cpp
testIsComplete.cpp
testLineOrder.cpp
testLut.cpp
testMagic.cpp
testMultiPartApi.cpp
testMultiPartFileMixingBasic.cpp
testMultiPartSharedAttributes.cpp
testMultiPartThreading.cpp
testMultiScanlinePartThreading.cpp
testMultiTiledPartThreading.cpp
testMultiView.cpp
testNativeFormat.cpp
testOptimized.cpp
testOptimizedInterleavePatterns.cpp
testPartHelper.cpp
testPreviewImage.cpp
testRgba.cpp
testRgbaThreading.cpp
testRle.cpp
testSampleImages.cpp
testScanLineApi.cpp
testSharedFrameBuffer.cpp
testStandardAttributes.cpp
testTiledCompression.cpp
testTiledCopyPixels.cpp
testTiledLineOrder.cpp
testTiledRgba.cpp
testTiledYa.cpp
testWav.cpp
testXdr.cpp
testYca.cpp
)
ADD_TEST ( TestIlmImf IlmImfTest )
TARGET_LINK_LIBRARIES ( IlmImfTest
IlmImf
Half
Iex${ILMBASE_LIBSUFFIX}
Imath${ILMBASE_LIBSUFFIX}
IlmThread${ILMBASE_LIBSUFFIX}
${PTHREAD_LIB} ${ZLIB_LIBRARIES}
)

View File

@ -0,0 +1,84 @@
## Process this file with automake to produce Makefile.in
check_PROGRAMS = IlmImfTest
IlmImfTest_SOURCES = main.cpp tmpDir.h testAttributes.cpp testChannels.cpp \
testCompression.cpp testCopyPixels.cpp \
testCustomAttributes.cpp testHuf.cpp testLineOrder.cpp \
testLut.cpp testRgba.cpp testRgbaThreading.cpp \
testSampleImages.cpp testSharedFrameBuffer.cpp \
testWav.cpp testXdr.cpp testAttributes.h testChannels.h \
testCompression.h testCopyPixels.h \
testCustomAttributes.h testHuf.h testLineOrder.h \
testLut.h testRgba.h testRgbaThreading.h \
testSampleImages.h testWav.h testSharedFrameBuffer.h \
testXdr.h testConversion.cpp testConversion.h \
testNativeFormat.cpp testNativeFormat.h \
testPreviewImage.cpp testPreviewImage.h \
testMagic.cpp testMagic.h testStandardAttributes.cpp \
testStandardAttributes.h testExistingStreams.cpp \
testExistingStreams.h testScanLineApi.cpp \
testScanLineApi.h testTiledCompression.cpp \
testTiledCompression.h testTiledCopyPixels.cpp \
testTiledCopyPixels.h testTiledLineOrder.cpp \
testTiledLineOrder.h testTiledRgba.cpp \
testTiledRgba.h compareFloat.h compareFloat.cpp \
testTiledYa.cpp testTiledYa.h \
testYca.cpp testYca.h compareB44.h compareB44.cpp \
testMultiView.cpp testMultiView.h \
testIsComplete.cpp testIsComplete.h \
testMultiPartApi.cpp testMultiPartApi.h \
testMultiPartThreading.cpp testMultiPartThreading.h \
testMultiScanlinePartThreading.cpp testMultiScanlinePartThreading.h \
testMultiTiledPartThreading.cpp testMultiTiledPartThreading.h \
testDeepScanLineBasic.cpp testDeepScanLineBasic.h \
testDeepTiledBasic.cpp testDeepTiledBasic.h \
testMultiPartFileMixingBasic.cpp testMultiPartFileMixingBasic.h \
testMultiPartSharedAttributes.cpp testMultiPartSharedAttributes.h \
testBackwardCompatibility.cpp testBackwardCompatibility.h \
testCopyDeepScanLine.cpp testCopyDeepScanLine.h \
testCopyDeepTiled.cpp testCopyDeepTiled.h \
testCopyMultiPartFile.h testCopyMultiPartFile.cpp \
testCompositeDeepScanLine.h testCompositeDeepScanLine.cpp \
testInputPart.cpp testInputPart.h \
testDeepScanLineMultipleRead.h testDeepScanLineMultipleRead.cpp \
testPartHelper.h testPartHelper.cpp \
testOptimized.cpp testOptimized.h \
testOptimizedInterleavePatterns.cpp testOptimizedInterleavePatterns.h \
testBadTypeAttributes.cpp testBadTypeAttributes.h \
testFutureProofing.cpp testFutureProofing.h \
compareDwa.cpp compareDwa.h \
testDwaCompressorSimd.cpp testDwaCompressorSimd.h \
testRle.cpp testRle.h
AM_CPPFLAGS = -DILM_IMF_TEST_IMAGEDIR=\"$(srcdir)/\"
if BUILD_IMFHUGETEST
IlmImfTest_SOURCES += testDeepScanLineHuge.cpp testDeepScanLineHuge.h
AM_CPPFLAGS += -DENABLE_IMFHUGETEST
endif
INCLUDES = -I$(top_builddir) \
-I$(top_srcdir)/IlmImf \
-I$(top_srcdir)/config \
@ILMBASE_CXXFLAGS@
LDADD = -L$(top_builddir)/IlmImf \
@ILMBASE_LDFLAGS@ @ILMBASE_LIBS@ \
-lIlmImf -lz
TESTS = IlmImfTest
EXTRA_DIST = comp_none.exr comp_piz.exr comp_rle.exr comp_zip.exr \
comp_zips.exr lineOrder_decreasing.exr lineOrder_increasing.exr \
test_native1.exr test_native2.exr invalid.exr \
tiled.exr comp_b44.exr comp_b44_piz.exr \
comp_dwaa_piz.exr comp_dwaa_v1.exr comp_dwaa_v2.exr \
comp_dwab_piz.exr comp_dwab_v1.exr comp_dwab_v2.exr \
v1.7.test.planar.exr v1.7.test.tiled.exr v1.7.test.1.exr v1.7.test.interleaved.exr \
invalid_shared_attrs_multipart.exr \
tiled_with_scanlineimage_type.exr scanline_with_tiledimage_type.exr \
tiled_with_deepscanline_type.exr tiled_with_deeptile_type.exr \
scanline_with_deepscanline_type.exr scanline_with_deeptiled_type.exr \
CMakeLists.txt

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,374 @@
//////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2006, Industrial Light & Magic, a division of Lucasfilm
// Entertainment Company Ltd. Portions contributed and copyright held by
// others as indicated. 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
// any other contributors to this software 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 "compareB44.h"
#include <algorithm>
#include <cassert>
using namespace OPENEXR_IMF_NAMESPACE;
using namespace std;
int
shiftAndRound (int x, int shift)
{
x <<= 1;
int a = (1 << shift) - 1;
shift += 1;
int b = (x >> shift) & 1;
return (x + a + b) >> shift;
}
bool
withinB44ErrorBounds (const half A[4][4], const half B[4][4])
{
//
// Assuming that a 4x4 pixel block, B, was generated by
// compressing and uncompressing another pixel block, A,
// using OpenEXR's B44 compression method, check whether
// the differences between A and B are what we would
// expect from the compressor.
//
//
// The block may not have been compressed at all if it
// was part of a very small tile.
//
bool equal = true;
for (int i = 0; i < 4; ++i)
for (int j = 0; j < 4; ++j)
if (A[i][j] != B[i][j])
equal = false;
if (equal)
return true;
//
// The block was compressed.
//
// Perform a "light" version of the B44 compression on A
// (see the pack() function in ImfB44Compressor.cpp).
//
unsigned short t[16];
for (int i = 0; i < 16; ++i)
{
unsigned short Abits = A[i / 4][i % 4].bits();
if ((Abits & 0x7c00) == 0x7c00)
t[i] = 0x8000;
else if (Abits & 0x8000)
t[i] = ~Abits;
else
t[i] = Abits | 0x8000;
}
unsigned short tMax = 0;
for (int i = 0; i < 16; ++i)
if (tMax < t[i])
tMax = t[i];
int shift = -1;
int d[16];
int r[15];
int rMin;
int rMax;
do
{
shift += 1;
for (int i = 0; i < 16; ++i)
d[i] = shiftAndRound (tMax - t[i], shift);
const int bias = 0x20;
r[ 0] = d[ 0] - d[ 4] + bias;
r[ 1] = d[ 4] - d[ 8] + bias;
r[ 2] = d[ 8] - d[12] + bias;
r[ 3] = d[ 0] - d[ 1] + bias;
r[ 4] = d[ 4] - d[ 5] + bias;
r[ 5] = d[ 8] - d[ 9] + bias;
r[ 6] = d[12] - d[13] + bias;
r[ 7] = d[ 1] - d[ 2] + bias;
r[ 8] = d[ 5] - d[ 6] + bias;
r[ 9] = d[ 9] - d[10] + bias;
r[10] = d[13] - d[14] + bias;
r[11] = d[ 2] - d[ 3] + bias;
r[12] = d[ 6] - d[ 7] + bias;
r[13] = d[10] - d[11] + bias;
r[14] = d[14] - d[15] + bias;
rMin = r[0];
rMax = r[0];
for (int i = 1; i < 15; ++i)
{
if (rMin > r[i])
rMin = r[i];
if (rMax < r[i])
rMax = r[i];
}
}
while (rMin < 0 || rMax > 0x3f);
t[0] = tMax - (d[0] << shift);
//
// Now perform a "light" version of the decompression method.
// (see the unpack() function in ImfB44Compressor.cpp).
//
unsigned short A1[16];
const int bias = 0x20 << shift;
A1[ 0] = t[ 0];
A1[ 4] = A1[ 0] + (r[ 0] << shift) - bias;
A1[ 8] = A1[ 4] + (r[ 1] << shift) - bias;
A1[12] = A1[ 8] + (r[ 2] << shift) - bias;
A1[ 1] = A1[ 0] + (r[ 3] << shift) - bias;
A1[ 5] = A1[ 4] + (r[ 4] << shift) - bias;
A1[ 9] = A1[ 8] + (r[ 5] << shift) - bias;
A1[13] = A1[12] + (r[ 6] << shift) - bias;
A1[ 2] = A1[ 1] + (r[ 7] << shift) - bias;
A1[ 6] = A1[ 5] + (r[ 8] << shift) - bias;
A1[10] = A1[ 9] + (r[ 9] << shift) - bias;
A1[14] = A1[13] + (r[10] << shift) - bias;
A1[ 3] = A1[ 2] + (r[11] << shift) - bias;
A1[ 7] = A1[ 6] + (r[12] << shift) - bias;
A1[11] = A1[10] + (r[13] << shift) - bias;
A1[15] = A1[14] + (r[14] << shift) - bias;
//
// Compare the result with B, allowing for an difference
// of a couple of units in the last place.
//
for (int i = 0; i < 16; ++i)
{
unsigned short A1bits = A1[i];
unsigned short Bbits = B[i / 4][i % 4].bits();
if (Bbits & 0x8000)
Bbits = ~Bbits;
else
Bbits = Bbits | 0x8000;
if (Bbits > A1bits + 5 || Bbits < A1bits - 5)
return false;
}
return true;
}
void
compareB44 (int width,
int height,
const Array2D<half> &p1,
const Array2D<half> &p2)
{
for (int y = 0; y < height; y += 4)
{
for (int x = 0; x < width; x += 4)
{
half A[4][4];
half B[4][4];
for (int y1 = 0; y1 < 4; ++y1)
{
for (int x1 = 0; x1 < 4; ++x1)
{
int y2 = min (y + y1, height - 1);
int x2 = min (x + x1, width - 1);
A[y1][x1] = p1[y2][x2];
B[y1][x1] = p2[y2][x2];
}
}
assert (withinB44ErrorBounds (A, B));
}
}
}
void
compareB44 (int width,
int height,
const Array2D<Rgba> &p1,
const Array2D<Rgba> &p2,
RgbaChannels channels)
{
if (channels & WRITE_R)
{
for (int y = 0; y < height; y += 4)
{
for (int x = 0; x < width; x += 4)
{
half A[4][4];
half B[4][4];
for (int y1 = 0; y1 < 4; ++y1)
{
for (int x1 = 0; x1 < 4; ++x1)
{
int y2 = min (y + y1, height - 1);
int x2 = min (x + x1, width - 1);
A[y1][x1] = p1[y2][x2].r;
B[y1][x1] = p2[y2][x2].r;
}
}
assert (withinB44ErrorBounds (A, B));
}
}
}
else
{
for (int y = 0; y < height; y += 1)
for (int x = 0; x < width; x += 1)
assert (p2[y][x].r == 0);
}
if (channels & WRITE_G)
{
for (int y = 0; y < height; y += 4)
{
for (int x = 0; x < width; x += 4)
{
half A[4][4];
half B[4][4];
for (int y1 = 0; y1 < 4; ++y1)
{
for (int x1 = 0; x1 < 4; ++x1)
{
int y2 = min (y + y1, height - 1);
int x2 = min (x + x1, width - 1);
A[y1][x1] = p1[y2][x2].g;
B[y1][x1] = p2[y2][x2].g;
}
}
assert (withinB44ErrorBounds (A, B));
}
}
}
else
{
for (int y = 0; y < height; y += 1)
for (int x = 0; x < width; x += 1)
assert (p2[y][x].g == 0);
}
if (channels & WRITE_B)
{
for (int y = 0; y < height; y += 4)
{
for (int x = 0; x < width; x += 4)
{
half A[4][4];
half B[4][4];
for (int y1 = 0; y1 < 4; ++y1)
{
for (int x1 = 0; x1 < 4; ++x1)
{
int y2 = min (y + y1, height - 1);
int x2 = min (x + x1, width - 1);
A[y1][x1] = p1[y2][x2].b;
B[y1][x1] = p2[y2][x2].b;
}
}
assert (withinB44ErrorBounds (A, B));
}
}
}
else
{
for (int y = 0; y < height; y += 1)
for (int x = 0; x < width; x += 1)
assert (p2[y][x].b == 0);
}
if (channels & WRITE_A)
{
for (int y = 0; y < height; y += 4)
{
for (int x = 0; x < width; x += 4)
{
half A[4][4];
half B[4][4];
for (int y1 = 0; y1 < 4; ++y1)
{
for (int x1 = 0; x1 < 4; ++x1)
{
int y2 = min (y + y1, height - 1);
int x2 = min (x + x1, width - 1);
A[y1][x1] = p1[y2][x2].a;
B[y1][x1] = p2[y2][x2].a;
}
}
assert (withinB44ErrorBounds (A, B));
}
}
}
else
{
for (int y = 0; y < height; y += 1)
for (int x = 0; x < width; x += 1)
assert (p2[y][x].a == 1);
}
}

View File

@ -0,0 +1,54 @@
//////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2006, Industrial Light & Magic, a division of Lucasfilm
// Entertainment Company Ltd. Portions contributed and copyright held by
// others as indicated. 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
// any other contributors to this software 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 "ImfNamespace.h"
#include <ImfRgba.h>
#include <ImfArray.h>
bool withinB44ErrorBounds (const half A[4][4], const half B[4][4]);
void compareB44 (int width,
int height,
const OPENEXR_IMF_NAMESPACE::Array2D<half> &p1,
const OPENEXR_IMF_NAMESPACE::Array2D<half> &p2);
void compareB44 (int width,
int height,
const OPENEXR_IMF_NAMESPACE::Array2D<OPENEXR_IMF_NAMESPACE::Rgba> &p1,
const OPENEXR_IMF_NAMESPACE::Array2D<OPENEXR_IMF_NAMESPACE::Rgba> &p2,
OPENEXR_IMF_NAMESPACE::RgbaChannels channels);

View File

@ -0,0 +1,144 @@
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2009-2014 DreamWorks Animation 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 DreamWorks Animation 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 <math.h>
#include <assert.h>
#include "half.h"
#include "compareDwa.h"
using namespace OPENEXR_IMF_NAMESPACE;
using namespace std;
//
// Convert from linear to a nonlinear representation,
//
half
toNonlinear(half linear)
{
float sign = 1;
float logBase = pow(2.7182818, 2.2);
if ((float)linear < 0) {
sign = -1;
}
if ((linear.bits() & 0x7c00) == 0x7c00) {
return (half)0.0;
}
if ( fabs( (float)linear ) <= 1.0f) {
return (half)(sign * pow(fabs((float)linear), 1.f/2.2f));
} else {
return (half)(sign * ( log(fabs((float)linear)) / log(logBase) + 1.0f) );
}
return (half)0.0f;
}
void
compareDwa(int width,
int height,
const Array2D<Rgba> &src,
const Array2D<Rgba> &test,
RgbaChannels channels)
{
half srcNonlin, testNonlin;
float relError;
for (int y=0; y<height; ++y) {
for (int x=0; x<width; ++x) {
for (int comp=0; comp<3; ++comp) {
switch (comp) {
case 0:
if (!(channels & WRITE_R)) continue;
srcNonlin = toNonlinear(src[y][x].r);
testNonlin = toNonlinear(test[y][x].r);
break;
case 1:
if (!(channels & WRITE_G)) continue;
srcNonlin = toNonlinear(src[y][x].g);
testNonlin = toNonlinear(test[y][x].g);
break;
case 2:
if (!(channels & WRITE_B)) continue;
srcNonlin = toNonlinear(src[y][x].b);
testNonlin = toNonlinear(test[y][x].b);
break;
}
//
// Try to compare with relative error. This breaks down
// for small numbers, which could be quantiezed to 0
// giving 100% error.
//
if (srcNonlin.bits() != 0x00) {
relError = fabs( (float)srcNonlin - (float)testNonlin ) /
fabs((float)srcNonlin);
if (fabs(srcNonlin) < .1) continue;
if (fabs(srcNonlin) < .25) {
assert( relError < .25);
} else {
assert( relError < .1);
}
} else {
assert( srcNonlin != testNonlin );
}
}
}
}
//
// Test alpha, if necessary
//
if (channels & WRITE_A) {
for (int y=0; y<height; ++y) {
for (int x=0; x<width; ++x) {
assert( src[y][x].a == test[y][x].a );
}
}
}
}

View File

@ -0,0 +1,47 @@
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2009-2014 DreamWorks Animation 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 DreamWorks Animation 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.
//
///////////////////////////////////////////////////////////////////////////
#ifndef COMPARE_DWA_H_INCLUDED
#define COMPARE_DWA_H_INCLUDED
#include "ImfRgba.h"
#include "ImfArray.h"
#include "ImfNamespace.h"
void compareDwa(int width,
int height,
const OPENEXR_IMF_NAMESPACE::Array2D<Imf::Rgba> &src,
const OPENEXR_IMF_NAMESPACE::Array2D<Imf::Rgba> &test,
OPENEXR_IMF_NAMESPACE::RgbaChannels channels);
#endif

View File

@ -0,0 +1,68 @@
//////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2004, Industrial Light & Magic, a division of Lucasfilm
// Entertainment Company Ltd. Portions contributed and copyright held by
// others as indicated. 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
// any other contributors to this software 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 "compareFloat.h"
using namespace OPENEXR_IMF_NAMESPACE;
bool
equivalent (float f1, float f2, Compression comp)
{
//
// Test if a float, f1, is "equivalent" to another float, f2,
// which results from storing f1 in an image file, and reading
// it back:
// If the file was compressed with PXR24_COMPRESSION, then f1
// and f2 must the same as f1 rounded to 24 bits (see class
// ImfPxr24Compressor); otherwise f1 and f2 must be the same.
//
union
{
float f;
unsigned int i;
} u1, u2;
u1.f = f1;
u2.f = f2;
if (comp == PXR24_COMPRESSION)
return (u2.i >> 8) - (u1.i >> 8) < 2;
else
return u2.i == u1.i;
}

View File

@ -0,0 +1,42 @@
//////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2004, Industrial Light & Magic, a division of Lucasfilm
// Entertainment Company Ltd. Portions contributed and copyright held by
// others as indicated. 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
// any other contributors to this software 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 "ImfNamespace.h"
#include "ImfCompression.h"
bool equivalent (float f1, float f2, OPENEXR_IMF_NAMESPACE::Compression comp);

View File

@ -0,0 +1,2 @@
this is not a valid EXR file

View File

@ -0,0 +1,236 @@
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2004-2013, 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 "ImfNamespace.h"
#include "testXdr.h"
#include "testMagic.h"
#include "testHuf.h"
#include "testWav.h"
#include "testChannels.h"
#include "testAttributes.h"
#include "testCustomAttributes.h"
#include "testLineOrder.h"
#include "testCompression.h"
#include "testCopyPixels.h"
#include "testRgba.h"
#include "testRgbaThreading.h"
#include "testLut.h"
#include "testSampleImages.h"
#include "testPreviewImage.h"
#include "testConversion.h"
#include "testStandardAttributes.h"
#include "testNativeFormat.h"
#include "testTiledRgba.h"
#include "testTiledCompression.h"
#include "testTiledCopyPixels.h"
#include "testTiledLineOrder.h"
#include "testScanLineApi.h"
#include "testExistingStreams.h"
#include "testYca.h"
#include "testTiledYa.h"
#include "testIsComplete.h"
#include "testSharedFrameBuffer.h"
#include "testMultiView.h"
#include "testMultiPartApi.h"
#include "testMultiPartSharedAttributes.h"
#include "testMultiPartThreading.h"
#include "testMultiScanlinePartThreading.h"
#include "testMultiTiledPartThreading.h"
#include "testDeepScanLineBasic.h"
#include "testCopyDeepScanLine.h"
#include "testDeepScanLineMultipleRead.h"
#include "testDeepScanLineHuge.h"
#include "testDeepTiledBasic.h"
#include "testCopyDeepTiled.h"
#include "testCompositeDeepScanLine.h"
#include "testMultiPartFileMixingBasic.h"
#include "testInputPart.h"
#include "testBackwardCompatibility.h"
#include "testCopyMultiPartFile.h"
#include "testPartHelper.h"
#include "testOptimized.h"
#include "testOptimizedInterleavePatterns.h"
#include "testBadTypeAttributes.h"
#include "testFutureProofing.h"
#include "testPartHelper.h"
#include "testDwaCompressorSimd.h"
#include "testRle.h"
#include "tmpDir.h"
#include "ImathRandom.h"
// system includes
#include <errno.h>
#include <stdlib.h>
#include <iostream>
#include <string.h>
#include <time.h>
#if defined(OPENEXR_IMF_HAVE_LINUX_PROCFS) || defined(OPENEXR_IMF_HAVE_DARWIN)
#include <unistd.h>
#include <sstream>
#endif
using namespace std;
#define TEST(x,y) \
if (argc < 2 || (!strcmp (argv[1], #x) || !strcmp (argv[1], y))) \
{ \
cout << "\n=======\nRunning " << #x <<endl; \
x(tempDir); \
}
int
main (int argc, char *argv[])
{
// Create temporary files in a uniquely named private temporary
// subdirectory of IMF_TMP_DIR to avoid colliding with other
// running instances of this program.
IMATH_NAMESPACE::Rand48 rand48 (time ((time_t*)0) );
std::string tempDir;
while (true)
{
tempDir = IMF_TMP_DIR "IlmImfTest_";
for (int i = 0; i < 8; ++i)
tempDir += ('A' + rand48.nexti() % 26);
std::cout << "tempDir = " << tempDir << std::endl;
int status = mkdir(tempDir.c_str(), 0777);
if (status == 0)
{
tempDir += IMF_PATH_SEPARATOR;
break; // success
}
if (errno != EEXIST)
{
std::cerr << "ERROR -- mkdir(" << tempDir << ") failed: "
"errno = " << errno << std::endl;
return 1;
}
}
TEST (testMagic, "core");
TEST (testXdr, "core");
TEST (testHuf, "core");
TEST (testWav, "core");
TEST (testRgba, "basic");
TEST (testSharedFrameBuffer, "basic");
TEST (testRgbaThreading, "basic");
TEST (testChannels, "basic");
TEST (testAttributes, "core");
TEST (testCustomAttributes, "core");
TEST (testLineOrder, "basic");
TEST (testCompression, "basic");
TEST (testCopyPixels, "basic");
TEST (testLut, "basic");
TEST (testSampleImages, "basic");
TEST (testPreviewImage, "basic");
TEST (testConversion, "basic");
TEST (testTiledRgba, "basic");
TEST (testTiledCopyPixels, "basic");
TEST (testTiledCompression, "basic");
TEST (testTiledLineOrder, "basic");
TEST (testScanLineApi, "basic");
TEST (testExistingStreams, "core");
TEST (testStandardAttributes, "core");
TEST (testOptimized, "basic");
TEST (testOptimizedInterleavePatterns, "basic");
TEST (testYca, "basic");
TEST (testTiledYa, "basic");
TEST (testNativeFormat, "basic");
TEST (testMultiView, "basic");
TEST (testIsComplete, "basic");
TEST (testDeepScanLineBasic, "deep");
TEST (testCopyDeepScanLine, "deep");
TEST (testDeepScanLineMultipleRead, "deep");
TEST (testDeepTiledBasic, "deep");
TEST (testCopyDeepTiled, "deep");
TEST (testCompositeDeepScanLine, "deep");
TEST (testMultiPartFileMixingBasic, "multi");
TEST (testInputPart, "multi");
TEST (testPartHelper, "multi");
TEST (testBadTypeAttributes, "multi");
TEST (testMultiScanlinePartThreading, "multi");
TEST (testMultiTiledPartThreading, "multi");
TEST (testMultiPartThreading, "multi");
TEST (testMultiPartApi, "multi");
TEST (testMultiPartSharedAttributes, "multi");
TEST (testCopyMultiPartFile, "multi");
TEST (testBackwardCompatibility, "core");
TEST (testFutureProofing, "core");
TEST (testDwaCompressorSimd, "basic");
TEST (testRle, "core");
//#ifdef ENABLE_IMFHUGETEST
// defined via configure with --enable-imfhugetest=yes/no
#if 0
TEST (testDeepScanLineHuge, "deep");
#endif
std::cout << "removing temp dir " << tempDir << std::endl;
rmdir (tempDir.c_str());
#ifdef OPENEXR_IMF_HAVE_LINUX_PROCFS
//
// Allow the user to check for file descriptor leaks
//
std::cout << "open file descriptors:" << std::endl;
std::stringstream ss;
ss << "ls -lG /proc/" << getpid() << "/fd";
if (system (ss.str().c_str()) == -1)
{
std::cout << "failed to run ls\n";
}
std::cout << std::endl;
#endif
return 0;
}

View File

@ -0,0 +1,537 @@
///////////////////////////////////////////////////////////////////////////
//
// 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);
}
}

View File

@ -0,0 +1,41 @@
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2002-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 <string>
void testAttributes (const std::string &tempDir);

View File

@ -0,0 +1,393 @@
///////////////////////////////////////////////////////////////////////////
//
// 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 <ImfArray.h>
#include <ImfHeader.h>
#include <IlmThreadPool.h>
#include <ImfFrameBuffer.h>
#include <ImfOutputFile.h>
#include <ImfPreviewImage.h>
#include <ImfTiledOutputFile.h>
#include <stdlib.h>
#include <stdio.h>
#include <tmpDir.h>
#include <ImathBox.h>
#include <ImfChannelList.h>
#include <IexMacros.h>
#include <ImfBoxAttribute.h>
#include <ImfChannelListAttribute.h>
#include <ImfCompressionAttribute.h>
#include <ImfChromaticitiesAttribute.h>
#include <ImfFloatAttribute.h>
#include <ImfEnvmapAttribute.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 <half.h>
#include <iostream>
#include <fstream>
#include <string>
#include <assert.h>
#include <time.h>
#ifndef WIN32
#include <sys/times.h>
#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 <OPENEXR_IMF_NAMESPACE::PreviewRgba> previewPixels (pW, pH);
for (size_t h=0; h<pH; h++)
{
for (size_t w=0; w<pW; w++)
{
previewPixels[w][h] = (w*h) % 255;
}
}
hdr.setPreviewImage (OPENEXR_IMF_NAMESPACE::PreviewImage (pW, pH, &previewPixels[0][0]));
}
void
addUserAttributesToHeader (OPENEXR_IMF_NAMESPACE::Header & hdr)
{
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);
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));
}
void
generateScanlinePlanarImage (const char * fn)
{
// generate a v 1.7 image and check against ground truth on disk
Array2D<float> pf (H, W); pf.resizeErase(H, W);
Array2D<half> 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> 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> 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);
}
}

View File

@ -0,0 +1,43 @@
///////////////////////////////////////////////////////////////////////////
//
// 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.
//
///////////////////////////////////////////////////////////////////////////
#ifndef TESTBACKWARDCOMPATIBILITY_H_
#define TESTBACKWARDCOMPATIBILITY_H_
#include <string>
void testBackwardCompatibility (const std::string & tempDir);
#endif /* TESTBACKWARDCOMPATIBILITY_H_ */

View File

@ -0,0 +1,373 @@
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2013, Weta Digital Ltd
//
// 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 "ImfInputFile.h"
#include "ImfInputPart.h"
#include "ImfTiledInputFile.h"
#include "ImfTiledInputPart.h"
#include "ImfDeepScanLineInputFile.h"
#include "ImfDeepScanLineInputPart.h"
#include "ImfDeepTiledInputFile.h"
#include "ImfDeepTiledInputPart.h"
#include "ImfChannelList.h"
#include "ImfMultiPartInputFile.h"
#include "ImfPartType.h"
#include <half.h>
#include <vector>
#include <assert.h>
#include "tmpDir.h"
namespace IMF = OPENEXR_IMF_NAMESPACE;
using namespace IMF;
using namespace std;
using namespace IMATH_NAMESPACE;
#ifndef ILM_IMF_TEST_IMAGEDIR
#define ILM_IMF_TEST_IMAGEDIR
#endif
namespace
{
void doFrameBuffer(vector<half>& storage, const Header & hdr,FrameBuffer& dummy)
{
int chans=0;
for( ChannelList::ConstIterator q =hdr.channels().begin() ; q!=hdr.channels().end() ; q++)
{
chans++;
}
Box2i dw= hdr.dataWindow();
storage.resize( (dw.size().x+1)*(dw.size().y+1)*chans);
int xstride = chans*sizeof(half);
int ystride = xstride*(dw.size().x+1);
int offset = ystride*dw.min.y + dw.min.x*xstride;
int chan=0;
for( ChannelList::ConstIterator q = hdr.channels().begin() ; q!=hdr.channels().end() ; q++)
{
dummy.insert(q.name(),Slice(HALF,((char*) &storage[chan])-offset,xstride,ystride));
chan++;
}
}
template<class T> void readTiledThing(T & input,bool test)
{
vector<half> value;
FrameBuffer dummy;
doFrameBuffer(value,input.header(),dummy);
input.setFrameBuffer(dummy);
int x_levels;
int y_levels;
if(test && input.header().hasType())
{
if(input.header().type()!=TILEDIMAGE)
{
std::cerr << "tiled image/part didn't have tiledimage type\n";
//assert(input.type()==TILEDIMAGE);
}
}
TileDescription t = input.header().tileDescription();
switch(t.mode)
{
case ONE_LEVEL :
x_levels = 1;
y_levels = 1;
break;
case MIPMAP_LEVELS :
x_levels = input.numXLevels();
y_levels = 1;
break;
case RIPMAP_LEVELS :
x_levels = input.numXLevels();
y_levels = input.numYLevels();
}
for(int x_level = 0 ; x_level < x_levels ; x_level++)
{
for(int y_level = 0 ; y_level < y_levels ;y_level++)
{
// unless we are RIPMapped, the y_level=x_level, not 0
int actual_y_level = t.mode==RIPMAP_LEVELS ? y_level : x_level;
input.readTiles(0,input.numXTiles(x_level)-1,0,input.numYTiles(actual_y_level)-1,x_level,actual_y_level);
}
}
}
template<class T> void readScanlineThing(T& input,bool test)
{
if(test && input.header().hasType())
{
if(input.header().type()!=SCANLINEIMAGE)
{
std::cerr << "tiled image/part didn't have tiledimage type\n";
//assert(input.type()==TILEDIMAGE);
}
}
vector<half> value;
FrameBuffer dummy;
doFrameBuffer(value,input.header(),dummy);
input.setFrameBuffer(dummy);
input.readPixels(input.header().dataWindow().min.x,input.header().dataWindow().max.x);
}
void checkDeepTypesFailToLoad(const char * file)
{
// trying to open it as a deep tiled file should fail
try{
DeepTiledInputFile f(file);
assert(false);
}catch(...)
{
}
// trying to open it as a deep tiled part of a multipart file should fail
try{
MultiPartInputFile multiin(file);
DeepTiledInputPart p(multiin,0);
assert(false);
}catch(...)
{
}
// trying to open it as a deep scanline file should fail
try{
DeepScanLineInputFile f(file);
assert(false);
}catch(...)
{
}
// trying to open it as a deep scanline part of a multipart file should fail
try{
MultiPartInputFile multiin(file);
DeepScanLineInputPart p(multiin,0);
assert(false);
}catch(...)
{
}
}
void testTiledWithBadAttribute(const char* file)
{
// it's a tiled file, so it should read as a file
TiledInputFile in(file);
readTiledThing(in,false);
{
// it should also read using the multipart API (and have its attribute fixed)
MultiPartInputFile multiin(file);
TiledInputPart tip(multiin,0);
readTiledThing(tip,true);
// it should also read using the regular file API as a scanline file
InputFile sin(file);
readScanlineThing(sin,false);
}
{
// it should also read using the multipart API as a scanline file
MultiPartInputFile multiin(file);
InputPart ip(multiin,0);
readScanlineThing(ip,false);
}
checkDeepTypesFailToLoad(file);
}
void testScanLineWithBadAttribute(const char * file)
{
InputFile in(file);
readScanlineThing(in,false);
MultiPartInputFile multiin(file);
InputPart ip(multiin,0);
readScanlineThing(ip,false);
checkDeepTypesFailToLoad(file);
// trying to open it as a tiled file should also fail
try{
TiledInputFile f(file);
assert(false);
}catch(...)
{
}
// trying to open it as a tiled part of a multipart file should fail
try{
MultiPartInputFile multiin(file);
TiledInputPart p(multiin,0);
assert(false);
}catch(...)
{
}
}
const std::string & NOTYPEATTR="";
template<class IN,class OUT> void check(const char* filename,const string& inputtype,const string &outputtype,bool add_tiledesc)
{
Header f;
if(inputtype!=NOTYPEATTR)
{
f.setType(inputtype);
}
f.compression()=ZIPS_COMPRESSION;
if(add_tiledesc)
{
f.setTileDescription(TileDescription());
}
remove(filename);
{
OUT file(filename,f);
}
{
IMF::MultiPartInputFile file(filename);
if(outputtype!=NOTYPEATTR && file.header(0).type()!=outputtype)
{
cerr << "Error: expected type in header to be " << outputtype << " but got " << file.header(0).type() << " from multipart when input type was " << (inputtype==NOTYPEATTR ? "unset" : inputtype )<< std::endl;
}
assert(outputtype==NOTYPEATTR || file.header(0).type()==outputtype);
}
{
IN file(filename);
if(outputtype==NOTYPEATTR)
{
if(file.header().hasType())
{
cerr << " type attribute got inserted when it shouldn't have been\n";
}
assert( !file.header().hasType() );
}else if(file.header().type()!=outputtype)
{
cerr << "Error: expected type in header to be " << outputtype << " but got " << file.header().type() << " when input type was " << (inputtype==NOTYPEATTR ? "unset" : inputtype )<< std::endl;
}
}
remove(filename);
}
void testWriteBadTypes()
{
static const char* tmpfile = IMF_TMP_DIR "badfile.exr";
// attributes should be added automatically for deep files
check<DeepScanLineInputFile,DeepScanLineOutputFile>(tmpfile,NOTYPEATTR,DEEPSCANLINE,false);
check<DeepTiledInputFile,DeepTiledOutputFile>(tmpfile,NOTYPEATTR,DEEPTILE,true);
// attributes should NOT be added automatically for normal images
check<InputFile,OutputFile>(tmpfile,NOTYPEATTR,NOTYPEATTR,false);
check<InputFile,TiledOutputFile>(tmpfile,NOTYPEATTR,NOTYPEATTR,true);
check<TiledInputFile,TiledOutputFile>(tmpfile,NOTYPEATTR,NOTYPEATTR,true);
// if an attribute is provided, it should get changed to the correct one
check<InputFile,OutputFile>(tmpfile,SCANLINEIMAGE,SCANLINEIMAGE,false);
check<InputFile,TiledOutputFile>(tmpfile,SCANLINEIMAGE,TILEDIMAGE,true);
check<TiledInputFile,TiledOutputFile>(tmpfile,SCANLINEIMAGE,TILEDIMAGE,true);
check<DeepScanLineInputFile,DeepScanLineOutputFile>(tmpfile,SCANLINEIMAGE,DEEPSCANLINE,false);
check<DeepTiledInputFile,DeepTiledOutputFile>(tmpfile,SCANLINEIMAGE,DEEPTILE,true);
check<InputFile,OutputFile>(tmpfile,TILEDIMAGE,SCANLINEIMAGE,false);
check<InputFile,TiledOutputFile>(tmpfile,TILEDIMAGE,TILEDIMAGE,true);
check<TiledInputFile,TiledOutputFile>(tmpfile,TILEDIMAGE,TILEDIMAGE,true);
check<DeepScanLineInputFile, DeepScanLineOutputFile>(tmpfile,TILEDIMAGE,DEEPSCANLINE,false);
check<DeepTiledInputFile,DeepTiledOutputFile>(tmpfile,TILEDIMAGE,DEEPTILE,true);
check<InputFile,OutputFile>(tmpfile,DEEPSCANLINE,SCANLINEIMAGE,false);
check<InputFile,TiledOutputFile>(tmpfile,DEEPSCANLINE,TILEDIMAGE,true);
check<TiledInputFile,TiledOutputFile>(tmpfile,DEEPSCANLINE,TILEDIMAGE,true);
check<DeepScanLineInputFile, DeepScanLineOutputFile>(tmpfile,DEEPSCANLINE,DEEPSCANLINE,false);
check<DeepTiledInputFile,DeepTiledOutputFile>(tmpfile,DEEPSCANLINE,DEEPTILE,true);
check<InputFile,OutputFile>(tmpfile,DEEPTILE,SCANLINEIMAGE,false);
check<InputFile,TiledOutputFile>(tmpfile,DEEPTILE,TILEDIMAGE,true);
check<TiledInputFile,TiledOutputFile>(tmpfile,DEEPTILE,TILEDIMAGE,true);
check<DeepScanLineInputFile,DeepScanLineOutputFile>(tmpfile,DEEPTILE,DEEPSCANLINE,false);
check<DeepTiledInputFile,DeepTiledOutputFile>(tmpfile,DEEPTILE,DEEPTILE,true);
}
}
void testBadTypeAttributes(const std::string & tempDir)
{
cout << "Testing whether bad type attributes are fixed on read... " << endl;
testTiledWithBadAttribute (ILM_IMF_TEST_IMAGEDIR "tiled_with_scanlineimage_type.exr");
testTiledWithBadAttribute (ILM_IMF_TEST_IMAGEDIR "tiled_with_deepscanline_type.exr");
testTiledWithBadAttribute (ILM_IMF_TEST_IMAGEDIR "tiled_with_deeptile_type.exr");
testScanLineWithBadAttribute (ILM_IMF_TEST_IMAGEDIR "scanline_with_tiledimage_type.exr");
testScanLineWithBadAttribute (ILM_IMF_TEST_IMAGEDIR "scanline_with_deeptiled_type.exr");
testScanLineWithBadAttribute (ILM_IMF_TEST_IMAGEDIR "scanline_with_deepscanline_type.exr");
cout << "Testing whether bad type attributes are fixed on write... " << endl;
testWriteBadTypes();
cout << "ok\n" << endl;
}

View File

@ -0,0 +1,41 @@
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2013, Weta Digital Ltd
//
// 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.
//
///////////////////////////////////////////////////////////////////////////
#ifndef TEST_BAD_TYPE_ATTRIBUTES
#define TEST_BAD_TYPE_ATTRIBUTES
#include <string>
void testBadTypeAttributes (const std::string & tempDir);
#endif

View File

@ -0,0 +1,260 @@
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2002-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 <ImfOutputFile.h>
#include <ImfInputFile.h>
#include <ImfChannelList.h>
#include <ImfArray.h>
#include "half.h"
#include <stdio.h>
#include <assert.h>
using namespace OPENEXR_IMF_NAMESPACE;
using namespace std;
using namespace IMATH_NAMESPACE;
namespace {
void
fillPixels (Array2D<half> &ph1,
Array2D<half> &ph2,
int width, int height)
{
for (int y = 0; y < height; ++y)
{
for (int x = 0; x < width; ++x)
{
ph1[y][x] = x % 10 + 10 * (y % 17);
ph2[y][x] = x % 11 + 11 * (y % 15);
}
}
}
void
writeRead (const Array2D<half> &h1out,
const Array2D<half> &h2out,
const char fileName[],
int width,
int height)
{
//
// Write an image file with three channels, H1, H2 and H3.
// Our frame buffer contains pixel data only for H1 and H2;
// the file's H3 channel should be filled with zeroes.
//
Header hdr (width, height);
hdr.channels().insert ("H1", // name
Channel (HALF, // type
1, // xSampling
1) // ySampling
);
hdr.channels().insert ("H2", // name
Channel (HALF, // type
1, // xSampling
1) // ySampling
);
hdr.channels().insert ("H3", // name
Channel (HALF, // type
1, // xSampling
1) // ySampling
);
{
FrameBuffer fb;
fb.insert ("H1", // name
Slice (HALF, // type
(char *) &h1out[0][0], // base
sizeof (h1out[0][0]), // xStride
sizeof (h1out[0][0]) * width, // yStride
1, // xSampling
1) // ySampling
);
fb.insert ("H2", // name
Slice (HALF, // type
(char *) &h2out[0][0], // base
sizeof (h2out[0][0]), // xStride
sizeof (h2out[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 image back from the file. Our frame buffer now
// contains space for the three channels, H1, H3 and H4.
// H1 and H3 should be read back from the file (but H3
// should contain only zeroes), and H4 should be filled
// with a default value, 3.0, because the file contains
// no data for it. The file's H2 channel should be ignored.
//
{
cout << " reading" << flush;
InputFile in (fileName);
const Box2i &dw = in.header().dataWindow();
int w = dw.max.x - dw.min.x + 1;
int h = dw.max.y - dw.min.y + 1;
int dx = dw.min.x;
int dy = dw.min.y;
Array2D<half> h1in (h, w);
Array2D<half> h3in (h, w);
Array2D<half> h4in (h, w);
FrameBuffer fb;
fb.insert ("H1", // name
Slice (HALF, // type
(char *) &h1in[-dy][-dx], // base
sizeof (h1in[0][0]), // xStride
sizeof (h1in[0][0]) * w, // yStride
1, // xSampling
1, // ySampling
3.0) // fillValue
);
fb.insert ("H3", // name
Slice (HALF, // type
(char *) &h3in[-dy][-dx], // base
sizeof (h3in[0][0]), // xStride
sizeof (h3in[0][0]) * w, // yStride
1, // xSampling
1, // ySampling
3.0) // fillValue
);
fb.insert ("H4", // name
Slice (HALF, // type
(char *) &h4in[-dy][-dx], // base
sizeof (h4in[0][0]), // xStride
sizeof (h4in[0][0]) * w, // yStride
1, // xSampling
1, // ySampling
3.0) // fillValue
);
in.setFrameBuffer (fb);
in.readPixels (dw.min.y, dw.max.y);
cout << " comparing" << flush;
assert (in.header().displayWindow() == hdr.displayWindow());
assert (in.header().dataWindow() == hdr.dataWindow());
assert (in.header().pixelAspectRatio() == hdr.pixelAspectRatio());
assert (in.header().screenWindowCenter() == hdr.screenWindowCenter());
assert (in.header().screenWindowWidth() == hdr.screenWindowWidth());
assert (in.header().lineOrder() == hdr.lineOrder());
assert (in.header().compression() == hdr.compression());
ChannelList::ConstIterator hi = hdr.channels().begin();
ChannelList::ConstIterator ii = in.header().channels().begin();
while (hi != hdr.channels().end())
{
assert (!strcmp (hi.name(), ii.name()));
assert (hi.channel().type == ii.channel().type);
assert (hi.channel().xSampling == ii.channel().xSampling);
assert (hi.channel().ySampling == ii.channel().ySampling);
++hi;
++ii;
}
assert (ii == in.header().channels().end());
for (int y = 0; y < h; ++y)
{
for (int x = 0; x < w; ++x)
{
assert (h1in[y][x] == h1out[y][x]);
assert (h3in[y][x] == 0.0);
assert (h4in[y][x] == 3.0);
}
}
}
remove (fileName);
cout << endl;
}
} // namespace
void
testChannels (const std::string &tempDir)
{
try
{
cout << "Testing filling of missing channels" << endl;
const int W = 117;
const int H = 97;
Array2D<half> ph1 (H, W);
Array2D<half> ph2 (H, W);
fillPixels (ph1, ph2, W, H);
std::string filename = tempDir + "imf_test_channels.exr";
writeRead (ph1, ph2, filename.c_str(), W, H);
cout << "ok\n" << endl;
}
catch (const std::exception &e)
{
cerr << "ERROR -- caught exception: " << e.what() << endl;
assert (false);
}
}

View File

@ -0,0 +1,41 @@
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2002-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 <string>
void testChannels (const std::string &tempDir);

View File

@ -0,0 +1,719 @@
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2012, Weta Digital Ltd
//
// 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 Weta Digital 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 "testCompositeDeepScanLine.h"
#include <vector>
#include <string>
#include <Iex.h>
#include <ostream>
#include <iostream>
#include <typeinfo>
#include <stdlib.h>
#include <assert.h>
#include <sstream>
#include <ImfMultiPartOutputFile.h>
#include <ImfMultiPartInputFile.h>
#include <ImfDeepScanLineOutputPart.h>
#include <ImfDeepScanLineInputPart.h>
#include <ImfChannelList.h>
#include <ImfHeader.h>
#include <ImfDeepFrameBuffer.h>
#include <ImfFrameBuffer.h>
#include <ImfPartType.h>
#include <ImfCompression.h>
#include <ImfInputFile.h>
#include <ImfCompositeDeepScanLine.h>
#include <ImfThreading.h>
#include <IlmThread.h>
#include <ImfNamespace.h>
namespace
{
using std::vector;
using std::string;
using std::ostream;
using std::endl;
using std::cout;
using std::ostringstream;
using OPENEXR_IMF_NAMESPACE::DeepScanLineOutputFile;
using OPENEXR_IMF_NAMESPACE::MultiPartInputFile;
using OPENEXR_IMF_NAMESPACE::DeepScanLineOutputPart;
using OPENEXR_IMF_NAMESPACE::DeepScanLineInputPart;
using OPENEXR_IMF_NAMESPACE::Header;
using OPENEXR_IMF_NAMESPACE::PixelType;
using OPENEXR_IMF_NAMESPACE::DeepFrameBuffer;
using OPENEXR_IMF_NAMESPACE::FrameBuffer;
using OPENEXR_IMF_NAMESPACE::FLOAT;
using OPENEXR_IMF_NAMESPACE::HALF;
using OPENEXR_IMF_NAMESPACE::UINT;
using OPENEXR_IMF_NAMESPACE::Slice;
using OPENEXR_IMF_NAMESPACE::DeepSlice;
using OPENEXR_IMF_NAMESPACE::MultiPartOutputFile;
using IMATH_NAMESPACE::Box2i;
using OPENEXR_IMF_NAMESPACE::DEEPSCANLINE;
using OPENEXR_IMF_NAMESPACE::ZIPS_COMPRESSION;
using OPENEXR_IMF_NAMESPACE::InputFile;
using OPENEXR_IMF_NAMESPACE::setGlobalThreadCount;
using OPENEXR_IMF_NAMESPACE::CompositeDeepScanLine;
// a marker to say we've done inserting values into a sample: do mydata << end()
struct end{};
// a marker to say we're about to send the final result, not another sample: do mydata << result()
struct result{};
//
// support class that generates deep data, along with the 'ground truth'
// result
//
template<class T>
class data
{
public:
vector<string> _channels; // channel names - same size and order as in all other arrays,
vector<T> _current_result; // one value per channel: the ground truth value for the given pixel
vector<vector <T> >_results; // a list of result pixels
bool _inserting_result;
bool _started; // we've started to assemble the values - no more channels permitted
vector<T> _current_sample; // one value per channel for the sample currently being inserted
vector< vector <T> > _current_pixel; // a list of results for the current pixwel
vector< vector< vector<T> > > _samples; // a list of pixels
PixelType _type;
data() : _inserting_result(false),_started(false)
{
if(typeid(T)==typeid(half))
{
_type = OPENEXR_IMF_NAMESPACE::HALF;
}
else
{
_type = OPENEXR_IMF_NAMESPACE::FLOAT;
}
}
// add a value to the current sample
data & operator << (float value)
{
if(_inserting_result)
{
_current_result.push_back(value);
}else{
_current_sample.push_back(T(value));
}
_started=true;
return *this;
}
// switch between writing samples and the result
data & operator << (const result &)
{
if(_current_sample.size()!=0)
{
throw IEX_NAMESPACE::ArgExc("bug in test code: can't switch to inserting result: values written without 'end' statement");
}
if(_current_result.size()!=0)
{
throw IEX_NAMESPACE::ArgExc("bug in test suite: already inserting result");
}
_inserting_result=true;
return *this;
}
// finalise the current sample/results
data & operator << (const end &)
{
if(_inserting_result)
{
if(_current_result.size()!=_channels.size())
{
throw IEX_NAMESPACE::ArgExc("bug in test suite: cannot end result: wrong number of values written");
}
_results.push_back(_current_result);
_current_result.resize(0);
//
// also cause the current_samples to be written as the given number of pixels
//
_samples.push_back(_current_pixel);
_current_pixel.resize(0);
_inserting_result=false;
}
else
{
if(_current_sample.size()!=_channels.size())
{
throw IEX_NAMESPACE::ArgExc("bug in test suite: cannot end sample: wrong number of values written");
}
_current_pixel.push_back(_current_sample);
_current_sample.resize(0);
}
return *this;
}
// add a new channel
data & operator << (const string & s)
{
if(_started)
{
throw IEX_NAMESPACE::ArgExc("bug in test suite: cannot insert new channels here");
}
_channels.push_back(s);
return *this;
}
// total number of samples - storage for one copy of everything is sizeof(T)*channels.size()*totalSamples
size_t totalSamples() const
{
size_t answer=0;
for(size_t i=0;i<_samples.size();i++)
{
answer+=_samples[i].size();
}
return answer;
}
//copy the channels into the header list
void
setHeader(Header & hdr) const
{
for(size_t i=0;i<_channels.size();i++)
{
hdr.channels().insert(_channels[i],_type);
}
}
void frak(vector< data<T> > & parts) const
{
for(size_t i=0;i<parts.size();i++)
{
parts[i]._channels = _channels;
parts[i]._results = _results;
parts[i]._type = _type;
parts[i]._samples.resize(_samples.size());
}
//
// loop over each pixel, pushing its values to a random part
//
for(size_t i=0;i<_samples.size();i++)
{
// copy sample to a random part
for(int s=0;s<_samples[i].size();s++)
{
int part = rand()% parts.size();
parts[part]._samples[i].push_back(_samples[i][s]);
}
}
}
void
writeData(DeepScanLineOutputPart & part) const
{
Box2i dw=part.header().dataWindow();
size_t output_pixels = (dw.size().x+1)*(dw.size().y+1);
// how many times we'll write the same pattern
size_t repeats = 1+(output_pixels/_results.size());
size_t sample_buffer_size = totalSamples()*repeats;
// buffer for sample counts
vector<unsigned int> counts(output_pixels);
// buffers for sample pointers
vector< vector<T *> > sample_pointers(_channels.size());
// buffer for actual sample data
vector< vector<T> > sample_buffers(_channels.size());
for(size_t i=0;i<sample_buffers.size();i++)
{
sample_pointers[i].resize(output_pixels);
sample_buffers[i].resize(sample_buffer_size);
}
size_t pixel=0; // which pixel we are currently writing
size_t sample=0; // which sample we are currently writing into
for(size_t p=0;p<output_pixels;p++)
{
size_t count = _samples[pixel].size();
counts[p]=count;
if( count>0 )
{
for(size_t c=0 ; c<_channels.size() ; c++)
{
for(size_t s=0 ; s < count ; s++ )
{
sample_buffers[c][sample+s]=_samples[pixel][s][c];
}
sample_pointers[c][p]=&sample_buffers[c][sample];
}
sample+=count;
}
pixel++;
if(pixel==_samples.size()) pixel=0;
}
cout << " wrote " << sample << " samples into " << output_pixels << " pixels\n";
DeepFrameBuffer fb;
fb.insertSampleCountSlice(Slice(UINT,
(char *)(&counts[0]-dw.min.x-(dw.size().x+1)*dw.min.y),
sizeof(unsigned int),
sizeof(unsigned int)*(dw.size().x+1)
)
);
for(size_t c=0;c<_channels.size();c++)
{
fb.insert(_channels[c],
DeepSlice(_type,(char *)(&sample_pointers[c][0]-dw.min.x-(dw.size().x+1)*dw.min.y),
sizeof(T *),
sizeof(T *)*(dw.size().x+1),
sizeof(T)
)
);
}
part.setFrameBuffer(fb);
part.writePixels(dw.size().y+1);
}
void
setUpFrameBuffer(vector<T> & data,FrameBuffer & framebuf,const Box2i & dw,bool dontbotherloadingdepth) const
{
// allocate enough space for all channels (even the depth channel)
data.resize(_channels.size()*(dw.size().x+1)*(dw.size().y+1));
for(size_t i=0;i<_channels.size();i++)
{
if(!dontbotherloadingdepth || (_channels[i]!="Z" && _channels[i]!="ZBack") )
{
framebuf.insert(_channels[i].c_str(),
Slice(_type,(char *) (&data[i] - (dw.min.x + dw.min.y*(dw.size().x+1))*_channels.size() ),
sizeof(T)*_channels.size(),
sizeof(T)*(dw.size().x+1)*_channels.size())
);
}
}
}
//
// check values are within a suitable tolerance of the expected value (expect some errors due to half float storage etc)
//
void
checkValues(const vector<T> & data,const Box2i & dw,bool dontbothercheckingdepth)
{
size_t size = _channels.size()+(dw.size().x+1)*(dw.size().y+1);
size_t pel=0;
size_t channel=0;
if(dontbothercheckingdepth)
{
for(size_t i=0;i<size;i++)
{
if(_channels[channel]!="Z" && _channels[channel]!="ZBack")
{
if(fabs(_results[pel][channel] - data[i])>0.005)
{
cout << "sample " << i << " (channel " << _channels[channel] << " of pixel " << i % _channels.size() << ") ";
cout << "doesn't match expected value (channel " << channel << " of pixel " << pel << ") : ";
cout << "got " << data[i] << " expected " << _results[pel][channel] << endl;
}
assert(fabs(_results[pel][channel]- data[i])<=0.005);
}
channel++;
if(channel==_channels.size())
{
channel=0;
pel++;
if(pel==_results.size())
{
pel=0;
}
}
}
}else{
for(size_t i=0;i<size;i++)
{
if(fabs(_results[pel][channel] - data[i])>0.005)
{
cout << "sample " << i << " (channel " << _channels[channel] << " of pixel " << i % _channels.size() << ") ";
cout << "doesn't match expected value (channel " << channel << " of pixel " << pel << ") : ";
cout << "got " << data[i] << " expected " << _results[pel][channel] << endl;
}
assert(fabs(_results[pel][channel] - data[i])<=0.005);
channel++;
if(channel==_channels.size())
{
channel=0;
pel++;
if(pel==_results.size())
{
pel=0;
}
}
}
}
}
};
template<class T>
ostream & operator << (ostream & o,data<T> & d)
{
o << "channels: [ ";
for(size_t i=0;i<d._channels.size();i++)
{
o << d._channels[i] << " ";
}
o << "]" << endl;
for(size_t i=0;i<d._samples.size();i++)
{
o << "pixel: " << d._samples[i].size() << " samples" << endl;
for(size_t j=0;j<d._samples[i].size();j++)
{
o << " " << j << ": [ ";
for(size_t k = 0; k < d._samples[i][j].size();k++)
{
o << d._samples[i][j][k] << ' ';
}
o << "]" << endl;
}
o << "result: [ ";
for(size_t k=0;k<d._results[i].size();k++)
{
o << d._results[i][k] << ' ' ;
}
o << "]\n" << endl;
}
return o;
}
template<class DATA>
void
make_pattern(data<DATA> & bob,int pattern_number)
{
if (pattern_number==0)
{
// set channels
bob << string("Z") << string("ZBack") << string("A") << string("R");
PixelType t;
// regular two-pixel composite
bob << 1.0 << 2.0 << 0.0 << 1.0 << end();
bob << 2.1 << 2.3 << 0.5 << 0.4 << end();
bob << result();
bob << 3.1 << 4.3 << 0.5 << 1.4 << end();
bob << 10 << 20 << 1.0 << 1.0 << end();
bob << 20 << 30 << 1.0 << 2.0 << end();
bob << result();
bob << 10 << 20 << 1.0 << 1.0 << end();
bob << result();
bob << 0.0 << 0.0 << 0.0 << 0.0 << end();
}
else if (pattern_number==1)
{
//
// out of order channels, no zback - should-re-order them for us
//
bob << string("Z") << string("R") << string("G") << string("B") << string("A");
// write this four times, so we get various patterns for splitting the blocks
for(int pass=0;pass<4;pass++)
{
// regular four-pixel composite
bob << 1.0 << 0.4 << 1.25 << -0.1 << 0.7 << end();
bob << 2.2 << 0.2 << -0.1 << 0.0 << 0.24 << end();
bob << 2.3 << 0.9 << 0.56 << 2.26 << 0.9 << end();
bob << 5.0 << 1.0 << 0.5 << 0.60 << 0.2 << end();
bob << result();
// eight-pixel composite
bob << 2.2984 << 0.68800 << 1.35908 << 0.42896 << 0.9817 << end();
bob << 1.0 << 0.4 << 1.25 << -0.1 << 0.7 << end();
bob << 2.2 << 0.2 << -0.1 << 0.0 << 0.24 << end();
bob << 2.3 << 0.9 << 0.56 << 2.26 << 0.9 << end();
bob << 5.0 << 1.0 << 0.5 << 0.60 << 0.2 << end();
bob << 11.0 << 0.4 << 1.25 << -0.1 << 0.7 << end();
bob << 12.2 << 0.2 << -0.1 << 0.0 << 0.24 << end();
bob << 12.3 << 0.9 << 0.56 << 2.26 << 0.9 << end();
bob << 15.0 << 1.0 << 0.5 << 0.60 << 0.2 << end();
bob << result();
bob << 2.62319 << 0.7005 << 1.38387 << 0.43678 << 0.99967 << end();
// one-pixel composite
bob << 27.0 << 1.0 << -1.0 << 42.0 << 14 << end(); // alpha>1 should still work
bob << result();
bob << 27.0 << 1.0 << -1.0 << 42.0 << 14 << end();
}
}
}
template<class T>
void
write_file(const char * filename, const data<T> & master, int number_of_parts)
{
vector<Header> headers(number_of_parts);
// all headers are the same in this test
headers[0].displayWindow().max.x=164;
headers[0].displayWindow().max.y=216;
headers[0].dataWindow().min.x=rand()%400 - 200;
headers[0].dataWindow().max.x=headers[0].dataWindow().min.x+40+rand()%400;
headers[0].dataWindow().min.y=rand()%400 - 200;
headers[0].dataWindow().max.y=headers[0].dataWindow().min.y+40+rand()%400;
cout << "data window: " << headers[0].dataWindow().min.x << ',' << headers[0].dataWindow().min.y << ' ' <<
headers[0].dataWindow().max.x << ',' << headers[0].dataWindow().max.y << endl;
headers[0].setType(DEEPSCANLINE);
headers[0].compression()=ZIPS_COMPRESSION;
headers[0].setName("Part0");
for(int i=1;i<number_of_parts;i++)
{
headers[i]=headers[0];
ostringstream s;
s << "Part" << i;
headers[i].setName(s.str());
}
vector< data<T> > sub_parts(number_of_parts);
if(number_of_parts>1)
{
master.frak(sub_parts);
}
if(number_of_parts==1)
{
master.setHeader(headers[0]);
}else{
for(int i=0;i<number_of_parts;i++)
{
sub_parts[i].setHeader(headers[i]);
}
}
MultiPartOutputFile f(filename,&headers[0],headers.size());
for(int i=0;i<number_of_parts;i++)
{
DeepScanLineOutputPart p(f,i);
if(number_of_parts==1)
{
master.writeData(p);
}else{
sub_parts[i].writeData(p);
}
}
}
template<class T>
void
test_parts (int pattern_number,
int number_of_parts,
bool load_depths,
bool entire_buffer,
const std::string &tempDir)
{
std::string fn = tempDir + "imf_test_composite_deep_scanline_source.exr";
data<T> master;
make_pattern (master, pattern_number);
write_file (fn.c_str(), master,number_of_parts);
{
vector<T> data;
CompositeDeepScanLine comp;
FrameBuffer testbuf;
MultiPartInputFile input(fn.c_str());
vector<DeepScanLineInputPart *> parts(number_of_parts);
// use 'part' interface TODO test file interface too
for(int i=0;i<number_of_parts;i++)
{
parts[i] = new DeepScanLineInputPart(input,i);
comp.addSource(parts[i]);
}
master.setUpFrameBuffer(data,testbuf,comp.dataWindow(),load_depths);
comp.setFrameBuffer(testbuf);
//
// try loading the whole buffer
//
if(entire_buffer)
{
comp.readPixels(comp.dataWindow().min.y,comp.dataWindow().max.y);
}else{
int low = comp.dataWindow().min.y;
while(low<comp.dataWindow().max.y)
{
int high = low + rand()%64;
if(high>comp.dataWindow().max.y)
high = comp.dataWindow().max.y;
comp.readPixels(low,high);
low = high;
}
}
master.checkValues(data,comp.dataWindow(),load_depths);
for(int i=0;i<number_of_parts;i++)
{
delete parts[i];
}
}
if(number_of_parts==1)
{
// also test InputFile interface
InputFile file(fn.c_str());
vector<T> data;
FrameBuffer testbuf;
const Box2i & dataWindow = file.header().dataWindow();
master.setUpFrameBuffer(data,testbuf,dataWindow,load_depths);
file.setFrameBuffer(testbuf);
if(entire_buffer)
{
file.readPixels(dataWindow.min.y,dataWindow.max.y);
}else{
int low = dataWindow.min.y;
while(low<dataWindow.max.y)
{
int high = low + rand()%64;
if(high>dataWindow.max.y)
high = dataWindow.max.y;
file.readPixels(low,high);
low = high;
}
}
master.checkValues (data, dataWindow, load_depths);
}
remove (fn.c_str());
}
}
void testCompositeDeepScanLine (const std::string & tempDir)
{
cout << "\n\nTesting deep compositing interface basic functionality:\n" << endl;
int passes=2;
if (!ILMTHREAD_NAMESPACE::supportsThreads ())
{
passes=1;
}
srand(1);
for(int pass=0;pass<2;pass++)
{
test_parts<float>(0, 1, true, true, tempDir);
test_parts<float>(0, 1, false, false, tempDir);
test_parts<half> (0, 1, true, false, tempDir);
test_parts<half> (0, 1, false, true, tempDir);
//
// test pattern 1: tested by confirming data is written correctly and
// then reading correct results in Nuke
//
test_parts<float>(1, 1, true, false, tempDir);
test_parts<float>(1, 1, false, true, tempDir);
test_parts<half> (1, 1, true, true, tempDir);
test_parts<half> (1, 1, false, false, tempDir);
cout << "Testing deep compositing across multiple parts:\n" << endl;
test_parts<float>(0, 5, true, false, tempDir);
test_parts<float>(0, 5, false, true, tempDir);
test_parts<half> (0, 5, true, false, tempDir);
test_parts<half> (0, 5, false, true, tempDir);
test_parts<float>(1, 3, true, true, tempDir);
test_parts<float>(1, 3, false, false, tempDir);
test_parts<half> (1, 3, true, true, tempDir);
test_parts<half> (1, 3, false, false, tempDir);
test_parts<float>(1, 4, true, true, tempDir);
test_parts<float>(1, 4, false, false, tempDir);
test_parts<half> (1, 4, true, false, tempDir);
test_parts<half> (1, 4, false, true, tempDir);
if(passes==2 && pass==0)
{
cout << " testing with multithreading...\n";
setGlobalThreadCount(64);
}
}
cout << " ok\n" << endl;
}

View File

@ -0,0 +1,41 @@
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2012, Weta Digital Ltd
//
// 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 Weta Digital 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.
//
///////////////////////////////////////////////////////////////////////////
#ifndef TESTCOMPOSITEDEEPSCANLINE_H_
#define TESTCOMPOSITEDEEPSCANLINE_H_
#include <string>
void testCompositeDeepScanLine (const std::string & tempDir);
#endif /* TESTCOMPOSITEDEEPSCANLINE_H_ */

View File

@ -0,0 +1,435 @@
///////////////////////////////////////////////////////////////////////////
//
// 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 "compareB44.h"
#include <ImfOutputFile.h>
#include <ImfInputFile.h>
#include <ImfChannelList.h>
#include <ImfArray.h>
#include <ImathRandom.h>
#include <half.h>
#include "compareFloat.h"
#include <stdio.h>
#include <assert.h>
namespace IMF = OPENEXR_IMF_NAMESPACE;
using namespace IMF;
using namespace std;
using namespace IMATH_NAMESPACE;
namespace {
void
fillPixels1 (Array2D<unsigned int> &pi,
Array2D<half> &ph,
Array2D<float> &pf,
int width,
int height)
{
cout << "only zeroes" << endl;
for (int y = 0; y < height; ++y)
for (int x = 0; x < width; ++x)
{
pi[y][x] = 0;
ph[y][x] = 0;
pf[y][x] = 0;
}
}
void
fillPixels2 (Array2D<unsigned int> &pi,
Array2D<half> &ph,
Array2D<float> &pf,
int width,
int height)
{
cout << "pattern 1" << endl;
for (int y = 0; y < height; ++y)
for (int x = 0; x < width; ++x)
{
pi[y][x] = (x + y) & 1;
ph[y][x] = pi[y][x];
pf[y][x] = pi[y][x];
}
}
void
fillPixels3 (Array2D<unsigned int> &pi,
Array2D<half> &ph,
Array2D<float> &pf,
int width,
int height)
{
cout << "pattern 2" << endl;
for (int y = 0; y < height; ++y)
for (int x = 0; x < width; ++x)
{
pi[y][x] = x % 100 + 100 * (y % 100);
ph[y][x] = sin (double (x)) + sin (y * 0.5);
pf[y][x] = sin (double (y)) + sin (x * 0.5);
}
}
void
fillPixels4 (Array2D<unsigned int> &pi,
Array2D<half> &ph,
Array2D<float> &pf,
int width,
int height)
{
cout << "random bits" << endl;
//
// Use of a union to extract the bit pattern from a float, as is
// done below, works only if int and float have the same size.
//
assert (sizeof (int) == sizeof (float));
Rand48 rand;
for (int y = 0; y < height; ++y)
for (int x = 0; x < width; ++x)
{
pi[y][x] = rand.nexti();
ph[y][x].setBits (rand.nexti());
union {int i; float f;} u;
u.i = rand.nexti();
pf[y][x] = u.f;
}
}
void
writeRead (const Array2D<unsigned int> &pi1,
const Array2D<half> &ph1,
const Array2D<float> &pf1,
const char fileName[],
int width,
int height,
int xOffset,
int yOffset,
Compression comp,
int xs,
int ys)
{
//
// Write the pixel data in pi1, ph1 and ph2 to an
// image file using the specified compression type
// and subsampling rates. Read the pixel data back
// from the file and verify that the data did not
// change.
//
cout << "compression " << comp <<
", x sampling " << xs <<
", y sampling " << ys <<
":" << flush;
Header hdr ((Box2i (V2i (0, 0), // display window
V2i (width - 1, height -1))),
(Box2i (V2i (xOffset, yOffset), // data window
V2i (xOffset + width - 1, yOffset + height - 1))));
hdr.compression() = comp;
hdr.channels().insert ("I", // name
Channel (IMF::UINT, // type
xs, // xSampling
ys) // ySampling
);
hdr.channels().insert ("H", // name
Channel (IMF::HALF, // type
xs, // xSampling
ys) // ySampling
);
hdr.channels().insert ("F", // name
Channel (IMF::FLOAT, // type
xs, // xSampling
ys) // ySampling
);
{
FrameBuffer fb;
fb.insert ("I", // name
Slice (IMF::UINT, // type
(char *) &pi1[-yOffset / ys][-xOffset / xs], // base
sizeof (pi1[0][0]), // xStride
sizeof (pi1[0][0]) * (width / xs), // yStride
xs, // xSampling
ys) // ySampling
);
fb.insert ("H", // name
Slice (IMF::HALF, // type
(char *) &ph1[-yOffset / ys][-xOffset / xs], // base
sizeof (ph1[0][0]), // xStride
sizeof (ph1[0][0]) * (width / xs), // yStride
xs, // xSampling
ys) // ySampling
);
fb.insert ("F", // name
Slice (IMF::FLOAT, // type
(char *) &pf1[-yOffset / ys][-xOffset / xs], // base
sizeof (pf1[0][0]), // xStride
sizeof (pf1[0][0]) * (width / xs), // yStride
xs, // xSampling
ys) // ySampling
);
cout << " writing" << flush;
remove (fileName);
OutputFile out (fileName, hdr);
out.setFrameBuffer (fb);
out.writePixels (height);
}
{
cout << " reading" << flush;
InputFile in (fileName);
const Box2i &dw = in.header().dataWindow();
int w = dw.max.x - dw.min.x + 1;
int h = dw.max.y - dw.min.y + 1;
int dx = dw.min.x;
int dy = dw.min.y;
Array2D<unsigned int> pi2 (h / ys, w / xs);
Array2D<half> ph2 (h / ys, w / xs);
Array2D<float> pf2 (h / ys, w / xs);
FrameBuffer fb;
{
int xs = in.header().channels()["I"].xSampling;
int ys = in.header().channels()["I"].ySampling;
fb.insert ("I", // name
Slice (IMF::UINT, // type
(char *) &pi2[-dy / ys][-dx / xs], // base
sizeof (pi2[0][0]), // xStride
sizeof (pi2[0][0]) * (w / xs), // yStride
xs, // xSampling
ys) // ySampling
);
}
{
int xs = in.header().channels()["H"].xSampling;
int ys = in.header().channels()["H"].ySampling;
fb.insert ("H", // name
Slice (IMF::HALF, // type
(char *) &ph2[-dy / ys][-dx / xs], // base
sizeof (ph2[0][0]), // xStride
sizeof (ph2[0][0]) * (w / xs), // yStride
xs, // xSampling
ys) // ySampling
);
}
{
int xs = in.header().channels()["F"].xSampling;
int ys = in.header().channels()["F"].ySampling;
fb.insert ("F", // name
Slice (IMF::FLOAT, // type
(char *) &pf2[-dy / ys][-dx / xs], // base
sizeof (pf2[0][0]), // xStride
sizeof (pf2[0][0]) * (w / xs), // yStride
xs, // xSampling
ys) // ySampling
);
}
in.setFrameBuffer (fb);
in.readPixels (dw.min.y, dw.max.y);
cout << " comparing" << flush;
assert (in.header().displayWindow() == hdr.displayWindow());
assert (in.header().dataWindow() == hdr.dataWindow());
assert (in.header().pixelAspectRatio() == hdr.pixelAspectRatio());
assert (in.header().screenWindowCenter() == hdr.screenWindowCenter());
assert (in.header().screenWindowWidth() == hdr.screenWindowWidth());
assert (in.header().lineOrder() == hdr.lineOrder());
assert (in.header().compression() == hdr.compression());
ChannelList::ConstIterator hi = hdr.channels().begin();
ChannelList::ConstIterator ii = in.header().channels().begin();
while (hi != hdr.channels().end())
{
assert (!strcmp (hi.name(), ii.name()));
assert (hi.channel().type == ii.channel().type);
assert (hi.channel().xSampling == ii.channel().xSampling);
assert (hi.channel().ySampling == ii.channel().ySampling);
++hi;
++ii;
}
assert (ii == in.header().channels().end());
for (int y = 0; y < h / ys; ++y)
{
for (int x = 0; x < w / xs; ++x)
{
assert (pi1[y][x] == pi2[y][x]);
assert (equivalent (pf1[y][x], pf2[y][x], comp));
if (comp != B44_COMPRESSION &&
comp != B44A_COMPRESSION)
{
assert (ph1[y][x].bits() == ph2[y][x].bits());
}
}
}
if (comp == B44_COMPRESSION ||
comp == B44A_COMPRESSION)
{
Array2D<half> ph3 (h / ys, w / xs);
for (int y = 0; y < h / ys; ++y)
for (int x = 0; x < w / xs; ++x)
ph3[y][x] = ph1[y][x];
compareB44 (w / xs, h / ys, ph3, ph2);
}
}
remove (fileName);
cout << endl;
}
void
writeRead (const std::string &tempDir,
const Array2D<unsigned int> &pi,
const Array2D<half> &ph,
const Array2D<float> &pf,
int w,
int h,
int dx,
int dy)
{
std::string filename = tempDir + "imf_test_comp.exr";
for (int xs = 1; xs <= 2; ++xs)
{
for (int ys = 1; ys <= 2; ++ys)
{
for (int comp = 0; comp < NUM_COMPRESSION_METHODS; ++comp)
{
writeRead (pi, ph, pf,
filename.c_str(),
w * xs, h * ys,
dx * xs, dy * ys,
Compression (comp),
xs, ys);
}
}
}
}
} // namespace
void
testCompression (const std::string &tempDir)
{
try
{
cout << "Testing pixel data types, "
"subsampling and "
"compression schemes" << endl;
const int W = 1371;
const int H = 159;
const int DX = 17;
const int DY = 29;
Array2D<unsigned int> pi (H, W);
Array2D<half> ph (H, W);
Array2D<float> pf (H, W);
//
// If the following assertion fails, new pixel types have
// been added to the Imf library; testing code for the new
// pixel types should be added to this file.
//
assert (NUM_PIXELTYPES == 3);
fillPixels1 (pi, ph, pf, W, H);
writeRead (tempDir, pi, ph, pf, W, H, DX, DY);
fillPixels2 (pi, ph, pf, W, H);
writeRead (tempDir, pi, ph, pf, W, H, DX, DY);
fillPixels3 (pi, ph, pf, W, H);
writeRead (tempDir, pi, ph, pf, W, H, DX, DY);
fillPixels4 (pi, ph, pf, W, H);
writeRead (tempDir, pi, ph, pf, W, H, DX, DY);
cout << "ok\n" << endl;
}
catch (const std::exception &e)
{
cerr << "ERROR -- caught exception: " << e.what() << endl;
assert (false);
}
}

View File

@ -0,0 +1,41 @@
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2002-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 <string>
void testCompression (const std::string &tempDir);

View File

@ -0,0 +1,413 @@
//////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2003-2012, Industrial Light & Magic, a division of Lucasfilm
// Entertainment Company Ltd. Portions contributed and copyright held by
// others as indicated. 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
// any other contributors to this software 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 <ImfOutputFile.h>
#include <ImfInputFile.h>
#include <ImfTiledOutputFile.h>
#include <ImfTiledInputFile.h>
#include <ImfChannelList.h>
#include <ImfArray.h>
#include <ImfConvert.h>
#include <half.h>
#include "compareFloat.h"
#include <stdio.h>
#include <assert.h>
namespace IMF = OPENEXR_IMF_NAMESPACE;
using namespace IMF;
using namespace std;
using namespace IMATH_NAMESPACE;
namespace {
//
// Functions to test conversion of individual numbers
//
void
testFloatToUint (unsigned int floatVal, unsigned int uintVal)
{
union {unsigned int ui; float f;} u;
u.ui = floatVal;
cout << "floatToUint (" << u.f << ") == " << floatToUint(u.f) << endl;
assert (floatToUint (u.f) == uintVal);
}
void
testHalfToUint (unsigned int halfVal, unsigned int uintVal)
{
half h;
h.setBits (halfVal);
cout << "halfToUint (" << h << ") == " << halfToUint(h) << endl;
assert (halfToUint (h) == uintVal);
}
void
testFloatToHalf (unsigned int floatVal, unsigned int halfVal)
{
union {unsigned int ui; float f;} u;
u.ui = floatVal;
cout << "floatToHalf (" << u.f << ") == " << floatToHalf(u.f) << endl;
assert (floatToHalf(u.f).bits() == halfVal);
}
void
testUintToHalf (unsigned int uintVal, unsigned int halfVal)
{
cout << "uintToHalf (" << uintVal << ") == " << uintToHalf(uintVal) << endl;
assert (uintToHalf(uintVal).bits() == halfVal);
}
void
testNumbers ()
{
testFloatToUint (0x00000000, 0); // 0.0
testFloatToUint (0x3f000000, 0); // +0.5
testFloatToUint (0xbf000000, 0); // -0.5
testFloatToUint (0x42f82000, 124); // +124.0625
testFloatToUint (0xc2f82000, 0); // -124.0625
testFloatToUint (0x58635fa9, 0xffffffff); // +1.0e15
testFloatToUint (0xd8635fa9, 0); // -1.0e15
testFloatToUint (0x7f800000, 0xffffffff); // +infinity
testFloatToUint (0xff800000, 0); // -infinity
testFloatToUint (0x7fffffff, 0); // NaN
testFloatToUint (0xffffffff, 0); // NaN
testHalfToUint (0x0000, 0); // 0.0
testHalfToUint (0x3800, 0); // +0.5
testHalfToUint (0xb800, 0); // -0.5
testHalfToUint (0x57c1, 124); // +124.0625
testHalfToUint (0xd7c1, 0); // -124.0625
testHalfToUint (0x7c00, 0xffffffff); // +infinity
testHalfToUint (0xfc00, 0); // -infinity
testHalfToUint (0x7fff, 0); // NaN
testHalfToUint (0xffff, 0); // NaN
testFloatToHalf (0x00000000, 0x0000); // 0.0
testFloatToHalf (0x3f000000, 0x3800); // +0.5
testFloatToHalf (0xbf000000, 0xb800); // -0.5
testFloatToHalf (0x42f82000, 0x57c1); // +124.0625
testFloatToHalf (0xc2f82000, 0xd7c1); // -124.0625
testFloatToHalf (0x58635fa9, 0x7c00); // +1.0e15
testFloatToHalf (0xd8635fa9, 0xfc00); // -1.0e15
testFloatToHalf (0x7f800000, 0x7c00); // +infinity
testFloatToHalf (0xff800000, 0xfc00); // -infinity
testFloatToHalf (0x7fffffff, 0x7fff); // NaN
testFloatToHalf (0xffffffff, 0xffff); // NaN
testUintToHalf (0, 0x0000);
testUintToHalf (1, 0x3c00);
testUintToHalf (124, 0x57c0);
testUintToHalf (1000000, 0x7c00);
testUintToHalf (0xffffffff, 0x7c00);
}
template <class T>
bool
isEquivalent (T t1, T t2, Compression compression)
{
return t1 == t2;
}
template<>
bool
isEquivalent (float t1, float t2, Compression compression)
{
return equivalent (t1, t2, compression);
}
template <class OutType, PixelType OutTypeTag,
class InType, PixelType InTypeTag>
void
testScanLineImageChannel (const char fileName[],
int width, int height,
Compression compression)
{
cout << "scan lines, "
"compression " << compression << ", " <<
"output type " << OutTypeTag << ", " <<
"input type " << InTypeTag << ":\n " << flush;
Array2D<OutType> outPixels (height, width);
for (int y = 0; y < height; ++y)
for (int x = 0; x < width; ++x)
outPixels[y][x] = x * 10 + y;
{
Header hdr (width, height);
hdr.compression() = compression;
hdr.channels().insert ("X", // name
Channel (OutTypeTag)); // type
FrameBuffer fb;
fb.insert ("X", // name
Slice (OutTypeTag, // type
(char *) &outPixels[0][0], // base
sizeof (outPixels[0][0]), // xStride
sizeof (outPixels[0][0]) * width)); // yStride
cout << "writing " << flush;
OutputFile out (fileName, hdr);
out.setFrameBuffer (fb);
out.writePixels (height);
}
Array2D<InType> inPixels (height, width);
{
cout << "reading " << flush;
FrameBuffer fb;
fb.insert ("X", // name
Slice (InTypeTag, // type
(char *) &inPixels[0][0], // base
sizeof (inPixels[0][0]), // xStride
sizeof (inPixels[0][0]) * width)); // yStride
InputFile in (fileName);
in.setFrameBuffer (fb);
in.readPixels (0, height - 1);
}
cout << "comparing" << flush;
for (int y = 0; y < height; ++y)
{
for (int x = 0; x < width; ++x)
{
assert (isEquivalent (inPixels[y][x],
InType (outPixels[y][x]),
compression));
}
}
cout << endl;
remove (fileName);
}
template <class OutType, PixelType OutTypeTag,
class InType, PixelType InTypeTag>
void
testTiledImageChannel (const char fileName[],
int width, int height,
Compression compression)
{
cout << "tiles, "
"compression " << compression << ", " <<
"output type " << OutTypeTag << ", " <<
"input type " << InTypeTag << ":\n " << flush;
Array2D<OutType> outPixels (height, width);
for (int y = 0; y < height; ++y)
for (int x = 0; x < width; ++x)
outPixels[y][x] = x * 10 + y;
{
Header hdr (width, height);
hdr.setTileDescription (TileDescription (67, 67, ONE_LEVEL));
hdr.compression() = compression;
hdr.channels().insert ("X", // name
Channel (OutTypeTag)); // type
FrameBuffer fb;
fb.insert ("X", // name
Slice (OutTypeTag, // type
(char *) &outPixels[0][0], // base
sizeof (outPixels[0][0]), // xStride
sizeof (outPixels[0][0]) * width)); // yStride
cout << "writing " << flush;
TiledOutputFile out (fileName, hdr);
out.setFrameBuffer (fb);
out.writeTiles (0, out.numXTiles() - 1, 0, out.numYTiles() - 1);
}
Array2D<InType> inPixels (height, width);
{
cout << "reading " << flush;
FrameBuffer fb;
fb.insert ("X", // name
Slice (InTypeTag, // type
(char *) &inPixels[0][0], // base
sizeof (inPixels[0][0]), // xStride
sizeof (inPixels[0][0]) * width)); // yStride
TiledInputFile in (fileName);
in.setFrameBuffer (fb);
in.readTiles (0, in.numXTiles() - 1, 0, in.numYTiles() - 1);
}
cout << "comparing" << flush;
for (int y = 0; y < height; ++y)
{
for (int x = 0; x < width; ++x)
{
assert (isEquivalent (inPixels[y][x],
InType (outPixels[y][x]),
compression));
}
}
cout << endl;
remove (fileName);
}
template <class OutType, PixelType OutTypeTag,
class InType, PixelType InTypeTag>
void
testImageChannel (const std::string &fileName,
int width, int height,
Compression compression)
{
testScanLineImageChannel <OutType, OutTypeTag, InType, InTypeTag>
(fileName.c_str(), width, height, compression);
testTiledImageChannel <OutType, OutTypeTag, InType, InTypeTag>
(fileName.c_str(), width, height, compression);
}
} // namespace
void
testConversion (const std::string &tempDir)
{
try
{
cout << "Testing conversion between pixel data types" << endl;
cout << "individual numbers" << endl;
testNumbers();
cout << "conversion of image channels while reading a file " << endl;
for (int comp = 0; comp < NUM_COMPRESSION_METHODS; ++comp)
{
if (comp == B44_COMPRESSION ||
comp == B44A_COMPRESSION)
{
continue;
}
testImageChannel <unsigned int, IMF::UINT, unsigned int, IMF::UINT>
(tempDir + "imf_test_conv.exr",
317, 539,
Compression (comp));
testImageChannel <unsigned int, IMF::UINT, half, IMF::HALF>
(tempDir + "imf_test_conv.exr",
317, 539,
Compression (comp));
testImageChannel <unsigned int, IMF::UINT, float, IMF::FLOAT>
(tempDir + "imf_test_conv.exr",
317, 539,
Compression (comp));
testImageChannel <half, IMF::HALF, unsigned int, IMF::UINT>
(tempDir + "imf_test_conv.exr",
317, 539,
Compression (comp));
testImageChannel <half, IMF::HALF, half, IMF::HALF>
(tempDir + "imf_test_conv.exr",
317, 539,
Compression (comp));
testImageChannel <half, IMF::HALF, float, IMF::FLOAT>
(tempDir + "imf_test_conv.exr",
317, 539,
Compression (comp));
testImageChannel <float, IMF::FLOAT, unsigned int, IMF::UINT>
(tempDir + "imf_test_conv.exr",
317, 539,
Compression (comp));
testImageChannel <float, IMF::FLOAT, half, IMF::HALF>
(tempDir + "imf_test_conv.exr",
317, 539,
Compression (comp));
testImageChannel <float, IMF::FLOAT, float, IMF::FLOAT>
(tempDir + "imf_test_conv.exr",
317, 539,
Compression (comp));
}
cout << "ok\n" << endl;
}
catch (const std::exception &e)
{
cerr << "ERROR -- caught exception: " << e.what() << endl;
assert (false);
}
}

View File

@ -0,0 +1,40 @@
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2003-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 <string>
void testConversion (const std::string &tempDir);

View File

@ -0,0 +1,441 @@
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2011, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
//
// Portions (c) 2012, Weta Digital Ltd
//
// 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 "testCopyDeepScanLine.h"
#include <assert.h>
#include <string.h>
#include <ImfDeepScanLineInputFile.h>
#include <ImfDeepScanLineOutputFile.h>
#include <ImfPartType.h>
#include <ImfChannelList.h>
#include <ImfDeepFrameBuffer.h>
#include <ImfArray.h>
#include <IlmThreadPool.h>
#include <stdlib.h>
#include <stdio.h>
#include <vector>
#include "tmpDir.h"
namespace IMF = OPENEXR_IMF_NAMESPACE;
using namespace IMF;
using namespace std;
using namespace IMATH_NAMESPACE;
using namespace ILMTHREAD_NAMESPACE;
namespace
{
const int width = 538;
const int height = 234;
const int minX = 42;
const int minY = 51;
const Box2i dataWindow(V2i(minX, minY), V2i(minX + width - 1, minY + height - 1));
const Box2i displayWindow(V2i(0, 0), V2i(minX + width * 2, minY + height * 2));
const char source_filename[] = IMF_TMP_DIR "imf_test_copy_deep_scanline_source.exr";
const char copy_filename[] = IMF_TMP_DIR "imf_test_copy_deep_scanline_copy.exr";
vector<int> channelTypes;
Array2D<unsigned int> sampleCount;
Header header;
void generateRandomFile (const std::string & source_filename,
int channelCount,
Compression compression)
{
cout << "generating " << flush;
header = Header(displayWindow, dataWindow,
1,
IMATH_NAMESPACE::V2f (0, 0),
1,
INCREASING_Y,
compression);
cout << "compression " << compression << " " << flush;
//
// Add channels.
//
channelTypes.clear();
for (int i = 0; i < channelCount; i++)
{
int type = rand() % 3;
stringstream ss;
ss << i;
string str = ss.str();
if (type == 0)
header.channels().insert(str, Channel(IMF::UINT));
if (type == 1)
header.channels().insert(str, Channel(IMF::HALF));
if (type == 2)
header.channels().insert(str, Channel(IMF::FLOAT));
channelTypes.push_back(type);
}
header.setType(DEEPSCANLINE);
Array<Array2D< void* > > data(channelCount);
for (int i = 0; i < channelCount; i++)
data[i].resizeErase(height, width);
sampleCount.resizeErase(height, width);
remove (source_filename.c_str());
DeepScanLineOutputFile file(source_filename.c_str(), header, 8);
DeepFrameBuffer frameBuffer;
frameBuffer.insertSampleCountSlice (Slice (IMF::UINT, // type // 7
(char *) (&sampleCount[0][0]
- dataWindow.min.x
- dataWindow.min.y * width), // base // 8
sizeof (unsigned int) * 1, // xStride// 9
sizeof (unsigned int) * width)); // yStride// 10
for (int i = 0; i < channelCount; i++)
{
PixelType type;
if (channelTypes[i] == 0)
type = IMF::UINT;
if (channelTypes[i] == 1)
type = IMF::HALF;
if (channelTypes[i] == 2)
type = IMF::FLOAT;
stringstream ss;
ss << i;
string str = ss.str();
int sampleSize;
if (channelTypes[i] == 0) sampleSize = sizeof (unsigned int);
if (channelTypes[i] == 1) sampleSize = sizeof (half);
if (channelTypes[i] == 2) sampleSize = sizeof (float);
int pointerSize = sizeof(char *);
frameBuffer.insert (str, // name // 6
DeepSlice (type, // type // 7
(char *) (&data[i][0][0]
- dataWindow.min.x
- dataWindow.min.y * width), // base // 8
pointerSize * 1, // xStride// 9
pointerSize * width, // yStride// 10
sampleSize)); // sampleStride
}
file.setFrameBuffer(frameBuffer);
cout << "writing " << flush;
for (int i = 0; i < height; i++)
{
//
// Fill in data at the last minute.
//
for (int j = 0; j < width; j++)
{
sampleCount[i][j] = rand() % 10 + 1;
for (int k = 0; k < channelCount; k++)
{
if (channelTypes[k] == 0)
data[k][i][j] = new unsigned int[sampleCount[i][j]];
if (channelTypes[k] == 1)
data[k][i][j] = new half[sampleCount[i][j]];
if (channelTypes[k] == 2)
data[k][i][j] = new float[sampleCount[i][j]];
for (int l = 0; l < sampleCount[i][j]; l++)
{
if (channelTypes[k] == 0)
((unsigned int*)data[k][i][j])[l] = (i * width + j) % 2049;
if (channelTypes[k] == 1)
((half*)data[k][i][j])[l] = (i * width + j) % 2049;
if (channelTypes[k] == 2)
((float*)data[k][i][j])[l] = (i * width + j) % 2049;
}
}
}
}
file.writePixels(height);
for (int i = 0; i < height; i++)
for (int j = 0; j < width; j++)
for (int k = 0; k < channelCount; k++)
{
if (channelTypes[k] == 0)
delete[] (unsigned int*) data[k][i][j];
if (channelTypes[k] == 1)
delete[] (half*) data[k][i][j];
if (channelTypes[k] == 2)
delete[] (float*) data[k][i][j];
}
}
void copyFile (const std::string & source_filename,
const std::string & copy_filename)
{
cout << "copying " ;
cout.flush();
{
DeepScanLineInputFile in_file(source_filename.c_str(), 8);
remove (copy_filename.c_str());
DeepScanLineOutputFile out_file (copy_filename.c_str(),
in_file.header(),
8);
out_file.copyPixels(in_file);
}
// remove the source file here to prevent accidentally reading it
// remove (source_filename);
}
void readFile (const std::string & copy_filename, int channelCount)
{
cout << "reading " ;
cout.flush();
DeepScanLineInputFile file(copy_filename.c_str(), 8);
const Header& fileHeader = file.header();
assert (fileHeader.displayWindow() == header.displayWindow());
assert (fileHeader.dataWindow() == header.dataWindow());
assert (fileHeader.pixelAspectRatio() == header.pixelAspectRatio());
assert (fileHeader.screenWindowCenter() == header.screenWindowCenter());
assert (fileHeader.screenWindowWidth() == header.screenWindowWidth());
assert (fileHeader.lineOrder() == header.lineOrder());
assert (fileHeader.compression() == header.compression());
assert (fileHeader.channels() == header.channels());
assert (fileHeader.type() == header.type());
Array2D<unsigned int> localSampleCount;
localSampleCount.resizeErase(height, width);
Array<Array2D< void* > > data(channelCount);
for (int i = 0; i < channelCount; i++)
data[i].resizeErase(height, width);
DeepFrameBuffer frameBuffer;
frameBuffer.insertSampleCountSlice (Slice (IMF::UINT, // type // 7
(char *) (&localSampleCount[0][0]
- dataWindow.min.x
- dataWindow.min.y * width), // base // 8)
sizeof (unsigned int) * 1, // xStride// 9
sizeof (unsigned int) * width)); // yStride// 10
for (int i = 0; i < channelCount; i++)
{
PixelType type;
if (channelTypes[i] == 0)
type = IMF::UINT;
if (channelTypes[i] == 1)
type = IMF::HALF;
if (channelTypes[i] == 2)
type = IMF::FLOAT;
stringstream ss;
ss << i;
string str = ss.str();
int sampleSize;
if (channelTypes[i] == 0) sampleSize = sizeof (unsigned int);
if (channelTypes[i] == 1) sampleSize = sizeof (half);
if (channelTypes[i] == 2) sampleSize = sizeof (float);
int pointerSize = sizeof (char *);
frameBuffer.insert (str, // name // 6
DeepSlice (type, // type // 7
(char *) (&data[i][0][0]
- dataWindow.min.x
- dataWindow.min.y * width), // base // 8)
pointerSize * 1, // xStride// 9
pointerSize * width, // yStride// 10
sampleSize)); // sampleStride
}
file.setFrameBuffer(frameBuffer);
file.readPixelSampleCounts(dataWindow.min.y, dataWindow.max.y);
for (int i = 0; i < dataWindow.max.y - dataWindow.min.y + 1; i++)
{
int y = i + dataWindow.min.y;
for (int j = 0; j < width; j++)
assert(localSampleCount[i][j] == sampleCount[i][j]);
for (int j = 0; j < width; j++)
{
for (int k = 0; k < channelCount; k++)
{
if (channelTypes[k] == 0)
data[k][i][j] = new unsigned int[localSampleCount[i][j]];
if (channelTypes[k] == 1)
data[k][i][j] = new half[localSampleCount[i][j]];
if (channelTypes[k] == 2)
data[k][i][j] = new float[localSampleCount[i][j]];
}
}
}
file.readPixels(dataWindow.min.y, dataWindow.max.y);
for (int i = 0; i < height; i++)
for (int j = 0; j < width; j++)
for (int k = 0; k < channelCount; k++)
{
for (int l = 0; l < sampleCount[i][j]; l++)
{
if (channelTypes[k] == 0)
{
unsigned int* value = (unsigned int*)(data[k][i][j]);
if (value[l] != (i * width + j) % 2049)
cout << j << ", " << i << " error, should be "
<< (i * width + j) % 2049 << ", is " << value[l]
<< endl << flush;
assert (value[l] == (i * width + j) % 2049);
}
if (channelTypes[k] == 1)
{
half* value = (half*)(data[k][i][j]);
if (value[l] != (i * width + j) % 2049)
cout << j << ", " << i << " error, should be "
<< (i * width + j) % 2049 << ", is " << value[l]
<< endl << flush;
assert (((half*)(data[k][i][j]))[l] == (i * width + j) % 2049);
}
if (channelTypes[k] == 2)
{
float* value = (float*)(data[k][i][j]);
if (value[l] != (i * width + j) % 2049)
cout << j << ", " << i << " error, should be "
<< (i * width + j) % 2049 << ", is " << value[l]
<< endl << flush;
assert (((float*)(data[k][i][j]))[l] == (i * width + j) % 2049);
}
}
}
for (int i = 0; i < height; i++)
for (int j = 0; j < width; j++)
for (int k = 0; k < channelCount; k++)
{
if (channelTypes[k] == 0)
delete[] (unsigned int*) data[k][i][j];
if (channelTypes[k] == 1)
delete[] (half*) data[k][i][j];
if (channelTypes[k] == 2)
delete[] (float*) data[k][i][j];
}
}
void readCopyWriteTest (const std::string & tempDir,
int channelCount,
int testTimes)
{
cout << "Testing files with " << channelCount << " channels " << testTimes << " times."
<< endl << flush;
std::string source_filename = tempDir + "imf_test_copy_deep_scanline_source.exr";
std::string copy_filename = tempDir + "imf_test_copy_deep_scanline_copy.exr";
for (int i = 0; i < testTimes; i++)
{
int compressionIndex = i % 3;
Compression compression;
switch (compressionIndex)
{
case 0:
compression = NO_COMPRESSION;
break;
case 1:
compression = RLE_COMPRESSION;
break;
case 2:
compression = ZIPS_COMPRESSION;
break;
}
generateRandomFile (source_filename, channelCount, compression);
copyFile (source_filename, copy_filename);
readFile (copy_filename, channelCount );
remove (source_filename.c_str());
remove (copy_filename.c_str());
cout << endl << flush;
}
}
}; // namespace
void testCopyDeepScanLine (const std::string &tempDir)
{
try
{
cout << "\n\nTesting raw data copy in DeepScanLineInput/OutputFile:\n" << endl;
srand(1);
int numThreads = ThreadPool::globalThreadPool().numThreads();
ThreadPool::globalThreadPool().setNumThreads(4);
readCopyWriteTest (tempDir, 1, 100);
readCopyWriteTest (tempDir, 3, 50);
readCopyWriteTest (tempDir, 10, 10);
ThreadPool::globalThreadPool().setNumThreads(numThreads);
cout << "ok\n" << endl;
}
catch (const std::exception &e)
{
cerr << "ERROR -- caught exception: " << e.what() << endl;
assert (false);
}
}

View File

@ -0,0 +1,45 @@
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2011, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
//
// Portions (c) 2012, Weta Digital Ltd
//
// 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.
//
///////////////////////////////////////////////////////////////////////////
#ifndef TESTCOPYDEEPSCANLINE_H_
#define TESTCOPYDEEPSCANLINE_H_
#include <string>
void testCopyDeepScanLine (const std::string &tempDir);
#endif /* TESTCOPYDEEPSCANLINE_H_ */

View File

@ -0,0 +1,519 @@
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2011, 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 "testCopyDeepTiled.h"
#include <assert.h>
#include <string.h>
#include <ImfDeepTiledInputFile.h>
#include <ImfDeepTiledOutputFile.h>
#include <ImfChannelList.h>
#include <ImfArray.h>
#include <ImfPartType.h>
#include <ImfNamespace.h>
#include <IlmThreadPool.h>
#include <stdio.h>
#include <stdlib.h>
#include <vector>
#include "tmpDir.h"
namespace IMF = OPENEXR_IMF_NAMESPACE;
using namespace IMF;
using namespace IMATH_NAMESPACE;
using namespace ILMTHREAD_NAMESPACE;
using namespace std;
namespace
{
const int width = 199;
const int height = 369;
const int minX = 23;
const int minY = 59;
const Box2i dataWindow(V2i(minX, minY), V2i(minX + width - 1, minY + height - 1));
const Box2i displayWindow(V2i(0, 0), V2i(minX + width * 2, minY + height * 2));
vector<int> channelTypes;
Array2D< Array2D<unsigned int> > sampleCountWhole;
Header header;
void
generateRandomFile (int channelCount,
Compression compression,
const std::string & srcFn)
{
cout << "generating " << flush;
header = Header(displayWindow, dataWindow,
1,
IMATH_NAMESPACE::V2f (0, 0),
1,
INCREASING_Y,
compression);
cout << "compression " << compression << " " << flush;
//
// Add channels.
//
channelTypes.clear();
for (int i = 0; i < channelCount; i++)
{
int type = rand() % 3;
stringstream ss;
ss << i;
string str = ss.str();
if (type == 0)
header.channels().insert(str, Channel(IMF::UINT));
if (type == 1)
header.channels().insert(str, Channel(IMF::HALF));
if (type == 2)
header.channels().insert(str, Channel(IMF::FLOAT));
channelTypes.push_back(type);
}
header.setType(DEEPTILE);
header.setTileDescription(
TileDescription(rand() % width + 1, rand() % height + 1, RIPMAP_LEVELS));
Array<Array2D< void* > > data(channelCount);
for (int i = 0; i < channelCount; i++)
data[i].resizeErase(height, width);
Array2D<unsigned int> sampleCount;
sampleCount.resizeErase(height, width);
remove (srcFn.c_str());
DeepTiledOutputFile file(srcFn.c_str(), header, 8);
cout << "tileSizeX " << file.tileXSize() << " tileSizeY " << file.tileYSize() << " ";
sampleCountWhole.resizeErase(file.numYLevels(), file.numXLevels());
for (int i = 0; i < sampleCountWhole.height(); i++)
for (int j = 0; j < sampleCountWhole.width(); j++)
sampleCountWhole[i][j].resizeErase(height, width);
DeepFrameBuffer frameBuffer;
int memOffset = dataWindow.min.x + dataWindow.min.y * width;
frameBuffer.insertSampleCountSlice (Slice (IMF::UINT,
(char *) (&sampleCount[0][0] - memOffset),
sizeof (unsigned int) * 1,
sizeof (unsigned int) * width,
1, 1,
0,
false,
false));
for (int i = 0; i < channelCount; i++)
{
PixelType type;
if (channelTypes[i] == 0)
type = IMF::UINT;
if (channelTypes[i] == 1)
type = IMF::HALF;
if (channelTypes[i] == 2)
type = IMF::FLOAT;
stringstream ss;
ss << i;
string str = ss.str();
int sampleSize;
if (channelTypes[i] == 0) sampleSize = sizeof (unsigned int);
if (channelTypes[i] == 1) sampleSize = sizeof (half);
if (channelTypes[i] == 2) sampleSize = sizeof (float);
int pointerSize = sizeof (char *);
frameBuffer.insert (str,
DeepSlice (type,
(char *) (&data[i][0][0] - memOffset),
pointerSize * 1,
pointerSize * width,
sampleSize,
1, 1,
0,
false,
false));
}
file.setFrameBuffer(frameBuffer);
cout << "writing " << flush;
for (int ly = 0; ly < file.numYLevels(); ly++)
for (int lx = 0; lx < file.numXLevels(); lx++)
{
Box2i dataWindowL = file.dataWindowForLevel(lx, ly);
//
// Bulk write (without relative coordinates).
//
for (int j = 0; j < file.numYTiles(ly); j++)
{
for (int i = 0; i < file.numXTiles(lx); i++)
{
Box2i box = file.dataWindowForTile(i, j, lx, ly);
for (int y = box.min.y; y <= box.max.y; y++)
for (int x = box.min.x; x <= box.max.x; x++)
{
int dwy = y - dataWindowL.min.y;
int dwx = x - dataWindowL.min.x;
sampleCount[dwy][dwx] = rand() % 10 + 1;
sampleCountWhole[ly][lx][dwy][dwx] = sampleCount[dwy][dwx];
for (int k = 0; k < channelCount; k++)
{
if (channelTypes[k] == 0)
data[k][dwy][dwx] = new unsigned int[sampleCount[dwy][dwx]];
if (channelTypes[k] == 1)
data[k][dwy][dwx] = new half[sampleCount[dwy][dwx]];
if (channelTypes[k] == 2)
data[k][dwy][dwx] = new float[sampleCount[dwy][dwx]];
for (int l = 0; l < sampleCount[dwy][dwx]; l++)
{
if (channelTypes[k] == 0)
((unsigned int*)data[k][dwy][dwx])[l] = (dwy * width + dwx) % 2049;
if (channelTypes[k] == 1)
((half*)data[k][dwy][dwx])[l] = (dwy* width + dwx) % 2049;
if (channelTypes[k] == 2)
((float*)data[k][dwy][dwx])[l] = (dwy * width + dwx) % 2049;
}
}
}
}
}
file.writeTiles(0, file.numXTiles(lx) - 1, 0, file.numYTiles(ly) - 1, lx, ly);
for (int i = 0; i < file.levelHeight(ly); i++)
for (int j = 0; j < file.levelWidth(lx); j++)
for (int k = 0; k < channelCount; k++)
{
if (channelTypes[k] == 0)
delete[] (unsigned int*) data[k][i][j];
if (channelTypes[k] == 1)
delete[] (half*) data[k][i][j];
if (channelTypes[k] == 2)
delete[] (float*) data[k][i][j];
}
}
}
void
checkValue (void* sampleRawData, int sampleCount, int channelType, int dwx, int dwy)
{
for (int l = 0; l < sampleCount; l++)
{
if (channelType == 0)
{
unsigned int* value = (unsigned int*)(sampleRawData);
if (value[l] != (dwy * width + dwx) % 2049)
cout << dwx << ", " << dwy << " error, should be "
<< (dwy * width + dwx) % 2049 << ", is " << value[l]
<< endl << flush;
assert (value[l] == (dwy * width + dwx) % 2049);
}
if (channelType == 1)
{
half* value = (half*)(sampleRawData);
if (value[l] != (dwy * width + dwx) % 2049)
cout << dwx << ", " << dwy << " error, should be "
<< (dwy * width + dwx) % 2049 << ", is " << value[l]
<< endl << flush;
assert (value[l] == (dwy * width + dwx) % 2049);
}
if (channelType == 2)
{
float* value = (float*)(sampleRawData);
if (value[l] != (dwy * width + dwx) % 2049)
cout << dwx << ", " << dwy << " error, should be "
<< (dwy * width + dwx) % 2049 << ", is " << value[l]
<< endl << flush;
assert (value[l] == (dwy * width + dwx) % 2049);
}
}
}
void
readFile (int channelCount, const std::string & cpyFn)
{
cout << "reading " << flush;
DeepTiledInputFile file (cpyFn.c_str(), 4);
const Header& fileHeader = file.header();
assert (fileHeader.displayWindow() == header.displayWindow());
assert (fileHeader.dataWindow() == header.dataWindow());
assert (fileHeader.pixelAspectRatio() == header.pixelAspectRatio());
assert (fileHeader.screenWindowCenter() == header.screenWindowCenter());
assert (fileHeader.screenWindowWidth() == header.screenWindowWidth());
assert (fileHeader.lineOrder() == header.lineOrder());
assert (fileHeader.compression() == header.compression());
assert (fileHeader.channels() == header.channels());
assert (fileHeader.type() == header.type());
assert (fileHeader.tileDescription() == header.tileDescription());
Array2D<unsigned int> localSampleCount;
localSampleCount.resizeErase(height, width);
Array<Array2D< void* > > data(channelCount);
for (int i = 0; i < channelCount; i++)
data[i].resizeErase(height, width);
DeepFrameBuffer frameBuffer;
int memOffset = dataWindow.min.x + dataWindow.min.y * width;
frameBuffer.insertSampleCountSlice (Slice (IMF::UINT,
(char *) (&localSampleCount[0][0] - memOffset),
sizeof (unsigned int) * 1,
sizeof (unsigned int) * width,
1, 1,
0,
false,
false));
for (int i = 0; i < channelCount; i++)
{
PixelType type;
if (channelTypes[i] == 0)
type = IMF::UINT;
if (channelTypes[i] == 1)
type = IMF::HALF;
if (channelTypes[i] == 2)
type = IMF::FLOAT;
stringstream ss;
ss << i;
string str = ss.str();
int sampleSize;
if (channelTypes[i] == 0) sampleSize = sizeof (unsigned int);
if (channelTypes[i] == 1) sampleSize = sizeof (half);
if (channelTypes[i] == 2) sampleSize = sizeof (float);
int pointerSize = sizeof (char *);
frameBuffer.insert (str,
DeepSlice (type,
(char *) (&data[i][0][0] - memOffset),
pointerSize * 1,
pointerSize * width,
sampleSize,
1, 1,
0,
false,
false));
}
file.setFrameBuffer(frameBuffer);
for (int ly = 0; ly < file.numYLevels(); ly++)
for (int lx = 0; lx < file.numXLevels(); lx++)
{
Box2i dataWindowL = file.dataWindowForLevel(lx, ly);
//
// Testing bulk read (without relative coordinates).
//
file.readPixelSampleCounts(0, file.numXTiles(lx) - 1, 0, file.numYTiles(ly) - 1, lx, ly);
for (int i = 0; i < file.numYTiles(ly); i++)
{
for (int j = 0; j < file.numXTiles(lx); j++)
{
Box2i box = file.dataWindowForTile(j, i, lx, ly);
for (int y = box.min.y; y <= box.max.y; y++)
for (int x = box.min.x; x <= box.max.x; x++)
{
int dwy = y - dataWindowL.min.y;
int dwx = x - dataWindowL.min.x;
assert(localSampleCount[dwy][dwx] == sampleCountWhole[ly][lx][dwy][dwx]);
for (int k = 0; k < channelTypes.size(); k++)
{
if (channelTypes[k] == 0)
data[k][dwy][dwx] = new unsigned int[localSampleCount[dwy][dwx]];
if (channelTypes[k] == 1)
data[k][dwy][dwx] = new half[localSampleCount[dwy][dwx]];
if (channelTypes[k] == 2)
data[k][dwy][dwx] = new float[localSampleCount[dwy][dwx]];
}
}
}
}
file.readTiles(0, file.numXTiles(lx) - 1, 0, file.numYTiles(ly) - 1, lx, ly);
for (int i = 0; i < file.levelHeight(ly); i++)
for (int j = 0; j < file.levelWidth(lx); j++)
for (int k = 0; k < channelCount; k++)
{
for (int l = 0; l < localSampleCount[i][j]; l++)
{
if (channelTypes[k] == 0)
{
unsigned int* value = (unsigned int*)(data[k][i][j]);
if (value[l] != (i * width + j) % 2049)
cout << j << ", " << i << " error, should be "
<< (i * width + j) % 2049 << ", is " << value[l]
<< endl << flush;
assert (value[l] == (i * width + j) % 2049);
}
if (channelTypes[k] == 1)
{
half* value = (half*)(data[k][i][j]);
if (value[l] != (i * width + j) % 2049)
cout << j << ", " << i << " error, should be "
<< (i * width + j) % 2049 << ", is " << value[l]
<< endl << flush;
assert (((half*)(data[k][i][j]))[l] == (i * width + j) % 2049);
}
if (channelTypes[k] == 2)
{
float* value = (float*)(data[k][i][j]);
if (value[l] != (i * width + j) % 2049)
cout << j << ", " << i << " error, should be "
<< (i * width + j) % 2049 << ", is " << value[l]
<< endl << flush;
assert (((float*)(data[k][i][j]))[l] == (i * width + j) % 2049);
}
}
}
for (int i = 0; i < file.levelHeight(ly); i++)
for (int j = 0; j < file.levelWidth(lx); j++)
for (int k = 0; k < channelCount; k++)
{
if (channelTypes[k] == 0)
delete[] (unsigned int*) data[k][i][j];
if (channelTypes[k] == 1)
delete[] (half*) data[k][i][j];
if (channelTypes[k] == 2)
delete[] (float*) data[k][i][j];
}
}
}
void
copyFile (const std::string & srcFn, const std::string & cpyFn)
{
cout << "copying " ;
cout.flush();
{
DeepTiledInputFile in_file (srcFn.c_str(),8);
remove (cpyFn.c_str());
DeepTiledOutputFile out_file (cpyFn.c_str(), in_file.header());
out_file.copyPixels (in_file);
}
// prevent accidentally reading souce instead of copy
remove (srcFn.c_str());
}
void
readCopyWriteTest (int channelCount, int testTimes, const std::string & tempDir)
{
cout << "Testing files with " << channelCount << " channels, using absolute coordinates "
<< testTimes << " times."
<< endl << flush;
std::string cpyFn = tempDir + "imf_test_copy_deep_tiled_copy.exr";
std::string srcFn = tempDir + "imf_test_copy_deep_tiled_source.exr";
for (int i = 0; i < testTimes; i++)
{
int compressionIndex = i % 3;
Compression compression;
switch (compressionIndex)
{
case 0:
compression = NO_COMPRESSION;
break;
case 1:
compression = RLE_COMPRESSION;
break;
case 2:
compression = ZIPS_COMPRESSION;
break;
}
generateRandomFile (channelCount, compression, srcFn);
copyFile (srcFn, cpyFn);
readFile (channelCount, cpyFn);
remove (cpyFn.c_str());
cout << endl << flush;
}
}
} // namespace
void testCopyDeepTiled (const std::string & tempDir)
{
try
{
cout << "Testing raw copy in DeepTiledInput/OutputFile " << endl;
srand(1);
int numThreads = ThreadPool::globalThreadPool().numThreads();
ThreadPool::globalThreadPool().setNumThreads(2);
readCopyWriteTest ( 3, 1, tempDir);
readCopyWriteTest ( 5, 2, tempDir);
readCopyWriteTest (11, 3, tempDir);
ThreadPool::globalThreadPool().setNumThreads (numThreads);
cout << "ok\n" << endl;
}
catch (const std::exception &e)
{
cerr << "ERROR -- caught exception: " << e.what() << endl;
assert (false);
}
}

View File

@ -0,0 +1,42 @@
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2011, 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.
//
///////////////////////////////////////////////////////////////////////////
#ifndef TESTCOPYDEEPTILED_H_
#define TESTCOPYDEEPTILED_H_
#include <string>
void testCopyDeepTiled (const std::string & tempDir);
#endif /* TESTCOPYDEEPTILED_H_ */

View File

@ -0,0 +1,980 @@
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2011, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
//
// Portions (c) 2012, Weta Digital Ltd
//
// 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
// Weta Digital nor any other ontributors 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 <iostream>
#include <string>
#include <vector>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "tmpDir.h"
#include "testCopyMultiPartFile.h"
#include <IlmThreadPool.h>
#include <ImfMultiPartInputFile.h>
#include <ImfMultiPartOutputFile.h>
#include <ImfArray.h>
#include <ImfChannelList.h>
#include <ImfOutputPart.h>
#include <ImfInputPart.h>
#include <ImfTiledOutputPart.h>
#include <ImfTiledInputPart.h>
#include <ImfDeepTiledOutputPart.h>
#include <ImfDeepScanLineOutputPart.h>
#include <ImfDeepTiledInputPart.h>
#include <ImfDeepScanLineInputPart.h>
#include <ImfPartType.h>
#include <ImfNamespace.h>
namespace IMF = OPENEXR_IMF_NAMESPACE;
using namespace IMF;
using namespace std;
using namespace IMATH_NAMESPACE;
using namespace ILMTHREAD_NAMESPACE;
namespace
{
const int height = 247;
const int width = 233;
vector<Header> headers;
vector<int> pixelTypes;
vector<int> partTypes;
vector<int> levelModes;
template <class T>
void fillPixels (Array2D<T> &ph, int width, int height)
{
ph.resizeErase(height, width);
for (int y = 0; y < height; ++y)
for (int x = 0; x < width; ++x)
{
//
// We do this because half cannot store number bigger than 2048 exactly.
//
ph[y][x] = (y * width + x) % 2049;
}
}
template <class T>
void fillPixels (Array2D<unsigned int>& sampleCount, Array2D<T*> &ph, int width, int height)
{
ph.resizeErase(height, width);
for (int y = 0; y < height; ++y)
for (int x = 0; x < width; ++x)
{
ph[y][x] = new T[sampleCount[y][x]];
for (int i = 0; i < sampleCount[y][x]; i++)
{
//
// We do this because half cannot store number bigger than 2048 exactly.
//
ph[y][x][i] = (y * width + x) % 2049;
}
}
}
void allocatePixels(int type, Array2D<unsigned int>& sampleCount,
Array2D<unsigned int*>& uintData, Array2D<float*>& floatData,
Array2D<half*>& halfData, int x1, int x2, int y1, int y2)
{
for (int y = y1; y <= y2; y++)
for (int x = x1; x <= x2; x++)
{
if (type == 0)
uintData[y][x] = new unsigned int[sampleCount[y][x]];
if (type == 1)
floatData[y][x] = new float[sampleCount[y][x]];
if (type == 2)
halfData[y][x] = new half[sampleCount[y][x]];
}
}
void allocatePixels(int type, Array2D<unsigned int>& sampleCount,
Array2D<unsigned int*>& uintData, Array2D<float*>& floatData,
Array2D<half*>& halfData, int width, int height)
{
allocatePixels(type, sampleCount, uintData, floatData, halfData, 0, width - 1, 0, height - 1);
}
void releasePixels(int type, Array2D<unsigned int*>& uintData, Array2D<float*>& floatData,
Array2D<half*>& halfData, int x1, int x2, int y1, int y2)
{
for (int y = y1; y <= y2; y++)
for (int x = x1; x <= x2; x++)
{
if (type == 0)
delete[] uintData[y][x];
if (type == 1)
delete[] floatData[y][x];
if (type == 2)
delete[] halfData[y][x];
}
}
void releasePixels(int type, Array2D<unsigned int*>& uintData, Array2D<float*>& floatData,
Array2D<half*>& halfData, int width, int height)
{
releasePixels(type, uintData, floatData, halfData, 0, width - 1, 0, height - 1);
}
template <class T>
bool checkPixels (Array2D<T> &ph, int lx, int rx, int ly, int ry, int width)
{
for (int y = ly; y <= ry; ++y)
for (int x = lx; x <= rx; ++x)
if (ph[y][x] != (y * width + x) % 2049)
{
cout << "value at " << x << ", " << y << ": " << ph[y][x]
<< ", should be " << (y * width + x) % 2049 << endl << flush;
return false;
}
return true;
}
template <class T>
bool checkPixels (Array2D<T> &ph, int width, int height)
{
return checkPixels<T> (ph, 0, width - 1, 0, height - 1, width);
}
template <class T>
bool checkPixels (Array2D<unsigned int>& sampleCount, Array2D<T*> &ph,
int lx, int rx, int ly, int ry, int width)
{
for (int y = ly; y <= ry; ++y)
for (int x = lx; x <= rx; ++x)
{
for (int i = 0; i < sampleCount[y][x]; i++)
{
if (ph[y][x][i] != (y * width + x) % 2049)
{
cout << "value at " << x << ", " << y << ", sample " << i << ": " << ph[y][x][i]
<< ", should be " << (y * width + x) % 2049 << endl << flush;
return false;
}
}
}
return true;
}
template <class T>
bool checkPixels (Array2D<unsigned int>& sampleCount, Array2D<T*> &ph, int width, int height)
{
return checkPixels<T> (sampleCount, ph, 0, width - 1, 0, height - 1, width);
}
bool checkSampleCount(Array2D<unsigned int>& sampleCount, int x1, int x2, int y1, int y2, int width)
{
for (int i = y1; i <= y2; i++)
for (int j = x1; j <= x2; j++)
{
if (sampleCount[i][j] != ((i * width) + j) % 10 + 1)
{
cout << "sample count at " << j << ", " << i << ": " << sampleCount[i][j]
<< ", should be " << (i * width + j) % 10 + 1 << endl << flush;
return false;
}
}
return true;
}
bool checkSampleCount(Array2D<unsigned int>& sampleCount, int width, int height)
{
return checkSampleCount(sampleCount, 0, width - 1, 0, height - 1, width);
}
void generateRandomHeaders(int partCount, vector<Header>& headers)
{
cout << "Generating headers and data" << endl << flush;
headers.clear();
for (int i = 0; i < partCount; i++)
{
Header header (width,
height,
1.f,
IMATH_NAMESPACE::V2f (0, 0),
1.f,
INCREASING_Y,
ZIPS_COMPRESSION);
int pixelType = rand() % 3;
int partType = rand() % 4;
pixelTypes[i] = pixelType;
partTypes[i] = partType;
stringstream ss;
ss << i;
header.setName(ss.str());
switch (pixelType)
{
case 0:
header.channels().insert("UINT", Channel(IMF::UINT));
break;
case 1:
header.channels().insert("FLOAT", Channel(IMF::FLOAT));
break;
case 2:
header.channels().insert("HALF", Channel(IMF::HALF));
break;
}
switch (partType)
{
case 0:
header.setType(SCANLINEIMAGE);
break;
case 1:
header.setType(TILEDIMAGE);
break;
case 2:
header.setType(DEEPSCANLINE);
break;
case 3:
header.setType(DEEPTILE);
break;
}
int tileX;
int tileY;
int levelMode;
if (partType == 1 || partType == 3)
{
tileX = rand() % width + 1;
tileY = rand() % height + 1;
levelMode = rand() % 3;
levelModes[i] = levelMode;
LevelMode lm;
switch (levelMode)
{
case 0:
lm = ONE_LEVEL;
break;
case 1:
lm = MIPMAP_LEVELS;
break;
case 2:
lm = RIPMAP_LEVELS;
break;
}
header.setTileDescription(TileDescription(tileX, tileY, lm));
}
int order = rand() % NUM_LINEORDERS;
if(partType==0 || partType ==2)
{
// can't write random scanlines
order = rand() % (NUM_LINEORDERS-1);
}
LineOrder l;
switch(order)
{
case 0 :
l = INCREASING_Y;
break;
case 1 :
l = DECREASING_Y;
break;
case 2 :
l = RANDOM_Y;
break;
}
header.lineOrder()=l;
if (partType == 0 || partType == 2)
{
cout << "pixelType = " << pixelType << " partType = " << partType
<< " line order =" << header.lineOrder() << endl << flush;
}
else
{
cout << "pixelType = " << pixelType << " partType = " << partType
<< " tile order =" << header.lineOrder()
<< " levelMode = " << levelModes[i] << endl << flush;
}
headers.push_back(header);
}
}
void setOutputFrameBuffer(FrameBuffer& frameBuffer, int pixelType,
Array2D<unsigned int>& uData, Array2D<float>& fData,
Array2D<half>& hData, int width)
{
switch (pixelType)
{
case 0:
frameBuffer.insert ("UINT",
Slice (IMF::UINT,
(char *) (&uData[0][0]),
sizeof (uData[0][0]) * 1,
sizeof (uData[0][0]) * width));
break;
case 1:
frameBuffer.insert ("FLOAT",
Slice (IMF::FLOAT,
(char *) (&fData[0][0]),
sizeof (fData[0][0]) * 1,
sizeof (fData[0][0]) * width));
break;
case 2:
frameBuffer.insert ("HALF",
Slice (IMF::HALF,
(char *) (&hData[0][0]),
sizeof (hData[0][0]) * 1,
sizeof (hData[0][0]) * width));
break;
}
}
void setOutputDeepFrameBuffer(DeepFrameBuffer& frameBuffer, int pixelType,
Array2D<unsigned int*>& uData, Array2D<float*>& fData,
Array2D<half*>& hData, int width)
{
switch (pixelType)
{
case 0:
frameBuffer.insert ("UINT",
DeepSlice (IMF::UINT,
(char *) (&uData[0][0]),
sizeof (uData[0][0]) * 1,
sizeof (uData[0][0]) * width,
sizeof (unsigned int)));
break;
case 1:
frameBuffer.insert ("FLOAT",
DeepSlice (IMF::FLOAT,
(char *) (&fData[0][0]),
sizeof (fData[0][0]) * 1,
sizeof (fData[0][0]) * width,
sizeof (float)));
break;
case 2:
frameBuffer.insert ("HALF",
DeepSlice (IMF::HALF,
(char *) (&hData[0][0]),
sizeof (hData[0][0]) * 1,
sizeof (hData[0][0]) * width,
sizeof (half)));
break;
}
}
void setInputFrameBuffer(FrameBuffer& frameBuffer, int pixelType,
Array2D<unsigned int>& uData, Array2D<float>& fData,
Array2D<half>& hData, int width, int height)
{
switch (pixelType)
{
case 0:
uData.resizeErase(height, width);
frameBuffer.insert ("UINT",
Slice (IMF::UINT,
(char *) (&uData[0][0]),
sizeof (uData[0][0]) * 1,
sizeof (uData[0][0]) * width,
1, 1,
0));
break;
case 1:
fData.resizeErase(height, width);
frameBuffer.insert ("FLOAT",
Slice (IMF::FLOAT,
(char *) (&fData[0][0]),
sizeof (fData[0][0]) * 1,
sizeof (fData[0][0]) * width,
1, 1,
0));
break;
case 2:
hData.resizeErase(height, width);
frameBuffer.insert ("HALF",
Slice (IMF::HALF,
(char *) (&hData[0][0]),
sizeof (hData[0][0]) * 1,
sizeof (hData[0][0]) * width,
1, 1,
0));
break;
}
}
void setInputDeepFrameBuffer(DeepFrameBuffer& frameBuffer, int pixelType,
Array2D<unsigned int*>& uData, Array2D<float*>& fData,
Array2D<half*>& hData, int width, int height)
{
switch (pixelType)
{
case 0:
uData.resizeErase(height, width);
frameBuffer.insert ("UINT",
DeepSlice (IMF::UINT,
(char *) (&uData[0][0]),
sizeof (uData[0][0]) * 1,
sizeof (uData[0][0]) * width,
sizeof (unsigned int)));
break;
case 1:
fData.resizeErase(height, width);
frameBuffer.insert ("FLOAT",
DeepSlice (IMF::FLOAT,
(char *) (&fData[0][0]),
sizeof (fData[0][0]) * 1,
sizeof (fData[0][0]) * width,
sizeof (float)));
break;
case 2:
hData.resizeErase(height, width);
frameBuffer.insert ("HALF",
DeepSlice (IMF::HALF,
(char *) (&hData[0][0]),
sizeof (hData[0][0]) * 1,
sizeof (hData[0][0]) * width,
sizeof (half)));
break;
}
}
void
generateRandomFile (int partCount, const std::string & srcFn)
{
//
// Init data.
//
Array2D<half> halfData;
Array2D<float> floatData;
Array2D<unsigned int> uintData;
Array2D<unsigned int> sampleCount;
Array2D<half*> deepHalfData;
Array2D<float*> deepFloatData;
Array2D<unsigned int*> deepUintData;
vector<GenericOutputFile*> outputfiles;
pixelTypes.resize(partCount);
partTypes.resize(partCount);
levelModes.resize(partCount);
//
// Generate headers and data.
//
generateRandomHeaders(partCount, headers);
remove(srcFn.c_str());
MultiPartOutputFile file(srcFn.c_str(), &headers[0],headers.size());
//
// Writing files.
//
cout << "Writing files " << flush;
//
// Pre-generating frameBuffers.
//
for (int i = 0; i < partCount; i++)
{
switch (partTypes[i])
{
case 0:
{
OutputPart part(file, i);
FrameBuffer frameBuffer;
fillPixels <unsigned int> (uintData, width, height);
fillPixels <float> (floatData, width, height);
fillPixels <half> (halfData, width, height);
setOutputFrameBuffer(frameBuffer, pixelTypes[i], uintData, floatData, halfData, width);
part.setFrameBuffer(frameBuffer);
part.writePixels(height);
break;
}
case 1:
{
TiledOutputPart part(file, i);
int numXLevels = part.numXLevels();
int numYLevels = part.numYLevels();
for (int xLevel = 0; xLevel < numXLevels; xLevel++)
for (int yLevel = 0; yLevel < numYLevels; yLevel++)
{
if (!part.isValidLevel(xLevel, yLevel))
continue;
int w = part.levelWidth(xLevel);
int h = part.levelHeight(yLevel);
FrameBuffer frameBuffer;
fillPixels <unsigned int> (uintData, w, h);
fillPixels <float> (floatData, w, h);
fillPixels <half> (halfData, w, h);
setOutputFrameBuffer(frameBuffer, pixelTypes[i],
uintData, floatData, halfData,
w);
part.setFrameBuffer(frameBuffer);
part.writeTiles(0, part.numXTiles(xLevel) - 1,
0, part.numYTiles(yLevel) - 1,
xLevel, yLevel);
}
break;
}
case 2:
{
DeepScanLineOutputPart part(file, i);
DeepFrameBuffer frameBuffer;
sampleCount.resizeErase(height, width);
for (int j = 0; j < height; j++)
for (int k = 0; k < width; k++)
sampleCount[j][k] = (j * width + k) % 10 + 1;
frameBuffer.insertSampleCountSlice (Slice (IMF::UINT,
(char *) (&sampleCount[0][0]),
sizeof (unsigned int) * 1,
sizeof (unsigned int) * width));
if (pixelTypes[i] == 0)
fillPixels <unsigned int> (sampleCount, deepUintData, width, height);
if (pixelTypes[i] == 1)
fillPixels <float> (sampleCount, deepFloatData, width, height);
if (pixelTypes[i] == 2)
fillPixels <half> (sampleCount, deepHalfData, width, height);
setOutputDeepFrameBuffer(frameBuffer, pixelTypes[i],
deepUintData, deepFloatData, deepHalfData,
width);
part.setFrameBuffer(frameBuffer);
part.writePixels(height);
releasePixels(pixelTypes[i], deepUintData, deepFloatData, deepHalfData, width, height);
break;
}
case 3:
{
DeepTiledOutputPart part(file, i);
int numXLevels = part.numXLevels();
int numYLevels = part.numYLevels();
for (int xLevel = 0; xLevel < numXLevels; xLevel++)
for (int yLevel = 0; yLevel < numYLevels; yLevel++)
{
if (!part.isValidLevel(xLevel, yLevel))
continue;
int w = part.levelWidth(xLevel);
int h = part.levelHeight(yLevel);
DeepFrameBuffer frameBuffer;
sampleCount.resizeErase(h, w);
for (int j = 0; j < h; j++)
for (int k = 0; k < w; k++)
sampleCount[j][k] = (j * w + k) % 10 + 1;
frameBuffer.insertSampleCountSlice (Slice (IMF::UINT,
(char *) (&sampleCount[0][0]),
sizeof (unsigned int) * 1,
sizeof (unsigned int) * w));
if (pixelTypes[i] == 0)
fillPixels <unsigned int> (sampleCount, deepUintData, w, h);
if (pixelTypes[i] == 1)
fillPixels <float> (sampleCount, deepFloatData, w, h);
if (pixelTypes[i] == 2)
fillPixels <half> (sampleCount, deepHalfData, w, h);
setOutputDeepFrameBuffer(frameBuffer, pixelTypes[i],
deepUintData, deepFloatData, deepHalfData,
w);
part.setFrameBuffer(frameBuffer);
part.writeTiles(0, part.numXTiles(xLevel) - 1,
0, part.numYTiles(yLevel) - 1,
xLevel, yLevel);
releasePixels(pixelTypes[i], deepUintData, deepFloatData, deepHalfData, w, h);
}
break;
}
}
}
}
void
readWholeFiles (const std::string & cpyFn)
{
Array2D<unsigned int> uData;
Array2D<float> fData;
Array2D<half> hData;
Array2D<unsigned int*> deepUData;
Array2D<float*> deepFData;
Array2D<half*> deepHData;
Array2D<unsigned int> sampleCount;
MultiPartInputFile file(cpyFn.c_str());
for (size_t i = 0; i < file.parts(); i++)
{
const Header& header = file.header(i);
assert (header.displayWindow() == headers[i].displayWindow());
assert (header.dataWindow() == headers[i].dataWindow());
assert (header.pixelAspectRatio() == headers[i].pixelAspectRatio());
assert (header.screenWindowCenter() == headers[i].screenWindowCenter());
assert (header.screenWindowWidth() == headers[i].screenWindowWidth());
assert (header.lineOrder() == headers[i].lineOrder());
assert (header.compression() == headers[i].compression());
assert (header.channels() == headers[i].channels());
assert (header.name() == headers[i].name());
assert (header.type() == headers[i].type());
}
cout << "Reading whole files " << flush;
//
// Shuffle part numbers.
//
vector<int> shuffledPartNumber;
for (int i = 0; i < headers.size(); i++)
shuffledPartNumber.push_back(i);
for (int i = 0; i < headers.size(); i++)
{
int a = rand() % headers.size();
int b = rand() % headers.size();
swap (shuffledPartNumber[a], shuffledPartNumber[b]);
}
//
// Start reading whole files.
//
int i;
int partNumber;
try
{
for (i = 0; i < headers.size(); i++)
{
partNumber = shuffledPartNumber[i];
switch (partTypes[partNumber])
{
case 0:
{
FrameBuffer frameBuffer;
setInputFrameBuffer(frameBuffer, pixelTypes[partNumber],
uData, fData, hData, width, height);
InputPart part(file, partNumber);
part.setFrameBuffer(frameBuffer);
part.readPixels(0, height - 1);
switch (pixelTypes[partNumber])
{
case 0:
assert(checkPixels<unsigned int>(uData, width, height));
break;
case 1:
assert(checkPixels<float>(fData, width, height));
break;
case 2:
assert(checkPixels<half>(hData, width, height));
break;
}
break;
}
case 1:
{
TiledInputPart part(file, partNumber);
int numXLevels = part.numXLevels();
int numYLevels = part.numYLevels();
for (int xLevel = 0; xLevel < numXLevels; xLevel++)
for (int yLevel = 0; yLevel < numYLevels; yLevel++)
{
if (!part.isValidLevel(xLevel, yLevel))
continue;
int w = part.levelWidth(xLevel);
int h = part.levelHeight(yLevel);
FrameBuffer frameBuffer;
setInputFrameBuffer(frameBuffer, pixelTypes[partNumber],
uData, fData, hData, w, h);
part.setFrameBuffer(frameBuffer);
int numXTiles = part.numXTiles(xLevel);
int numYTiles = part.numYTiles(yLevel);
part.readTiles(0, numXTiles - 1, 0, numYTiles - 1, xLevel, yLevel);
switch (pixelTypes[partNumber])
{
case 0:
assert(checkPixels<unsigned int>(uData, w, h));
break;
case 1:
assert(checkPixels<float>(fData, w, h));
break;
case 2:
assert(checkPixels<half>(hData, w, h));
break;
}
}
break;
}
case 2:
{
DeepScanLineInputPart part(file, partNumber);
DeepFrameBuffer frameBuffer;
sampleCount.resizeErase(height, width);
frameBuffer.insertSampleCountSlice (Slice (IMF::UINT,
(char *) (&sampleCount[0][0]),
sizeof (unsigned int) * 1,
sizeof (unsigned int) * width));
setInputDeepFrameBuffer(frameBuffer, pixelTypes[partNumber],
deepUData, deepFData, deepHData, width, height);
part.setFrameBuffer(frameBuffer);
part.readPixelSampleCounts(0, height - 1);
allocatePixels(pixelTypes[partNumber], sampleCount,
deepUData, deepFData, deepHData, width, height);
part.readPixels(0, height - 1);
switch (pixelTypes[partNumber])
{
case 0:
assert(checkPixels<unsigned int>(sampleCount, deepUData, width, height));
break;
case 1:
assert(checkPixels<float>(sampleCount, deepFData, width, height));
break;
case 2:
assert(checkPixels<half>(sampleCount, deepHData, width, height));
break;
}
releasePixels(pixelTypes[partNumber],
deepUData, deepFData, deepHData, width, height);
break;
}
case 3:
{
DeepTiledInputPart part(file, partNumber);
int numXLevels = part.numXLevels();
int numYLevels = part.numYLevels();
for (int xLevel = 0; xLevel < numXLevels; xLevel++)
for (int yLevel = 0; yLevel < numYLevels; yLevel++)
{
if (!part.isValidLevel(xLevel, yLevel))
continue;
int w = part.levelWidth(xLevel);
int h = part.levelHeight(yLevel);
DeepFrameBuffer frameBuffer;
sampleCount.resizeErase(h, w);
frameBuffer.insertSampleCountSlice (Slice (IMF::UINT,
(char *) (&sampleCount[0][0]),
sizeof (unsigned int) * 1,
sizeof (unsigned int) * w));
setInputDeepFrameBuffer(frameBuffer, pixelTypes[partNumber],
deepUData, deepFData, deepHData, w, h);
part.setFrameBuffer(frameBuffer);
int numXTiles = part.numXTiles(xLevel);
int numYTiles = part.numYTiles(yLevel);
part.readPixelSampleCounts(0, numXTiles - 1, 0, numYTiles - 1,
xLevel, yLevel);
allocatePixels(pixelTypes[partNumber], sampleCount,
deepUData, deepFData, deepHData, w, h);
part.readTiles(0, numXTiles - 1, 0, numYTiles - 1, xLevel, yLevel);
switch (pixelTypes[partNumber])
{
case 0:
assert(checkPixels<unsigned int>(sampleCount, deepUData, w, h));
break;
case 1:
assert(checkPixels<float>(sampleCount, deepFData, w, h));
break;
case 2:
assert(checkPixels<half>(sampleCount, deepHData, w, h));
break;
}
releasePixels(pixelTypes[partNumber],
deepUData, deepFData, deepHData, w, h);
}
break;
}
}
}
}
catch (...)
{
cout << "Error while reading part " << partNumber << endl << flush;
throw;
}
}
void
copyFile (const std::string & srcFn, const std::string & cpyFn)
{
cout << "copying ";
cout.flush();
MultiPartInputFile in(srcFn.c_str());
vector<Header> in_hdr(in.parts());
for(int i=0;i<in.parts();i++)
{
in_hdr[i]=in.header(i);
}
MultiPartOutputFile out(cpyFn.c_str(),&in_hdr[0],in.parts());
for(size_t i=0;i<in.parts();i++)
{
std::string part_type = in.header(i).type();
if(part_type == DEEPSCANLINE)
{
DeepScanLineInputPart partin(in,i);
DeepScanLineOutputPart partout(out,i);
partout.copyPixels(partin);
}
else if(part_type == DEEPTILE)
{
DeepTiledInputPart partin(in,i);
DeepTiledOutputPart partout(out,i);
partout.copyPixels(partin);
}else if(part_type== SCANLINEIMAGE)
{
InputPart partin(in,i);
OutputPart partout(out,i);
partout.copyPixels(partin);
}
else if(part_type==TILEDIMAGE)
{
TiledInputPart partin(in,i);
TiledOutputPart partout(out,i);
partout.copyPixels(partin);
}
}
}
void
testWriteCopyRead (int partNumber,
int runCount,
int randomReadCount,
const std::string & tempDir)
{
cout << "Testing file with " << partNumber << " part(s)." << endl << flush;
std::string srcFn = tempDir + "imf_test_copy_multipart_source.exr";
std::string cpyFn = tempDir + "imf_test_copy_multipart_copy.exr";
for (int i = 0; i < runCount; i++)
{
generateRandomFile (partNumber, srcFn);
copyFile (srcFn, cpyFn);
remove (srcFn.c_str());
readWholeFiles (cpyFn);
remove (cpyFn.c_str());
cout << endl << flush;
}
}
} // namespace
void testCopyMultiPartFile (const std::string & tempDir)
{
try
{
cout << "Testing copying multi-part files" << endl;
srand(1);
int numThreads = ThreadPool::globalThreadPool().numThreads();
ThreadPool::globalThreadPool().setNumThreads(4);
testWriteCopyRead ( 2, 20, 10, tempDir);
testWriteCopyRead ( 1, 10, 5, tempDir);
testWriteCopyRead ( 5, 4, 25, tempDir);
testWriteCopyRead (50, 1, 250, tempDir);
ThreadPool::globalThreadPool().setNumThreads(numThreads);
cout << "ok\n" << endl;
}
catch (const std::exception &e)
{
cerr << "ERROR -- caught exception: " << e.what() << endl;
assert (false);
}
}

View File

@ -0,0 +1,44 @@
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2011, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
//
// Portions (c) 2012, Weta Digital Ltd
//
// 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.
//
///////////////////////////////////////////////////////////////////////////
#ifndef TESTCOPYMULTIPARTFILE_H_
#define TESTCOPYMULTIPARTFILE_H_
#include <string>
void testCopyMultiPartFile (const std::string & tempDir);
#endif /* TESTCOPYMULTIPARTFILE_H_ */

View File

@ -0,0 +1,229 @@
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2002-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 <ImfOutputFile.h>
#include <ImfInputFile.h>
#include <ImfChannelList.h>
#include <ImfArray.h>
#include <half.h>
#include <stdio.h>
#include <assert.h>
using namespace OPENEXR_IMF_NAMESPACE;
using namespace std;
using namespace IMATH_NAMESPACE;
namespace {
void
fillPixels (Array2D<half> &ph, int width, int height)
{
for (int y = 0; y < height; ++y)
for (int x = 0; x < width; ++x)
ph[y][x] = sin (double (x)) + sin (y * 0.5);
}
void
writeCopyRead (const Array2D<half> &ph1,
const char fileName1[],
const char fileName2[],
int width,
int height,
int xOffset,
int yOffset,
Compression comp)
{
//
// Write the pixel data in ph1 to an image file using the
// specified compression type and subsampling rates.
// Then copy the image file using OutputFile::copyPixels()
// Read the pixel data back from the copied file verify
// that the data are the same as those in ph1.
//
cout << "compression " << comp << ":" << flush;
Header hdr ((Box2i (V2i (0, 0), // display window
V2i (width - 1, height -1))),
(Box2i (V2i (xOffset, yOffset), // data window
V2i (xOffset + width - 1, yOffset + height - 1))));
hdr.compression() = comp;
hdr.channels().insert ("H", Channel (HALF, 1, 1));
{
FrameBuffer fb;
fb.insert ("H", // name
Slice (HALF, // type
(char *) &ph1[-yOffset][-xOffset], // base
sizeof (ph1[0][0]), // xStride
sizeof (ph1[0][0]) * width, // yStride
1, // xSampling
1) // ySampling
);
cout << " writing" << flush;
remove (fileName1);
OutputFile out (fileName1, hdr);
out.setFrameBuffer (fb);
out.writePixels (height);
}
{
cout << " copying" << flush;
remove (fileName2);
InputFile in (fileName1);
OutputFile out (fileName2, in.header());
out.copyPixels (in);
}
{
cout << " reading" << flush;
InputFile in1 (fileName1);
InputFile in2 (fileName2);
const Box2i &dw = in2.header().dataWindow();
int w = dw.max.x - dw.min.x + 1;
int h = dw.max.y - dw.min.y + 1;
int dx = dw.min.x;
int dy = dw.min.y;
Array2D<half> ph1 (h, w);
Array2D<half> ph2 (h, w);
FrameBuffer fb1;
FrameBuffer fb2;
fb1.insert ("H", // name
Slice (HALF, // type
(char *) &ph1[-dy][-dx], // base
sizeof (ph1[0][0]), // xStride
sizeof (ph1[0][0]) * w, // yStride
1, // xSampling
1) // ySampling
);
fb2.insert ("H", // name
Slice (HALF, // type
(char *) &ph2[-dy][-dx], // base
sizeof (ph2[0][0]), // xStride
sizeof (ph2[0][0]) * w, // yStride
1, // xSampling
1) // ySampling
);
in1.setFrameBuffer (fb1);
in1.readPixels (dw.min.y, dw.max.y);
in2.setFrameBuffer (fb2);
in2.readPixels (dw.min.y, dw.max.y);
cout << " comparing" << flush;
assert (in2.header().displayWindow() == hdr.displayWindow());
assert (in2.header().dataWindow() == hdr.dataWindow());
assert (in2.header().pixelAspectRatio() == hdr.pixelAspectRatio());
assert (in2.header().screenWindowCenter() == hdr.screenWindowCenter());
assert (in2.header().screenWindowWidth() == hdr.screenWindowWidth());
assert (in2.header().lineOrder() == hdr.lineOrder());
assert (in2.header().compression() == hdr.compression());
assert (in2.header().channels() == hdr.channels());
for (int y = 0; y < h; ++y)
for (int x = 0; x < w; ++x)
assert (ph1[y][x] == ph2[y][x]);
}
remove (fileName1);
remove (fileName2);
cout << endl;
}
void
writeCopyRead (const std::string &tempDir, const Array2D<half> &ph, int w, int h, int dx, int dy)
{
std::string filename1 = tempDir + "imf_test_copy1.exr";
std::string filename2 = tempDir + "imf_test_copy2.exr";
for (int comp = 0; comp < NUM_COMPRESSION_METHODS; ++comp)
{
writeCopyRead (ph,
filename1.c_str(),
filename2.c_str(),
w, h,
dx, dy,
Compression (comp));
}
}
} // namespace
void
testCopyPixels (const std::string &tempDir)
{
try
{
cout << "Testing fast pixel copying" << endl;
const int W = 371;
const int H = 559;
const int DX = 17;
const int DY = 29;
Array2D<half> ph (H, W);
fillPixels (ph, W, H);
writeCopyRead (tempDir, ph, W, H, 0, 0);
writeCopyRead (tempDir, ph, W, H, 0, DY);
writeCopyRead (tempDir, ph, W, H, DX, 0);
writeCopyRead (tempDir, ph, W, H, DX, DY);
cout << "ok\n" << endl;
}
catch (const std::exception &e)
{
cerr << "ERROR -- caught exception: " << e.what() << endl;
assert (false);
}
}

View File

@ -0,0 +1,41 @@
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2002-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 <string>
void testCopyPixels (const std::string &tempDir);

View File

@ -0,0 +1,279 @@
///////////////////////////////////////////////////////////////////////////
//
// 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 <ImfOutputFile.h>
#include <ImfInputFile.h>
#include <ImfChannelList.h>
#include <ImfAttribute.h>
#include <ImfIntAttribute.h>
#include <ImfOpaqueAttribute.h>
#include <ImfArray.h>
#include <half.h>
#include <stdio.h>
#include <assert.h>
namespace IMF = OPENEXR_IMF_NAMESPACE;
using namespace IMF;
using namespace std;
using namespace IMATH_NAMESPACE;
//
// Definition of the custom GlorpAttribute type.
// Note that this must be in the same namespace as the definition
//
OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
struct Glorp
{
int a, b;
Glorp (int a = 0, int b = 0): a(a), b(b) {}
};
typedef TypedAttribute<Glorp> GlorpAttribute;
template <> const char *GlorpAttribute::staticTypeName ();
template <> void GlorpAttribute::writeValueTo (OStream &, int) const;
template <> void GlorpAttribute::readValueFrom (IStream &, int, int);
template <>
const char *
GlorpAttribute::staticTypeName ()
{
return "glorp";
}
template <>
void
GlorpAttribute::writeValueTo (OStream &os, int version) const
{
Xdr::write <StreamIO> (os, _value.a);
Xdr::write <StreamIO> (os, _value.b);
}
template <>
void
GlorpAttribute::readValueFrom (IStream &is, int size, int version)
{
Xdr::read <StreamIO> (is, _value.a);
Xdr::read <StreamIO> (is, _value.b);
}
OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
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
writeReadCustomAttr (const Array2D<float> &pf1,
const char fileName[],
int width,
int height)
{
//
// Tell the image file library about the custom GlorpAttribute type.
//
GlorpAttribute::registerAttributeType();
//
// Write an image file with two custom attributes:
// "custom1", of type IntAttribute, and
// "custom2", of type GlorpAttribute.
//
{
Header hdr (width, height);
hdr.insert ("custom1", IntAttribute (25));
hdr.insert ("custom2", GlorpAttribute (Glorp (4, 9)));
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);
}
//
// Tell the image file library to forget the GlorpAttribute type.
//
GlorpAttribute::unRegisterAttributeType();
//
// Read the header back from the file:
// "custom1" should come back as an IntAttribute, and
// "custom2" should come back as an OpaqueAttribute.
//
Header hdr;
{
cout << " reading" << flush;
InputFile in (fileName);
const IntAttribute *c1;
const OpaqueAttribute *c2;
c1 = in.header().findTypedAttribute <IntAttribute> ("custom1");
c2 = in.header().findTypedAttribute <OpaqueAttribute> ("custom2");
assert (c1 != 0 && c1->value() == 25);
assert (c2 != 0);
hdr = in.header();
}
//
// Tell the image file library to remember the custom GlorpAttribute type.
//
GlorpAttribute::registerAttributeType();
//
// Write a new image file using the header read back from
// the previous file file. The two custom attributes should
// be stored in the new file.
//
{
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 of the new image file:
// "custom1" should come back as an IntAttribute, and
// "custom2" should come back as a GlorpAttribute.
//
{
cout << " reading" << flush;
InputFile in (fileName);
const IntAttribute *c1;
const GlorpAttribute *c2;
c1 = in.header().findTypedAttribute <IntAttribute> ("custom1");
c2 = in.header().findTypedAttribute <GlorpAttribute> ("custom2");
assert (c1 != 0 && c1->value() == 25);
assert (c2 != 0 && c2->value().a == 4 && c2->value().b == 9);
}
remove (fileName);
cout << endl;
}
} // namespace
void
testCustomAttributes (const std::string &tempDir)
{
try
{
cout << "Testing custom 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_custom_attr.exr";
writeReadCustomAttr (pf, filename.c_str(), W, H);
cout << "ok\n" << endl;
}
catch (const std::exception &e)
{
cerr << "ERROR -- caught exception: " << e.what() << endl;
assert (false);
}
}

View File

@ -0,0 +1,41 @@
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2002-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 <string>
void testCustomAttributes (const std::string &tempDir);

View File

@ -0,0 +1,576 @@
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2011, 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 "testDeepScanLineBasic.h"
#include <assert.h>
#include <string.h>
#include <ImfDeepScanLineInputFile.h>
#include <ImfDeepScanLineOutputFile.h>
#include <ImfDeepFrameBuffer.h>
#include <ImfPartType.h>
#include <ImfChannelList.h>
#include <ImfArray.h>
#include <IlmThreadPool.h>
#include <stdlib.h>
#include <stdio.h>
#include <vector>
namespace IMF = OPENEXR_IMF_NAMESPACE;
using namespace IMF;
using namespace std;
using namespace IMATH_NAMESPACE;
using namespace ILMTHREAD_NAMESPACE;
namespace
{
const int width = 273;
const int height = 173;
const int minX = 10;
const int minY = 11;
const Box2i dataWindow(V2i(minX, minY), V2i(minX + width - 1, minY + height - 1));
const Box2i displayWindow(V2i(0, 0), V2i(minX + width * 2, minY + height * 2));
vector<int> channelTypes;
Array2D<unsigned int> sampleCount;
Header header;
void generateRandomFile (const std::string filename,
int channelCount,
Compression compression,
bool bulkWrite)
{
cout << "generating " << flush;
header = Header(displayWindow, dataWindow,
1,
IMATH_NAMESPACE::V2f (0, 0),
1,
INCREASING_Y,
compression);
cout << "compression " << compression << " " << flush;
//
// Add channels.
//
channelTypes.clear();
for (int i = 0; i < channelCount; i++)
{
int type = rand() % 3;
stringstream ss;
ss << i;
string str = ss.str();
if (type == 0)
header.channels().insert(str, Channel(IMF::UINT));
if (type == 1)
header.channels().insert(str, Channel(IMF::HALF));
if (type == 2)
header.channels().insert(str, Channel(IMF::FLOAT));
channelTypes.push_back(type);
}
header.setType(DEEPSCANLINE);
Array<Array2D< void* > > data(channelCount);
for (int i = 0; i < channelCount; i++)
data[i].resizeErase(height, width);
sampleCount.resizeErase(height, width);
remove (filename.c_str());
DeepScanLineOutputFile file(filename.c_str(), header, 8);
DeepFrameBuffer frameBuffer;
frameBuffer.insertSampleCountSlice (Slice (IMF::UINT, // type // 7
(char *) (&sampleCount[0][0]
- dataWindow.min.x
- dataWindow.min.y * width), // base
sizeof (unsigned int) * 1, // xStride
sizeof (unsigned int) * width)); // yStride
for (int i = 0; i < channelCount; i++)
{
PixelType type;
if (channelTypes[i] == 0)
type = IMF::UINT;
if (channelTypes[i] == 1)
type = IMF::HALF;
if (channelTypes[i] == 2)
type = IMF::FLOAT;
stringstream ss;
ss << i;
string str = ss.str();
int sampleSize;
if (channelTypes[i] == 0) sampleSize = sizeof (unsigned int);
if (channelTypes[i] == 1) sampleSize = sizeof (half);
if (channelTypes[i] == 2) sampleSize = sizeof (float);
int pointerSize = sizeof(char *);
frameBuffer.insert (str, // name // 6
DeepSlice (type, // type // 7
(char *) (&data[i][0][0]
- dataWindow.min.x
- dataWindow.min.y * width), // base // 8
pointerSize * 1, // xStride// 9
pointerSize * width, // yStride// 10
sampleSize)); // sampleStride
}
file.setFrameBuffer(frameBuffer);
cout << "writing " << flush;
if (bulkWrite)
{
cout << "bulk " << flush;
for (int i = 0; i < height; i++)
{
//
// Fill in data at the last minute.
//
for (int j = 0; j < width; j++)
{
sampleCount[i][j] = rand() % 10 + 1;
for (int k = 0; k < channelCount; k++)
{
if (channelTypes[k] == 0)
data[k][i][j] = new unsigned int[sampleCount[i][j]];
if (channelTypes[k] == 1)
data[k][i][j] = new half[sampleCount[i][j]];
if (channelTypes[k] == 2)
data[k][i][j] = new float[sampleCount[i][j]];
for (int l = 0; l < sampleCount[i][j]; l++)
{
if (channelTypes[k] == 0)
((unsigned int*)data[k][i][j])[l] = (i * width + j) % 2049;
if (channelTypes[k] == 1)
((half*)data[k][i][j])[l] = (i * width + j) % 2049;
if (channelTypes[k] == 2)
((float*)data[k][i][j])[l] = (i * width + j) % 2049;
}
}
}
}
file.writePixels(height);
}
else
{
cout << "per-line " << flush;
for (int i = 0; i < height; i++)
{
//
// Fill in data at the last minute.
//
for (int j = 0; j < width; j++)
{
sampleCount[i][j] = rand() % 10 + 1;
for (int k = 0; k < channelCount; k++)
{
if (channelTypes[k] == 0)
data[k][i][j] = new unsigned int[sampleCount[i][j]];
if (channelTypes[k] == 1)
data[k][i][j] = new half[sampleCount[i][j]];
if (channelTypes[k] == 2)
data[k][i][j] = new float[sampleCount[i][j]];
for (int l = 0; l < sampleCount[i][j]; l++)
{
if (channelTypes[k] == 0)
((unsigned int*)data[k][i][j])[l] = (i * width + j) % 2049;
if (channelTypes[k] == 1)
((half*)data[k][i][j])[l] = (i * width + j) % 2049;
if (channelTypes[k] == 2)
((float*)data[k][i][j])[l] = (i * width + j) % 2049;
}
}
}
file.writePixels(1);
}
}
for (int i = 0; i < height; i++)
for (int j = 0; j < width; j++)
for (int k = 0; k < channelCount; k++)
{
if (channelTypes[k] == 0)
delete[] (unsigned int*) data[k][i][j];
if (channelTypes[k] == 1)
delete[] (half*) data[k][i][j];
if (channelTypes[k] == 2)
delete[] (float*) data[k][i][j];
}
}
void readFile (const std::string & filename,
int channelCount,
bool bulkRead,
bool randomChannels)
{
if(randomChannels)
{
cout << " reading random channels " << flush;
}
else
{
cout << " reading all channels " << flush;
}
DeepScanLineInputFile file(filename.c_str(), 8);
const Header& fileHeader = file.header();
assert (fileHeader.displayWindow() == header.displayWindow());
assert (fileHeader.dataWindow() == header.dataWindow());
assert (fileHeader.pixelAspectRatio() == header.pixelAspectRatio());
assert (fileHeader.screenWindowCenter() == header.screenWindowCenter());
assert (fileHeader.screenWindowWidth() == header.screenWindowWidth());
assert (fileHeader.lineOrder() == header.lineOrder());
assert (fileHeader.compression() == header.compression());
assert (fileHeader.channels() == header.channels());
assert (fileHeader.type() == header.type());
Array2D<unsigned int> localSampleCount;
localSampleCount.resizeErase(height, width);
Array<Array2D< void* > > data(channelCount);
for (int i = 0; i < channelCount; i++)
data[i].resizeErase(height, width);
DeepFrameBuffer frameBuffer;
frameBuffer.insertSampleCountSlice (Slice (IMF::UINT, // type // 7
(char *) (&localSampleCount[0][0]
- dataWindow.min.x
- dataWindow.min.y * width), // base // 8)
sizeof (unsigned int) * 1, // xStride// 9
sizeof (unsigned int) * width)); // yStride// 10
vector<int> read_channel(channelCount);
int channels_added=0;
for (int i = 0; i < channelCount; i++)
{
if(randomChannels)
{
read_channel[i] = rand() % 2;
}
if(!randomChannels || read_channel[i]==1)
{
PixelType type;
if (channelTypes[i] == 0)
type = IMF::UINT;
if (channelTypes[i] == 1)
type = IMF::HALF;
if (channelTypes[i] == 2)
type = IMF::FLOAT;
stringstream ss;
ss << i;
string str = ss.str();
int sampleSize;
if (channelTypes[i] == 0) sampleSize = sizeof (unsigned int);
if (channelTypes[i] == 1) sampleSize = sizeof (half);
if (channelTypes[i] == 2) sampleSize = sizeof (float);
int pointerSize = sizeof (char *);
frameBuffer.insert (str, // name // 6
DeepSlice (type, // type // 7
(char *) (&data[i][0][0]
- dataWindow.min.x
- dataWindow.min.y * width), // base // 8)
pointerSize * 1, // xStride// 9
pointerSize * width, // yStride// 10
sampleSize)); // sampleStride
channels_added++;
}
}
if(channels_added==0)
{
cout << "skipping " <<flush;
return;
}
file.setFrameBuffer(frameBuffer);
if (bulkRead)
{
cout << "bulk " << flush;
file.readPixelSampleCounts(dataWindow.min.y, dataWindow.max.y);
for (int i = 0; i < dataWindow.max.y - dataWindow.min.y + 1; i++)
{
int y = i + dataWindow.min.y;
for (int j = 0; j < width; j++)
assert(localSampleCount[i][j] == sampleCount[i][j]);
for (int j = 0; j < width; j++)
{
for (int k = 0; k < channelCount; k++)
{
if(!randomChannels || read_channel[k]==1)
{
if (channelTypes[k] == 0)
data[k][i][j] = new unsigned int[localSampleCount[i][j]];
if (channelTypes[k] == 1)
data[k][i][j] = new half[localSampleCount[i][j]];
if (channelTypes[k] == 2)
data[k][i][j] = new float[localSampleCount[i][j]];
}
}
}
}
file.readPixels(dataWindow.min.y, dataWindow.max.y);
}
else
{
cout << "per-line " << flush;
for (int i = 0; i < dataWindow.max.y - dataWindow.min.y + 1; i++)
{
int y = i + dataWindow.min.y;
file.readPixelSampleCounts(y);
for (int j = 0; j < width; j++)
assert(localSampleCount[i][j] == sampleCount[i][j]);
for (int j = 0; j < width; j++)
{
for (int k = 0; k < channelCount; k++)
{
if( !randomChannels || read_channel[k]==1)
{
if (channelTypes[k] == 0)
data[k][i][j] = new unsigned int[localSampleCount[i][j]];
if (channelTypes[k] == 1)
data[k][i][j] = new half[localSampleCount[i][j]];
if (channelTypes[k] == 2)
data[k][i][j] = new float[localSampleCount[i][j]];
}
}
}
file.readPixels(y);
}
}
for (int i = 0; i < height; i++)
for (int j = 0; j < width; j++)
for (int k = 0; k < channelCount; k++)
{
if( !randomChannels || read_channel[k]==1 )
{
for (int l = 0; l < sampleCount[i][j]; l++)
{
if (channelTypes[k] == 0)
{
unsigned int* value = (unsigned int*)(data[k][i][j]);
if (value[l] != (i * width + j) % 2049)
cout << j << ", " << i << " error, should be "
<< (i * width + j) % 2049 << ", is " << value[l]
<< endl << flush;
assert (value[l] == (i * width + j) % 2049);
}
if (channelTypes[k] == 1)
{
half* value = (half*)(data[k][i][j]);
if (value[l] != (i * width + j) % 2049)
cout << j << ", " << i << " error, should be "
<< (i * width + j) % 2049 << ", is " << value[l]
<< endl << flush;
assert (((half*)(data[k][i][j]))[l] == (i * width + j) % 2049);
}
if (channelTypes[k] == 2)
{
float* value = (float*)(data[k][i][j]);
if (value[l] != (i * width + j) % 2049)
cout << j << ", " << i << " error, should be "
<< (i * width + j) % 2049 << ", is " << value[l]
<< endl << flush;
assert (((float*)(data[k][i][j]))[l] == (i * width + j) % 2049);
}
}
}
}
for (int i = 0; i < height; i++)
for (int j = 0; j < width; j++)
for (int k = 0; k < channelCount; k++)
{
if( !randomChannels || read_channel[k]==1 )
{
if (channelTypes[k] == 0)
delete[] (unsigned int*) data[k][i][j];
if (channelTypes[k] == 1)
delete[] (half*) data[k][i][j];
if (channelTypes[k] == 2)
delete[] (float*) data[k][i][j];
}
}
}
void readWriteTest(const std::string & tempDir, int channelCount, int testTimes)
{
cout << "Testing files with " << channelCount << " channels " << testTimes << " times."
<< endl << flush;
std::string filename = tempDir + "imf_test_deep_scanline_basic.exr";
for (int i = 0; i < testTimes; i++)
{
int compressionIndex = i % 3;
Compression compression;
switch (compressionIndex)
{
case 0:
compression = NO_COMPRESSION;
break;
case 1:
compression = RLE_COMPRESSION;
break;
case 2:
compression = ZIPS_COMPRESSION;
break;
}
generateRandomFile (filename, channelCount, compression, false);
readFile (filename, channelCount, false , false );
if (channelCount>1)
readFile (filename, channelCount, false , true );
remove (filename.c_str());
cout << endl << flush;
generateRandomFile (filename, channelCount, compression, true);
readFile (filename, channelCount, true , false );
if (channelCount>1)
readFile (filename, channelCount, true , true );
remove (filename.c_str());
cout << endl << flush;
}
}
void testCompressionTypeChecks()
{
Header h;
h.setType(DEEPTILE);
h.compression()=NO_COMPRESSION;
h.sanityCheck();
h.compression()=ZIPS_COMPRESSION;
h.sanityCheck();
h.compression()=RLE_COMPRESSION;
h.sanityCheck();
cout << "accepted valid compression types\n";
//
// these should fail
//
try{
h.compression()=ZIP_COMPRESSION;
h.sanityCheck();
assert(false);
}catch(...){
cout << "correctly identified bad compression setting (zip)\n";
}
try{
h.compression()=B44_COMPRESSION;
h.sanityCheck();
assert(false);
}catch(...){
cout << "correctly identified bad compression setting (b44)\n";
}
try{
h.compression()=B44A_COMPRESSION;
h.sanityCheck();
assert(false);
}catch(...) {
cout << "correctly identified bad compression setting (b44a)\n";
}
try{
h.compression()=PXR24_COMPRESSION;
h.sanityCheck();
assert(false);
}catch(...) {
cout << "correctly identified bad compression setting (pxr24)\n";
}
return;
}
}; // namespace
void testDeepScanLineBasic (const std::string &tempDir)
{
try
{
cout << "\n\nTesting the DeepScanLineInput/OutputFile for basic use:\n" << endl;
srand(1);
int numThreads = ThreadPool::globalThreadPool().numThreads();
ThreadPool::globalThreadPool().setNumThreads(4);
testCompressionTypeChecks();
readWriteTest (tempDir, 1, 100);
readWriteTest (tempDir, 3, 50);
readWriteTest (tempDir,10, 10);
ThreadPool::globalThreadPool().setNumThreads(numThreads);
cout << "ok\n" << endl;
}
catch (const std::exception &e)
{
cerr << "ERROR -- caught exception: " << e.what() << endl;
assert (false);
}
}

View File

@ -0,0 +1,42 @@
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2011, 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.
//
///////////////////////////////////////////////////////////////////////////
#ifndef TESTDEEPSCANLINEBASIC_H_
#define TESTDEEPSCANLINEBASIC_H_
#include <string>
void testDeepScanLineBasic (const std::string &tempDir);
#endif /* TESTDEEPSCANLINEBASIC_H_ */

View File

@ -0,0 +1,438 @@
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2011, 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 "testDeepScanLineBasic.h"
#include "ImfDeepScanLineInputFile.h"
#include "ImfDeepScanLineOutputFile.h"
#include "ImfDeepFrameBuffer.h"
#include "ImfPartType.h"
#include "ImfChannelList.h"
#include "ImfArray.h"
#include "IlmThreadPool.h"
#include "tmpDir.h"
#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <vector>
namespace IMF = OPENEXR_IMF_NAMESPACE;
using namespace IMF;
using namespace std;
using namespace IMATH_NAMESPACE;
using namespace ILMTHREAD_NAMESPACE;
namespace
{
const int width = 8193;
const int height = 1;
const int minX = 0;
const int minY = 0;
const long numGib = 1; // number of GiB to allocate for huge test
const Box2i dataWindow(V2i(minX, minY), V2i(minX + width - 1, minY + height - 1));
const Box2i displayWindow(V2i(0, 0), V2i(minX + width * 2, minY + height * 2));
vector<int> channelTypes;
Array2D<unsigned int> sampleCount;
vector<unsigned char> storage; // actual pixel storage for entire image (effectively)
Header header;
void
generateRandomFile (int channelCount,
Compression compression,
bool random_channel_data,
const std::string & fn)
{
cout << "generating ... " << flush;
header = Header(displayWindow, dataWindow,
1,
IMATH_NAMESPACE::V2f (0, 0),
1,
INCREASING_Y,
compression);
cout << "compression " << compression << " " << flush;
//
// Add channels.
//
channelTypes.clear();
for (int i = 0; i < channelCount; i++)
{
int type = rand() % 3;
stringstream ss;
ss << i;
string str = ss.str();
if (type == 0)
header.channels().insert(str, Channel(IMF::UINT));
if (type == 1)
header.channels().insert(str, Channel(IMF::HALF));
if (type == 2)
header.channels().insert(str, Channel(IMF::FLOAT));
channelTypes.push_back(type);
}
header.setType(DEEPSCANLINE);
Array<Array2D< void* > > data(channelCount);
for (int i = 0; i < channelCount; i++)
data[i].resizeErase(height, width);
sampleCount.resizeErase(height, width);
remove (fn.c_str());
DeepScanLineOutputFile file (fn.c_str(), header, 8);
DeepFrameBuffer frameBuffer;
frameBuffer.insertSampleCountSlice (Slice (IMF::UINT, // type // 7
(char *) (&sampleCount[0][0]
- dataWindow.min.x
- dataWindow.min.y * width), // base // 8
sizeof (unsigned int) * 1, // xStride// 9
sizeof (unsigned int) * width)); // yStride// 10
// count total size of all pixels
Int64 bytes_per_sample = 0;
for (int i = 0; i < channelCount; i++)
{
PixelType type;
if (channelTypes[i] == 0)
type = IMF::UINT;
if (channelTypes[i] == 1)
type = IMF::HALF;
if (channelTypes[i] == 2)
type = IMF::FLOAT;
stringstream ss;
ss << i;
string str = ss.str();
int sampleSize;
if (channelTypes[i] == 0) sampleSize = sizeof (unsigned int);
if (channelTypes[i] == 1) sampleSize = sizeof (half);
if (channelTypes[i] == 2) sampleSize = sizeof (float);
int pointerSize = sizeof(char *);
bytes_per_sample+=sampleSize;
frameBuffer.insert (str, // name // 6
DeepSlice (type, // type // 7
(char *) (&data[i][0][0]
- dataWindow.min.x
- dataWindow.min.y * width), // base // 8
pointerSize * 1, // xStride// 9
pointerSize * width, // yStride// 10
sampleSize)); // sampleStride
}
file.setFrameBuffer(frameBuffer);
cout << "writing file " << endl;
Int64 total_number_of_samples = 0;
// compute ideal number of samples per pixel assuming we want abotut 5GiB of data
// int samples_per_pixel = int(5l*1024l*1024l*1024l/Int64(width*height)) / bytes_per_sample;
// compute ideal number of samples per pixel assuming we want abotut 15GiB of data
int samples_per_pixel = int(numGib*1024l*1024l*1024l/Int64(width*height)) / bytes_per_sample;
cout << " generating approx. " << samples_per_pixel << " samples per pixel\n";
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
sampleCount[i][j] = (rand() % 4000) + (samples_per_pixel-2000);
total_number_of_samples += sampleCount[i][j];
}
}
cout << " total number of samples: " << total_number_of_samples << std::endl;
cout << " storage required: " << total_number_of_samples*bytes_per_sample << " bytes (" <<
((total_number_of_samples*bytes_per_sample)>>30) << "GiB)" << std::endl;
//
// storage layout scheme:
// [Pixel1: [Channel1: [Sample1 Sample2 Sample...] ] [Channel2: [Sample1 Sample2...] ] [Channnel...] ]
// [Pixel2: [Channel1: [Sample1 Sample2 Sample...] ] [Channel2: [Sample1 Sample2...] ] [Channnel...] ]
// [Pixel...]
//
storage.resize(total_number_of_samples*bytes_per_sample);
Int64 write_pointer=0;
for (int i = 0; i < height; i++)
{
//
// Fill in data at the last minute.
//
for (int j = 0; j < width; j++)
{
for (int k = 0; k < channelCount; k++)
{
data[k][i][j]=&storage[write_pointer];
if (channelTypes[k] == 0)
write_pointer+=sizeof(int)*sampleCount[i][j];
if (channelTypes[k] == 1)
write_pointer+=sizeof(half)*sampleCount[i][j];
if (channelTypes[k] == 2)
write_pointer+=sizeof(float)*sampleCount[i][j];
if(random_channel_data)
{
for (int l = 0; l < sampleCount[i][j]; l++)
{
if (channelTypes[k] == 0)
((unsigned int*)data[k][i][j])[l] = rand();
if (channelTypes[k] == 1)
((half*)data[k][i][j])[l] = rand()/RAND_MAX;
if (channelTypes[k] == 2)
((float*)data[k][i][j])[l] = rand()/RAND_MAX;
}
}
else
{
for (int l = 0; l < sampleCount[i][j]; l++)
{
if (channelTypes[k] == 0)
((unsigned int*)data[k][i][j])[l] = (i * width + j) % 2049;
if (channelTypes[k] == 1)
((half*)data[k][i][j])[l] = (i * width + j) % 2049;
if (channelTypes[k] == 2)
((float*)data[k][i][j])[l] = (i * width + j) % 2049;
}
}
}
}
}
cout << " data prepared, writing ...";
file.writePixels(height);
cout << " data written\n";
}
void
readFile (int channelCount, bool bulkRead, const std::string & fn)
{
cout << "reading \n" << flush;
DeepScanLineInputFile file (fn.c_str(), 8);
const Header& fileHeader = file.header();
assert (fileHeader.displayWindow() == header.displayWindow());
assert (fileHeader.dataWindow() == header.dataWindow());
assert (fileHeader.pixelAspectRatio() == header.pixelAspectRatio());
assert (fileHeader.screenWindowCenter() == header.screenWindowCenter());
assert (fileHeader.screenWindowWidth() == header.screenWindowWidth());
assert (fileHeader.lineOrder() == header.lineOrder());
assert (fileHeader.compression() == header.compression());
assert (fileHeader.channels() == header.channels());
assert (fileHeader.type() == header.type());
Array2D<unsigned int> localSampleCount;
localSampleCount.resizeErase(height, width);
Array<Array2D< void* > > data(channelCount);
for (int i = 0; i < channelCount; i++)
data[i].resizeErase(height, width);
DeepFrameBuffer frameBuffer;
frameBuffer.insertSampleCountSlice (Slice (IMF::UINT, // type // 7
(char *) (&localSampleCount[0][0]
- dataWindow.min.x
- dataWindow.min.y * width), // base // 8)
sizeof (unsigned int) * 1, // xStride// 9
sizeof (unsigned int) * width)); // yStride// 10
Int64 bytes_per_sample=0;
for (int i = 0; i < channelCount; i++)
{
PixelType type;
if (channelTypes[i] == 0)
type = IMF::UINT;
if (channelTypes[i] == 1)
type = IMF::HALF;
if (channelTypes[i] == 2)
type = IMF::FLOAT;
stringstream ss;
ss << i;
string str = ss.str();
int sampleSize;
if (channelTypes[i] == 0) sampleSize = sizeof (unsigned int);
if (channelTypes[i] == 1) sampleSize = sizeof (half);
if (channelTypes[i] == 2) sampleSize = sizeof (float);
int pointerSize = sizeof (char *);
bytes_per_sample+=sampleSize;
frameBuffer.insert (str, // name // 6
DeepSlice (type, // type // 7
(char *) (&data[i][0][0]
- dataWindow.min.x
- dataWindow.min.y * width), // base // 8)
pointerSize * 1, // xStride// 9
pointerSize * width, // yStride// 10
sampleSize)); // sampleStride
}
file.setFrameBuffer(frameBuffer);
file.readPixelSampleCounts(dataWindow.min.y, dataWindow.max.y);
Int64 total_pixel_count = 0;
for (int i = 0; i < dataWindow.max.y - dataWindow.min.y + 1; i++)
{
int y = i + dataWindow.min.y;
for (int j = 0; j < width; j++)
{
assert(localSampleCount[i][j] == sampleCount[i][j]);
total_pixel_count += localSampleCount[i][j];
}
}
vector<char> localstorage(total_pixel_count*bytes_per_sample);
Int64 write_pointer=0;
for (int i = 0; i < height; i++)
{
//
// Fill in data at the last minute.
//
for (int j = 0; j < width; j++)
{
for (int k = 0; k < channelCount; k++)
{
data[k][i][j]=&localstorage[write_pointer];
if (channelTypes[k] == 0)
write_pointer+=sizeof(int)*sampleCount[i][j];
if (channelTypes[k] == 1)
write_pointer+=sizeof(half)*sampleCount[i][j];
if (channelTypes[k] == 2)
write_pointer+=sizeof(float)*sampleCount[i][j];
}
}
}
cout << "reading image data ... " << flush;
file.readPixels(dataWindow.min.y, dataWindow.max.y);
cout << " image read \n" << flush;
}
void
readWriteTest (int channelCount,
int testTimes,
bool random_channel_data,
const std::string & fn)
{
cout << "Testing files with " << channelCount << " channels " << testTimes << " times."
<< endl << flush;
for (int i = 0; i < testTimes; i++)
{
int compressionIndex = i % 3;
Compression compression;
switch (compressionIndex)
{
case 0:
compression = NO_COMPRESSION;
break;
case 1:
compression = RLE_COMPRESSION;
break;
case 2:
compression = ZIPS_COMPRESSION;
break;
}
generateRandomFile (channelCount, compression, random_channel_data, fn);
readFile (channelCount, false, fn);
remove (fn.c_str());
}
}
}; // namespace
void testDeepScanLineHuge (const std::string & tempDir)
{
try
{
cout << "\n\nTesting the DeepScanLineInput/OutputFile for huge scanlines:\n" << endl;
srand(1);
std::string fn = tempDir + "imf_test_deep_scanline_huge.exr";
readWriteTest (10, 5 , false, fn);
readWriteTest (10, 5 , true, fn);
cout << "ok\n" << endl;
}
catch (const std::exception &e)
{
cerr << "ERROR -- caught exception: " << e.what() << endl;
assert (false);
}
}

View File

@ -0,0 +1,40 @@
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2011, 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.
//
///////////////////////////////////////////////////////////////////////////
#ifndef TESTDEEPSCANLINEHUGE_H_
#define TESTDEEPSCANLINEHUGE_H_
void testDeepScanLineHuge (const std::string & tempDir);
#endif /* TESTDEEPSCANLINEHUGE_H_ */

View File

@ -0,0 +1,229 @@
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2012, Weta Digital Ltd
//
// 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 Weta Digital 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 "testCompositeDeepScanLine.h"
#include <ImfDeepScanLineOutputFile.h>
#include <ImfDeepScanLineInputFile.h>
#include <ImfChannelList.h>
#include <ImfPartType.h>
#include <ImfDeepFrameBuffer.h>
#include <ImfHeader.h>
#include <ImfNamespace.h>
#include <vector>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "tmpDir.h"
namespace{
const char source_filename[] = IMF_TMP_DIR "imf_test_multiple_read.exr";
using std::cout;
using std::endl;
using std::flush;
using std::vector;
using OPENEXR_IMF_NAMESPACE::Header;
using OPENEXR_IMF_NAMESPACE::Channel;
using OPENEXR_IMF_NAMESPACE::UINT;
using OPENEXR_IMF_NAMESPACE::FLOAT;
using OPENEXR_IMF_NAMESPACE::DEEPSCANLINE;
using OPENEXR_IMF_NAMESPACE::ZIPS_COMPRESSION;
using OPENEXR_IMF_NAMESPACE::DeepScanLineOutputFile;
using OPENEXR_IMF_NAMESPACE::DeepScanLineInputFile;
using OPENEXR_IMF_NAMESPACE::DeepFrameBuffer;
using OPENEXR_IMF_NAMESPACE::Slice;
using OPENEXR_IMF_NAMESPACE::DeepSlice;
using IMATH_NAMESPACE::Box2i;
namespace IMF = OPENEXR_IMF_NAMESPACE;
static void
make_file(const char * filename)
{
int width=4;
int height=48;
//
// create a deep output file of widthxheight, where each pixel has 'y' samples,
// each with value 'x'
//
Header header( width,height);
header.channels().insert("Z", Channel(IMF::FLOAT));
header.compression()=ZIPS_COMPRESSION;
header.setType(DEEPSCANLINE);
remove (filename);
DeepScanLineOutputFile file(filename, header);
unsigned int sample_count;
float sample;
float * sample_ptr = &sample;
DeepFrameBuffer fb;
fb.insertSampleCountSlice(Slice(IMF::UINT,(char *)&sample_count));
fb.insert("Z",DeepSlice(IMF::FLOAT,(char *) &sample_ptr));
file.setFrameBuffer(fb);
for( int y=0 ; y < height ; y++ )
{
//
// ensure each scanline contains a different number of samples,
// with different values. We don't care that each sample has the same
// value, or that each pixel on the scanline is identical
//
sample_count = y;
sample = y+100.0;
file.writePixels(1);
}
}
static void read_file(const char * filename)
{
DeepScanLineInputFile file(filename);
Box2i datawin = file.header().dataWindow();
int width = datawin.size().x+1;
int height = datawin.size().y+1;
int x_offset = datawin.min.x;
int y_offset = datawin.min.y;
const char * channel = file.header().channels().begin().name();
vector<unsigned int> samplecounts(width);
vector<float *> sample_pointers(width);
vector<float> samples;
DeepFrameBuffer fb;
fb.insertSampleCountSlice(Slice(IMF::UINT,(char *) (&samplecounts[0]-x_offset) , sizeof(unsigned int)));
fb.insert( channel, DeepSlice(IMF::FLOAT,(char *) (&sample_pointers[0]-x_offset) , sizeof(float *),0,sizeof(float)) );
file.setFrameBuffer(fb);
for(int count=0;count<4000;count++)
{
int row = rand() % height + y_offset;
//
// read row y (at random)
//
file.readPixelSampleCounts(row,row);
//
// check that's correct, and also resize samples array
//
int total_samples = 0;
for(int i=0;i<width;i++)
{
if( samplecounts[i]!= row)
{
cout << i << ", " << row << " error, sample counts hould be "
<< row << ", is " << samplecounts[i]
<< endl << flush;
}
assert (samplecounts[i]== row);
total_samples+=samplecounts[i];
}
samples.resize(total_samples);
//
// set pointers to point to the correct place
//
int total=0;
for(int i=0 ; i<width && total < total_samples ; i++)
{
sample_pointers[i] = &samples[total];
total+=samplecounts[i];
}
//
// read channel
//
file.readPixels(row,row);
//
// check
//
for(int i=0;i<total_samples;i++)
{
if(samples[i]!=row+100.f)
{
cout << " sample " << i << " on row " << row << " error, shuold be "
<< 100.f+row << " got " << samples[i] << endl;
cout << flush;
}
assert(samples[i]==row+100.f);
}
}
}
}
void
testDeepScanLineMultipleRead(const std::string & tempDir)
{
cout << "\n\nTesting random re-reads from deep scanline file:\n" << endl;
std::string source_filename = tempDir + "imf_test_multiple_read";
srand(1);
make_file(source_filename.c_str());
read_file(source_filename.c_str());
remove(source_filename.c_str());
cout << " ok\n" << endl;
}

View File

@ -0,0 +1,41 @@
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2012, Weta Digital Ltd
//
// 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 Weta Digital 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.
//
///////////////////////////////////////////////////////////////////////////
#ifndef TESTDEEPSCANLINEMULTIPLEREAD_H_
#define TESTDEEPSCANLINEMULTIPLEREAD_H_
#include <string>
void testDeepScanLineMultipleRead(const std::string & tempDir);
#endif /* DEEPSCANLINEMULTIPLEREAD_H_ */

View File

@ -0,0 +1,761 @@
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2011, 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 "testDeepTiledBasic.h"
#include <assert.h>
#include <string.h>
#include <ImfDeepTiledInputFile.h>
#include <ImfDeepTiledOutputFile.h>
#include <ImfChannelList.h>
#include <ImfArray.h>
#include <ImfPartType.h>
#include <IlmThreadPool.h>
#include <stdio.h>
#include <stdlib.h>
#include <vector>
namespace IMF = OPENEXR_IMF_NAMESPACE;
using namespace IMF;
using namespace IMATH_NAMESPACE;
using namespace ILMTHREAD_NAMESPACE;
using namespace std;
namespace
{
const int width = 273;
const int height = 169;
const int minX = 10;
const int minY = 11;
const Box2i dataWindow(V2i(minX, minY), V2i(minX + width - 1, minY + height - 1));
const Box2i displayWindow(V2i(0, 0), V2i(minX + width * 2, minY + height * 2));
vector<int> channelTypes;
Array2D< Array2D<unsigned int> > sampleCountWhole;
Header header;
void generateRandomFile (int channelCount,
Compression compression,
bool bulkWrite,
bool relativeCoords,
const std::string & filename)
{
if (relativeCoords)
assert(bulkWrite == false);
cout << "generating " << flush;
header = Header(displayWindow, dataWindow,
1,
IMATH_NAMESPACE::V2f (0, 0),
1,
INCREASING_Y,
compression);
cout << "compression " << compression << " " << flush;
//
// Add channels.
//
channelTypes.clear();
for (int i = 0; i < channelCount; i++)
{
int type = rand() % 3;
stringstream ss;
ss << i;
string str = ss.str();
if (type == 0)
header.channels().insert(str, Channel(IMF::UINT));
if (type == 1)
header.channels().insert(str, Channel(IMF::HALF));
if (type == 2)
header.channels().insert(str, Channel(IMF::FLOAT));
channelTypes.push_back(type);
}
header.setType(DEEPTILE);
header.setTileDescription(
TileDescription(rand() % width + 1, rand() % height + 1, RIPMAP_LEVELS));
//
// Set up the output file
//
remove (filename.c_str());
DeepTiledOutputFile file(filename.c_str(), header, 8);
DeepFrameBuffer frameBuffer;
Array<Array2D< void* > > data(channelCount);
for (int i = 0; i < channelCount; i++)
data[i].resizeErase(height, width);
Array2D<unsigned int> sampleCount;
sampleCount.resizeErase(height, width);
cout << " tileSizeX " << file.tileXSize()
<< " tileSizeY " << file.tileYSize() << " ";
sampleCountWhole.resizeErase(file.numYLevels(), file.numXLevels());
for (int i = 0; i < sampleCountWhole.height(); i++)
for (int j = 0; j < sampleCountWhole.width(); j++)
sampleCountWhole[i][j].resizeErase(height, width);
int memOffset;
if (relativeCoords)
memOffset = 0;
else
memOffset = dataWindow.min.x + dataWindow.min.y * width;
frameBuffer.insertSampleCountSlice (Slice (IMF::UINT,
(char *) (&sampleCount[0][0] - memOffset),
sizeof (unsigned int) * 1,
sizeof (unsigned int) * width,
1, 1,
0,
relativeCoords,
relativeCoords));
for (int i = 0; i < channelCount; i++)
{
PixelType type;
if (channelTypes[i] == 0)
type = IMF::UINT;
if (channelTypes[i] == 1)
type = IMF::HALF;
if (channelTypes[i] == 2)
type = IMF::FLOAT;
stringstream ss;
ss << i;
string str = ss.str();
int sampleSize;
if (channelTypes[i] == 0) sampleSize = sizeof (unsigned int);
if (channelTypes[i] == 1) sampleSize = sizeof (half);
if (channelTypes[i] == 2) sampleSize = sizeof (float);
int pointerSize = sizeof (char *);
frameBuffer.insert (str,
DeepSlice (type,
(char *) (&data[i][0][0] - memOffset),
pointerSize * 1,
pointerSize * width,
sampleSize,
1, 1,
0,
relativeCoords,
relativeCoords));
}
file.setFrameBuffer(frameBuffer);
cout << "writing " << flush;
if (bulkWrite)
cout << "bulk " << flush;
else
{
if (relativeCoords == false)
cout << "per-tile " << flush;
else
cout << "per-tile with relative coordinates " << flush;
}
for (int ly = 0; ly < file.numYLevels(); ly++)
for (int lx = 0; lx < file.numXLevels(); lx++)
{
Box2i dataWindowL = file.dataWindowForLevel(lx, ly);
if (bulkWrite)
{
//
// Bulk write (without relative coordinates).
//
for (int j = 0; j < file.numYTiles(ly); j++)
{
for (int i = 0; i < file.numXTiles(lx); i++)
{
Box2i box = file.dataWindowForTile(i, j, lx, ly);
for (int y = box.min.y; y <= box.max.y; y++)
for (int x = box.min.x; x <= box.max.x; x++)
{
int dwy = y - dataWindowL.min.y;
int dwx = x - dataWindowL.min.x;
sampleCount[dwy][dwx] = rand() % 10 + 1;
sampleCountWhole[ly][lx][dwy][dwx] = sampleCount[dwy][dwx];
for (int k = 0; k < channelCount; k++)
{
if (channelTypes[k] == 0)
data[k][dwy][dwx] = new unsigned int[sampleCount[dwy][dwx]];
if (channelTypes[k] == 1)
data[k][dwy][dwx] = new half[sampleCount[dwy][dwx]];
if (channelTypes[k] == 2)
data[k][dwy][dwx] = new float[sampleCount[dwy][dwx]];
for (int l = 0; l < sampleCount[dwy][dwx]; l++)
{
if (channelTypes[k] == 0)
((unsigned int*)data[k][dwy][dwx])[l] = (dwy * width + dwx) % 2049;
if (channelTypes[k] == 1)
((half*)data[k][dwy][dwx])[l] = (dwy* width + dwx) % 2049;
if (channelTypes[k] == 2)
((float*)data[k][dwy][dwx])[l] = (dwy * width + dwx) % 2049;
}
}
}
}
}
file.writeTiles(0, file.numXTiles(lx) - 1, 0, file.numYTiles(ly) - 1, lx, ly);
}
else if (bulkWrite == false)
{
if (relativeCoords == false)
{
//
// Per-tile write without relative coordinates.
//
for (int j = 0; j < file.numYTiles(ly); j++)
{
for (int i = 0; i < file.numXTiles(lx); i++)
{
Box2i box = file.dataWindowForTile(i, j, lx, ly);
for (int y = box.min.y; y <= box.max.y; y++)
for (int x = box.min.x; x <= box.max.x; x++)
{
int dwy = y - dataWindowL.min.y;
int dwx = x - dataWindowL.min.x;
sampleCount[dwy][dwx] = rand() % 10 + 1;
sampleCountWhole[ly][lx][dwy][dwx] = sampleCount[dwy][dwx];
for (int k = 0; k < channelCount; k++)
{
if (channelTypes[k] == 0)
data[k][dwy][dwx] = new unsigned int[sampleCount[dwy][dwx]];
if (channelTypes[k] == 1)
data[k][dwy][dwx] = new half[sampleCount[dwy][dwx]];
if (channelTypes[k] == 2)
data[k][dwy][dwx] = new float[sampleCount[dwy][dwx]];
for (int l = 0; l < sampleCount[dwy][dwx]; l++)
{
if (channelTypes[k] == 0)
((unsigned int*)data[k][dwy][dwx])[l] = (dwy * width + dwx) % 2049;
if (channelTypes[k] == 1)
((half*)data[k][dwy][dwx])[l] = (dwy* width + dwx) % 2049;
if (channelTypes[k] == 2)
((float*)data[k][dwy][dwx])[l] = (dwy * width + dwx) % 2049;
}
}
}
file.writeTile(i, j, lx, ly);
}
}
}
else if (relativeCoords)
{
//
// Per-tile write with relative coordinates.
//
for (int j = 0; j < file.numYTiles(ly); j++)
{
for (int i = 0; i < file.numXTiles(lx); i++)
{
Box2i box = file.dataWindowForTile(i, j, lx, ly);
for (int y = box.min.y; y <= box.max.y; y++)
for (int x = box.min.x; x <= box.max.x; x++)
{
int dwy = y - dataWindowL.min.y;
int dwx = x - dataWindowL.min.x;
int ty = y - box.min.y;
int tx = x - box.min.x;
sampleCount[ty][tx] = rand() % 10 + 1;
sampleCountWhole[ly][lx][dwy][dwx] = sampleCount[ty][tx];
for (int k = 0; k < channelCount; k++)
{
if (channelTypes[k] == 0)
data[k][ty][tx] = new unsigned int[sampleCount[ty][tx]];
if (channelTypes[k] == 1)
data[k][ty][tx] = new half[sampleCount[ty][tx]];
if (channelTypes[k] == 2)
data[k][ty][tx] = new float[sampleCount[ty][tx]];
for (int l = 0; l < sampleCount[ty][tx]; l++)
{
if (channelTypes[k] == 0)
((unsigned int*)data[k][ty][tx])[l] =
(dwy * width + dwx) % 2049;
if (channelTypes[k] == 1)
((half*)data[k][ty][tx])[l] =
(dwy * width + dwx) % 2049;
if (channelTypes[k] == 2)
((float*)data[k][ty][tx])[l] =
(dwy * width + dwx) % 2049;
}
}
}
file.writeTile(i, j, lx, ly);
for (int y = box.min.y; y <= box.max.y; y++)
for (int x = box.min.x; x <= box.max.x; x++)
for (int k = 0; k < channelCount; k++)
{
int ty = y - box.min.y;
int tx = x - box.min.x;
if (channelTypes[k] == 0)
delete[] (unsigned int*) data[k][ty][tx];
if (channelTypes[k] == 1)
delete[] (half*) data[k][ty][tx];
if (channelTypes[k] == 2)
delete[] (float*) data[k][ty][tx];
}
}
}
}
}
if (relativeCoords == false)
{
for (int i = 0; i < file.levelHeight(ly); i++)
for (int j = 0; j < file.levelWidth(lx); j++)
for (int k = 0; k < channelCount; k++)
{
if (channelTypes[k] == 0)
delete[] (unsigned int*) data[k][i][j];
if (channelTypes[k] == 1)
delete[] (half*) data[k][i][j];
if (channelTypes[k] == 2)
delete[] (float*) data[k][i][j];
}
}
}
}
void checkValue (void* sampleRawData,
int sampleCount,
int channelType,
int dwx,
int dwy)
{
for (int l = 0; l < sampleCount; l++)
{
if (channelType == 0)
{
unsigned int* value = (unsigned int*)(sampleRawData);
if (value[l] != (dwy * width + dwx) % 2049)
cout << dwx << ", " << dwy << " error, should be "
<< (dwy * width + dwx) % 2049 << ", is " << value[l]
<< endl << flush;
assert (value[l] == (dwy * width + dwx) % 2049);
}
if (channelType == 1)
{
half* value = (half*)(sampleRawData);
if (value[l] != (dwy * width + dwx) % 2049)
cout << dwx << ", " << dwy << " error, should be "
<< (dwy * width + dwx) % 2049 << ", is " << value[l]
<< endl << flush;
assert (value[l] == (dwy * width + dwx) % 2049);
}
if (channelType == 2)
{
float* value = (float*)(sampleRawData);
if (value[l] != (dwy * width + dwx) % 2049)
cout << dwx << ", " << dwy << " error, should be "
<< (dwy * width + dwx) % 2049 << ", is " << value[l]
<< endl << flush;
assert (value[l] == (dwy * width + dwx) % 2049);
}
}
}
void readFile (int channelCount,
bool bulkRead,
bool relativeCoords,
const std::string & filename)
{
if (relativeCoords)
assert(bulkRead == false);
cout << "reading " << flush;
DeepTiledInputFile file (filename.c_str(), 4);
const Header& fileHeader = file.header();
assert (fileHeader.displayWindow() == header.displayWindow());
assert (fileHeader.dataWindow() == header.dataWindow());
assert (fileHeader.pixelAspectRatio() == header.pixelAspectRatio());
assert (fileHeader.screenWindowCenter() == header.screenWindowCenter());
assert (fileHeader.screenWindowWidth() == header.screenWindowWidth());
assert (fileHeader.lineOrder() == header.lineOrder());
assert (fileHeader.compression() == header.compression());
assert (fileHeader.channels() == header.channels());
assert (fileHeader.type() == header.type());
assert (fileHeader.tileDescription() == header.tileDescription());
Array2D<unsigned int> localSampleCount;
localSampleCount.resizeErase(height, width);
Array<Array2D< void* > > data(channelCount);
for (int i = 0; i < channelCount; i++)
data[i].resizeErase(height, width);
DeepFrameBuffer frameBuffer;
int memOffset;
if (relativeCoords)
memOffset = 0;
else
memOffset = dataWindow.min.x + dataWindow.min.y * width;
frameBuffer.insertSampleCountSlice (Slice (IMF::UINT,
(char *) (&localSampleCount[0][0] - memOffset),
sizeof (unsigned int) * 1,
sizeof (unsigned int) * width,
1, 1,
0,
relativeCoords,
relativeCoords));
for (int i = 0; i < channelCount; i++)
{
PixelType type;
if (channelTypes[i] == 0)
type = IMF::UINT;
if (channelTypes[i] == 1)
type = IMF::HALF;
if (channelTypes[i] == 2)
type = IMF::FLOAT;
stringstream ss;
ss << i;
string str = ss.str();
int sampleSize;
if (channelTypes[i] == 0) sampleSize = sizeof (unsigned int);
if (channelTypes[i] == 1) sampleSize = sizeof (half);
if (channelTypes[i] == 2) sampleSize = sizeof (float);
int pointerSize = sizeof (char *);
frameBuffer.insert (str,
DeepSlice (type,
(char *) (&data[i][0][0] - memOffset),
pointerSize * 1,
pointerSize * width,
sampleSize,
1, 1,
0,
relativeCoords,
relativeCoords));
}
file.setFrameBuffer(frameBuffer);
if (bulkRead)
cout << "bulk " << flush;
else
{
if (relativeCoords == false)
cout << "per-tile " << flush;
else
cout << "per-tile with relative coordinates " << flush;
}
for (int ly = 0; ly < file.numYLevels(); ly++)
for (int lx = 0; lx < file.numXLevels(); lx++)
{
Box2i dataWindowL = file.dataWindowForLevel(lx, ly);
if (bulkRead)
{
//
// Testing bulk read (without relative coordinates).
//
file.readPixelSampleCounts(0, file.numXTiles(lx) - 1, 0, file.numYTiles(ly) - 1, lx, ly);
for (int i = 0; i < file.numYTiles(ly); i++)
{
for (int j = 0; j < file.numXTiles(lx); j++)
{
Box2i box = file.dataWindowForTile(j, i, lx, ly);
for (int y = box.min.y; y <= box.max.y; y++)
for (int x = box.min.x; x <= box.max.x; x++)
{
int dwy = y - dataWindowL.min.y;
int dwx = x - dataWindowL.min.x;
assert(localSampleCount[dwy][dwx] == sampleCountWhole[ly][lx][dwy][dwx]);
for (int k = 0; k < channelTypes.size(); k++)
{
if (channelTypes[k] == 0)
data[k][dwy][dwx] = new unsigned int[localSampleCount[dwy][dwx]];
if (channelTypes[k] == 1)
data[k][dwy][dwx] = new half[localSampleCount[dwy][dwx]];
if (channelTypes[k] == 2)
data[k][dwy][dwx] = new float[localSampleCount[dwy][dwx]];
}
}
}
}
file.readTiles(0, file.numXTiles(lx) - 1, 0, file.numYTiles(ly) - 1, lx, ly);
}
else if (bulkRead == false)
{
if (relativeCoords == false)
{
//
// Testing per-tile read without relative coordinates.
//
for (int i = 0; i < file.numYTiles(ly); i++)
{
for (int j = 0; j < file.numXTiles(lx); j++)
{
file.readPixelSampleCount(j, i, lx, ly);
Box2i box = file.dataWindowForTile(j, i, lx, ly);
for (int y = box.min.y; y <= box.max.y; y++)
for (int x = box.min.x; x <= box.max.x; x++)
{
int dwy = y - dataWindowL.min.y;
int dwx = x - dataWindowL.min.x;
assert(localSampleCount[dwy][dwx] == sampleCountWhole[ly][lx][dwy][dwx]);
for (int k = 0; k < channelTypes.size(); k++)
{
if (channelTypes[k] == 0)
data[k][dwy][dwx] = new unsigned int[localSampleCount[dwy][dwx]];
if (channelTypes[k] == 1)
data[k][dwy][dwx] = new half[localSampleCount[dwy][dwx]];
if (channelTypes[k] == 2)
data[k][dwy][dwx] = new float[localSampleCount[dwy][dwx]];
}
}
file.readTile(j, i, lx, ly);
}
}
}
else if (relativeCoords)
{
//
// Testing per-tile read with relative coordinates.
//
for (int i = 0; i < file.numYTiles(ly); i++)
{
for (int j = 0; j < file.numXTiles(lx); j++)
{
file.readPixelSampleCount(j, i, lx, ly);
Box2i box = file.dataWindowForTile(j, i, lx, ly);
for (int y = box.min.y; y <= box.max.y; y++)
for (int x = box.min.x; x <= box.max.x; x++)
{
int dwy = y - dataWindowL.min.y;
int dwx = x - dataWindowL.min.x;
int ty = y - box.min.y;
int tx = x - box.min.x;
assert(localSampleCount[ty][tx] == sampleCountWhole[ly][lx][dwy][dwx]);
for (int k = 0; k < channelTypes.size(); k++)
{
if (channelTypes[k] == 0)
data[k][ty][tx] = new unsigned int[localSampleCount[ty][tx]];
if (channelTypes[k] == 1)
data[k][ty][tx] = new half[localSampleCount[ty][tx]];
if (channelTypes[k] == 2)
data[k][ty][tx] = new float[localSampleCount[ty][tx]];
}
}
file.readTile(j, i, lx, ly);
for (int y = box.min.y; y <= box.max.y; y++)
for (int x = box.min.x; x <= box.max.x; x++)
{
int dwy = y - dataWindowL.min.y;
int dwx = x - dataWindowL.min.x;
int ty = y - box.min.y;
int tx = x - box.min.x;
for (int k = 0; k < channelTypes.size(); k++)
{
checkValue(data[k][ty][tx],
localSampleCount[ty][tx],
channelTypes[k],
dwx, dwy);
if (channelTypes[k] == 0)
delete[] (unsigned int*) data[k][ty][tx];
if (channelTypes[k] == 1)
delete[] (half*) data[k][ty][tx];
if (channelTypes[k] == 2)
delete[] (float*) data[k][ty][tx];
}
}
}
}
}
}
if (relativeCoords == false)
{
for (int i = 0; i < file.levelHeight(ly); i++)
for (int j = 0; j < file.levelWidth(lx); j++)
for (int k = 0; k < channelCount; k++)
{
for (int l = 0; l < localSampleCount[i][j]; l++)
{
if (channelTypes[k] == 0)
{
unsigned int* value = (unsigned int*)(data[k][i][j]);
if (value[l] != (i * width + j) % 2049)
cout << j << ", " << i << " error, should be "
<< (i * width + j) % 2049 << ", is " << value[l]
<< endl << flush;
assert (value[l] == (i * width + j) % 2049);
}
if (channelTypes[k] == 1)
{
half* value = (half*)(data[k][i][j]);
if (value[l] != (i * width + j) % 2049)
cout << j << ", " << i << " error, should be "
<< (i * width + j) % 2049 << ", is " << value[l]
<< endl << flush;
assert (((half*)(data[k][i][j]))[l] == (i * width + j) % 2049);
}
if (channelTypes[k] == 2)
{
float* value = (float*)(data[k][i][j]);
if (value[l] != (i * width + j) % 2049)
cout << j << ", " << i << " error, should be "
<< (i * width + j) % 2049 << ", is " << value[l]
<< endl << flush;
assert (((float*)(data[k][i][j]))[l] == (i * width + j) % 2049);
}
}
}
for (int i = 0; i < file.levelHeight(ly); i++)
for (int j = 0; j < file.levelWidth(lx); j++)
for (int k = 0; k < channelCount; k++)
{
if (channelTypes[k] == 0)
delete[] (unsigned int*) data[k][i][j];
if (channelTypes[k] == 1)
delete[] (half*) data[k][i][j];
if (channelTypes[k] == 2)
delete[] (float*) data[k][i][j];
}
}
}
}
void readWriteTestWithAbsoluateCoordinates (int channelCount,
int testTimes,
const std::string & tempDir)
{
cout << "Testing files with " << channelCount
<< " channels, using absolute coordinates "
<< testTimes << " times."
<< endl << flush;
std::string fn = tempDir + "imf_test_deep_tiled_basic.exr";
for (int i = 0; i < testTimes; i++)
{
int compressionIndex = i % 3;
Compression compression;
switch (compressionIndex)
{
case 0:
compression = NO_COMPRESSION;
break;
case 1:
compression = RLE_COMPRESSION;
break;
case 2:
compression = ZIPS_COMPRESSION;
break;
}
generateRandomFile (channelCount, compression, false, false, fn);
readFile (channelCount, false, false, fn);
remove (fn.c_str());
cout << endl << flush;
generateRandomFile (channelCount, compression, true, false, fn);
readFile (channelCount, true, false, fn);
remove (fn.c_str());
cout << endl << flush;
generateRandomFile (channelCount, compression, false, true, fn);
readFile (channelCount, false, true, fn);
remove (fn.c_str());
cout << endl << flush;
}
}
} // namespace
void testDeepTiledBasic (const std::string & tempDir)
{
try
{
cout << "Testing the DeepTiledInput/OutputFile for basic use" << endl;
srand(1);
int numThreads = ThreadPool::globalThreadPool().numThreads();
ThreadPool::globalThreadPool().setNumThreads(2);
readWriteTestWithAbsoluateCoordinates ( 1, 2, tempDir);
readWriteTestWithAbsoluateCoordinates ( 3, 2, tempDir);
readWriteTestWithAbsoluateCoordinates (10, 2, tempDir);
ThreadPool::globalThreadPool().setNumThreads(numThreads);
cout << "ok\n" << endl;
}
catch (const std::exception &e)
{
cerr << "ERROR -- caught exception: " << e.what() << endl;
assert (false);
}
}

View File

@ -0,0 +1,42 @@
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2011, 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.
//
///////////////////////////////////////////////////////////////////////////
#ifndef TESTDEEPTILEDBASIC_H_
#define TESTDEEPTILEDBASIC_H_
#include <string>
void testDeepTiledBasic (const std::string & tempDir);
#endif /* TESTDEEPTILEDBASIC_H_ */

View File

@ -0,0 +1,543 @@
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2009-2014 DreamWorks Animation 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 DreamWorks Animation 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 <half.h>
#include <math.h>
#include <string.h>
#include <ImfDwaCompressorSimd.h>
#include <ImfSystemSpecific.h>
#include <ImathRandom.h>
#include <iostream>
#include <assert.h>
using namespace OPENEXR_IMF_NAMESPACE;
using namespace IMATH_NAMESPACE;
using namespace std;
namespace
{
void
dumpBuffer (const SimdAlignedBuffer64f &buffer)
{
for (int i=0; i<8; ++i)
{
for (int j=0; j<8; ++j)
{
cout << buffer._buffer[i*8+j] << " ";
}
cout << endl;
}
}
void
compareBuffer (const SimdAlignedBuffer64f &src,
const SimdAlignedBuffer64f &dst,
const float errThresh)
{
for (int i=0; i<64; ++i)
{
double diff = fabs(src._buffer[i] - dst._buffer[i]);
if (diff > errThresh)
{
cout << scientific;
cout << "Error exceeded threshold on element " << i << endl;
cout << " diff: " << diff << endl;
cout << "Goal (src): " << scientific << endl;
dumpBuffer(src);
cout << "Test (dst): " << endl;
dumpBuffer(dst);
assert(false);
}
}
}
void
compareBufferRelative (const SimdAlignedBuffer64f &src,
const SimdAlignedBuffer64f &dst,
const float relErrThresh,
const float absErrThresh)
{
for (int i=0; i<64; ++i)
{
double diff = fabs(src._buffer[i] - dst._buffer[i]);
double relDiff = diff / fabs(src._buffer[i]);
if (relDiff > relErrThresh && diff > absErrThresh)
{
cout << scientific;
cout << "Error exceeded threshold on element " << i << endl;
cout << " diff: " << diff << " relErr: " << fixed << 100.0*relDiff << " %" << endl;
cout << "Goal (src): " << scientific << endl;
dumpBuffer(src);
cout << "Test (dst): " << endl;
dumpBuffer(dst);
assert(false);
}
}
}
//
// Test that we can round trip CSC data with reasonable precision
//
void
testCsc()
{
const int numIter = 1000000;
Rand48 rand48(0);
SimdAlignedBuffer64f orig[3];
SimdAlignedBuffer64f test[3];
cout << " Color Space Conversion Round Trip " << endl;
cout << " csc709Forward64() - 64 x csc709Inverse()" << endl;
for (int iter=0; iter<numIter; ++iter)
{
for (int i=0; i<64; ++i)
{
test[0]._buffer[i] = orig[0]._buffer[i] = rand48.nextf();
test[1]._buffer[i] = orig[1]._buffer[i] = rand48.nextf();
test[2]._buffer[i] = orig[2]._buffer[i] = rand48.nextf();
}
csc709Forward64(test[0]._buffer, test[1]._buffer, test[2]._buffer);
for (int i=0; i<64; ++i)
{
csc709Inverse(test[0]._buffer[i], test[1]._buffer[i], test[2]._buffer[i]);
}
compareBuffer(orig[0], test[0], 1e-3);
compareBuffer(orig[1], test[1], 1e-3);
compareBuffer(orig[2], test[2], 1e-3);
} // iter
cout << " csc709Forward64() - csc709Inverse64()" << endl;
for (int iter=0; iter<numIter; ++iter)
{
for (int i=0; i<64; ++i)
{
test[0]._buffer[i] = orig[0]._buffer[i] = rand48.nextf();
test[1]._buffer[i] = orig[1]._buffer[i] = rand48.nextf();
test[2]._buffer[i] = orig[2]._buffer[i] = rand48.nextf();
}
csc709Forward64(test[0]._buffer, test[1]._buffer, test[2]._buffer);
csc709Inverse64(test[0]._buffer, test[1]._buffer, test[2]._buffer);
compareBuffer(orig[0], test[0], 1e-3);
compareBuffer(orig[1], test[1], 1e-3);
compareBuffer(orig[2], test[2], 1e-3);
} // iter
}
//
// Test interleaving two byte arrays
//
void
testInterleave()
{
const int bufferLen = 100000;
const int randomNumIter = 10000;
const int lengthNumIter = 128;
Rand48 rand48(0);
char *srcA = new char[bufferLen];
char *srcB = new char[bufferLen];
char *dst = new char[2*bufferLen];
char *test = new char[2*bufferLen];
cout << " Byte Interleaving " << endl;
for (int i=0; i<bufferLen; ++i)
{
srcA[i] = (char)rand48.nextf(0.0, 255.0);
srcB[i] = (char)rand48.nextf(0.0, 255.0);
dst[2*i] = srcA[i];
dst[2*i+1] = srcB[i];
}
for (int iter=0; iter<randomNumIter; ++iter)
{
memset(test, 0, 2*bufferLen);
int offset = (int)rand48.nextf(0.0, bufferLen/2);
int len = (int)rand48.nextf(1.0, bufferLen - 1 - offset);
interleaveByte2( test+2*offset, srcA+offset, srcB+offset, len);
for (int i=0; i<len; ++i) {
assert( test[2*offset + 2*i] == dst[2*offset + 2*i]);
assert( test[2*offset + 2*i + 1] == dst[2*offset + 2*i + 1]);
}
}
//
// Test increasing length buffers, with varying alignment
// on all the buffers.
//
for (int len=1; len<lengthNumIter; ++len)
{
for (int offset=0; offset<16*16*16; ++offset)
{
int offsetA = offset % 16;
int offsetB = (offset / 16) % 16;
int offsetTest = (offset / 256) % 16;
memset(srcA, 255, bufferLen);
memset(srcB, 255, bufferLen);
memset(dst, 0, 2*bufferLen);
memset(test, 0, 2*bufferLen);
char *a = srcA + offsetA;
char *b = srcB + offsetB;
char *out = test + offsetTest;
for (int i=0; i<len; ++i)
{
a[i] = (char)rand48.nextf(0.0, 255.0);
b[i] = (char)rand48.nextf(0.0, 255.0);
dst[2*i] = a[i];
dst[2*i+1] = b[i];
}
interleaveByte2(out, a, b, len);
for (int i=0; i<2*len+8; ++i)
{
assert( dst[2*i] == out[2*i] );
assert( dst[2*i+1] == out[2*i+1] );
}
}
}
delete[] srcA;
delete[] srcB;
delete[] dst;
delete[] test;
}
//
// Test that we can route trip DCT data with reasonable precision
//
void
testDct()
{
const int numIter = 1000000;
Rand48 rand48(0);
SimdAlignedBuffer64f orig;
SimdAlignedBuffer64f test;
cout << " DCT Round Trip " << endl;
for (int iter=0; iter<numIter; ++iter)
{
for (int i=0; i<64; ++i)
{
orig._buffer[i] = test._buffer[i] = rand48.nextf();
}
dctForward8x8(test._buffer);
dctInverse8x8_scalar<0>(test._buffer);
compareBufferRelative(orig, test, .02, 1e-3);
}
cout << " Inverse, DC Only" << endl;
for (int iter=0; iter<numIter; ++iter)
{
orig._buffer[0] = test._buffer[0] = rand48.nextf();
for (int i=1; i<64; ++i)
{
orig._buffer[i] = test._buffer[i] = 0;
}
dctInverse8x8_scalar<0>(orig._buffer);
dctInverse8x8DcOnly(test._buffer);
compareBufferRelative(orig, test, .01, 1e-6);
}
#define INVERSE_DCT_SCALAR_TEST_N(_func, _n, _desc) \
cout << " " << _desc << endl; \
for (int iter=0; iter<numIter; ++iter) \
{ \
for (int i=0; i<64; ++i) \
{ \
if (i < 8*(8-_n)) \
{ \
orig._buffer[i] = test._buffer[i] = rand48.nextf(); \
} else { \
orig._buffer[i] = test._buffer[i] = 0; \
} \
} \
dctInverse8x8_scalar<0>(orig._buffer); \
_func<_n>(test._buffer); \
compareBufferRelative(orig, test, .01, 1e-6); \
}
cout << " Inverse, Scalar: " << endl;
INVERSE_DCT_SCALAR_TEST_N(dctInverse8x8_scalar, 0, "8x8")
INVERSE_DCT_SCALAR_TEST_N(dctInverse8x8_scalar, 1, "7x8")
INVERSE_DCT_SCALAR_TEST_N(dctInverse8x8_scalar, 2, "6x8")
INVERSE_DCT_SCALAR_TEST_N(dctInverse8x8_scalar, 3, "5x8")
INVERSE_DCT_SCALAR_TEST_N(dctInverse8x8_scalar, 4, "4x8")
INVERSE_DCT_SCALAR_TEST_N(dctInverse8x8_scalar, 5, "3x8")
INVERSE_DCT_SCALAR_TEST_N(dctInverse8x8_scalar, 6, "2x8")
INVERSE_DCT_SCALAR_TEST_N(dctInverse8x8_scalar, 7, "1x8")
CpuId cpuid;
if (cpuid.sse2)
{
cout << " Inverse, SSE2: " << endl;
INVERSE_DCT_SCALAR_TEST_N(dctInverse8x8_sse2, 0, "8x8")
INVERSE_DCT_SCALAR_TEST_N(dctInverse8x8_sse2, 1, "7x8")
INVERSE_DCT_SCALAR_TEST_N(dctInverse8x8_sse2, 2, "6x8")
INVERSE_DCT_SCALAR_TEST_N(dctInverse8x8_sse2, 3, "5x8")
INVERSE_DCT_SCALAR_TEST_N(dctInverse8x8_sse2, 4, "4x8")
INVERSE_DCT_SCALAR_TEST_N(dctInverse8x8_sse2, 5, "3x8")
INVERSE_DCT_SCALAR_TEST_N(dctInverse8x8_sse2, 6, "2x8")
INVERSE_DCT_SCALAR_TEST_N(dctInverse8x8_sse2, 7, "1x8")
}
if (cpuid.avx)
{
cout << " Inverse, AVX: " << endl;
INVERSE_DCT_SCALAR_TEST_N(dctInverse8x8_avx, 0, "8x8")
INVERSE_DCT_SCALAR_TEST_N(dctInverse8x8_avx, 1, "7x8")
INVERSE_DCT_SCALAR_TEST_N(dctInverse8x8_avx, 2, "6x8")
INVERSE_DCT_SCALAR_TEST_N(dctInverse8x8_avx, 3, "5x8")
INVERSE_DCT_SCALAR_TEST_N(dctInverse8x8_avx, 4, "4x8")
INVERSE_DCT_SCALAR_TEST_N(dctInverse8x8_avx, 5, "3x8")
INVERSE_DCT_SCALAR_TEST_N(dctInverse8x8_avx, 6, "2x8")
INVERSE_DCT_SCALAR_TEST_N(dctInverse8x8_avx, 7, "1x8")
}
}
//
// Test FLOAT -> HALF conversion, mostly for F16C enabled processors
//
void
testFloatToHalf()
{
cout << " FLOAT -> HALF conversion" << endl;
const int numIter = 1000000;
Rand48 rand48(0);
SimdAlignedBuffer64f src;
SimdAlignedBuffer64us dst;
cout << " convertFloatToHalf64_scalar()" << endl;
for (int iter=0; iter<numIter; ++iter)
{
for (int i=0; i<64; ++i)
{
if (i < 32)
{
src._buffer[i] = (float)140000*(rand48.nextf()-.5);
} else
{
src._buffer[i] = (float)(rand48.nextf()-.5);
}
dst._buffer[i] = 0;
}
convertFloatToHalf64_scalar(dst._buffer, src._buffer);
for (int i=0; i<64; ++i)
{
half value = (half)src._buffer[i];
if (value.bits() != dst._buffer[i])
{
cout << src._buffer[i] << " -> " << dst._buffer[i]
<< " expected " << value.bits() << endl;
assert(false);
}
}
}
CpuId cpuid;
if (cpuid.avx && cpuid.f16c)
{
cout << " convertFloatToHalf64_f16c()" << endl;
for (int iter=0; iter<numIter; ++iter)
{
for (int i=0; i<64; ++i)
{
if (i < 32)
{
src._buffer[i] = (float)140000*(rand48.nextf()-.5);
}
else
{
src._buffer[i] = (float)(rand48.nextf()-.5);
}
dst._buffer[i] = 0;
}
convertFloatToHalf64_f16c(dst._buffer, src._buffer);
for (int i=0; i<64; ++i)
{
half value = (half)src._buffer[i];
if (value.bits() != dst._buffer[i])
{
cout << src._buffer[i] << " -> " << dst._buffer[i]
<< " expected " << value.bits() << endl;
assert(false);
}
}
}
}
}
//
// Test ZigZag reordering + HALF -> FLOAT conversion
//
void
testFromHalfZigZag()
{
SimdAlignedBuffer64us src;
SimdAlignedBuffer64f dst;
cout << " ZigZag re-ordering with HALF -> FLOAT conversion" << endl;
// First off, simple check to see that the reordering is working
// This pattern, when converted, should give 0.0 - 63.0 as floats
// in order.
unsigned short pattern[] = {
0x0000, 0x3c00, 0x4800, 0x4c00, 0x4880, 0x4000, 0x4200, 0x4900,
0x4c40, 0x4e00, 0x5000, 0x4e40, 0x4c80, 0x4980, 0x4400, 0x4500,
0x4a00, 0x4cc0, 0x4e80, 0x5020, 0x5100, 0x5200, 0x5120, 0x5040,
0x4ec0, 0x4d00, 0x4a80, 0x4600, 0x4700, 0x4b00, 0x4d40, 0x4f00,
0x5060, 0x5140, 0x5220, 0x5300, 0x5320, 0x5240, 0x5160, 0x5080,
0x4f40, 0x4d80, 0x4b80, 0x4dc0, 0x4f80, 0x50a0, 0x5180, 0x5260,
0x5340, 0x5360, 0x5280, 0x51a0, 0x50c0, 0x4fc0, 0x50e0, 0x51c0,
0x52a0, 0x5380, 0x53a0, 0x52c0, 0x51e0, 0x52e0, 0x53c0, 0x53e0
};
cout << " fromHalfZigZag_scaler()" << endl;
for (int i=0; i<64; ++i)
{
src._buffer[i] = pattern[i];
}
fromHalfZigZag_scalar(src._buffer, dst._buffer);
for (int i=0; i<64; ++i)
{
if ( fabsf(dst._buffer[i] - (float)i) > 1e-5 )
{
cout << "At index " << i << ": ";
cout << "expecting " << (float)i << "; got " << dst._buffer[i] << endl;
assert(false);
}
}
// Then compare the two implementations, if supported
CpuId cpuid;
if (cpuid.avx && cpuid.f16c)
{
const int numIter = 1000000;
Rand48 rand48(0);
half h;
SimdAlignedBuffer64f dstF16c;
cout << " fromHalfZigZag_f16c()" << endl;
for (int iter=0; iter<numIter; ++iter)
{
for (int i=0; i<64; ++i)
{
if (i < 32)
{
h = (half)(140000.*(rand48.nextf() - .5));
}
else
{
h = (half)(rand48.nextf() - .5);
}
src._buffer[i] = h.bits();
}
fromHalfZigZag_scalar(src._buffer, dst._buffer);
fromHalfZigZag_f16c(src._buffer, dstF16c._buffer);
for (int i=0; i<64; ++i)
{
if ( fabsf(dst._buffer[i] - dstF16c._buffer[i]) > 1e-5 )
{
cout << "At index " << i << ": ";
cout << "expecting " << dst._buffer[i] << "; got "
<< dstF16c._buffer[i] << endl;
assert(false);
}
}
} // iter
} // f16c
}
} // namespace
void
testDwaCompressorSimd (const string&)
{
cout << "SIMD helper functions for DwaCompressor:" << endl;
try
{
testCsc();
testInterleave();
testFloatToHalf();
testFromHalfZigZag();
testDct();
}
catch (const exception &e)
{
cout << "unexpected exception: " << e.what() << endl;
assert (false);
}
catch (...)
{
cout << "unexpected exception" << endl;
assert (false);
}
cout << "ok\n" << endl;
}

View File

@ -0,0 +1,41 @@
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2009-2014 DreamWorks Animation 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 DreamWorks Animation 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.
//
///////////////////////////////////////////////////////////////////////////
#ifndef TESTDWACOMPRESSORSIMD_H_
#define TESTDWACOMPRESSORSIMD_H_
#include <string>
void testDwaCompressorSimd(const std::string&);
#endif /* TESTDWACOMPRESSORSIMD_H_ */

View File

@ -0,0 +1,566 @@
///////////////////////////////////////////////////////////////////////////
//
// 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 <ImfRgbaFile.h>
#include <ImfTiledRgbaFile.h>
#include <ImfMultiPartInputFile.h>
#include <ImfMultiPartOutputFile.h>
#include <ImfPartType.h>
#include <ImfInputPart.h>
#include <ImfOutputPart.h>
#include <ImfStdIO.h>
#include <ImfArray.h>
#include <stdio.h>
#include <assert.h>
#include "Iex.h"
#include <errno.h>
#include <vector>
#include <ImfChannelList.h>
using namespace OPENEXR_IMF_NAMESPACE;
using namespace std;
using namespace IMATH_NAMESPACE;
namespace {
void
fillPixels1 (Array2D<Rgba> &pixels, int w, int h)
{
for (int y = 0; y < h; ++y)
{
for (int x = 0; x < w; ++x)
{
Rgba &p = pixels[y][x];
p.r = (x & 1);
p.g = ((x + y) & 1);
p.b = (y & 1);
p.a = (p.r + p.b + p.g) / 3.0;
}
}
}
void
fillPixels2 (Array2D<Rgba> &pixels, int w, int h)
{
for (int y = 0; y < h; ++y)
{
for (int x = 0; x < w; ++x)
{
Rgba &p = pixels[y][x];
p.r = (x & 2);
p.g = ((x + y) & 2);
p.b = (y & 2);
p.a = (p.r + p.b + p.g) / 3.0;
}
}
}
//
// class MMIFStream -- a memory-mapped implementation of
// class IStream based on class std::ifstream
//
class MMIFStream: public OPENEXR_IMF_NAMESPACE::IStream
{
public:
//-------------------------------------------------------
// A constructor that opens the file with the given name.
// It reads the whole file into an internal buffer and
// then immediately closes the file.
//-------------------------------------------------------
MMIFStream (const char fileName[]);
virtual ~MMIFStream ();
virtual bool isMemoryMapped () const {return true;}
virtual bool read (char c[/*n*/], int n);
virtual char* readMemoryMapped (int n);
virtual Int64 tellg () {return _pos;}
virtual void seekg (Int64 pos) {_pos = pos;}
virtual void clear () {}
private:
char* _buffer;
Int64 _length;
Int64 _pos;
};
MMIFStream::MMIFStream (const char fileName[]):
OPENEXR_IMF_NAMESPACE::IStream (fileName),
_buffer (0),
_length (0),
_pos (0)
{
std::ifstream ifs (fileName, ios_base::binary);
//
// Get length of file
//
ifs.seekg (0, ios::end);
_length = ifs.tellg();
ifs.seekg (0, ios::beg);
//
// Allocate memory
//
_buffer = new char [_length];
//
// Read the entire file
//
ifs.read (_buffer, _length);
ifs.close();
}
MMIFStream::~MMIFStream ()
{
delete [] _buffer;
}
bool
MMIFStream::read (char c[/*n*/], int n)
{
if ((_pos < 0 || _pos >= _length) && n != 0)
throw IEX_NAMESPACE::InputExc ("Unexpected end of file.");
Int64 n2 = n;
bool retVal = true;
if (_length - _pos <= n2)
{
n2 = _length - _pos;
retVal = false;
}
memcpy (c, &(_buffer[_pos]), n2);
_pos += n2;
return retVal;
}
char*
MMIFStream::readMemoryMapped (int n)
{
if (_pos < 0 || _pos >= _length)
throw IEX_NAMESPACE::InputExc ("Unexpected end of file.");
if (_pos + n > _length)
throw IEX_NAMESPACE::InputExc ("Reading past end of file.");
char* retVal = &(_buffer[_pos]);
_pos += n;
return retVal;
}
void
writeReadScanLines (const char fileName[],
int width,
int height,
const Array2D<Rgba> &p1)
{
//
// Save a scanline-based RGBA image, but instead of
// letting the RgbaOutputFile object open the file,
// make the RgbaOutputFile object use an existing
// StdOFStream. Read the image back, using an
// existing StdIFStream, and compare the pixels
// with the original data. Then read the image
// back a second time using a memory-mapped
// MMIFStream (see above).
//
cout << "scan-line based file:" << endl;
Header header (width, height);
{
cout << "writing";
remove (fileName);
std::ofstream os (fileName, ios_base::binary);
StdOFStream ofs (os, fileName);
RgbaOutputFile out (ofs, header, WRITE_RGBA);
out.setFrameBuffer (&p1[0][0], 1, width);
out.writePixels (height);
}
{
cout << ", reading";
std::ifstream is (fileName, ios_base::binary);
StdIFStream ifs (is, fileName);
RgbaInputFile in (ifs);
const Box2i &dw = in.dataWindow();
int w = dw.max.x - dw.min.x + 1;
int h = dw.max.y - dw.min.y + 1;
int dx = dw.min.x;
int dy = dw.min.y;
Array2D<Rgba> p2 (h, w);
in.setFrameBuffer (&p2[-dy][-dx], 1, w);
in.readPixels (dw.min.y, dw.max.y);
cout << ", comparing";
for (int y = 0; y < h; ++y)
{
for (int x = 0; x < w; ++x)
{
assert (p2[y][x].r == p1[y][x].r);
assert (p2[y][x].g == p1[y][x].g);
assert (p2[y][x].b == p1[y][x].b);
assert (p2[y][x].a == p1[y][x].a);
}
}
}
{
cout << ", reading (memory-mapped)";
MMIFStream ifs (fileName);
RgbaInputFile in (ifs);
const Box2i &dw = in.dataWindow();
int w = dw.max.x - dw.min.x + 1;
int h = dw.max.y - dw.min.y + 1;
int dx = dw.min.x;
int dy = dw.min.y;
Array2D<Rgba> p2 (h, w);
in.setFrameBuffer (&p2[-dy][-dx], 1, w);
in.readPixels (dw.min.y, dw.max.y);
cout << ", comparing";
for (int y = 0; y < h; ++y)
{
for (int x = 0; x < w; ++x)
{
assert (p2[y][x].r == p1[y][x].r);
assert (p2[y][x].g == p1[y][x].g);
assert (p2[y][x].b == p1[y][x].b);
assert (p2[y][x].a == p1[y][x].a);
}
}
}
cout << endl;
remove (fileName);
}
void
writeReadMultiPart (const char fileName[],
int width,
int height,
const Array2D<Rgba> &p1)
{
//
// Save a two scanline parts in an image, but instead of
// letting the MultiPartOutputFile object open the file,
// make the MultiPartOutputFile object use an existing
// StdOFStream. Read the image back, using an
// existing StdIFStream, and compare the pixels
// with the original data. Then read the image
// back a second time using a memory-mapped
// MMIFStream (see above).
//
cout << "scan-line based mulitpart file:" << endl;
vector<Header> headers(2);
headers[0] = Header(width, height);
headers[0].setName("part1");
headers[0].channels().insert("R",Channel());
headers[0].channels().insert("G",Channel());
headers[0].channels().insert("B",Channel());
headers[0].channels().insert("A",Channel());
headers[0].setType(SCANLINEIMAGE);
headers[1]=headers[0];
headers[1].setName("part2");
{
cout << "writing";
remove (fileName);
std::ofstream os (fileName, ios_base::binary);
StdOFStream ofs (os, fileName);
MultiPartOutputFile out (ofs, &headers[0],2);
FrameBuffer f;
f.insert("R",Slice(HALF,(char *) &p1[0][0].r,sizeof(Rgba),width*sizeof(Rgba)));
f.insert("G",Slice(HALF,(char *) &p1[0][0].g,sizeof(Rgba),width*sizeof(Rgba)));
f.insert("B",Slice(HALF,(char *) &p1[0][0].b,sizeof(Rgba),width*sizeof(Rgba)));
f.insert("A",Slice(HALF,(char *) &p1[0][0].a,sizeof(Rgba),width*sizeof(Rgba)));
for(int i=0;i<2;i++)
{
OutputPart p(out,i);
p.setFrameBuffer (f);
p.writePixels (height);
}
}
{
cout << ", reading";
std::ifstream is (fileName, ios_base::binary);
StdIFStream ifs (is, fileName);
MultiPartInputFile in (ifs);
assert(in.parts() == 2);
assert(in.header(0).dataWindow()==in.header(1).dataWindow());
const Box2i &dw = in.header(0).dataWindow();
int w = dw.max.x - dw.min.x + 1;
int h = dw.max.y - dw.min.y + 1;
int dx = dw.min.x;
int dy = dw.min.y;
Array2D<Rgba> p2 (h, w);
FrameBuffer f;
f.insert("R",Slice(HALF,(char *) &p2[-dy][-dx].r,sizeof(Rgba),w*sizeof(Rgba)));
f.insert("G",Slice(HALF,(char *) &p2[-dy][-dx].g,sizeof(Rgba),w*sizeof(Rgba)));
f.insert("B",Slice(HALF,(char *) &p2[-dy][-dx].b,sizeof(Rgba),w*sizeof(Rgba)));
f.insert("A",Slice(HALF,(char *) &p2[-dy][-dx].a,sizeof(Rgba),w*sizeof(Rgba)));
for(int part=0;part<2;part++)
{
InputPart p(in,part);
p.setFrameBuffer(f);
p.readPixels (dw.min.y, dw.max.y);
cout << ", comparing pt " << part;
for (int y = 0; y < h; ++y)
{
for (int x = 0; x < w; ++x)
{
assert (p2[y][x].r == p1[y][x].r);
assert (p2[y][x].g == p1[y][x].g);
assert (p2[y][x].b == p1[y][x].b);
assert (p2[y][x].a == p1[y][x].a);
}
}
}
}
{
cout << ", reading (memory-mapped)";
MMIFStream ifs (fileName);
MultiPartInputFile in (ifs);
assert(in.parts() == 2);
assert(in.header(0).dataWindow()==in.header(1).dataWindow());
const Box2i &dw = in.header(0).dataWindow();
int w = dw.max.x - dw.min.x + 1;
int h = dw.max.y - dw.min.y + 1;
int dx = dw.min.x;
int dy = dw.min.y;
Array2D<Rgba> p2 (h, w);
FrameBuffer f;
f.insert("R",Slice(HALF,(char *) &p2[-dy][-dx].r,sizeof(Rgba),w*sizeof(Rgba)));
f.insert("G",Slice(HALF,(char *) &p2[-dy][-dx].g,sizeof(Rgba),w*sizeof(Rgba)));
f.insert("B",Slice(HALF,(char *) &p2[-dy][-dx].b,sizeof(Rgba),w*sizeof(Rgba)));
f.insert("A",Slice(HALF,(char *) &p2[-dy][-dx].a,sizeof(Rgba),w*sizeof(Rgba)));
for(int part=0;part<2;part++)
{
InputPart p(in,part);
p.setFrameBuffer(f);
p.readPixels (dw.min.y, dw.max.y);
cout << ", comparing pt " << part;
for (int y = 0; y < h; ++y)
{
for (int x = 0; x < w; ++x)
{
assert (p2[y][x].r == p1[y][x].r);
assert (p2[y][x].g == p1[y][x].g);
assert (p2[y][x].b == p1[y][x].b);
assert (p2[y][x].a == p1[y][x].a);
}
}
}
}
cout << endl;
remove (fileName);
}
void
writeReadTiles (const char fileName[],
int width,
int height,
const Array2D<Rgba> &p1)
{
//
// Save a tiled RGBA image, but instead of letting
// the TiledRgbaOutputFile object open the file, make
// it use an existing StdOFStream. Read the image back,
// using an existing StdIFStream, and compare the pixels
// with the original data. Then read the image back a
// second time using a memory-mapped MMIFStream (see above).
//
cout << "tiled file:" << endl;
Header header (width, height);
{
cout << "writing";
remove (fileName);
std::ofstream os (fileName, ios_base::binary);
StdOFStream ofs (os, fileName);
TiledRgbaOutputFile out (ofs, header, WRITE_RGBA, 20, 20, ONE_LEVEL);
out.setFrameBuffer (&p1[0][0], 1, width);
out.writeTiles (0, out.numXTiles() - 1, 0, out.numYTiles() - 1);
}
{
cout << ", reading";
std::ifstream is (fileName, ios_base::binary);
StdIFStream ifs (is, fileName);
TiledRgbaInputFile in (ifs);
const Box2i &dw = in.dataWindow();
int w = dw.max.x - dw.min.x + 1;
int h = dw.max.y - dw.min.y + 1;
int dx = dw.min.x;
int dy = dw.min.y;
Array2D<Rgba> p2 (h, w);
in.setFrameBuffer (&p2[-dy][-dx], 1, w);
in.readTiles (0, in.numXTiles() - 1, 0, in.numYTiles() - 1);
cout << ", comparing";
for (int y = 0; y < h; ++y)
{
for (int x = 0; x < w; ++x)
{
assert (p2[y][x].r == p1[y][x].r);
assert (p2[y][x].g == p1[y][x].g);
assert (p2[y][x].b == p1[y][x].b);
assert (p2[y][x].a == p1[y][x].a);
}
}
}
{
cout << ", reading (memory-mapped)";
MMIFStream ifs (fileName);
TiledRgbaInputFile in (ifs);
const Box2i &dw = in.dataWindow();
int w = dw.max.x - dw.min.x + 1;
int h = dw.max.y - dw.min.y + 1;
int dx = dw.min.x;
int dy = dw.min.y;
Array2D<Rgba> p2 (h, w);
in.setFrameBuffer (&p2[-dy][-dx], 1, w);
in.readTiles (0, in.numXTiles() - 1, 0, in.numYTiles() - 1);
cout << ", comparing";
for (int y = 0; y < h; ++y)
{
for (int x = 0; x < w; ++x)
{
assert (p2[y][x].r == p1[y][x].r);
assert (p2[y][x].g == p1[y][x].g);
assert (p2[y][x].b == p1[y][x].b);
assert (p2[y][x].a == p1[y][x].a);
}
}
}
cout << endl;
remove (fileName);
}
} // namespace
void
testExistingStreams (const std::string &tempDir)
{
try
{
cout << "Testing reading and writing using existing streams" << endl;
const int W = 119;
const int H = 237;
Array2D<Rgba> p1 (H, W);
fillPixels1 (p1, W, H);
writeReadScanLines ((tempDir + "imf_test_streams.exr").c_str(), W, H, p1);
fillPixels2 (p1, W, H);
writeReadTiles ((tempDir + "imf_test_streams2.exr").c_str(), W, H, p1);
fillPixels1 (p1, W, H);
writeReadMultiPart ((tempDir + "imf_test_streams3.exr").c_str(), W, H, p1);
cout << "ok\n" << endl;
}
catch (const std::exception &e)
{
cerr << "ERROR -- caught exception: " << e.what() << endl;
assert (false);
}
}

View File

@ -0,0 +1,39 @@
///////////////////////////////////////////////////////////////////////////
//
// 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 <string>
void testExistingStreams (const std::string &tempDir);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,40 @@
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2013, Weta Digital Ltd
//
// 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.
//
///////////////////////////////////////////////////////////////////////////
#ifndef TESTFUTUREPROOFING_H_
#define TESTFUTUREPROOFING_H_
#include <string>
void testFutureProofing (const std::string & tempDir);
#endif

View File

@ -0,0 +1,252 @@
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2002-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 <ImfHuf.h>
#include "ImathRandom.h"
#include <ImfArray.h>
#include <iostream>
#include <exception>
#include <limits.h>
#include <math.h>
#include <stdlib.h>
#include <assert.h>
using namespace OPENEXR_IMF_NAMESPACE;
using namespace std;
namespace {
void
fill1 (unsigned short data[/*n*/], int n, float bias, IMATH_NAMESPACE::Rand48 & rand48)
{
for (int i = 0; i < n; ++i)
data[i] = (unsigned short)
(pow (rand48.nextf(), double(bias)) * (USHRT_MAX + 1));
}
void
fill2 (unsigned short data[/*n*/], int n, int m, IMATH_NAMESPACE::Rand48 & rand48)
{
for (int i = 0; i < n; ++i)
data[i] = 0;
for (int i = 0; i < m; ++i)
data[rand48.nexti() % n] = (unsigned short) (rand48.nextf() * (USHRT_MAX + 1));
}
void
fill3 (unsigned short data[/*n*/], int n, int m)
{
for (int i = 0; i < n; ++i)
data[i] = m;
}
void
fill4 (unsigned short data[/*n*/], int n)
{
for (int i = 0; i < n; ++i)
data[i] = i & USHRT_MAX;
}
void
fill5 (unsigned short data[/*n*/], int n)
{
for (int i = 0; i < n; ++i)
data[i] = 0;
int j = 0, k = 0;
for (int i = 0; i < n; ++i)
{
data[i] = j;
j = j + k;
k = k + 1;
if (j > USHRT_MAX)
break;
}
}
void
compressUncompress (const unsigned short raw[], int n)
{
Array <char> compressed (3 * n + 4 * 65536);
Array <unsigned short> uncompressed (n);
cout << "compressing " << flush;
int nCompressed = hufCompress (raw, n, compressed);
cout << "uncompressing " << flush;
hufUncompress (compressed, nCompressed, uncompressed, n);
cout << "comparing: " << flush;
for (int i = 0; i < n; ++i)
assert (uncompressed[i] == raw[i]);
cout << sizeof (raw[0]) * n << " bytes, compressed " <<
nCompressed << " bytes" << endl;
}
void
compressUncompressSubset(const unsigned short raw[], int n)
{
// Test various subsets of the data set
Array <char> compressed (3 * n + 4 * 65536);
Array <unsigned short> uncompressed (n);
int maxOffset = 16;
if (n <= maxOffset) {
maxOffset = n-1;
}
for (int offset=1; offset<maxOffset; ++offset) {
int maxLength = n - offset;
int minLength = maxLength - 16;
if (minLength < 1) minLength = 1;
for (int length=minLength; length<=maxLength; ++length) {
cout << "compressing " << flush;
int nCompressed = hufCompress (raw + offset, length, compressed + offset);
cout << "uncompressing " << flush;
hufUncompress (compressed + offset, nCompressed, uncompressed + offset, length);
for (int i = 0; i < length; ++i)
assert (uncompressed[offset+i] == raw[offset+i]);
cout << sizeof (raw[0]) * length << " bytes, compressed " << nCompressed << " bytes ";
cout << "(+" << offset << ",-" << n-offset-length << ")" << endl;
}
}
}
} // namespace
void
testHuf (const std::string&)
{
try
{
cout << "Testing Huffman encoder" << endl;
IMATH_NAMESPACE::Rand48 rand48 (0);
const int N = 1000000;
Array <unsigned short> raw (N);
fill1 (raw, N, 1, rand48); // test various symbol distributions
compressUncompress (raw, N);
compressUncompressSubset (raw, N);
fill1 (raw, N, 10, rand48);
compressUncompress (raw, N);
compressUncompressSubset (raw, N);
fill1 (raw, N, 100, rand48);
compressUncompress (raw, N);
compressUncompressSubset (raw, N);
fill1 (raw, N, 1000, rand48);
compressUncompress (raw, N);
compressUncompressSubset (raw, N);
fill2 (raw, N, 1, rand48);
compressUncompress (raw, N);
compressUncompressSubset (raw, N);
fill2 (raw, N, 10, rand48);
compressUncompress (raw, N);
compressUncompressSubset (raw, N);
fill2 (raw, N, 100, rand48);
compressUncompress (raw, N);
compressUncompressSubset (raw, N);
fill2 (raw, N, 1000, rand48);
compressUncompress (raw, N);
compressUncompressSubset (raw, N);
fill3 (raw, N, 0);
compressUncompress (raw, N);
compressUncompressSubset (raw, N);
fill3 (raw, N, 1);
compressUncompress (raw, N);
compressUncompressSubset (raw, N);
fill3 (raw, N, USHRT_MAX - 1);
compressUncompress (raw, N);
compressUncompressSubset (raw, N);
fill3 (raw, N, USHRT_MAX);
compressUncompress (raw, N);
compressUncompressSubset (raw, N);
fill4 (raw, USHRT_MAX + 1);
compressUncompress (raw, USHRT_MAX + 1);
compressUncompressSubset (raw, USHRT_MAX + 1);
fill4 (raw, N);
compressUncompress (raw, N);
compressUncompressSubset (raw, N);
fill4 (raw, 0);
compressUncompress (raw, 0); // test small input data sets
fill4 (raw, 1);
compressUncompress (raw, 1);
fill4 (raw, 2);
compressUncompress (raw, 2);
fill4 (raw, 3);
compressUncompress (raw, 3);
fill5 (raw, N); // test run-length coding of code table
compressUncompress (raw, N);
compressUncompressSubset (raw, N);
cout << "ok\n" << endl;
}
catch (const std::exception &e)
{
cerr << "ERROR -- caught exception: " << e.what() << endl;
assert (false);
}
}

View File

@ -0,0 +1,41 @@
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2002-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 <string>
void testHuf (const std::string &tempDir);

View File

@ -0,0 +1,729 @@
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2011, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
//
// Portions (c) 2012, Weta Digital Ltd
//
// 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
// Weta Digital nor any other ontributors 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 <iostream>
#include <string>
#include <vector>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "tmpDir.h"
#include "testInputPart.h"
#include <IlmThreadPool.h>
#include <ImfMultiPartInputFile.h>
#include <ImfMultiPartOutputFile.h>
#include <ImfArray.h>
#include <ImfChannelList.h>
#include <ImfOutputPart.h>
#include <ImfInputPart.h>
#include <ImfTiledOutputPart.h>
#include <ImfPartType.h>
#include <ImfMisc.h>
namespace IMF = OPENEXR_IMF_NAMESPACE;
using namespace IMF;
using namespace std;
using namespace IMATH_NAMESPACE;
using namespace ILMTHREAD_NAMESPACE;
namespace
{
const int height = 267;
const int width = 193;
vector<Header> headers;
vector<int> pixelTypes;
vector<int> partTypes;
vector<int> levelModes;
template <class T>
void fillPixels (Array2D<T> &ph, int width, int height)
{
ph.resizeErase(height, width);
for (int y = 0; y < height; ++y)
for (int x = 0; x < width; ++x)
{
//
// We do this because half cannot store number bigger than 2048 exactly.
//
ph[y][x] = (y * width + x) % 2049;
}
}
template <class T>
void fillPixels (Array2D<unsigned int>& sampleCount, Array2D<T*> &ph, int width, int height)
{
ph.resizeErase(height, width);
for (int y = 0; y < height; ++y)
for (int x = 0; x < width; ++x)
{
ph[y][x] = new T[sampleCount[y][x]];
for (int i = 0; i < sampleCount[y][x]; i++)
{
//
// We do this because half cannot store number bigger than 2048 exactly.
//
ph[y][x][i] = (y * width + x) % 2049;
}
}
}
void allocatePixels(int type, Array2D<unsigned int>& sampleCount,
Array2D<unsigned int*>& uintData, Array2D<float*>& floatData,
Array2D<half*>& halfData, int x1, int x2, int y1, int y2)
{
for (int y = y1; y <= y2; y++)
for (int x = x1; x <= x2; x++)
{
if (type == 0)
uintData[y][x] = new unsigned int[sampleCount[y][x]];
if (type == 1)
floatData[y][x] = new float[sampleCount[y][x]];
if (type == 2)
halfData[y][x] = new half[sampleCount[y][x]];
}
}
void allocatePixels(int type, Array2D<unsigned int>& sampleCount,
Array2D<unsigned int*>& uintData, Array2D<float*>& floatData,
Array2D<half*>& halfData, int width, int height)
{
allocatePixels(type, sampleCount, uintData, floatData, halfData, 0, width - 1, 0, height - 1);
}
void releasePixels(int type, Array2D<unsigned int*>& uintData, Array2D<float*>& floatData,
Array2D<half*>& halfData, int x1, int x2, int y1, int y2)
{
for (int y = y1; y <= y2; y++)
for (int x = x1; x <= x2; x++)
{
if (type == 0)
delete[] uintData[y][x];
if (type == 1)
delete[] floatData[y][x];
if (type == 2)
delete[] halfData[y][x];
}
}
void releasePixels(int type, Array2D<unsigned int*>& uintData, Array2D<float*>& floatData,
Array2D<half*>& halfData, int width, int height)
{
releasePixels(type, uintData, floatData, halfData, 0, width - 1, 0, height - 1);
}
template <class T>
bool checkPixels (Array2D<T> &ph, int lx, int rx, int ly, int ry, int width)
{
for (int y = ly; y <= ry; ++y)
for (int x = lx; x <= rx; ++x)
if (ph[y][x] != (y * width + x) % 2049)
{
cout << "value at " << x << ", " << y << ": " << ph[y][x]
<< ", should be " << (y * width + x) % 2049 << endl << flush;
return false;
}
return true;
}
template <class T>
bool checkPixels (Array2D<T> &ph, int width, int height)
{
return checkPixels<T> (ph, 0, width - 1, 0, height - 1, width);
}
template <class T>
bool checkPixels (Array2D<unsigned int>& sampleCount, Array2D<T*> &ph,
int lx, int rx, int ly, int ry, int width)
{
for (int y = ly; y <= ry; ++y)
for (int x = lx; x <= rx; ++x)
{
for (int i = 0; i < sampleCount[y][x]; i++)
{
if (ph[y][x][i] != (y * width + x) % 2049)
{
cout << "value at " << x << ", " << y << ", sample " << i << ": " << ph[y][x][i]
<< ", should be " << (y * width + x) % 2049 << endl << flush;
return false;
}
}
}
return true;
}
template <class T>
bool checkPixels (Array2D<unsigned int>& sampleCount, Array2D<T*> &ph, int width, int height)
{
return checkPixels<T> (sampleCount, ph, 0, width - 1, 0, height - 1, width);
}
bool checkSampleCount(Array2D<unsigned int>& sampleCount, int x1, int x2, int y1, int y2, int width)
{
for (int i = y1; i <= y2; i++)
for (int j = x1; j <= x2; j++)
{
if (sampleCount[i][j] != ((i * width) + j) % 10 + 1)
{
cout << "sample count at " << j << ", " << i << ": " << sampleCount[i][j]
<< ", should be " << (i * width + j) % 10 + 1 << endl << flush;
return false;
}
}
return true;
}
bool checkSampleCount(Array2D<unsigned int>& sampleCount, int width, int height)
{
return checkSampleCount(sampleCount, 0, width - 1, 0, height - 1, width);
}
void generateRandomHeaders(int partCount, vector<Header>& headers)
{
cout << "Generating headers and data" << endl << flush;
headers.clear();
for (int i = 0; i < partCount; i++)
{
Header header (width,
height,
1.f,
IMATH_NAMESPACE::V2f (0, 0),
1.f,
INCREASING_Y,
ZIPS_COMPRESSION);
int pixelType = rand() % 3;
int partType = rand() % 2;
pixelTypes[i] = pixelType;
partTypes[i] = partType;
stringstream ss;
ss << i;
header.setName(ss.str());
switch (pixelType)
{
case 0:
header.channels().insert("UINT", Channel(IMF::UINT));
break;
case 1:
header.channels().insert("FLOAT", Channel(IMF::FLOAT));
break;
case 2:
header.channels().insert("HALF", Channel(IMF::HALF));
break;
}
switch (partType)
{
case 0:
header.setType(SCANLINEIMAGE);
break;
case 1:
header.setType(TILEDIMAGE);
break;
}
int tileX;
int tileY;
int levelMode;
if (partType == 1)
{
tileX = rand() % width + 1;
tileY = rand() % height + 1;
levelMode = rand() % 3;
levelModes[i] = levelMode;
LevelMode lm;
switch (levelMode)
{
case 0:
lm = ONE_LEVEL;
break;
case 1:
lm = MIPMAP_LEVELS;
break;
case 2:
lm = RIPMAP_LEVELS;
break;
}
header.setTileDescription(TileDescription(tileX, tileY, lm));
}
int order = rand() % NUM_LINEORDERS;
if(partType==0 || partType ==2)
{
// can't write random scanlines
order = rand() % (NUM_LINEORDERS-1);
}
LineOrder l;
switch(order)
{
case 0 :
l = INCREASING_Y;
break;
case 1 :
l = DECREASING_Y;
break;
case 2 :
l = RANDOM_Y;
break;
}
header.lineOrder()=l;
if (partType == 0)
{
cout << "pixelType = " << pixelType << " partType = " << partType
<< " line order =" << header.lineOrder() << endl << flush;
}
else
{
cout << "pixelType = " << pixelType << " partType = " << partType
<< " tile order =" << header.lineOrder()
<< " levelMode = " << levelModes[i] << endl << flush;
}
headers.push_back(header);
}
}
void setOutputFrameBuffer(FrameBuffer& frameBuffer, int pixelType,
Array2D<unsigned int>& uData, Array2D<float>& fData,
Array2D<half>& hData, int width)
{
switch (pixelType)
{
case 0:
frameBuffer.insert ("UINT",
Slice (IMF::UINT,
(char *) (&uData[0][0]),
sizeof (uData[0][0]) * 1,
sizeof (uData[0][0]) * width));
break;
case 1:
frameBuffer.insert ("FLOAT",
Slice (IMF::FLOAT,
(char *) (&fData[0][0]),
sizeof (fData[0][0]) * 1,
sizeof (fData[0][0]) * width));
break;
case 2:
frameBuffer.insert ("HALF",
Slice (IMF::HALF,
(char *) (&hData[0][0]),
sizeof (hData[0][0]) * 1,
sizeof (hData[0][0]) * width));
break;
}
}
void setInputFrameBuffer(FrameBuffer& frameBuffer, int pixelType,
Array2D<unsigned int>& uData, Array2D<float>& fData,
Array2D<half>& hData, int width, int height)
{
switch (pixelType)
{
case 0:
uData.resizeErase(height, width);
frameBuffer.insert ("UINT",
Slice (IMF::UINT,
(char *) (&uData[0][0]),
sizeof (uData[0][0]) * 1,
sizeof (uData[0][0]) * width,
1, 1,
0));
break;
case 1:
fData.resizeErase(height, width);
frameBuffer.insert ("FLOAT",
Slice (IMF::FLOAT,
(char *) (&fData[0][0]),
sizeof (fData[0][0]) * 1,
sizeof (fData[0][0]) * width,
1, 1,
0));
break;
case 2:
hData.resizeErase(height, width);
frameBuffer.insert ("HALF",
Slice (IMF::HALF,
(char *) (&hData[0][0]),
sizeof (hData[0][0]) * 1,
sizeof (hData[0][0]) * width,
1, 1,
0));
break;
}
}
void
generateRandomFile (int partCount, const std::string & fn)
{
//
// Init data.
//
Array2D<half> halfData;
Array2D<float> floatData;
Array2D<unsigned int> uintData;
Array2D<unsigned int> sampleCount;
Array2D<half*> deepHalfData;
Array2D<float*> deepFloatData;
Array2D<unsigned int*> deepUintData;
vector<GenericOutputFile*> outputfiles;
pixelTypes.resize(partCount);
partTypes.resize(partCount);
levelModes.resize(partCount);
//
// Generate headers and data.
//
generateRandomHeaders(partCount, headers);
remove(fn.c_str());
MultiPartOutputFile file(fn.c_str(), &headers[0],headers.size());
//
// Writing files.
//
cout << "Writing files " << flush;
//
// Pre-generating frameBuffers.
//
for (int i = 0; i < partCount; i++)
{
switch (partTypes[i])
{
case 0:
{
OutputPart part(file, i);
FrameBuffer frameBuffer;
fillPixels <unsigned int> (uintData, width, height);
fillPixels <float> (floatData, width, height);
fillPixels <half> (halfData, width, height);
setOutputFrameBuffer(frameBuffer, pixelTypes[i], uintData, floatData, halfData, width);
part.setFrameBuffer(frameBuffer);
part.writePixels(height);
break;
}
case 1:
{
TiledOutputPart part(file, i);
int numXLevels = part.numXLevels();
int numYLevels = part.numYLevels();
for (int xLevel = 0; xLevel < numXLevels; xLevel++)
for (int yLevel = 0; yLevel < numYLevels; yLevel++)
{
if (!part.isValidLevel(xLevel, yLevel))
continue;
int w = part.levelWidth(xLevel);
int h = part.levelHeight(yLevel);
FrameBuffer frameBuffer;
fillPixels <unsigned int> (uintData, w, h);
fillPixels <float> (floatData, w, h);
fillPixels <half> (halfData, w, h);
setOutputFrameBuffer(frameBuffer, pixelTypes[i],
uintData, floatData, halfData,
w);
part.setFrameBuffer(frameBuffer);
part.writeTiles(0, part.numXTiles(xLevel) - 1,
0, part.numYTiles(yLevel) - 1,
xLevel, yLevel);
}
break;
}
}
}
}
void
readWholeFiles (const std::string & fn)
{
Array2D<unsigned int> uData;
Array2D<float> fData;
Array2D<half> hData;
Array2D<unsigned int*> deepUData;
Array2D<float*> deepFData;
Array2D<half*> deepHData;
Array2D<unsigned int> sampleCount;
MultiPartInputFile file(fn.c_str());
for (size_t i = 0; i < file.parts(); i++)
{
const Header& header = file.header(i);
assert (header.displayWindow() == headers[i].displayWindow());
assert (header.dataWindow() == headers[i].dataWindow());
assert (header.pixelAspectRatio() == headers[i].pixelAspectRatio());
assert (header.screenWindowCenter() == headers[i].screenWindowCenter());
assert (header.screenWindowWidth() == headers[i].screenWindowWidth());
assert (header.lineOrder() == headers[i].lineOrder());
assert (header.compression() == headers[i].compression());
assert (header.channels() == headers[i].channels());
assert (header.name() == headers[i].name());
assert (header.type() == headers[i].type());
}
cout << "Reading whole files " << flush;
//
// Shuffle part numbers.
//
vector<int> shuffledPartNumber;
for (int i = 0; i < headers.size(); i++)
shuffledPartNumber.push_back(i);
for (int i = 0; i < headers.size(); i++)
{
int a = rand() % headers.size();
int b = rand() % headers.size();
swap (shuffledPartNumber[a], shuffledPartNumber[b]);
}
//
// Start reading whole files.
//
int i;
int partNumber;
try
{
for (i = 0; i < headers.size(); i++)
{
partNumber = shuffledPartNumber[i];
FrameBuffer frameBuffer;
setInputFrameBuffer(frameBuffer, pixelTypes[partNumber],
uData, fData, hData, width, height);
InputPart part(file, partNumber);
part.setFrameBuffer(frameBuffer);
part.readPixels(0, height - 1);
switch (pixelTypes[partNumber])
{
case 0:
assert(checkPixels<unsigned int>(uData, width, height));
break;
case 1:
assert(checkPixels<float>(fData, width, height));
break;
case 2:
assert(checkPixels<half>(hData, width, height));
break;
}
}
}
catch (...)
{
cout << "Error while reading part " << partNumber << endl << flush;
throw;
}
}
void
readFirstPart (const std::string & fn)
{
Array2D<unsigned int> uData;
Array2D<float> fData;
Array2D<half> hData;
Array2D<unsigned int*> deepUData;
Array2D<float*> deepFData;
Array2D<half*> deepHData;
Array2D<unsigned int> sampleCount;
cout << "Reading first part " << flush;
int pixelType = pixelTypes[0];
int levelMode = levelModes[0];
int l1, l2;
l1 = rand() % height;
l2 = rand() % height;
if (l1 > l2) swap(l1, l2);
InputFile part(fn.c_str());
FrameBuffer frameBuffer;
setInputFrameBuffer(frameBuffer, pixelType,
uData, fData, hData, width, height);
part.setFrameBuffer(frameBuffer);
part.readPixels(l1, l2);
switch (pixelType)
{
case 0:
assert(checkPixels<unsigned int>(uData, 0, width - 1, l1, l2, width));
break;
case 1:
assert(checkPixels<float>(fData, 0, width - 1, l1, l2, width));
break;
case 2:
assert(checkPixels<half>(hData, 0, width - 1, l1, l2, width));
break;
}
}
void
readPartialFiles (int randomReadCount, const std::string & fn)
{
Array2D<unsigned int> uData;
Array2D<float> fData;
Array2D<half> hData;
Array2D<unsigned int*> deepUData;
Array2D<float*> deepFData;
Array2D<half*> deepHData;
Array2D<unsigned int> sampleCount;
cout << "Reading partial files " << flush;
MultiPartInputFile file(fn.c_str());
for (int i = 0; i < randomReadCount; i++)
{
int partNumber = rand() % file.parts();
int partType = partTypes[partNumber];
int pixelType = pixelTypes[partNumber];
int levelMode = levelModes[partNumber];
int l1, l2;
l1 = rand() % height;
l2 = rand() % height;
if (l1 > l2) swap(l1, l2);
InputPart part(file, partNumber);
FrameBuffer frameBuffer;
setInputFrameBuffer(frameBuffer, pixelType,
uData, fData, hData, width, height);
part.setFrameBuffer(frameBuffer);
part.readPixels(l1, l2);
switch (pixelType)
{
case 0:
assert(checkPixels<unsigned int>(uData, 0, width - 1, l1, l2, width));
break;
case 1:
assert(checkPixels<float>(fData, 0, width - 1, l1, l2, width));
break;
case 2:
assert(checkPixels<half>(hData, 0, width - 1, l1, l2, width));
break;
}
}
}
void
testWriteRead (int partNumber,
int runCount,
int randomReadCount,
const std::string & tempDir)
{
cout << "Testing file with " << partNumber << " part(s)." << endl << flush;
const std::string fn = tempDir + "imf_test_input_part.exr";
for (int i = 0; i < runCount; i++)
{
generateRandomFile (partNumber, fn);
readWholeFiles (fn);
readFirstPart (fn);
readPartialFiles (randomReadCount, fn);
remove (fn.c_str());
cout << endl << flush;
}
}
} // namespace
void testInputPart (const std::string & tempDir)
{
try
{
cout << "Testing reading multipart tiles and scanlines with InputPart" << endl;
srand(1);
int numThreads = ThreadPool::globalThreadPool().numThreads();
ThreadPool::globalThreadPool().setNumThreads(4);
testWriteRead ( 1, 1, 5, tempDir);
testWriteRead ( 2, 2, 1, tempDir);
testWriteRead ( 8, 4, 2, tempDir);
testWriteRead (50, 3, 11, tempDir);
ThreadPool::globalThreadPool().setNumThreads(numThreads);
cout << "ok\n" << endl;
}
catch (const std::exception &e)
{
cerr << "ERROR -- caught exception: " << e.what() << endl;
assert (false);
}
}

View File

@ -0,0 +1,42 @@
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2011, 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.
//
///////////////////////////////////////////////////////////////////////////
#ifndef TESTINPUTPART_H_
#define TESTINPUTPART_H_
#include <string>
void testInputPart (const std::string & tempDir);
#endif /* TESTINPUTPART_H_ */

View File

@ -0,0 +1,166 @@
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2005-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 <ImfRgbaFile.h>
#include <ImfTiledRgbaFile.h>
#include <ImfArray.h>
#include <stdio.h>
#include <assert.h>
using namespace OPENEXR_IMF_NAMESPACE;
using namespace std;
using namespace IMATH_NAMESPACE;
namespace {
void
writeFiles (const char completeScanLinesName[],
const char incompleteScanLinesName[],
const char completeTilesName[],
const char incompleteTilesName[],
int width,
int height,
int tileXSize,
int tileYSize)
{
Array2D <Rgba> pixels (height, width);
for (int y = 0; y < height; ++y)
for (int x = 0; x < width; ++x)
pixels[y][x] = Rgba (x, y, 0.0, 1.0);
{
RgbaOutputFile out (completeScanLinesName, width, height);
out.setFrameBuffer (&pixels[0][0], 1, width);
out.writePixels (height);
}
{
RgbaOutputFile out (incompleteScanLinesName, width, height);
out.setFrameBuffer (&pixels[0][0], 1, width);
out.writePixels (height - 1);
}
{
TiledRgbaOutputFile out (completeTilesName,
width, height,
tileXSize, tileYSize,
ONE_LEVEL);
out.setFrameBuffer (&pixels[0][0], 1, width);
out.writeTiles (0, out.numXTiles() - 1, 0, out.numYTiles() - 1);
}
{
TiledRgbaOutputFile out (incompleteTilesName,
width, height,
tileXSize, tileYSize,
ONE_LEVEL);
out.setFrameBuffer (&pixels[0][0], 1, width);
out.writeTiles (0, out.numXTiles() - 1, 0, out.numYTiles() - 2);
}
}
void
checkFiles (const char completeScanLinesName[],
const char incompleteScanLinesName[],
const char completeTilesName[],
const char incompleteTilesName[])
{
{
RgbaInputFile in (completeScanLinesName);
assert (in.isComplete());
}
{
RgbaInputFile in (incompleteScanLinesName);
assert (!in.isComplete());
}
{
RgbaInputFile in (completeTilesName);
assert (in.isComplete());
}
{
RgbaInputFile in (incompleteTilesName);
assert (!in.isComplete());
}
{
TiledRgbaInputFile in (completeTilesName);
assert (in.isComplete());
}
{
TiledRgbaInputFile in (incompleteTilesName);
assert (!in.isComplete());
}
}
} // namespace
void
testIsComplete (const std::string &tempDir)
{
try
{
cout << "Testing isComplete() function" << endl;
std::string csl = tempDir + "imf_test_complete_sl.exr";
std::string icsl = tempDir + "imf_test_incomplete_sl.exr";
std::string ct = tempDir + "imf_test_complete_t.exr";
std::string ict = tempDir + "imf_test_incomplete_t.exr";
writeFiles (csl.c_str(), icsl.c_str(), ct.c_str(), ict.c_str(), 327, 289, 17, 17);
checkFiles (csl.c_str(), icsl.c_str(), ct.c_str(), ict.c_str());
remove (csl.c_str());
remove (icsl.c_str());
remove (ct.c_str());
remove (ict.c_str());
cout << "ok\n" << endl;
}
catch (const std::exception &e)
{
cerr << "ERROR -- caught exception: " << e.what() << endl;
assert (false);
}
}

View File

@ -0,0 +1,42 @@
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2005-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 <string>
void testIsComplete (const std::string &tempDir);

View File

@ -0,0 +1,227 @@
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2002-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 <ImfOutputFile.h>
#include <ImfInputFile.h>
#include <ImfChannelList.h>
#include <ImfArray.h>
#include <ImfThreading.h>
#include "IlmThread.h"
#include "half.h"
#include <stdio.h>
#include <assert.h>
using namespace OPENEXR_IMF_NAMESPACE;
using namespace std;
using namespace IMATH_NAMESPACE;
namespace {
void
fillPixels (Array2D<half> &ph, int width, int height)
{
for (int y = 0; y < height; ++y)
for (int x = 0; x < width; ++x)
ph[y][x] = x % 10 + 10 * (y % 17);
}
void
writeRead (const Array2D<half> &ph1,
const char fileName[],
int width,
int height,
LineOrder lorder)
{
//
// Write the pixel data in ph1 to an image file using
// the specified line order. Read the pixel data back
// from the file in pseudo-random order and verify that
// the data did not change.
//
cout << "line order " << lorder <<
":" << flush;
Header hdr (width, height);
hdr.lineOrder() = lorder;
hdr.channels().insert ("H", // name
Channel (HALF, // type
1, // xSampling
1) // ySampling
);
{
FrameBuffer fb;
fb.insert ("H", // name
Slice (HALF, // type
(char *) &ph1[0][0], // base
sizeof (ph1[0][0]), // xStride
sizeof (ph1[0][0]) * width, // yStride
1, // xSampling
1) // ySampling
);
cout << " writing" << flush;
remove (fileName);
OutputFile out (fileName, hdr);
out.setFrameBuffer (fb);
out.writePixels (height);
}
{
cout << " reading" << flush;
InputFile in (fileName);
const Box2i &dw = in.header().dataWindow();
int w = dw.max.x - dw.min.x + 1;
int h = dw.max.y - dw.min.y + 1;
int dx = dw.min.x;
int dy = dw.min.y;
Array2D<half> ph2 (h, w);
FrameBuffer fb;
fb.insert ("H", // name
Slice (HALF, // type
(char *) &ph2[-dy][-dx], // base
sizeof (ph2[0][0]), // xStride
sizeof (ph2[0][0]) * w, // yStride
1, // xSampling
1) // ySampling
);
in.setFrameBuffer (fb);
//
// Read the scan lines in this order:
// 0, N, 2N, 3N, ... 1, N+1, 2N+1, ... 2, N+2, 2N+2, ...
//
const int N = 7;
for (int i = 0; i < N; ++i)
for (int y = dw.min.y + i; y <= dw.max.y; y += N)
in.readPixels (y);
cout << " comparing" << flush;
assert (in.header().displayWindow() == hdr.displayWindow());
assert (in.header().dataWindow() == hdr.dataWindow());
assert (in.header().pixelAspectRatio() == hdr.pixelAspectRatio());
assert (in.header().screenWindowCenter() == hdr.screenWindowCenter());
assert (in.header().screenWindowWidth() == hdr.screenWindowWidth());
assert (in.header().lineOrder() == hdr.lineOrder());
assert (in.header().compression() == hdr.compression());
ChannelList::ConstIterator hi = hdr.channels().begin();
ChannelList::ConstIterator ii = in.header().channels().begin();
while (hi != hdr.channels().end())
{
assert (!strcmp (hi.name(), ii.name()));
assert (hi.channel().type == ii.channel().type);
assert (hi.channel().xSampling == ii.channel().xSampling);
assert (hi.channel().ySampling == ii.channel().ySampling);
++hi;
++ii;
}
assert (ii == in.header().channels().end());
for (int y = 0; y < h; ++y)
for (int x = 0; x < w; ++x)
assert (ph1[y][x] == ph2[y][x]);
}
remove (fileName);
cout << endl;
}
} // namespace
void
testLineOrder (const std::string &tempDir)
{
try
{
cout << "Testing line order and random access to scan lines" << endl;
const int W = 117;
const int H = 97;
Array2D<half> ph (H, W);
fillPixels (ph, W, H);
int maxThreads = ILMTHREAD_NAMESPACE::supportsThreads()? 3: 0;
for (int n = 0; n <= maxThreads; ++n)
{
if (ILMTHREAD_NAMESPACE::supportsThreads())
{
setGlobalThreadCount (n);
cout << "\nnumber of threads: " << globalThreadCount() << endl;
}
std::string filename = tempDir + "imf_test_lorder.exr";
for (int lorder = 0; lorder < RANDOM_Y; ++lorder)
{
writeRead (ph,
filename.c_str(),
W, H,
LineOrder (lorder));
}
}
cout << "ok\n" << endl;
}
catch (const std::exception &e)
{
cerr << "ERROR -- caught exception: " << e.what() << endl;
assert (false);
}
}

View File

@ -0,0 +1,41 @@
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2002-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 <string>
void testLineOrder (const std::string &tempDir);

View File

@ -0,0 +1,256 @@
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2002-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 <ImfLut.h>
#include <ImfArray.h>
#include "ImathRandom.h"
#include <iostream>
#include <assert.h>
using namespace OPENEXR_IMF_NAMESPACE;
using namespace std;
using namespace IMATH_NAMESPACE;
namespace {
half
one (half)
{
return 1;
}
void
testHalfLut ()
{
const int NX = 67;
const int NY = 31;
Array2D<half> h (NY, NX);
HalfLut lut (one);
//
// apply (data, nData, stride);
//
for (int y = 0; y < NY; ++y)
for (int x = 0; x < NX; ++x)
h[y][x] = 0;
lut.apply (&h[0][0], NX * NY, 1);
for (int y = 0; y < NY; ++y)
for (int x = 0; x < NX; ++x)
assert (h[y][x] == 1);
//
// apply (slice, dataWindow);
//
for (int y = 0; y < NY; ++y)
for (int x = 0; x < NX; ++x)
h[y][x] = 0;
Slice s (HALF, // type
(char *) &h[0][0], // base
sizeof (h[0][0]), // xStride
sizeof (h[0][0]) * NX, // yStride
1, 1); // xSampling, ySampling
Box2i dw (V2i (3, 5), V2i (45, 27));
lut.apply (s, dw);
for (int y = 0; y < NY; ++y)
for (int x = 0; x < NX; ++x)
if (dw.intersects (V2i (x, y)))
assert (h[y][x] == 1);
else
assert (h[y][x] == 0);
}
void
testRgbaLut ()
{
const int NX = 67;
const int NY = 31;
Array2D<Rgba> rgba (NY, NX);
RgbaLut lut (one, WRITE_RGB);
//
// apply (data, nData, stride);
//
for (int y = 0; y < NY; ++y)
{
for (int x = 0; x < NX; ++x)
{
rgba[y][x].r = 0;
rgba[y][x].g = 0;
rgba[y][x].b = 0;
rgba[y][x].a = 0;
}
}
lut.apply (&rgba[0][0], NX * NY, 1);
for (int y = 0; y < NY; ++y)
{
for (int x = 0; x < NX; ++x)
{
assert (rgba[y][x].r == 1);
assert (rgba[y][x].g == 1);
assert (rgba[y][x].b == 1);
assert (rgba[y][x].a == 0);
}
}
//
// apply (base, xStride, yStride, dataWindow);
//
for (int y = 0; y < NY; ++y)
{
for (int x = 0; x < NX; ++x)
{
rgba[y][x].r = 0;
rgba[y][x].g = 0;
rgba[y][x].b = 0;
rgba[y][x].a = 0;
}
}
Box2i dw (V2i (3, 5), V2i (45, 27));
lut.apply (&rgba[0][0], 1, NX, dw);
for (int y = 0; y < NY; ++y)
{
for (int x = 0; x < NX; ++x)
{
if (dw.intersects (V2i (x, y)))
{
assert (rgba[y][x].r == 1);
assert (rgba[y][x].g == 1);
assert (rgba[y][x].b == 1);
assert (rgba[y][x].a == 0);
}
else
{
assert (rgba[y][x].r == 0);
assert (rgba[y][x].g == 0);
assert (rgba[y][x].b == 0);
assert (rgba[y][x].a == 0);
}
}
}
}
void
testRounding ()
{
//
// For each rounding function, f,
// f(f(x)) == f(x) must be true.
//
Rand32 rand;
for (int i = 0; i < 10000; ++i)
{
half h = rand.nextf (HALF_MIN, HALF_MAX);
assert (round12log (h) == round12log (round12log (h)));
}
for (int n = 0; n <= 10; ++n)
{
roundNBit rn (n);
for (int i = 0; i < 10000; ++i)
{
half h = rand.nextf (HALF_MIN, HALF_MAX);
assert (rn (h) == rn (rn (h)));
}
}
//
// Special cases:
//
assert (round12log (-1) == 0);
assert (round12log (0) == 0);
assert (round12log (0.5) == 0.5);
assert (round12log (1) == 1);
assert (round12log (2) == 2);
roundNBit r3 (3);
assert (r3 (-1) == -1);
assert (r3 (0) == 0);
assert (r3 (0.5) == 0.5);
assert (r3 (1) == 1);
assert (r3 (2) == 2);
}
} // namespace
void
testLut (const std::string&)
{
try
{
cout << "Testing lookup tables" << endl;
testHalfLut();
testRgbaLut();
testRounding();
cout << "ok\n" << endl;
}
catch (const std::exception &e)
{
cerr << "ERROR -- caught exception: " << e.what() << endl;
assert (false);
}
}

View File

@ -0,0 +1,41 @@
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2002-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 <string>
void testLut (const std::string &tempDir);

View File

@ -0,0 +1,140 @@
//////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2003-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 <ImfVersion.h>
#include <ImfTestFile.h>
#include <ImfStdIO.h>
#include <iostream>
#include <exception>
#include <stdio.h>
#include <assert.h>
#ifndef ILM_IMF_TEST_IMAGEDIR
#define ILM_IMF_TEST_IMAGEDIR
#endif
using namespace OPENEXR_IMF_NAMESPACE;
using namespace std;
namespace {
void
testFile1 (const char fileName[], bool isImfFile)
{
cout << fileName << " " << flush;
ifstream f (fileName, ios_base::binary);
assert (!!f);
char bytes[4];
f.read (bytes, sizeof (bytes));
assert (!!f && isImfFile == isImfMagic (bytes));
cout << "is " << (isImfMagic (bytes)? "": "not ") << "an OpenEXR file\n";
}
void
testFile2 (const char fileName[], bool exists, bool exrFile, bool tiledFile)
{
cout << fileName << " " << flush;
bool exr, tiled;
exr = isOpenExrFile (fileName, tiled);
assert (exr == exrFile && tiled == tiledFile);
exr = isOpenExrFile (fileName);
assert (exr == exrFile);
tiled = isTiledOpenExrFile (fileName);
assert (tiled == tiledFile);
if (exists)
{
StdIFStream is (fileName);
exr = isOpenExrFile (is, tiled);
assert (exr == exrFile && tiled == tiledFile);
if (exr)
assert (is.tellg() == 0);
exr = isOpenExrFile (is);
assert (exr == exrFile);
if (exr)
assert (is.tellg() == 0);
tiled = isTiledOpenExrFile (is);
assert (tiled == tiledFile);
if (tiled)
assert (is.tellg() == 0);
}
cout << (exists? "exists": "does not exist") << ", " <<
(exrFile? "is an OpenEXR file": "is not an OpenEXR file") << ", " <<
(tiledFile? "is tiled": "is not tiled") << endl;
}
} // namespace
void
testMagic (const std::string &)
{
try
{
cout << "Testing magic number" << endl;
testFile1 (ILM_IMF_TEST_IMAGEDIR "comp_none.exr", true);
testFile1 (ILM_IMF_TEST_IMAGEDIR "invalid.exr", false);
testFile2 (ILM_IMF_TEST_IMAGEDIR "tiled.exr", true, true, true);
testFile2 (ILM_IMF_TEST_IMAGEDIR "comp_none.exr", true, true, false);
testFile2 (ILM_IMF_TEST_IMAGEDIR "invalid.exr", true, false, false);
testFile2 (ILM_IMF_TEST_IMAGEDIR "does_not_exist.exr", false, false, false);
cout << "ok\n" << endl;
}
catch (const std::exception &e)
{
cerr << "ERROR -- caught exception: " << e.what() << endl;
assert (false);
}
}

View File

@ -0,0 +1,38 @@
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2003-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 <string>
void testMagic(const std::string &tempDir);

View File

@ -0,0 +1,744 @@
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2011, 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 <iostream>
#include <string>
#include <vector>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "tmpDir.h"
#include "testMultiPartApi.h"
#include <ImfPartType.h>
#include <ImfMultiPartInputFile.h>
#include <ImfMultiPartOutputFile.h>
#include <ImfOutputFile.h>
#include <ImfTiledOutputFile.h>
#include <ImfGenericOutputFile.h>
#include <ImfArray.h>
#include <ImfChannelList.h>
#include <ImfOutputPart.h>
#include <ImfInputPart.h>
#include <ImfTiledOutputPart.h>
#include <ImfTiledInputPart.h>
#include <ImfTiledMisc.h>
namespace IMF = OPENEXR_IMF_NAMESPACE;
using namespace IMF;
using namespace std;
using namespace IMATH_NAMESPACE;
namespace
{
const int height = 263;
const int width = 197;
struct Task
{
int partNumber;
int tx, ty, lx, ly;
Task(int partNumber):
partNumber(partNumber)
{}
Task(int partNumber, int tx, int ty, int lx, int ly):
partNumber(partNumber),
tx(tx),
ty(ty),
lx(lx),
ly(ly)
{}
};
vector<Header> headers;
vector<int> pixelTypes;
vector<int> partTypes;
vector<int> levelModes;
template <class T>
void fillPixels (Array2D<T> &ph, int width, int height)
{
ph.resizeErase(height, width);
for (int y = 0; y < height; ++y)
for (int x = 0; x < width; ++x)
{
//
// We do this because half cannot store number bigger than 2048 exactly.
//
ph[y][x] = (y * width + x) % 2049;
}
}
template <class T>
bool checkPixels (Array2D<T> &ph, int lx, int rx, int ly, int ry, int width)
{
for (int y = ly; y <= ry; ++y)
for (int x = lx; x <= rx; ++x)
if (ph[y][x] != (y * width + x) % 2049)
{
cout << "value at " << x << ", " << y << ": " << ph[y][x]
<< ", should be " << (y * width + x) % 2049 << endl << flush;
return false;
}
return true;
}
template <class T>
bool checkPixels (Array2D<T> &ph, int width, int height)
{
return checkPixels<T> (ph, 0, width - 1, 0, height - 1, width);
}
void generateRandomHeaders(int partCount, vector<Header>& headers, vector<Task>& taskList)
{
headers.clear();
for (int i = 0; i < partCount; i++)
{
Header header(width, height);
int pixelType = rand() % 3;
int partType = rand() % 2;
pixelTypes[i] = pixelType;
partTypes[i] = partType;
stringstream ss;
ss << i;
header.setName(ss.str());
switch (pixelType)
{
case 0:
header.channels().insert("UINT", Channel(IMF::UINT));
break;
case 1:
header.channels().insert("FLOAT", Channel(IMF::FLOAT));
break;
case 2:
header.channels().insert("HALF", Channel(IMF::HALF));
break;
}
switch (partType)
{
case 0:
header.setType(SCANLINEIMAGE);
break;
case 1:
header.setType(TILEDIMAGE);
break;
}
int tileX;
int tileY;
int levelMode;
if (partType == 1)
{
tileX = rand() % width + 1;
tileY = rand() % height + 1;
levelMode = rand() % 3;
levelModes[i] = levelMode;
LevelMode lm;
switch (levelMode)
{
case 0:
lm = ONE_LEVEL;
break;
case 1:
lm = MIPMAP_LEVELS;
break;
case 2:
lm = RIPMAP_LEVELS;
break;
}
header.setTileDescription(TileDescription(tileX, tileY, lm));
}
//
// Add lines or tiles to task list.
//
if (partType == 0)
{
for (int j = 0; j < height; j++)
taskList.push_back(Task(i));
}
else
{
int numXLevel;
int numYLevel;
int* numXTiles;
int* numYTiles;
precalculateTileInfo (header.tileDescription(),
0, width - 1,
0, height - 1,
numXTiles, numYTiles,
numXLevel, numYLevel);
for (int lx = 0; lx < numXLevel; lx++)
for (int ly = 0; ly < numYLevel; ly++)
{
if (levelMode == 1)
if (lx != ly) continue;
// Get all tasks for this level.
for (int tx = 0; tx < numXTiles[lx]; tx++)
for (int ty = 0; ty < numYTiles[ly]; ty++)
taskList.push_back(Task(i, tx, ty, lx, ly));
}
delete[] numXTiles;
delete[] numYTiles;
}
// if (partType == 0)
// {
// cout << "pixelType = " << pixelType << " partType = " << partType
// << endl << flush;
// }
// else
// {
// cout << "pixelType = " << pixelType << " partType = " << partType
// << " levelMode = " << levelModes[i] << endl << flush;
// }
headers.push_back(header);
}
}
void setOutputFrameBuffer(FrameBuffer& frameBuffer, int pixelType,
Array2D<unsigned int>& uData, Array2D<float>& fData,
Array2D<half>& hData, int width)
{
switch (pixelType)
{
case 0:
frameBuffer.insert ("UINT",
Slice (IMF::UINT,
(char *) (&uData[0][0]),
sizeof (uData[0][0]) * 1,
sizeof (uData[0][0]) * width));
break;
case 1:
frameBuffer.insert ("FLOAT",
Slice (IMF::FLOAT,
(char *) (&fData[0][0]),
sizeof (fData[0][0]) * 1,
sizeof (fData[0][0]) * width));
break;
case 2:
frameBuffer.insert ("HALF",
Slice (IMF::HALF,
(char *) (&hData[0][0]),
sizeof (hData[0][0]) * 1,
sizeof (hData[0][0]) * width));
break;
}
}
void setInputFrameBuffer(FrameBuffer& frameBuffer, int pixelType,
Array2D<unsigned int>& uData, Array2D<float>& fData,
Array2D<half>& hData, int width, int height)
{
switch (pixelType)
{
case 0:
uData.resizeErase(height, width);
frameBuffer.insert ("UINT",
Slice (IMF::UINT,
(char *) (&uData[0][0]),
sizeof (uData[0][0]) * 1,
sizeof (uData[0][0]) * width,
1, 1,
0));
break;
case 1:
fData.resizeErase(height, width);
frameBuffer.insert ("FLOAT",
Slice (IMF::FLOAT,
(char *) (&fData[0][0]),
sizeof (fData[0][0]) * 1,
sizeof (fData[0][0]) * width,
1, 1,
0));
break;
case 2:
hData.resizeErase(height, width);
frameBuffer.insert ("HALF",
Slice (IMF::HALF,
(char *) (&hData[0][0]),
sizeof (hData[0][0]) * 1,
sizeof (hData[0][0]) * width,
1, 1,
0));
break;
}
}
void
generateRandomFile (int partCount, const std::string & fn)
{
//
// Init data.
//
Array2D<half> halfData;
Array2D<float> floatData;
Array2D<unsigned int> uintData;
fillPixels<unsigned int>(uintData, width, height);
fillPixels<half>(halfData, width, height);
fillPixels<float>(floatData, width, height);
Array2D< Array2D< half > >* tiledHalfData = new Array2D< Array2D< half > >[partCount];
Array2D< Array2D< float > >* tiledFloatData = new Array2D< Array2D< float > >[partCount];
Array2D< Array2D< unsigned int > >* tiledUintData = new Array2D< Array2D< unsigned int > >[partCount];
vector<GenericOutputFile*> outputfiles;
vector<Task> taskList;
pixelTypes.resize(partCount);
partTypes.resize(partCount);
levelModes.resize(partCount);
//
// Generate headers and data.
//
cout << "Generating headers and data " << flush;
generateRandomHeaders(partCount, headers, taskList);
//
// Shuffle tasks.
//
cout << "Shuffling " << taskList.size() << " tasks " << flush;
int taskListSize = taskList.size();
for (int i = 0; i < taskListSize; i++)
{
int a, b;
a = rand() % taskListSize;
b = rand() % taskListSize;
swap(taskList[a], taskList[b]);
}
remove(fn.c_str());
MultiPartOutputFile file(fn.c_str(), &headers[0],headers.size());
//
// Writing tasks.
//
cout << "Writing tasks " << flush;
//
// Pre-generating frameBuffers.
//
vector<void *> parts;
vector<FrameBuffer> frameBuffers(partCount);
Array<Array2D<FrameBuffer> > tiledFrameBuffers(partCount);
for (int i = 0; i < partCount; i++)
{
if (partTypes[i] == 0)
{
OutputPart* part = new OutputPart(file, i);
parts.push_back((void*) part);
FrameBuffer& frameBuffer = frameBuffers[i];
setOutputFrameBuffer(frameBuffer, pixelTypes[i], uintData, floatData, halfData, width);
part->setFrameBuffer(frameBuffer);
}
else
{
TiledOutputPart* part = new TiledOutputPart(file, i);
parts.push_back((void*) part);
int numXLevels = part->numXLevels();
int numYLevels = part->numYLevels();
// Allocating space.
switch (pixelTypes[i])
{
case 0:
tiledUintData[i].resizeErase(numYLevels, numXLevels);
break;
case 1:
tiledFloatData[i].resizeErase(numYLevels, numXLevels);
break;
case 2:
tiledHalfData[i].resizeErase(numYLevels, numXLevels);
break;
}
tiledFrameBuffers[i].resizeErase(numYLevels, numXLevels);
for (int xLevel = 0; xLevel < numXLevels; xLevel++)
for (int yLevel = 0; yLevel < numYLevels; yLevel++)
{
if (!part->isValidLevel(xLevel, yLevel))
continue;
int w = part->levelWidth(xLevel);
int h = part->levelHeight(yLevel);
FrameBuffer& frameBuffer = tiledFrameBuffers[i][yLevel][xLevel];
switch (pixelTypes[i])
{
case 0:
fillPixels<unsigned int>(tiledUintData[i][yLevel][xLevel], w, h);
break;
case 1:
fillPixels<float>(tiledFloatData[i][yLevel][xLevel], w, h);
break;
case 2:
fillPixels<half>(tiledHalfData[i][yLevel][xLevel], w, h);
break;
}
setOutputFrameBuffer(frameBuffer, pixelTypes[i],
tiledUintData[i][yLevel][xLevel],
tiledFloatData[i][yLevel][xLevel],
tiledHalfData[i][yLevel][xLevel],
w);
}
}
}
//
// Writing tasks.
//
for (int i = 0; i < taskListSize; i++)
{
int partNumber = taskList[i].partNumber;
int partType = partTypes[partNumber];
int pixelType = pixelTypes[partNumber];
int levelMode = levelModes[partNumber];
if (partType == 0)
{
OutputPart* part = (OutputPart*) parts[partNumber];
part->writePixels();
}
else
{
int tx = taskList[i].tx;
int ty = taskList[i].ty;
int lx = taskList[i].lx;
int ly = taskList[i].ly;
TiledOutputPart* part = (TiledOutputPart*) parts[partNumber];
part->setFrameBuffer(tiledFrameBuffers[partNumber][ly][lx]);
part->writeTile(tx, ty, lx, ly);
}
}
delete[] tiledHalfData;
delete[] tiledUintData;
delete[] tiledFloatData;
}
void
readWholeFiles (const std::string & fn)
{
Array2D<unsigned int> uData;
Array2D<float> fData;
Array2D<half> hData;
MultiPartInputFile file(fn.c_str());
for (size_t i = 0; i < file.parts(); i++)
{
const Header& header = file.header(i);
assert (header.displayWindow() == headers[i].displayWindow());
assert (header.dataWindow() == headers[i].dataWindow());
assert (header.pixelAspectRatio() == headers[i].pixelAspectRatio());
assert (header.screenWindowCenter() == headers[i].screenWindowCenter());
assert (header.screenWindowWidth() == headers[i].screenWindowWidth());
assert (header.lineOrder() == headers[i].lineOrder());
assert (header.compression() == headers[i].compression());
//
// It rarely fails here. Added code to see what's wrong when it happens.
//
ChannelList::ConstIterator i1 = header.channels().begin();
ChannelList::ConstIterator i2 = headers[i].channels().begin();
Channel c1 = i1.channel();
Channel c2 = i2.channel();
if (!(c1 == c2))
{
cout << " type is " << c1.type << ", should be " << c2.type
<< " xSampling is " << c1.xSampling << ", should be " << c2.xSampling
<< " ySampling is " << c1.ySampling << ", should be " << c2.ySampling
<< " pLinear is " << c1.pLinear << ", should be " << c2.pLinear << flush;
}
assert (header.channels() == headers[i].channels());
assert (header.name() == headers[i].name());
assert (header.type() == headers[i].type());
}
cout << "Reading whole files " << flush;
//
// Shuffle part numbers.
//
vector<int> shuffledPartNumber;
for (int i = 0; i < headers.size(); i++)
shuffledPartNumber.push_back(i);
for (int i = 0; i < headers.size(); i++)
{
int a = rand() % headers.size();
int b = rand() % headers.size();
swap (shuffledPartNumber[a], shuffledPartNumber[b]);
}
//
// Start reading whole files.
//
int i;
int partNumber;
try
{
for (i = 0; i < headers.size(); i++)
{
partNumber = shuffledPartNumber[i];
if (partTypes[partNumber] == 0)
{
FrameBuffer frameBuffer;
setInputFrameBuffer(frameBuffer, pixelTypes[partNumber],
uData, fData, hData, width, height);
InputPart part(file, partNumber);
part.setFrameBuffer(frameBuffer);
part.readPixels(0, height - 1);
switch (pixelTypes[partNumber])
{
case 0:
assert(checkPixels<unsigned int>(uData, width, height));
break;
case 1:
assert(checkPixels<float>(fData, width, height));
break;
case 2:
assert(checkPixels<half>(hData, width, height));
break;
}
}
else
{
FrameBuffer frameBuffer;
TiledInputPart part(file, partNumber);
int numXLevels = part.numXLevels();
int numYLevels = part.numYLevels();
for (int xLevel = 0; xLevel < numXLevels; xLevel++)
for (int yLevel = 0; yLevel < numYLevels; yLevel++)
{
if (!part.isValidLevel(xLevel, yLevel))
continue;
int w = part.levelWidth(xLevel);
int h = part.levelHeight(yLevel);
setInputFrameBuffer(frameBuffer, pixelTypes[partNumber],
uData, fData, hData, width, height);
part.setFrameBuffer(frameBuffer);
int numXTiles = part.numXTiles(xLevel);
int numYTiles = part.numYTiles(yLevel);
part.readTiles(0, numXTiles - 1, 0, numYTiles - 1, xLevel, yLevel);
switch (pixelTypes[partNumber])
{
case 0:
assert(checkPixels<unsigned int>(uData, w, h));
break;
case 1:
assert(checkPixels<float>(fData, w, h));
break;
case 2:
assert(checkPixels<half>(hData, w, h));
break;
}
}
}
}
}
catch (...)
{
cout << "Error while reading part " << partNumber << endl << flush;
throw;
}
}
void
readPartialFiles (int randomReadCount, const std::string & fn)
{
Array2D<unsigned int> uData;
Array2D<float> fData;
Array2D<half> hData;
cout << "Reading partial files " << flush;
MultiPartInputFile file(fn.c_str());
//const vector<Header>& headers = file.parts();
for (int i = 0; i < randomReadCount; i++)
{
int partNumber = rand() % headers.size();
int partType = partTypes[partNumber];
int pixelType = pixelTypes[partNumber];
int levelMode = levelModes[partNumber];
if (partType == 0)
{
int l1, l2;
l1 = rand() % height;
l2 = rand() % height;
if (l1 > l2) swap(l1, l2);
InputPart part(file, partNumber);
FrameBuffer frameBuffer;
setInputFrameBuffer(frameBuffer, pixelType,
uData, fData, hData, width, height);
part.setFrameBuffer(frameBuffer);
part.readPixels(l1, l2);
switch (pixelType)
{
case 0:
assert(checkPixels<unsigned int>(uData, 0, width - 1, l1, l2, width));
break;
case 1:
assert(checkPixels<float>(fData, 0, width - 1, l1, l2, width));
break;
case 2:
assert(checkPixels<half>(hData, 0, width - 1, l1, l2, width));
break;
}
}
else
{
int tx1, tx2, ty1, ty2;
int lx, ly;
TiledInputPart part(file, partNumber);
int numXLevels = part.numXLevels();
int numYLevels = part.numYLevels();
lx = rand() % numXLevels;
ly = rand() % numYLevels;
if (levelMode == 1) ly = lx;
int w = part.levelWidth(lx);
int h = part.levelHeight(ly);
int numXTiles = part.numXTiles(lx);
int numYTiles = part.numYTiles(ly);
tx1 = rand() % numXTiles;
tx2 = rand() % numXTiles;
ty1 = rand() % numYTiles;
ty2 = rand() % numYTiles;
if (tx1 > tx2) swap(tx1, tx2);
if (ty1 > ty2) swap(ty1, ty2);
FrameBuffer frameBuffer;
setInputFrameBuffer(frameBuffer, pixelType,
uData, fData, hData, w, h);
part.setFrameBuffer(frameBuffer);
part.readTiles(tx1, tx2, ty1, ty2, lx, ly);
Box2i b1 = part.dataWindowForTile(tx1, ty1, lx, ly);
Box2i b2 = part.dataWindowForTile(tx2, ty2, lx, ly);
switch (pixelType)
{
case 0:
assert(checkPixels<unsigned int>(uData, b1.min.x, b2.max.x, b1.min.y, b2.max.y,
w));
break;
case 1:
assert(checkPixels<float>(fData, b1.min.x, b2.max.x, b1.min.y, b2.max.y,
w));
break;
case 2:
assert(checkPixels<half>(hData, b1.min.x, b2.max.x, b1.min.y, b2.max.y,
w));
break;
}
}
}
}
void
testWriteRead (int partNumber,
int runCount,
int randomReadCount,
const std::string & tempDir)
{
cout << "Testing file with " << partNumber << " part(s)." << endl << flush;
std::string fn = tempDir + "imf_test_multipart_api.exr";
for (int i = 0; i < runCount; i++)
{
generateRandomFile (partNumber, fn);
readWholeFiles (fn);
readPartialFiles (randomReadCount, fn);
remove (fn.c_str());
cout << endl << flush;
}
}
} // namespace
void testMultiPartApi (const std::string & tempDir)
{
try
{
cout << "Testing the multi part APIs for normal use" << endl;
srand(1);
testWriteRead ( 1, 2, 5, tempDir);
testWriteRead ( 2, 5, 10, tempDir);
testWriteRead ( 5, 1, 25, tempDir);
testWriteRead (50, 2, 100, tempDir);
cout << "ok\n" << endl;
}
catch (const std::exception &e)
{
cerr << "ERROR -- caught exception: " << e.what() << endl;
assert (false);
}
}

View File

@ -0,0 +1,42 @@
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2011, 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.
//
///////////////////////////////////////////////////////////////////////////
#ifndef TESTMULTIPARTAPI_H_
#define TESTMULTIPARTAPI_H_
#include <string>
void testMultiPartApi (const std::string & tempDir);
#endif /* TESTMULTIPARTAPI_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,42 @@
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2011, 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.
//
///////////////////////////////////////////////////////////////////////////
#ifndef TESTMULTIPARTFILEMIXINGBASIC_H_
#define TESTMULTIPARTFILEMIXINGBASIC_H_
#include <string>
void testMultiPartFileMixingBasic (const std::string & tempDir);
#endif /* TESTMULTIPARTFILEMIXINGBASIC_H_ */

View File

@ -0,0 +1,527 @@
///////////////////////////////////////////////////////////////////////////
//
// 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 "testMultiPartSharedAttributes.h"
#include <ImfMultiPartInputFile.h>
#include <ImfMultiPartOutputFile.h>
#include <ImfOutputFile.h>
#include <ImfTiledOutputFile.h>
#include <ImfGenericOutputFile.h>
#include <ImfArray.h>
#include <ImfChannelList.h>
#include <ImfOutputPart.h>
#include <ImfInputPart.h>
#include <ImfTiledOutputPart.h>
#include <ImfTiledInputPart.h>
#include <ImfBoxAttribute.h>
#include <ImfChromaticitiesAttribute.h>
#include <ImfTimeCodeAttribute.h>
#include <ImfIntAttribute.h>
#include <ImfPartType.h>
#include <IexBaseExc.h>
#include <iostream>
#include <string>
#include <vector>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
namespace IMF = OPENEXR_IMF_NAMESPACE;
using namespace IMF;
using namespace std;
using namespace IMATH_NAMESPACE;
#ifndef ILM_IMF_TEST_IMAGEDIR
#define ILM_IMF_TEST_IMAGEDIR
#endif
namespace
{
const int height = 263;
const int width = 197;
void
generateRandomHeaders (int partCount, vector<Header> & headers)
{
headers.clear();
for (int i = 0; i < partCount; i++)
{
Header header(width, height);
int pixelType = rand() % 3;
int partType = rand() % 2;
stringstream ss;
ss << i;
header.setName(ss.str());
switch (pixelType)
{
case 0:
header.channels().insert("UINT", Channel(IMF::UINT));
break;
case 1:
header.channels().insert("FLOAT", Channel(IMF::FLOAT));
break;
case 2:
header.channels().insert("HALF", Channel(IMF::HALF));
break;
}
switch (partType)
{
case 0:
header.setType(IMF::SCANLINEIMAGE);
break;
case 1:
header.setType(IMF::TILEDIMAGE);
break;
}
int tileX;
int tileY;
int levelMode;
if (partType == 1)
{
tileX = rand() % width + 1;
tileY = rand() % height + 1;
levelMode = rand() % 3;
LevelMode lm;
switch (levelMode)
{
case 0:
lm = ONE_LEVEL;
break;
case 1:
lm = MIPMAP_LEVELS;
break;
case 2:
lm = RIPMAP_LEVELS;
break;
}
header.setTileDescription(TileDescription(tileX, tileY, lm));
}
headers.push_back(header);
}
}
void
testMultiPartOutputFileForExpectedFailure (const vector<Header> & headers,
const std::string & fn,
const string & failMessage="")
{
try
{
remove(fn.c_str());
MultiPartOutputFile file(fn.c_str(), &headers[0],headers.size());
cerr << "ERROR -- " << failMessage << endl;
assert (false);
}
catch (const IEX_NAMESPACE::ArgExc & e)
{
// expected behaviour
}
return;
}
void
testDisplayWindow (const vector<Header> & hs, const std::string & fn)
{
vector<Header> headers(hs);
IMATH_NAMESPACE::Box2i newDisplayWindow = headers[0].displayWindow();
Header newHeader (newDisplayWindow.size().x+10, newDisplayWindow.size().y+10);
newHeader.setType (headers[0].type());
newHeader.setName (headers[0].name() + string("_newHeader"));
headers.push_back (newHeader);
testMultiPartOutputFileForExpectedFailure (headers,
fn,
"Shared Attributes : displayWindow : should fail for !=values");
return;
}
void
testPixelAspectRatio (const vector<Header> & hs, const std::string & fn)
{
vector<Header> headers(hs);
IMATH_NAMESPACE::Box2i newDisplayWindow = headers[0].displayWindow();
Header newHeader (headers[0].displayWindow().size().x+1,
headers[0].displayWindow().size().y+1,
headers[0].pixelAspectRatio() + 1.f);
newHeader.setType (headers[0].type());
newHeader.setName (headers[0].name() + string("_newHeader"));
headers.push_back (newHeader);
testMultiPartOutputFileForExpectedFailure (headers,
fn,
"Shared Attributes : pixelAspecRatio : should fail for !=values");
return;
}
void
testTimeCode (const vector<Header> & hs, const std::string & fn)
{
vector<Header> headers(hs);
Header newHeader (headers[0]);
newHeader.setName (headers[0].name() + string("_newHeader"));
//
// Test against a vector of headers that has no attributes of this type
//
TimeCode t(1234567);
TimeCodeAttribute ta(t);
newHeader.insert(TimeCodeAttribute::staticTypeName(), ta);
headers.push_back (newHeader);
testMultiPartOutputFileForExpectedFailure (headers,
fn,
"Shared Attributes : timecode : should fail for !presence");
//
// Test against a vector of headers that has chromaticities attribute
// but of differing value
//
for (int i=0; i<headers.size(); i++)
headers[i].insert (TimeCodeAttribute::staticTypeName(), ta);
t.setTimeAndFlags (t.timeAndFlags()+1);
TimeCodeAttribute tta(t);
newHeader.insert (TimeCodeAttribute::staticTypeName(), tta);
newHeader.setName (newHeader.name() + string("_+1"));
headers.push_back (newHeader);
testMultiPartOutputFileForExpectedFailure (headers,
fn,
"Shared Attributes : timecode : should fail for != values");
return;
}
void
testChromaticities (const vector<Header> & hs, const std::string & fn)
{
vector<Header> headers(hs);
Header newHeader (headers[0]);
newHeader.setName (headers[0].name() + string("_newHeader"));
Chromaticities c;
ChromaticitiesAttribute ca(c);
newHeader.insert (ChromaticitiesAttribute::staticTypeName(), ca);
//
// Test against a vector of headers that has no attributes of this type
//
headers.push_back (newHeader);
testMultiPartOutputFileForExpectedFailure (headers,
fn,
"Shared Attributes : chromaticities : should fail for !present");
//
// Test against a vector of headers that has chromaticities attribute
// but of differing value
//
for (int i=0; i<headers.size(); i++)
headers[i].insert (ChromaticitiesAttribute::staticTypeName(), ca);
c.red += IMATH_NAMESPACE::V2f (1.0f, 1.0f);
ChromaticitiesAttribute cca(c);
newHeader.insert (ChromaticitiesAttribute::staticTypeName(), cca);
headers.push_back (newHeader);
testMultiPartOutputFileForExpectedFailure (headers,
fn,
"Shared Attributes : chromaticities : should fail for != values");
return;
}
void
testSharedAttributes (const std::string & fn)
{
//
// The Shared Attributes are currently:
// Display Window
// Pixel Aspect Ratio
// TimeCode
// Chromaticities
//
int partCount = 3;
vector<Header> headers;
// This will generate headers that are valid for all parts
generateRandomHeaders (partCount, headers);
// expect this to be successful
{
remove(fn.c_str());
MultiPartOutputFile file(fn.c_str(), &headers[0],headers.size());
}
// Adding a header a that has non-complient standard attributes will throw
// an exception.
// Run the tests
testDisplayWindow (headers, fn);
testPixelAspectRatio (headers, fn);
testTimeCode (headers, fn);
testChromaticities (headers, fn);
}
template <class T>
void
testDiskAttrValue (const Header & diskHeader, const T & testAttribute)
{
const string & attrName = testAttribute.typeName();
const T & diskAttr = dynamic_cast <const T &> (diskHeader[attrName]);
if (diskAttr.value() != testAttribute.value())
{
throw IEX_NAMESPACE::InputExc ("incorrect value from disk");
}
return;
}
void
testHeaders (const std::string & fn)
{
//
// In a multipart context the headers must be subject to the following
// constraints
// * type must be set and valid
// * unique names
//
vector<Header> headers;
//
// expect this to fail - empty header list
//
testMultiPartOutputFileForExpectedFailure (headers,
fn,
"Header : empty header list passed");
//
// expect this to fail - header has no image attribute type
//
Header h;
headers.push_back (h);
testMultiPartOutputFileForExpectedFailure (headers,
fn,
"Header : empty image type passed");
//
// expect this to fail - header name duplication
//
headers[0].setType (IMF::SCANLINEIMAGE);
Header hh(headers[0]);
headers.push_back(hh);
testMultiPartOutputFileForExpectedFailure (headers,
fn,
"Header: duplicate header names passed");
//
// expect this to fail - header has incorrect image attribute type
//
try
{
headers[0].setType ("invalid image type");
cerr << "Header : unsupported image type passed" << endl;
assert (false);
}
catch (const IEX_NAMESPACE::ArgExc & e)
{
// expected behaviour
}
//
// Write and Read the data off disk and check values
//
TimeCode t(1234567);
TimeCodeAttribute ta(t);
Chromaticities c;
ChromaticitiesAttribute ca(c);
vector<IntAttribute> ia;
for (int i=0; i<headers.size(); i++)
{
stringstream ss;
ss << i;
headers[i].setName (ss.str());
headers[i].setType (IMF::SCANLINEIMAGE);
headers[i].insert(TimeCodeAttribute::staticTypeName(), ta);
headers[i].insert(ChromaticitiesAttribute::staticTypeName(), ca);
IntAttribute ta(i);
ia.push_back(ta);
headers[i].insert(IntAttribute::staticTypeName(), ta);
}
// write out the file
remove(fn.c_str());
{
MultiPartOutputFile file(fn.c_str(), &headers[0],headers.size());
}
// read in the file and look at the attribute data
MultiPartInputFile file (fn.c_str());
assert (file.parts() == 2);
for (int i=0; i<file.parts(); i++)
{
const Header & diskHeader = file.header(i);
//
// Test Display Window
//
const IMATH_NAMESPACE::Box2i & diskDispWin = diskHeader.displayWindow();
const IMATH_NAMESPACE::Box2i & testDispWin = headers[i].displayWindow();
assert (diskDispWin == testDispWin);
//
// Test Pixel Aspect Ratio
//
float diskPAR = diskHeader.pixelAspectRatio();
float testPAR = headers[i].pixelAspectRatio();
assert (diskPAR == testPAR);
//
// Test TimeCode
//
try
{
testDiskAttrValue<TimeCodeAttribute> (diskHeader, ta);
}
catch (const IEX_NAMESPACE::InputExc &e)
{
cerr << "Shared Attributes : TimeCode : " << e.what() << endl;
assert (false);
}
//
// Test Chromaticities
//
try
{
testDiskAttrValue<ChromaticitiesAttribute> (diskHeader, ca);
}
catch (const IEX_NAMESPACE::InputExc &e)
{
cerr << "Shared Attributes : Chromaticities : " << e.what() << endl;
assert (false);
}
//
// Test for non-shared attribute that can have differing values across
// multiple parts
//
try
{
testDiskAttrValue<IntAttribute> (diskHeader, ia[i]);
}
catch (const IEX_NAMESPACE::InputExc &e)
{
cerr << "Shared Attributes : IntAttribute : " << e.what() << endl;
assert (false);
}
}
//
// Test the code against an incorrectly constructed file
//
try
{
MultiPartInputFile file (ILM_IMF_TEST_IMAGEDIR "invalid_shared_attrs_multipart.exr");
cerr << "Shared Attributes : InputFile : incorrect input file passed\n";
assert (false);
}
catch (const IEX_NAMESPACE::InputExc &e)
{
// expectected behaviour
}
return;
}
} // namespace
void
testMultiPartSharedAttributes (const std::string & tempDir)
{
try
{
cout << "Testing multi part APIs : shared attributes, header... " << endl;
std::string fn = tempDir + "imf_test_multipart_shared_attrs.exr";
testSharedAttributes (fn);
testHeaders (fn);
cout << " ... ok\n" << endl;
}
catch (const IEX_NAMESPACE::BaseExc & e)
{
cerr << "ERROR -- caught IEX_NAMESPACE::BaseExc exception: " << e.what() << endl;
assert (false);
}
catch (const std::exception & e)
{
cerr << "ERROR -- caught std::exception exception: " << e.what() << endl;
assert (false);
}
}

View File

@ -0,0 +1,44 @@
///////////////////////////////////////////////////////////////////////////
//
// 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.
//
///////////////////////////////////////////////////////////////////////////
#ifndef TESTMULTIPARTSHAREDATTRIBUTES_H_
#define TESTMULTIPARTSHAREDATTRIBUTES_H_
#include <string>
void testMultiPartSharedAttributes (const std::string & tempDir);
#endif /* TESTMULTIPARTSHAREDATTRIBUTES_H_ */

View File

@ -0,0 +1,829 @@
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2011, 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 <iostream>
#include <string>
#include <vector>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "tmpDir.h"
#include "testMultiPartThreading.h"
#include <ImfPartType.h>
#include <ImfMultiPartInputFile.h>
#include <ImfMultiPartOutputFile.h>
#include <ImfOutputFile.h>
#include <ImfTiledOutputFile.h>
#include <ImfGenericOutputFile.h>
#include <ImfArray.h>
#include <ImfChannelList.h>
#include <ImfOutputPart.h>
#include <ImfInputPart.h>
#include <ImfTiledOutputPart.h>
#include <ImfTiledInputPart.h>
#include <IlmThreadPool.h>
#include <IlmThreadMutex.h>
#include <ImfTiledMisc.h>
namespace IMF = OPENEXR_IMF_NAMESPACE;
using namespace IMF;
using namespace std;
using namespace IMATH_NAMESPACE;
using namespace ILMTHREAD_NAMESPACE;
namespace
{
const int height = 263;
const int width = 197;
vector<Header> headers;
vector<int> pixelTypes;
vector<int> partTypes;
vector<int> levelModes;
Mutex mutexes[200];
template <class T>
void fillPixels (Array2D<T> &ph, int width, int height)
{
ph.resizeErase(height, width);
for (int y = 0; y < height; ++y)
for (int x = 0; x < width; ++x)
{
//
// We do this because half cannot store number bigger than 2048 exactly.
//
ph[y][x] = (y * width + x) % 2049;
}
}
template <class T>
bool checkPixels (Array2D<T> &ph, int lx, int rx, int ly, int ry, int width)
{
for (int y = ly; y <= ry; ++y)
for (int x = lx; x <= rx; ++x)
if (ph[y][x] != (y * width + x) % 2049)
{
cout << "value at " << x << ", " << y << ": " << ph[y][x]
<< ", should be " << (y * width + x) % 2049 << endl << flush;
return false;
}
return true;
}
template <class T>
bool checkPixels (Array2D<T> &ph, int width, int height)
{
return checkPixels<T> (ph, 0, width - 1, 0, height - 1, width);
}
void setOutputFrameBuffer(FrameBuffer& frameBuffer, int pixelType,
Array2D<unsigned int>& uData, Array2D<float>& fData,
Array2D<half>& hData, int width)
{
switch (pixelType)
{
case 0:
frameBuffer.insert ("UINT",
Slice (IMF::UINT,
(char *) (&uData[0][0]),
sizeof (uData[0][0]) * 1,
sizeof (uData[0][0]) * width));
break;
case 1:
frameBuffer.insert ("FLOAT",
Slice (IMF::FLOAT,
(char *) (&fData[0][0]),
sizeof (fData[0][0]) * 1,
sizeof (fData[0][0]) * width));
break;
case 2:
frameBuffer.insert ("HALF",
Slice (IMF::HALF,
(char *) (&hData[0][0]),
sizeof (hData[0][0]) * 1,
sizeof (hData[0][0]) * width));
break;
}
}
void setInputFrameBuffer(FrameBuffer& frameBuffer, int pixelType,
Array2D<unsigned int>& uData, Array2D<float>& fData,
Array2D<half>& hData, int width, int height)
{
switch (pixelType)
{
case 0:
uData.resizeErase(height, width);
frameBuffer.insert ("UINT",
Slice (IMF::UINT,
(char *) (&uData[0][0]),
sizeof (uData[0][0]) * 1,
sizeof (uData[0][0]) * width,
1, 1,
0));
break;
case 1:
fData.resizeErase(height, width);
frameBuffer.insert ("FLOAT",
Slice (IMF::FLOAT,
(char *) (&fData[0][0]),
sizeof (fData[0][0]) * 1,
sizeof (fData[0][0]) * width,
1, 1,
0));
break;
case 2:
hData.resizeErase(height, width);
frameBuffer.insert ("HALF",
Slice (IMF::HALF,
(char *) (&hData[0][0]),
sizeof (hData[0][0]) * 1,
sizeof (hData[0][0]) * width,
1, 1,
0));
break;
}
}
struct WritingTaskData
{
int partNumber;
int tx, ty, lx, ly;
WritingTaskData(int partNumber):
partNumber(partNumber)
{}
WritingTaskData(int partNumber, int tx, int ty, int lx, int ly):
partNumber(partNumber),
tx(tx),
ty(ty),
lx(lx),
ly(ly)
{}
};
class WritingTask: public Task
{
public:
WritingTask (TaskGroup *group, MultiPartOutputFile* file, vector<WritingTaskData*> data,
Array2D<FrameBuffer>* tiledFrameBuffers):
Task(group),
file(file),
data(data),
tiledFrameBuffers(tiledFrameBuffers)
{}
void execute()
{
for (int i = 0; i < data.size(); i++)
{
int partNumber = data[i]->partNumber;
int partType = partTypes[partNumber];
int pixelType = pixelTypes[partNumber];
int levelMode = levelModes[partNumber];
if (partType == 0)
{
OutputPart part(*file, partNumber);
part.writePixels();
}
else
{
int tx = data[i]->tx;
int ty = data[i]->ty;
int lx = data[i]->lx;
int ly = data[i]->ly;
TiledOutputPart part(*file, partNumber);
//
// We add lock here to assure that two threads that accessing
// the same part won't mess things up.
//
Lock lock(mutexes[partNumber]);
part.setFrameBuffer(tiledFrameBuffers[partNumber][ly][lx]);
part.writeTile(tx, ty, lx, ly);
}
}
}
private:
MultiPartOutputFile* file;
vector<WritingTaskData*> data;
Array2D<FrameBuffer>* tiledFrameBuffers;
};
class RandomReadingTask : public Task
{
public:
RandomReadingTask (TaskGroup *group, MultiPartInputFile* file):
Task(group),
file(file)
{}
void execute()
{
int partNumber = rand() % headers.size();
int partType = partTypes[partNumber];
int pixelType = pixelTypes[partNumber];
int levelMode = levelModes[partNumber];
Array2D<unsigned int> uData;
Array2D<float> fData;
Array2D<half> hData;
if (partType == 0)
{
int l1, l2;
l1 = rand() % height;
l2 = rand() % height;
if (l1 > l2) swap(l1, l2);
InputPart part(*file, partNumber);
//
// We add lock here to assure that two threads that accessing
// the same part won't mess things up.
//
Lock lock(mutexes[partNumber]);
FrameBuffer frameBuffer;
setInputFrameBuffer(frameBuffer, pixelType,
uData, fData, hData, width, height);
part.setFrameBuffer(frameBuffer);
part.readPixels(l1, l2);
switch (pixelType)
{
case 0:
assert(checkPixels<unsigned int>(uData, 0, width - 1, l1, l2, width));
break;
case 1:
assert(checkPixels<float>(fData, 0, width - 1, l1, l2, width));
break;
case 2:
assert(checkPixels<half>(hData, 0, width - 1, l1, l2, width));
break;
}
}
else
{
int tx1, tx2, ty1, ty2;
int lx, ly;
TiledInputPart part(*file, partNumber);
//
// We add lock here to assure that two threads that accessing
// the same part won't mess things up.
//
Lock lock(mutexes[partNumber]);
int numXLevels = part.numXLevels();
int numYLevels = part.numYLevels();
lx = rand() % numXLevels;
ly = rand() % numYLevels;
if (levelMode == 1) ly = lx;
int w = part.levelWidth(lx);
int h = part.levelHeight(ly);
int numXTiles = part.numXTiles(lx);
int numYTiles = part.numYTiles(ly);
tx1 = rand() % numXTiles;
tx2 = rand() % numXTiles;
ty1 = rand() % numYTiles;
ty2 = rand() % numYTiles;
if (tx1 > tx2) swap(tx1, tx2);
if (ty1 > ty2) swap(ty1, ty2);
FrameBuffer frameBuffer;
setInputFrameBuffer(frameBuffer, pixelType,
uData, fData, hData, w, h);
part.setFrameBuffer(frameBuffer);
part.readTiles(tx1, tx2, ty1, ty2, lx, ly);
Box2i b1 = part.dataWindowForTile(tx1, ty1, lx, ly);
Box2i b2 = part.dataWindowForTile(tx2, ty2, lx, ly);
switch (pixelType)
{
case 0:
assert(checkPixels<unsigned int>(uData, b1.min.x, b2.max.x, b1.min.y, b2.max.y,
w));
break;
case 1:
assert(checkPixels<float>(fData, b1.min.x, b2.max.x, b1.min.y, b2.max.y,
w));
break;
case 2:
assert(checkPixels<half>(hData, b1.min.x, b2.max.x, b1.min.y, b2.max.y,
w));
break;
}
}
}
private:
MultiPartInputFile* file;
};
void generateRandomHeaders(int partCount, vector<Header>& headers, vector<WritingTaskData>& taskList)
{
headers.clear();
for (int i = 0; i < partCount; i++)
{
Header header(width, height);
int pixelType = rand() % 3;
int partType = rand() % 2;
pixelTypes[i] = pixelType;
partTypes[i] = partType;
stringstream ss;
ss << i;
header.setName(ss.str());
switch (pixelType)
{
case 0:
header.channels().insert("UINT", Channel(IMF::UINT));
break;
case 1:
header.channels().insert("FLOAT", Channel(IMF::FLOAT));
break;
case 2:
header.channels().insert("HALF", Channel(IMF::HALF));
break;
}
switch (partType)
{
case 0:
header.setType(SCANLINEIMAGE);
break;
case 1:
header.setType(TILEDIMAGE);
break;
}
int tileX;
int tileY;
int levelMode;
if (partType == 1)
{
tileX = rand() % width + 1;
tileY = rand() % height + 1;
levelMode = rand() % 3;
levelModes[i] = levelMode;
LevelMode lm;
switch (levelMode)
{
case 0:
lm = ONE_LEVEL;
break;
case 1:
lm = MIPMAP_LEVELS;
break;
case 2:
lm = RIPMAP_LEVELS;
break;
}
header.setTileDescription(TileDescription(tileX, tileY, lm));
}
//
// Add lines or tiles to task list.
//
if (partType == 0)
{
for (int j = 0; j < height; j++)
taskList.push_back(WritingTaskData(i));
}
else
{
int numXLevel;
int numYLevel;
int* numXTiles;
int* numYTiles;
precalculateTileInfo (header.tileDescription(),
0, width - 1,
0, height - 1,
numXTiles, numYTiles,
numXLevel, numYLevel);
for (int lx = 0; lx < numXLevel; lx++)
for (int ly = 0; ly < numYLevel; ly++)
{
if (levelMode == 1)
if (lx != ly) continue;
// Get all tasks for this level.
for (int tx = 0; tx < numXTiles[lx]; tx++)
for (int ty = 0; ty < numYTiles[ly]; ty++)
taskList.push_back(WritingTaskData(i, tx, ty, lx, ly));
}
delete[] numXTiles;
delete[] numYTiles;
}
// if (partType == 0)
// {
// cout << "pixelType = " << pixelType << " partType = " << partType
// << endl << flush;
// }
// else
// {
// cout << "pixelType = " << pixelType << " partType = " << partType
// << " levelMode = " << levelModes[i] << endl << flush;
// }
headers.push_back(header);
}
}
void
generateRandomFile (int partCount, const std::string & fn)
{
//
// Init data.
//
Array2D<half> halfData;
Array2D<float> floatData;
Array2D<unsigned int> uintData;
fillPixels<unsigned int>(uintData, width, height);
fillPixels<half>(halfData, width, height);
fillPixels<float>(floatData, width, height);
Array2D< Array2D< half > >* tiledHalfData = new Array2D< Array2D< half > >[partCount];
Array2D< Array2D< float > >* tiledFloatData = new Array2D< Array2D< float > >[partCount];
Array2D< Array2D< unsigned int > >* tiledUintData = new Array2D< Array2D< unsigned int > >[partCount];
vector<GenericOutputFile*> outputfiles;
vector<WritingTaskData> taskList;
pixelTypes.resize(partCount);
partTypes.resize(partCount);
levelModes.resize(partCount);
//
// Generate headers and data.
//
cout << "Generating headers and data " << flush;
generateRandomHeaders(partCount, headers, taskList);
//
// Shuffle tasks.
//
cout << "Shuffling " << taskList.size() << " tasks " << flush;
int taskListSize = taskList.size();
for (int i = 0; i < taskListSize; i++)
{
int a, b;
a = rand() % taskListSize;
b = rand() % taskListSize;
swap(taskList[a], taskList[b]);
}
remove(fn.c_str());
MultiPartOutputFile file(fn.c_str(), &headers[0],headers.size());
//
// Writing tasks.
//
cout << "Writing tasks " << flush;
//
// Pre-generating frameBuffers.
//
vector<void *> parts;
vector<FrameBuffer> frameBuffers(partCount);
Array<Array2D<FrameBuffer> >tiledFrameBuffers(partCount);
for (int i = 0; i < partCount; i++)
{
if (partTypes[i] == 0)
{
OutputPart* part = new OutputPart(file, i);
parts.push_back((void*) part);
FrameBuffer& frameBuffer = frameBuffers[i];
setOutputFrameBuffer(frameBuffer, pixelTypes[i], uintData, floatData, halfData, width);
part->setFrameBuffer(frameBuffer);
}
else
{
TiledOutputPart* part = new TiledOutputPart(file, i);
parts.push_back((void*) part);
int numXLevels = part->numXLevels();
int numYLevels = part->numYLevels();
// Allocating space.
switch (pixelTypes[i])
{
case 0:
tiledUintData[i].resizeErase(numYLevels, numXLevels);
break;
case 1:
tiledFloatData[i].resizeErase(numYLevels, numXLevels);
break;
case 2:
tiledHalfData[i].resizeErase(numYLevels, numXLevels);
break;
}
tiledFrameBuffers[i].resizeErase(numYLevels, numXLevels);
for (int xLevel = 0; xLevel < numXLevels; xLevel++)
for (int yLevel = 0; yLevel < numYLevels; yLevel++)
{
if (!part->isValidLevel(xLevel, yLevel))
continue;
int w = part->levelWidth(xLevel);
int h = part->levelHeight(yLevel);
FrameBuffer& frameBuffer = tiledFrameBuffers[i][yLevel][xLevel];
switch (pixelTypes[i])
{
case 0:
fillPixels<unsigned int>(tiledUintData[i][yLevel][xLevel], w, h);
break;
case 1:
fillPixels<float>(tiledFloatData[i][yLevel][xLevel], w, h);
break;
case 2:
fillPixels<half>(tiledHalfData[i][yLevel][xLevel], w, h);
break;
}
setOutputFrameBuffer(frameBuffer, pixelTypes[i],
tiledUintData[i][yLevel][xLevel],
tiledFloatData[i][yLevel][xLevel],
tiledHalfData[i][yLevel][xLevel],
w);
}
}
}
//
// Writing tasks.
//
TaskGroup taskGroup;
ThreadPool* threadPool = new ThreadPool(32);
vector<WritingTaskData*> list;
for (int i = 0; i < taskListSize; i++)
{
list.push_back(&taskList[i]);
if (i % 10 == 0 || i == taskListSize - 1)
{
threadPool->addTask(
(new WritingTask (&taskGroup, &file, list, tiledFrameBuffers)));
list.clear();
}
}
delete threadPool;
delete[] tiledHalfData;
delete[] tiledUintData;
delete[] tiledFloatData;
}
void
readWholeFiles (const std::string & fn)
{
Array2D<unsigned int> uData;
Array2D<float> fData;
Array2D<half> hData;
MultiPartInputFile file(fn.c_str());
for (size_t i = 0; i < file.parts(); i++)
{
const Header& header = file.header(i);
assert (header.displayWindow() == headers[i].displayWindow());
assert (header.dataWindow() == headers[i].dataWindow());
assert (header.pixelAspectRatio() == headers[i].pixelAspectRatio());
assert (header.screenWindowCenter() == headers[i].screenWindowCenter());
assert (header.screenWindowWidth() == headers[i].screenWindowWidth());
assert (header.lineOrder() == headers[i].lineOrder());
assert (header.compression() == headers[i].compression());
//
// It rarely fails here. Added code to see what's wrong when it happens.
//
ChannelList::ConstIterator i1 = header.channels().begin();
ChannelList::ConstIterator i2 = headers[i].channels().begin();
Channel c1 = i1.channel();
Channel c2 = i2.channel();
if (!(c1 == c2))
{
cout << " type " << c1.type << ", " << c2.type
<< " xSampling " << c1.xSampling << ", " << c2.xSampling
<< " ySampling " << c1.ySampling << ", " << c2.ySampling
<< " pLinear " << c1.pLinear << ", " << c2.pLinear << flush;
}
assert (header.channels() == headers[i].channels());
assert (header.name() == headers[i].name());
assert (header.type() == headers[i].type());
}
cout << "Reading whole files " << flush;
//
// Shuffle part numbers.
//
vector<int> shuffledPartNumber;
for (int i = 0; i < headers.size(); i++)
shuffledPartNumber.push_back(i);
for (int i = 0; i < headers.size(); i++)
{
int a = rand() % headers.size();
int b = rand() % headers.size();
swap (shuffledPartNumber[a], shuffledPartNumber[b]);
}
//
// Start reading whole files.
//
int i;
int partNumber;
try
{
for (i = 0; i < headers.size(); i++)
{
partNumber = shuffledPartNumber[i];
if (partTypes[partNumber] == 0)
{
FrameBuffer frameBuffer;
setInputFrameBuffer(frameBuffer, pixelTypes[partNumber],
uData, fData, hData, width, height);
InputPart part(file, partNumber);
part.setFrameBuffer(frameBuffer);
part.readPixels(0, height - 1);
switch (pixelTypes[partNumber])
{
case 0:
assert(checkPixels<unsigned int>(uData, width, height));
break;
case 1:
assert(checkPixels<float>(fData, width, height));
break;
case 2:
assert(checkPixels<half>(hData, width, height));
break;
}
}
else
{
FrameBuffer frameBuffer;
TiledInputPart part(file, partNumber);
int numXLevels = part.numXLevels();
int numYLevels = part.numYLevels();
for (int xLevel = 0; xLevel < numXLevels; xLevel++)
for (int yLevel = 0; yLevel < numYLevels; yLevel++)
{
if (!part.isValidLevel(xLevel, yLevel))
continue;
int w = part.levelWidth(xLevel);
int h = part.levelHeight(yLevel);
setInputFrameBuffer(frameBuffer, pixelTypes[partNumber],
uData, fData, hData, width, height);
part.setFrameBuffer(frameBuffer);
int numXTiles = part.numXTiles(xLevel);
int numYTiles = part.numYTiles(yLevel);
part.readTiles(0, numXTiles - 1, 0, numYTiles - 1, xLevel, yLevel);
switch (pixelTypes[partNumber])
{
case 0:
assert(checkPixels<unsigned int>(uData, w, h));
break;
case 1:
assert(checkPixels<float>(fData, w, h));
break;
case 2:
assert(checkPixels<half>(hData, w, h));
break;
}
}
}
}
}
catch (...)
{
cout << "Error while reading part " << partNumber << endl << flush;
throw;
}
}
void
readPartialFiles (int randomReadCount, const std::string & fn)
{
cout << "Reading partial files " << flush;
MultiPartInputFile file(fn.c_str());
TaskGroup taskGroup;
ThreadPool* threadPool = new ThreadPool(32);
for (int i = 0; i < randomReadCount; i++)
{
threadPool->addTask(
(new RandomReadingTask (&taskGroup, &file)));
}
delete threadPool;
}
void
testWriteRead (int partNumber,
int runCount,
int randomReadCount,
const std::string & tempDir)
{
cout << "Testing file with " << partNumber << " part(s)." << endl << flush;
std::string fn = tempDir + "imf_test_multipart_threading.exr";
for (int i = 0; i < runCount; i++)
{
generateRandomFile (partNumber, fn);
readWholeFiles (fn);
readPartialFiles (randomReadCount, fn);
remove (fn.c_str());
cout << endl << flush;
}
}
} // namespace
void testMultiPartThreading (const std::string & tempDir)
{
try
{
cout << "Testing the multi part APIs for multi-thread use" << endl;
srand(1);
int numThreads = ThreadPool::globalThreadPool().numThreads();
ThreadPool::globalThreadPool().setNumThreads(32);
testWriteRead ( 1, 1, 5, tempDir);
testWriteRead ( 2, 2, 10, tempDir);
testWriteRead ( 5, 5, 25, tempDir);
testWriteRead (50, 2, 250, tempDir);
ThreadPool::globalThreadPool().setNumThreads(numThreads);
cout << "ok\n" << endl;
}
catch (const std::exception &e)
{
cerr << "ERROR -- caught exception: " << e.what() << endl;
assert (false);
}
}

View File

@ -0,0 +1,42 @@
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2011, 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.
//
///////////////////////////////////////////////////////////////////////////
#ifndef TESTMULTIPARTTHREADING_H_
#define TESTMULTIPARTTHREADING_H_
#include <string>
void testMultiPartThreading (const std::string & tempDir);
#endif /* TESTMULTIPARTTHREADING_H_ */

View File

@ -0,0 +1,438 @@
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2011, 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 <iostream>
#include <string>
#include <vector>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "tmpDir.h"
#include "testMultiScanlinePartThreading.h"
#include <ImfPartType.h>
#include <ImfMultiPartInputFile.h>
#include <ImfMultiPartOutputFile.h>
#include <ImfOutputFile.h>
#include <ImfTiledOutputFile.h>
#include <ImfGenericOutputFile.h>
#include <ImfArray.h>
#include <ImfChannelList.h>
#include <ImfOutputPart.h>
#include <ImfInputPart.h>
#include <ImfTiledOutputPart.h>
#include <ImfTiledInputPart.h>
#include <IlmThreadPool.h>
#include <IlmThreadMutex.h>
namespace IMF = OPENEXR_IMF_NAMESPACE;
using namespace IMF;
using namespace std;
using namespace IMATH_NAMESPACE;
using namespace ILMTHREAD_NAMESPACE;
namespace
{
const int height = 263;
const int width = 197;
vector<Header> headers;
template <class T>
void fillPixels (Array2D<T> &ph, int width, int height)
{
ph.resizeErase(height, width);
for (int y = 0; y < height; ++y)
for (int x = 0; x < width; ++x)
{
//
// We do this because half cannot store number bigger than 2048 exactly.
//
ph[y][x] = (y * width + x) % 2049;
}
}
template <class T>
bool checkPixels (Array2D<T> &ph, int lx, int rx, int ly, int ry, int width)
{
for (int y = ly; y <= ry; ++y)
for (int x = lx; x <= rx; ++x)
if (ph[y][x] != (y * width + x) % 2049)
{
cout << "value at " << x << ", " << y << ": " << ph[y][x]
<< ", should be " << (y * width + x) % 2049 << endl << flush;
return false;
}
return true;
}
template <class T>
bool checkPixels (Array2D<T> &ph, int width, int height)
{
return checkPixels<T> (ph, 0, width - 1, 0, height - 1, width);
}
class WritingTask: public Task
{
public:
WritingTask (TaskGroup *group, OutputPart& part, int outputLines):
Task(group),
part(part),
outputLines(outputLines)
{}
void execute()
{
for (int i = 0; i < outputLines; i++)
part.writePixels();
}
private:
OutputPart& part;
int outputLines;
};
class ReadingTask: public Task
{
public:
ReadingTask (TaskGroup *group, InputPart& part, int startPos):
Task(group),
part(part),
startPos(startPos)
{}
void execute()
{
int endPos = startPos + 9;
if (endPos >= height) endPos = height - 1;
part.readPixels(startPos, endPos);
}
private:
InputPart& part;
int startPos;
};
void setOutputFrameBuffer(FrameBuffer& frameBuffer, int pixelType,
Array2D<unsigned int>& uData, Array2D<float>& fData,
Array2D<half>& hData, int width)
{
switch (pixelType)
{
case 0:
frameBuffer.insert ("UINT",
Slice (IMF::UINT,
(char *) (&uData[0][0]),
sizeof (uData[0][0]) * 1,
sizeof (uData[0][0]) * width));
break;
case 1:
frameBuffer.insert ("FLOAT",
Slice (IMF::FLOAT,
(char *) (&fData[0][0]),
sizeof (fData[0][0]) * 1,
sizeof (fData[0][0]) * width));
break;
case 2:
frameBuffer.insert ("HALF",
Slice (IMF::HALF,
(char *) (&hData[0][0]),
sizeof (hData[0][0]) * 1,
sizeof (hData[0][0]) * width));
break;
}
}
void setInputFrameBuffer(FrameBuffer& frameBuffer, int pixelType,
Array2D<unsigned int>& uData, Array2D<float>& fData,
Array2D<half>& hData, int width, int height)
{
switch (pixelType)
{
case 0:
uData.resizeErase(height, width);
frameBuffer.insert ("UINT",
Slice (IMF::UINT,
(char *) (&uData[0][0]),
sizeof (uData[0][0]) * 1,
sizeof (uData[0][0]) * width,
1, 1,
0));
break;
case 1:
fData.resizeErase(height, width);
frameBuffer.insert ("FLOAT",
Slice (IMF::FLOAT,
(char *) (&fData[0][0]),
sizeof (fData[0][0]) * 1,
sizeof (fData[0][0]) * width,
1, 1,
0));
break;
case 2:
hData.resizeErase(height, width);
frameBuffer.insert ("HALF",
Slice (IMF::HALF,
(char *) (&hData[0][0]),
sizeof (hData[0][0]) * 1,
sizeof (hData[0][0]) * width,
1, 1,
0));
break;
}
}
void
generateFiles (int pixelTypes[], const std::string & fn)
{
//
// Generate headers.
//
cout << "Generating headers " << flush;
headers.clear();
for (int i = 0; i < 2; i++)
{
Header header(width, height);
int pixelType = pixelTypes[i];
stringstream ss;
ss << i;
header.setName(ss.str());
switch (pixelType)
{
case 0:
header.channels().insert("UINT", Channel(IMF::UINT));
break;
case 1:
header.channels().insert("FLOAT", Channel(IMF::FLOAT));
break;
case 2:
header.channels().insert("HALF", Channel(IMF::HALF));
break;
}
header.setType(SCANLINEIMAGE);
headers.push_back(header);
}
//
// Preparing.
//
cout << "Writing files " << flush;
Array2D<half> halfData;
Array2D<float> floatData;
Array2D<unsigned int> uintData;
fillPixels<unsigned int>(uintData, width, height);
fillPixels<half>(halfData, width, height);
fillPixels<float>(floatData, width, height);
remove(fn.c_str());
MultiPartOutputFile file(fn.c_str(), &headers[0],headers.size() );
vector<OutputPart> parts;
FrameBuffer frameBuffers[2];
for (int i = 0; i < 2; i++)
{
OutputPart part(file, i);
FrameBuffer& frameBuffer = frameBuffers[i];
setOutputFrameBuffer(frameBuffer, pixelTypes[i], uintData, floatData, halfData, width);
part.setFrameBuffer(frameBuffer);
parts.push_back(part);
}
//
// Writing tasks.
//
TaskGroup taskGroup;
ThreadPool* threadPool = new ThreadPool(2);
for (int i = 0; i < height / 10; i++)
{
threadPool->addTask((new WritingTask (&taskGroup, parts[0], 10)));
threadPool->addTask((new WritingTask (&taskGroup, parts[1], 10)));
}
threadPool->addTask((new WritingTask (&taskGroup, parts[0], height % 10)));
threadPool->addTask((new WritingTask (&taskGroup, parts[1], height % 10)));
delete threadPool;
}
void
readFiles (int pixelTypes[], const std::string & fn)
{
cout << "Checking headers " << flush;
MultiPartInputFile file(fn.c_str());
assert (file.parts() == 2);
for (size_t i = 0; i < 2; i++)
{
const Header& header = file.header(i);
assert (header.displayWindow() == headers[i].displayWindow());
assert (header.dataWindow() == headers[i].dataWindow());
assert (header.pixelAspectRatio() == headers[i].pixelAspectRatio());
assert (header.screenWindowCenter() == headers[i].screenWindowCenter());
assert (header.screenWindowWidth() == headers[i].screenWindowWidth());
assert (header.lineOrder() == headers[i].lineOrder());
assert (header.compression() == headers[i].compression());
assert (header.channels() == headers[i].channels());
assert (header.name() == headers[i].name());
assert (header.type() == headers[i].type());
}
//
// Preparing.
//
Array2D<unsigned int> uData[2];
Array2D<float> fData[2];
Array2D<half> hData[2];
vector<InputPart> parts;
FrameBuffer frameBuffers[2];
for (int i = 0; i < 2; i++)
{
InputPart part(file, i);
FrameBuffer& frameBuffer = frameBuffers[i];
setInputFrameBuffer(frameBuffer, pixelTypes[i], uData[i], fData[i], hData[i], width, height);
part.setFrameBuffer(frameBuffer);
parts.push_back(part);
}
//
// Reading files.
//
cout << "Reading files " << flush;
TaskGroup taskGroup;
ThreadPool* threadPool = new ThreadPool(2);
for (int i = 0; i <= height / 10; i++)
{
threadPool->addTask((new ReadingTask (&taskGroup, parts[0], i * 10)));
threadPool->addTask((new ReadingTask (&taskGroup, parts[1], i * 10)));
}
delete threadPool;
//
// Checking data.
//
cout << "Comparing" << endl << flush;
for (int i = 0; i < 2; i++)
{
switch (pixelTypes[i])
{
case 0:
assert(checkPixels<unsigned int>(uData[i], width, height));
break;
case 1:
assert(checkPixels<float>(fData[i], width, height));
break;
case 2:
assert(checkPixels<half>(hData[i], width, height));
break;
}
}
}
void
testWriteRead (int pixelTypes[], const std::string & tempDir)
{
std::string fn = tempDir + "imf_test_multi_scanline_part_threading.exr";
string typeNames[2];
for (int i = 0; i < 2; i++)
{
switch (pixelTypes[i])
{
case 0:
typeNames[i] = "unsigned int";
break;
case 1:
typeNames[i] = "float";
break;
case 2:
typeNames[i] = "half";
break;
}
}
cout << "part 1: " << typeNames[0] << " scanline part, "
<< "part 2: " << typeNames[1] << " scanline part. " << endl << flush;
generateFiles (pixelTypes, fn);
readFiles (pixelTypes, fn);
remove (fn.c_str());
cout << endl << flush;
}
} // namespace
void testMultiScanlinePartThreading (const std::string & tempDir)
{
try
{
cout << "Testing the two threads reading/writing on two-scanline-part file" << endl;
int numThreads = ThreadPool::globalThreadPool().numThreads();
ThreadPool::globalThreadPool().setNumThreads(2);
int pixelTypes[2];
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
{
pixelTypes[0] = i;
pixelTypes[1] = j;
testWriteRead (pixelTypes, tempDir);
}
ThreadPool::globalThreadPool().setNumThreads(numThreads);
cout << "ok\n" << endl;
}
catch (const std::exception &e)
{
cerr << "ERROR -- caught exception: " << e.what() << endl;
assert (false);
}
}

View File

@ -0,0 +1,42 @@
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2011, 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.
//
///////////////////////////////////////////////////////////////////////////
#ifndef TESTMULTISCANLINEPARTTHREADING_H_
#define TESTMULTISCANLINEPARTTHREADING_H_
#include <string>
void testMultiScanlinePartThreading (const std::string & tempDir);
#endif /* TESTMULTISCANLINEPARTTHREADING_H_ */

View File

@ -0,0 +1,550 @@
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2011, 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 <iostream>
#include <string>
#include <vector>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <algorithm>
#include "tmpDir.h"
#include "testMultiTiledPartThreading.h"
#include <ImfPartType.h>
#include <ImfMultiPartInputFile.h>
#include <ImfMultiPartOutputFile.h>
#include <ImfOutputFile.h>
#include <ImfTiledOutputFile.h>
#include <ImfGenericOutputFile.h>
#include <ImfArray.h>
#include <ImfChannelList.h>
#include <ImfOutputPart.h>
#include <ImfInputPart.h>
#include <ImfTiledOutputPart.h>
#include <ImfTiledInputPart.h>
#include <IlmThreadPool.h>
#include <IlmThreadMutex.h>
namespace
{
namespace IMF = OPENEXR_IMF_NAMESPACE;
using namespace IMF;
using namespace std;
using namespace IMATH_NAMESPACE;
using namespace ILMTHREAD_NAMESPACE;
const int height = 263;
const int width = 197;
vector<Header> headers;
int pixelTypes[2];
int levelMode;
int tileSize;
template <class T>
void fillPixels (Array2D<T> &ph, int width, int height)
{
ph.resizeErase(height, width);
for (int y = 0; y < height; ++y)
for (int x = 0; x < width; ++x)
{
//
// We do this because half cannot store number bigger than 2048 exactly.
//
ph[y][x] = (y * width + x) % 2049;
}
}
template <class T>
bool checkPixels (Array2D<T> &ph, int lx, int rx, int ly, int ry, int width)
{
for (int y = ly; y <= ry; ++y)
for (int x = lx; x <= rx; ++x)
if (ph[y][x] != (y * width + x) % 2049)
{
cout << "value at " << x << ", " << y << ": " << ph[y][x]
<< ", should be " << (y * width + x) % 2049 << endl << flush;
return false;
}
return true;
}
template <class T>
bool checkPixels (Array2D<T> &ph, int width, int height)
{
return checkPixels<T> (ph, 0, width - 1, 0, height - 1, width);
}
void setOutputFrameBuffer(FrameBuffer& frameBuffer, int pixelType,
Array2D<unsigned int>& uData, Array2D<float>& fData,
Array2D<half>& hData, int width)
{
switch (pixelType)
{
case 0:
frameBuffer.insert ("UINT",
Slice (IMF::UINT,
(char *) (&uData[0][0]),
sizeof (uData[0][0]) * 1,
sizeof (uData[0][0]) * width));
break;
case 1:
frameBuffer.insert ("FLOAT",
Slice (IMF::FLOAT,
(char *) (&fData[0][0]),
sizeof (fData[0][0]) * 1,
sizeof (fData[0][0]) * width));
break;
case 2:
frameBuffer.insert ("HALF",
Slice (IMF::HALF,
(char *) (&hData[0][0]),
sizeof (hData[0][0]) * 1,
sizeof (hData[0][0]) * width));
break;
}
}
void setInputFrameBuffer(FrameBuffer& frameBuffer, int pixelType,
Array2D<unsigned int>& uData, Array2D<float>& fData,
Array2D<half>& hData, int width, int height)
{
switch (pixelType)
{
case 0:
uData.resizeErase(height, width);
frameBuffer.insert ("UINT",
Slice (IMF::UINT,
(char *) (&uData[0][0]),
sizeof (uData[0][0]) * 1,
sizeof (uData[0][0]) * width,
1, 1,
0));
break;
case 1:
fData.resizeErase(height, width);
frameBuffer.insert ("FLOAT",
Slice (IMF::FLOAT,
(char *) (&fData[0][0]),
sizeof (fData[0][0]) * 1,
sizeof (fData[0][0]) * width,
1, 1,
0));
break;
case 2:
hData.resizeErase(height, width);
frameBuffer.insert ("HALF",
Slice (IMF::HALF,
(char *) (&hData[0][0]),
sizeof (hData[0][0]) * 1,
sizeof (hData[0][0]) * width,
1, 1,
0));
break;
}
}
class WritingTask: public Task
{
public:
WritingTask (TaskGroup *group, TiledOutputPart& part,
int lx, int ly, int startY, int numXTiles):
Task(group),
part(part),
lx(lx),
ly(ly),
startY(startY),
numXTiles(numXTiles)
{}
void execute()
{
part.writeTiles(0, numXTiles - 1, startY, startY, lx, ly);
}
private:
TiledOutputPart& part;
int lx, ly;
int startY;
int numXTiles;
};
class ReadingTask: public Task
{
public:
ReadingTask (TaskGroup *group, TiledInputPart& part,
int lx, int ly, int startY, int numXTiles):
Task(group),
part(part),
lx(lx),
ly(ly),
startY(startY),
numXTiles(numXTiles)
{}
void execute()
{
part.readTiles(0, numXTiles - 1, startY, startY, lx, ly);
}
private:
TiledInputPart& part;
int lx, ly;
int startY;
int numXTiles;
};
void
generateFiles (const std::string & fn)
{
//
// Generating headers.
//
cout << "Generating headers " << flush;
headers.clear();
for (int i = 0; i < 2; i++)
{
Header header(width, height);
int pixelType = pixelTypes[i];
stringstream ss;
ss << i;
header.setName(ss.str());
switch (pixelType)
{
case 0:
header.channels().insert("UINT", Channel(IMF::UINT));
break;
case 1:
header.channels().insert("FLOAT", Channel(IMF::FLOAT));
break;
case 2:
header.channels().insert("HALF", Channel(IMF::HALF));
break;
}
header.setType(TILEDIMAGE);
int tileX = tileSize;
int tileY = tileSize;
LevelMode lm;
switch (levelMode)
{
case 0:
lm = ONE_LEVEL;
break;
case 1:
lm = MIPMAP_LEVELS;
break;
case 2:
lm = RIPMAP_LEVELS;
break;
}
header.setTileDescription(TileDescription(tileX, tileY, lm));
headers.push_back(header);
}
//
// Preparing.
//
remove (fn.c_str());
MultiPartOutputFile file(fn.c_str(), &headers[0],headers.size());
vector<TiledOutputPart> parts;
Array2D<half> halfData[2];
Array2D<float> floatData[2];
Array2D<unsigned int> uintData[2];
for (int i = 0; i < 2; i++)
{
TiledOutputPart part(file, i);
parts.push_back(part);
}
//
// Writing files.
//
cout << "Writing files " << flush;
//
// Two parts are the same, and we pick parts[0].
//
TiledOutputPart& part = parts[0];
int numXLevels = part.numXLevels();
int numYLevels = part.numYLevels();
for (int xLevel = 0; xLevel < numXLevels; xLevel++)
for (int yLevel = 0; yLevel < numYLevels; yLevel++)
{
if (!part.isValidLevel(xLevel, yLevel))
continue;
int w = part.levelWidth(xLevel);
int h = part.levelHeight(yLevel);
FrameBuffer frameBuffers[2];
for (int i = 0; i < 2; i++)
{
FrameBuffer& frameBuffer = frameBuffers[i];
switch (pixelTypes[i])
{
case 0:
fillPixels<unsigned int>(uintData[i], w, h);
break;
case 1:
fillPixels<float>(floatData[i], w, h);
break;
case 2:
fillPixels<half>(halfData[i], w, h);
break;
}
setOutputFrameBuffer(frameBuffer, pixelTypes[i],
uintData[i],
floatData[i],
halfData[i],
w);
parts[i].setFrameBuffer(frameBuffer);
}
TaskGroup taskGroup;
ThreadPool* threadPool = new ThreadPool(2);
int numXTiles = part.numXTiles(xLevel);
int numYTiles = part.numYTiles(yLevel);
for (int i = 0; i < numYTiles; i++)
{
threadPool->addTask(
(new WritingTask (&taskGroup, parts[0],
xLevel, yLevel, i, numXTiles)));
threadPool->addTask(
(new WritingTask (&taskGroup, parts[1],
xLevel, yLevel, i, numXTiles)));
}
delete threadPool;
}
}
void
readFiles (const std::string & fn)
{
cout << "Checking headers " << flush;
MultiPartInputFile file(fn.c_str());
assert (file.parts() == 2);
for (size_t i = 0; i < 2; i++)
{
const Header& header = file.header(i);
assert (header.displayWindow() == headers[i].displayWindow());
assert (header.dataWindow() == headers[i].dataWindow());
assert (header.pixelAspectRatio() == headers[i].pixelAspectRatio());
assert (header.screenWindowCenter() == headers[i].screenWindowCenter());
assert (header.screenWindowWidth() == headers[i].screenWindowWidth());
assert (header.lineOrder() == headers[i].lineOrder());
assert (header.compression() == headers[i].compression());
assert (header.channels() == headers[i].channels());
assert (header.name() == headers[i].name());
assert (header.type() == headers[i].type());
}
//
// Preparing.
//
Array2D<unsigned int> uData[2];
Array2D<float> fData[2];
Array2D<half> hData[2];
vector<TiledInputPart> parts;
for (int i = 0; i < 2; i++)
{
TiledInputPart part(file, i);
parts.push_back(part);
}
//
// Reading files.
//
cout << "Reading and comparing files " << flush;
TiledInputPart& part = parts[0];
int numXLevels = part.numXLevels();
int numYLevels = part.numYLevels();
for (int xLevel = 0; xLevel < numXLevels; xLevel++)
for (int yLevel = 0; yLevel < numYLevels; yLevel++)
{
if (!part.isValidLevel(xLevel, yLevel))
continue;
int w = part.levelWidth(xLevel);
int h = part.levelHeight(yLevel);
FrameBuffer frameBuffers[2];
for (int i = 0; i < 2; i++)
{
FrameBuffer& frameBuffer = frameBuffers[i];
setInputFrameBuffer(frameBuffer, pixelTypes[i],
uData[i],
fData[i],
hData[i],
w, h);
parts[i].setFrameBuffer(frameBuffer);
}
TaskGroup taskGroup;
ThreadPool* threadPool = new ThreadPool(2);
int numXTiles = part.numXTiles(xLevel);
int numYTiles = part.numYTiles(yLevel);
for (int i = 0; i < numYTiles; i++)
{
threadPool->addTask(
(new ReadingTask (&taskGroup, parts[0],
xLevel, yLevel, i, numXTiles)));
threadPool->addTask(
(new ReadingTask (&taskGroup, parts[1],
xLevel, yLevel, i, numXTiles)));
}
delete threadPool;
for (int i = 0; i < 2; i++)
{
switch (pixelTypes[i])
{
case 0:
assert(checkPixels<unsigned int>(uData[i], w, h));
break;
case 1:
assert(checkPixels<float>(fData[i], w, h));
break;
case 2:
assert(checkPixels<half>(hData[i], w, h));
break;
}
}
}
}
void
testWriteRead (const std::string & tempDir)
{
std::string fn = tempDir + "imf_test_multi_tiled_part_threading.exr";
string typeNames[2];
string levelModeName;
for (int i = 0; i < 2; i++)
{
switch (pixelTypes[i])
{
case 0:
typeNames[i] = "unsigned int";
break;
case 1:
typeNames[i] = "float";
break;
case 2:
typeNames[i] = "half";
break;
}
switch (levelMode)
{
case 0:
levelModeName = "ONE_LEVEL";
break;
case 1:
levelModeName = "MIPMAP";
break;
case 2:
levelModeName = "RIPMAP";
break;
}
}
cout << "part 1: type " << typeNames[0]
<< " tiled part, "
<< "part 2: type " << typeNames[1]
<< " tiled part, "
<< "level mode " << levelModeName
<< " tile size " << tileSize << "x" << tileSize
<< endl << flush;
generateFiles (fn);
readFiles (fn);
remove (fn.c_str());
cout << endl << flush;
}
} // namespace
void testMultiTiledPartThreading (const std::string & tempDir)
{
try
{
cout << "Testing the two threads reading/writing on two-tiled-part file" << endl;
int numThreads = ThreadPool::globalThreadPool().numThreads();
ThreadPool::globalThreadPool().setNumThreads(2);
for (int pt1 = 0; pt1 < 3; pt1++)
for (int pt2 = 0; pt2 < 3; pt2++)
for (int lm = 0; lm < 3; lm++)
for (int size = 1; size < min(width, height); size += 50)
{
pixelTypes[0] = pt1;
pixelTypes[1] = pt2;
levelMode = lm;
tileSize = size;
testWriteRead (tempDir);
}
ThreadPool::globalThreadPool().setNumThreads(numThreads);
cout << "ok\n" << endl;
}
catch (const std::exception &e)
{
cerr << "ERROR -- caught exception: " << e.what() << endl;
assert (false);
}
}

View File

@ -0,0 +1,42 @@
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2011, 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.
//
///////////////////////////////////////////////////////////////////////////
#ifndef TESTMULTITILEDPARTTHREADING_H_
#define TESTMULTITILEDPARTTHREADING_H_
#include <string>
void testMultiTiledPartThreading (const std::string & tempDir);
#endif /* TESTMULTITILEDPARTTHREADING_H_ */

View File

@ -0,0 +1,510 @@
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2007 Weta Digital Ltd
// Copyright (c) 2012 Industrial Light & Magic, a division of Lucasfilm
//
// 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 Weta Digital 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 <ImfMultiView.h>
#include <typeinfo>
#include <sstream>
#include <string.h>
#include <assert.h>
#include <stdarg.h>
using namespace OPENEXR_IMF_NAMESPACE;
using namespace std;
namespace {
ChannelList
buildList (const char *name, ...)
{
//
// nice function to build channel lists
//
ChannelList list;
const char *channelName = name;
va_list ap;
va_start (ap, name);
while (channelName != 0)
{
list.insert (channelName, Channel());
channelName = va_arg (ap, char *);
}
va_end (ap);
return list;
}
void
testMultiViewFunctions ()
{
StringVector multiView;
multiView.push_back ("right");
multiView.push_back ("left");
multiView.push_back ("centre");
//
// Test viewFromChannelName()
//
// default view
assert (viewFromChannelName ("R", multiView) == "right");
// explicitly specified default view
assert (viewFromChannelName ("right.balween", multiView) == "right");
// non-default view: two sections
assert (viewFromChannelName ("left.gritstone", multiView) == "left");
// non-default view: two sections
assert (viewFromChannelName ("centre.ronaldsay", multiView) == "centre");
// non-default view: three sections
assert (viewFromChannelName ("swaledale.left.lonk", multiView) == "left");
// explicitly specified default view: four sections
assert (viewFromChannelName ("manx.loghtan.right.shetland",
multiView) == "right");
// non-default view: five sections
assert (viewFromChannelName ("dorset.down.hebridean.centre.r",
multiView) == "centre");
// shouldn't happen that we have null channel names
assert (viewFromChannelName ("", multiView) == "");
// single section with no view name: default view
assert (viewFromChannelName ("dartmoor", multiView) == "right");
// two sections with no view name: no view
assert (viewFromChannelName ("scottish.blackface", multiView) == "");
// three sections with no view name: no view
assert (viewFromChannelName ("beulah.speckled.face", multiView) == "");
// four sections with no view name: no view
assert (viewFromChannelName ("devon.and.cornwall.longwool",
multiView) == "");
//
// Test areCounterparts()
//
// two non default channel names in list
assert (areCounterparts ("right.R",
"centre.R",
multiView) == true);
// two channel names, both explicit and in list,
// even though one is default channel
assert (areCounterparts ("left.R",
"right.R",
multiView) == true);
// default view with non-default view
assert (areCounterparts ("R",
"left.R",
multiView) == true);
// as above, but other way round
assert (areCounterparts ("left.R",
"R",
multiView) == true);
// same channel name specified in two different ways
assert (areCounterparts ("right.R",
"R",
multiView) == false);
// as above, but other way round
assert (areCounterparts ("R",
"right.R",
multiView) == false);
// none.R is not in a view
assert (areCounterparts ("none.R",
"left.R",
multiView) == false);
// as above, but other way round
assert (areCounterparts ("left.R",
"none.R",
multiView) == false);
// as above, but with default channel
assert (areCounterparts ("X",
"none.X",
multiView) == false);
// as above, but other way round
assert (areCounterparts ("none.B",
"B",
multiView) == false);
// both not in a view
assert (areCounterparts ("southdown.none.G",
"wiltshire.horn.G",
multiView) == false);
// as above, but different lengths of names
assert (areCounterparts ("wiltshire.horn.G",
"cotswold.G",
multiView) == false);
// three section pairs
assert (areCounterparts ("wensleydale.left.baa",
"wensleydale.right.baa",
multiView) == true);
// different in first section
assert (areCounterparts ("wensleydal.left.baa",
"wensleydale.right.baa",
multiView) == false);
// different in last section
assert (areCounterparts ("wensleydale.left.bah",
"wensleydale.right.baa",
multiView) == false);
// same channel
assert (areCounterparts ("wensleydale.left.baa",
"wensleydale.left.baa",
multiView) == false);
// second is in no view
assert (areCounterparts ("wensleydale.right.fell",
"wensleydale.rough.fell",
multiView) == false);
// first is in no view
assert (areCounterparts ("wensleydale.rough.fell",
"wensleydale.left.fell",
multiView) == false);
// four sectons
assert (areCounterparts ("lincoln.longwool.right.A",
"lincoln.longwool.left.A",
multiView) == true);
// different in final section
assert (areCounterparts ("lincoln.longwool.right.B",
"lincoln.longwool.left.A",
multiView) == false);
// different in second section
assert (areCounterparts ("lincoln.shortwool.right.A",
"lincoln.longwool.left.A",
multiView) == false);
// different in first section
assert (areCounterparts ("cumbria.longwool.right.A",
"lincoln.longwool.left.A",
multiView) == false);
// enough said
assert (areCounterparts ("baa.baa.black.sheep",
"lincoln.longwool.left.A",
multiView) == false);
// three sections with default - only last is same
assert (areCounterparts ("portland.left.baa",
"baa",
multiView) == false);
// four sections with default
assert (areCounterparts ("dorset.down.left.baa",
"baa",
multiView) == false);
//
// Channel list tests
//
// list of channels in some multiview image
ChannelList a = buildList
("A",
"B",
"C",
"right.jacob",
"shropshire.right.D",
"castlemilk.moorit.right.A",
"black.welsh.mountain.right.A",
"left.A",
"left.B",
"left.C",
"left.jacob",
"shropshire.left.D",
"castlemilk.moorit.left.A",
"black.welsh.mountain.left.A",
"centre.A",
"centre.B",
"centre.C",
"shropshire.centre.D",
"castlemilk.moorit.centre.A",
"none.A",
"none.B",
"none.C",
"none.D",
"none.jacob",
"shropshire.none.D",
"rough.fell",
(char *) 0);
//
// List of channels in each view
//
// all left channels
ChannelList realLeft = buildList
("left.A",
"left.B",
"left.C",
"left.jacob",
"shropshire.left.D",
"castlemilk.moorit.left.A",
"black.welsh.mountain.left.A",
(char *) 0);
ChannelList realRight = buildList
("A",
"B",
"C",
"right.jacob",
"shropshire.right.D",
"castlemilk.moorit.right.A",
"black.welsh.mountain.right.A",
(char *) 0);
// all the right channels including the default channels
ChannelList realCentre = buildList
("centre.A",
"centre.B",
"centre.C",
"shropshire.centre.D",
"castlemilk.moorit.centre.A",
(char *) 0);
// no jacob channel
// there IS a jacob channel but it has no counterparts because
// this is in "no view"
ChannelList realNone = buildList
("none.A",
"none.B",
"none.D",
"none.C",
"none.jacob",
"shropshire.none.D",
"rough.fell",
(char *) 0);
// have a dummy name just to throw a wolf amongst the sheep
multiView.push_back ("wolf");
// no channels
ChannelList realNull = buildList ((char *) 0);
//
// Test channelsInView()
//
// default view channel extraction
assert (channelsInView ("right", a, multiView) == realRight);
// non-default view channel extraction
assert (channelsInView ("left", a, multiView) == realLeft);
// missing 'centre.jacob'
assert (channelsInView ("centre", a, multiView) == realCentre);
// "none" isn't a view name, no channels returned
assert (channelsInView ("none", a, multiView) == realNull);
// "wolf" has no channels, no channels returned
assert (channelsInView ("wolf", a, multiView) == realNull);
// all no view channels
assert (channelsInNoView (a, multiView) == realNone);
//
// Test channelInAllViews()
//
ChannelList realA = buildList
("left.A",
"A",
"centre.A",
(char *) 0);
ChannelList realB = buildList
("left.B",
"B",
"centre.B",
(char *) 0);
ChannelList realJacob = buildList
("left.jacob",
"right.jacob",
(char *) 0);
ChannelList realCm = buildList
("castlemilk.moorit.left.A",
"castlemillk.moorit.right.A",
"castlemilk.moorit.centre.A",
(char *) 0);
ChannelList realBwm = buildList
("black.welsh.mountain.left.A",
"black.welsh.mountain.right.A",
(char *) 0);
assert (channelInAllViews ("left.A", a, multiView) == realA);
assert (channelInAllViews ("A", a, multiView) == realA);
assert (channelInAllViews ("centre.B", a, multiView) == realB);
assert (channelInAllViews ("right.jacob", a, multiView) == realJacob);
assert (channelInAllViews ("castlemilk.moorit.centre.A",
a, multiView) == realCm);
assert (channelInAllViews ("black.welsh.mountain.right.A",
a, multiView) == realBwm);
//
// Test insertViewName()
//
assert (insertViewName ("A", multiView, 0) ==
"A");
assert (insertViewName ("mountain.A", multiView, 0) ==
"mountain.right.A");
assert (insertViewName ("welsh.mountain.A", multiView, 0) ==
"welsh.mountain.right.A");
assert (insertViewName ("black.welsh.mountain.A", multiView, 0) ==
"black.welsh.mountain.right.A");
assert (insertViewName ("A", multiView, 1) ==
"left.A");
assert (insertViewName ("mountain.A", multiView, 1) ==
"mountain.left.A");
assert (insertViewName ("welsh.mountain.A", multiView, 1) ==
"welsh.mountain.left.A");
assert (insertViewName ("black.welsh.mountain.A", multiView, 1) ==
"black.welsh.mountain.left.A");
}
} // namespace
void
testMultiView (const std::string&)
{
try
{
cout << "Testing multi-view channel list functions" << endl;
testMultiViewFunctions();
cout << "ok\n" << endl;
}
catch (const std::exception &e)
{
cerr << "ERROR -- caught exception: " << e.what() << endl;
assert (false);
}
}

View File

@ -0,0 +1,41 @@
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2007 Weta Digital Ltd
// Copyright (c) 2012 Industrial Light & Magic, a division of Lucasfilm
//
// 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 Weta Digital 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 <string>
void testMultiView (const std::string &tempDir);

View File

@ -0,0 +1,294 @@
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2003-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 <ImfOutputFile.h>
#include <ImfInputFile.h>
#include <ImfChannelList.h>
#include <ImfRgbaFile.h>
#include <ImfArray.h>
#include <stdio.h>
#include <assert.h>
#ifndef ILM_IMF_TEST_IMAGEDIR
#define ILM_IMF_TEST_IMAGEDIR
#endif
using namespace OPENEXR_IMF_NAMESPACE;
using namespace std;
using namespace IMATH_NAMESPACE;
namespace {
void
readImage (const char fileName[],
Array2D<Rgba>& pixels,
int& w,
int& h,
unsigned int correctChecksum)
{
RgbaInputFile in (fileName);
const Box2i &dw = in.dataWindow();
w = dw.max.x - dw.min.x + 1;
h = dw.max.y - dw.min.y + 1;
int dx = dw.min.x;
int dy = dw.min.y;
pixels.resizeErase (h, w);
in.setFrameBuffer (&pixels[0][0] - dx - dy * w, 1, w);
in.readPixels (in.dataWindow().min.y, in.dataWindow().max.y);
unsigned int checksum = 0;
for (int y = 0; y < h; ++y)
for (int x = 0; x < w; ++x)
{
checksum ^= pixels[y][x].r.bits();
checksum ^= pixels[y][x].g.bits();
checksum ^= pixels[y][x].b.bits();
checksum ^= pixels[y][x].a.bits();
}
cout << "checksum = " << checksum << flush;
assert (checksum == correctChecksum);
cout << ", ok" << flush;
}
void
readBackImage (const char fileName[],
Array2D<Rgba>& pixels,
const Array2D<Rgba>& pixels2,
int& w,
int& h,
const int& xs,
const int& ys)
{
InputFile file (fileName);
Box2i dw = file.header().dataWindow();
w = dw.max.x - dw.min.x + 1;
h = dw.max.y - dw.min.y + 1;
pixels.resizeErase (h, w);
FrameBuffer frameBuffer;
Rgba *base = &pixels[0][0] - dw.min.x - dw.min.y * w;
int xStride = sizeof (pixels[0][0]) * xs;
int yStride = sizeof (pixels[0][0]) * w * ys;
frameBuffer.insert ("R", // name
Slice (HALF, // type
(char *) &base[0].r, // base
xStride, // xStride
yStride, // yStride
xs, ys, // x/y sampling
0.0)); // fillValue
frameBuffer.insert ("G", // name
Slice (HALF, // type
(char *) &base[0].g, // base
xStride, // xStride
yStride, // yStride
xs, ys, // x/y sampling
0.0)); // fillValue
frameBuffer.insert ("B", // name
Slice (HALF, // type
(char *) &base[0].b, // base
xStride, // xStride
yStride, // yStride
xs, ys, // x/y sampling
0.0)); // fillValue
frameBuffer.insert ("A", // name
Slice (HALF, // type
(char *) &base[0].a, // base
xStride, // xStride
yStride, // yStride
xs, ys, // x/y sampling
1.0)); // fillValue
file.setFrameBuffer (frameBuffer);
file.readPixels (dw.min.y, dw.max.y);
cout << "comparing, " << flush;
for (int y = 0; y < h; y+=ys)
for (int x = 0; x < w; x+=xs)
{
assert(pixels2[y][x].r.bits() == pixels[y][x].r.bits());
assert(pixels2[y][x].g.bits() == pixels[y][x].g.bits());
assert(pixels2[y][x].b.bits() == pixels[y][x].b.bits());
assert(pixels2[y][x].a.bits() == pixels[y][x].a.bits());
}
cout << "ok" << endl << flush;
}
void
writeImage (const char fileName[],
const Array2D<OPENEXR_IMF_NAMESPACE::Rgba>& pixels,
const int& width,
const int& height,
const int& xs = 1,
const int& ys = 1)
{
//
// Write the image to fileName one scanline at a time
//
Header header (width, height);
header.compression() = PIZ_COMPRESSION;
header.channels().insert ("R", Channel (HALF,xs,ys));
header.channels().insert ("G", Channel (HALF,xs,ys));
header.channels().insert ("B", Channel (HALF,xs,ys));
header.channels().insert ("A", Channel (HALF,xs,ys));
OutputFile file (fileName, header);
FrameBuffer frameBuffer;
const Rgba *base = &pixels[0][0];
int xStride = sizeof (pixels[0][0]) * xs;
int yStride = sizeof (pixels[0][0]) * 0;
frameBuffer.insert ("R", // name
Slice (HALF, // type
(char *) &base[0].r, // base
xStride, // xStride
yStride, // yStride
xs, ys)); // x/y sampling
frameBuffer.insert ("G", // name
Slice (HALF, // type
(char *) &base[0].g, // base
xStride, // xStride
yStride, // yStride
xs, ys)); // x/y sampling
frameBuffer.insert ("B", // name
Slice (HALF, // type
(char *) &base[0].b, // base
xStride, // xStride
yStride, // yStride
xs, ys)); // x/y sampling
frameBuffer.insert ("A", // name
Slice (HALF, // type
(char *) &base[0].a, // base
xStride, // xStride
yStride, // yStride
xs, ys)); // x/y sampling
// iterate over all scanlines, and write them out
for (int y = 0; y < height; ++y)
{
// set the base address for this scanline
base = &pixels[y][0];
frameBuffer["R"].base = (char *) &base[0].r;
frameBuffer["G"].base = (char *) &base[0].g;
frameBuffer["B"].base = (char *) &base[0].b;
frameBuffer["A"].base = (char *) &base[0].a;
// set the framebuffer and write the pixels
file.setFrameBuffer (frameBuffer);
file.writePixels (1);
}
}
void
readCopyRead (const std::string &tempDir,
const char* infilename,
unsigned int correctChecksum)
{
std::string outfilename = tempDir + "imf_test_native.exr";
int w, h;
Array2D<OPENEXR_IMF_NAMESPACE::Rgba> pixels (1,1);
cout << " reading, " << flush;
readImage(infilename, pixels, w, h, correctChecksum);
cout << endl;
for (int xs = 1; xs <= 2; ++xs)
{
for (int ys = 1; ys <= 2; ++ys)
{
cout << " x sampling " << xs << ", y sampling " << ys <<
": writing image, " << flush;
writeImage(outfilename.c_str(), pixels, w, h, xs, ys);
Array2D<OPENEXR_IMF_NAMESPACE::Rgba> pixels2 (1,1);
cout << "reading back, " << flush;
readBackImage(outfilename.c_str(), pixels2, pixels, w, h, xs, ys);
remove(outfilename.c_str());
}
}
}
} // namespace
void
testNativeFormat (const std::string &tempDir)
{
try
{
cout << "Testing if uncompressible pixel data are written "
"in Xdr, not native format" << endl;
cout << "image 1:" << endl;
readCopyRead(tempDir, ILM_IMF_TEST_IMAGEDIR "test_native1.exr", 54435);
cout << "image 2:" << endl;
readCopyRead(tempDir, ILM_IMF_TEST_IMAGEDIR "test_native2.exr", 37639);
cout << "ok\n" << endl;
}
catch (const std::exception &e)
{
cerr << "ERROR -- caught exception: " << e.what() << endl;
assert (false);
}
}

View File

@ -0,0 +1,39 @@
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2003-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 <string>
void testNativeFormat (const std::string &tempDir);

View File

@ -0,0 +1,626 @@
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2004, 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 <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 <ImfEnvmapAttribute.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>
#include <string.h>
using namespace std;
namespace IMF = OPENEXR_IMF_NAMESPACE;
using namespace IMF;
namespace IMATH = IMATH_NAMESPACE;
using namespace IMATH;
namespace
{
static const int IMAGE_2K_HEIGHT = 1152;
static const int IMAGE_2K_WIDTH = 2048;
static const char* CHANNEL_NAMES[] = {"R", "G", "B", "A"};
static const char* CHANNEL_NAMES_LEFT[] = {"left.R", "left.G", "left.B", "left.A"};
static const half ALPHA_DEFAULT_VALUE(1.0f);
#define RGB_FILENAME "imf_optimized_aces_rgb.exr"
#define RGBA_FILENAME "imf_optimized_aces_rgba.exr"
#define RGB_STEREO_FILENAME "imf_optimized_aces_rgb_stereo.exr"
#define RGBA_STEREO_FILENAME "imf_optimized_aces_rgba_stereo.exr"
typedef enum EImageType
{
IMAGE_TYPE_RGB = 1,
IMAGE_TYPE_RGBA = 2,
IMAGE_TYPE_OTHER =3
} EImageType;
int
getNbChannels(EImageType pImageType)
{
int retVal = 0;
switch(pImageType)
{
case IMAGE_TYPE_RGB:
retVal = 3;
break;
case IMAGE_TYPE_RGBA:
retVal = 4;
break;
case IMAGE_TYPE_OTHER:
retVal = 2;
break;
default:
retVal = 0;
break;
}
return retVal;
}
//
//
//
void
generatePixel (int i, int j, half* rgbaValue, bool pIsLeft)
{
float redValue = 0.0f;
float greenValue = 0.0f;
float blueValue = 0.0f;
float alphaValue = 0.0f;
// These formulas are arbitrary but generate results that vary
// depending on pixel position. They are used to validate that
// pixels are read/written correctly, because if we had only one
// value for the whole image, the tests would still pass if we read
// only one pixel and copied it all across the buffer.
if(pIsLeft)
{
redValue = ((i + j) % 10 + 0.004f * j) / 10.0f;
greenValue = ((j + j) % 10 + 0.006f * i) / 10.0f;
blueValue = ((j * j + i) % 10 + 0.003f * j) / 10.0f;
alphaValue = ALPHA_DEFAULT_VALUE;
}
else
{
redValue = ((i * j) % 10 + 0.005f * j) / 10.0f;
greenValue = ((i + i) % 10 + 0.007f * i) / 10.0f;
blueValue = ((i * i + j) % 10 + 0.006f * j) / 10.0f;
alphaValue = ALPHA_DEFAULT_VALUE;
}
rgbaValue[0] = redValue;
rgbaValue[1] = greenValue;
rgbaValue[2] = blueValue;
rgbaValue[3] = alphaValue;
}
//
// Given a buffer, fill the pixels with arbitrary but deterministic values.
// Used to fill the pixels in a buffer before writing them to a file.
//
void
fillPixels (const int& pImageHeight,
const int& pImageWidth,
Array2D<half>& pPixels,
int pNbChannels,
bool pIsLeft)
{
for(int i = 0; i < pImageHeight; ++i)
{
for(int j = 0; j < pImageWidth; ++j)
{
half rgbaValue[4];
generatePixel(i, j, &rgbaValue[0], pIsLeft);
memcpy( (void*)&pPixels[i][j * pNbChannels],
&rgbaValue[0],
pNbChannels * sizeof(half));
}
}
}
//
// Validate that the pixels value are the same as what we used to fill them.
// Used after reading the pixels from the file to validate that it was read
// properly.
//
void
validatePixels (const int& pImageHeight,
const int& pImageWidth,
Array2D<half>& pPixels,
int pNbChannels,
bool pIsLeft)
{
for(int i = 0; i < pImageHeight; ++i)
{
for(int j = 0; j < pImageWidth; ++j)
{
int retVal = -1;
half rgbaValue[4];
generatePixel(i, j, &rgbaValue[0], pIsLeft);
retVal = memcmp ((void*)&pPixels[i][j * pNbChannels],
(void*)&rgbaValue[0],
pNbChannels * sizeof(half));
if(retVal != 0)
{
cout << "ERROR at pixel [" << i << ";" << j << "]" << endl;
cout << "\tExpected [" << rgbaValue[0] << ", "
<< rgbaValue[1] << ", "
<< rgbaValue[2] << "] " << endl;
cout << "\tReceived [" << pPixels[i][j * pNbChannels] << ", "
<< pPixels[i][j * pNbChannels + 1] << ", "
<< pPixels[i][j * pNbChannels + 2] << "]" << endl;
assert(retVal == 0);
}
}
}
}
//
// Write pixels to a file (mono version)
//
void
writePixels (const char pFilename[],
const int& pImageHeight,
const int& pImageWidth,
Array2D<half>& pPixels,
int pNbChannels,
Compression pCompression)
{
Header header (pImageWidth,
pImageHeight,
1.0f,
V2f(0.0f,0.0f),
1.0f,
INCREASING_Y,
pCompression);
for(int i = 0; i < pNbChannels; ++i)
{
header.channels().insert (CHANNEL_NAMES[i], Channel(HALF));
}
OutputFile lFile(pFilename, header);
FrameBuffer lOutputFrameBuffer;
for(int i = 0; i < pNbChannels; ++i)
{
lOutputFrameBuffer.insert (CHANNEL_NAMES[i],
Slice (HALF,
(char *) &pPixels[0][i],
sizeof (pPixels[0][0]) * pNbChannels,
sizeof (pPixels[0][0]) * pNbChannels * pImageWidth));
}
lFile.setFrameBuffer (lOutputFrameBuffer);
lFile.writePixels (pImageHeight);
}
//
// Write pixels to a file (stereo version)
//
void
writePixels (const char pFilename[],
const int& pImageHeight,
const int& pImageWidth,
Array2D<half>& pPixels,
Array2D<half>& pPixelsLeft,
int pNbChannels,
Compression pCompression)
{
Header header (pImageWidth,
pImageHeight,
1.0f,
V2f(0.0f,0.0f),
1.0f,
INCREASING_Y,
pCompression);
for(int i = 0; i < pNbChannels; ++i)
{
header.channels().insert (CHANNEL_NAMES[i], Channel(HALF));
header.channels().insert (CHANNEL_NAMES_LEFT[i], Channel(HALF));
}
StringVector multiView;
multiView.push_back ("right");
multiView.push_back ("left");
header.insert("multiView", IMF::TypedAttribute<IMF::StringVector>(multiView));
OutputFile lFile(pFilename, header);
FrameBuffer lOutputFrameBuffer;
for(int i = 0; i < pNbChannels; ++i)
{
lOutputFrameBuffer.insert (CHANNEL_NAMES[i],
Slice (HALF,
(char *) &pPixels[0][i],
sizeof (pPixels[0][0]) * pNbChannels,
sizeof (pPixels[0][0]) * pNbChannels * pImageWidth));
lOutputFrameBuffer.insert (CHANNEL_NAMES_LEFT[i],
Slice (HALF,
(char *) &pPixelsLeft[0][i],
sizeof (pPixelsLeft[0][0]) * pNbChannels,
sizeof (pPixelsLeft[0][0]) * pNbChannels * pImageWidth));
}
lFile.setFrameBuffer (lOutputFrameBuffer);
lFile.writePixels (pImageHeight);
}
//
// Read pixels from a file (mono version).
//
void
readPixels (const char pFilename[], int pNbChannels, Array2D<half>& pPixels)
{
InputFile lFile(pFilename);
IMATH::Box2i lDataWindow = lFile.header().dataWindow();
int lWidth = lDataWindow.max.x - lDataWindow.min.x + 1;
int lHeight = lDataWindow.max.y - lDataWindow.min.y + 1;
FrameBuffer lInputFrameBuffer;
for(int i = 0; i < pNbChannels; ++i)
{
lInputFrameBuffer.insert (CHANNEL_NAMES[i],
Slice (HALF,
(char *) &pPixels[0][i],
sizeof (pPixels[0][0]) * pNbChannels,
sizeof (pPixels[0][0]) * pNbChannels * lWidth,
1,
1,
ALPHA_DEFAULT_VALUE));
}
lFile.setFrameBuffer (lInputFrameBuffer);
bool is_optimized = lFile.isOptimizationEnabled();
if(is_optimized)
{
cout << " optimization enabled\n";
if(pNbChannels==2)
{
cerr << " error: isOptimizationEnabled returned TRUE, but "
"optimization not known to work for two channel images\n";
assert(pNbChannels!=2);
}
}else{
cout << " optimization disabled\n";
#ifdef IMF_HAVE_SSE2
if(pNbChannels!=2)
{
cerr << " error: isOptimizationEnabled returned FALSE, but "
"should work for " << pNbChannels << "channel images\n";
assert(pNbChannels==2);
}
#endif
}
lFile.readPixels (lDataWindow.min.y, lDataWindow.max.y);
}
//
// Read pixels from a file (stereo version).
//
void
readPixels (const char pFilename[],
int pNbChannels,
Array2D<half>& pPixels,
Array2D<half>& pPixelsLeft)
{
InputFile lFile(pFilename);
IMATH::Box2i lDataWindow = lFile.header().dataWindow();
int lWidth = lDataWindow.max.x - lDataWindow.min.x + 1;
int lHeight = lDataWindow.max.y - lDataWindow.min.y + 1;
FrameBuffer lInputFrameBuffer;
for(int i = 0; i < pNbChannels; ++i)
{
lInputFrameBuffer.insert (CHANNEL_NAMES[i],
Slice (HALF,
(char *) &pPixels[0][i],
sizeof (pPixels[0][0]) * pNbChannels,
sizeof (pPixels[0][0]) * pNbChannels * lWidth,
1,
1,
ALPHA_DEFAULT_VALUE));
lInputFrameBuffer.insert (CHANNEL_NAMES_LEFT[i],
Slice (HALF,
(char *) &pPixelsLeft[0][i],
sizeof (pPixelsLeft[0][0]) * pNbChannels,
sizeof (pPixelsLeft[0][0]) * pNbChannels * lWidth,
1,
1,
ALPHA_DEFAULT_VALUE));
}
lFile.setFrameBuffer (lInputFrameBuffer);
lFile.readPixels (lDataWindow.min.y, lDataWindow.max.y);
}
//
// Allocate an array of pixels, fill them with values and then write
// them to a file.
void
writeFile (const char pFilename[],
int pHeight,
int pWidth,
EImageType pImageType,
bool pIsStereo,
Compression pCompression)
{
const int lNbChannels = getNbChannels (pImageType);
Array2D<half> lPixels;
lPixels.resizeErase (pHeight, pWidth * lNbChannels);
fillPixels (pHeight, pWidth, lPixels, lNbChannels, false);
if(pIsStereo)
{
Array2D<half> lPixelsLeft;
lPixelsLeft.resizeErase (pHeight, pWidth * lNbChannels);
fillPixels (pHeight,
pWidth,
lPixelsLeft,
lNbChannels,
true);
writePixels (pFilename,
pHeight,
pWidth,
lPixels,
lPixelsLeft,
lNbChannels,
pCompression);
}
else
{
writePixels (pFilename,
pHeight,
pWidth,
lPixels,
lNbChannels,
pCompression);
}
}
//
// Read pixels from a file and then validate that the values are the
// same as what was used to fill them before writing.
//
void
readValidateFile (const char pFilename[],
int pHeight,
int pWidth,
EImageType
pImageType,
bool pIsStereo)
{
const int lNbChannels = getNbChannels(pImageType);
Array2D<half> lPixels;
lPixels.resizeErase(pHeight, pWidth * lNbChannels);
//readPixels(pFilename, lNbChannels, lPixels);
//writePixels("pkTest.exr", pHeight, pWidth, lPixels, lNbChannels, NO_COMPRESSION);
if(pIsStereo)
{
Array2D<half> lPixelsLeft;
lPixelsLeft.resizeErase (pHeight, pWidth * lNbChannels);
readPixels (pFilename, lNbChannels, lPixels, lPixelsLeft);
validatePixels (pHeight, pWidth, lPixels, lNbChannels, false);
validatePixels (pHeight, pWidth, lPixelsLeft, lNbChannels, true);
}
else
{
readPixels (pFilename, lNbChannels, lPixels);
validatePixels (pHeight, pWidth, lPixels, lNbChannels, false);
}
}
//
// confirm the optimization flag returns false for non-RGB files
//
void
testNonOptimized (const std::string & tempDir)
{
const int pHeight = IMAGE_2K_HEIGHT - 1;
const int pWidth = IMAGE_2K_WIDTH - 1;
std::string fn = tempDir + RGB_FILENAME;
const char* filename = fn.c_str();
remove(filename);
writeFile (filename, pHeight, pWidth, IMAGE_TYPE_OTHER, false, NO_COMPRESSION);
readValidateFile(filename,pHeight,pWidth,IMAGE_TYPE_OTHER,false);
remove(filename);
}
//
// Test all combinations of file/framebuffer
// RGB file to RGB framebuffer
// RGB file to RGBA framebuffer
// RGBA file to RGB framebuffer
// RGBA file to RGBA framebuffer
// Given a switch that determines whether the pixels will be SSE-aligned,
// whether the file is mono or stereo, and the compression algorithm used
// to write the file.
//
void
testAllCombinations (bool isAligned,
bool isStereo,
Compression pCompression,
const std::string & tempDir)
{
std::string pRgb = isStereo ? RGB_STEREO_FILENAME :
RGB_FILENAME;
pRgb = tempDir + pRgb;
std::string pRgba = isStereo ? RGBA_STEREO_FILENAME :
RGBA_FILENAME;
pRgba = tempDir + pRgba;
const char * pRgbFilename = pRgb.c_str();
const char * pRgbaFilename = pRgba.c_str();
const int pHeight = isAligned ? IMAGE_2K_HEIGHT : IMAGE_2K_HEIGHT - 1;
const int pWidth = isAligned ? IMAGE_2K_WIDTH : IMAGE_2K_WIDTH - 1;
remove(pRgbFilename);
remove(pRgbaFilename);
writeFile (pRgbFilename, pHeight, pWidth, IMAGE_TYPE_RGB, isStereo, pCompression);
writeFile (pRgbaFilename, pHeight, pWidth, IMAGE_TYPE_RGBA, isStereo, pCompression);
cout << "\t\tRGB file to RGB framebuffer" << endl;
readValidateFile (pRgbFilename, pHeight, pWidth, IMAGE_TYPE_RGB, isStereo);
cout << "\t\tRGB file to RGB framebuffer" << endl;
readValidateFile (pRgbFilename, pHeight, pWidth, IMAGE_TYPE_RGB, isStereo);
cout << "\t\tRGB file to RGBA framebuffer" << endl;
readValidateFile (pRgbFilename, pHeight, pWidth, IMAGE_TYPE_RGBA, isStereo);
cout << "\t\tRGBA file to RGB framebuffer" << endl;
readValidateFile (pRgbaFilename, pHeight, pWidth, IMAGE_TYPE_RGB, isStereo);
cout << "\t\tRGBA file to RGBA framebuffer" << endl;
readValidateFile (pRgbaFilename, pHeight, pWidth, IMAGE_TYPE_RGBA, isStereo);
remove(pRgbFilename);
remove(pRgbaFilename);
}
} // anonymous namespace
void
testOptimized (const std::string & tempDir)
{
try
{
// Test all combinations
// Aligned file with no compression
// Unaligned file with no compression
// Aligned file with zip compression
// Unaligned file with zip compression
//
// Other algorithms are not necessary because we are not testing
// compression but whetherthe optimized readPixels() code works
// with a compressed file.
// MONO
cout << "\nTesting optimized code path for rgb(a) images-- "
"2048x1152 (alignment respected) UNCOMPRESSED" << endl;
cout << "\tNON-OPTIMIZABLE file" << endl;
testNonOptimized(tempDir);
cout << "\tALIGNED -- MONO -- NO COMPRESSION" << endl;
testAllCombinations (true, false, NO_COMPRESSION, tempDir);
cout << "\tUNALIGNED -- MONO -- NO COMPRESSION" << endl;
testAllCombinations (false, false, NO_COMPRESSION, tempDir);
cout << "\tALIGNED -- MONO -- ZIP COMPRESSION" << endl;
testAllCombinations (true, false, ZIP_COMPRESSION, tempDir);
cout << "\tUNALIGNED -- MONO -- ZIP COMPRESSION" << endl;
testAllCombinations (false, false, ZIP_COMPRESSION, tempDir);
//// STEREO
cout << "\tALIGNED -- STEREO -- NO COMPRESSION" << endl;
testAllCombinations (true, true, NO_COMPRESSION, tempDir);
cout << "\tUNALIGNED -- STEREO -- NO COMPRESSION" << endl;
testAllCombinations (false, true, NO_COMPRESSION, tempDir);
cout << "\tALIGNED -- STEREO -- ZIP COMPRESSION" << endl;
testAllCombinations (true, true, ZIP_COMPRESSION, tempDir);
cout << "\tUNALIGNED -- STEREO -- ZIP COMPRESSION" << endl;
testAllCombinations (false, true, ZIP_COMPRESSION, tempDir);
cout << "RGB(A) files validation complete \n" << endl;
}
catch (const std::exception &e)
{
cerr << "ERROR -- caught exception: " << e.what() << endl;
assert (false);
}
}

View File

@ -0,0 +1,39 @@
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2004, 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 <string>
void testOptimized (const std::string &tempDir);

View File

@ -0,0 +1,624 @@
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2013, Weta Digital Ltd
//
// 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 "ImfInputFile.h"
#include <stdlib.h>
#include <vector>
#include "ImfChannelList.h"
#include "ImfOutputFile.h"
#include "ImfCompression.h"
#include "ImfStandardAttributes.h"
#include <algorithm>
#include <iostream>
#include <assert.h>
#include <IlmThread.h>
#include <ImathBox.h>
#include "tmpDir.h"
namespace IMF = OPENEXR_IMF_NAMESPACE;
using namespace IMF;
using namespace std;
using namespace IMATH_NAMESPACE;
using namespace ILMTHREAD_NAMESPACE;
namespace
{
using OPENEXR_IMF_NAMESPACE::UINT;
using OPENEXR_IMF_NAMESPACE::FLOAT;
std::string filename;
vector<char> writingBuffer; // buffer as file was written
vector<char> readingBuffer; // buffer containing new image (and filled channels?)
vector<char> preReadBuffer; // buffer as it was before reading - unread, unfilled channels should be unchanged
int gOptimisedReads = 0;
int gSuccesses = 0;
int gFailures = 0;
//
// @todo Needs a description of what this is used for.
//
//
struct Schema
{
const char* _name; // name of this scheme
const char* const* _active; // channels to be read
const char* const * _passive; // channels to be ignored (keep in buffer passed to inputfile, should not be overwritten)
int _banks;
const char* const * _views; // list of views to write, or NULL
const PixelType* _types; // NULL for all HALF, otherwise per-channel type
vector<string> views() const
{
const char * const* v = _views;
vector<string> svec;
while(*v!=NULL)
{
svec.push_back (*v);
v++;
}
return svec;
}
};
const char * rgb[] = {"R","G","B",NULL};
const char * rgba[] = {"R","G","B","A",NULL};
const char * bgr[] = {"B","G","R",NULL};
const char * abgr[] = {"A","B","G","R",NULL};
const char * alpha[] = {"A",NULL};
const char * redalpha[] = {"R","A",NULL};
const char * rgbrightrgb[] = {"R","G","B","right.R","right.G","right.B",NULL};
const char * rgbleftrgb[] = {"R","G","B","left.R","left.G","left.B",NULL};
const char * rgbarightrgba[] = {"R","G","B","A","right.R","right.G","right.B","right.A",NULL};
const char * rgbaleftrgba[] = {"R","G","B","A","left.R","left.G","left.B","left.A",NULL};
const char * rgbrightrgba[] = {"R","G","B","right.R","right.G","right.B","right.A",NULL};
const char * rgbleftrgba[] = {"R","G","B","left.R","left.G","left.B","left.A",NULL};
const char * rgbarightrgb[] = {"R","G","B","A","right.R","right.G","right.B",NULL};
const char * rgbaleftrgb[] = {"R","G","B","A","left.R","left.G","left.B",NULL};
const char * rightrgba[] = {"right.R","right.G","right.B","right.A",NULL};
const char * leftrgba[] = {"left.R","left.G","left.B","left.A",NULL};
const char * rightrgb[] = {"right.R","right.G","right.B",NULL};
const char * leftrgb[] = {"left.R","left.G","left.B",NULL};
const char * threeview[] ={"R","G","B","A","left.R","left.G","left.B","left.A","right.R","right.G","right.B","right.A",NULL};
const char * trees[] = {"rimu","pohutukawa","manuka","kauri",NULL};
const char * treesandbirds[]= {"kiwi","rimu","pohutukawa","kakapu","kauri","manuka","moa","fantail",NULL};
const char * lefthero[] = {"left","right",NULL};
const char * righthero[] = {"right","left",NULL};
const char * centrehero[] = {"centre","left","right",NULL};
const PixelType four_floats[] = {IMF::FLOAT,IMF::FLOAT,IMF::FLOAT,IMF::FLOAT};
const PixelType hhhfff[] = {IMF::HALF,IMF::HALF,IMF::HALF,IMF::FLOAT,IMF::FLOAT,IMF::FLOAT};
const PixelType hhhhffff[] = {IMF::HALF,IMF::HALF,IMF::HALF,IMF::HALF,IMF::FLOAT,IMF::FLOAT,IMF::FLOAT,IMF::FLOAT};
Schema Schemes[] =
{
{"RGBHalf" ,rgb ,NULL ,1 ,NULL ,NULL },
{"RGBAHalf" ,rgba ,NULL ,1 ,NULL ,NULL },
{"ABGRHalf" ,abgr ,NULL ,1 ,NULL ,NULL },
{"RGBFloat" ,rgb ,NULL ,1 ,NULL ,four_floats},
{"BGRHalf" ,bgr ,NULL ,1 ,NULL ,NULL },
{"RGBLeftRGB" ,rgbleftrgb ,NULL ,1 ,righthero ,NULL },
{"RGBRightRGB" ,rgbrightrgb ,NULL ,1 ,lefthero ,NULL },
{"RGBALeftRGBA" ,rgbaleftrgba ,NULL ,1 ,righthero ,NULL },
{"RGBARightRGBA" ,rgbarightrgba ,NULL ,1 ,lefthero ,NULL },
{"LeftRGB" ,leftrgb ,NULL ,1 ,NULL ,NULL },
{"RightRGB" ,rightrgb ,NULL ,1 ,NULL ,NULL },
{"LeftRGBA" ,leftrgba ,NULL ,1 ,NULL ,NULL },
{"RightRGBA" ,rightrgba ,NULL ,1 ,NULL ,NULL },
{"TripleView" ,threeview ,NULL ,1 ,centrehero ,NULL },
{"Trees" ,trees ,NULL ,1 ,NULL ,NULL },
{"TreesAndBirds" ,treesandbirds ,NULL ,1 ,NULL ,NULL },
{"RGBLeftRGBA" ,rgbleftrgba ,NULL ,1 ,righthero ,NULL },
{"RGBRightRGBA" ,rgbrightrgba ,NULL ,1 ,lefthero ,NULL },
{"RGBALeftRGB" ,rgbaleftrgb ,NULL ,1 ,righthero ,NULL },
{"RGBARightRGB" ,rgbarightrgb ,NULL ,1 ,lefthero ,NULL },
{"TwinRGBLeftRGB" ,rgbleftrgb ,NULL ,2 ,righthero ,NULL },
{"TwinRGBRightRGB" ,rgbrightrgb ,NULL ,2 ,lefthero ,NULL },
{"TwinRGBALeftRGBA" ,rgbaleftrgba ,NULL ,2 ,righthero ,NULL },
{"TwinRGBARightRGBA" ,rgbarightrgba ,NULL , 2 ,lefthero ,NULL },
{"TripleTripleView" ,threeview ,NULL ,3 ,centrehero ,NULL },
{"Alpha" ,alpha ,NULL ,1 ,NULL ,NULL },
{"RedAlpha" ,redalpha ,NULL ,1 ,NULL ,NULL },
{"RG+BA" ,rgba ,NULL ,2 ,NULL ,NULL },//interleave only RG, then BA
{"RGBpassiveA" ,rgb ,alpha ,1 ,NULL ,NULL },//interleave only RG, then BA
{"RGBpassiveleftRGB" ,rgb ,leftrgb ,1 ,NULL ,NULL },
{"RGBFloatA" ,rgba ,NULL ,1 ,NULL ,hhhfff },
{"RGBFloatLeftRGB" ,rgbleftrgb ,NULL ,1 ,righthero ,hhhfff },
{"RGBAFloatLeftRGBA" ,rgbaleftrgba ,NULL ,1 ,righthero ,hhhhffff },
{"RGBApassiverightRGBA" ,rgba ,rightrgba ,1 ,NULL ,NULL },
{"BanksOfTreesAndBirds" ,treesandbirds ,NULL ,2 ,NULL ,NULL },
{NULL,NULL,NULL,0,NULL,NULL}
};
bool compare(const FrameBuffer& asRead,
const FrameBuffer& asWritten,
const Box2i& dataWindow,
bool nonfatal
)
{
for (FrameBuffer::ConstIterator i =asRead.begin();i!=asRead.end();i++)
{
FrameBuffer::ConstIterator p = asWritten.find(i.name());
for (int y=dataWindow.min.y; y<= dataWindow.max.y; y++)
{
for (int x = dataWindow.min.x; x <= dataWindow.max.x; x++)
{
char * ptr = (i.slice().base+i.slice().yStride*y +i.slice().xStride*x);
half readHalf;
switch (i.slice().type)
{
case IMF::FLOAT :
readHalf = half(*(float*) ptr);
break;
case IMF::HALF :
readHalf = half(*(half*) ptr);
break;
case IMF::UINT :
continue; // can't very well check this
default :
cout << "don't know about that\n";
exit(1);
}
half writtenHalf;
if (p!=asWritten.end())
{
char * ptr = p.slice().base+p.slice().yStride*y +
p.slice().xStride*x;
switch (p.slice().type)
{
case IMF::FLOAT :
writtenHalf = half(*(float*) ptr);
break;
case IMF::HALF :
writtenHalf = half(*(half*) ptr);
break;
case IMF::UINT :
continue;
default :
cout << "don't know about that\n";
exit(1);
}
}
else
{
writtenHalf=half(i.slice().fillValue);
}
if (writtenHalf.bits()!=readHalf.bits())
{
if (nonfatal)
{
return false;
}
else
{
cout << "\n\nerror reading back channel " << i.name() << " pixel " << x << ',' << y << " got " << readHalf << " expected " << writtenHalf << endl;
assert(writtenHalf.bits()==readHalf.bits());
exit(1);
}
}
}
}
}
return true;
}
//
// allocate readingBuffer or writingBuffer, setting up a framebuffer to point to the right thing
//
ChannelList
setupBuffer (const Header& hdr, // header to grab datawindow from
const char * const *channels, // NULL terminated list of channels to write
const char * const *passivechannels, // NULL terminated list of channels to write
const PixelType* pt, // type of each channel, or NULL for all HALF
FrameBuffer& buf, // buffer to fill with pointers to channel
FrameBuffer& prereadbuf, // channels which aren't being read - indexes into the preread buffer
FrameBuffer& postreadbuf, // channels which aren't being read - indexes into the postread buffer
int banks, // number of banks - channels within each bank are interleaved, banks are scanline interleaved
bool writing // true if should allocate
)
{
Box2i dw = hdr.dataWindow();
//
// how many channels in total
//
int activechans = 0;
int bytes_per_pixel =0;
while (channels[activechans]!=NULL)
{
if (pt==NULL)
{
bytes_per_pixel+=2;
}
else
{
switch (pt[activechans])
{
case IMF::HALF : bytes_per_pixel+=2;break;
case IMF::FLOAT : case IMF::UINT : bytes_per_pixel+=4;break;
default :
cout << "Unexpected PixelType?\n";
exit(1);
}
}
activechans++;
}
int passivechans=0;
while (passivechannels!=NULL && passivechannels[passivechans]!=NULL)
{
if (pt==NULL)
{
bytes_per_pixel+=2;
}
else
{
switch (pt[passivechans+activechans])
{
case IMF::HALF : bytes_per_pixel+=2;break;
case IMF::FLOAT : case IMF::UINT : bytes_per_pixel+=4;break;
default :
cout << "Unexpected PixelType?\n";
exit(1);
}
}
passivechans++;
}
int chans = activechans+passivechans;
int bytes_per_bank = bytes_per_pixel/banks;
int samples = (hdr.dataWindow().max.x+1-hdr.dataWindow().min.x)*
(hdr.dataWindow().max.y+1-hdr.dataWindow().min.y)*chans;
int size = samples*bytes_per_pixel;
if (writing)
{
writingBuffer.resize(size);
}
else
{
readingBuffer.resize(size);
}
const char * write_ptr = writing ? &writingBuffer[0] : &readingBuffer[0];
// fill with random halfs, casting to floats for float channels
int chan=0;
for (int i=0;i<samples;i++)
{
unsigned short int values = (unsigned short int) floor((double(rand())/double(RAND_MAX))*65535.0);
half v;
v.setBits(values);
if (pt==NULL || pt[chan]==IMF::HALF)
{
*(half*)write_ptr = half(v);
write_ptr+=2;
}
else
{
*(float*)write_ptr = float(v);
write_ptr+=4;
}
chan++;
if (chan==chans)
{
chan=0;
}
}
if (!writing)
{
//take a copy of the buffer as it was before being read
preReadBuffer = readingBuffer;
}
char* offset=NULL;
ChannelList chanlist;
int bytes_per_row = bytes_per_pixel*(dw.max.x+1-dw.min.x);
int bytes_per_bank_row = bytes_per_row/banks;
int first_pixel_index = bytes_per_row*dw.min.y+bytes_per_bank*dw.min.x;
for (int i=0;i<chans;i++)
{
PixelType type = pt==NULL ? IMF::HALF : pt[i];
if (i<activechans && writing)
{
chanlist.insert(channels[i],type);
}
if (i % (chans/banks) ==0)
{
//
// set offset pointer to beginning of bank
//
int bank = i / (chans/banks);
offset = (writing ? &writingBuffer[0] :
&readingBuffer[0]) + bank*bytes_per_bank_row - first_pixel_index;
}
if (i<activechans)
{
buf.insert (channels[i],
Slice (type,
offset,
bytes_per_bank,
bytes_per_row,
1,1,100+i));
}
else
{
if (!writing)
{
postreadbuf.insert (passivechannels[i-activechans],
Slice (type,
offset,
bytes_per_bank,
bytes_per_row,
1,1,0.4));
char * pre_offset = offset-&readingBuffer[0]+&preReadBuffer[0];
prereadbuf.insert (passivechannels[i-activechans],
Slice (type,
pre_offset,
bytes_per_bank,
bytes_per_row,
1,1,0.4));
}
}
switch (type)
{
case IMF::HALF :
offset+=2;
break;
case IMF::FLOAT :
offset+=4;
break;
default :
cout << "Unexpected Pixel Type\n";
exit(1);
}
}
return chanlist;
}
Box2i writefile(Schema & scheme,FrameBuffer& buf,bool tiny)
{
const int height = 128;
const int width = 128;
Header hdr(width,height,1);
//min values in range (-100,100)
hdr.dataWindow().min.x = int(200.0*double(rand())/double(RAND_MAX)-100.0);
hdr.dataWindow().min.y = int(200.0*double(rand())/double(RAND_MAX)-100.0);
// in tiny mode, make image up to 14*14 pixels (less than two SSE instructions)
if (tiny)
{
hdr.dataWindow().max.x = hdr.dataWindow().min.x + 1+int(13*double(rand())/double(RAND_MAX));
hdr.dataWindow().max.y = hdr.dataWindow().min.y + 1+int(13*double(rand())/double(RAND_MAX));
}
else
{
// in normal mode, make chunky images
hdr.dataWindow().max.x = hdr.dataWindow().min.x + 64+int(400*double(rand())/double(RAND_MAX));
hdr.dataWindow().max.y = hdr.dataWindow().min.y + 64+int(400*double(rand())/double(RAND_MAX));
}
hdr.compression()=ZIPS_COMPRESSION;
FrameBuffer dummy1,dummy2;
hdr.channels() = setupBuffer (hdr,
scheme._active,
scheme._passive,
scheme._types,
buf,
dummy1,
dummy2,
scheme._banks,
true);
if (scheme._views)
{
addMultiView(hdr,scheme.views());
}
remove (filename.c_str());
OutputFile f(filename.c_str(), hdr);
f.setFrameBuffer(buf);
f.writePixels(hdr.dataWindow().max.y-hdr.dataWindow().min.y+1);
return hdr.dataWindow();
}
bool
readfile (Schema scheme,
FrameBuffer & buf, ///< list of channels to read: index to readingBuffer
FrameBuffer & preread, ///< list of channels to skip: index to preReadBuffer
FrameBuffer & postread) ///< list of channels to skip: index to readingBuffer)
{
InputFile infile (filename.c_str());
setupBuffer(infile.header(),
scheme._active,
scheme._passive,
scheme._types,
buf,
preread,
postread,
scheme._banks,false);
infile.setFrameBuffer(buf);
cout.flush();
infile.readPixels (infile.header().dataWindow().min.y,
infile.header().dataWindow().max.y);
return infile.isOptimizationEnabled();
}
void
test (Schema writeScheme, Schema readScheme, bool nonfatal, bool tiny)
{
ostringstream q;
q << writeScheme._name << " read as " << readScheme._name << "...";
cout << left << setw(53) << q.str();
FrameBuffer writeFrameBuf;
Box2i dw = writefile(writeScheme,writeFrameBuf,tiny);
FrameBuffer readFrameBuf;
FrameBuffer preReadFrameBuf;
FrameBuffer postReadFrameBuf;
cout.flush();
bool opt = readfile (readScheme,
readFrameBuf,
preReadFrameBuf,
postReadFrameBuf);
if (compare(readFrameBuf, writeFrameBuf, dw, nonfatal) &&
compare(preReadFrameBuf, postReadFrameBuf, dw, nonfatal)
)
{
cout << " OK ";
if (opt)
{
cout << "OPTIMISED ";
gOptimisedReads++;
}
cout << "\n";
gSuccesses++;
}
else
{
cout << " FAIL" << endl;
gFailures++;
}
remove (filename.c_str());
}
void runtests(bool nonfatal,bool tiny)
{
srand(1);
int i=0;
int skipped=0;
gFailures=0;
gSuccesses=0;
gOptimisedReads=0;
while(Schemes[i]._name!=NULL)
{
int j=0;
while(Schemes[j]._name!=NULL)
{
cout << right << setw(2) << i << ',' << right << setw(2) << j << ": ";
cout.flush();
if (nonfatal)
{
cout << " skipping " << Schemes[i]._name << ',' << Schemes[j]._name << ": known to crash\n";
skipped++;
}
else
{
test(Schemes[i],Schemes[j],nonfatal,tiny);
}
j++;
}
i++;
}
cout << gFailures << '/' << (gSuccesses+gFailures) << " runs failed\n";
cout << skipped << " tests skipped (assumed to be bad)\n";
cout << gOptimisedReads << '/' << gSuccesses << " optimised\n";
if (gFailures>0 )
{
cout << " TESTS FAILED\n";
assert(false);
}
}
} // namespace anon
void
testOptimizedInterleavePatterns (const std::string & tempDir)
{
filename = tempDir + "imf_test_interleave_patterns.exr";
cout << "Testing SSE optimisation with different interleave patterns (large images) ... " << endl;
runtests (false,false);
cout << "Testing SSE optimisation with different interleave patterns (tiny images) ... " << endl;
runtests (false,true);
cout << "ok\n" << endl;
}

View File

@ -0,0 +1,39 @@
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2013, Weta Digital Ltd
//
// 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.
//
///////////////////////////////////////////////////////////////////////////
#ifndef _TEST_OPTIMIZED_INTERLEAVE_PATTERNS_
#define _TEST_OPTIMIZED_INTERLEAVE_PATTERNS_
void testOptimizedInterleavePatterns (const std::string &tempDir);
#endif

Some files were not shown because too many files have changed in this diff Show More