Open Source Tomb Raider Engine
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

png.cpp 7.1KB

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 "global.h"
  13. #include "utils/pixel.h"
  14. #include "utils/png.h"
  15. #ifdef DEBUG
  16. #include "Console.h"
  17. #define pngPrint getConsole().print
  18. #else
  19. void pngPrint(...) { }
  20. #endif
  21. int pngCheck(const char *filename) {
  22. png_byte header[8];
  23. assert(filename != NULL);
  24. assert(filename[0] != '\0');
  25. FILE *fp = fopen(filename, "rb");
  26. if (fp == NULL) {
  27. pngPrint("Could not open %s", filename);
  28. return -1;
  29. }
  30. fread(header, 1, 8, fp);
  31. fclose(fp);
  32. if (png_sig_cmp(header, 0, 8)) {
  33. pngPrint("File %s is not a PNG.", filename);
  34. return -2;
  35. }
  36. return 0;
  37. }
  38. int pngLoad(const char *filename, unsigned char **image, unsigned int *width, unsigned int *height, TextureManager::ColorMode *mode, unsigned int *bpp) {
  39. png_byte header[8];
  40. assert(filename != NULL);
  41. assert(filename[0] != '\0');
  42. assert(image != NULL);
  43. assert(width != NULL);
  44. assert(height != NULL);
  45. assert(mode != NULL);
  46. assert(bpp != NULL);
  47. FILE *fp = fopen(filename, "rb");
  48. if (fp == NULL) {
  49. pngPrint("Could not open %s", filename);
  50. return -1;
  51. }
  52. fread(header, 1, 8, fp);
  53. if (png_sig_cmp(header, 0, 8)) {
  54. pngPrint("File %s is not a PNG.", filename);
  55. fclose(fp);
  56. return -2;
  57. }
  58. png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
  59. if (!png_ptr) {
  60. pngPrint("png_create_read_struct returned 0.");
  61. fclose(fp);
  62. return -3;
  63. }
  64. png_infop info_ptr = png_create_info_struct(png_ptr);
  65. if (!info_ptr) {
  66. pngPrint("png_create_info_struct returned 0.");
  67. png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
  68. fclose(fp);
  69. return -4;
  70. }
  71. png_infop end_info = png_create_info_struct(png_ptr);
  72. if (!end_info) {
  73. pngPrint("png_create_info_struct returned 0.");
  74. png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) NULL);
  75. fclose(fp);
  76. return -5;
  77. }
  78. if (setjmp(png_jmpbuf(png_ptr))) {
  79. pngPrint("Error from libpng");
  80. png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
  81. fclose(fp);
  82. return -6;
  83. }
  84. png_init_io(png_ptr, fp);
  85. png_set_sig_bytes(png_ptr, 8);
  86. png_read_info(png_ptr, info_ptr);
  87. int bit_depth, color_type;
  88. png_get_IHDR(png_ptr, info_ptr, width, height, &bit_depth, &color_type,
  89. NULL, NULL, NULL);
  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. int 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 = TextureManager::GREYSCALE;
  106. *bpp = 8;
  107. } else if (color_type == PNG_COLOR_TYPE_RGB) {
  108. *mode = TextureManager::RGB;
  109. *bpp = 24;
  110. } else if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) {
  111. *mode = TextureManager::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, unsigned int width, unsigned int height, TextureManager::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. pngPrint("File %s could not be opened for writing", filename);
  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. pngPrint("png_create_write_struct failed");
  149. fclose(fp);
  150. return -2;
  151. }
  152. png_infop info_ptr = png_create_info_struct(png_ptr);
  153. if (!info_ptr) {
  154. pngPrint("png_create_info_struct failed");
  155. fclose(fp);
  156. return -3;
  157. }
  158. if (setjmp(png_jmpbuf(png_ptr))) {
  159. pngPrint("Error during init_io");
  160. fclose(fp);
  161. return -4;
  162. }
  163. png_init_io(png_ptr, fp);
  164. if (setjmp(png_jmpbuf(png_ptr))) {
  165. pngPrint("Error during writing header");
  166. fclose(fp);
  167. return -5;
  168. }
  169. int color_type;
  170. if ((mode == TextureManager::GREYSCALE) && (bpp == 8)) {
  171. color_type = PNG_COLOR_TYPE_GRAY;
  172. } else if (((mode == TextureManager::RGB) || (mode == TextureManager::BGR)) && (bpp == 24)) {
  173. if (mode == TextureManager::BGR) {
  174. bgr2rgb24(image, width, height);
  175. }
  176. color_type = PNG_COLOR_TYPE_RGB;
  177. } else if (((mode == TextureManager::RGBA) || (mode == TextureManager::BGRA)) && (bpp == 32)) {
  178. if (mode == TextureManager::BGRA) {
  179. bgra2rgba32(image, width, height);
  180. }
  181. color_type = PNG_COLOR_TYPE_RGB_ALPHA;
  182. } else {
  183. pngPrint("Error invalid color mode");
  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. pngPrint("Error during writing bytes");
  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. pngPrint("Error during end of write");
  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. }