// Assume this file is encoded in UTF-8 #define CATCH_CONFIG_MAIN // This tells Catch to provide a main() - only do // this in one cpp file #include #include #include #include #include #include #include "catch.hpp" #ifdef _WIN32 #ifndef _CRT_SECURE_NO_WARNINGS #define _CRT_SECURE_NO_WARNINGS #endif #include #endif #define TINYEXR_IMPLEMENTATION #include "../../tinyexr.h" // uncomment it to write out memory-saved images to files //#define DUMP_IMAGES // path to https://github.com/openexr/openexr-images // TODO(syoyo): Read openexr-images path from command argument. const char* kOpenEXRImagePath = "../../../openexr-images/"; std::string GetPath(const char* basename) { std::string s; s = std::string(kOpenEXRImagePath) + std::string(basename); return s; } // simply dumping to build folder std::string GetDumpPath(const char* basename) { std::string s = basename; size_t index = s.find_last_of("/\\"); if (index != std::string::npos && index + 1 < s.size()) { s = s.substr(index + 1); } //return "dump/" + s; return s; } // https://stackoverflow.com/questions/148403/utf8-to-from-wide-char-conversion-in-stl/148665#148665 std::wstring UTF8_to_wchar(const char* in) { std::wstring out; unsigned int codepoint; while (*in != 0) { unsigned char ch = static_cast(*in); if (ch <= 0x7f) codepoint = ch; else if (ch <= 0xbf) codepoint = (codepoint << 6) | (ch & 0x3f); else if (ch <= 0xdf) codepoint = ch & 0x1f; else if (ch <= 0xef) codepoint = ch & 0x0f; else codepoint = ch & 0x07; ++in; if (((*in & 0xc0) != 0x80) && (codepoint <= 0x10ffff)) { if (sizeof(wchar_t) > 2) out.append(1, static_cast(codepoint)); else if (codepoint > 0xffff) { out.append(1, static_cast(0xd800 + (codepoint >> 10))); out.append(1, static_cast(0xdc00 + (codepoint & 0x03ff))); } else if (codepoint < 0xd800 || codepoint >= 0xe000) out.append(1, static_cast(codepoint)); } } return out; } #ifdef DUMP_IMAGES // return true if success static bool WriteMemoryToFile(const char *filename, const unsigned char* memory, size_t size) { std::cout << "Saving:" << std::string(filename) << std::endl; FILE *fp = NULL; #ifdef _WIN32 #if defined(_MSC_VER) || defined(__MINGW32__) // MSVC, MinGW gcc or clang errno_t errcode = _wfopen_s(&fp, UTF8_to_wchar(filename).c_str(), L"wb"); if (errcode != 0) return false; #else // Unknown compiler fp = fopen(filename, "wb"); #endif #else fp = fopen(filename, "wb"); #endif if (!fp) return false; size_t written_size = 0; if (size && memory) { written_size = fwrite(memory, 1, size, fp); } fclose(fp); return written_size == size; } #endif // some helper funcs static bool operator == (const EXRBox2i& a, const EXRBox2i& b) { return a.min_x == b.min_x && a.min_y == b.min_y && a.max_x == b.max_x && a.max_y == b.max_y; } static int GetWidth(const EXRBox2i& box) { return box.max_x - box.min_x + 1; } static int GetHeight(const EXRBox2i& box) { return box.max_y - box.min_y + 1; } static void CompareHeaders(const EXRHeader& header1, const EXRHeader& header2) { #if 0 printf("header1.dataWindow = %d, %d, %d, %d\n", header1.data_window.min_x, header1.data_window.min_y, header1.data_window.max_x, header1.data_window.max_y); printf("header2.dataWindow = %d, %d, %d, %d\n", header2.data_window.min_x, header2.data_window.min_y, header2.data_window.max_x, header2.data_window.max_y); #endif REQUIRE(header1.compression_type == header2.compression_type); REQUIRE(header1.num_channels == header2.num_channels); REQUIRE(GetWidth(header1.data_window) == GetWidth(header2.data_window)); REQUIRE(GetHeight(header1.data_window) == GetHeight(header2.data_window)); //REQUIRE(header1.display_window == header2.display_window); //REQUIRE(header1.screen_window_width == header2.screen_window_width); //REQUIRE(header1.pixel_aspect_ratio == header2.pixel_aspect_ratio); REQUIRE(header1.tiled == header2.tiled); REQUIRE(header1.tile_size_x == header2.tile_size_x); REQUIRE(header1.tile_size_y == header2.tile_size_y); REQUIRE(header1.tile_level_mode == header2.tile_level_mode); REQUIRE(header1.tile_rounding_mode == header2.tile_rounding_mode); REQUIRE(header1.non_image == header2.non_image); REQUIRE(0 == strcmp(header1.name, header2.name)); for (int c = 0; c < header1.num_channels; c++) { REQUIRE(header1.pixel_types[c] == header2.pixel_types[c]); // assume no conversion REQUIRE(0 == strcmp(header1.channels[c].name, header2.channels[c].name)); REQUIRE(header1.channels[c].pixel_type == header2.pixel_types[c]); //REQUIRE(header1.channels[c].p_linear == header2.channels[c].p_linear); //REQUIRE(header1.channels[c].x_sampling == header2.channels[c].x_sampling); //REQUIRE(header1.channels[c].y_sampling == header2.channels[c].y_sampling); } } static void CompareImages(const EXRImage& image1, const EXRImage& image2) { bool tiles_ok = image1.tiles && image2.tiles || image1.tiles == NULL && image2.tiles == NULL; REQUIRE(true == tiles_ok); bool images_ok = image1.images && image2.images || image1.images == NULL && image2.images == NULL; REQUIRE(true == images_ok); REQUIRE(image1.num_channels == image2.num_channels); const EXRImage* level_image1 = &image1; const EXRImage* level_image2 = &image2; while(level_image1 && level_image2) { REQUIRE(level_image1->level_x == level_image2->level_x); REQUIRE(level_image1->level_y == level_image2->level_y); REQUIRE(level_image1->width == level_image2->width); REQUIRE(level_image1->height == level_image2->height); REQUIRE(level_image1->num_tiles == level_image2->num_tiles); level_image1 = level_image1->next_level; level_image2 = level_image2->next_level; bool levels_ok = level_image1 && level_image2 || level_image1 == NULL && level_image2 == NULL; REQUIRE(true == levels_ok); } } TEST_CASE("asakusa", "[Load]") { EXRVersion exr_version; EXRImage exr_image; InitEXRImage(&exr_image); EXRHeader exr_header; InitEXRHeader(&exr_header); const char* err = NULL; int ret = ParseEXRVersionFromFile(&exr_version, "../../asakusa.exr"); REQUIRE(TINYEXR_SUCCESS == ret); ret = ParseEXRHeaderFromFile(&exr_header, &exr_version, "../../asakusa.exr", &err); REQUIRE(NULL == err); REQUIRE(TINYEXR_SUCCESS == ret); FreeEXRImage(&exr_image); FreeEXRHeader(&exr_header); } TEST_CASE("utf8filename", "[Load]") { EXRVersion exr_version; EXRHeader exr_header; InitEXRHeader(&exr_header); const char* err = NULL; #ifdef _WIN32 #if defined(_MSC_VER) // Include UTF-16LE encoded string const wchar_t* wfilename = #include "win32-filelist-utf16le.inc" ; // convert to char* // https://stackoverflow.com/questions/12637779/how-to-convert-const-wchar-to-const-char/12637971 FILE* fp; errno_t errcode = _wfopen_s(&fp, wfilename, L"rb"); REQUIRE(0 == errcode); char filename[1024]; int charlen = 1000; int strlen = WideCharToMultiByte(65001 /* UTF8 */, 0, wfilename, -1, filename, (int)charlen, NULL, NULL); REQUIRE(strlen == 27); #else // MinGW or clang. // At least clang cannot feed UTF-16LE source code, so provide UTF-8 encoded // file path const char* utf8filename = #include "win32-filelist-utf8.inc" ; // to wchar_t const std::wstring wfilename = UTF8_to_wchar(utf8filename); FILE* fp; errno_t errcode = _wfopen_s(&fp, wfilename.c_str(), L"rb"); REQUIRE(0 == errcode); char filename[1024]; int charlen = 1000; // wchar_t to multibyte char int strlen = WideCharToMultiByte(65001 /* UTF8 */, 0, wfilename.c_str(), -1, filename, (int)charlen, NULL, NULL); REQUIRE(strlen == 27); #endif #else // Assume this source code is compiled with UTF-8(UNICODE) const char* filename = "./regression/日本語.exr"; #endif int ret = ParseEXRVersionFromFile(&exr_version, filename); REQUIRE(TINYEXR_SUCCESS == ret); ret = ParseEXRHeaderFromFile(&exr_header, &exr_version, filename, &err); REQUIRE(NULL == err); REQUIRE(TINYEXR_SUCCESS == ret); FreeEXRHeader(&exr_header); } TEST_CASE("ScanLines", "[Load]") { std::vector inputs; inputs.push_back("ScanLines/Blobbies.exr"); inputs.push_back("ScanLines/CandleGlass.exr"); // inputs.push_back("ScanLines/Cannon.exr"); // Cannon.exr will fail since it // uses b44 compression which is not yet supported on TinyEXR. inputs.push_back("ScanLines/Desk.exr"); inputs.push_back("ScanLines/MtTamWest.exr"); inputs.push_back("ScanLines/PrismsLenses.exr"); inputs.push_back("ScanLines/StillLife.exr"); inputs.push_back("ScanLines/Tree.exr"); for (size_t i = 0; i < inputs.size(); i++) { EXRVersion exr_version; std::string filepath = GetPath(inputs[i].c_str()); std::cout << "Loading" << filepath << std::endl; int ret = ParseEXRVersionFromFile(&exr_version, filepath.c_str()); REQUIRE(TINYEXR_SUCCESS == ret); REQUIRE(false == exr_version.tiled); REQUIRE(false == exr_version.non_image); REQUIRE(false == exr_version.multipart); EXRVersion version; EXRHeader header; EXRImage image; InitEXRHeader(&header); InitEXRImage(&image); const char* err; ret = ParseEXRHeaderFromFile(&header, &exr_version, filepath.c_str(), &err); REQUIRE(TINYEXR_SUCCESS == ret); ret = LoadEXRImageFromFile(&image, &header, filepath.c_str(), &err); REQUIRE(TINYEXR_SUCCESS == ret); FreeEXRHeader(&header); FreeEXRImage(&image); } } TEST_CASE("Chromaticities", "[Load]") { std::vector inputs; inputs.push_back("Chromaticities/Rec709.exr"); inputs.push_back("Chromaticities/Rec709_YC.exr"); inputs.push_back("Chromaticities/XYZ.exr"); inputs.push_back("Chromaticities/XYZ_YC.exr"); for (size_t i = 0; i < inputs.size(); i++) { EXRVersion exr_version; std::string filepath = GetPath(inputs[i].c_str()); std::cout << "Loading" << filepath << std::endl; int ret = ParseEXRVersionFromFile(&exr_version, filepath.c_str()); REQUIRE(TINYEXR_SUCCESS == ret); REQUIRE(false == exr_version.tiled); REQUIRE(false == exr_version.non_image); REQUIRE(false == exr_version.multipart); EXRVersion version; EXRHeader header; EXRImage image; InitEXRHeader(&header); InitEXRImage(&image); const char* err; ret = ParseEXRHeaderFromFile(&header, &exr_version, filepath.c_str(), &err); REQUIRE(TINYEXR_SUCCESS == ret); ret = LoadEXRImageFromFile(&image, &header, filepath.c_str(), &err); REQUIRE(TINYEXR_SUCCESS == ret); FreeEXRHeader(&header); FreeEXRImage(&image); } } TEST_CASE("TestImages", "[Load]") { std::vector inputs; inputs.push_back("TestImages/AllHalfValues.exr"); inputs.push_back("TestImages/BrightRings.exr"); inputs.push_back("TestImages/BrightRingsNanInf.exr"); // inputs.push_back("TestImages/GammaChart.exr"); // disable since this uses // pxr24 compression // inputs.push_back("TestImages/GrayRampsDiagonal.exr"); // pxr24 // inputs.push_back("TestImages/GrayRampsHorizontal.exr"); // pxr24 // inputs.push_back("TestImages/RgbRampsDiagonal.exr"); // pxr24 // inputs.push_back("TestImages/SquaresSwirls.exr"); // pxr24 inputs.push_back("TestImages/WideColorGamut.exr"); // inputs.push_back("TestImages/WideFloatRange.exr"); // pxr24 for (size_t i = 0; i < inputs.size(); i++) { EXRVersion exr_version; std::string filepath = GetPath(inputs[i].c_str()); std::cout << "Loading" << filepath << std::endl; int ret = ParseEXRVersionFromFile(&exr_version, filepath.c_str()); REQUIRE(TINYEXR_SUCCESS == ret); REQUIRE(false == exr_version.tiled); REQUIRE(false == exr_version.non_image); REQUIRE(false == exr_version.multipart); EXRVersion version; EXRHeader header; EXRImage image; InitEXRHeader(&header); InitEXRImage(&image); const char* err; ret = ParseEXRHeaderFromFile(&header, &exr_version, filepath.c_str(), &err); REQUIRE(TINYEXR_SUCCESS == ret); ret = LoadEXRImageFromFile(&image, &header, filepath.c_str(), &err); REQUIRE(TINYEXR_SUCCESS == ret); FreeEXRHeader(&header); FreeEXRImage(&image); } } TEST_CASE("LuminanceChroma", "[Load]") { std::vector inputs; // inputs.push_back("LuminanceChroma/CrissyField.exr"); // b44 // inputs.push_back("LuminanceChroma/Flowers.exr"); // b44 // inputs.push_back("LuminanceChroma/Garden.exr"); // tiled inputs.push_back("LuminanceChroma/MtTamNorth.exr"); inputs.push_back("LuminanceChroma/StarField.exr"); for (size_t i = 0; i < inputs.size(); i++) { EXRVersion exr_version; std::string filepath = GetPath(inputs[i].c_str()); std::cout << "Loading" << filepath << std::endl; int ret = ParseEXRVersionFromFile(&exr_version, filepath.c_str()); REQUIRE(TINYEXR_SUCCESS == ret); REQUIRE(false == exr_version.tiled); REQUIRE(false == exr_version.non_image); REQUIRE(false == exr_version.multipart); EXRVersion version; EXRHeader header; EXRImage image; InitEXRHeader(&header); InitEXRImage(&image); const char* err; ret = ParseEXRHeaderFromFile(&header, &exr_version, filepath.c_str(), &err); REQUIRE(TINYEXR_SUCCESS == ret); ret = LoadEXRImageFromFile(&image, &header, filepath.c_str(), &err); REQUIRE(TINYEXR_SUCCESS == ret); FreeEXRHeader(&header); FreeEXRImage(&image); } } TEST_CASE("DisplayWindow", "[Load]") { std::vector inputs; inputs.push_back("DisplayWindow/t01.exr"); inputs.push_back("DisplayWindow/t02.exr"); inputs.push_back("DisplayWindow/t03.exr"); inputs.push_back("DisplayWindow/t04.exr"); inputs.push_back("DisplayWindow/t05.exr"); inputs.push_back("DisplayWindow/t06.exr"); inputs.push_back("DisplayWindow/t07.exr"); inputs.push_back("DisplayWindow/t08.exr"); inputs.push_back("DisplayWindow/t09.exr"); inputs.push_back("DisplayWindow/t10.exr"); inputs.push_back("DisplayWindow/t11.exr"); inputs.push_back("DisplayWindow/t12.exr"); inputs.push_back("DisplayWindow/t13.exr"); inputs.push_back("DisplayWindow/t14.exr"); inputs.push_back("DisplayWindow/t15.exr"); inputs.push_back("DisplayWindow/t16.exr"); for (size_t i = 0; i < inputs.size(); i++) { EXRVersion exr_version; std::string filepath = GetPath(inputs[i].c_str()); std::cout << "Loading" << filepath << std::endl; int ret = ParseEXRVersionFromFile(&exr_version, filepath.c_str()); REQUIRE(TINYEXR_SUCCESS == ret); REQUIRE(false == exr_version.tiled); REQUIRE(false == exr_version.non_image); REQUIRE(false == exr_version.multipart); EXRVersion version; EXRHeader header; EXRImage image; InitEXRHeader(&header); InitEXRImage(&image); const char* err; ret = ParseEXRHeaderFromFile(&header, &exr_version, filepath.c_str(), &err); REQUIRE(TINYEXR_SUCCESS == ret); ret = LoadEXRImageFromFile(&image, &header, filepath.c_str(), &err); REQUIRE(TINYEXR_SUCCESS == ret); FreeEXRHeader(&header); FreeEXRImage(&image); } } TEST_CASE("Tiles/GoldenGate.exr", "[Version]") { EXRVersion exr_version; std::string filepath = GetPath("Tiles/GoldenGate.exr"); int ret = ParseEXRVersionFromFile(&exr_version, filepath.c_str()); REQUIRE(TINYEXR_SUCCESS == ret); REQUIRE(true == exr_version.tiled); } TEST_CASE("Tiles/GoldenGate.exr|Load", "[Load]") { EXRVersion exr_version; std::string filepath = GetPath("Tiles/GoldenGate.exr"); int ret = ParseEXRVersionFromFile(&exr_version, filepath.c_str()); REQUIRE(TINYEXR_SUCCESS == ret); REQUIRE(true == exr_version.tiled); REQUIRE(false == exr_version.non_image); REQUIRE(false == exr_version.multipart); EXRVersion version; EXRHeader header; EXRImage image; InitEXRHeader(&header); InitEXRImage(&image); const char* err; ret = ParseEXRHeaderFromFile(&header, &exr_version, filepath.c_str(), &err); REQUIRE(TINYEXR_SUCCESS == ret); REQUIRE(1 == header.tiled); REQUIRE(TINYEXR_TILE_ONE_LEVEL == header.tile_level_mode); REQUIRE(128 == header.tile_size_x); REQUIRE(128 == header.tile_size_y); ret = LoadEXRImageFromFile(&image, &header, filepath.c_str(), &err); REQUIRE(TINYEXR_SUCCESS == ret); REQUIRE(NULL != image.tiles); REQUIRE(0 == image.level_x); REQUIRE(0 == image.level_y); REQUIRE(1 == EXRNumLevels(&image)); FreeEXRHeader(&header); FreeEXRImage(&image); } TEST_CASE("LuminanceChroma/Garden.exr|Load", "[Load]") { EXRVersion exr_version; std::string filepath = GetPath("LuminanceChroma/Garden.exr"); int ret = ParseEXRVersionFromFile(&exr_version, filepath.c_str()); REQUIRE(TINYEXR_SUCCESS == ret); REQUIRE(true == exr_version.tiled); REQUIRE(false == exr_version.non_image); REQUIRE(false == exr_version.multipart); EXRVersion version; EXRHeader header; EXRImage image; InitEXRHeader(&header); InitEXRImage(&image); const char* err; ret = ParseEXRHeaderFromFile(&header, &exr_version, filepath.c_str(), &err); REQUIRE(TINYEXR_SUCCESS == ret); ret = LoadEXRImageFromFile(&image, &header, filepath.c_str(), &err); REQUIRE(TINYEXR_SUCCESS == ret); FreeEXRHeader(&header); FreeEXRImage(&image); } TEST_CASE("Tiles/Ocean.exr", "[Load]") { EXRVersion exr_version; std::string filepath = GetPath("Tiles/Ocean.exr"); int ret = ParseEXRVersionFromFile(&exr_version, filepath.c_str()); REQUIRE(TINYEXR_SUCCESS == ret); REQUIRE(true == exr_version.tiled); REQUIRE(false == exr_version.non_image); REQUIRE(false == exr_version.multipart); EXRVersion version; EXRHeader header; EXRImage image; InitEXRHeader(&header); InitEXRImage(&image); const char* err; ret = ParseEXRHeaderFromFile(&header, &exr_version, filepath.c_str(), &err); REQUIRE(TINYEXR_SUCCESS == ret); ret = LoadEXRImageFromFile(&image, &header, filepath.c_str(), &err); REQUIRE(TINYEXR_SUCCESS == ret); FreeEXRHeader(&header); FreeEXRImage(&image); } TEST_CASE("MultiResolution/Bonita.exr", "[Load]") { EXRVersion exr_version; std::string filepath = GetPath("MultiResolution/Bonita.exr"); std::cout << "Loading" << filepath << std::endl; int ret = ParseEXRVersionFromFile(&exr_version, filepath.c_str()); REQUIRE(TINYEXR_SUCCESS == ret); REQUIRE(true == exr_version.tiled); REQUIRE(false == exr_version.non_image); REQUIRE(false == exr_version.multipart); EXRVersion version; EXRHeader header; EXRImage image; InitEXRHeader(&header); InitEXRImage(&image); const char* err; ret = ParseEXRHeaderFromFile(&header, &exr_version, filepath.c_str(), &err); REQUIRE(TINYEXR_SUCCESS == ret); REQUIRE(1 == header.tiled); REQUIRE(TINYEXR_TILE_MIPMAP_LEVELS == header.tile_level_mode); REQUIRE(TINYEXR_TILE_ROUND_DOWN == header.tile_rounding_mode); ret = LoadEXRImageFromFile(&image, &header, filepath.c_str(), &err); REQUIRE(TINYEXR_SUCCESS == ret); REQUIRE(10 == EXRNumLevels(&image)); FreeEXRHeader(&header); FreeEXRImage(&image); } TEST_CASE("MultiResolution/Kapaa.exr", "[Load]") { EXRVersion exr_version; std::string filepath = GetPath("MultiResolution/Kapaa.exr"); std::cout << "Loading" << filepath << std::endl; int ret = ParseEXRVersionFromFile(&exr_version, filepath.c_str()); REQUIRE(TINYEXR_SUCCESS == ret); REQUIRE(true == exr_version.tiled); REQUIRE(false == exr_version.non_image); REQUIRE(false == exr_version.multipart); EXRVersion version; EXRHeader header; EXRImage image; InitEXRHeader(&header); InitEXRImage(&image); const char* err; ret = ParseEXRHeaderFromFile(&header, &exr_version, filepath.c_str(), &err); REQUIRE(TINYEXR_SUCCESS == ret); REQUIRE(1 == header.tiled); REQUIRE(TINYEXR_TILE_RIPMAP_LEVELS == header.tile_level_mode); REQUIRE(TINYEXR_TILE_ROUND_UP == header.tile_rounding_mode); REQUIRE(64 == header.tile_size_x); REQUIRE(64 == header.tile_size_y); ret = LoadEXRImageFromFile(&image, &header, filepath.c_str(), &err); REQUIRE(TINYEXR_SUCCESS == ret); REQUIRE(11*11 == EXRNumLevels(&image)); FreeEXRHeader(&header); FreeEXRImage(&image); } TEST_CASE("Saving ScanLines", "[Save]") { std::vector inputs; inputs.push_back("ScanLines/Blobbies.exr"); inputs.push_back("ScanLines/CandleGlass.exr"); // inputs.push_back("ScanLines/Cannon.exr"); // Cannon.exr will fail since it // uses b44 compression which is not yet supported on TinyEXR. inputs.push_back("ScanLines/Desk.exr"); inputs.push_back("ScanLines/MtTamWest.exr"); inputs.push_back("ScanLines/PrismsLenses.exr"); inputs.push_back("ScanLines/StillLife.exr"); inputs.push_back("ScanLines/Tree.exr"); for (size_t i = 0; i < inputs.size(); i++) { std::string filepath = GetPath(inputs[i].c_str()); std::cout << "Input:" << filepath << std::endl; EXRVersion version1; int ret = ParseEXRVersionFromFile(&version1, filepath.c_str()); REQUIRE(TINYEXR_SUCCESS == ret); EXRHeader header1; EXRImage image1; unsigned char *data = NULL; size_t data_size; // loading from file { InitEXRHeader(&header1); InitEXRImage(&image1); const char* err; ret = ParseEXRHeaderFromFile(&header1, &version1, filepath.c_str(), &err); REQUIRE(TINYEXR_SUCCESS == ret); ret = LoadEXRImageFromFile(&image1, &header1, filepath.c_str(), &err); REQUIRE(TINYEXR_SUCCESS == ret); } // saving to memory { const char* err = NULL; data_size = SaveEXRImageToMemory(&image1, &header1, &data, &err); REQUIRE(0 != data_size); //FreeEXRHeader(&header); #ifdef DUMP_IMAGES bool ret = WriteMemoryToFile(GetDumpPath(inputs[i].c_str()).c_str(), data, data_size); REQUIRE(true == ret); #endif } // loading back from memory { EXRVersion version2; { int ret = ParseEXRVersionFromMemory(&version2, data, data_size); REQUIRE(0 == ret); } EXRHeader header2; { const char* err = NULL; InitEXRHeader(&header2); int ret = ParseEXRHeaderFromMemory(&header2, &version2, data, data_size, &err); REQUIRE(0 == ret); } EXRImage image2; { const char* err = NULL; InitEXRImage(&image2); int ret = LoadEXRImageFromMemory(&image2, &header2, data, data_size, &err); REQUIRE(TINYEXR_SUCCESS == ret); free(data); } CompareHeaders(header1, header2); CompareImages(image1, image2); FreeEXRImage(&image2); FreeEXRHeader(&header2); } FreeEXRHeader(&header1); FreeEXRImage(&image1); } } TEST_CASE("Saving MultiResolution", "[Save]") { //std::string filepath = GetPath("MultiResolution/Bonita.exr"); //std::cout << "Load-save-reload:" << filepath << std::endl; std::vector inputs; inputs.push_back("MultiResolution/Bonita.exr"); inputs.push_back("MultiResolution/Kapaa.exr"); for (size_t i = 0; i < inputs.size(); i++) { std::string filepath = GetPath(inputs[i].c_str()); std::cout << "Input:" << filepath << std::endl; EXRVersion version1; int ret = ParseEXRVersionFromFile(&version1, filepath.c_str()); REQUIRE(TINYEXR_SUCCESS == ret); EXRHeader header1; EXRImage image1; unsigned char *data = NULL; size_t data_size; // loading from file { InitEXRHeader(&header1); InitEXRImage(&image1); const char* err; ret = ParseEXRHeaderFromFile(&header1, &version1, filepath.c_str(), &err); REQUIRE(TINYEXR_SUCCESS == ret); ret = LoadEXRImageFromFile(&image1, &header1, filepath.c_str(), &err); REQUIRE(TINYEXR_SUCCESS == ret); } // saving to memory { const char* err = NULL; data_size = SaveEXRImageToMemory(&image1, &header1, &data, &err); REQUIRE(0 != data_size); #ifdef DUMP_IMAGES bool ret = WriteMemoryToFile(GetDumpPath(inputs[i].c_str()).c_str(), data, data_size); REQUIRE(true == ret); #endif } // loading back from memory { EXRVersion version2; { int ret = ParseEXRVersionFromMemory(&version2, data, data_size); REQUIRE(0 == ret); } EXRHeader header2; { const char* err = NULL; InitEXRHeader(&header2); int ret = ParseEXRHeaderFromMemory(&header2, &version2, data, data_size, &err); REQUIRE(0 == ret); } EXRImage image2; { const char* err = NULL; InitEXRImage(&image2); int ret = LoadEXRImageFromMemory(&image2, &header2, data, data_size, &err); REQUIRE(TINYEXR_SUCCESS == ret); free(data); } CompareHeaders(header1, header2); CompareImages(image1, image2); FreeEXRImage(&image2); FreeEXRHeader(&header2); } FreeEXRHeader(&header1); FreeEXRImage(&image1); } } TEST_CASE("Saving multipart", "[Save]") { std::vector inputs; inputs.push_back("Beachball/multipart.0001.exr"); for (size_t i = 0; i < inputs.size(); i++) { std::string filepath = GetPath(inputs[i].c_str()); std::cout << "Input:" << filepath << std::endl; EXRVersion version1; { int ret = ParseEXRVersionFromFile(&version1, filepath.c_str()); REQUIRE(TINYEXR_SUCCESS == ret); REQUIRE(true == version1.multipart); } EXRHeader** headers1; // list of EXRHeader pointers. int num_headers1; { const char* err = NULL; int ret = ParseEXRMultipartHeaderFromFile(&headers1, &num_headers1, &version1, filepath.c_str(), &err); REQUIRE(TINYEXR_SUCCESS == ret); } unsigned char *data = NULL; size_t data_size; std::vector images1(num_headers1); // loading from file { const char* err = NULL; for (int j = 0; j < num_headers1; j++) { InitEXRImage(&images1[j]); } int ret = LoadEXRMultipartImageFromFile(&images1[0], const_cast(headers1), static_cast(num_headers1), filepath.c_str(), &err); REQUIRE(TINYEXR_SUCCESS == ret); } // saving to memory { const char* err = NULL; data_size = SaveEXRMultipartImageToMemory(&images1[0], const_cast(headers1), static_cast(num_headers1), &data, &err); REQUIRE(0 != data_size); #ifdef DUMP_IMAGES bool ret = WriteMemoryToFile(GetDumpPath(inputs[i].c_str()).c_str(), data, data_size); REQUIRE(true == ret); #endif } // loading back from memory { EXRVersion version2; { int ret = ParseEXRVersionFromMemory(&version2, data, data_size); REQUIRE(TINYEXR_SUCCESS == ret); REQUIRE(true == version2.multipart); } EXRHeader** headers2; int num_headers2; { const char* err = NULL; int ret = ParseEXRMultipartHeaderFromMemory(&headers2, &num_headers2, &version2, data, data_size, &err); REQUIRE(TINYEXR_SUCCESS == ret); } REQUIRE(num_headers1 == num_headers2); std::vector images2(num_headers2); { for (int j = 0; j < num_headers2; j++) { InitEXRImage(&images2[j]); } const char* err = NULL; int ret = LoadEXRMultipartImageFromMemory(&images2[0], const_cast(headers2), static_cast(num_headers2), data, data_size, &err); REQUIRE(TINYEXR_SUCCESS == ret); free(data); } for (int j = 0; j < num_headers2; j++) { CompareHeaders(*headers1[j], *headers2[j]); } for (int j = 0; j < num_headers2; j++) { CompareImages(images1[j], images2[j]); } for (int j = 0; j < num_headers2; j++) { FreeEXRImage(&images2[j]); FreeEXRHeader(headers2[j]); free(headers2[j]); } free(headers2); } for (int j = 0; j < num_headers1; j++) { FreeEXRImage(&images1[j]); FreeEXRHeader(headers1[j]); free(headers1[j]); } free(headers1); } } TEST_CASE("Saving multipart|Combine", "[Save]") { std::vector inputs; inputs.push_back("MultiResolution/Kapaa.exr"); // tiled, ripmap inputs.push_back("Tiles/GoldenGate.exr"); // tiled, one level inputs.push_back("ScanLines/Desk.exr"); // scanline inputs.push_back("MultiResolution/PeriodicPattern.exr"); // tiled, mipmap const char* dstName = "multipart.collection.exr"; unsigned num_headers1 = inputs.size(); std::vector headers1(num_headers1); std::vector images1(num_headers1); // collecting images for (size_t i = 0; i < num_headers1; i++) { std::string filepath = GetPath(inputs[i].c_str()); std::cout << "Input:" << filepath << std::endl; EXRVersion version1; { int ret = ParseEXRVersionFromFile(&version1, filepath.c_str()); REQUIRE(TINYEXR_SUCCESS == ret); REQUIRE(false == version1.multipart); } { InitEXRHeader(&headers1[i]); const char* err = NULL; int ret = ParseEXRHeaderFromFile(&headers1[i], &version1, filepath.c_str(), &err); REQUIRE(TINYEXR_SUCCESS == ret); } { InitEXRImage(&images1[i]); const char* err = NULL; int ret = LoadEXRImageFromFile(&images1[i], &headers1[i], filepath.c_str(), &err); REQUIRE(TINYEXR_SUCCESS == ret); } } unsigned char *data = NULL; size_t data_size; // saving collection to memory as multipart { std::vector pheaders1(num_headers1); for(unsigned i = 0; i < num_headers1; ++i) pheaders1[i] = &headers1[i]; for (size_t i = 0; i < num_headers1; i++) { EXRSetNameAttr(pheaders1[i], inputs[i].c_str()); } const char* err = NULL; data_size = SaveEXRMultipartImageToMemory(&images1[0], const_cast(&pheaders1[0]), static_cast(num_headers1), &data, &err); REQUIRE(0 != data_size); #ifdef DUMP_IMAGES bool ret = WriteMemoryToFile(GetDumpPath(dstName).c_str(), data, data_size); REQUIRE(true == ret); #endif } // loading back from memory { EXRVersion version2; { int ret = ParseEXRVersionFromMemory(&version2, data, data_size); REQUIRE(TINYEXR_SUCCESS == ret); REQUIRE(true == version2.multipart); } EXRHeader** headers2; int num_headers2; { const char* err = NULL; int ret = ParseEXRMultipartHeaderFromMemory(&headers2, &num_headers2, &version2, data, data_size, &err); REQUIRE(TINYEXR_SUCCESS == ret); } REQUIRE(num_headers1 == num_headers2); std::vector images2(num_headers2); { for (int j = 0; j < num_headers2; j++) { InitEXRImage(&images2[j]); } const char* err = NULL; int ret = LoadEXRMultipartImageFromMemory(&images2[0], const_cast(headers2), static_cast(num_headers2), data, data_size, &err); REQUIRE(TINYEXR_SUCCESS == ret); free(data); } for (int j = 0; j < num_headers2; j++) { CompareHeaders(headers1[j], *headers2[j]); } for (int j = 0; j < num_headers2; j++) { CompareImages(images1[j], images2[j]); } for (int j = 0; j < num_headers2; j++) { FreeEXRImage(&images2[j]); FreeEXRHeader(headers2[j]); free(headers2[j]); } free(headers2); } for (int i = 0; i < num_headers1; i++) { FreeEXRImage(&images1[i]); FreeEXRHeader(&headers1[i]); } } #if 0 // Spirals.exr uses pxr24 compression TEST_CASE("Tiles/Spirals.exr", "[Load]") { EXRVersion exr_version; std::string filepath = GetPath("Tiles/Spirals.exr"); int ret = ParseEXRVersionFromFile(&exr_version, filepath.c_str()); REQUIRE(TINYEXR_SUCCESS == ret); REQUIRE(true == exr_version.tiled); REQUIRE(false == exr_version.non_image); REQUIRE(false == exr_version.multipart); EXRVersion version; EXRHeader header; EXRImage image; InitEXRHeader(&header); InitEXRImage(&image); const char* err; ret = ParseEXRHeaderFromFile(&header, &exr_version, filepath.c_str(), &err); REQUIRE(TINYEXR_SUCCESS == ret); ret= LoadEXRImageFromFile(&image, &header, filepath.c_str(), &err); REQUIRE(TINYEXR_SUCCESS == ret); FreeEXRHeader(&header); FreeEXRImage(&image); } #endif TEST_CASE("Beachball/multipart.0001.exr", "[Version]") { EXRVersion exr_version; std::string filepath = GetPath("Beachball/multipart.0001.exr"); int ret = ParseEXRVersionFromFile(&exr_version, filepath.c_str()); REQUIRE(TINYEXR_SUCCESS == ret); REQUIRE(true == exr_version.multipart); EXRHeader* headers; } TEST_CASE("Beachball/multipart.0001.exr|Load", "[Load]") { EXRVersion exr_version; std::string filepath = GetPath("Beachball/multipart.0001.exr"); int ret = ParseEXRVersionFromFile(&exr_version, filepath.c_str()); REQUIRE(TINYEXR_SUCCESS == ret); REQUIRE(true == exr_version.multipart); EXRHeader** exr_headers; // list of EXRHeader pointers. int num_exr_headers; const char* err; ret = ParseEXRMultipartHeaderFromFile(&exr_headers, &num_exr_headers, &exr_version, filepath.c_str(), &err); REQUIRE(TINYEXR_SUCCESS == ret); REQUIRE(10 == num_exr_headers); std::vector images(static_cast(num_exr_headers)); for (int i = 0; i < num_exr_headers; i++) { InitEXRImage(&images[static_cast(i)]); } ret = LoadEXRMultipartImageFromFile( &images.at(0), const_cast(exr_headers), static_cast(num_exr_headers), filepath.c_str(), &err); REQUIRE(TINYEXR_SUCCESS == ret); for (int i = 0; i < num_exr_headers; i++) { FreeEXRImage(&images.at(static_cast(i))); } for (int i = 0; i < num_exr_headers; i++) { FreeEXRHeader(exr_headers[static_cast(i)]); // free content free(exr_headers[static_cast(i)]); // free pointer } free(exr_headers); } TEST_CASE("Beachbal multiparts", "[Load]") { int num = 8; char buf[1024]; for (int i = 0; i < num + 1; i++) { sprintf(buf, "Beachball/multipart.%04d.exr", i); EXRVersion exr_version; std::string filepath = GetPath(buf); int ret = ParseEXRVersionFromFile(&exr_version, filepath.c_str()); if (i == 0) { // multipart.0000.exr does not exist. REQUIRE(TINYEXR_ERROR_CANT_OPEN_FILE == ret); continue; } REQUIRE(TINYEXR_SUCCESS == ret); REQUIRE(true == exr_version.multipart); EXRHeader** exr_headers; // list of EXRHeader pointers. int num_exr_headers; const char* err; ret = ParseEXRMultipartHeaderFromFile(&exr_headers, &num_exr_headers, &exr_version, filepath.c_str(), &err); REQUIRE(TINYEXR_SUCCESS == ret); REQUIRE(10 == num_exr_headers); std::vector images(static_cast(num_exr_headers)); for (int j = 0; j < num_exr_headers; j++) { InitEXRImage(&images[static_cast(j)]); } ret = LoadEXRMultipartImageFromFile( &images.at(0), const_cast(exr_headers), static_cast(num_exr_headers), filepath.c_str(), &err); REQUIRE(TINYEXR_SUCCESS == ret); for (int j = 0; j < num_exr_headers; j++) { FreeEXRImage(&images.at(static_cast(j))); } for (int j = 0; j < num_exr_headers; j++) { FreeEXRHeader(exr_headers[static_cast(j)]); free(exr_headers[static_cast(j)]); } free(exr_headers); } } TEST_CASE("Beachbal singleparts", "[Load]") { int num = 8; char buf[1024]; for (int i = 0; i < num + 1; i++) { sprintf(buf, "Beachball/singlepart.%04d.exr", i); EXRVersion exr_version; std::string filepath = GetPath(buf); int ret = ParseEXRVersionFromFile(&exr_version, filepath.c_str()); if (i == 0) { // multipart.0000.exr does not exist. REQUIRE(TINYEXR_ERROR_CANT_OPEN_FILE == ret); continue; } REQUIRE(TINYEXR_SUCCESS == ret); REQUIRE(false == exr_version.tiled); REQUIRE(false == exr_version.non_image); REQUIRE(false == exr_version.multipart); EXRVersion version; memset(&version, 0, sizeof(EXRVersion)); EXRHeader header; EXRImage image; InitEXRHeader(&header); InitEXRImage(&image); const char* err; ret = ParseEXRHeaderFromFile(&header, &exr_version, filepath.c_str(), &err); REQUIRE(TINYEXR_SUCCESS == ret); ret = LoadEXRImageFromFile(&image, &header, filepath.c_str(), &err); REQUIRE(TINYEXR_SUCCESS == ret); REQUIRE(image.tiles == NULL); REQUIRE(image.images); FreeEXRHeader(&header); FreeEXRImage(&image); } } TEST_CASE("ParseEXRVersionFromMemory invalid input", "[Parse]") { int ret = ParseEXRVersionFromMemory(NULL, NULL, 0); REQUIRE(ret == TINYEXR_ERROR_INVALID_ARGUMENT); { EXRVersion version; memset(&version, 0, sizeof(EXRVersion)); ret = ParseEXRVersionFromMemory(&version, NULL, 0); REQUIRE(ret == TINYEXR_ERROR_INVALID_ARGUMENT); } { EXRVersion version; memset(&version, 0, sizeof(EXRVersion)); std::vector buf(128); ret = ParseEXRVersionFromMemory(&version, buf.data(), 0); REQUIRE(ret == TINYEXR_ERROR_INVALID_DATA); } { EXRVersion version; memset(&version, 0, sizeof(EXRVersion)); std::vector buf(4); ret = ParseEXRVersionFromMemory( &version, buf.data(), 1); // size is less than version header size REQUIRE(ret == TINYEXR_ERROR_INVALID_DATA); } { EXRVersion version; memset(&version, 0, sizeof(EXRVersion)); std::vector buf(8, 0); // invalid magic number ret = ParseEXRVersionFromMemory(&version, buf.data(), 8); REQUIRE(ret == TINYEXR_ERROR_INVALID_MAGIC_NUMBER); } } TEST_CASE("ParseEXRHeaderFromMemory invalid input", "[Parse]") { { int ret = ParseEXRHeaderFromMemory(NULL, NULL, NULL, 0, NULL); REQUIRE(ret == TINYEXR_ERROR_INVALID_ARGUMENT); } { EXRHeader header; InitEXRHeader(&header); EXRVersion version; memset(&version, 0, sizeof(EXRVersion)); int ret = ParseEXRHeaderFromMemory(&header, &version, NULL, 0, NULL); REQUIRE(ret == TINYEXR_ERROR_INVALID_ARGUMENT); FreeEXRHeader(&header); } { EXRHeader header; InitEXRHeader(&header); EXRVersion version; memset(&version, 0, sizeof(EXRVersion)); std::vector buf(128); int ret = ParseEXRHeaderFromMemory(&header, &version, buf.data(), 0, NULL); REQUIRE(ret == TINYEXR_ERROR_INVALID_DATA); FreeEXRHeader(&header); } { EXRHeader header; InitEXRHeader(&header); EXRVersion version; memset(&version, 0, sizeof(EXRVersion)); std::vector buf(128, 0); int ret = ParseEXRHeaderFromMemory(&header, &version, buf.data(), 128, NULL); REQUIRE(ret == TINYEXR_ERROR_INVALID_HEADER); FreeEXRHeader(&header); } } TEST_CASE("Compressed is smaller than uncompressed", "[Issue40]") { EXRHeader header; InitEXRHeader(&header); header.compression_type = TINYEXR_COMPRESSIONTYPE_ZIP; EXRImage image; InitEXRImage(&image); image.num_channels = 3; float const images[3][1] = { {1.0f}, {0.0f}, {0.0f}, }; float const* const image_ptr[3] = { images[2], images[1], images[0], }; image.images = const_cast(reinterpret_cast(image_ptr)); image.width = 1; image.height = 1; header.num_channels = 3; header.channels = static_cast(malloc(sizeof(EXRChannelInfo) * static_cast(header.num_channels))); // Must be BGR(A) order, since most of EXR viewers expect this channel order. strncpy(header.channels[0].name, "B", 255); header.channels[0].name[strlen("B")] = '\0'; strncpy(header.channels[1].name, "G", 255); header.channels[1].name[strlen("G")] = '\0'; strncpy(header.channels[2].name, "R", 255); header.channels[2].name[strlen("R")] = '\0'; header.pixel_types = static_cast(malloc(sizeof(int) * static_cast(header.num_channels))); header.requested_pixel_types = static_cast(malloc(sizeof(int) * static_cast(header.num_channels))); for (int i = 0; i < header.num_channels; i++) { header.pixel_types[i] = TINYEXR_PIXELTYPE_FLOAT; // pixel type of input image header.requested_pixel_types[i] = TINYEXR_PIXELTYPE_FLOAT; // pixel type of output image to be stored in // .EXR } const char* err; int const ret = SaveEXRImageToFile(&image, &header, "issue40.exr", &err); REQUIRE(ret == TINYEXR_SUCCESS); free(header.channels); free(header.requested_pixel_types); free(header.pixel_types); } // TEST_CASE("Regression: Issue54", "[fuzzing]") { // EXRVersion exr_version; // std::string filepath = // "./regression/poc-360c3b0555cb979ca108f2d178cf8a80959cfeabaa4ec1d310d062fa653a8c6b_min"; // int ret = ParseEXRVersionFromFile(&exr_version, filepath.c_str()); // REQUIRE(TINYEXR_SUCCESS == ret); // REQUIRE(false == exr_version.tiled); // REQUIRE(false == exr_version.non_image); // REQUIRE(false == exr_version.multipart); // // EXRVersion version; // EXRHeader header; // EXRImage image; // InitEXRHeader(&header); // InitEXRImage(&image); // // const char* err; // ret = ParseEXRHeaderFromFile(&header, &exr_version, filepath.c_str(), &err); // REQUIRE(TINYEXR_SUCCESS == ret); // // ret = LoadEXRImageFromFile(&image, &header, filepath.c_str(), &err); // REQUIRE(TINYEXR_SUCCESS == ret); // // FreeEXRHeader(&header); // FreeEXRImage(&image); //} TEST_CASE("Regression: Issue50", "[fuzzing]") { EXRVersion exr_version; std::string filepath = "./regression/" "poc-eedff3a9e99eb1c0fd3a3b0989e7c44c0a69f04f10b23e5264f362a4773f4397_" "min"; int ret = ParseEXRVersionFromFile(&exr_version, filepath.c_str()); REQUIRE(TINYEXR_SUCCESS == ret); REQUIRE(false == exr_version.tiled); REQUIRE(false == exr_version.non_image); REQUIRE(false == exr_version.multipart); EXRVersion version; EXRHeader header; EXRImage image; InitEXRHeader(&header); InitEXRImage(&image); const char* err = nullptr; ret = ParseEXRHeaderFromFile(&header, &exr_version, filepath.c_str(), &err); REQUIRE(TINYEXR_SUCCESS == false); if (ret) { FreeEXRErrorMessage(err); } FreeEXRHeader(&header); // FreeEXRImage(&image); } TEST_CASE("Regression: Issue57", "[fuzzing]") { EXRVersion exr_version; std::string filepath = "./regression/" "poc-df76d1f27adb8927a1446a603028272140905c168a336128465a1162ec7af270." "mini"; int ret = ParseEXRVersionFromFile(&exr_version, filepath.c_str()); REQUIRE(TINYEXR_SUCCESS == ret); REQUIRE(false == exr_version.tiled); REQUIRE(false == exr_version.non_image); REQUIRE(false == exr_version.multipart); EXRVersion version; EXRHeader header; EXRImage image; InitEXRHeader(&header); InitEXRImage(&image); const char* err = nullptr; ret = ParseEXRHeaderFromFile(&header, &exr_version, filepath.c_str(), &err); REQUIRE(TINYEXR_SUCCESS == false); if (err) { FreeEXRErrorMessage(err); } FreeEXRHeader(&header); // FreeEXRImage(&image); } TEST_CASE("Regression: Issue56", "[fuzzing]") { EXRVersion exr_version; std::string filepath = "./regression/" "poc-1383755b301e5f505b2198dc0508918b537fdf48bbfc6deeffe268822e6f6cd6"; int ret = ParseEXRVersionFromFile(&exr_version, filepath.c_str()); REQUIRE(TINYEXR_SUCCESS == ret); REQUIRE(false == exr_version.tiled); REQUIRE(false == exr_version.non_image); REQUIRE(false == exr_version.multipart); EXRVersion version; EXRHeader header; EXRImage image; InitEXRHeader(&header); InitEXRImage(&image); const char* err = nullptr; ret = ParseEXRHeaderFromFile(&header, &exr_version, filepath.c_str(), &err); REQUIRE(TINYEXR_SUCCESS == false); if (err) { FreeEXRErrorMessage(err); } FreeEXRHeader(&header); // FreeEXRImage(&image); } TEST_CASE("Regression: Issue61", "[fuzzing]") { EXRVersion exr_version; std::string filepath = "./regression/" "poc-3f1f642c3356fd8e8d2a0787613ec09a56572b3a1e38c9629b6db9e8dead1117_" "min"; int ret = ParseEXRVersionFromFile(&exr_version, filepath.c_str()); REQUIRE(TINYEXR_SUCCESS == ret); REQUIRE(false == exr_version.tiled); REQUIRE(false == exr_version.non_image); REQUIRE(false == exr_version.multipart); EXRVersion version; EXRHeader header; EXRImage image; InitEXRHeader(&header); InitEXRImage(&image); const char* err = nullptr; ret = ParseEXRHeaderFromFile(&header, &exr_version, filepath.c_str(), &err); REQUIRE(TINYEXR_SUCCESS == false); if (err) { FreeEXRErrorMessage(err); } FreeEXRHeader(&header); // FreeEXRImage(&image); } TEST_CASE("Regression: Issue60", "[fuzzing]") { EXRVersion exr_version; std::string filepath = "./regression/" "poc-5b66774a7498c635334ad386be0c3b359951738ac47f14878a3346d1c6ea0fe5_" "min"; int ret = ParseEXRVersionFromFile(&exr_version, filepath.c_str()); REQUIRE(TINYEXR_SUCCESS == ret); REQUIRE(false == exr_version.tiled); REQUIRE(false == exr_version.non_image); REQUIRE(false == exr_version.multipart); EXRVersion version; EXRHeader header; EXRImage image; InitEXRHeader(&header); InitEXRImage(&image); const char* err = nullptr; ret = ParseEXRHeaderFromFile(&header, &exr_version, filepath.c_str(), &err); REQUIRE(TINYEXR_SUCCESS == false); if (err) { FreeEXRErrorMessage(err); } FreeEXRHeader(&header); // FreeEXRImage(&image); } TEST_CASE("Regression: Issue71", "[issue71]") { std::string filepath = "./regression/2by2.exr"; const char* err; int width, height; float* image; int ret = LoadEXR(&image, &width, &height, filepath.c_str(), &err); REQUIRE(TINYEXR_SUCCESS == ret); REQUIRE(2 == width); REQUIRE(2 == height); REQUIRE(0.0f == Approx(image[8])); REQUIRE(0.447021f == Approx(image[9])); REQUIRE(1.0f == Approx(image[10])); REQUIRE(0.250977f == Approx(image[11])); REQUIRE(0.0f == Approx(image[12])); REQUIRE(0.0f == Approx(image[13])); REQUIRE(0.0f == Approx(image[14])); REQUIRE(1.0f == Approx(image[15])); free(image); } // LoadEXRLoadFromMemory fails to load tiled image. TEST_CASE("Regression: Issue93", "[issue93]") { std::string filepath = GetPath("Tiles/GoldenGate.exr"); std::ifstream f(filepath.c_str(), std::ifstream::binary); REQUIRE(f.good()); f.seekg(0, f.end); size_t sz = static_cast(f.tellg()); f.seekg(0, f.beg); REQUIRE(sz > 16); std::vector data; data.resize(sz); f.read(reinterpret_cast(&data.at(0)), static_cast(sz)); f.close(); const char* err; int width, height; float* image; int ret = LoadEXRFromMemory(&image, &width, &height, data.data(), data.size(), &err); REQUIRE(TINYEXR_SUCCESS == ret); std::cout << "val = " << image[0] << ", " << image[1] << ", " << image[2] << ", " << image[3] << std::endl; REQUIRE(0.0612183 == Approx(image[0])); REQUIRE(0.0892334 == Approx(image[1])); REQUIRE(0.271973 == Approx(image[2])); free(image); } // PIZ decompress bug(issue 100) TEST_CASE("Regression: Issue100", "[issue100]") { std::string filepath = "./regression/piz-bug-issue-100.exr"; std::ifstream f(filepath.c_str(), std::ifstream::binary); REQUIRE(f.good()); f.seekg(0, f.end); size_t sz = static_cast(f.tellg()); f.seekg(0, f.beg); REQUIRE(sz > 16); std::vector data; data.resize(sz); f.read(reinterpret_cast(&data.at(0)), static_cast(sz)); f.close(); const char* err = nullptr; int width, height; float* image; int ret = LoadEXRFromMemory(&image, &width, &height, data.data(), data.size(), &err); if (err) { std::cerr << "issue100 err " << err << std::endl; FreeEXRErrorMessage(err); } REQUIRE(TINYEXR_SUCCESS == ret); REQUIRE(35 == width); REQUIRE(1 == height); // pixel should be white. std::cout << "pixel[0] = " << image[0] << ", " << image[1] << ", " << image[2] << ", " << image[3] << std::endl; std::cout << "pixel[34] = " << image[4 * 34 + 0] << ", " << image[4 * 34 + 1] << ", " << image[4 * 34 + 2] << ", " << image[4 * 34 + 3] << std::endl; REQUIRE(0.0 == Approx(image[0])); REQUIRE(0.0 == Approx(image[1])); REQUIRE(0.0 == Approx(image[2])); REQUIRE(0.0 == Approx(image[3])); REQUIRE(1.0 == Approx(image[4 * 34 + 0])); REQUIRE(1.0 == Approx(image[4 * 34 + 1])); REQUIRE(1.0 == Approx(image[4 * 34 + 2])); REQUIRE(1.0 == Approx(image[4 * 34 + 3])); free(image); } TEST_CASE("Regression: Issue53|Channels", "[issue53]") { EXRVersion exr_version; std::string filepath = "./regression/flaga.exr"; int ret = ParseEXRVersionFromFile(&exr_version, filepath.c_str()); REQUIRE(TINYEXR_SUCCESS == ret); EXRHeader header; EXRImage image; InitEXRHeader(&header); const char* err = nullptr; ret = ParseEXRHeaderFromFile(&header, &exr_version, filepath.c_str(), &err); REQUIRE(TINYEXR_SUCCESS == ret); std::vector layer_names; tinyexr::GetLayers(header, layer_names); REQUIRE(2 == layer_names.size()); std::vector channels; tinyexr::ChannelsInLayer(header, "", channels); REQUIRE(8 == channels.size()); channels.clear(); tinyexr::ChannelsInLayer(header, "Warstwa 3", channels); REQUIRE(0 == channels.size()); channels.clear(); tinyexr::ChannelsInLayer(header, "Warstwa 1", channels); REQUIRE(4 == channels.size()); FreeEXRHeader(&header); if (err) { FreeEXRErrorMessage(err); } } TEST_CASE("Regression: Issue53|Image", "[issue53]") { std::string filepath = "./regression/flaga.exr"; const char* err = nullptr; const char** layer_names = nullptr; int num_layers = 0; int ret = EXRLayers(filepath.c_str(), &layer_names, &num_layers, &err); REQUIRE(TINYEXR_SUCCESS == ret); REQUIRE(2 == num_layers); for (int i = 0; i < num_layers; i++) { free(reinterpret_cast(const_cast(layer_names[i]))); } free(layer_names); int width, height; float* image; ret = LoadEXRWithLayer(&image, &width, &height, filepath.c_str(), NULL, &err); REQUIRE(TINYEXR_SUCCESS == ret); free(image); if (err) { FreeEXRErrorMessage(err); } ret = LoadEXRWithLayer(&image, &width, &height, filepath.c_str(), "Warstwa 1", &err); REQUIRE(TINYEXR_SUCCESS == ret); free(image); if (err) { FreeEXRErrorMessage(err); } } TEST_CASE("Regression: Issue53|Image|Missing Layer", "[issue53]") { std::string filepath = GetPath("MultiView/Impact.exr"); const char* err = nullptr; int width, height; float* image = nullptr; int ret = LoadEXRWithLayer(&image, &width, &height, filepath.c_str(), "Warstwa", &err); REQUIRE(TINYEXR_ERROR_LAYER_NOT_FOUND == ret); if (image) { free(image); } if (err) { FreeEXRErrorMessage(err); } } TEST_CASE("Regression: PR150|Read|1x1 1xhalf", "[pr150]") { std::string filepath = "./regression/tiled_half_1x1_alpha.exr"; EXRVersion exr_version; std::cout << "Loading" << filepath << std::endl; int ret = ParseEXRVersionFromFile(&exr_version, filepath.c_str()); REQUIRE(TINYEXR_SUCCESS == ret); REQUIRE(true == exr_version.tiled); REQUIRE(false == exr_version.non_image); REQUIRE(false == exr_version.multipart); EXRVersion version; EXRHeader header; EXRImage image; InitEXRHeader(&header); InitEXRImage(&image); const char* err; ret = ParseEXRHeaderFromFile(&header, &exr_version, filepath.c_str(), &err); REQUIRE(TINYEXR_SUCCESS == ret); ret = LoadEXRImageFromFile(&image, &header, filepath.c_str(), &err); REQUIRE(TINYEXR_SUCCESS == ret); FreeEXRHeader(&header); FreeEXRImage(&image); }