bitmapPng.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 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 "platform/platform.h"
  23. #include "core/stream/fileStream.h"
  24. #include "core/stream/memStream.h"
  25. #include "core/strings/stringFunctions.h"
  26. #include "gfx/bitmap/gBitmap.h"
  27. #include "gfx/bitmap/pngUtils.h"
  28. #define PNG_INTERNAL 1
  29. #include <time.h>
  30. #include "lpng/png.h"
  31. #include "zlib/zlib.h"
  32. #ifdef NULL
  33. #undef NULL
  34. #define NULL 0
  35. #endif
  36. static bool sReadPNG(Stream &stream, GBitmap *bitmap);
  37. /// Compression levels for PNGs range from 0-9.
  38. /// A value outside that range will cause the write routine to look for the best compression for a given PNG. This can be slow.
  39. static bool sWritePNG(GBitmap *bitmap, Stream &stream, U32 compressionLevel);
  40. static bool _writePNG(GBitmap *bitmap, Stream &stream, U32 compressionLevel, U32 strategy, U32 filter);
  41. static struct _privateRegisterPNG
  42. {
  43. _privateRegisterPNG()
  44. {
  45. GBitmap::Registration reg;
  46. reg.priority = 100;
  47. reg.extensions.push_back( "png" );
  48. reg.readFunc = sReadPNG;
  49. reg.writeFunc = sWritePNG;
  50. reg.defaultCompression = 6;
  51. GBitmap::sRegisterFormat( reg );
  52. }
  53. } sStaticRegisterPNG;
  54. //-------------------------------------- Replacement I/O for standard LIBPng
  55. // functions. we don't wanna use
  56. // FILE*'s...
  57. static void pngReadDataFn(png_structp png_ptr,
  58. png_bytep data,
  59. png_size_t length)
  60. {
  61. AssertFatal(png_ptr->io_ptr != NULL, "No stream?");
  62. Stream *strm = (Stream*)png_ptr->io_ptr;
  63. bool success = strm->read(length, data);
  64. AssertFatal(success, "pngReadDataFn - failed to read from stream!");
  65. }
  66. //--------------------------------------
  67. static void pngWriteDataFn(png_structp png_ptr,
  68. png_bytep data,
  69. png_size_t length)
  70. {
  71. AssertFatal(png_ptr->io_ptr != NULL, "No stream?");
  72. Stream *strm = (Stream*)png_ptr->io_ptr;
  73. bool success = strm->write(length, data);
  74. AssertFatal(success, "pngWriteDataFn - failed to write to stream!");
  75. }
  76. //--------------------------------------
  77. static void pngFlushDataFn(png_structp /*png_ptr*/)
  78. {
  79. //
  80. }
  81. static png_voidp pngMallocFn(png_structp /*png_ptr*/, png_size_t size)
  82. {
  83. return FrameAllocator::alloc(size);
  84. }
  85. static void pngFreeFn(png_structp /*png_ptr*/, png_voidp /*mem*/)
  86. {
  87. }
  88. static png_voidp pngRealMallocFn(png_structp /*png_ptr*/, png_size_t size)
  89. {
  90. return (png_voidp)dMalloc(size);
  91. }
  92. static void pngRealFreeFn(png_structp /*png_ptr*/, png_voidp mem)
  93. {
  94. dFree(mem);
  95. }
  96. //--------------------------------------
  97. static void pngFatalErrorFn(png_structp /*png_ptr*/,
  98. png_const_charp pMessage)
  99. {
  100. AssertISV(false, avar("Error reading PNG file:\n %s", pMessage));
  101. }
  102. //--------------------------------------
  103. static void pngWarningFn(png_structp, png_const_charp /*pMessage*/)
  104. {
  105. // AssertWarn(false, avar("Warning reading PNG file:\n %s", pMessage));
  106. }
  107. //--------------------------------------
  108. static bool sReadPNG(Stream &stream, GBitmap *bitmap)
  109. {
  110. static const U32 cs_headerBytesChecked = 8;
  111. U8 header[cs_headerBytesChecked];
  112. stream.read(cs_headerBytesChecked, header);
  113. bool isPng = png_check_sig(header, cs_headerBytesChecked) != 0;
  114. if (isPng == false)
  115. {
  116. AssertWarn(false, "GBitmap::readPNG: stream doesn't contain a PNG");
  117. return false;
  118. }
  119. U32 prevWaterMark = FrameAllocator::getWaterMark();
  120. png_structp png_ptr = png_create_read_struct_2(PNG_LIBPNG_VER_STRING,
  121. NULL,
  122. pngFatalErrorFn,
  123. pngWarningFn,
  124. NULL,
  125. pngRealMallocFn,
  126. pngRealFreeFn);
  127. if (png_ptr == NULL)
  128. {
  129. FrameAllocator::setWaterMark(prevWaterMark);
  130. return false;
  131. }
  132. png_infop info_ptr = png_create_info_struct(png_ptr);
  133. if (info_ptr == NULL)
  134. {
  135. png_destroy_read_struct(&png_ptr,
  136. (png_infopp)NULL,
  137. (png_infopp)NULL);
  138. FrameAllocator::setWaterMark(prevWaterMark);
  139. return false;
  140. }
  141. png_infop end_info = png_create_info_struct(png_ptr);
  142. if (end_info == NULL)
  143. {
  144. png_destroy_read_struct(&png_ptr,
  145. &info_ptr,
  146. (png_infopp)NULL);
  147. FrameAllocator::setWaterMark(prevWaterMark);
  148. return false;
  149. }
  150. png_set_read_fn(png_ptr, &stream, pngReadDataFn);
  151. // Read off the info on the image.
  152. png_set_sig_bytes(png_ptr, cs_headerBytesChecked);
  153. png_read_info(png_ptr, info_ptr);
  154. // OK, at this point, if we have reached it ok, then we can reset the
  155. // image to accept the new data...
  156. //
  157. bitmap->deleteImage();
  158. png_uint_32 width;
  159. png_uint_32 height;
  160. S32 bit_depth;
  161. S32 color_type;
  162. png_get_IHDR(png_ptr, info_ptr,
  163. &width, &height, // obv.
  164. &bit_depth, &color_type, // obv.
  165. NULL, // interlace
  166. NULL, // compression_type
  167. NULL); // filter_type
  168. // First, handle the color transformations. We need this to read in the
  169. // data as RGB or RGBA, _always_, with a maximal channel width of 8 bits.
  170. //
  171. bool transAlpha = false;
  172. GFXFormat format = GFXFormatR8G8B8;
  173. // Strip off any 16 bit info
  174. //
  175. if (bit_depth == 16 && color_type != PNG_COLOR_TYPE_GRAY)
  176. {
  177. png_set_strip_16(png_ptr);
  178. }
  179. // Expand a transparency channel into a full alpha channel...
  180. //
  181. if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
  182. {
  183. png_set_expand(png_ptr);
  184. transAlpha = true;
  185. }
  186. if (color_type == PNG_COLOR_TYPE_PALETTE)
  187. {
  188. png_set_expand(png_ptr);
  189. format = transAlpha ? GFXFormatR8G8B8A8 : GFXFormatR8G8B8;
  190. }
  191. else if (color_type == PNG_COLOR_TYPE_GRAY)
  192. {
  193. png_set_expand(png_ptr);
  194. if (bit_depth == 16)
  195. format = GFXFormatR5G6B5;
  196. else
  197. format = GFXFormatA8;
  198. }
  199. else if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
  200. {
  201. png_set_expand(png_ptr);
  202. png_set_gray_to_rgb(png_ptr);
  203. format = GFXFormatR8G8B8A8;
  204. }
  205. else if (color_type == PNG_COLOR_TYPE_RGB)
  206. {
  207. format = transAlpha ? GFXFormatR8G8B8A8 : GFXFormatR8G8B8;
  208. png_set_expand(png_ptr);
  209. }
  210. else if (color_type == PNG_COLOR_TYPE_RGB_ALPHA)
  211. {
  212. png_set_expand(png_ptr);
  213. format = GFXFormatR8G8B8A8;
  214. }
  215. // Update the info pointer with the result of the transformations
  216. // above...
  217. png_read_update_info(png_ptr, info_ptr);
  218. png_uint_32 rowBytes = png_get_rowbytes(png_ptr, info_ptr);
  219. if (format == GFXFormatR8G8B8)
  220. {
  221. AssertFatal(rowBytes == width * 3,
  222. "Error, our rowbytes are incorrect for this transform... (3)");
  223. }
  224. else if (format == GFXFormatR8G8B8A8)
  225. {
  226. AssertFatal(rowBytes == width * 4,
  227. "Error, our rowbytes are incorrect for this transform... (4)");
  228. }
  229. else if (format == GFXFormatR5G6B5)
  230. {
  231. AssertFatal(rowBytes == width * 2,
  232. "Error, our rowbytes are incorrect for this transform... (2)");
  233. }
  234. // actually allocate the bitmap space...
  235. bitmap->allocateBitmap(width, height,
  236. false, // don't extrude miplevels...
  237. format); // use determined format...
  238. // Set up the row pointers...
  239. png_bytep* rowPointers = new png_bytep[ height ];
  240. U8* pBase = (U8*)bitmap->getBits();
  241. for (U32 i = 0; i < height; i++)
  242. rowPointers[i] = pBase + (i * rowBytes);
  243. // And actually read the image!
  244. png_read_image(png_ptr, rowPointers);
  245. // We're outta here, destroy the png structs, and release the lock
  246. // as quickly as possible...
  247. //png_read_end(png_ptr, end_info);
  248. delete [] rowPointers;
  249. png_read_end(png_ptr, NULL);
  250. png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
  251. // Ok, the image is read in, now we need to finish up the initialization,
  252. // which means: setting up the detailing members, init'ing the palette
  253. // key, etc...
  254. //
  255. // actually, all of that was handled by allocateBitmap, so we're outta here
  256. //
  257. // Check this bitmap for transparency
  258. bitmap->checkForTransparency();
  259. FrameAllocator::setWaterMark(prevWaterMark);
  260. return true;
  261. }
  262. //--------------------------------------------------------------------------
  263. static bool _writePNG(GBitmap *bitmap, Stream &stream, U32 compressionLevel, U32 strategy, U32 filter)
  264. {
  265. GFXFormat format = bitmap->getFormat();
  266. // ONLY RGB bitmap writing supported at this time!
  267. AssertFatal( format == GFXFormatR8G8B8 ||
  268. format == GFXFormatR8G8B8A8 ||
  269. format == GFXFormatR8G8B8X8 ||
  270. format == GFXFormatA8 ||
  271. format == GFXFormatR5G6B5, "_writePNG: ONLY RGB bitmap writing supported at this time.");
  272. if ( format != GFXFormatR8G8B8 &&
  273. format != GFXFormatR8G8B8A8 &&
  274. format != GFXFormatR8G8B8X8 &&
  275. format != GFXFormatA8 &&
  276. format != GFXFormatR5G6B5 )
  277. return false;
  278. png_structp png_ptr = png_create_write_struct_2(PNG_LIBPNG_VER_STRING,
  279. NULL,
  280. pngFatalErrorFn,
  281. pngWarningFn,
  282. NULL,
  283. pngMallocFn,
  284. pngFreeFn);
  285. if (png_ptr == NULL)
  286. return (false);
  287. png_infop info_ptr = png_create_info_struct(png_ptr);
  288. if (info_ptr == NULL)
  289. {
  290. png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
  291. return false;
  292. }
  293. png_set_write_fn(png_ptr, &stream, pngWriteDataFn, pngFlushDataFn);
  294. // Set the compression level, image filters, and compression strategy...
  295. png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_STRATEGY;
  296. png_ptr->zlib_strategy = strategy;
  297. png_set_compression_window_bits(png_ptr, 15);
  298. png_set_compression_level(png_ptr, compressionLevel);
  299. png_set_filter(png_ptr, 0, filter);
  300. // Set the image information here. Width and height are up to 2^31,
  301. // bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on
  302. // the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY,
  303. // PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB,
  304. // or PNG_COLOR_TYPE_RGB_ALPHA. interlace is either PNG_INTERLACE_NONE or
  305. // PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST
  306. // currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED
  307. U32 width = bitmap->getWidth();
  308. U32 height = bitmap->getHeight();
  309. if (format == GFXFormatR8G8B8)
  310. {
  311. png_set_IHDR(png_ptr, info_ptr,
  312. width, height, // the width & height
  313. 8, PNG_COLOR_TYPE_RGB, // bit_depth, color_type,
  314. NULL, // no interlace
  315. NULL, // compression type
  316. NULL); // filter type
  317. }
  318. else if (format == GFXFormatR8G8B8A8 || format == GFXFormatR8G8B8X8)
  319. {
  320. png_set_IHDR(png_ptr, info_ptr,
  321. width, height, // the width & height
  322. 8, PNG_COLOR_TYPE_RGB_ALPHA, // bit_depth, color_type,
  323. NULL, // no interlace
  324. NULL, // compression type
  325. NULL); // filter type
  326. }
  327. else if (format == GFXFormatA8)
  328. {
  329. png_set_IHDR(png_ptr, info_ptr,
  330. width, height, // the width & height
  331. 8, PNG_COLOR_TYPE_GRAY, // bit_depth, color_type,
  332. NULL, // no interlace
  333. NULL, // compression type
  334. NULL); // filter type
  335. }
  336. else if (format == GFXFormatR5G6B5)
  337. {
  338. png_set_IHDR(png_ptr, info_ptr,
  339. width, height, // the width & height
  340. 16, PNG_COLOR_TYPE_GRAY, // bit_depth, color_type,
  341. PNG_INTERLACE_NONE, // no interlace
  342. PNG_COMPRESSION_TYPE_DEFAULT, // compression type
  343. PNG_FILTER_TYPE_DEFAULT); // filter type
  344. png_color_8_struct sigBit = { 0 };
  345. sigBit.gray = 16;
  346. png_set_sBIT(png_ptr, info_ptr, &sigBit );
  347. png_set_swap( png_ptr );
  348. }
  349. png_write_info(png_ptr, info_ptr);
  350. FrameAllocatorMarker marker;
  351. png_bytep* row_pointers = (png_bytep*)marker.alloc( height * sizeof( png_bytep ) );
  352. for (U32 i=0; i<height; i++)
  353. row_pointers[i] = const_cast<png_bytep>(bitmap->getAddress(0, i));
  354. png_write_image(png_ptr, row_pointers);
  355. // Write S3TC data if present...
  356. // Write FXT1 data if present...
  357. png_write_end(png_ptr, info_ptr);
  358. png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
  359. return true;
  360. }
  361. //--------------------------------------------------------------------------
  362. static bool sWritePNG(GBitmap *bitmap, Stream &stream, U32 compressionLevel)
  363. {
  364. U32 waterMark = FrameAllocator::getWaterMark();
  365. if ( compressionLevel < 10 )
  366. {
  367. bool retVal = _writePNG(bitmap, stream, compressionLevel, 0, PNG_ALL_FILTERS);
  368. FrameAllocator::setWaterMark(waterMark);
  369. return retVal;
  370. }
  371. // check all our methods of compression to find the best one and use it
  372. U8* buffer = new U8[1 << 22]; // 4 Megs. Should be enough...
  373. MemStream* pMemStream = new MemStream(1 << 22, buffer, false, true);
  374. const U32 zStrategies[] = { Z_DEFAULT_STRATEGY,
  375. Z_FILTERED };
  376. const U32 pngFilters[] = { PNG_FILTER_NONE,
  377. PNG_FILTER_SUB,
  378. PNG_FILTER_UP,
  379. PNG_FILTER_AVG,
  380. PNG_FILTER_PAETH,
  381. PNG_ALL_FILTERS };
  382. U32 minSize = 0xFFFFFFFF;
  383. U32 bestStrategy = 0xFFFFFFFF;
  384. U32 bestFilter = 0xFFFFFFFF;
  385. U32 bestCLevel = 0xFFFFFFFF;
  386. for (U32 cl = 0; cl <=9; cl++)
  387. {
  388. for (U32 zs = 0; zs < 2; zs++)
  389. {
  390. for (U32 pf = 0; pf < 6; pf++)
  391. {
  392. pMemStream->setPosition(0);
  393. U32 waterMarkInner = FrameAllocator::getWaterMark();
  394. if (_writePNG(bitmap, *pMemStream, cl, zStrategies[zs], pngFilters[pf]) == false)
  395. AssertFatal(false, "Handle this error!");
  396. FrameAllocator::setWaterMark(waterMarkInner);
  397. if (pMemStream->getPosition() < minSize)
  398. {
  399. minSize = pMemStream->getPosition();
  400. bestStrategy = zs;
  401. bestFilter = pf;
  402. bestCLevel = cl;
  403. }
  404. }
  405. }
  406. }
  407. AssertFatal(minSize != 0xFFFFFFFF, "Error, no best found?");
  408. delete pMemStream;
  409. delete [] buffer;
  410. bool retVal = _writePNG(bitmap, stream,
  411. bestCLevel,
  412. zStrategies[bestStrategy],
  413. pngFilters[bestFilter]);
  414. FrameAllocator::setWaterMark(waterMark);
  415. return retVal;
  416. }
  417. //--------------------------------------------------------------------------
  418. // Stores PNG stream data
  419. struct DeferredPNGWriterData {
  420. png_structp png_ptr;
  421. png_infop info_ptr;
  422. U32 width;
  423. U32 height;
  424. };
  425. DeferredPNGWriter::DeferredPNGWriter() :
  426. mData( NULL ),
  427. mActive(false)
  428. {
  429. mData = new DeferredPNGWriterData();
  430. }
  431. DeferredPNGWriter::~DeferredPNGWriter()
  432. {
  433. delete mData;
  434. }
  435. bool DeferredPNGWriter::begin( GFXFormat format, S32 width, S32 height, Stream &stream, U32 compressionLevel )
  436. {
  437. // ONLY RGB bitmap writing supported at this time!
  438. AssertFatal( format == GFXFormatR8G8B8 ||
  439. format == GFXFormatR8G8B8A8 ||
  440. format == GFXFormatR8G8B8X8 ||
  441. format == GFXFormatA8 ||
  442. format == GFXFormatR5G6B5, "_writePNG: ONLY RGB bitmap writing supported at this time.");
  443. if ( format != GFXFormatR8G8B8 &&
  444. format != GFXFormatR8G8B8A8 &&
  445. format != GFXFormatR8G8B8X8 &&
  446. format != GFXFormatA8 &&
  447. format != GFXFormatR5G6B5 )
  448. return false;
  449. mData->png_ptr = png_create_write_struct_2(PNG_LIBPNG_VER_STRING,
  450. NULL,
  451. pngFatalErrorFn,
  452. pngWarningFn,
  453. NULL,
  454. pngRealMallocFn,
  455. pngRealFreeFn);
  456. if (mData->png_ptr == NULL)
  457. return (false);
  458. mData->info_ptr = png_create_info_struct(mData->png_ptr);
  459. if (mData->info_ptr == NULL)
  460. {
  461. png_destroy_write_struct(&mData->png_ptr, (png_infopp)NULL);
  462. return false;
  463. }
  464. png_set_write_fn(mData->png_ptr, &stream, pngWriteDataFn, pngFlushDataFn);
  465. // Set the compression level, image filters, and compression strategy...
  466. mData->png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_STRATEGY;
  467. mData->png_ptr->zlib_strategy = 0;
  468. png_set_compression_window_bits(mData->png_ptr, 15);
  469. png_set_compression_level(mData->png_ptr, compressionLevel);
  470. png_set_filter(mData->png_ptr, 0, PNG_ALL_FILTERS);
  471. // Set the image information here. Width and height are up to 2^31,
  472. // bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on
  473. // the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY,
  474. // PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB,
  475. // or PNG_COLOR_TYPE_RGB_ALPHA. interlace is either PNG_INTERLACE_NONE or
  476. // PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST
  477. // currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED
  478. if (format == GFXFormatR8G8B8)
  479. {
  480. png_set_IHDR(mData->png_ptr, mData->info_ptr,
  481. width, height, // the width & height
  482. 8, PNG_COLOR_TYPE_RGB, // bit_depth, color_type,
  483. NULL, // no interlace
  484. NULL, // compression type
  485. NULL); // filter type
  486. }
  487. else if (format == GFXFormatR8G8B8A8 || format == GFXFormatR8G8B8X8)
  488. {
  489. png_set_IHDR(mData->png_ptr, mData->info_ptr,
  490. width, height, // the width & height
  491. 8, PNG_COLOR_TYPE_RGB_ALPHA, // bit_depth, color_type,
  492. NULL, // no interlace
  493. NULL, // compression type
  494. NULL); // filter type
  495. }
  496. else if (format == GFXFormatA8)
  497. {
  498. png_set_IHDR(mData->png_ptr, mData->info_ptr,
  499. width, height, // the width & height
  500. 8, PNG_COLOR_TYPE_GRAY, // bit_depth, color_type,
  501. NULL, // no interlace
  502. NULL, // compression type
  503. NULL); // filter type
  504. }
  505. else if (format == GFXFormatR5G6B5)
  506. {
  507. png_set_IHDR(mData->png_ptr, mData->info_ptr,
  508. width, height, // the width & height
  509. 16, PNG_COLOR_TYPE_GRAY, // bit_depth, color_type,
  510. PNG_INTERLACE_NONE, // no interlace
  511. PNG_COMPRESSION_TYPE_DEFAULT, // compression type
  512. PNG_FILTER_TYPE_DEFAULT); // filter type
  513. png_color_8_struct sigBit = { 0 };
  514. sigBit.gray = 16;
  515. png_set_sBIT(mData->png_ptr, mData->info_ptr, &sigBit );
  516. png_set_swap( mData->png_ptr );
  517. }
  518. png_write_info(mData->png_ptr, mData->info_ptr);
  519. mActive = true;
  520. return true;
  521. }
  522. void DeferredPNGWriter::append( GBitmap* bitmap, U32 rows)
  523. {
  524. AssertFatal(mActive, "Cannot append to an inactive DeferredPNGWriter!");
  525. U32 height = getMin( bitmap->getHeight(), rows);
  526. FrameAllocatorMarker marker;
  527. png_bytep* row_pointers = (png_bytep*)marker.alloc( height * sizeof( png_bytep ) );
  528. for (U32 i=0; i<height; i++)
  529. row_pointers[i] = const_cast<png_bytep>(bitmap->getAddress(0, i));
  530. png_write_rows(mData->png_ptr, row_pointers, height);
  531. }
  532. void DeferredPNGWriter::end()
  533. {
  534. AssertFatal(mActive, "Cannot end an inactive DeferredPNGWriter!");
  535. png_write_end(mData->png_ptr, mData->info_ptr);
  536. png_destroy_write_struct(&mData->png_ptr, (png_infopp)NULL);
  537. mActive = false;
  538. }