Open Source Tomb Raider Engine
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

png.cpp 7.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. /*!
  2. * \file src/utils/png.cpp
  3. * \brief PNG image reader
  4. *
  5. * https://github.com/DavidEGrayson/ahrs-visualizer/blob/master/png_texture.cpp
  6. * http://zarb.org/~gc/html/libpng.html
  7. *
  8. * \author xythobuz
  9. */
  10. #include <png.h>
  11. #include <cstdio>
  12. #include <iostream>
  13. #include "global.h"
  14. #include "utils/pixel.h"
  15. #include "utils/png.h"
  16. int pngCheck(const char* filename) {
  17. png_byte header[8];
  18. assert(filename != NULL);
  19. assert(filename[0] != '\0');
  20. FILE* fp = fopen(filename, "rb");
  21. if (fp == NULL) {
  22. std::cout << "Could not open " << filename << std::endl;
  23. return -1;
  24. }
  25. fread(header, 1, 8, fp);
  26. fclose(fp);
  27. if (png_sig_cmp(header, 0, 8)) {
  28. std::cout << "File " << filename << " is not a PNG." << std::endl;
  29. return -2;
  30. }
  31. return 0;
  32. }
  33. int pngLoad(const char* filename, unsigned char** image,
  34. unsigned int* width, unsigned int* height, ColorMode* mode, unsigned int* bpp) {
  35. png_byte header[8];
  36. assert(filename != NULL);
  37. assert(filename[0] != '\0');
  38. assert(image != NULL);
  39. assert(width != NULL);
  40. assert(height != NULL);
  41. assert(mode != NULL);
  42. assert(bpp != NULL);
  43. FILE* fp = fopen(filename, "rb");
  44. if (fp == NULL) {
  45. std::cout << "Could not open " << filename << std::endl;
  46. return -1;
  47. }
  48. fread(header, 1, 8, fp);
  49. if (png_sig_cmp(header, 0, 8)) {
  50. std::cout << "File " << filename << " is not a PNG." << std::endl;
  51. fclose(fp);
  52. return -2;
  53. }
  54. png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
  55. if (!png_ptr) {
  56. std::cout << "png_create_read_struct returned 0." << std::endl;
  57. fclose(fp);
  58. return -3;
  59. }
  60. png_infop info_ptr = png_create_info_struct(png_ptr);
  61. if (!info_ptr) {
  62. std::cout << "png_create_info_struct returned 0." << std::endl;
  63. png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
  64. fclose(fp);
  65. return -4;
  66. }
  67. png_infop end_info = png_create_info_struct(png_ptr);
  68. if (!end_info) {
  69. std::cout << "png_create_info_struct returned 0." << std::endl;
  70. png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) NULL);
  71. fclose(fp);
  72. return -5;
  73. }
  74. if (setjmp(png_jmpbuf(png_ptr))) {
  75. std::cout << "Error from libpng" << std::endl;
  76. png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
  77. fclose(fp);
  78. return -6;
  79. }
  80. png_init_io(png_ptr, fp);
  81. png_set_sig_bytes(png_ptr, 8);
  82. png_read_info(png_ptr, info_ptr);
  83. int bit_depth, color_type;
  84. png_uint_32 tmpWidth, tmpHeight;
  85. png_get_IHDR(png_ptr, info_ptr, &tmpWidth, &tmpHeight, &bit_depth, &color_type,
  86. NULL, NULL, NULL);
  87. *width = tmpWidth;
  88. *height = tmpHeight;
  89. if (bit_depth != 8) {
  90. std::cout << filename << ": Unsupported bit depth " << bit_depth << ". Must be 8." << std::endl;
  91. return -7;
  92. }
  93. png_read_update_info(png_ptr, info_ptr);
  94. png_size_t rowbytes = png_get_rowbytes(png_ptr, info_ptr);
  95. png_byte* image_data = new png_byte[(rowbytes** height) + 15];
  96. png_bytep* row_pointers = new png_bytep[*height];
  97. for (unsigned int i = 0; i < *height; i++)
  98. row_pointers[*height - 1 - i] = image_data + i * rowbytes;
  99. png_read_image(png_ptr, row_pointers);
  100. png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
  101. delete [] row_pointers;
  102. fclose(fp);
  103. if (color_type == PNG_COLOR_TYPE_GRAY) {
  104. *mode = GREYSCALE;
  105. *bpp = 8;
  106. } else if (color_type == PNG_COLOR_TYPE_RGB) {
  107. *mode = RGB;
  108. *bpp = 24;
  109. } else if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) {
  110. *mode = RGBA;
  111. *bpp = 32;
  112. } else {
  113. std::cout << filename << ": Unknown libpng color type " << color_type << std::endl;
  114. delete [] image_data;
  115. return -8;
  116. }
  117. // Flip
  118. *image = new unsigned char[*width** height * (*bpp / 8)];
  119. for (unsigned int y = 0; y < (*height); y++) {
  120. for (unsigned int x = 0; x < (*width); x++) {
  121. (*image)[((y** width) + x) * (*bpp / 8)]
  122. = image_data[(((*height - y - 1)** width) + x) * (*bpp / 8)];
  123. (*image)[(((y** width) + x) * (*bpp / 8)) + 1]
  124. = image_data[((((*height - y - 1)** width) + x) * (*bpp / 8)) + 1];
  125. (*image)[(((y** width) + x) * (*bpp / 8)) + 2]
  126. = image_data[((((*height - y - 1)** width) + x) * (*bpp / 8)) + 2];
  127. (*image)[(((y** width) + x) * (*bpp / 8)) + 3]
  128. = image_data[((((*height - y - 1)** width) + x) * (*bpp / 8)) + 3];
  129. }
  130. }
  131. delete [] image_data;
  132. return 0;
  133. }
  134. int pngSave(const char* filename, unsigned char* image,
  135. unsigned int width, unsigned int height, ColorMode mode, unsigned int bpp) {
  136. assert(filename != NULL);
  137. assert(filename[0] != '\0');
  138. assert(image != NULL);
  139. assert(width > 0);
  140. assert(height > 0);
  141. FILE* fp = fopen(filename, "wb");
  142. if (!fp) {
  143. std::cout << "File " << filename << " could not be opened for writing" << std::endl;
  144. return -1;
  145. }
  146. png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
  147. if (!png_ptr) {
  148. std::cout << "png_create_write_struct failed" << std::endl;
  149. fclose(fp);
  150. return -2;
  151. }
  152. png_infop info_ptr = png_create_info_struct(png_ptr);
  153. if (!info_ptr) {
  154. std::cout << "png_create_info_struct failed" << std::endl;
  155. fclose(fp);
  156. return -3;
  157. }
  158. if (setjmp(png_jmpbuf(png_ptr))) {
  159. std::cout << "Error during init_io" << std::endl;
  160. fclose(fp);
  161. return -4;
  162. }
  163. png_init_io(png_ptr, fp);
  164. if (setjmp(png_jmpbuf(png_ptr))) {
  165. std::cout << "Error during writing header" << std::endl;
  166. fclose(fp);
  167. return -5;
  168. }
  169. int color_type;
  170. if ((mode == GREYSCALE) && (bpp == 8)) {
  171. color_type = PNG_COLOR_TYPE_GRAY;
  172. } else if (((mode == RGB) || (mode == BGR)) && (bpp == 24)) {
  173. if (mode == BGR) {
  174. bgr2rgb24(image, width, height);
  175. }
  176. color_type = PNG_COLOR_TYPE_RGB;
  177. } else if (((mode == RGBA) || (mode == BGRA)) && (bpp == 32)) {
  178. if (mode == BGRA) {
  179. bgra2rgba32(image, width, height);
  180. }
  181. color_type = PNG_COLOR_TYPE_RGB_ALPHA;
  182. } else {
  183. std::cout << "Error invalid color mode" << std::endl;
  184. fclose(fp);
  185. return -6;
  186. }
  187. png_set_IHDR(png_ptr, info_ptr, width, height,
  188. 8, color_type, PNG_INTERLACE_NONE,
  189. PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
  190. png_write_info(png_ptr, info_ptr);
  191. png_bytep* row_pointers = new png_bytep[height];
  192. for (unsigned int i = 0; i < height; i++)
  193. row_pointers[height - 1 - i] = image + (i * width * 4);
  194. if (setjmp(png_jmpbuf(png_ptr))) {
  195. std::cout << "Error during writing bytes" << std::endl;
  196. delete [] row_pointers;
  197. fclose(fp);
  198. return -7;
  199. }
  200. png_write_image(png_ptr, row_pointers);
  201. if (setjmp(png_jmpbuf(png_ptr))) {
  202. std::cout << "Error during end of write" << std::endl;
  203. delete [] row_pointers;
  204. fclose(fp);
  205. return -8;
  206. }
  207. png_write_end(png_ptr, NULL);
  208. delete [] row_pointers;
  209. fclose(fp);
  210. return 0;
  211. }