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.0KB

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