bitmapPng.cc 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2013 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include "io/stream.h"
  23. #include "io/fileStream.h"
  24. #include "io/memstream.h"
  25. #include "graphics/gPalette.h"
  26. #include "graphics/gBitmap.h"
  27. #include "memory/frameAllocator.h"
  28. //-Mat used when checking for palleted textures
  29. #include "console/console.h"
  30. bool sgForcePalletedPNGsTo16Bit= false;
  31. #define PNG_INTERNAL 1
  32. // Ignore PNG time chunks
  33. #define PNG_NO_READ_TIME
  34. #define PNG_NO_WRITE_TIME
  35. #include <time.h>
  36. #include "png.h"
  37. #include "zlib.h"
  38. // Our chunk signatures...
  39. static const U32 csgMaxRowPointers = (1 << GBitmap::c_maxMipLevels) - 1; ///< 2^11 = 2048, 12 mip levels (see c_maxMipLievels)
  40. static png_bytep sRowPointers[csgMaxRowPointers];
  41. //-------------------------------------- Instead of using the user_ptr,
  42. // we use a global pointer, we
  43. // need to ensure that only one thread
  44. // at once may be using the variable.
  45. // NOTE: Removed mutex for g_varAccess.
  46. // may have to re-thread safe this.
  47. static Stream* sg_pStream = NULL;
  48. //-------------------------------------- Replacement I/O for standard LIBPng
  49. // functions. we don't wanna use
  50. // FILE*'s...
  51. static void pngReadDataFn(png_structp /*png_ptr*/,
  52. png_bytep data,
  53. png_size_t length)
  54. {
  55. AssertFatal(sg_pStream != NULL, "No stream?");
  56. bool success;
  57. success = sg_pStream->read((U32)length, data);
  58. AssertFatal(success, "PNG read catastrophic error!");
  59. }
  60. //--------------------------------------
  61. static void pngWriteDataFn(png_structp /*png_ptr*/,
  62. png_bytep data,
  63. png_size_t length)
  64. {
  65. AssertFatal(sg_pStream != NULL, "No stream?");
  66. sg_pStream->write((U32)length, data);
  67. }
  68. //--------------------------------------
  69. static void pngFlushDataFn(png_structp /*png_ptr*/)
  70. {
  71. //
  72. }
  73. static png_voidp pngMallocFn(png_structp /*png_ptr*/, png_size_t size)
  74. {
  75. #ifndef _WIN64
  76. return FrameAllocator::alloc((U32)size);
  77. #else
  78. return (png_voidp)dMalloc(size);
  79. #endif
  80. }
  81. static void pngFreeFn(png_structp /*png_ptr*/, png_voidp mem)
  82. {
  83. #ifdef _WIN64
  84. dFree(mem);
  85. #endif
  86. }
  87. //--------------------------------------
  88. static void pngFatalErrorFn(png_structp /*png_ptr*/,
  89. png_const_charp pMessage)
  90. {
  91. AssertISV(false, avar("Error reading PNG file:\n %s", pMessage));
  92. }
  93. //--------------------------------------
  94. static void pngWarningFn(png_structp, png_const_charp pMessage)
  95. {
  96. AssertWarn(false, avar("Warning reading PNG file:\n %s", pMessage));
  97. }
  98. //--------------------------------------
  99. bool GBitmap::readPNG(Stream& io_rStream)
  100. {
  101. static const U32 cs_headerBytesChecked = 8;
  102. U8 header[cs_headerBytesChecked];
  103. io_rStream.read(cs_headerBytesChecked, header);
  104. bool isPng = (png_check_sig(header, cs_headerBytesChecked)) != 0;
  105. if (isPng == false)
  106. {
  107. AssertWarn(false, "GBitmap::readPNG: stream doesn't contain a PNG");
  108. return false;
  109. }
  110. U32 prevWaterMark = FrameAllocator::getWaterMark();
  111. #if defined(PNG_USER_MEM_SUPPORTED)
  112. png_structp png_ptr = png_create_read_struct_2(PNG_LIBPNG_VER_STRING,
  113. NULL,
  114. pngFatalErrorFn,
  115. pngWarningFn,
  116. NULL,
  117. pngMallocFn,
  118. pngFreeFn);
  119. #else
  120. png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
  121. NULL,
  122. pngFatalErrorFn,
  123. pngWarningFn);
  124. #endif
  125. if (png_ptr == NULL)
  126. {
  127. FrameAllocator::setWaterMark(prevWaterMark);
  128. return false;
  129. }
  130. png_infop info_ptr = png_create_info_struct(png_ptr);
  131. if (info_ptr == NULL) {
  132. png_destroy_read_struct(&png_ptr,
  133. (png_infopp)NULL,
  134. (png_infopp)NULL);
  135. FrameAllocator::setWaterMark(prevWaterMark);
  136. return false;
  137. }
  138. png_infop end_info = png_create_info_struct(png_ptr);
  139. if (end_info == NULL) {
  140. png_destroy_read_struct(&png_ptr,
  141. &info_ptr,
  142. (png_infopp)NULL);
  143. FrameAllocator::setWaterMark(prevWaterMark);
  144. return false;
  145. }
  146. sg_pStream = &io_rStream;
  147. png_set_read_fn(png_ptr, NULL, pngReadDataFn);
  148. // Read off the info on the image.
  149. png_set_sig_bytes(png_ptr, cs_headerBytesChecked);
  150. png_read_info(png_ptr, info_ptr);
  151. // OK, at this point, if we have reached it ok, then we can reset the
  152. // image to accept the new data...
  153. //
  154. deleteImage();
  155. png_uint_32 width;
  156. png_uint_32 height;
  157. S32 bit_depth;
  158. S32 color_type;
  159. png_get_IHDR(png_ptr, info_ptr,
  160. &width, &height, // obv.
  161. &bit_depth, &color_type, // obv.
  162. NULL, // interlace
  163. NULL, // compression_type
  164. NULL); // filter_type
  165. // First, handle the color transformations. We need this to read in the
  166. // data as RGB or RGBA, _always_, with a maximal channel width of 8 bits.
  167. //
  168. bool transAlpha = false;
  169. BitmapFormat format = RGB;
  170. // Strip off any 16 bit info
  171. //
  172. if (bit_depth == 16) {
  173. png_set_strip_16(png_ptr);
  174. }
  175. // Expand a transparency channel into a full alpha channel...
  176. //
  177. if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
  178. png_set_expand(png_ptr);
  179. transAlpha = true;
  180. }
  181. if (color_type == PNG_COLOR_TYPE_PALETTE)
  182. {
  183. png_set_expand(png_ptr);
  184. format = transAlpha ? RGBA : RGB;
  185. }
  186. else if (color_type == PNG_COLOR_TYPE_GRAY)
  187. {
  188. png_set_expand(png_ptr);
  189. //png_set_gray_to_rgb(png_ptr);
  190. format = Alpha; //transAlpha ? RGBA : RGB;
  191. }
  192. else if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
  193. {
  194. png_set_expand(png_ptr);
  195. png_set_gray_to_rgb(png_ptr);
  196. format = RGBA;
  197. }
  198. else if (color_type == PNG_COLOR_TYPE_RGB)
  199. {
  200. format = transAlpha ? RGBA : RGB;
  201. png_set_expand(png_ptr);
  202. }
  203. else if (color_type == PNG_COLOR_TYPE_RGB_ALPHA)
  204. {
  205. png_set_expand(png_ptr);
  206. format = RGBA;
  207. }
  208. // Update the info pointer with the result of the transformations
  209. // above...
  210. png_set_interlace_handling(png_ptr);
  211. png_read_update_info(png_ptr, info_ptr);
  212. png_uint_32 rowBytes = (png_uint_32)png_get_rowbytes(png_ptr, info_ptr);
  213. if (format == RGB) {
  214. AssertFatal(rowBytes == width * 3,
  215. "Error, our rowbytes are incorrect for this transform... (3)");
  216. }
  217. else if (format == RGBA)
  218. {
  219. AssertFatal(rowBytes == width * 4,
  220. "Error, our rowbytes are incorrect for this transform... (4)");
  221. }
  222. // actually allocate the bitmap space...
  223. allocateBitmap(width, height,
  224. false, // don't extrude miplevels...
  225. format); // use determined format...
  226. // Set up the row pointers...
  227. AssertISV(height <= csgMaxRowPointers, "Error, cannot load pngs taller than 2048 pixels!");
  228. png_bytep* rowPointers = sRowPointers;
  229. U8* pBase = (U8*)getBits();
  230. for (U32 i = 0; i < height; i++)
  231. rowPointers[i] = pBase + (i * rowBytes);
  232. // And actually read the image!
  233. png_read_image(png_ptr, rowPointers);
  234. // We're outta here, destroy the png structs, and release the lock
  235. // as quickly as possible...
  236. //png_read_end(png_ptr, end_info);
  237. png_read_end(png_ptr, NULL);
  238. png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
  239. sg_pStream = NULL;
  240. // Ok, the image is read in, now we need to finish up the initialization,
  241. // which means: setting up the detailing members, init'ing the palette
  242. // key, etc...
  243. //
  244. // actually, all of that was handled by allocateBitmap, so we're outta here
  245. //
  246. FrameAllocator::setWaterMark(prevWaterMark);
  247. //
  248. //-Mat if all palleted images are to be converted, set mForce16bit
  249. if( color_type == PNG_COLOR_TYPE_PALETTE ) {
  250. sgForcePalletedPNGsTo16Bit = dAtob( Con::getVariable("$pref::iPhone::ForcePalletedPNGsTo16Bit") );
  251. if( sgForcePalletedPNGsTo16Bit ) {
  252. mForce16Bit = true;
  253. }
  254. }
  255. return true;
  256. }
  257. //--------------------------------------------------------------------------
  258. bool GBitmap::_writePNG(Stream& stream,
  259. const U32 compressionLevel,
  260. const U32 strategy,
  261. const U32 filter) const
  262. {
  263. // ONLY RGB bitmap writing supported at this time!
  264. AssertFatal(getFormat() == RGB || getFormat() == RGBA || getFormat() == Alpha, "GBitmap::writePNG: ONLY RGB bitmap writing supported at this time.");
  265. if (internalFormat != RGB && internalFormat != RGBA && internalFormat != Alpha)
  266. return (false);
  267. #define MAX_HEIGHT 4096
  268. if (height >= MAX_HEIGHT)
  269. return (false);
  270. #if defined(PNG_USER_MEM_SUPPORTED)
  271. png_structp png_ptr = png_create_write_struct_2(PNG_LIBPNG_VER_STRING,
  272. NULL,
  273. pngFatalErrorFn,
  274. pngWarningFn,
  275. NULL,
  276. pngMallocFn,
  277. pngFreeFn);
  278. #else
  279. png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
  280. NULL,
  281. pngFatalErrorFn,
  282. pngWarningFn);
  283. #endif
  284. if (png_ptr == NULL)
  285. return (false);
  286. png_infop info_ptr = png_create_info_struct(png_ptr);
  287. if (info_ptr == NULL)
  288. {
  289. png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
  290. return false;
  291. }
  292. sg_pStream = &stream;
  293. png_set_write_fn(png_ptr, NULL, pngWriteDataFn, pngFlushDataFn);
  294. // Set the compression level, image filters, and compression strategy...
  295. png_set_compression_strategy( png_ptr, strategy );
  296. png_set_compression_window_bits(png_ptr, 15);
  297. png_set_compression_level(png_ptr, compressionLevel);
  298. png_set_filter(png_ptr, 0, filter);
  299. // Set the image information here. Width and height are up to 2^31,
  300. // bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on
  301. // the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY,
  302. // PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB,
  303. // or PNG_COLOR_TYPE_RGB_ALPHA. interlace is either PNG_INTERLACE_NONE or
  304. // PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST
  305. // currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED
  306. if (getFormat() == RGB) {
  307. png_set_IHDR(png_ptr, info_ptr,
  308. width, height, // the width & height
  309. 8, PNG_COLOR_TYPE_RGB, // bit_depth, color_type,
  310. PNG_INTERLACE_NONE, // no interlace
  311. PNG_COMPRESSION_TYPE_BASE, // compression type
  312. PNG_FILTER_TYPE_BASE); // filter type
  313. }
  314. else if (getFormat() == RGBA) {
  315. png_set_IHDR(png_ptr, info_ptr,
  316. width, height, // the width & height
  317. 8, PNG_COLOR_TYPE_RGB_ALPHA, // bit_depth, color_type,
  318. PNG_INTERLACE_NONE, // no interlace
  319. PNG_COMPRESSION_TYPE_BASE, // compression type
  320. PNG_FILTER_TYPE_BASE); // filter type
  321. }
  322. else if (getFormat() == Alpha) {
  323. png_set_IHDR(png_ptr, info_ptr,
  324. width, height, // the width & height
  325. 8, PNG_COLOR_TYPE_GRAY, // bit_depth, color_type,
  326. PNG_INTERLACE_NONE, // no interlace
  327. PNG_COMPRESSION_TYPE_BASE, // compression type
  328. PNG_FILTER_TYPE_BASE); // filter type
  329. }
  330. png_write_info(png_ptr, info_ptr);
  331. png_bytep row_pointers[MAX_HEIGHT];
  332. for (U32 i=0; i<height; i++)
  333. row_pointers[i] = const_cast<png_bytep>(getAddress(0, i));
  334. png_write_image(png_ptr, row_pointers);
  335. // Write S3TC data if present...
  336. // Write FXT1 data if present...
  337. png_write_end(png_ptr, info_ptr);
  338. png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
  339. return true;
  340. }
  341. //--------------------------------------------------------------------------
  342. bool GBitmap::writePNG(Stream& stream, const bool compressHard) const
  343. {
  344. U32 waterMark = FrameAllocator::getWaterMark();
  345. if (compressHard == false) {
  346. bool retVal = _writePNG(stream, 6, 0, PNG_ALL_FILTERS);
  347. FrameAllocator::setWaterMark(waterMark);
  348. return retVal;
  349. } else {
  350. U8* buffer = new U8[1 << 22]; // 4 Megs. Should be enough...
  351. MemStream* pMemStream = new MemStream(1 << 22, buffer, false, true);
  352. // We have to try the potentially useful compression methods here.
  353. const U32 zStrategies[] = { Z_DEFAULT_STRATEGY,
  354. Z_FILTERED };
  355. const U32 pngFilters[] = { PNG_FILTER_NONE,
  356. PNG_FILTER_SUB,
  357. PNG_FILTER_UP,
  358. PNG_FILTER_AVG,
  359. PNG_FILTER_PAETH,
  360. PNG_ALL_FILTERS };
  361. U32 minSize = 0xFFFFFFFF;
  362. U32 bestStrategy = 0xFFFFFFFF;
  363. U32 bestFilter = 0xFFFFFFFF;
  364. U32 bestCLevel = 0xFFFFFFFF;
  365. for (U32 cl = 0; cl <=9; cl++)
  366. {
  367. for (U32 zs = 0; zs < 2; zs++)
  368. {
  369. for (U32 pf = 0; pf < 6; pf++)
  370. {
  371. pMemStream->setPosition(0);
  372. if (_writePNG(*pMemStream, cl, zStrategies[zs], pngFilters[pf]) == false)
  373. AssertFatal(false, "PNG output failed!");
  374. if (pMemStream->getPosition() < minSize)
  375. {
  376. minSize = pMemStream->getPosition();
  377. bestStrategy = zs;
  378. bestFilter = pf;
  379. bestCLevel = cl;
  380. }
  381. }
  382. }
  383. }
  384. AssertFatal(minSize != 0xFFFFFFFF, "Error, no best found?");
  385. delete pMemStream;
  386. delete [] buffer;
  387. bool retVal = _writePNG(stream,
  388. bestCLevel,
  389. zStrategies[bestStrategy],
  390. pngFilters[bestFilter]);
  391. FrameAllocator::setWaterMark(waterMark);
  392. return retVal;
  393. }
  394. }
  395. //--------------------------------------------------------------------------
  396. bool GBitmap::writePNGUncompressed(Stream& stream) const
  397. {
  398. U32 waterMark = FrameAllocator::getWaterMark();
  399. bool retVal = _writePNG(stream, 0, 0, PNG_FILTER_NONE);
  400. FrameAllocator::setWaterMark(waterMark);
  401. return retVal;
  402. }