image_decode.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743
  1. /*
  2. * Copyright 2011-2018 Branimir Karadzic. All rights reserved.
  3. * License: https://github.com/bkaradzic/bimg#license-bsd-2-clause
  4. */
  5. #include "bimg_p.h"
  6. BX_PRAGMA_DIAGNOSTIC_IGNORED_CLANG_GCC("-Wunused-function")
  7. BX_PRAGMA_DIAGNOSTIC_PUSH()
  8. BX_PRAGMA_DIAGNOSTIC_IGNORED_CLANG_GCC("-Wtype-limits")
  9. BX_PRAGMA_DIAGNOSTIC_IGNORED_CLANG_GCC("-Wunused-parameter")
  10. BX_PRAGMA_DIAGNOSTIC_IGNORED_CLANG_GCC("-Wunused-value")
  11. BX_PRAGMA_DIAGNOSTIC_IGNORED_CLANG("-Wdeprecated-declarations")
  12. BX_PRAGMA_DIAGNOSTIC_IGNORED_MSVC(4100) // error C4100: '' : unreferenced formal parameter
  13. BX_PRAGMA_DIAGNOSTIC_IGNORED_MSVC(4505) // warning C4505: 'tinyexr::miniz::def_realloc_func': unreferenced local function has been removed
  14. #if BX_PLATFORM_EMSCRIPTEN
  15. # include <compat/ctype.h>
  16. #endif // BX_PLATFORM_EMSCRIPTEN
  17. #define MINIZ_NO_ARCHIVE_APIS
  18. #define MINIZ_NO_STDIO
  19. #define TINYEXR_IMPLEMENTATION
  20. #include <tinyexr/tinyexr.h>
  21. BX_PRAGMA_DIAGNOSTIC_POP()
  22. BX_PRAGMA_DIAGNOSTIC_PUSH();
  23. BX_PRAGMA_DIAGNOSTIC_IGNORED_MSVC(4127) // warning C4127: conditional expression is constant
  24. #define LODEPNG_NO_COMPILE_ENCODER
  25. #define LODEPNG_NO_COMPILE_DISK
  26. #define LODEPNG_NO_COMPILE_ANCILLARY_CHUNKS
  27. #define LODEPNG_NO_COMPILE_ALLOCATORS
  28. #define LODEPNG_NO_COMPILE_CPP
  29. #include <lodepng/lodepng.cpp>
  30. BX_PRAGMA_DIAGNOSTIC_POP();
  31. void* lodepng_malloc(size_t _size)
  32. {
  33. return ::malloc(_size);
  34. }
  35. void* lodepng_realloc(void* _ptr, size_t _size)
  36. {
  37. return ::realloc(_ptr, _size);
  38. }
  39. void lodepng_free(void* _ptr)
  40. {
  41. ::free(_ptr);
  42. }
  43. BX_PRAGMA_DIAGNOSTIC_PUSH();
  44. BX_PRAGMA_DIAGNOSTIC_IGNORED_CLANG_GCC("-Wmissing-field-initializers");
  45. BX_PRAGMA_DIAGNOSTIC_IGNORED_CLANG_GCC("-Wshadow");
  46. BX_PRAGMA_DIAGNOSTIC_IGNORED_CLANG_GCC("-Wint-to-pointer-cast")
  47. BX_PRAGMA_DIAGNOSTIC_IGNORED_GCC("-Warray-bounds");
  48. #if BX_COMPILER_GCC >= 60000
  49. BX_PRAGMA_DIAGNOSTIC_IGNORED_GCC("-Wmisleading-indentation");
  50. BX_PRAGMA_DIAGNOSTIC_IGNORED_GCC("-Wshift-negative-value");
  51. # if BX_COMPILER_GCC >= 70000
  52. BX_PRAGMA_DIAGNOSTIC_IGNORED_GCC("-Wimplicit-fallthrough");
  53. # endif // BX_COMPILER_GCC >= 70000
  54. #endif // BX_COMPILER_GCC >= 60000_
  55. #define STBI_MALLOC(_size) lodepng_malloc(_size)
  56. #define STBI_REALLOC(_ptr, _size) lodepng_realloc(_ptr, _size)
  57. #define STBI_FREE(_ptr) lodepng_free(_ptr)
  58. #define STB_IMAGE_IMPLEMENTATION
  59. #include <stb/stb_image.h>
  60. BX_PRAGMA_DIAGNOSTIC_POP();
  61. namespace bimg
  62. {
  63. static ImageContainer* imageParseLodePng(bx::AllocatorI* _allocator, const void* _data, uint32_t _size, bx::Error* _err)
  64. {
  65. BX_ERROR_SCOPE(_err);
  66. static uint8_t pngMagic[] = { 0x89, 0x50, 0x4E, 0x47, 0x0d, 0x0a };
  67. if (0 != bx::memCmp(_data, pngMagic, sizeof(pngMagic) ) )
  68. {
  69. return NULL;
  70. }
  71. ImageContainer* output = NULL;
  72. bimg::TextureFormat::Enum format = bimg::TextureFormat::RGBA8;
  73. uint32_t width = 0;
  74. uint32_t height = 0;
  75. unsigned error;
  76. LodePNGState state;
  77. lodepng_state_init(&state);
  78. state.decoder.color_convert = 0;
  79. uint8_t* data = NULL;
  80. error = lodepng_decode(&data, &width, &height, &state, (uint8_t*)_data, _size);
  81. if (0 != error)
  82. {
  83. _err->setError(BIMG_ERROR, lodepng_error_text(error) );
  84. }
  85. else
  86. {
  87. bool palette = false;
  88. bool supported = false;
  89. switch (state.info_raw.bitdepth)
  90. {
  91. case 1:
  92. case 2:
  93. case 4:
  94. format = bimg::TextureFormat::R8;
  95. palette = false;
  96. supported = true;
  97. break;
  98. case 8:
  99. switch (state.info_raw.colortype)
  100. {
  101. case LCT_GREY:
  102. format = bimg::TextureFormat::R8;
  103. supported = true;
  104. break;
  105. case LCT_GREY_ALPHA:
  106. format = bimg::TextureFormat::RG8;
  107. supported = true;
  108. break;
  109. case LCT_RGB:
  110. format = bimg::TextureFormat::RGB8;
  111. supported = true;
  112. break;
  113. case LCT_RGBA:
  114. format = bimg::TextureFormat::RGBA8;
  115. supported = true;
  116. break;
  117. case LCT_PALETTE:
  118. format = bimg::TextureFormat::RGBA8;
  119. palette = true;
  120. supported = true;
  121. break;
  122. }
  123. break;
  124. case 16:
  125. switch (state.info_raw.colortype)
  126. {
  127. case LCT_GREY:
  128. for (uint32_t ii = 0, num = width*height; ii < num; ++ii)
  129. {
  130. uint16_t* rgba = (uint16_t*)data + ii;
  131. rgba[0] = bx::toHostEndian(rgba[0], false);
  132. }
  133. format = bimg::TextureFormat::R16;
  134. supported = true;
  135. break;
  136. case LCT_GREY_ALPHA:
  137. for (uint32_t ii = 0, num = width*height; ii < num; ++ii)
  138. {
  139. uint16_t* rgba = (uint16_t*)data + ii*2;
  140. rgba[0] = bx::toHostEndian(rgba[0], false);
  141. rgba[1] = bx::toHostEndian(rgba[1], false);
  142. }
  143. format = bimg::TextureFormat::RG16;
  144. supported = true;
  145. break;
  146. case LCT_RGB:
  147. for (uint32_t ii = 0, num = width*height; ii < num; ++ii)
  148. {
  149. uint16_t* rgba = (uint16_t*)data + ii*3;
  150. rgba[0] = bx::toHostEndian(rgba[0], false);
  151. rgba[1] = bx::toHostEndian(rgba[1], false);
  152. rgba[2] = bx::toHostEndian(rgba[2], false);
  153. }
  154. format = bimg::TextureFormat::RGBA16;
  155. supported = true;
  156. break;
  157. case LCT_RGBA:
  158. for (uint32_t ii = 0, num = width*height; ii < num; ++ii)
  159. {
  160. uint16_t* rgba = (uint16_t*)data + ii*4;
  161. rgba[0] = bx::toHostEndian(rgba[0], false);
  162. rgba[1] = bx::toHostEndian(rgba[1], false);
  163. rgba[2] = bx::toHostEndian(rgba[2], false);
  164. rgba[3] = bx::toHostEndian(rgba[3], false);
  165. }
  166. format = bimg::TextureFormat::RGBA16;
  167. supported = true;
  168. break;
  169. case LCT_PALETTE:
  170. break;
  171. }
  172. break;
  173. default:
  174. break;
  175. }
  176. if (supported)
  177. {
  178. const uint8_t* copyData = data;
  179. TextureFormat::Enum dstFormat = format;
  180. if (1 == state.info_raw.bitdepth
  181. || 2 == state.info_raw.bitdepth
  182. || 4 == state.info_raw.bitdepth)
  183. {
  184. copyData = NULL;
  185. }
  186. else if (16 == state.info_raw.bitdepth
  187. && LCT_RGB == state.info_raw.colortype)
  188. {
  189. dstFormat = bimg::TextureFormat::RGBA16;
  190. copyData = NULL;
  191. }
  192. else if (palette)
  193. {
  194. copyData = NULL;
  195. }
  196. output = imageAlloc(_allocator
  197. , dstFormat
  198. , uint16_t(width)
  199. , uint16_t(height)
  200. , 0
  201. , 1
  202. , false
  203. , false
  204. , copyData
  205. );
  206. if (1 == state.info_raw.bitdepth)
  207. {
  208. for (uint32_t ii = 0, num = width*height/8; ii < num; ++ii)
  209. {
  210. uint8_t* src = (uint8_t*)data + ii;
  211. uint8_t eightBits = src[0];
  212. uint8_t* dst = (uint8_t*)output->m_data + ii*8;
  213. dst[0] = uint8_t( (eightBits>>7)&0x1)*255;
  214. dst[1] = uint8_t( (eightBits>>6)&0x1)*255;
  215. dst[2] = uint8_t( (eightBits>>5)&0x1)*255;
  216. dst[3] = uint8_t( (eightBits>>4)&0x1)*255;
  217. dst[4] = uint8_t( (eightBits>>3)&0x1)*255;
  218. dst[5] = uint8_t( (eightBits>>2)&0x1)*255;
  219. dst[6] = uint8_t( (eightBits>>1)&0x1)*255;
  220. dst[7] = uint8_t( (eightBits )&0x1)*255;
  221. }
  222. }
  223. else if (2 == state.info_raw.bitdepth)
  224. {
  225. for (uint32_t ii = 0, num = width*height/4; ii < num; ++ii)
  226. {
  227. uint8_t* src = (uint8_t*)data + ii;
  228. uint8_t eightBits = src[0];
  229. uint8_t* dst = (uint8_t*)output->m_data + ii*4;
  230. // Note: not exactly precise.
  231. // Correct way: dst[0] = uint8_t(float( (eightBits>>6)&0x3)*(255.0f/4.0f) );
  232. dst[0] = uint8_t(uint32_t(((eightBits>>6)&0x3)*64)&0xff);
  233. dst[1] = uint8_t(uint32_t(((eightBits>>4)&0x3)*64)&0xff);
  234. dst[2] = uint8_t(uint32_t(((eightBits>>2)&0x3)*64)&0xff);
  235. dst[3] = uint8_t(uint32_t(((eightBits )&0x3)*64)&0xff);
  236. }
  237. }
  238. else if (4 == state.info_raw.bitdepth)
  239. {
  240. for (uint32_t ii = 0, num = width*height/2; ii < num; ++ii)
  241. {
  242. uint8_t* src = (uint8_t*)data + ii;
  243. uint8_t eightBits = src[0];
  244. uint8_t* dst = (uint8_t*)output->m_data + ii*2;
  245. // Note: not exactly precise.
  246. // Correct way: dst[0] = uint8_t(float( (eightBits>>4)&0xf)*(255.0f/16.0f) );
  247. dst[0] = uint8_t(uint32_t(((eightBits>>4)&0xf)*16)&0xff);
  248. dst[1] = uint8_t(uint32_t(((eightBits )&0xf)*16)&0xff);
  249. }
  250. }
  251. else if (16 == state.info_raw.bitdepth
  252. && LCT_RGB == state.info_raw.colortype)
  253. {
  254. for (uint32_t ii = 0, num = width*height; ii < num; ++ii)
  255. {
  256. const uint16_t* src = (uint16_t*)data + ii*3;
  257. uint16_t* dst = (uint16_t*)output->m_data + ii*4;
  258. dst[0] = src[0];
  259. dst[1] = src[1];
  260. dst[2] = src[2];
  261. dst[3] = UINT16_MAX;
  262. }
  263. }
  264. else if (palette)
  265. {
  266. for (uint32_t ii = 0, num = width*height; ii < num; ++ii)
  267. {
  268. bx::memCopy( (uint8_t*)output->m_data + ii*4, state.info_raw.palette + data[ii]*4, 4);
  269. }
  270. }
  271. }
  272. else
  273. {
  274. BX_ERROR_SET(_err, BIMG_ERROR, "PNG: Unsupported format.");
  275. }
  276. }
  277. lodepng_state_cleanup(&state);
  278. lodepng_free(data);
  279. return output;
  280. }
  281. static ImageContainer* imageParseTinyExr(bx::AllocatorI* _allocator, const void* _data, uint32_t _size, bx::Error* _err)
  282. {
  283. BX_ERROR_SCOPE(_err);
  284. EXRVersion exrVersion;
  285. int result = ParseEXRVersionFromMemory(&exrVersion, (uint8_t*)_data, _size);
  286. if (TINYEXR_SUCCESS != result)
  287. {
  288. return NULL;
  289. }
  290. bimg::TextureFormat::Enum format = bimg::TextureFormat::RGBA8;
  291. uint32_t width = 0;
  292. uint32_t height = 0;
  293. uint8_t* data = NULL;
  294. const char* err = NULL;
  295. EXRHeader exrHeader;
  296. result = ParseEXRHeaderFromMemory(&exrHeader, &exrVersion, (uint8_t*)_data, _size, &err);
  297. if (TINYEXR_SUCCESS == result)
  298. {
  299. EXRImage exrImage;
  300. InitEXRImage(&exrImage);
  301. result = LoadEXRImageFromMemory(&exrImage, &exrHeader, (uint8_t*)_data, _size, &err);
  302. if (TINYEXR_SUCCESS == result)
  303. {
  304. uint8_t idxR = UINT8_MAX;
  305. uint8_t idxG = UINT8_MAX;
  306. uint8_t idxB = UINT8_MAX;
  307. uint8_t idxA = UINT8_MAX;
  308. for (uint8_t ii = 0, num = uint8_t(exrHeader.num_channels); ii < num; ++ii)
  309. {
  310. const EXRChannelInfo& channel = exrHeader.channels[ii];
  311. if (UINT8_MAX == idxR
  312. && 0 == bx::strCmp(channel.name, "R") )
  313. {
  314. idxR = ii;
  315. }
  316. else if (UINT8_MAX == idxG
  317. && 0 == bx::strCmp(channel.name, "G") )
  318. {
  319. idxG = ii;
  320. }
  321. else if (UINT8_MAX == idxB
  322. && 0 == bx::strCmp(channel.name, "B") )
  323. {
  324. idxB = ii;
  325. }
  326. else if (UINT8_MAX == idxA
  327. && 0 == bx::strCmp(channel.name, "A") )
  328. {
  329. idxA = ii;
  330. }
  331. }
  332. if (UINT8_MAX != idxR)
  333. {
  334. const bool asFloat = exrHeader.pixel_types[idxR] == TINYEXR_PIXELTYPE_FLOAT;
  335. uint32_t srcBpp = 32;
  336. uint32_t dstBpp = asFloat ? 32 : 16;
  337. format = asFloat ? TextureFormat::R32F : TextureFormat::R16F;
  338. uint32_t stepR = 1;
  339. uint32_t stepG = 0;
  340. uint32_t stepB = 0;
  341. uint32_t stepA = 0;
  342. if (UINT8_MAX != idxG)
  343. {
  344. srcBpp += 32;
  345. dstBpp = asFloat ? 64 : 32;
  346. format = asFloat ? TextureFormat::RG32F : TextureFormat::RG16F;
  347. stepG = 1;
  348. }
  349. if (UINT8_MAX != idxB)
  350. {
  351. srcBpp += 32;
  352. dstBpp = asFloat ? 128 : 64;
  353. format = asFloat ? TextureFormat::RGBA32F : TextureFormat::RGBA16F;
  354. stepB = 1;
  355. }
  356. if (UINT8_MAX != idxA)
  357. {
  358. srcBpp += 32;
  359. dstBpp = asFloat ? 128 : 64;
  360. format = asFloat ? TextureFormat::RGBA32F : TextureFormat::RGBA16F;
  361. stepA = 1;
  362. }
  363. data = (uint8_t*)BX_ALLOC(_allocator, exrImage.width * exrImage.height * dstBpp/8);
  364. width = exrImage.width;
  365. height = exrImage.height;
  366. if (asFloat)
  367. {
  368. const float zero = 0.0f;
  369. const float* srcR = UINT8_MAX == idxR ? &zero : (const float*)(exrImage.images)[idxR];
  370. const float* srcG = UINT8_MAX == idxG ? &zero : (const float*)(exrImage.images)[idxG];
  371. const float* srcB = UINT8_MAX == idxB ? &zero : (const float*)(exrImage.images)[idxB];
  372. const float* srcA = UINT8_MAX == idxA ? &zero : (const float*)(exrImage.images)[idxA];
  373. const uint32_t bytesPerPixel = dstBpp/8;
  374. for (uint32_t ii = 0, num = exrImage.width * exrImage.height; ii < num; ++ii)
  375. {
  376. float rgba[4] =
  377. {
  378. *srcR,
  379. *srcG,
  380. *srcB,
  381. *srcA,
  382. };
  383. bx::memCopy(&data[ii * bytesPerPixel], rgba, bytesPerPixel);
  384. srcR += stepR;
  385. srcG += stepG;
  386. srcB += stepB;
  387. srcA += stepA;
  388. }
  389. }
  390. else
  391. {
  392. const uint16_t zero = 0;
  393. const uint16_t* srcR = UINT8_MAX == idxR ? &zero : (const uint16_t*)(exrImage.images)[idxR];
  394. const uint16_t* srcG = UINT8_MAX == idxG ? &zero : (const uint16_t*)(exrImage.images)[idxG];
  395. const uint16_t* srcB = UINT8_MAX == idxB ? &zero : (const uint16_t*)(exrImage.images)[idxB];
  396. const uint16_t* srcA = UINT8_MAX == idxA ? &zero : (const uint16_t*)(exrImage.images)[idxA];
  397. const uint32_t bytesPerPixel = dstBpp/8;
  398. for (uint32_t ii = 0, num = exrImage.width * exrImage.height; ii < num; ++ii)
  399. {
  400. uint16_t rgba[4] =
  401. {
  402. *srcR,
  403. *srcG,
  404. *srcB,
  405. *srcA,
  406. };
  407. bx::memCopy(&data[ii * bytesPerPixel], rgba, bytesPerPixel);
  408. srcR += stepR;
  409. srcG += stepG;
  410. srcB += stepB;
  411. srcA += stepA;
  412. }
  413. }
  414. }
  415. else
  416. {
  417. BX_ERROR_SET(_err, BIMG_ERROR, "EXR: Couldn't find R channel.");
  418. }
  419. FreeEXRImage(&exrImage);
  420. }
  421. else
  422. {
  423. switch (result)
  424. {
  425. case TINYEXR_ERROR_INVALID_MAGIC_NUMBER: BX_ERROR_SET(_err, BIMG_ERROR, "EXR: Failed to parse image. Invalid magic number."); break;
  426. case TINYEXR_ERROR_INVALID_EXR_VERSION: BX_ERROR_SET(_err, BIMG_ERROR, "EXR: Failed to parse image. Invalid EXR version."); break;
  427. case TINYEXR_ERROR_INVALID_ARGUMENT: BX_ERROR_SET(_err, BIMG_ERROR, "EXR: Failed to parse image. Invalid argument."); break;
  428. case TINYEXR_ERROR_INVALID_DATA: BX_ERROR_SET(_err, BIMG_ERROR, "EXR: Failed to parse image. Invalid data."); break;
  429. case TINYEXR_ERROR_INVALID_FILE: BX_ERROR_SET(_err, BIMG_ERROR, "EXR: Failed to parse image. Invalid file."); break;
  430. // case TINYEXR_ERROR_INVALID_PARAMETER: BX_ERROR_SET(_err, BIMG_ERROR, "EXR: Failed to parse image. Invalid parameter."); break;
  431. case TINYEXR_ERROR_CANT_OPEN_FILE: BX_ERROR_SET(_err, BIMG_ERROR, "EXR: Failed to parse image. Can't open file."); break;
  432. case TINYEXR_ERROR_UNSUPPORTED_FORMAT: BX_ERROR_SET(_err, BIMG_ERROR, "EXR: Failed to parse image. Unsupported format."); break;
  433. case TINYEXR_ERROR_INVALID_HEADER: BX_ERROR_SET(_err, BIMG_ERROR, "EXR: Failed to parse image. Invalid header."); break;
  434. case TINYEXR_ERROR_UNSUPPORTED_FEATURE: BX_ERROR_SET(_err, BIMG_ERROR, "EXR: Failed to parse image. Unsupported feature."); break;
  435. case TINYEXR_ERROR_CANT_WRITE_FILE: BX_ERROR_SET(_err, BIMG_ERROR, "EXR: Failed to parse image. Can't write file."); break;
  436. case TINYEXR_ERROR_SERIALZATION_FAILED: BX_ERROR_SET(_err, BIMG_ERROR, "EXR: Failed to parse image. Serialization failed."); break;
  437. default: BX_ERROR_SET(_err, BIMG_ERROR, "EXR: Failed to parse image."); break;
  438. }
  439. }
  440. FreeEXRHeader(&exrHeader);
  441. }
  442. else
  443. {
  444. BX_ERROR_SET(_err, BIMG_ERROR, "EXR: Failed to parse header.");
  445. }
  446. ImageContainer* output = NULL;
  447. if (NULL != data)
  448. {
  449. output = imageAlloc(_allocator
  450. , format
  451. , uint16_t(width)
  452. , uint16_t(height)
  453. , 0
  454. , 1
  455. , false
  456. , false
  457. , data
  458. );
  459. BX_FREE(_allocator, data);
  460. }
  461. return output;
  462. }
  463. static ImageContainer* imageParseStbImage(bx::AllocatorI* _allocator, const void* _data, uint32_t _size, bx::Error* _err)
  464. {
  465. BX_ERROR_SCOPE(_err);
  466. const int isHdr = stbi_is_hdr_from_memory( (const uint8_t*)_data, (int)_size);
  467. void* data;
  468. uint32_t width = 0;
  469. uint32_t height = 0;
  470. int comp = 0;
  471. if (isHdr)
  472. {
  473. data = stbi_loadf_from_memory( (const uint8_t*)_data, (int)_size, (int*)&width, (int*)&height, &comp, 4);
  474. }
  475. else
  476. {
  477. data = stbi_load_from_memory ( (const uint8_t*)_data, (int)_size, (int*)&width, (int*)&height, &comp, 0);
  478. }
  479. if (NULL == data)
  480. {
  481. return NULL;
  482. }
  483. bimg::TextureFormat::Enum format = bimg::TextureFormat::RGBA8;
  484. if (isHdr)
  485. {
  486. format = bimg::TextureFormat::RGBA32F;
  487. }
  488. else
  489. {
  490. switch (comp)
  491. {
  492. case 1: format = bimg::TextureFormat::R8; break;
  493. case 2: format = bimg::TextureFormat::RG8; break;
  494. case 3: format = bimg::TextureFormat::RGB8; break;
  495. default: break;
  496. }
  497. }
  498. ImageContainer* output = imageAlloc(_allocator
  499. , format
  500. , uint16_t(width)
  501. , uint16_t(height)
  502. , 0
  503. , 1
  504. , false
  505. , false
  506. , data
  507. );
  508. stbi_image_free(data);
  509. return output;
  510. }
  511. static ImageContainer* imageParseJpeg(bx::AllocatorI* _allocator, const void* _data, uint32_t _size, bx::Error* _err)
  512. {
  513. bx::MemoryReader reader(_data, _size);
  514. bx::Error err;
  515. uint16_t magic = 0;
  516. bx::readHE(&reader, magic, false, &err);
  517. if (!err.isOk()
  518. || 0xffd8 != magic)
  519. {
  520. return NULL;
  521. }
  522. Orientation::Enum orientation = Orientation::R0;
  523. while (err.isOk() )
  524. {
  525. bx::readHE(&reader, magic, false, &err);
  526. uint16_t size;
  527. bx::readHE(&reader, size, false, &err);
  528. if (!err.isOk() )
  529. {
  530. return NULL;
  531. }
  532. if (0xffe1 != magic)
  533. {
  534. bx::seek(&reader, size-2);
  535. continue;
  536. }
  537. char exif00[6];
  538. bx::read(&reader, exif00, 6, &err);
  539. if (0 == bx::memCmp(exif00, "Exif\0\0", 6) )
  540. {
  541. uint16_t iimm = 0;
  542. bx::read(&reader, iimm, &err);
  543. const bool littleEndian = iimm == 0x4949; //II - Intel - little endian
  544. if (!err.isOk()
  545. && !littleEndian
  546. && iimm != 0x4d4d) // MM - Motorola - big endian
  547. {
  548. return NULL;
  549. }
  550. bx::readHE(&reader, magic, littleEndian, &err);
  551. if (!err.isOk()
  552. || 0x2a != magic)
  553. {
  554. return NULL;
  555. }
  556. uint32_t ifd0;
  557. bx::readHE(&reader, ifd0, littleEndian, &err);
  558. if (!err.isOk()
  559. || 8 > ifd0)
  560. {
  561. return NULL;
  562. }
  563. bx::seek(&reader, ifd0-8);
  564. uint16_t numEntries;
  565. bx::readHE(&reader, numEntries, littleEndian, &err);
  566. for (uint32_t ii = 0; err.isOk() && ii < numEntries; ++ii)
  567. {
  568. // https://sno.phy.queensu.ca/~phil/exiftool/TagNames/EXIF.html
  569. uint16_t tag;
  570. bx::readHE(&reader, tag, littleEndian, &err);
  571. uint16_t format;
  572. bx::readHE(&reader, format, littleEndian, &err);
  573. uint32_t length;
  574. bx::readHE(&reader, length, littleEndian, &err);
  575. uint32_t data;
  576. bx::readHE(&reader, data, littleEndian, &err);
  577. switch (tag)
  578. {
  579. case 0x112: // orientation
  580. if (3 == format)
  581. {
  582. bx::seek(&reader, -4);
  583. uint16_t u16;
  584. bx::readHE(&reader, u16, littleEndian, &err);
  585. uint16_t pad;
  586. bx::read(&reader, pad, &err);
  587. switch (u16)
  588. {
  589. default:
  590. case 1: orientation = Orientation::R0; break; // Horizontal (normal)
  591. case 2: orientation = Orientation::HFlip; break; // Mirror horizontal
  592. case 3: orientation = Orientation::R180; break; // Rotate 180
  593. case 4: orientation = Orientation::VFlip; break; // Mirror vertical
  594. case 5: orientation = Orientation::HFlipR270; break; // Mirror horizontal and rotate 270 CW
  595. case 6: orientation = Orientation::R90; break; // Rotate 90 CW
  596. case 7: orientation = Orientation::HFlipR90; break; // Mirror horizontal and rotate 90 CW
  597. case 8: orientation = Orientation::R270; break; // Rotate 270 CW
  598. }
  599. }
  600. break;
  601. default:
  602. break;
  603. }
  604. }
  605. }
  606. break;
  607. }
  608. ImageContainer* image = imageParseStbImage(_allocator, _data, _size, _err);
  609. if (NULL != image)
  610. {
  611. image->m_orientation = orientation;
  612. }
  613. return image;
  614. }
  615. ImageContainer* imageParse(bx::AllocatorI* _allocator, const void* _data, uint32_t _size, TextureFormat::Enum _dstFormat, bx::Error* _err)
  616. {
  617. BX_ERROR_SCOPE(_err);
  618. ImageContainer* input = imageParseDds (_allocator, _data, _size, _err) ;
  619. input = NULL == input ? imageParseKtx (_allocator, _data, _size, _err) : input;
  620. input = NULL == input ? imageParsePvr3 (_allocator, _data, _size, _err) : input;
  621. input = NULL == input ? imageParseGnf (_allocator, _data, _size, _err) : input;
  622. input = NULL == input ? imageParseLodePng (_allocator, _data, _size, _err) : input;
  623. input = NULL == input ? imageParseTinyExr (_allocator, _data, _size, _err) : input;
  624. input = NULL == input ? imageParseJpeg (_allocator, _data, _size, _err) : input;
  625. input = NULL == input ? imageParseStbImage(_allocator, _data, _size, _err) : input;
  626. if (NULL == input)
  627. {
  628. return NULL;
  629. }
  630. _dstFormat = TextureFormat::Count == _dstFormat
  631. ? input->m_format
  632. : _dstFormat
  633. ;
  634. if (_dstFormat == input->m_format)
  635. {
  636. return input;
  637. }
  638. ImageContainer* output = imageConvert(_allocator, _dstFormat, *input);
  639. imageFree(input);
  640. return output;
  641. }
  642. } // namespace bimg