png_driver_common.cpp 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. /*************************************************************************/
  2. /* png_driver_common.cpp */
  3. /*************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* https://godotengine.org */
  7. /*************************************************************************/
  8. /* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
  9. /* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
  10. /* */
  11. /* Permission is hereby granted, free of charge, to any person obtaining */
  12. /* a copy of this software and associated documentation files (the */
  13. /* "Software"), to deal in the Software without restriction, including */
  14. /* without limitation the rights to use, copy, modify, merge, publish, */
  15. /* distribute, sublicense, and/or sell copies of the Software, and to */
  16. /* permit persons to whom the Software is furnished to do so, subject to */
  17. /* the following conditions: */
  18. /* */
  19. /* The above copyright notice and this permission notice shall be */
  20. /* included in all copies or substantial portions of the Software. */
  21. /* */
  22. /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
  23. /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
  24. /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
  25. /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
  26. /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
  27. /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
  28. /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
  29. /*************************************************************************/
  30. #include "png_driver_common.h"
  31. #include "core/os/os.h"
  32. #include <png.h>
  33. #include <string.h>
  34. namespace PNGDriverCommon {
  35. // Print any warnings.
  36. // On error, set explain and return true.
  37. // Call should be wrapped in ERR_FAIL_COND
  38. static bool check_error(const png_image &image) {
  39. const png_uint_32 failed = PNG_IMAGE_FAILED(image);
  40. if (failed & PNG_IMAGE_ERROR) {
  41. return true;
  42. } else if (failed) {
  43. #ifdef TOOLS_ENABLED
  44. // suppress this warning, to avoid log spam when opening assetlib
  45. const static char *const noisy = "iCCP: known incorrect sRGB profile";
  46. const Engine *const eng = Engine::get_singleton();
  47. if (eng && eng->is_editor_hint() && !strcmp(image.message, noisy)) {
  48. return false;
  49. }
  50. #endif
  51. WARN_PRINT(image.message);
  52. }
  53. return false;
  54. }
  55. Error png_to_image(const uint8_t *p_source, size_t p_size, bool p_force_linear, Ref<Image> p_image) {
  56. png_image png_img;
  57. memset(&png_img, 0, sizeof(png_img));
  58. png_img.version = PNG_IMAGE_VERSION;
  59. // fetch image properties
  60. int success = png_image_begin_read_from_memory(&png_img, p_source, p_size);
  61. ERR_FAIL_COND_V_MSG(check_error(png_img), ERR_FILE_CORRUPT, png_img.message);
  62. ERR_FAIL_COND_V(!success, ERR_FILE_CORRUPT);
  63. // flags to be masked out of input format to give target format
  64. const png_uint_32 format_mask = ~(
  65. // convert component order to RGBA
  66. PNG_FORMAT_FLAG_BGR | PNG_FORMAT_FLAG_AFIRST
  67. // convert 16 bit components to 8 bit
  68. | PNG_FORMAT_FLAG_LINEAR
  69. // convert indexed image to direct color
  70. | PNG_FORMAT_FLAG_COLORMAP);
  71. png_img.format &= format_mask;
  72. Image::Format dest_format;
  73. switch (png_img.format) {
  74. case PNG_FORMAT_GRAY:
  75. dest_format = Image::FORMAT_L8;
  76. break;
  77. case PNG_FORMAT_GA:
  78. dest_format = Image::FORMAT_LA8;
  79. break;
  80. case PNG_FORMAT_RGB:
  81. dest_format = Image::FORMAT_RGB8;
  82. break;
  83. case PNG_FORMAT_RGBA:
  84. dest_format = Image::FORMAT_RGBA8;
  85. break;
  86. default:
  87. png_image_free(&png_img); // only required when we return before finish_read
  88. ERR_PRINT("Unsupported png format.");
  89. return ERR_UNAVAILABLE;
  90. }
  91. if (!p_force_linear) {
  92. // assume 16 bit pngs without sRGB or gAMA chunks are in sRGB format
  93. png_img.flags |= PNG_IMAGE_FLAG_16BIT_sRGB;
  94. }
  95. const png_uint_32 stride = PNG_IMAGE_ROW_STRIDE(png_img);
  96. PoolVector<uint8_t> buffer;
  97. Error err = buffer.resize(PNG_IMAGE_BUFFER_SIZE(png_img, stride));
  98. if (err) {
  99. png_image_free(&png_img); // only required when we return before finish_read
  100. return err;
  101. }
  102. PoolVector<uint8_t>::Write writer = buffer.write();
  103. // read image data to buffer and release libpng resources
  104. success = png_image_finish_read(&png_img, NULL, writer.ptr(), stride, NULL);
  105. ERR_FAIL_COND_V_MSG(check_error(png_img), ERR_FILE_CORRUPT, png_img.message);
  106. ERR_FAIL_COND_V(!success, ERR_FILE_CORRUPT);
  107. p_image->create(png_img.width, png_img.height, 0, dest_format, buffer);
  108. return OK;
  109. }
  110. Error image_to_png(const Ref<Image> &p_image, PoolVector<uint8_t> &p_buffer) {
  111. Ref<Image> source_image = p_image->duplicate();
  112. if (source_image->is_compressed())
  113. source_image->decompress();
  114. ERR_FAIL_COND_V(source_image->is_compressed(), FAILED);
  115. png_image png_img;
  116. memset(&png_img, 0, sizeof(png_img));
  117. png_img.version = PNG_IMAGE_VERSION;
  118. png_img.width = source_image->get_width();
  119. png_img.height = source_image->get_height();
  120. switch (source_image->get_format()) {
  121. case Image::FORMAT_L8:
  122. png_img.format = PNG_FORMAT_GRAY;
  123. break;
  124. case Image::FORMAT_LA8:
  125. png_img.format = PNG_FORMAT_GA;
  126. break;
  127. case Image::FORMAT_RGB8:
  128. png_img.format = PNG_FORMAT_RGB;
  129. break;
  130. case Image::FORMAT_RGBA8:
  131. png_img.format = PNG_FORMAT_RGBA;
  132. break;
  133. default:
  134. if (source_image->detect_alpha()) {
  135. source_image->convert(Image::FORMAT_RGBA8);
  136. png_img.format = PNG_FORMAT_RGBA;
  137. } else {
  138. source_image->convert(Image::FORMAT_RGB8);
  139. png_img.format = PNG_FORMAT_RGB;
  140. }
  141. }
  142. const PoolVector<uint8_t> image_data = source_image->get_data();
  143. const PoolVector<uint8_t>::Read reader = image_data.read();
  144. // we may be passed a buffer with existing content we're expected to append to
  145. const int buffer_offset = p_buffer.size();
  146. const size_t png_size_estimate = PNG_IMAGE_PNG_SIZE_MAX(png_img);
  147. // try with estimated size
  148. size_t compressed_size = png_size_estimate;
  149. int success = 0;
  150. { // scope writer lifetime
  151. Error err = p_buffer.resize(buffer_offset + png_size_estimate);
  152. ERR_FAIL_COND_V(err, err);
  153. PoolVector<uint8_t>::Write writer = p_buffer.write();
  154. success = png_image_write_to_memory(&png_img, &writer[buffer_offset],
  155. &compressed_size, 0, reader.ptr(), 0, NULL);
  156. ERR_FAIL_COND_V_MSG(check_error(png_img), FAILED, png_img.message);
  157. }
  158. if (!success) {
  159. // buffer was big enough, must be some other error
  160. ERR_FAIL_COND_V(compressed_size <= png_size_estimate, FAILED);
  161. // write failed due to buffer size, resize and retry
  162. Error err = p_buffer.resize(buffer_offset + compressed_size);
  163. ERR_FAIL_COND_V(err, err);
  164. PoolVector<uint8_t>::Write writer = p_buffer.write();
  165. success = png_image_write_to_memory(&png_img, &writer[buffer_offset],
  166. &compressed_size, 0, reader.ptr(), 0, NULL);
  167. ERR_FAIL_COND_V_MSG(check_error(png_img), FAILED, png_img.message);
  168. ERR_FAIL_COND_V(!success, FAILED);
  169. }
  170. // trim buffer size to content
  171. Error err = p_buffer.resize(buffer_offset + compressed_size);
  172. ERR_FAIL_COND_V(err, err);
  173. return OK;
  174. }
  175. } // namespace PNGDriverCommon