🛠️🐜 Antkeeper superbuild with dependencies included https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1714 lines
52 KiB

  1. // Assume this file is encoded in UTF-8
  2. #define CATCH_CONFIG_MAIN // This tells Catch to provide a main() - only do
  3. // this in one cpp file
  4. #include <cassert>
  5. #include <cstdio>
  6. #include <cstdlib>
  7. #include <fstream>
  8. #include <iostream>
  9. #include <sstream>
  10. #include "catch.hpp"
  11. #ifdef _WIN32
  12. #ifndef _CRT_SECURE_NO_WARNINGS
  13. #define _CRT_SECURE_NO_WARNINGS
  14. #endif
  15. #include <windows.h>
  16. #endif
  17. #define TINYEXR_IMPLEMENTATION
  18. #include "../../tinyexr.h"
  19. // uncomment it to write out memory-saved images to files
  20. //#define DUMP_IMAGES
  21. // path to https://github.com/openexr/openexr-images
  22. // TODO(syoyo): Read openexr-images path from command argument.
  23. const char* kOpenEXRImagePath = "../../../openexr-images/";
  24. std::string GetPath(const char* basename) {
  25. std::string s;
  26. s = std::string(kOpenEXRImagePath) + std::string(basename);
  27. return s;
  28. }
  29. // simply dumping to build folder
  30. std::string GetDumpPath(const char* basename) {
  31. std::string s = basename;
  32. size_t index = s.find_last_of("/\\");
  33. if (index != std::string::npos && index + 1 < s.size()) {
  34. s = s.substr(index + 1);
  35. }
  36. //return "dump/" + s;
  37. return s;
  38. }
  39. // https://stackoverflow.com/questions/148403/utf8-to-from-wide-char-conversion-in-stl/148665#148665
  40. std::wstring UTF8_to_wchar(const char* in) {
  41. std::wstring out;
  42. unsigned int codepoint;
  43. while (*in != 0) {
  44. unsigned char ch = static_cast<unsigned char>(*in);
  45. if (ch <= 0x7f)
  46. codepoint = ch;
  47. else if (ch <= 0xbf)
  48. codepoint = (codepoint << 6) | (ch & 0x3f);
  49. else if (ch <= 0xdf)
  50. codepoint = ch & 0x1f;
  51. else if (ch <= 0xef)
  52. codepoint = ch & 0x0f;
  53. else
  54. codepoint = ch & 0x07;
  55. ++in;
  56. if (((*in & 0xc0) != 0x80) && (codepoint <= 0x10ffff)) {
  57. if (sizeof(wchar_t) > 2)
  58. out.append(1, static_cast<wchar_t>(codepoint));
  59. else if (codepoint > 0xffff) {
  60. out.append(1, static_cast<wchar_t>(0xd800 + (codepoint >> 10)));
  61. out.append(1, static_cast<wchar_t>(0xdc00 + (codepoint & 0x03ff)));
  62. } else if (codepoint < 0xd800 || codepoint >= 0xe000)
  63. out.append(1, static_cast<wchar_t>(codepoint));
  64. }
  65. }
  66. return out;
  67. }
  68. #ifdef DUMP_IMAGES
  69. // return true if success
  70. static bool WriteMemoryToFile(const char *filename, const unsigned char* memory, size_t size)
  71. {
  72. std::cout << "Saving:" << std::string(filename) << std::endl;
  73. FILE *fp = NULL;
  74. #ifdef _WIN32
  75. #if defined(_MSC_VER) || defined(__MINGW32__) // MSVC, MinGW gcc or clang
  76. errno_t errcode =
  77. _wfopen_s(&fp, UTF8_to_wchar(filename).c_str(), L"wb");
  78. if (errcode != 0) return false;
  79. #else
  80. // Unknown compiler
  81. fp = fopen(filename, "wb");
  82. #endif
  83. #else
  84. fp = fopen(filename, "wb");
  85. #endif
  86. if (!fp) return false;
  87. size_t written_size = 0;
  88. if (size && memory) {
  89. written_size = fwrite(memory, 1, size, fp);
  90. }
  91. fclose(fp);
  92. return written_size == size;
  93. }
  94. #endif
  95. // some helper funcs
  96. static bool operator == (const EXRBox2i& a, const EXRBox2i& b)
  97. {
  98. return a.min_x == b.min_x && a.min_y == b.min_y &&
  99. a.max_x == b.max_x && a.max_y == b.max_y;
  100. }
  101. static int GetWidth(const EXRBox2i& box)
  102. {
  103. return box.max_x - box.min_x + 1;
  104. }
  105. static int GetHeight(const EXRBox2i& box)
  106. {
  107. return box.max_y - box.min_y + 1;
  108. }
  109. static void CompareHeaders(const EXRHeader& header1, const EXRHeader& header2)
  110. {
  111. #if 0
  112. printf("header1.dataWindow = %d, %d, %d, %d\n", header1.data_window.min_x,
  113. header1.data_window.min_y, header1.data_window.max_x, header1.data_window.max_y);
  114. printf("header2.dataWindow = %d, %d, %d, %d\n", header2.data_window.min_x,
  115. header2.data_window.min_y, header2.data_window.max_x, header2.data_window.max_y);
  116. #endif
  117. REQUIRE(header1.compression_type == header2.compression_type);
  118. REQUIRE(header1.num_channels == header2.num_channels);
  119. REQUIRE(GetWidth(header1.data_window) == GetWidth(header2.data_window));
  120. REQUIRE(GetHeight(header1.data_window) == GetHeight(header2.data_window));
  121. //REQUIRE(header1.display_window == header2.display_window);
  122. //REQUIRE(header1.screen_window_width == header2.screen_window_width);
  123. //REQUIRE(header1.pixel_aspect_ratio == header2.pixel_aspect_ratio);
  124. REQUIRE(header1.tiled == header2.tiled);
  125. REQUIRE(header1.tile_size_x == header2.tile_size_x);
  126. REQUIRE(header1.tile_size_y == header2.tile_size_y);
  127. REQUIRE(header1.tile_level_mode == header2.tile_level_mode);
  128. REQUIRE(header1.tile_rounding_mode == header2.tile_rounding_mode);
  129. REQUIRE(header1.non_image == header2.non_image);
  130. REQUIRE(0 == strcmp(header1.name, header2.name));
  131. for (int c = 0; c < header1.num_channels; c++)
  132. {
  133. REQUIRE(header1.pixel_types[c] == header2.pixel_types[c]); // assume no conversion
  134. REQUIRE(0 == strcmp(header1.channels[c].name, header2.channels[c].name));
  135. REQUIRE(header1.channels[c].pixel_type == header2.pixel_types[c]);
  136. //REQUIRE(header1.channels[c].p_linear == header2.channels[c].p_linear);
  137. //REQUIRE(header1.channels[c].x_sampling == header2.channels[c].x_sampling);
  138. //REQUIRE(header1.channels[c].y_sampling == header2.channels[c].y_sampling);
  139. }
  140. }
  141. static void CompareImages(const EXRImage& image1, const EXRImage& image2)
  142. {
  143. bool tiles_ok = image1.tiles && image2.tiles || image1.tiles == NULL && image2.tiles == NULL;
  144. REQUIRE(true == tiles_ok);
  145. bool images_ok = image1.images && image2.images || image1.images == NULL && image2.images == NULL;
  146. REQUIRE(true == images_ok);
  147. REQUIRE(image1.num_channels == image2.num_channels);
  148. const EXRImage* level_image1 = &image1;
  149. const EXRImage* level_image2 = &image2;
  150. while(level_image1 && level_image2)
  151. {
  152. REQUIRE(level_image1->level_x == level_image2->level_x);
  153. REQUIRE(level_image1->level_y == level_image2->level_y);
  154. REQUIRE(level_image1->width == level_image2->width);
  155. REQUIRE(level_image1->height == level_image2->height);
  156. REQUIRE(level_image1->num_tiles == level_image2->num_tiles);
  157. level_image1 = level_image1->next_level;
  158. level_image2 = level_image2->next_level;
  159. bool levels_ok = level_image1 && level_image2 || level_image1 == NULL && level_image2 == NULL;
  160. REQUIRE(true == levels_ok);
  161. }
  162. }
  163. TEST_CASE("asakusa", "[Load]") {
  164. EXRVersion exr_version;
  165. EXRImage exr_image;
  166. InitEXRImage(&exr_image);
  167. EXRHeader exr_header;
  168. InitEXRHeader(&exr_header);
  169. const char* err = NULL;
  170. int ret = ParseEXRVersionFromFile(&exr_version, "../../asakusa.exr");
  171. REQUIRE(TINYEXR_SUCCESS == ret);
  172. ret = ParseEXRHeaderFromFile(&exr_header, &exr_version, "../../asakusa.exr",
  173. &err);
  174. REQUIRE(NULL == err);
  175. REQUIRE(TINYEXR_SUCCESS == ret);
  176. FreeEXRImage(&exr_image);
  177. FreeEXRHeader(&exr_header);
  178. }
  179. TEST_CASE("utf8filename", "[Load]") {
  180. EXRVersion exr_version;
  181. EXRHeader exr_header;
  182. InitEXRHeader(&exr_header);
  183. const char* err = NULL;
  184. #ifdef _WIN32
  185. #if defined(_MSC_VER)
  186. // Include UTF-16LE encoded string
  187. const wchar_t* wfilename =
  188. #include "win32-filelist-utf16le.inc"
  189. ;
  190. // convert to char*
  191. // https://stackoverflow.com/questions/12637779/how-to-convert-const-wchar-to-const-char/12637971
  192. FILE* fp;
  193. errno_t errcode = _wfopen_s(&fp, wfilename, L"rb");
  194. REQUIRE(0 == errcode);
  195. char filename[1024];
  196. int charlen = 1000;
  197. int strlen = WideCharToMultiByte(65001 /* UTF8 */, 0, wfilename, -1, filename,
  198. (int)charlen, NULL, NULL);
  199. REQUIRE(strlen == 27);
  200. #else
  201. // MinGW or clang.
  202. // At least clang cannot feed UTF-16LE source code, so provide UTF-8 encoded
  203. // file path
  204. const char* utf8filename =
  205. #include "win32-filelist-utf8.inc"
  206. ;
  207. // to wchar_t
  208. const std::wstring wfilename = UTF8_to_wchar(utf8filename);
  209. FILE* fp;
  210. errno_t errcode = _wfopen_s(&fp, wfilename.c_str(), L"rb");
  211. REQUIRE(0 == errcode);
  212. char filename[1024];
  213. int charlen = 1000;
  214. // wchar_t to multibyte char
  215. int strlen = WideCharToMultiByte(65001 /* UTF8 */, 0, wfilename.c_str(), -1,
  216. filename, (int)charlen, NULL, NULL);
  217. REQUIRE(strlen == 27);
  218. #endif
  219. #else
  220. // Assume this source code is compiled with UTF-8(UNICODE)
  221. const char* filename = "./regression/日本語.exr";
  222. #endif
  223. int ret = ParseEXRVersionFromFile(&exr_version, filename);
  224. REQUIRE(TINYEXR_SUCCESS == ret);
  225. ret = ParseEXRHeaderFromFile(&exr_header, &exr_version, filename, &err);
  226. REQUIRE(NULL == err);
  227. REQUIRE(TINYEXR_SUCCESS == ret);
  228. FreeEXRHeader(&exr_header);
  229. }
  230. TEST_CASE("ScanLines", "[Load]") {
  231. std::vector<std::string> inputs;
  232. inputs.push_back("ScanLines/Blobbies.exr");
  233. inputs.push_back("ScanLines/CandleGlass.exr");
  234. // inputs.push_back("ScanLines/Cannon.exr"); // Cannon.exr will fail since it
  235. // uses b44 compression which is not yet supported on TinyEXR.
  236. inputs.push_back("ScanLines/Desk.exr");
  237. inputs.push_back("ScanLines/MtTamWest.exr");
  238. inputs.push_back("ScanLines/PrismsLenses.exr");
  239. inputs.push_back("ScanLines/StillLife.exr");
  240. inputs.push_back("ScanLines/Tree.exr");
  241. for (size_t i = 0; i < inputs.size(); i++) {
  242. EXRVersion exr_version;
  243. std::string filepath = GetPath(inputs[i].c_str());
  244. std::cout << "Loading" << filepath << std::endl;
  245. int ret = ParseEXRVersionFromFile(&exr_version, filepath.c_str());
  246. REQUIRE(TINYEXR_SUCCESS == ret);
  247. REQUIRE(false == exr_version.tiled);
  248. REQUIRE(false == exr_version.non_image);
  249. REQUIRE(false == exr_version.multipart);
  250. EXRVersion version;
  251. EXRHeader header;
  252. EXRImage image;
  253. InitEXRHeader(&header);
  254. InitEXRImage(&image);
  255. const char* err;
  256. ret = ParseEXRHeaderFromFile(&header, &exr_version, filepath.c_str(), &err);
  257. REQUIRE(TINYEXR_SUCCESS == ret);
  258. ret = LoadEXRImageFromFile(&image, &header, filepath.c_str(), &err);
  259. REQUIRE(TINYEXR_SUCCESS == ret);
  260. FreeEXRHeader(&header);
  261. FreeEXRImage(&image);
  262. }
  263. }
  264. TEST_CASE("Chromaticities", "[Load]") {
  265. std::vector<std::string> inputs;
  266. inputs.push_back("Chromaticities/Rec709.exr");
  267. inputs.push_back("Chromaticities/Rec709_YC.exr");
  268. inputs.push_back("Chromaticities/XYZ.exr");
  269. inputs.push_back("Chromaticities/XYZ_YC.exr");
  270. for (size_t i = 0; i < inputs.size(); i++) {
  271. EXRVersion exr_version;
  272. std::string filepath = GetPath(inputs[i].c_str());
  273. std::cout << "Loading" << filepath << std::endl;
  274. int ret = ParseEXRVersionFromFile(&exr_version, filepath.c_str());
  275. REQUIRE(TINYEXR_SUCCESS == ret);
  276. REQUIRE(false == exr_version.tiled);
  277. REQUIRE(false == exr_version.non_image);
  278. REQUIRE(false == exr_version.multipart);
  279. EXRVersion version;
  280. EXRHeader header;
  281. EXRImage image;
  282. InitEXRHeader(&header);
  283. InitEXRImage(&image);
  284. const char* err;
  285. ret = ParseEXRHeaderFromFile(&header, &exr_version, filepath.c_str(), &err);
  286. REQUIRE(TINYEXR_SUCCESS == ret);
  287. ret = LoadEXRImageFromFile(&image, &header, filepath.c_str(), &err);
  288. REQUIRE(TINYEXR_SUCCESS == ret);
  289. FreeEXRHeader(&header);
  290. FreeEXRImage(&image);
  291. }
  292. }
  293. TEST_CASE("TestImages", "[Load]") {
  294. std::vector<std::string> inputs;
  295. inputs.push_back("TestImages/AllHalfValues.exr");
  296. inputs.push_back("TestImages/BrightRings.exr");
  297. inputs.push_back("TestImages/BrightRingsNanInf.exr");
  298. // inputs.push_back("TestImages/GammaChart.exr"); // disable since this uses
  299. // pxr24 compression
  300. // inputs.push_back("TestImages/GrayRampsDiagonal.exr"); // pxr24
  301. // inputs.push_back("TestImages/GrayRampsHorizontal.exr"); // pxr24
  302. // inputs.push_back("TestImages/RgbRampsDiagonal.exr"); // pxr24
  303. // inputs.push_back("TestImages/SquaresSwirls.exr"); // pxr24
  304. inputs.push_back("TestImages/WideColorGamut.exr");
  305. // inputs.push_back("TestImages/WideFloatRange.exr"); // pxr24
  306. for (size_t i = 0; i < inputs.size(); i++) {
  307. EXRVersion exr_version;
  308. std::string filepath = GetPath(inputs[i].c_str());
  309. std::cout << "Loading" << filepath << std::endl;
  310. int ret = ParseEXRVersionFromFile(&exr_version, filepath.c_str());
  311. REQUIRE(TINYEXR_SUCCESS == ret);
  312. REQUIRE(false == exr_version.tiled);
  313. REQUIRE(false == exr_version.non_image);
  314. REQUIRE(false == exr_version.multipart);
  315. EXRVersion version;
  316. EXRHeader header;
  317. EXRImage image;
  318. InitEXRHeader(&header);
  319. InitEXRImage(&image);
  320. const char* err;
  321. ret = ParseEXRHeaderFromFile(&header, &exr_version, filepath.c_str(), &err);
  322. REQUIRE(TINYEXR_SUCCESS == ret);
  323. ret = LoadEXRImageFromFile(&image, &header, filepath.c_str(), &err);
  324. REQUIRE(TINYEXR_SUCCESS == ret);
  325. FreeEXRHeader(&header);
  326. FreeEXRImage(&image);
  327. }
  328. }
  329. TEST_CASE("LuminanceChroma", "[Load]") {
  330. std::vector<std::string> inputs;
  331. // inputs.push_back("LuminanceChroma/CrissyField.exr"); // b44
  332. // inputs.push_back("LuminanceChroma/Flowers.exr"); // b44
  333. // inputs.push_back("LuminanceChroma/Garden.exr"); // tiled
  334. inputs.push_back("LuminanceChroma/MtTamNorth.exr");
  335. inputs.push_back("LuminanceChroma/StarField.exr");
  336. for (size_t i = 0; i < inputs.size(); i++) {
  337. EXRVersion exr_version;
  338. std::string filepath = GetPath(inputs[i].c_str());
  339. std::cout << "Loading" << filepath << std::endl;
  340. int ret = ParseEXRVersionFromFile(&exr_version, filepath.c_str());
  341. REQUIRE(TINYEXR_SUCCESS == ret);
  342. REQUIRE(false == exr_version.tiled);
  343. REQUIRE(false == exr_version.non_image);
  344. REQUIRE(false == exr_version.multipart);
  345. EXRVersion version;
  346. EXRHeader header;
  347. EXRImage image;
  348. InitEXRHeader(&header);
  349. InitEXRImage(&image);
  350. const char* err;
  351. ret = ParseEXRHeaderFromFile(&header, &exr_version, filepath.c_str(), &err);
  352. REQUIRE(TINYEXR_SUCCESS == ret);
  353. ret = LoadEXRImageFromFile(&image, &header, filepath.c_str(), &err);
  354. REQUIRE(TINYEXR_SUCCESS == ret);
  355. FreeEXRHeader(&header);
  356. FreeEXRImage(&image);
  357. }
  358. }
  359. TEST_CASE("DisplayWindow", "[Load]") {
  360. std::vector<std::string> inputs;
  361. inputs.push_back("DisplayWindow/t01.exr");
  362. inputs.push_back("DisplayWindow/t02.exr");
  363. inputs.push_back("DisplayWindow/t03.exr");
  364. inputs.push_back("DisplayWindow/t04.exr");
  365. inputs.push_back("DisplayWindow/t05.exr");
  366. inputs.push_back("DisplayWindow/t06.exr");
  367. inputs.push_back("DisplayWindow/t07.exr");
  368. inputs.push_back("DisplayWindow/t08.exr");
  369. inputs.push_back("DisplayWindow/t09.exr");
  370. inputs.push_back("DisplayWindow/t10.exr");
  371. inputs.push_back("DisplayWindow/t11.exr");
  372. inputs.push_back("DisplayWindow/t12.exr");
  373. inputs.push_back("DisplayWindow/t13.exr");
  374. inputs.push_back("DisplayWindow/t14.exr");
  375. inputs.push_back("DisplayWindow/t15.exr");
  376. inputs.push_back("DisplayWindow/t16.exr");
  377. for (size_t i = 0; i < inputs.size(); i++) {
  378. EXRVersion exr_version;
  379. std::string filepath = GetPath(inputs[i].c_str());
  380. std::cout << "Loading" << filepath << std::endl;
  381. int ret = ParseEXRVersionFromFile(&exr_version, filepath.c_str());
  382. REQUIRE(TINYEXR_SUCCESS == ret);
  383. REQUIRE(false == exr_version.tiled);
  384. REQUIRE(false == exr_version.non_image);
  385. REQUIRE(false == exr_version.multipart);
  386. EXRVersion version;
  387. EXRHeader header;
  388. EXRImage image;
  389. InitEXRHeader(&header);
  390. InitEXRImage(&image);
  391. const char* err;
  392. ret = ParseEXRHeaderFromFile(&header, &exr_version, filepath.c_str(), &err);
  393. REQUIRE(TINYEXR_SUCCESS == ret);
  394. ret = LoadEXRImageFromFile(&image, &header, filepath.c_str(), &err);
  395. REQUIRE(TINYEXR_SUCCESS == ret);
  396. FreeEXRHeader(&header);
  397. FreeEXRImage(&image);
  398. }
  399. }
  400. TEST_CASE("Tiles/GoldenGate.exr", "[Version]") {
  401. EXRVersion exr_version;
  402. std::string filepath = GetPath("Tiles/GoldenGate.exr");
  403. int ret = ParseEXRVersionFromFile(&exr_version, filepath.c_str());
  404. REQUIRE(TINYEXR_SUCCESS == ret);
  405. REQUIRE(true == exr_version.tiled);
  406. }
  407. TEST_CASE("Tiles/GoldenGate.exr|Load", "[Load]") {
  408. EXRVersion exr_version;
  409. std::string filepath = GetPath("Tiles/GoldenGate.exr");
  410. int ret = ParseEXRVersionFromFile(&exr_version, filepath.c_str());
  411. REQUIRE(TINYEXR_SUCCESS == ret);
  412. REQUIRE(true == exr_version.tiled);
  413. REQUIRE(false == exr_version.non_image);
  414. REQUIRE(false == exr_version.multipart);
  415. EXRVersion version;
  416. EXRHeader header;
  417. EXRImage image;
  418. InitEXRHeader(&header);
  419. InitEXRImage(&image);
  420. const char* err;
  421. ret = ParseEXRHeaderFromFile(&header, &exr_version, filepath.c_str(), &err);
  422. REQUIRE(TINYEXR_SUCCESS == ret);
  423. REQUIRE(1 == header.tiled);
  424. REQUIRE(TINYEXR_TILE_ONE_LEVEL == header.tile_level_mode);
  425. REQUIRE(128 == header.tile_size_x);
  426. REQUIRE(128 == header.tile_size_y);
  427. ret = LoadEXRImageFromFile(&image, &header, filepath.c_str(), &err);
  428. REQUIRE(TINYEXR_SUCCESS == ret);
  429. REQUIRE(NULL != image.tiles);
  430. REQUIRE(0 == image.level_x);
  431. REQUIRE(0 == image.level_y);
  432. REQUIRE(1 == EXRNumLevels(&image));
  433. FreeEXRHeader(&header);
  434. FreeEXRImage(&image);
  435. }
  436. TEST_CASE("LuminanceChroma/Garden.exr|Load", "[Load]") {
  437. EXRVersion exr_version;
  438. std::string filepath = GetPath("LuminanceChroma/Garden.exr");
  439. int ret = ParseEXRVersionFromFile(&exr_version, filepath.c_str());
  440. REQUIRE(TINYEXR_SUCCESS == ret);
  441. REQUIRE(true == exr_version.tiled);
  442. REQUIRE(false == exr_version.non_image);
  443. REQUIRE(false == exr_version.multipart);
  444. EXRVersion version;
  445. EXRHeader header;
  446. EXRImage image;
  447. InitEXRHeader(&header);
  448. InitEXRImage(&image);
  449. const char* err;
  450. ret = ParseEXRHeaderFromFile(&header, &exr_version, filepath.c_str(), &err);
  451. REQUIRE(TINYEXR_SUCCESS == ret);
  452. ret = LoadEXRImageFromFile(&image, &header, filepath.c_str(), &err);
  453. REQUIRE(TINYEXR_SUCCESS == ret);
  454. FreeEXRHeader(&header);
  455. FreeEXRImage(&image);
  456. }
  457. TEST_CASE("Tiles/Ocean.exr", "[Load]") {
  458. EXRVersion exr_version;
  459. std::string filepath = GetPath("Tiles/Ocean.exr");
  460. int ret = ParseEXRVersionFromFile(&exr_version, filepath.c_str());
  461. REQUIRE(TINYEXR_SUCCESS == ret);
  462. REQUIRE(true == exr_version.tiled);
  463. REQUIRE(false == exr_version.non_image);
  464. REQUIRE(false == exr_version.multipart);
  465. EXRVersion version;
  466. EXRHeader header;
  467. EXRImage image;
  468. InitEXRHeader(&header);
  469. InitEXRImage(&image);
  470. const char* err;
  471. ret = ParseEXRHeaderFromFile(&header, &exr_version, filepath.c_str(), &err);
  472. REQUIRE(TINYEXR_SUCCESS == ret);
  473. ret = LoadEXRImageFromFile(&image, &header, filepath.c_str(), &err);
  474. REQUIRE(TINYEXR_SUCCESS == ret);
  475. FreeEXRHeader(&header);
  476. FreeEXRImage(&image);
  477. }
  478. TEST_CASE("MultiResolution/Bonita.exr", "[Load]") {
  479. EXRVersion exr_version;
  480. std::string filepath = GetPath("MultiResolution/Bonita.exr");
  481. std::cout << "Loading" << filepath << std::endl;
  482. int ret = ParseEXRVersionFromFile(&exr_version, filepath.c_str());
  483. REQUIRE(TINYEXR_SUCCESS == ret);
  484. REQUIRE(true == exr_version.tiled);
  485. REQUIRE(false == exr_version.non_image);
  486. REQUIRE(false == exr_version.multipart);
  487. EXRVersion version;
  488. EXRHeader header;
  489. EXRImage image;
  490. InitEXRHeader(&header);
  491. InitEXRImage(&image);
  492. const char* err;
  493. ret = ParseEXRHeaderFromFile(&header, &exr_version, filepath.c_str(), &err);
  494. REQUIRE(TINYEXR_SUCCESS == ret);
  495. REQUIRE(1 == header.tiled);
  496. REQUIRE(TINYEXR_TILE_MIPMAP_LEVELS == header.tile_level_mode);
  497. REQUIRE(TINYEXR_TILE_ROUND_DOWN == header.tile_rounding_mode);
  498. ret = LoadEXRImageFromFile(&image, &header, filepath.c_str(), &err);
  499. REQUIRE(TINYEXR_SUCCESS == ret);
  500. REQUIRE(10 == EXRNumLevels(&image));
  501. FreeEXRHeader(&header);
  502. FreeEXRImage(&image);
  503. }
  504. TEST_CASE("MultiResolution/Kapaa.exr", "[Load]") {
  505. EXRVersion exr_version;
  506. std::string filepath = GetPath("MultiResolution/Kapaa.exr");
  507. std::cout << "Loading" << filepath << std::endl;
  508. int ret = ParseEXRVersionFromFile(&exr_version, filepath.c_str());
  509. REQUIRE(TINYEXR_SUCCESS == ret);
  510. REQUIRE(true == exr_version.tiled);
  511. REQUIRE(false == exr_version.non_image);
  512. REQUIRE(false == exr_version.multipart);
  513. EXRVersion version;
  514. EXRHeader header;
  515. EXRImage image;
  516. InitEXRHeader(&header);
  517. InitEXRImage(&image);
  518. const char* err;
  519. ret = ParseEXRHeaderFromFile(&header, &exr_version, filepath.c_str(), &err);
  520. REQUIRE(TINYEXR_SUCCESS == ret);
  521. REQUIRE(1 == header.tiled);
  522. REQUIRE(TINYEXR_TILE_RIPMAP_LEVELS == header.tile_level_mode);
  523. REQUIRE(TINYEXR_TILE_ROUND_UP == header.tile_rounding_mode);
  524. REQUIRE(64 == header.tile_size_x);
  525. REQUIRE(64 == header.tile_size_y);
  526. ret = LoadEXRImageFromFile(&image, &header, filepath.c_str(), &err);
  527. REQUIRE(TINYEXR_SUCCESS == ret);
  528. REQUIRE(11*11 == EXRNumLevels(&image));
  529. FreeEXRHeader(&header);
  530. FreeEXRImage(&image);
  531. }
  532. TEST_CASE("Saving ScanLines", "[Save]") {
  533. std::vector<std::string> inputs;
  534. inputs.push_back("ScanLines/Blobbies.exr");
  535. inputs.push_back("ScanLines/CandleGlass.exr");
  536. // inputs.push_back("ScanLines/Cannon.exr"); // Cannon.exr will fail since it
  537. // uses b44 compression which is not yet supported on TinyEXR.
  538. inputs.push_back("ScanLines/Desk.exr");
  539. inputs.push_back("ScanLines/MtTamWest.exr");
  540. inputs.push_back("ScanLines/PrismsLenses.exr");
  541. inputs.push_back("ScanLines/StillLife.exr");
  542. inputs.push_back("ScanLines/Tree.exr");
  543. for (size_t i = 0; i < inputs.size(); i++) {
  544. std::string filepath = GetPath(inputs[i].c_str());
  545. std::cout << "Input:" << filepath << std::endl;
  546. EXRVersion version1;
  547. int ret = ParseEXRVersionFromFile(&version1, filepath.c_str());
  548. REQUIRE(TINYEXR_SUCCESS == ret);
  549. EXRHeader header1;
  550. EXRImage image1;
  551. unsigned char *data = NULL;
  552. size_t data_size;
  553. // loading from file
  554. {
  555. InitEXRHeader(&header1);
  556. InitEXRImage(&image1);
  557. const char* err;
  558. ret = ParseEXRHeaderFromFile(&header1, &version1, filepath.c_str(), &err);
  559. REQUIRE(TINYEXR_SUCCESS == ret);
  560. ret = LoadEXRImageFromFile(&image1, &header1, filepath.c_str(), &err);
  561. REQUIRE(TINYEXR_SUCCESS == ret);
  562. }
  563. // saving to memory
  564. {
  565. const char* err = NULL;
  566. data_size = SaveEXRImageToMemory(&image1, &header1, &data, &err);
  567. REQUIRE(0 != data_size);
  568. //FreeEXRHeader(&header);
  569. #ifdef DUMP_IMAGES
  570. bool ret = WriteMemoryToFile(GetDumpPath(inputs[i].c_str()).c_str(), data, data_size);
  571. REQUIRE(true == ret);
  572. #endif
  573. }
  574. // loading back from memory
  575. {
  576. EXRVersion version2;
  577. {
  578. int ret = ParseEXRVersionFromMemory(&version2, data, data_size);
  579. REQUIRE(0 == ret);
  580. }
  581. EXRHeader header2;
  582. {
  583. const char* err = NULL;
  584. InitEXRHeader(&header2);
  585. int ret = ParseEXRHeaderFromMemory(&header2, &version2, data, data_size, &err);
  586. REQUIRE(0 == ret);
  587. }
  588. EXRImage image2;
  589. {
  590. const char* err = NULL;
  591. InitEXRImage(&image2);
  592. int ret = LoadEXRImageFromMemory(&image2, &header2, data, data_size, &err);
  593. REQUIRE(TINYEXR_SUCCESS == ret);
  594. free(data);
  595. }
  596. CompareHeaders(header1, header2);
  597. CompareImages(image1, image2);
  598. FreeEXRImage(&image2);
  599. FreeEXRHeader(&header2);
  600. }
  601. FreeEXRHeader(&header1);
  602. FreeEXRImage(&image1);
  603. }
  604. }
  605. TEST_CASE("Saving MultiResolution", "[Save]") {
  606. //std::string filepath = GetPath("MultiResolution/Bonita.exr");
  607. //std::cout << "Load-save-reload:" << filepath << std::endl;
  608. std::vector<std::string> inputs;
  609. inputs.push_back("MultiResolution/Bonita.exr");
  610. inputs.push_back("MultiResolution/Kapaa.exr");
  611. for (size_t i = 0; i < inputs.size(); i++) {
  612. std::string filepath = GetPath(inputs[i].c_str());
  613. std::cout << "Input:" << filepath << std::endl;
  614. EXRVersion version1;
  615. int ret = ParseEXRVersionFromFile(&version1, filepath.c_str());
  616. REQUIRE(TINYEXR_SUCCESS == ret);
  617. EXRHeader header1;
  618. EXRImage image1;
  619. unsigned char *data = NULL;
  620. size_t data_size;
  621. // loading from file
  622. {
  623. InitEXRHeader(&header1);
  624. InitEXRImage(&image1);
  625. const char* err;
  626. ret = ParseEXRHeaderFromFile(&header1, &version1, filepath.c_str(), &err);
  627. REQUIRE(TINYEXR_SUCCESS == ret);
  628. ret = LoadEXRImageFromFile(&image1, &header1, filepath.c_str(), &err);
  629. REQUIRE(TINYEXR_SUCCESS == ret);
  630. }
  631. // saving to memory
  632. {
  633. const char* err = NULL;
  634. data_size = SaveEXRImageToMemory(&image1, &header1, &data, &err);
  635. REQUIRE(0 != data_size);
  636. #ifdef DUMP_IMAGES
  637. bool ret = WriteMemoryToFile(GetDumpPath(inputs[i].c_str()).c_str(), data, data_size);
  638. REQUIRE(true == ret);
  639. #endif
  640. }
  641. // loading back from memory
  642. {
  643. EXRVersion version2;
  644. {
  645. int ret = ParseEXRVersionFromMemory(&version2, data, data_size);
  646. REQUIRE(0 == ret);
  647. }
  648. EXRHeader header2;
  649. {
  650. const char* err = NULL;
  651. InitEXRHeader(&header2);
  652. int ret = ParseEXRHeaderFromMemory(&header2, &version2, data, data_size, &err);
  653. REQUIRE(0 == ret);
  654. }
  655. EXRImage image2;
  656. {
  657. const char* err = NULL;
  658. InitEXRImage(&image2);
  659. int ret = LoadEXRImageFromMemory(&image2, &header2, data, data_size, &err);
  660. REQUIRE(TINYEXR_SUCCESS == ret);
  661. free(data);
  662. }
  663. CompareHeaders(header1, header2);
  664. CompareImages(image1, image2);
  665. FreeEXRImage(&image2);
  666. FreeEXRHeader(&header2);
  667. }
  668. FreeEXRHeader(&header1);
  669. FreeEXRImage(&image1);
  670. }
  671. }
  672. TEST_CASE("Saving multipart", "[Save]") {
  673. std::vector<std::string> inputs;
  674. inputs.push_back("Beachball/multipart.0001.exr");
  675. for (size_t i = 0; i < inputs.size(); i++) {
  676. std::string filepath = GetPath(inputs[i].c_str());
  677. std::cout << "Input:" << filepath << std::endl;
  678. EXRVersion version1;
  679. {
  680. int ret = ParseEXRVersionFromFile(&version1, filepath.c_str());
  681. REQUIRE(TINYEXR_SUCCESS == ret);
  682. REQUIRE(true == version1.multipart);
  683. }
  684. EXRHeader** headers1; // list of EXRHeader pointers.
  685. int num_headers1;
  686. {
  687. const char* err = NULL;
  688. int ret = ParseEXRMultipartHeaderFromFile(&headers1, &num_headers1,
  689. &version1, filepath.c_str(), &err);
  690. REQUIRE(TINYEXR_SUCCESS == ret);
  691. }
  692. unsigned char *data = NULL;
  693. size_t data_size;
  694. std::vector<EXRImage> images1(num_headers1);
  695. // loading from file
  696. {
  697. const char* err = NULL;
  698. for (int j = 0; j < num_headers1; j++) {
  699. InitEXRImage(&images1[j]);
  700. }
  701. int ret = LoadEXRMultipartImageFromFile(&images1[0], const_cast<const EXRHeader**>(headers1),
  702. static_cast<unsigned int>(num_headers1), filepath.c_str(), &err);
  703. REQUIRE(TINYEXR_SUCCESS == ret);
  704. }
  705. // saving to memory
  706. {
  707. const char* err = NULL;
  708. data_size = SaveEXRMultipartImageToMemory(&images1[0],
  709. const_cast<const EXRHeader**>(headers1), static_cast<unsigned int>(num_headers1), &data, &err);
  710. REQUIRE(0 != data_size);
  711. #ifdef DUMP_IMAGES
  712. bool ret = WriteMemoryToFile(GetDumpPath(inputs[i].c_str()).c_str(), data, data_size);
  713. REQUIRE(true == ret);
  714. #endif
  715. }
  716. // loading back from memory
  717. {
  718. EXRVersion version2;
  719. {
  720. int ret = ParseEXRVersionFromMemory(&version2, data, data_size);
  721. REQUIRE(TINYEXR_SUCCESS == ret);
  722. REQUIRE(true == version2.multipart);
  723. }
  724. EXRHeader** headers2;
  725. int num_headers2;
  726. {
  727. const char* err = NULL;
  728. int ret = ParseEXRMultipartHeaderFromMemory(&headers2, &num_headers2, &version2,
  729. data, data_size, &err);
  730. REQUIRE(TINYEXR_SUCCESS == ret);
  731. }
  732. REQUIRE(num_headers1 == num_headers2);
  733. std::vector<EXRImage> images2(num_headers2);
  734. {
  735. for (int j = 0; j < num_headers2; j++) {
  736. InitEXRImage(&images2[j]);
  737. }
  738. const char* err = NULL;
  739. int ret = LoadEXRMultipartImageFromMemory(&images2[0], const_cast<const EXRHeader**>(headers2),
  740. static_cast<unsigned int>(num_headers2),
  741. data, data_size, &err);
  742. REQUIRE(TINYEXR_SUCCESS == ret);
  743. free(data);
  744. }
  745. for (int j = 0; j < num_headers2; j++) {
  746. CompareHeaders(*headers1[j], *headers2[j]);
  747. }
  748. for (int j = 0; j < num_headers2; j++) {
  749. CompareImages(images1[j], images2[j]);
  750. }
  751. for (int j = 0; j < num_headers2; j++) {
  752. FreeEXRImage(&images2[j]);
  753. FreeEXRHeader(headers2[j]);
  754. free(headers2[j]);
  755. }
  756. free(headers2);
  757. }
  758. for (int j = 0; j < num_headers1; j++) {
  759. FreeEXRImage(&images1[j]);
  760. FreeEXRHeader(headers1[j]);
  761. free(headers1[j]);
  762. }
  763. free(headers1);
  764. }
  765. }
  766. TEST_CASE("Saving multipart|Combine", "[Save]") {
  767. std::vector<std::string> inputs;
  768. inputs.push_back("MultiResolution/Kapaa.exr"); // tiled, ripmap
  769. inputs.push_back("Tiles/GoldenGate.exr"); // tiled, one level
  770. inputs.push_back("ScanLines/Desk.exr"); // scanline
  771. inputs.push_back("MultiResolution/PeriodicPattern.exr"); // tiled, mipmap
  772. const char* dstName = "multipart.collection.exr";
  773. unsigned num_headers1 = inputs.size();
  774. std::vector<EXRHeader> headers1(num_headers1);
  775. std::vector<EXRImage> images1(num_headers1);
  776. // collecting images
  777. for (size_t i = 0; i < num_headers1; i++) {
  778. std::string filepath = GetPath(inputs[i].c_str());
  779. std::cout << "Input:" << filepath << std::endl;
  780. EXRVersion version1;
  781. {
  782. int ret = ParseEXRVersionFromFile(&version1, filepath.c_str());
  783. REQUIRE(TINYEXR_SUCCESS == ret);
  784. REQUIRE(false == version1.multipart);
  785. }
  786. {
  787. InitEXRHeader(&headers1[i]);
  788. const char* err = NULL;
  789. int ret = ParseEXRHeaderFromFile(&headers1[i], &version1, filepath.c_str(), &err);
  790. REQUIRE(TINYEXR_SUCCESS == ret);
  791. }
  792. {
  793. InitEXRImage(&images1[i]);
  794. const char* err = NULL;
  795. int ret = LoadEXRImageFromFile(&images1[i], &headers1[i], filepath.c_str(), &err);
  796. REQUIRE(TINYEXR_SUCCESS == ret);
  797. }
  798. }
  799. unsigned char *data = NULL;
  800. size_t data_size;
  801. // saving collection to memory as multipart
  802. {
  803. std::vector<EXRHeader*> pheaders1(num_headers1);
  804. for(unsigned i = 0; i < num_headers1; ++i) pheaders1[i] = &headers1[i];
  805. for (size_t i = 0; i < num_headers1; i++) {
  806. EXRSetNameAttr(pheaders1[i], inputs[i].c_str());
  807. }
  808. const char* err = NULL;
  809. data_size = SaveEXRMultipartImageToMemory(&images1[0],
  810. const_cast<const EXRHeader**>(&pheaders1[0]),
  811. static_cast<unsigned int>(num_headers1),
  812. &data, &err);
  813. REQUIRE(0 != data_size);
  814. #ifdef DUMP_IMAGES
  815. bool ret = WriteMemoryToFile(GetDumpPath(dstName).c_str(), data, data_size);
  816. REQUIRE(true == ret);
  817. #endif
  818. }
  819. // loading back from memory
  820. {
  821. EXRVersion version2;
  822. {
  823. int ret = ParseEXRVersionFromMemory(&version2, data, data_size);
  824. REQUIRE(TINYEXR_SUCCESS == ret);
  825. REQUIRE(true == version2.multipart);
  826. }
  827. EXRHeader** headers2;
  828. int num_headers2;
  829. {
  830. const char* err = NULL;
  831. int ret = ParseEXRMultipartHeaderFromMemory(&headers2, &num_headers2, &version2,
  832. data, data_size, &err);
  833. REQUIRE(TINYEXR_SUCCESS == ret);
  834. }
  835. REQUIRE(num_headers1 == num_headers2);
  836. std::vector<EXRImage> images2(num_headers2);
  837. {
  838. for (int j = 0; j < num_headers2; j++) {
  839. InitEXRImage(&images2[j]);
  840. }
  841. const char* err = NULL;
  842. int ret = LoadEXRMultipartImageFromMemory(&images2[0], const_cast<const EXRHeader**>(headers2),
  843. static_cast<unsigned int>(num_headers2),
  844. data, data_size, &err);
  845. REQUIRE(TINYEXR_SUCCESS == ret);
  846. free(data);
  847. }
  848. for (int j = 0; j < num_headers2; j++) {
  849. CompareHeaders(headers1[j], *headers2[j]);
  850. }
  851. for (int j = 0; j < num_headers2; j++) {
  852. CompareImages(images1[j], images2[j]);
  853. }
  854. for (int j = 0; j < num_headers2; j++) {
  855. FreeEXRImage(&images2[j]);
  856. FreeEXRHeader(headers2[j]);
  857. free(headers2[j]);
  858. }
  859. free(headers2);
  860. }
  861. for (int i = 0; i < num_headers1; i++) {
  862. FreeEXRImage(&images1[i]);
  863. FreeEXRHeader(&headers1[i]);
  864. }
  865. }
  866. #if 0 // Spirals.exr uses pxr24 compression
  867. TEST_CASE("Tiles/Spirals.exr", "[Load]") {
  868. EXRVersion exr_version;
  869. std::string filepath = GetPath("Tiles/Spirals.exr");
  870. int ret = ParseEXRVersionFromFile(&exr_version, filepath.c_str());
  871. REQUIRE(TINYEXR_SUCCESS == ret);
  872. REQUIRE(true == exr_version.tiled);
  873. REQUIRE(false == exr_version.non_image);
  874. REQUIRE(false == exr_version.multipart);
  875. EXRVersion version;
  876. EXRHeader header;
  877. EXRImage image;
  878. InitEXRHeader(&header);
  879. InitEXRImage(&image);
  880. const char* err;
  881. ret = ParseEXRHeaderFromFile(&header, &exr_version, filepath.c_str(), &err);
  882. REQUIRE(TINYEXR_SUCCESS == ret);
  883. ret= LoadEXRImageFromFile(&image, &header, filepath.c_str(), &err);
  884. REQUIRE(TINYEXR_SUCCESS == ret);
  885. FreeEXRHeader(&header);
  886. FreeEXRImage(&image);
  887. }
  888. #endif
  889. TEST_CASE("Beachball/multipart.0001.exr", "[Version]") {
  890. EXRVersion exr_version;
  891. std::string filepath = GetPath("Beachball/multipart.0001.exr");
  892. int ret = ParseEXRVersionFromFile(&exr_version, filepath.c_str());
  893. REQUIRE(TINYEXR_SUCCESS == ret);
  894. REQUIRE(true == exr_version.multipart);
  895. EXRHeader* headers;
  896. }
  897. TEST_CASE("Beachball/multipart.0001.exr|Load", "[Load]") {
  898. EXRVersion exr_version;
  899. std::string filepath = GetPath("Beachball/multipart.0001.exr");
  900. int ret = ParseEXRVersionFromFile(&exr_version, filepath.c_str());
  901. REQUIRE(TINYEXR_SUCCESS == ret);
  902. REQUIRE(true == exr_version.multipart);
  903. EXRHeader** exr_headers; // list of EXRHeader pointers.
  904. int num_exr_headers;
  905. const char* err;
  906. ret = ParseEXRMultipartHeaderFromFile(&exr_headers, &num_exr_headers,
  907. &exr_version, filepath.c_str(), &err);
  908. REQUIRE(TINYEXR_SUCCESS == ret);
  909. REQUIRE(10 == num_exr_headers);
  910. std::vector<EXRImage> images(static_cast<size_t>(num_exr_headers));
  911. for (int i = 0; i < num_exr_headers; i++) {
  912. InitEXRImage(&images[static_cast<size_t>(i)]);
  913. }
  914. ret = LoadEXRMultipartImageFromFile(
  915. &images.at(0), const_cast<const EXRHeader**>(exr_headers),
  916. static_cast<unsigned int>(num_exr_headers), filepath.c_str(), &err);
  917. REQUIRE(TINYEXR_SUCCESS == ret);
  918. for (int i = 0; i < num_exr_headers; i++) {
  919. FreeEXRImage(&images.at(static_cast<size_t>(i)));
  920. }
  921. for (int i = 0; i < num_exr_headers; i++) {
  922. FreeEXRHeader(exr_headers[static_cast<size_t>(i)]); // free content
  923. free(exr_headers[static_cast<size_t>(i)]); // free pointer
  924. }
  925. free(exr_headers);
  926. }
  927. TEST_CASE("Beachbal multiparts", "[Load]") {
  928. int num = 8;
  929. char buf[1024];
  930. for (int i = 0; i < num + 1; i++) {
  931. sprintf(buf, "Beachball/multipart.%04d.exr", i);
  932. EXRVersion exr_version;
  933. std::string filepath = GetPath(buf);
  934. int ret = ParseEXRVersionFromFile(&exr_version, filepath.c_str());
  935. if (i == 0) { // multipart.0000.exr does not exist.
  936. REQUIRE(TINYEXR_ERROR_CANT_OPEN_FILE == ret);
  937. continue;
  938. }
  939. REQUIRE(TINYEXR_SUCCESS == ret);
  940. REQUIRE(true == exr_version.multipart);
  941. EXRHeader** exr_headers; // list of EXRHeader pointers.
  942. int num_exr_headers;
  943. const char* err;
  944. ret = ParseEXRMultipartHeaderFromFile(&exr_headers, &num_exr_headers,
  945. &exr_version, filepath.c_str(), &err);
  946. REQUIRE(TINYEXR_SUCCESS == ret);
  947. REQUIRE(10 == num_exr_headers);
  948. std::vector<EXRImage> images(static_cast<size_t>(num_exr_headers));
  949. for (int j = 0; j < num_exr_headers; j++) {
  950. InitEXRImage(&images[static_cast<size_t>(j)]);
  951. }
  952. ret = LoadEXRMultipartImageFromFile(
  953. &images.at(0), const_cast<const EXRHeader**>(exr_headers),
  954. static_cast<unsigned int>(num_exr_headers), filepath.c_str(), &err);
  955. REQUIRE(TINYEXR_SUCCESS == ret);
  956. for (int j = 0; j < num_exr_headers; j++) {
  957. FreeEXRImage(&images.at(static_cast<size_t>(j)));
  958. }
  959. for (int j = 0; j < num_exr_headers; j++) {
  960. FreeEXRHeader(exr_headers[static_cast<size_t>(j)]);
  961. free(exr_headers[static_cast<size_t>(j)]);
  962. }
  963. free(exr_headers);
  964. }
  965. }
  966. TEST_CASE("Beachbal singleparts", "[Load]") {
  967. int num = 8;
  968. char buf[1024];
  969. for (int i = 0; i < num + 1; i++) {
  970. sprintf(buf, "Beachball/singlepart.%04d.exr", i);
  971. EXRVersion exr_version;
  972. std::string filepath = GetPath(buf);
  973. int ret = ParseEXRVersionFromFile(&exr_version, filepath.c_str());
  974. if (i == 0) { // multipart.0000.exr does not exist.
  975. REQUIRE(TINYEXR_ERROR_CANT_OPEN_FILE == ret);
  976. continue;
  977. }
  978. REQUIRE(TINYEXR_SUCCESS == ret);
  979. REQUIRE(false == exr_version.tiled);
  980. REQUIRE(false == exr_version.non_image);
  981. REQUIRE(false == exr_version.multipart);
  982. EXRVersion version;
  983. memset(&version, 0, sizeof(EXRVersion));
  984. EXRHeader header;
  985. EXRImage image;
  986. InitEXRHeader(&header);
  987. InitEXRImage(&image);
  988. const char* err;
  989. ret = ParseEXRHeaderFromFile(&header, &exr_version, filepath.c_str(), &err);
  990. REQUIRE(TINYEXR_SUCCESS == ret);
  991. ret = LoadEXRImageFromFile(&image, &header, filepath.c_str(), &err);
  992. REQUIRE(TINYEXR_SUCCESS == ret);
  993. REQUIRE(image.tiles == NULL);
  994. REQUIRE(image.images);
  995. FreeEXRHeader(&header);
  996. FreeEXRImage(&image);
  997. }
  998. }
  999. TEST_CASE("ParseEXRVersionFromMemory invalid input", "[Parse]") {
  1000. int ret = ParseEXRVersionFromMemory(NULL, NULL, 0);
  1001. REQUIRE(ret == TINYEXR_ERROR_INVALID_ARGUMENT);
  1002. {
  1003. EXRVersion version;
  1004. memset(&version, 0, sizeof(EXRVersion));
  1005. ret = ParseEXRVersionFromMemory(&version, NULL, 0);
  1006. REQUIRE(ret == TINYEXR_ERROR_INVALID_ARGUMENT);
  1007. }
  1008. {
  1009. EXRVersion version;
  1010. memset(&version, 0, sizeof(EXRVersion));
  1011. std::vector<unsigned char> buf(128);
  1012. ret = ParseEXRVersionFromMemory(&version, buf.data(), 0);
  1013. REQUIRE(ret == TINYEXR_ERROR_INVALID_DATA);
  1014. }
  1015. {
  1016. EXRVersion version;
  1017. memset(&version, 0, sizeof(EXRVersion));
  1018. std::vector<unsigned char> buf(4);
  1019. ret = ParseEXRVersionFromMemory(
  1020. &version, buf.data(), 1); // size is less than version header size
  1021. REQUIRE(ret == TINYEXR_ERROR_INVALID_DATA);
  1022. }
  1023. {
  1024. EXRVersion version;
  1025. memset(&version, 0, sizeof(EXRVersion));
  1026. std::vector<unsigned char> buf(8, 0); // invalid magic number
  1027. ret = ParseEXRVersionFromMemory(&version, buf.data(), 8);
  1028. REQUIRE(ret == TINYEXR_ERROR_INVALID_MAGIC_NUMBER);
  1029. }
  1030. }
  1031. TEST_CASE("ParseEXRHeaderFromMemory invalid input", "[Parse]") {
  1032. {
  1033. int ret = ParseEXRHeaderFromMemory(NULL, NULL, NULL, 0, NULL);
  1034. REQUIRE(ret == TINYEXR_ERROR_INVALID_ARGUMENT);
  1035. }
  1036. {
  1037. EXRHeader header;
  1038. InitEXRHeader(&header);
  1039. EXRVersion version;
  1040. memset(&version, 0, sizeof(EXRVersion));
  1041. int ret = ParseEXRHeaderFromMemory(&header, &version, NULL, 0, NULL);
  1042. REQUIRE(ret == TINYEXR_ERROR_INVALID_ARGUMENT);
  1043. FreeEXRHeader(&header);
  1044. }
  1045. {
  1046. EXRHeader header;
  1047. InitEXRHeader(&header);
  1048. EXRVersion version;
  1049. memset(&version, 0, sizeof(EXRVersion));
  1050. std::vector<unsigned char> buf(128);
  1051. int ret = ParseEXRHeaderFromMemory(&header, &version, buf.data(), 0, NULL);
  1052. REQUIRE(ret == TINYEXR_ERROR_INVALID_DATA);
  1053. FreeEXRHeader(&header);
  1054. }
  1055. {
  1056. EXRHeader header;
  1057. InitEXRHeader(&header);
  1058. EXRVersion version;
  1059. memset(&version, 0, sizeof(EXRVersion));
  1060. std::vector<unsigned char> buf(128, 0);
  1061. int ret =
  1062. ParseEXRHeaderFromMemory(&header, &version, buf.data(), 128, NULL);
  1063. REQUIRE(ret == TINYEXR_ERROR_INVALID_HEADER);
  1064. FreeEXRHeader(&header);
  1065. }
  1066. }
  1067. TEST_CASE("Compressed is smaller than uncompressed", "[Issue40]") {
  1068. EXRHeader header;
  1069. InitEXRHeader(&header);
  1070. header.compression_type = TINYEXR_COMPRESSIONTYPE_ZIP;
  1071. EXRImage image;
  1072. InitEXRImage(&image);
  1073. image.num_channels = 3;
  1074. float const images[3][1] = {
  1075. {1.0f},
  1076. {0.0f},
  1077. {0.0f},
  1078. };
  1079. float const* const image_ptr[3] = {
  1080. images[2],
  1081. images[1],
  1082. images[0],
  1083. };
  1084. image.images = const_cast<unsigned char**>(reinterpret_cast<const unsigned char*const *>(image_ptr));
  1085. image.width = 1;
  1086. image.height = 1;
  1087. header.num_channels = 3;
  1088. header.channels =
  1089. static_cast<EXRChannelInfo*>(malloc(sizeof(EXRChannelInfo) * static_cast<size_t>(header.num_channels)));
  1090. // Must be BGR(A) order, since most of EXR viewers expect this channel order.
  1091. strncpy(header.channels[0].name, "B", 255);
  1092. header.channels[0].name[strlen("B")] = '\0';
  1093. strncpy(header.channels[1].name, "G", 255);
  1094. header.channels[1].name[strlen("G")] = '\0';
  1095. strncpy(header.channels[2].name, "R", 255);
  1096. header.channels[2].name[strlen("R")] = '\0';
  1097. header.pixel_types = static_cast<int*>(malloc(sizeof(int) * static_cast<size_t>(header.num_channels)));
  1098. header.requested_pixel_types =
  1099. static_cast<int*>(malloc(sizeof(int) * static_cast<size_t>(header.num_channels)));
  1100. for (int i = 0; i < header.num_channels; i++) {
  1101. header.pixel_types[i] =
  1102. TINYEXR_PIXELTYPE_FLOAT; // pixel type of input image
  1103. header.requested_pixel_types[i] =
  1104. TINYEXR_PIXELTYPE_FLOAT; // pixel type of output image to be stored in
  1105. // .EXR
  1106. }
  1107. const char* err;
  1108. int const ret = SaveEXRImageToFile(&image, &header, "issue40.exr", &err);
  1109. REQUIRE(ret == TINYEXR_SUCCESS);
  1110. free(header.channels);
  1111. free(header.requested_pixel_types);
  1112. free(header.pixel_types);
  1113. }
  1114. // TEST_CASE("Regression: Issue54", "[fuzzing]") {
  1115. // EXRVersion exr_version;
  1116. // std::string filepath =
  1117. // "./regression/poc-360c3b0555cb979ca108f2d178cf8a80959cfeabaa4ec1d310d062fa653a8c6b_min";
  1118. // int ret = ParseEXRVersionFromFile(&exr_version, filepath.c_str());
  1119. // REQUIRE(TINYEXR_SUCCESS == ret);
  1120. // REQUIRE(false == exr_version.tiled);
  1121. // REQUIRE(false == exr_version.non_image);
  1122. // REQUIRE(false == exr_version.multipart);
  1123. //
  1124. // EXRVersion version;
  1125. // EXRHeader header;
  1126. // EXRImage image;
  1127. // InitEXRHeader(&header);
  1128. // InitEXRImage(&image);
  1129. //
  1130. // const char* err;
  1131. // ret = ParseEXRHeaderFromFile(&header, &exr_version, filepath.c_str(), &err);
  1132. // REQUIRE(TINYEXR_SUCCESS == ret);
  1133. //
  1134. // ret = LoadEXRImageFromFile(&image, &header, filepath.c_str(), &err);
  1135. // REQUIRE(TINYEXR_SUCCESS == ret);
  1136. //
  1137. // FreeEXRHeader(&header);
  1138. // FreeEXRImage(&image);
  1139. //}
  1140. TEST_CASE("Regression: Issue50", "[fuzzing]") {
  1141. EXRVersion exr_version;
  1142. std::string filepath =
  1143. "./regression/"
  1144. "poc-eedff3a9e99eb1c0fd3a3b0989e7c44c0a69f04f10b23e5264f362a4773f4397_"
  1145. "min";
  1146. int ret = ParseEXRVersionFromFile(&exr_version, filepath.c_str());
  1147. REQUIRE(TINYEXR_SUCCESS == ret);
  1148. REQUIRE(false == exr_version.tiled);
  1149. REQUIRE(false == exr_version.non_image);
  1150. REQUIRE(false == exr_version.multipart);
  1151. EXRVersion version;
  1152. EXRHeader header;
  1153. EXRImage image;
  1154. InitEXRHeader(&header);
  1155. InitEXRImage(&image);
  1156. const char* err = nullptr;
  1157. ret = ParseEXRHeaderFromFile(&header, &exr_version, filepath.c_str(), &err);
  1158. REQUIRE(TINYEXR_SUCCESS == false);
  1159. if (ret) {
  1160. FreeEXRErrorMessage(err);
  1161. }
  1162. FreeEXRHeader(&header);
  1163. // FreeEXRImage(&image);
  1164. }
  1165. TEST_CASE("Regression: Issue57", "[fuzzing]") {
  1166. EXRVersion exr_version;
  1167. std::string filepath =
  1168. "./regression/"
  1169. "poc-df76d1f27adb8927a1446a603028272140905c168a336128465a1162ec7af270."
  1170. "mini";
  1171. int ret = ParseEXRVersionFromFile(&exr_version, filepath.c_str());
  1172. REQUIRE(TINYEXR_SUCCESS == ret);
  1173. REQUIRE(false == exr_version.tiled);
  1174. REQUIRE(false == exr_version.non_image);
  1175. REQUIRE(false == exr_version.multipart);
  1176. EXRVersion version;
  1177. EXRHeader header;
  1178. EXRImage image;
  1179. InitEXRHeader(&header);
  1180. InitEXRImage(&image);
  1181. const char* err = nullptr;
  1182. ret = ParseEXRHeaderFromFile(&header, &exr_version, filepath.c_str(), &err);
  1183. REQUIRE(TINYEXR_SUCCESS == false);
  1184. if (err) {
  1185. FreeEXRErrorMessage(err);
  1186. }
  1187. FreeEXRHeader(&header);
  1188. // FreeEXRImage(&image);
  1189. }
  1190. TEST_CASE("Regression: Issue56", "[fuzzing]") {
  1191. EXRVersion exr_version;
  1192. std::string filepath =
  1193. "./regression/"
  1194. "poc-1383755b301e5f505b2198dc0508918b537fdf48bbfc6deeffe268822e6f6cd6";
  1195. int ret = ParseEXRVersionFromFile(&exr_version, filepath.c_str());
  1196. REQUIRE(TINYEXR_SUCCESS == ret);
  1197. REQUIRE(false == exr_version.tiled);
  1198. REQUIRE(false == exr_version.non_image);
  1199. REQUIRE(false == exr_version.multipart);
  1200. EXRVersion version;
  1201. EXRHeader header;
  1202. EXRImage image;
  1203. InitEXRHeader(&header);
  1204. InitEXRImage(&image);
  1205. const char* err = nullptr;
  1206. ret = ParseEXRHeaderFromFile(&header, &exr_version, filepath.c_str(), &err);
  1207. REQUIRE(TINYEXR_SUCCESS == false);
  1208. if (err) {
  1209. FreeEXRErrorMessage(err);
  1210. }
  1211. FreeEXRHeader(&header);
  1212. // FreeEXRImage(&image);
  1213. }
  1214. TEST_CASE("Regression: Issue61", "[fuzzing]") {
  1215. EXRVersion exr_version;
  1216. std::string filepath =
  1217. "./regression/"
  1218. "poc-3f1f642c3356fd8e8d2a0787613ec09a56572b3a1e38c9629b6db9e8dead1117_"
  1219. "min";
  1220. int ret = ParseEXRVersionFromFile(&exr_version, filepath.c_str());
  1221. REQUIRE(TINYEXR_SUCCESS == ret);
  1222. REQUIRE(false == exr_version.tiled);
  1223. REQUIRE(false == exr_version.non_image);
  1224. REQUIRE(false == exr_version.multipart);
  1225. EXRVersion version;
  1226. EXRHeader header;
  1227. EXRImage image;
  1228. InitEXRHeader(&header);
  1229. InitEXRImage(&image);
  1230. const char* err = nullptr;
  1231. ret = ParseEXRHeaderFromFile(&header, &exr_version, filepath.c_str(), &err);
  1232. REQUIRE(TINYEXR_SUCCESS == false);
  1233. if (err) {
  1234. FreeEXRErrorMessage(err);
  1235. }
  1236. FreeEXRHeader(&header);
  1237. // FreeEXRImage(&image);
  1238. }
  1239. TEST_CASE("Regression: Issue60", "[fuzzing]") {
  1240. EXRVersion exr_version;
  1241. std::string filepath =
  1242. "./regression/"
  1243. "poc-5b66774a7498c635334ad386be0c3b359951738ac47f14878a3346d1c6ea0fe5_"
  1244. "min";
  1245. int ret = ParseEXRVersionFromFile(&exr_version, filepath.c_str());
  1246. REQUIRE(TINYEXR_SUCCESS == ret);
  1247. REQUIRE(false == exr_version.tiled);
  1248. REQUIRE(false == exr_version.non_image);
  1249. REQUIRE(false == exr_version.multipart);
  1250. EXRVersion version;
  1251. EXRHeader header;
  1252. EXRImage image;
  1253. InitEXRHeader(&header);
  1254. InitEXRImage(&image);
  1255. const char* err = nullptr;
  1256. ret = ParseEXRHeaderFromFile(&header, &exr_version, filepath.c_str(), &err);
  1257. REQUIRE(TINYEXR_SUCCESS == false);
  1258. if (err) {
  1259. FreeEXRErrorMessage(err);
  1260. }
  1261. FreeEXRHeader(&header);
  1262. // FreeEXRImage(&image);
  1263. }
  1264. TEST_CASE("Regression: Issue71", "[issue71]") {
  1265. std::string filepath = "./regression/2by2.exr";
  1266. const char* err;
  1267. int width, height;
  1268. float* image;
  1269. int ret = LoadEXR(&image, &width, &height, filepath.c_str(), &err);
  1270. REQUIRE(TINYEXR_SUCCESS == ret);
  1271. REQUIRE(2 == width);
  1272. REQUIRE(2 == height);
  1273. REQUIRE(0.0f == Approx(image[8]));
  1274. REQUIRE(0.447021f == Approx(image[9]));
  1275. REQUIRE(1.0f == Approx(image[10]));
  1276. REQUIRE(0.250977f == Approx(image[11]));
  1277. REQUIRE(0.0f == Approx(image[12]));
  1278. REQUIRE(0.0f == Approx(image[13]));
  1279. REQUIRE(0.0f == Approx(image[14]));
  1280. REQUIRE(1.0f == Approx(image[15]));
  1281. free(image);
  1282. }
  1283. // LoadEXRLoadFromMemory fails to load tiled image.
  1284. TEST_CASE("Regression: Issue93", "[issue93]") {
  1285. std::string filepath = GetPath("Tiles/GoldenGate.exr");
  1286. std::ifstream f(filepath.c_str(), std::ifstream::binary);
  1287. REQUIRE(f.good());
  1288. f.seekg(0, f.end);
  1289. size_t sz = static_cast<size_t>(f.tellg());
  1290. f.seekg(0, f.beg);
  1291. REQUIRE(sz > 16);
  1292. std::vector<unsigned char> data;
  1293. data.resize(sz);
  1294. f.read(reinterpret_cast<char*>(&data.at(0)),
  1295. static_cast<std::streamsize>(sz));
  1296. f.close();
  1297. const char* err;
  1298. int width, height;
  1299. float* image;
  1300. int ret = LoadEXRFromMemory(&image, &width, &height, data.data(), data.size(),
  1301. &err);
  1302. REQUIRE(TINYEXR_SUCCESS == ret);
  1303. std::cout << "val = " << image[0] << ", " << image[1] << ", " << image[2]
  1304. << ", " << image[3] << std::endl;
  1305. REQUIRE(0.0612183 == Approx(image[0]));
  1306. REQUIRE(0.0892334 == Approx(image[1]));
  1307. REQUIRE(0.271973 == Approx(image[2]));
  1308. free(image);
  1309. }
  1310. // PIZ decompress bug(issue 100)
  1311. TEST_CASE("Regression: Issue100", "[issue100]") {
  1312. std::string filepath = "./regression/piz-bug-issue-100.exr";
  1313. std::ifstream f(filepath.c_str(), std::ifstream::binary);
  1314. REQUIRE(f.good());
  1315. f.seekg(0, f.end);
  1316. size_t sz = static_cast<size_t>(f.tellg());
  1317. f.seekg(0, f.beg);
  1318. REQUIRE(sz > 16);
  1319. std::vector<unsigned char> data;
  1320. data.resize(sz);
  1321. f.read(reinterpret_cast<char*>(&data.at(0)),
  1322. static_cast<std::streamsize>(sz));
  1323. f.close();
  1324. const char* err = nullptr;
  1325. int width, height;
  1326. float* image;
  1327. int ret = LoadEXRFromMemory(&image, &width, &height, data.data(), data.size(),
  1328. &err);
  1329. if (err) {
  1330. std::cerr << "issue100 err " << err << std::endl;
  1331. FreeEXRErrorMessage(err);
  1332. }
  1333. REQUIRE(TINYEXR_SUCCESS == ret);
  1334. REQUIRE(35 == width);
  1335. REQUIRE(1 == height);
  1336. // pixel should be white.
  1337. std::cout << "pixel[0] = " << image[0] << ", " << image[1] << ", " << image[2]
  1338. << ", " << image[3] << std::endl;
  1339. std::cout << "pixel[34] = " << image[4 * 34 + 0] << ", " << image[4 * 34 + 1]
  1340. << ", " << image[4 * 34 + 2] << ", " << image[4 * 34 + 3]
  1341. << std::endl;
  1342. REQUIRE(0.0 == Approx(image[0]));
  1343. REQUIRE(0.0 == Approx(image[1]));
  1344. REQUIRE(0.0 == Approx(image[2]));
  1345. REQUIRE(0.0 == Approx(image[3]));
  1346. REQUIRE(1.0 == Approx(image[4 * 34 + 0]));
  1347. REQUIRE(1.0 == Approx(image[4 * 34 + 1]));
  1348. REQUIRE(1.0 == Approx(image[4 * 34 + 2]));
  1349. REQUIRE(1.0 == Approx(image[4 * 34 + 3]));
  1350. free(image);
  1351. }
  1352. TEST_CASE("Regression: Issue53|Channels", "[issue53]") {
  1353. EXRVersion exr_version;
  1354. std::string filepath = "./regression/flaga.exr";
  1355. int ret = ParseEXRVersionFromFile(&exr_version, filepath.c_str());
  1356. REQUIRE(TINYEXR_SUCCESS == ret);
  1357. EXRHeader header;
  1358. EXRImage image;
  1359. InitEXRHeader(&header);
  1360. const char* err = nullptr;
  1361. ret = ParseEXRHeaderFromFile(&header, &exr_version, filepath.c_str(), &err);
  1362. REQUIRE(TINYEXR_SUCCESS == ret);
  1363. std::vector<std::string> layer_names;
  1364. tinyexr::GetLayers(header, layer_names);
  1365. REQUIRE(2 == layer_names.size());
  1366. std::vector<tinyexr::LayerChannel> channels;
  1367. tinyexr::ChannelsInLayer(header, "", channels);
  1368. REQUIRE(8 == channels.size());
  1369. channels.clear();
  1370. tinyexr::ChannelsInLayer(header, "Warstwa 3", channels);
  1371. REQUIRE(0 == channels.size());
  1372. channels.clear();
  1373. tinyexr::ChannelsInLayer(header, "Warstwa 1", channels);
  1374. REQUIRE(4 == channels.size());
  1375. FreeEXRHeader(&header);
  1376. if (err) {
  1377. FreeEXRErrorMessage(err);
  1378. }
  1379. }
  1380. TEST_CASE("Regression: Issue53|Image", "[issue53]") {
  1381. std::string filepath = "./regression/flaga.exr";
  1382. const char* err = nullptr;
  1383. const char** layer_names = nullptr;
  1384. int num_layers = 0;
  1385. int ret = EXRLayers(filepath.c_str(), &layer_names, &num_layers, &err);
  1386. REQUIRE(TINYEXR_SUCCESS == ret);
  1387. REQUIRE(2 == num_layers);
  1388. for (int i = 0; i < num_layers; i++) {
  1389. free(reinterpret_cast<void*>(const_cast<char*>(layer_names[i])));
  1390. }
  1391. free(layer_names);
  1392. int width, height;
  1393. float* image;
  1394. ret = LoadEXRWithLayer(&image, &width, &height, filepath.c_str(), NULL, &err);
  1395. REQUIRE(TINYEXR_SUCCESS == ret);
  1396. free(image);
  1397. if (err) {
  1398. FreeEXRErrorMessage(err);
  1399. }
  1400. ret = LoadEXRWithLayer(&image, &width, &height, filepath.c_str(), "Warstwa 1",
  1401. &err);
  1402. REQUIRE(TINYEXR_SUCCESS == ret);
  1403. free(image);
  1404. if (err) {
  1405. FreeEXRErrorMessage(err);
  1406. }
  1407. }
  1408. TEST_CASE("Regression: Issue53|Image|Missing Layer", "[issue53]") {
  1409. std::string filepath = GetPath("MultiView/Impact.exr");
  1410. const char* err = nullptr;
  1411. int width, height;
  1412. float* image = nullptr;
  1413. int ret = LoadEXRWithLayer(&image, &width, &height, filepath.c_str(),
  1414. "Warstwa", &err);
  1415. REQUIRE(TINYEXR_ERROR_LAYER_NOT_FOUND == ret);
  1416. if (image) {
  1417. free(image);
  1418. }
  1419. if (err) {
  1420. FreeEXRErrorMessage(err);
  1421. }
  1422. }
  1423. TEST_CASE("Regression: PR150|Read|1x1 1xhalf", "[pr150]") {
  1424. std::string filepath = "./regression/tiled_half_1x1_alpha.exr";
  1425. EXRVersion exr_version;
  1426. std::cout << "Loading" << filepath << std::endl;
  1427. int ret = ParseEXRVersionFromFile(&exr_version, filepath.c_str());
  1428. REQUIRE(TINYEXR_SUCCESS == ret);
  1429. REQUIRE(true == exr_version.tiled);
  1430. REQUIRE(false == exr_version.non_image);
  1431. REQUIRE(false == exr_version.multipart);
  1432. EXRVersion version;
  1433. EXRHeader header;
  1434. EXRImage image;
  1435. InitEXRHeader(&header);
  1436. InitEXRImage(&image);
  1437. const char* err;
  1438. ret = ParseEXRHeaderFromFile(&header, &exr_version, filepath.c_str(), &err);
  1439. REQUIRE(TINYEXR_SUCCESS == ret);
  1440. ret = LoadEXRImageFromFile(&image, &header, filepath.c_str(), &err);
  1441. REQUIRE(TINYEXR_SUCCESS == ret);
  1442. FreeEXRHeader(&header);
  1443. FreeEXRImage(&image);
  1444. }