1
0

PNGLoader.cpp 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. #include "PNGLoader.h"
  2. #include "api__png.h"
  3. #include <png.h>
  4. #include <wchar.h>
  5. #include <malloc.h>
  6. #include <bfc/platform/strcmp.h>
  7. #include <intsafe.h>
  8. void premultiplyARGB32(ARGB32 *words, int nwords)
  9. {
  10. for (; nwords > 0; nwords--, words++) {
  11. unsigned char *pixel = (unsigned char *)words;
  12. unsigned int alpha = pixel[3];
  13. if (alpha == 255) continue;
  14. pixel[0] = (pixel[0] * alpha) >> 8; // blue
  15. pixel[1] = (pixel[1] * alpha) >> 8; // green
  16. pixel[2] = (pixel[2] * alpha) >> 8; // red
  17. }
  18. }
  19. static bool StringEnds(const wchar_t *a, const wchar_t *b)
  20. {
  21. size_t aLen = wcslen(a);
  22. size_t bLen = wcslen(b);
  23. if (aLen < bLen) return false; // too short
  24. if (!_wcsicmp(a + aLen- bLen, b))
  25. return true;
  26. return false;
  27. }
  28. int PNGLoader::isMine(const wchar_t *filename)
  29. {
  30. if (filename && StringEnds(filename, L".PNG"))
  31. return 1;
  32. else
  33. return 0;
  34. }
  35. const wchar_t *PNGLoader::mimeType()
  36. {
  37. return L"image/png";
  38. }
  39. int PNGLoader::getHeaderSize()
  40. {
  41. return 8;
  42. }
  43. int PNGLoader::testData(const void *data, int datalen) {
  44. unsigned char *ptr = (unsigned char *)data;
  45. return !png_sig_cmp(ptr, 0, datalen);
  46. }
  47. typedef struct {
  48. const unsigned char *data;
  49. size_t pos;
  50. size_t datalen;
  51. } my_read_info;
  52. static void my_png_read_data(png_structp png_ptr, png_bytep data, png_size_t length) {
  53. my_read_info *mri = (my_read_info *)png_get_io_ptr(png_ptr);
  54. if (mri->datalen - mri->pos < length)
  55. length = mri->datalen - mri->pos;
  56. memmove(data, mri->data + mri->pos, length);
  57. mri->pos += length;
  58. }
  59. ARGB32 *PNGLoader::loadImage(const void *data, int datalen, int *w, int *h, ifc_xmlreaderparams *params) {
  60. int w0=0, h0=0;
  61. ARGB32 *pixels = read_png(data, datalen, &w0, &h0, FALSE);
  62. if (pixels == NULL) return NULL;
  63. premultiplyARGB32(pixels, w0 * h0);
  64. if(w) *w = w0;
  65. if(h) *h = h0;
  66. return pixels;
  67. }
  68. ARGB32 *PNGLoader::loadImageData(const void *data, int datalen, int *w, int *h, ifc_xmlreaderparams *params)
  69. {
  70. return read_png(data, datalen, w, h, FALSE);
  71. }
  72. int PNGLoader::getDimensions(const void *data, int datalen, int *w, int *h) {
  73. return (read_png(data, datalen, w, h, TRUE) == reinterpret_cast<ARGB32*>(-1));
  74. }
  75. // From libpng example.c
  76. ARGB32 *PNGLoader::read_png(const void *data, int datalen, int *w, int *h, int dimensions_only) {
  77. png_structp png_ptr;
  78. png_infop info_ptr;
  79. png_uint_32 width, height;
  80. int bit_depth, color_type, interlace_type;
  81. my_read_info mri;
  82. mri.data = static_cast<const unsigned char *>(data);
  83. mri.pos = 0;
  84. mri.datalen = datalen;
  85. /* Create and initialize the png_struct with the desired error handler
  86. * functions. If you want to use the default stderr and longjump method,
  87. * you can supply NULL for the last three parameters. We also supply the
  88. * the compiler header file version, so that we know if the application
  89. * was compiled with a compatible version of the library. REQUIRED
  90. */
  91. png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
  92. NULL, NULL, NULL);
  93. if (png_ptr == NULL)
  94. {
  95. return NULL;
  96. }
  97. /* Allocate/initialize the memory for image information. REQUIRED. */
  98. info_ptr = png_create_info_struct(png_ptr);
  99. if (info_ptr == NULL)
  100. {
  101. png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
  102. return NULL;
  103. }
  104. /* Set error handling if you are using the setjmp/longjmp method (this is
  105. * the normal method of doing things with libpng). REQUIRED unless you
  106. * set up your own error handlers in the png_create_read_struct() earlier.
  107. */
  108. if (setjmp(png_jmpbuf(png_ptr)))
  109. {
  110. /* Free all of the memory associated with the png_ptr and info_ptr */
  111. png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
  112. /* If we get here, we had a problem reading the file */
  113. return NULL;
  114. }
  115. png_set_read_fn(png_ptr, &mri, my_png_read_data);
  116. /* The call to png_read_info() gives us all of the information from the
  117. * PNG file before the first IDAT (image data chunk). REQUIRED
  118. */
  119. png_read_info(png_ptr, info_ptr);
  120. png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
  121. &interlace_type, NULL, NULL);
  122. if (w) *w = (int)width;
  123. if (h) *h = (int)height;
  124. ARGB32 *retval = 0;
  125. if (!dimensions_only) {
  126. /* tell libpng to strip 16 bit/color files down to 8 bits/color */
  127. if (bit_depth == 16) png_set_strip_16(png_ptr);
  128. if (bit_depth < 8) png_set_packing(png_ptr);
  129. /* flip the RGB pixels to BGR (or RGBA to BGRA) */
  130. png_set_bgr(png_ptr);
  131. /* Expand paletted colors into true RGB triplets */
  132. if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_expand(png_ptr);
  133. /* Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel */
  134. if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
  135. png_set_expand(png_ptr);
  136. png_set_gray_to_rgb(png_ptr);
  137. /* Expand paletted or RGB images with transparency to full alpha channels
  138. * so the data will be available as RGBA quartets.
  139. */
  140. if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
  141. png_set_expand(png_ptr);
  142. }
  143. /* Add filler (or alpha) byte (before/after each RGB triplet) */
  144. png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER);
  145. /* Optional call to gamma correct and add the background to the palette
  146. * and update info structure. REQUIRED if you are expecting libpng to
  147. * update the palette for you (ie you selected such a transform above).
  148. */
  149. png_read_update_info(png_ptr, info_ptr);
  150. /* Allocate the memory to hold the image using the fields of info_ptr. */
  151. /* The easiest way to read the image: */
  152. //row_pointers = (png_bytep*)malloc(sizeof(png_bytep*)*height);
  153. size_t row_ptr_size = 0;
  154. if (SizeTMult(sizeof(png_bytep*), height, &row_ptr_size) == S_OK)
  155. {
  156. png_bytep *row_pointers = (png_bytep*)alloca(row_ptr_size);
  157. size_t image_size=0;
  158. if (SizeTMult(width, height, &image_size) == S_OK && SizeTMult(image_size, 4, &image_size)== S_OK)
  159. {
  160. ARGB32 *bytes = (ARGB32 *)WASABI_API_MEMMGR->sysMalloc(image_size);
  161. for (unsigned int row = 0; row < height; row++) {
  162. row_pointers[row] = ((unsigned char *)bytes) + width * 4 * (row);
  163. }
  164. /* Now it's time to read the image. One of these methods is REQUIRED */
  165. png_read_image(png_ptr, row_pointers);
  166. /* read rest of file, and get additional chunks in info_ptr - REQUIRED */
  167. png_read_end(png_ptr, info_ptr);
  168. retval = bytes;
  169. }
  170. }
  171. //free(row_pointers);
  172. }
  173. /* clean up after the read, and free any memory allocated - REQUIRED */
  174. png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
  175. /* that's it */
  176. return retval;
  177. }
  178. #define CBCLASS PNGLoader
  179. START_DISPATCH;
  180. CB(ISMINE, isMine);
  181. CB(MIMETYPE, mimeType);
  182. CB(TESTDATA, testData);
  183. CB(GETHEADERSIZE, getHeaderSize);
  184. CB(GETDIMENSIONS, getDimensions);
  185. CB(LOADIMAGE, loadImage);
  186. CB(LOADIMAGEDATA, loadImageData);
  187. END_DISPATCH;
  188. #undef CBCLASS