image_decode.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527
  1. /*
  2. * Copyright 2011-2017 Branimir Karadzic. All rights reserved.
  3. * License: https://github.com/bkaradzic/bgfx#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_ERROR_TEXT
  28. #define LODEPNG_NO_COMPILE_ALLOCATORS
  29. #define LODEPNG_NO_COMPILE_CPP
  30. #include <lodepng/lodepng.cpp>
  31. BX_PRAGMA_DIAGNOSTIC_POP();
  32. void* lodepng_malloc(size_t _size)
  33. {
  34. return ::malloc(_size);
  35. }
  36. void* lodepng_realloc(void* _ptr, size_t _size)
  37. {
  38. return ::realloc(_ptr, _size);
  39. }
  40. void lodepng_free(void* _ptr)
  41. {
  42. ::free(_ptr);
  43. }
  44. BX_PRAGMA_DIAGNOSTIC_PUSH();
  45. BX_PRAGMA_DIAGNOSTIC_IGNORED_CLANG_GCC("-Wmissing-field-initializers");
  46. BX_PRAGMA_DIAGNOSTIC_IGNORED_CLANG_GCC("-Wshadow");
  47. BX_PRAGMA_DIAGNOSTIC_IGNORED_CLANG_GCC("-Wint-to-pointer-cast")
  48. BX_PRAGMA_DIAGNOSTIC_IGNORED_GCC("-Warray-bounds");
  49. #if BX_COMPILER_GCC >= 60000
  50. BX_PRAGMA_DIAGNOSTIC_IGNORED_GCC("-Wmisleading-indentation");
  51. BX_PRAGMA_DIAGNOSTIC_IGNORED_GCC("-Wshift-negative-value");
  52. #elif BX_COMPILER_GCC >= 70000
  53. BX_PRAGMA_DIAGNOSTIC_IGNORED_GCC("-Wimplicit-fallthrough");
  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. bool palette = false;
  84. bool supported = false;
  85. switch (state.info_raw.bitdepth)
  86. {
  87. case 1:
  88. format = bimg::TextureFormat::R1;
  89. palette = false;
  90. supported = true;
  91. break;
  92. case 8:
  93. switch (state.info_raw.colortype)
  94. {
  95. case LCT_GREY:
  96. format = bimg::TextureFormat::R8;
  97. supported = true;
  98. break;
  99. case LCT_GREY_ALPHA:
  100. format = bimg::TextureFormat::RG8;
  101. supported = true;
  102. break;
  103. case LCT_RGB:
  104. format = bimg::TextureFormat::RGB8;
  105. supported = true;
  106. break;
  107. case LCT_RGBA:
  108. format = bimg::TextureFormat::RGBA8;
  109. supported = true;
  110. break;
  111. case LCT_PALETTE:
  112. format = bimg::TextureFormat::RGBA8;
  113. palette = true;
  114. supported = true;
  115. break;
  116. }
  117. break;
  118. case 16:
  119. switch (state.info_raw.colortype)
  120. {
  121. case LCT_GREY:
  122. for (uint32_t ii = 0, num = width*height; ii < num; ++ii)
  123. {
  124. uint16_t* rgba = (uint16_t*)data + ii;
  125. rgba[0] = bx::toHostEndian(rgba[0], false);
  126. }
  127. format = bimg::TextureFormat::R16;
  128. supported = true;
  129. break;
  130. case LCT_GREY_ALPHA:
  131. for (uint32_t ii = 0, num = width*height; ii < num; ++ii)
  132. {
  133. uint16_t* rgba = (uint16_t*)data + ii*2;
  134. rgba[0] = bx::toHostEndian(rgba[0], false);
  135. rgba[1] = bx::toHostEndian(rgba[1], false);
  136. }
  137. format = bimg::TextureFormat::RG16;
  138. supported = true;
  139. break;
  140. case LCT_RGB:
  141. for (uint32_t ii = 0, num = width*height; ii < num; ++ii)
  142. {
  143. uint16_t* rgba = (uint16_t*)data + ii*3;
  144. rgba[0] = bx::toHostEndian(rgba[0], false);
  145. rgba[1] = bx::toHostEndian(rgba[1], false);
  146. rgba[2] = bx::toHostEndian(rgba[2], false);
  147. }
  148. format = bimg::TextureFormat::RGBA16;
  149. supported = true;
  150. break;
  151. case LCT_RGBA:
  152. for (uint32_t ii = 0, num = width*height; ii < num; ++ii)
  153. {
  154. uint16_t* rgba = (uint16_t*)data + ii*4;
  155. rgba[0] = bx::toHostEndian(rgba[0], false);
  156. rgba[1] = bx::toHostEndian(rgba[1], false);
  157. rgba[2] = bx::toHostEndian(rgba[2], false);
  158. rgba[3] = bx::toHostEndian(rgba[3], false);
  159. }
  160. format = bimg::TextureFormat::RGBA16;
  161. supported = true;
  162. break;
  163. case LCT_PALETTE:
  164. break;
  165. }
  166. break;
  167. default:
  168. break;
  169. }
  170. if (supported)
  171. {
  172. const uint8_t* copyData = data;
  173. TextureFormat::Enum dstFormat = format;
  174. if (1 == state.info_raw.bitdepth)
  175. {
  176. dstFormat = bimg::TextureFormat::R8;
  177. copyData = NULL;
  178. }
  179. else if (16 == state.info_raw.bitdepth
  180. && LCT_RGB == state.info_raw.colortype)
  181. {
  182. dstFormat = bimg::TextureFormat::RGBA16;
  183. copyData = NULL;
  184. }
  185. else if (palette)
  186. {
  187. copyData = NULL;
  188. }
  189. output = imageAlloc(_allocator
  190. , dstFormat
  191. , uint16_t(width)
  192. , uint16_t(height)
  193. , 0
  194. , 1
  195. , false
  196. , false
  197. , copyData
  198. );
  199. if (1 == state.info_raw.bitdepth)
  200. {
  201. for (uint32_t ii = 0, num = width*height/8; ii < num; ++ii)
  202. {
  203. uint8_t value = data[ii];
  204. uint8_t* dst = (uint8_t*)output->m_data + ii * 8;
  205. dst[0] = value & 0x01 ? 255 : 0;
  206. dst[1] = value & 0x02 ? 255 : 0;
  207. dst[2] = value & 0x04 ? 255 : 0;
  208. dst[3] = value & 0x08 ? 255 : 0;
  209. dst[4] = value & 0x10 ? 255 : 0;
  210. dst[5] = value & 0x20 ? 255 : 0;
  211. dst[6] = value & 0x40 ? 255 : 0;
  212. dst[7] = value & 0x80 ? 255 : 0;
  213. }
  214. }
  215. else if (16 == state.info_raw.bitdepth
  216. && LCT_RGB == state.info_raw.colortype)
  217. {
  218. for (uint32_t ii = 0, num = width*height; ii < num; ++ii)
  219. {
  220. const uint16_t* src = (uint16_t*)data + ii*3;
  221. uint16_t* dst = (uint16_t*)output->m_data + ii*4;
  222. dst[0] = src[0];
  223. dst[1] = src[1];
  224. dst[2] = src[2];
  225. dst[3] = UINT16_MAX;
  226. }
  227. }
  228. else if (palette)
  229. {
  230. for (uint32_t ii = 0, num = width*height; ii < num; ++ii)
  231. {
  232. bx::memCopy( (uint8_t*)output->m_data + ii*4, state.info_raw.palette + data[ii]*4, 4);
  233. }
  234. }
  235. }
  236. }
  237. lodepng_state_cleanup(&state);
  238. lodepng_free(data);
  239. return output;
  240. }
  241. static ImageContainer* imageParseTinyExr(bx::AllocatorI* _allocator, const void* _data, uint32_t _size, bx::Error* _err)
  242. {
  243. BX_ERROR_SCOPE(_err);
  244. EXRVersion exrVersion;
  245. int result = ParseEXRVersionFromMemory(&exrVersion, (uint8_t*)_data, _size);
  246. if (TINYEXR_SUCCESS != result)
  247. {
  248. return NULL;
  249. }
  250. bimg::TextureFormat::Enum format = bimg::TextureFormat::RGBA8;
  251. uint32_t width = 0;
  252. uint32_t height = 0;
  253. uint8_t* data = NULL;
  254. const char* err = NULL;
  255. EXRHeader exrHeader;
  256. result = ParseEXRHeaderFromMemory(&exrHeader, &exrVersion, (uint8_t*)_data, _size, &err);
  257. if (TINYEXR_SUCCESS == result)
  258. {
  259. EXRImage exrImage;
  260. InitEXRImage(&exrImage);
  261. result = LoadEXRImageFromMemory(&exrImage, &exrHeader, (uint8_t*)_data, _size, &err);
  262. if (TINYEXR_SUCCESS == result)
  263. {
  264. uint8_t idxR = UINT8_MAX;
  265. uint8_t idxG = UINT8_MAX;
  266. uint8_t idxB = UINT8_MAX;
  267. uint8_t idxA = UINT8_MAX;
  268. for (uint8_t ii = 0, num = uint8_t(exrHeader.num_channels); ii < num; ++ii)
  269. {
  270. const EXRChannelInfo& channel = exrHeader.channels[ii];
  271. if (UINT8_MAX == idxR
  272. && 0 == bx::strCmp(channel.name, "R") )
  273. {
  274. idxR = ii;
  275. }
  276. else if (UINT8_MAX == idxG
  277. && 0 == bx::strCmp(channel.name, "G") )
  278. {
  279. idxG = ii;
  280. }
  281. else if (UINT8_MAX == idxB
  282. && 0 == bx::strCmp(channel.name, "B") )
  283. {
  284. idxB = ii;
  285. }
  286. else if (UINT8_MAX == idxA
  287. && 0 == bx::strCmp(channel.name, "A") )
  288. {
  289. idxA = ii;
  290. }
  291. }
  292. if (UINT8_MAX != idxR)
  293. {
  294. const bool asFloat = exrHeader.pixel_types[idxR] == TINYEXR_PIXELTYPE_FLOAT;
  295. uint32_t srcBpp = 32;
  296. uint32_t dstBpp = asFloat ? 32 : 16;
  297. format = asFloat ? TextureFormat::R32F : TextureFormat::R16F;
  298. uint32_t stepR = 1;
  299. uint32_t stepG = 0;
  300. uint32_t stepB = 0;
  301. uint32_t stepA = 0;
  302. if (UINT8_MAX != idxG)
  303. {
  304. srcBpp += 32;
  305. dstBpp = asFloat ? 64 : 32;
  306. format = asFloat ? TextureFormat::RG32F : TextureFormat::RG16F;
  307. stepG = 1;
  308. }
  309. if (UINT8_MAX != idxB)
  310. {
  311. srcBpp += 32;
  312. dstBpp = asFloat ? 128 : 64;
  313. format = asFloat ? TextureFormat::RGBA32F : TextureFormat::RGBA16F;
  314. stepB = 1;
  315. }
  316. if (UINT8_MAX != idxA)
  317. {
  318. srcBpp += 32;
  319. dstBpp = asFloat ? 128 : 64;
  320. format = asFloat ? TextureFormat::RGBA32F : TextureFormat::RGBA16F;
  321. stepA = 1;
  322. }
  323. data = (uint8_t*)BX_ALLOC(_allocator, exrImage.width * exrImage.height * dstBpp/8);
  324. width = exrImage.width;
  325. height = exrImage.height;
  326. if (asFloat)
  327. {
  328. const float zero = 0.0f;
  329. const float* srcR = UINT8_MAX == idxR ? &zero : (const float*)(exrImage.images)[idxR];
  330. const float* srcG = UINT8_MAX == idxG ? &zero : (const float*)(exrImage.images)[idxG];
  331. const float* srcB = UINT8_MAX == idxB ? &zero : (const float*)(exrImage.images)[idxB];
  332. const float* srcA = UINT8_MAX == idxA ? &zero : (const float*)(exrImage.images)[idxA];
  333. const uint32_t bytesPerPixel = dstBpp/8;
  334. for (uint32_t ii = 0, num = exrImage.width * exrImage.height; ii < num; ++ii)
  335. {
  336. float rgba[4] =
  337. {
  338. *srcR,
  339. *srcG,
  340. *srcB,
  341. *srcA,
  342. };
  343. bx::memCopy(&data[ii * bytesPerPixel], rgba, bytesPerPixel);
  344. srcR += stepR;
  345. srcG += stepG;
  346. srcB += stepB;
  347. srcA += stepA;
  348. }
  349. }
  350. else
  351. {
  352. const uint16_t zero = 0;
  353. const uint16_t* srcR = UINT8_MAX == idxR ? &zero : (const uint16_t*)(exrImage.images)[idxR];
  354. const uint16_t* srcG = UINT8_MAX == idxG ? &zero : (const uint16_t*)(exrImage.images)[idxG];
  355. const uint16_t* srcB = UINT8_MAX == idxB ? &zero : (const uint16_t*)(exrImage.images)[idxB];
  356. const uint16_t* srcA = UINT8_MAX == idxA ? &zero : (const uint16_t*)(exrImage.images)[idxA];
  357. const uint32_t bytesPerPixel = dstBpp/8;
  358. for (uint32_t ii = 0, num = exrImage.width * exrImage.height; ii < num; ++ii)
  359. {
  360. uint16_t rgba[4] =
  361. {
  362. *srcR,
  363. *srcG,
  364. *srcB,
  365. *srcA,
  366. };
  367. bx::memCopy(&data[ii * bytesPerPixel], rgba, bytesPerPixel);
  368. srcR += stepR;
  369. srcG += stepG;
  370. srcB += stepB;
  371. srcA += stepA;
  372. }
  373. }
  374. }
  375. FreeEXRImage(&exrImage);
  376. }
  377. FreeEXRHeader(&exrHeader);
  378. }
  379. ImageContainer* output = NULL;
  380. if (NULL != data)
  381. {
  382. output = imageAlloc(_allocator
  383. , format
  384. , uint16_t(width)
  385. , uint16_t(height)
  386. , 0
  387. , 1
  388. , false
  389. , false
  390. , data
  391. );
  392. BX_FREE(_allocator, data);
  393. }
  394. return output;
  395. }
  396. static ImageContainer* imageParseStbImage(bx::AllocatorI* _allocator, const void* _data, uint32_t _size, bx::Error* _err)
  397. {
  398. BX_ERROR_SCOPE(_err);
  399. const int isHdr = stbi_is_hdr_from_memory((const uint8_t*)_data, (int)_size);
  400. void* data;
  401. uint32_t width = 0;
  402. uint32_t height = 0;
  403. int comp = 0;
  404. if (isHdr) { data = stbi_loadf_from_memory((const uint8_t*)_data, (int)_size, (int*)&width, (int*)&height, &comp, 4); }
  405. else { data = stbi_load_from_memory ((const uint8_t*)_data, (int)_size, (int*)&width, (int*)&height, &comp, 0); }
  406. if (NULL == data)
  407. {
  408. return NULL;
  409. }
  410. bimg::TextureFormat::Enum format;
  411. if (isHdr)
  412. {
  413. format = bimg::TextureFormat::RGBA32F;
  414. }
  415. else
  416. {
  417. if (1 == comp) { format = bimg::TextureFormat::R8; }
  418. else if (2 == comp) { format = bimg::TextureFormat::RG8; }
  419. else if (3 == comp) { format = bimg::TextureFormat::RGB8; }
  420. else/*if (4 == comp)*/ { format = bimg::TextureFormat::RGBA8; }
  421. }
  422. ImageContainer* output = imageAlloc(_allocator
  423. , format
  424. , uint16_t(width)
  425. , uint16_t(height)
  426. , 0
  427. , 1
  428. , false
  429. , false
  430. , data
  431. );
  432. stbi_image_free(data);
  433. return output;
  434. }
  435. ImageContainer* imageParse(bx::AllocatorI* _allocator, const void* _data, uint32_t _size, TextureFormat::Enum _dstFormat, bx::Error* _err)
  436. {
  437. BX_ERROR_SCOPE(_err);
  438. ImageContainer* input = imageParseDds (_allocator, _data, _size, _err) ;
  439. input = NULL == input ? imageParseKtx (_allocator, _data, _size, _err) : input;
  440. input = NULL == input ? imageParsePvr3 (_allocator, _data, _size, _err) : input;
  441. input = NULL == input ? imageParseLodePng (_allocator, _data, _size, _err) : input;
  442. input = NULL == input ? imageParseTinyExr (_allocator, _data, _size, _err) : input;
  443. input = NULL == input ? imageParseStbImage(_allocator, _data, _size, _err) : input;
  444. if (NULL == input)
  445. {
  446. return NULL;
  447. }
  448. _dstFormat = TextureFormat::Count == _dstFormat
  449. ? input->m_format
  450. : _dstFormat
  451. ;
  452. if (_dstFormat == input->m_format)
  453. {
  454. return input;
  455. }
  456. ImageContainer* output = imageConvert(_allocator, _dstFormat, *input);
  457. imageFree(input);
  458. return output;
  459. }
  460. } // namespace bimg