diff --git a/Makefile b/Makefile index c1a96c9426..26cad018fc 100644 --- a/Makefile +++ b/Makefile @@ -312,6 +312,14 @@ test: build cd ${build_dir} ; \ lcov -b . -d . -c -o cov.info ; \ lcov --remove cov.info "/usr*" -o cov.info ; \ + lcov --remove cov.info "*/usr/incude" -o cov.info ; \ + lcov --remove cov.info "/Library/Developer/*" -o cov.info ; \ + lcov --remove cov.info "*/detail/pugixml/*" -o cov.info ; \ + lcov --remove cov.info "*/detail/fmt/*" -o cov.info ; \ + lcov --remove cov.info "*/v1/*" -o cov.info ; \ + lcov --remove cov.info "*/ext/robin-map/*" -o cov.info ; \ + lcov --remove cov.info "*/kissfft.hh" -o cov.info ; \ + lcov --remove cov.info "*/stb_sprintf.h" -o cov.info ; \ genhtml -o ./cov -t "Test coverage" --num-spaces 4 cov.info ; \ fi ) diff --git a/sonar-project.properties b/sonar-project.properties index 0e74666d1d..5f54b94b42 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -11,13 +11,13 @@ sonar.projectKey=OpenImageIO_oiio # Source properties sonar.sources=src -sonar.exclusions=src/include/OpenImageIO/detail/pugixml/**,src/libutil/stb_sprintf.h,src/libutil/xxhash.cpp,src/include/OpenImageIO/detail/farmhash.h,src/libutil/farmhash.cpp +sonar.exclusions=src/doc/**,src/include/OpenImageIO/detail/pugixml/**,src/libutil/stb_sprintf.h,src/libutil/xxhash.cpp,src/include/OpenImageIO/detail/farmhash.h,src/libutil/farmhash.cpp sonar.sourceEncoding=UTF-8 # C/C++ analyzer properties sonar.cfamily.build-wrapper-output=build/bw_output sonar.cfamily.gcov.reportsPath=_coverage -sonar.coverage.exclusions=src/iv/**,src/include/OpenImageIO/detail/pugixml/** +sonar.coverage.exclusions=src/iv/**,src/include/OpenImageIO/detail/pugixml/**,src/include/OpenImageIO/detail/fmt/**,src/libOpenImageIO/kissfft.hh sonar.cfamily.cache.enabled=true sonar.cfamily.cache.path=/tmp/sonarcache diff --git a/src/build-scripts/ci-coverage.bash b/src/build-scripts/ci-coverage.bash index 361defb870..6fc3728fa2 100755 --- a/src/build-scripts/ci-coverage.bash +++ b/src/build-scripts/ci-coverage.bash @@ -1,7 +1,7 @@ #!/usr/bin/env bash # Run code coverage analysis -# This assumes that the build occurred with CODECOV=1 andtests have already +# This assumes that the build occurred with CODECOV=1 and tests have already # fully run. set -ex diff --git a/src/build-scripts/ci-test.bash b/src/build-scripts/ci-test.bash index 8d0e1325f8..734b837af6 100755 --- a/src/build-scripts/ci-test.bash +++ b/src/build-scripts/ci-test.bash @@ -2,7 +2,10 @@ # Important: set -ex causes this whole script to terminate with error if # any command in it fails. This is crucial for CI tests. -set -ex +# (Though we let it run all the way through for code coverage workflows.) +if [[ "${CODECOV}" == "" ]]; then + set -ex +fi : ${CTEST_EXCLUSIONS:="broken"} : ${CTEST_TEST_TIMEOUT:=180} diff --git a/src/cmake/compiler.cmake b/src/cmake/compiler.cmake index f674e38c08..d84b13501e 100644 --- a/src/cmake/compiler.cmake +++ b/src/cmake/compiler.cmake @@ -406,8 +406,8 @@ option (CODECOV "Build code coverage tests" OFF) if (CODECOV AND (CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_CLANG)) message (STATUS "Compiling for code coverage analysis") add_compile_options (-ftest-coverage -fprofile-arcs) + add_link_options (-ftest-coverage -fprofile-arcs) add_definitions ("-D${PROJ_NAME}_CODE_COVERAGE=1") - link_libraries(gcov) endif () diff --git a/src/include/OpenImageIO/imagebufalgo.h b/src/include/OpenImageIO/imagebufalgo.h index 246de744c8..dbe85cdee7 100644 --- a/src/include/OpenImageIO/imagebufalgo.h +++ b/src/include/OpenImageIO/imagebufalgo.h @@ -167,6 +167,9 @@ class Image_or_Const { Image_or_Const (const float *v, size_t s) : m_type(VAL), m_val(v,s) {} Image_or_Const (const float *v, int s) : m_type(VAL), m_val(v,s) {} + template + Image_or_Const(const float (&array)[N]) : Image_or_Const(cspan(array)) {} + bool is_img () const { return m_type == IMG; } bool is_val () const { return m_type == VAL; } bool is_empty () const { return m_type == NONE; } diff --git a/src/libOpenImageIO/imagebufalgo_test.cpp b/src/libOpenImageIO/imagebufalgo_test.cpp index da030b654b..9c7a713916 100644 --- a/src/libOpenImageIO/imagebufalgo_test.cpp +++ b/src/libOpenImageIO/imagebufalgo_test.cpp @@ -95,6 +95,38 @@ test_type_merge() +// Helper: make an IB filled with a constant value, with a spec that +// describes the image shape. +static ImageBuf +filled_image(cspan value, const ImageSpec& spec) +{ + ImageBuf buf(spec); + ImageBufAlgo::fill(buf, value); + return buf; +} + +// Helper: make an IB filled with a constant value, with given resolution and +// data type (defaulting to 4x4 float), with number of channels determined by +// the size of the value array). +static ImageBuf +filled_image(cspan value, int width = 4, int height = 4, + TypeDesc dtype = TypeDesc::FLOAT) +{ + ImageSpec spec(width, height, std::ssize(value), dtype); + return filled_image(value, spec); +} + +// Helper: make a 4x4 IB filled with a constant value, with given data type +// (defaulting to float), with number of channels determined by the size of +// the value array). +inline ImageBuf +filled_image(cspan value, TypeDesc dtype) +{ + return filled_image(value, 4, 4, dtype); +} + + + // Test ImageBuf::zero and ImageBuf::fill void test_zero_fill() @@ -363,29 +395,22 @@ void test_add() { std::cout << "test add\n"; - const int WIDTH = 4, HEIGHT = 4, CHANNELS = 4; - ImageSpec spec(WIDTH, HEIGHT, CHANNELS, TypeDesc::FLOAT); // Create buffers - ImageBuf A(spec); - const float Aval[CHANNELS] = { 0.1f, 0.2f, 0.3f, 0.4f }; - ImageBufAlgo::fill(A, Aval); - ImageBuf B(spec); - const float Bval[CHANNELS] = { 0.01f, 0.02f, 0.03f, 0.04f }; - ImageBufAlgo::fill(B, Bval); + const float Aval[] = { 0.1f, 0.2f, 0.3f, 0.4f }; + const float Bval[] = { 0.01f, 0.02f, 0.03f, 0.04f }; + ImageBuf A = filled_image(Aval); + ImageBuf B = filled_image(Bval); // Test addition of images - ImageBuf R(spec); - ImageBufAlgo::add(R, A, B); - for (int j = 0; j < spec.height; ++j) - for (int i = 0; i < spec.width; ++i) - for (int c = 0; c < spec.nchannels; ++c) - OIIO_CHECK_EQUAL(R.getchannel(i, j, 0, c), Aval[c] + Bval[c]); + ImageBuf R = ImageBufAlgo::add(A, B); + for (ImageBuf::ConstIterator r(R); !r.done(); ++r) + for (int c = 0, nc = R.nchannels(); c < nc; ++c) + OIIO_CHECK_EQUAL(r[c], Aval[c] + Bval[c]); // Test addition of image and constant color - ImageBuf D(spec); - ImageBufAlgo::add(D, A, Bval); - auto comp = ImageBufAlgo::compare(R, D, 1e-6f, 1e-6f); + ImageBuf D = ImageBufAlgo::add(A, Bval); + auto comp = ImageBufAlgo::compare(R, D, 1e-6f, 1e-6f); OIIO_CHECK_EQUAL(comp.maxerror, 0.0f); } @@ -396,29 +421,22 @@ void test_sub() { std::cout << "test sub\n"; - const int WIDTH = 4, HEIGHT = 4, CHANNELS = 4; - ImageSpec spec(WIDTH, HEIGHT, CHANNELS, TypeDesc::FLOAT); // Create buffers - ImageBuf A(spec); - const float Aval[CHANNELS] = { 0.1f, 0.2f, 0.3f, 0.4f }; - ImageBufAlgo::fill(A, Aval); - ImageBuf B(spec); - const float Bval[CHANNELS] = { 0.01f, 0.02f, 0.03f, 0.04f }; - ImageBufAlgo::fill(B, Bval); + const float Aval[] = { 0.1f, 0.2f, 0.3f, 0.4f }; + const float Bval[] = { 0.01f, 0.02f, 0.03f, 0.04f }; + ImageBuf A = filled_image(Aval); + ImageBuf B = filled_image(Bval); // Test subtraction of images - ImageBuf R(spec); - ImageBufAlgo::sub(R, A, B); - for (int j = 0; j < spec.height; ++j) - for (int i = 0; i < spec.width; ++i) - for (int c = 0; c < spec.nchannels; ++c) - OIIO_CHECK_EQUAL(R.getchannel(i, j, 0, c), Aval[c] - Bval[c]); + ImageBuf R = ImageBufAlgo::sub(A, B); + for (ImageBuf::ConstIterator r(R); !r.done(); ++r) + for (int c = 0, nc = R.nchannels(); c < nc; ++c) + OIIO_CHECK_EQUAL(r[c], Aval[c] - Bval[c]); // Test subtraction of image and constant color - ImageBuf D(spec); - ImageBufAlgo::sub(D, A, Bval); - auto comp = ImageBufAlgo::compare(R, D, 1e-6f, 1e-6f); + ImageBuf D = ImageBufAlgo::sub(A, Bval); + auto comp = ImageBufAlgo::compare(R, D, 1e-6f, 1e-6f); OIIO_CHECK_EQUAL(comp.maxerror, 0.0f); } @@ -429,29 +447,23 @@ void test_mul() { std::cout << "test mul\n"; - const int WIDTH = 4, HEIGHT = 4, CHANNELS = 4; - ImageSpec spec(WIDTH, HEIGHT, CHANNELS, TypeDesc::FLOAT); // Create buffers - ImageBuf A(spec); - const float Aval[CHANNELS] = { 0.1f, 0.2f, 0.3f, 0.4f }; - ImageBufAlgo::fill(A, Aval); - ImageBuf B(spec); - const float Bval[CHANNELS] = { 0.01f, 0.02f, 0.03f, 0.04f }; - ImageBufAlgo::fill(B, Bval); + // Create buffers + const float Aval[] = { 0.1f, 0.2f, 0.3f, 0.4f }; + const float Bval[] = { 0.01f, 0.02f, 0.03f, 0.04f }; + ImageBuf A = filled_image(Aval); + ImageBuf B = filled_image(Bval); // Test multiplication of images - ImageBuf R(spec); - ImageBufAlgo::mul(R, A, B); - for (int j = 0; j < spec.height; ++j) - for (int i = 0; i < spec.width; ++i) - for (int c = 0; c < spec.nchannels; ++c) - OIIO_CHECK_EQUAL(R.getchannel(i, j, 0, c), Aval[c] * Bval[c]); + ImageBuf R = ImageBufAlgo::mul(A, B); + for (ImageBuf::ConstIterator r(R); !r.done(); ++r) + for (int c = 0, nc = R.nchannels(); c < nc; ++c) + OIIO_CHECK_EQUAL(r[c], Aval[c] * Bval[c]); // Test multiplication of image and constant color - ImageBuf D(spec); - ImageBufAlgo::mul(D, A, Bval); - auto comp = ImageBufAlgo::compare(R, D, 1e-6f, 1e-6f); + ImageBuf D = ImageBufAlgo::mul(A, Bval); + auto comp = ImageBufAlgo::compare(R, D, 1e-6f, 1e-6f); OIIO_CHECK_EQUAL(comp.maxerror, 0.0f); } @@ -494,48 +506,94 @@ test_mad() +// Tests ImageBufAlgo::min +void +test_min() +{ + std::cout << "test min\n"; + + // Create buffers + const float Aval[] = { 0.1f, 0.02f, 0.3f, 0.04f }; + const float Bval[] = { 0.01f, 0.2f, 0.03f, 0.4f }; + ImageBuf A = filled_image(Aval); + ImageBuf B = filled_image(Bval); + + // Test min of images + ImageBuf R = ImageBufAlgo::min(A, B); + for (ImageBuf::ConstIterator r(R); !r.done(); ++r) + for (int c = 0, nc = R.nchannels(); c < nc; ++c) + OIIO_CHECK_EQUAL(r[c], std::min(Aval[c], Bval[c])); + + // Test min of image and constant color + ImageBuf D = ImageBufAlgo::min(A, Bval); + auto comp = ImageBufAlgo::compare(R, D, 1e-6f, 1e-6f); + OIIO_CHECK_EQUAL(comp.maxerror, 0.0f); +} + + + +// Tests ImageBufAlgo::max +void +test_max() +{ + std::cout << "test max\n"; + + // Create buffers + const float Aval[] = { 0.1f, 0.02f, 0.3f, 0.04f }; + const float Bval[] = { 0.01f, 0.2f, 0.03f, 0.4f }; + ImageBuf A = filled_image(Aval); + ImageBuf B = filled_image(Bval); + + // Test max of images + ImageBuf R = ImageBufAlgo::max(A, B); + for (ImageBuf::ConstIterator r(R); !r.done(); ++r) + for (int c = 0, nc = R.nchannels(); c < nc; ++c) + OIIO_CHECK_EQUAL(r[c], std::max(Aval[c], Bval[c])); + + // Test max of image and constant color + ImageBuf D = ImageBufAlgo::max(A, Bval); + auto comp = ImageBufAlgo::compare(R, D, 1e-6f, 1e-6f); + OIIO_CHECK_EQUAL(comp.maxerror, 0.0f); +} + + + // Test ImageBuf::over void -test_over() +test_over(TypeDesc dtype = TypeFloat) { - std::cout << "test over\n"; + std::cout << "test over " << dtype << "\n"; - const int WIDTH = 4, HEIGHT = 4, CHANNELS = 4; - ImageSpec spec(WIDTH, HEIGHT, CHANNELS, TypeDesc::FLOAT); ROI roi(2, 4, 1, 3); // region with fg // Create buffers - ImageBuf BG(spec); - const float BGval[CHANNELS] = { 0.5f, 0.0f, 0.0f, 0.5f }; - ImageBufAlgo::fill(BG, BGval); + const float BGval[] = { 0.5f, 0.0f, 0.0f, 0.5f }; + ImageBuf BG = filled_image(BGval, dtype); - ImageBuf FG(spec); - ImageBufAlgo::zero(FG); - const float FGval[CHANNELS] = { 0.0f, 0.5f, 0.0f, 0.5f }; + ImageBuf FG = filled_image({ 0.0f, 0.0f, 0.0f, 0.0f }, dtype); + const float FGval[] = { 0.0f, 0.5f, 0.0f, 0.5f }; ImageBufAlgo::fill(FG, FGval, roi); // value it should be where composited - const float comp_val[CHANNELS] = { 0.25f, 0.5f, 0.0f, 0.75f }; + const float comp_val[] = { 0.25f, 0.5f, 0.0f, 0.75f }; // Test over - ImageBuf R(spec); - ImageBufAlgo::over(R, FG, BG); + ImageBuf R = ImageBufAlgo::over(FG, BG); + int nc = R.nchannels(); for (ImageBuf::ConstIterator r(R); !r.done(); ++r) { if (roi.contains(r.x(), r.y())) - for (int c = 0; c < CHANNELS; ++c) - OIIO_CHECK_EQUAL(r[c], comp_val[c]); + for (int c = 0; c < nc; ++c) + OIIO_CHECK_EQUAL(R.getchannel(r.x(), r.y(), 0, c), comp_val[c]); else - for (int c = 0; c < CHANNELS; ++c) - OIIO_CHECK_EQUAL(r[c], BGval[c]); + for (int c = 0; c < nc; ++c) + OIIO_CHECK_EQUAL(R.getchannel(r.x(), r.y(), 0, c), BGval[c]); } // Timing Benchmarker bench; ImageSpec onekfloat(1000, 1000, 4, TypeFloat); - BG.reset(onekfloat); - ImageBufAlgo::fill(BG, BGval); - FG.reset(onekfloat); - ImageBufAlgo::zero(FG); + BG = filled_image(BGval, 1000, 1000); + FG = filled_image({ 0.0f, 0.0f, 0.0f, 0.0f }, 1000, 1000); ImageBufAlgo::fill(FG, FGval, ROI(250, 750, 100, 900)); R.reset(onekfloat); bench(" IBA::over ", [&]() { ImageBufAlgo::over(R, FG, BG); }); @@ -543,6 +601,41 @@ test_over() +// Test ImageBuf::zover +void +test_zover() +{ + std::cout << "test zover\n"; + + ImageSpec spec(4, 4, 5, TypeFloat); + spec.channelnames.assign({ "R", "G", "B", "A", "Z" }); + spec.z_channel = 4; + + ROI roi(2, 4, 1, 3); // region with fg + + // Create buffers + const float Aval[] = { 0.5f, 0.5, 0.5, 1.0f, 10.0f }; // z == 10 + ImageBuf A = filled_image(Aval, spec); + + ImageBuf B = filled_image({ 0.0f, 0.0f, 0.0f, 1.0f, 15.0f }, spec); + const float Bval[] = { 1.0f, 1.0f, 1.0f, 1.0f, 5.0f }; + ImageBufAlgo::fill(B, Bval, roi); + + // Test zover + ImageBuf R = ImageBufAlgo::zover(A, B, true); + int nc = R.nchannels(); + for (ImageBuf::ConstIterator r(R); !r.done(); ++r) { + if (roi.contains(r.x(), r.y())) + for (int c = 0; c < nc; ++c) + OIIO_CHECK_EQUAL(R.getchannel(r.x(), r.y(), 0, c), Bval[c]); + else + for (int c = 0; c < nc; ++c) + OIIO_CHECK_EQUAL(R.getchannel(r.x(), r.y(), 0, c), Aval[c]); + } +} + + + // Tests ImageBufAlgo::compare void test_compare() @@ -1083,7 +1176,11 @@ main(int argc, char** argv) test_sub(); test_mul(); test_mad(); - test_over(); + test_min(); + test_max(); + test_over(TypeFloat); + test_over(TypeHalf); + test_zover(); test_compare(); test_isConstantColor(); test_isConstantChannel(); diff --git a/src/libutil/filter_test.cpp b/src/libutil/filter_test.cpp index 00c8480708..0cbaad62eb 100644 --- a/src/libutil/filter_test.cpp +++ b/src/libutil/filter_test.cpp @@ -52,18 +52,10 @@ getargs(int argc, char* argv[]) -int -main(int argc, char* argv[]) +void +test_1d() { -#if !defined(NDEBUG) || defined(OIIO_CI) || defined(OIIO_CODE_COVERAGE) - // For the sake of test time, reduce the default iterations for DEBUG, - // CI, and code coverage builds. Explicit use of --iters or --trials - // will override this, since it comes before the getargs() call. - iterations /= 10; - ntrials = 1; -#endif - - getargs(argc, argv); + print("Testing 1D filters\n"); Benchmarker bench; bench.iterations(iterations); @@ -83,11 +75,14 @@ main(int argc, char* argv[]) FilterDesc filtdesc; Filter1D::get_filterdesc(i, &filtdesc); Filter1D* f = Filter1D::create(filtdesc.name, filtdesc.width); - float scale = normalize ? 1.0f / (*f)(0.0f) : 1.0f; // Graph it - float color[3] = { 0.25f * (i & 3), 0.25f * ((i >> 2) & 3), + float scale = normalize ? 1.0f / (*f)(0.0f) : 1.0f; + float color[3] = { 0.25f * (i & 3), 0.25f * ((i >> 2) & 3), 0.25f * ((i >> 4) & 3) }; - ImageBufAlgo::render_text(graph, 10, 20 + i * 20, filtdesc.name, 16, + std::string filtname = filtdesc.name; + if (filtdesc.name != f->name()) + filtname = Strutil::fmt::format("{} ({})", filtname, f->name()); + ImageBufAlgo::render_text(graph, 10, 20 + i * 20, filtname, 16, "" /*font name*/, color); for (int x = 0; x < graphxres; ++x) { float xx = float(x - graphxzero) / graphunit; @@ -100,18 +95,83 @@ main(int argc, char* argv[]) } // Time it - const size_t ncalls = 100000; - bench.work(ncalls); - float ninv = (filtdesc.width / 2.0f) / ncalls; - bench(filtdesc.name, [=]() { - for (size_t i = 0; i < ncalls; ++i) - DoNotOptimize((*f)(i * ninv)); - }); + bench(filtdesc.name, [=]() { DoNotOptimize((*f)(0.25f)); }); Filter1D::destroy(f); } graph.write("filters.tif"); +} + + + +void +test_2d() +{ + print("\nTesting 2D filters\n"); + + Benchmarker bench; + bench.iterations(iterations); + bench.trials(ntrials); + // bench.units (Benchmarker::Unit::ms); + + ImageBuf graph(ImageSpec(graphxres, graphyres, 3, TypeDesc::UINT8)); + float white[3] = { 1, 1, 1 }; + float black[3] = { 0, 0, 0 }; + ImageBufAlgo::fill(graph, white); + ImageBufAlgo::render_line(graph, 0, graphyzero, graphxres - 1, graphyzero, + black); + ImageBufAlgo::render_line(graph, graphxzero, 0, graphxzero, graphyres - 1, + black); + int lastx = 0, lasty = 0; + for (int i = 0, e = Filter2D::num_filters(); i < e; ++i) { + FilterDesc filtdesc; + Filter2D::get_filterdesc(i, &filtdesc); + Filter2D* f = Filter2D::create(filtdesc.name, filtdesc.width, + filtdesc.width); + // Graph it + float scale = normalize ? 1.0f / (*f)(0.0f, 0.0f) : 1.0f; + float color[3] = { 0.25f * (i & 3), 0.25f * ((i >> 2) & 3), + 0.25f * ((i >> 4) & 3) }; + std::string filtname = filtdesc.name; + if (filtdesc.name != f->name()) + filtname = Strutil::fmt::format("{} ({})", filtname, f->name()); + ImageBufAlgo::render_text(graph, 10, 20 + i * 20, filtname, 16, + "" /*font name*/, color); + for (int x = 0; x < graphxres; ++x) { + float xx = float(x - graphxzero) / graphunit; + float yy = (*f)(xx, 0.0f) * scale; + int y = int(graphyzero - yy * graphunit); + if (x > 0) + ImageBufAlgo::render_line(graph, lastx, lasty, x, y, color); + lastx = x; + lasty = y; + } + + // Time it + bench(filtdesc.name, [=]() { DoNotOptimize((*f)(0.25f, 0.25f)); }); + + Filter2D::destroy(f); + } + + graph.write("filters2d.tif"); +} + + + +int +main(int argc, char* argv[]) +{ +#if !defined(NDEBUG) || defined(OIIO_CI) || defined(OIIO_CODE_COVERAGE) + // For the sake of test time, reduce the default iterations for DEBUG, + // CI, and code coverage builds. Explicit use of --iters or --trials + // will override this, since it comes before the getargs() call. + iterations /= 10; + ntrials = 1; +#endif + + getargs(argc, argv); - return unit_test_failures != 0; + test_1d(); + test_2d(); } diff --git a/src/libutil/xxhash.cpp b/src/libutil/xxhash.cpp index 46a8ce11e7..c0afcfefbb 100644 --- a/src/libutil/xxhash.cpp +++ b/src/libutil/xxhash.cpp @@ -91,6 +91,7 @@ typedef struct { long long ll[11]; } XXH64_state_t; +#ifdef OIIO_DOES_NOT_NEED_THESE //#include "xxhash.h" // Modify the local functions below should you wish to use some other memory routines // for malloc(), free() @@ -103,6 +104,7 @@ static void* XXH_memcpy(void* dest, const void* src, size_t size) { return memcpy(dest,src,size); } +#endif /* OIIO_DOES_NOT_NEED_THESE */ //************************************** @@ -514,6 +516,9 @@ unsigned long long XXH64 (const void* input, size_t len, unsigned long long seed #endif } + +#ifdef OIIO_DOES_NOT_NEED_THESE + /**************************************************** * Advanced Hash Functions ****************************************************/ @@ -943,6 +948,8 @@ unsigned long long XXH64_digest (const XXH64_state_t* state_in) return XXH64_digest_endian(state_in, XXH_bigEndian); } +#endif /* OIIO_DOES_NOT_NEED_THESE */ + } // namespace xxhash OIIO_NAMESPACE_END diff --git a/src/python/py_oiio.cpp b/src/python/py_oiio.cpp index 509be57a33..3b7f79e7cd 100644 --- a/src/python/py_oiio.cpp +++ b/src/python/py_oiio.cpp @@ -9,6 +9,7 @@ namespace PyOpenImageIO { +#if 0 /* unused */ const char* python_array_code(TypeDesc format) { @@ -28,7 +29,7 @@ python_array_code(TypeDesc format) return "B"; } } - +#endif TypeDesc @@ -185,40 +186,6 @@ oiio_bufinfo::oiio_bufinfo(const py::buffer_info& pybuf, int nchans, int width, -bool -oiio_attribute_typed(const std::string& name, TypeDesc type, - const py::object& obj) -{ - if (type.basetype == TypeDesc::INT) { - std::vector vals; - py_to_stdvector(vals, obj); - if (vals.size() == type.numelements() * type.aggregate) - return OIIO::attribute(name, type, &vals[0]); - return false; - } - if (type.basetype == TypeDesc::FLOAT) { - std::vector vals; - py_to_stdvector(vals, obj); - if (vals.size() == type.numelements() * type.aggregate) - return OIIO::attribute(name, type, &vals[0]); - return false; - } - if (type.basetype == TypeDesc::STRING) { - std::vector vals; - py_to_stdvector(vals, obj); - if (vals.size() == type.numelements() * type.aggregate) { - std::vector u; - for (auto& val : vals) - u.emplace_back(val); - return OIIO::attribute(name, type, &u[0]); - } - return false; - } - return false; -} - - - py::object make_pyobject(const void* data, TypeDesc type, int nvalues, py::object defaultvalue) @@ -277,6 +244,15 @@ oiio_getattribute_typed(const std::string& name, TypeDesc type = TypeUnknown) } +// Wrapper to let attribute_typed work for global attributes. +struct oiio_global_attrib_wrapper { + bool attribute(string_view name, TypeDesc type, const void* data) + { + return OIIO::attribute(name, type, data); + } +}; + + // This OIIO_DECLARE_PYMODULE mojo is necessary if we want to pass in the // MODULE name as a #define. Google for Argument-Prescan for additional @@ -326,7 +302,8 @@ OIIO_DECLARE_PYMODULE(PYMODULE_NAME) }); m.def("attribute", [](const std::string& name, TypeDesc type, const py::object& obj) { - oiio_attribute_typed(name, type, obj); + oiio_global_attrib_wrapper wrapper; + attribute_typed(wrapper, name, type, obj); }); m.def( diff --git a/src/python/py_oiio.h b/src/python/py_oiio.h index a9d6254ce5..1369cb2b91 100644 --- a/src/python/py_oiio.h +++ b/src/python/py_oiio.h @@ -116,8 +116,8 @@ void declare_texturesystem (py::module& m); // bool PyProgressCallback(void*, float); // object C_array_to_Python_array (const char *data, TypeDesc type, size_t size); -const char * python_array_code (TypeDesc format); TypeDesc typedesc_from_python_array_code (string_view code); +// const char * python_array_code (TypeDesc format); // unused inline std::string diff --git a/testsuite/oiiotool-color/ref/cmap-blue-red.tif b/testsuite/oiiotool-color/ref/cmap-blue-red.tif new file mode 100644 index 0000000000..2ec06e2841 Binary files /dev/null and b/testsuite/oiiotool-color/ref/cmap-blue-red.tif differ diff --git a/testsuite/oiiotool-color/ref/cmap-heat.tif b/testsuite/oiiotool-color/ref/cmap-heat.tif new file mode 100644 index 0000000000..19a05cf21d Binary files /dev/null and b/testsuite/oiiotool-color/ref/cmap-heat.tif differ diff --git a/testsuite/oiiotool-color/ref/cmap-inferno.tif b/testsuite/oiiotool-color/ref/cmap-inferno.tif new file mode 100644 index 0000000000..7e49bf5aff Binary files /dev/null and b/testsuite/oiiotool-color/ref/cmap-inferno.tif differ diff --git a/testsuite/oiiotool-color/ref/cmap-magma.tif b/testsuite/oiiotool-color/ref/cmap-magma.tif new file mode 100644 index 0000000000..a9b8c5abf6 Binary files /dev/null and b/testsuite/oiiotool-color/ref/cmap-magma.tif differ diff --git a/testsuite/oiiotool-color/ref/cmap-plasma.tif b/testsuite/oiiotool-color/ref/cmap-plasma.tif new file mode 100644 index 0000000000..dc0226421b Binary files /dev/null and b/testsuite/oiiotool-color/ref/cmap-plasma.tif differ diff --git a/testsuite/oiiotool-color/ref/cmap-spectrum.tif b/testsuite/oiiotool-color/ref/cmap-spectrum.tif new file mode 100644 index 0000000000..362a8c9b49 Binary files /dev/null and b/testsuite/oiiotool-color/ref/cmap-spectrum.tif differ diff --git a/testsuite/oiiotool-color/ref/cmap-turbo.tif b/testsuite/oiiotool-color/ref/cmap-turbo.tif new file mode 100644 index 0000000000..f04534e5de Binary files /dev/null and b/testsuite/oiiotool-color/ref/cmap-turbo.tif differ diff --git a/testsuite/oiiotool-color/ref/cmap-viridis.tif b/testsuite/oiiotool-color/ref/cmap-viridis.tif new file mode 100644 index 0000000000..e2b049c013 Binary files /dev/null and b/testsuite/oiiotool-color/ref/cmap-viridis.tif differ diff --git a/testsuite/oiiotool-color/ref/out-ocio1.1.0.txt b/testsuite/oiiotool-color/ref/out-ocio1.1.0.txt index e3c88a470f..c1393dc0c2 100644 --- a/testsuite/oiiotool-color/ref/out-ocio1.1.0.txt +++ b/testsuite/oiiotool-color/ref/out-ocio1.1.0.txt @@ -40,6 +40,22 @@ Comparing "tahoe-sat0.tif" and "ref/tahoe-sat0.tif" PASS Comparing "tahoe-sat2.tif" and "ref/tahoe-sat2.tif" PASS +Comparing "cmap-magma.tif" and "ref/cmap-magma.tif" +PASS +Comparing "cmap-inferno.tif" and "ref/cmap-inferno.tif" +PASS +Comparing "cmap-plasma.tif" and "ref/cmap-plasma.tif" +PASS +Comparing "cmap-viridis.tif" and "ref/cmap-viridis.tif" +PASS +Comparing "cmap-turbo.tif" and "ref/cmap-turbo.tif" +PASS +Comparing "cmap-blue-red.tif" and "ref/cmap-blue-red.tif" +PASS +Comparing "cmap-spectrum.tif" and "ref/cmap-spectrum.tif" +PASS +Comparing "cmap-heat.tif" and "ref/cmap-heat.tif" +PASS Comparing "greyalpha_Cineon.tif" and "ref/greyalpha_Cineon.tif" PASS Comparing "greyalpha_Cineon_un.tif" and "ref/greyalpha_Cineon_un.tif" diff --git a/testsuite/oiiotool-color/ref/out-ocio1.1.0b.txt b/testsuite/oiiotool-color/ref/out-ocio1.1.0b.txt index e3b6898c4e..486d41ed56 100644 --- a/testsuite/oiiotool-color/ref/out-ocio1.1.0b.txt +++ b/testsuite/oiiotool-color/ref/out-ocio1.1.0b.txt @@ -40,6 +40,22 @@ Comparing "tahoe-sat0.tif" and "ref/tahoe-sat0.tif" PASS Comparing "tahoe-sat2.tif" and "ref/tahoe-sat2.tif" PASS +Comparing "cmap-magma.tif" and "ref/cmap-magma.tif" +PASS +Comparing "cmap-inferno.tif" and "ref/cmap-inferno.tif" +PASS +Comparing "cmap-plasma.tif" and "ref/cmap-plasma.tif" +PASS +Comparing "cmap-viridis.tif" and "ref/cmap-viridis.tif" +PASS +Comparing "cmap-turbo.tif" and "ref/cmap-turbo.tif" +PASS +Comparing "cmap-blue-red.tif" and "ref/cmap-blue-red.tif" +PASS +Comparing "cmap-spectrum.tif" and "ref/cmap-spectrum.tif" +PASS +Comparing "cmap-heat.tif" and "ref/cmap-heat.tif" +PASS Comparing "greyalpha_Cineon.tif" and "ref/greyalpha_Cineon.tif" PASS Comparing "greyalpha_Cineon_un.tif" and "ref/greyalpha_Cineon_un.tif" diff --git a/testsuite/oiiotool-color/ref/out-ocio22.txt b/testsuite/oiiotool-color/ref/out-ocio22.txt index e25768e4a0..7b22f34d2e 100644 --- a/testsuite/oiiotool-color/ref/out-ocio22.txt +++ b/testsuite/oiiotool-color/ref/out-ocio22.txt @@ -38,5 +38,21 @@ Comparing "tahoe-sat0.tif" and "ref/tahoe-sat0.tif" PASS Comparing "tahoe-sat2.tif" and "ref/tahoe-sat2.tif" PASS +Comparing "cmap-magma.tif" and "ref/cmap-magma.tif" +PASS +Comparing "cmap-inferno.tif" and "ref/cmap-inferno.tif" +PASS +Comparing "cmap-plasma.tif" and "ref/cmap-plasma.tif" +PASS +Comparing "cmap-viridis.tif" and "ref/cmap-viridis.tif" +PASS +Comparing "cmap-turbo.tif" and "ref/cmap-turbo.tif" +PASS +Comparing "cmap-blue-red.tif" and "ref/cmap-blue-red.tif" +PASS +Comparing "cmap-spectrum.tif" and "ref/cmap-spectrum.tif" +PASS +Comparing "cmap-heat.tif" and "ref/cmap-heat.tif" +PASS Comparing "look-default.tif" and "ref/look-default.tif" PASS diff --git a/testsuite/oiiotool-color/ref/out.txt b/testsuite/oiiotool-color/ref/out.txt index f1eb5c2b77..aa94045daf 100644 --- a/testsuite/oiiotool-color/ref/out.txt +++ b/testsuite/oiiotool-color/ref/out.txt @@ -38,6 +38,22 @@ Comparing "tahoe-sat0.tif" and "ref/tahoe-sat0.tif" PASS Comparing "tahoe-sat2.tif" and "ref/tahoe-sat2.tif" PASS +Comparing "cmap-magma.tif" and "ref/cmap-magma.tif" +PASS +Comparing "cmap-inferno.tif" and "ref/cmap-inferno.tif" +PASS +Comparing "cmap-plasma.tif" and "ref/cmap-plasma.tif" +PASS +Comparing "cmap-viridis.tif" and "ref/cmap-viridis.tif" +PASS +Comparing "cmap-turbo.tif" and "ref/cmap-turbo.tif" +PASS +Comparing "cmap-blue-red.tif" and "ref/cmap-blue-red.tif" +PASS +Comparing "cmap-spectrum.tif" and "ref/cmap-spectrum.tif" +PASS +Comparing "cmap-heat.tif" and "ref/cmap-heat.tif" +PASS Comparing "greyalpha_Cineon.tif" and "ref/greyalpha_Cineon.tif" PASS Comparing "greyalpha_Cineon_un.tif" and "ref/greyalpha_Cineon_un.tif" diff --git a/testsuite/oiiotool-color/run.py b/testsuite/oiiotool-color/run.py index 65ae390d3b..98fe36324b 100644 --- a/testsuite/oiiotool-color/run.py +++ b/testsuite/oiiotool-color/run.py @@ -22,6 +22,12 @@ " --colormap .25,.25,.25,0,.5,0,1,0,0 " + "-d uint8 -o colormap-custom.tif") +colormaps = [ "magma", "inferno", "plasma", "viridis", "turbo", "blue-red", "spectrum", "heat" ] +for c in colormaps : + command += oiiotool ("--pattern fill:left=0,0,0:right=1,1,1 64x64 3" + + " --colormap " + c + + " -d uint8 -o cmap-" + c + ".tif") + # test unpremult/premult command += oiiotool ("--pattern constant:color=.1,.1,.1,1 100x100 4 " + " --fill:color=.2,.2,.2,.5 30x30+50+50 " @@ -121,6 +127,8 @@ "tahoe-sat0.tif", "tahoe-sat2.tif" ] +for c in colormaps : + outputs += [ "cmap-" + c + ".tif" ] if float(ociover) >= 2.2 : outputs += [ "look-default.tif" ] else : diff --git a/testsuite/oiiotool-fixnan/ref/out.txt b/testsuite/oiiotool-fixnan/ref/out.txt index c4798d6ea2..d75c493c2c 100644 --- a/testsuite/oiiotool-fixnan/ref/out.txt +++ b/testsuite/oiiotool-fixnan/ref/out.txt @@ -1,3 +1,6 @@ +oiiotool ERROR: --fixnan : Nonfinite pixel values found +Full command line was: +> oiiotool src/bad.exr --fixnan error -o err.exr Reading src/bad.exr src/bad.exr : 64 x 64, 3 channel, half openexr SHA-1: BDEA744AE77E178C4F9C3462110F57923AB496CE @@ -55,6 +58,117 @@ box3.exr : 64 x 64, 3 channel, half openexr Stats FiniteCount: 4096 4096 4096 Constant: No Monochrome: Yes +Bad deep (black): + 64 x 64, 3 channel, deep half openexr + Stats Min: 1.000000 0.000000 0.000000 (float) + Stats Max: 1.000000 1.000000 1.000000 (float) + Stats Avg: 1.000000 0.999512 0.999512 (float) + Stats StdDev: 0.000000 0.022086 0.022086 (float) + Stats NanCount: 1 0 0 + Stats InfCount: 1 0 0 + Stats FiniteCount: 2047 2049 2049 + Min deep samples in any pixel : 0 + Max deep samples in any pixel : 1 + 2049 pixels had the max of 1 samples, including (x=8, y=0) + Average deep samples per pixel: 0.50 + Total deep samples in all pixels: 2049 + Pixels with deep samples : 2049 + Pixels with no deep samples: 2047 + Samples/pixel histogram: + 0 : 2047 (50.0%) + 1 : 2049 (50.0%) + Minimum depth was 0 at (4, 4) + Maximum depth was 1 at (8, 0) + Nonfinite values: 2, including (x=4, y=4, chan=R, samp=0) + 64 x 64, 3 channel, deep half + Stats Min: 0.000000 0.000000 0.000000 (float) + Stats Max: 1.000000 1.000000 1.000000 (float) + Stats Avg: 0.999024 0.999512 0.999512 (float) + Stats StdDev: 0.031227 0.022086 0.022086 (float) + Stats NanCount: 0 0 0 + Stats InfCount: 0 0 0 + Stats FiniteCount: 2049 2049 2049 + Min deep samples in any pixel : 0 + Max deep samples in any pixel : 1 + 2049 pixels had the max of 1 samples, including (x=8, y=0) + Average deep samples per pixel: 0.50 + Total deep samples in all pixels: 2049 + Pixels with deep samples : 2049 + Pixels with no deep samples: 2047 + Samples/pixel histogram: + 0 : 2047 (50.0%) + 1 : 2049 (50.0%) + Minimum depth was 0 at (4, 4) + Maximum depth was 1 at (8, 0) + +Bad deep (box3): + 64 x 64, 3 channel, deep half openexr + Stats Min: 1.000000 0.000000 0.000000 (float) + Stats Max: 1.000000 1.000000 1.000000 (float) + Stats Avg: 1.000000 0.999512 0.999512 (float) + Stats StdDev: 0.000000 0.022086 0.022086 (float) + Stats NanCount: 1 0 0 + Stats InfCount: 1 0 0 + Stats FiniteCount: 2047 2049 2049 + Min deep samples in any pixel : 0 + Max deep samples in any pixel : 1 + 2049 pixels had the max of 1 samples, including (x=8, y=0) + Average deep samples per pixel: 0.50 + Total deep samples in all pixels: 2049 + Pixels with deep samples : 2049 + Pixels with no deep samples: 2047 + Samples/pixel histogram: + 0 : 2047 (50.0%) + 1 : 2049 (50.0%) + Minimum depth was 0 at (4, 4) + Maximum depth was 1 at (8, 0) + Nonfinite values: 2, including (x=4, y=4, chan=R, samp=0) + 64 x 64, 3 channel, deep half + Stats Min: 0.000000 0.000000 0.000000 (float) + Stats Max: 1.000000 1.000000 1.000000 (float) + Stats Avg: 0.999024 0.999512 0.999512 (float) + Stats StdDev: 0.031227 0.022086 0.022086 (float) + Stats NanCount: 0 0 0 + Stats InfCount: 0 0 0 + Stats FiniteCount: 2049 2049 2049 + Min deep samples in any pixel : 0 + Max deep samples in any pixel : 1 + 2049 pixels had the max of 1 samples, including (x=8, y=0) + Average deep samples per pixel: 0.50 + Total deep samples in all pixels: 2049 + Pixels with deep samples : 2049 + Pixels with no deep samples: 2047 + Samples/pixel histogram: + 0 : 2047 (50.0%) + 1 : 2049 (50.0%) + Minimum depth was 0 at (4, 4) + Maximum depth was 1 at (8, 0) + +Bad deep (error): + 64 x 64, 3 channel, deep half openexr + Stats Min: 1.000000 0.000000 0.000000 (float) + Stats Max: 1.000000 1.000000 1.000000 (float) + Stats Avg: 1.000000 0.999512 0.999512 (float) + Stats StdDev: 0.000000 0.022086 0.022086 (float) + Stats NanCount: 1 0 0 + Stats InfCount: 1 0 0 + Stats FiniteCount: 2047 2049 2049 + Min deep samples in any pixel : 0 + Max deep samples in any pixel : 1 + 2049 pixels had the max of 1 samples, including (x=8, y=0) + Average deep samples per pixel: 0.50 + Total deep samples in all pixels: 2049 + Pixels with deep samples : 2049 + Pixels with no deep samples: 2047 + Samples/pixel histogram: + 0 : 2047 (50.0%) + 1 : 2049 (50.0%) + Minimum depth was 0 at (4, 4) + Maximum depth was 1 at (8, 0) + Nonfinite values: 2, including (x=4, y=4, chan=R, samp=0) +oiiotool ERROR: --fixnan : Nonfinite pixel values found +Full command line was: +> oiiotool deep.exr --echo "Bad deep (error):" --printstats --fixnan error --printstats --echo " " Comparing "black.exr" and "ref/black.exr" PASS Comparing "box3.exr" and "ref/box3.exr" diff --git a/testsuite/oiiotool-fixnan/run.py b/testsuite/oiiotool-fixnan/run.py index a30a380a1a..389769ad50 100755 --- a/testsuite/oiiotool-fixnan/run.py +++ b/testsuite/oiiotool-fixnan/run.py @@ -1,10 +1,23 @@ #!/usr/bin/env python +redirect = " >> out.txt 2>&1" +failureok = True + command += oiiotool ("src/bad.exr --fixnan black -o black.exr") command += oiiotool ("src/bad.exr --fixnan box3 -o box3.exr") +command += oiiotool ("src/bad.exr --fixnan error -o err.exr") command += info_command ("src/bad.exr", "--stats", safematch=True) command += info_command ("black.exr", "--stats", safematch=True) command += info_command ("box3.exr", "--stats", safematch=True) +# test deep +command += oiiotool ("src/bad.exr --chnames R,A,Z --deepen -o deep.exr") +command += oiiotool ("deep.exr --echo \"Bad deep (black):\" --printstats" + + " --fixnan black --printstats --echo \" \"") +command += oiiotool ("deep.exr --echo \"Bad deep (box3):\" --printstats" + + " --fixnan box3 --printstats --echo \" \"") +command += oiiotool ("deep.exr --echo \"Bad deep (error):\" --printstats" + + " --fixnan error --printstats --echo \" \"") + # Outputs to check against references outputs = [ "black.exr", "box3.exr", "out.txt" ]