1
0

PNGWriter.cpp 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. #include "PNGWriter.h"
  2. #include "api__png.h"
  3. #include <png.h>
  4. #include <wchar.h>
  5. #include <bfc/platform/strcmp.h>
  6. // valid items include "quality" for jpeg files with value "0" to "100"
  7. // return value is 1 if the config item is supported, 0 if it is not.
  8. int PNGWriter::setConfig(const wchar_t * item, const wchar_t * value) {
  9. return 0; // no config yet
  10. }
  11. // valid items include "quality" for jpeg files with value "0" to "100", "lossless" returns "1" if it is "0" otherwise
  12. // return value is 1 if the config item is supported, 0 if it is not.
  13. int PNGWriter::getConfig(const wchar_t * item, wchar_t * value, int valuelen) {
  14. if(!_wcsicmp(item,L"lossless")) lstrcpynW(value,L"1",valuelen);
  15. else return 0;
  16. return 1;
  17. }
  18. typedef struct {
  19. BYTE * data;
  20. unsigned int len;
  21. unsigned int alloc;
  22. } pngWrite;
  23. extern "C" static void PNGAPI png_write(png_structp png_ptr, png_bytep data, png_size_t len) {
  24. pngWrite * p = (pngWrite *)png_get_io_ptr(png_ptr);
  25. while (len + p->len > p->alloc) { // allocate more memory
  26. int d = ((p->alloc / 4) & 0xffffff00) + 0x100;
  27. if(d < 4096) d = 4096;
  28. p->alloc+=d;
  29. p->data = (BYTE*)WASABI_API_MEMMGR->sysRealloc(p->data,p->alloc);
  30. }
  31. memcpy(p->data+p->len,data,len);
  32. p->len += int(len);
  33. }
  34. extern "C" static void PNGAPI png_flush(png_structp png_ptr) {}
  35. // returns 1 if the bit depth is supported (eg 32 for ARGB32, 24 for RGB24)
  36. // ARGB32 MUST be supported
  37. int PNGWriter::bitDepthSupported(int depth) {
  38. if(depth == 32 || depth == 24) return 1;
  39. return 0;
  40. }
  41. // returns the image in our format, free the returned buffer with api_memmgr::sysFree()
  42. void * PNGWriter::convert(const void *pixels0, int bitDepth, int w, int h, int *length) {
  43. if(bitDepth != 32 && bitDepth != 24) return 0;
  44. BYTE * pixels = (BYTE*)pixels0;
  45. png_structp png_ptr;
  46. png_infop info_ptr;
  47. /* Create and initialize the png_struct with the desired error handler
  48. * functions. If you want to use the default stderr and longjump method,
  49. * you can supply NULL for the last three parameters. We also check that
  50. * the library version is compatible with the one used at compile time,
  51. * in case we are using dynamically linked libraries. REQUIRED.
  52. */
  53. png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
  54. (png_voidp*)NULL, NULL, NULL);
  55. if (png_ptr == NULL)
  56. return 0;
  57. /* Allocate/initialize the image information data. REQUIRED */
  58. info_ptr = png_create_info_struct(png_ptr);
  59. if (info_ptr == NULL)
  60. {
  61. png_destroy_write_struct(&png_ptr, NULL);
  62. return 0;
  63. }
  64. pngWrite writer={0};
  65. /* Set error handling. REQUIRED if you aren't supplying your own
  66. * error handling functions in the png_create_write_struct() call.
  67. */
  68. if (setjmp(png_jmpbuf(png_ptr)))
  69. {
  70. /* If we get here, we had a problem reading the file */
  71. png_destroy_write_struct(&png_ptr, &info_ptr);
  72. if(writer.data) WASABI_API_MEMMGR->sysFree(writer.data);
  73. return 0;
  74. }
  75. writer.alloc = (int(double(w*h)*1.25) & 0xffffff00) + 0x100;
  76. if (writer.alloc < 4096) writer.alloc = 4096;
  77. writer.data = (BYTE*)WASABI_API_MEMMGR->sysMalloc(writer.alloc);
  78. /* If you are using replacement read functions, instead of calling
  79. * png_init_io() here you would call */
  80. png_set_write_fn(png_ptr, (void *)&writer, png_write,
  81. png_flush);
  82. /* Set the image information here. Width and height are up to 2^31,
  83. * bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on
  84. * the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY,
  85. * PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB,
  86. * or PNG_COLOR_TYPE_RGB_ALPHA. interlace is either PNG_INTERLACE_NONE or
  87. * PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST
  88. * currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED
  89. */
  90. int colortype = (bitDepth == 32) ? PNG_COLOR_TYPE_RGB_ALPHA : PNG_COLOR_TYPE_RGB;
  91. png_set_IHDR(png_ptr, info_ptr, w, h, 8, colortype,
  92. PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
  93. /* optional significant bit chunk */
  94. png_color_8 sig_bit;
  95. /* if we are dealing with a grayscale image then */
  96. sig_bit.gray = 8;
  97. /* otherwise, if we are dealing with a color image then */
  98. sig_bit.red = 8;
  99. sig_bit.green = 8;
  100. sig_bit.blue = 8;
  101. /* if the image has an alpha channel then */
  102. sig_bit.alpha = (bitDepth==32)?8:0;
  103. png_set_sBIT(png_ptr, info_ptr, &sig_bit);
  104. /* Write the file header information. REQUIRED */
  105. png_write_info(png_ptr, info_ptr);
  106. /* set up the transformations you want. Note that these are
  107. * all optional. Only call them if you want them.
  108. */
  109. /* invert monochrome pixels */
  110. png_set_invert_mono(png_ptr);
  111. /* Shift the pixels up to a legal bit depth and fill in
  112. * as appropriate to correctly scale the image.
  113. */
  114. png_set_shift(png_ptr, &sig_bit);
  115. /* pack pixels into bytes */
  116. png_set_packing(png_ptr);
  117. /* flip BGR pixels to RGB */
  118. png_set_bgr(png_ptr);
  119. /* swap bytes of 16-bit files to most significant byte first */
  120. png_set_swap(png_ptr);
  121. /* swap bits of 1, 2, 4 bit packed pixel formats */
  122. png_set_packswap(png_ptr);
  123. /*if (interlacing)
  124. number_passes = png_set_interlace_handling(png_ptr);
  125. else*/
  126. png_uint_32 number_passes = 1;
  127. /* The easiest way to write the image (you may have a different memory
  128. * layout, however, so choose what fits your needs best). You need to
  129. * use the first method if you aren't handling interlacing yourself.
  130. */
  131. int bytes_per_pixel = bitDepth / 8;
  132. /* The number of passes is either 1 for non-interlaced images,
  133. * or 7 for interlaced images.
  134. */
  135. for (png_uint_32 pass = 0; pass < number_passes; pass++)
  136. {
  137. BYTE * row = pixels; // + (h*w*bytes_per_pixel);
  138. for (int y = 0; y < h; y++) {
  139. //row -= w*bytes_per_pixel;
  140. png_write_rows(png_ptr, &row, 1);
  141. row += w*bytes_per_pixel;
  142. }
  143. }
  144. /* It is REQUIRED to call this to finish writing the rest of the file */
  145. png_write_end(png_ptr, info_ptr);
  146. /* clean up after the write, and free any memory allocated */
  147. png_destroy_write_struct(&png_ptr, &info_ptr);
  148. /* that's it */
  149. if(length) *length = writer.len;
  150. return writer.data;
  151. }
  152. #define CBCLASS PNGWriter
  153. START_DISPATCH;
  154. CB(GETIMAGETYPENAME, getImageTypeName);
  155. CB(GETEXTENSIONS, getExtensions);
  156. CB(SETCONFIG, setConfig);
  157. CB(GETCONFIG, getConfig);
  158. CB(BITDEPTHSUPPORTED, bitDepthSupported);
  159. CB(CONVERT, convert);
  160. END_DISPATCH;
  161. #undef CBCLASS