PNGReader.cpp 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. #include <libpng16/png.h>
  2. #include "images/PNGReader.h"
  3. #include "utils/Logger.h"
  4. #include "utils/StringBuffer.h"
  5. PNGReader::PNGReader(const char* path)
  6. : path(path), width(0), height(0), channels(0), bitDepth(0), rowBytes(0),
  7. file(fopen(path, "r")), read(nullptr), info(nullptr),
  8. rowPointers(nullptr) {
  9. if(file == nullptr) {
  10. LOG_WARNING(StringBuffer<100>("file '")
  11. .append(path)
  12. .append("' cannot be read: ")
  13. .append(static_cast<const char*>(strerror(errno))));
  14. return;
  15. }
  16. if(checkSignature()) {
  17. return;
  18. }
  19. read = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr,
  20. nullptr);
  21. if(read == nullptr) {
  22. LOG_WARNING("cannot create png read data structure");
  23. return;
  24. }
  25. info = png_create_info_struct(read);
  26. if(info == nullptr) {
  27. LOG_WARNING("cannot create png info structure");
  28. return;
  29. }
  30. if(setjmp(png_jmpbuf(read))) {
  31. LOG_WARNING(StringBuffer<100>("png file '")
  32. .append(path)
  33. .append("' has used error callback"));
  34. return;
  35. }
  36. png_init_io(read, file);
  37. png_set_sig_bytes(read, 8);
  38. png_read_info(read, info);
  39. png_set_expand(read);
  40. width = png_get_image_width(read, info);
  41. height = png_get_image_height(read, info);
  42. channels = png_get_channels(read, info);
  43. bitDepth = png_get_bit_depth(read, info);
  44. if(png_get_bit_depth(read, info) == 16) {
  45. png_set_strip_16(read);
  46. }
  47. rowBytes = png_get_rowbytes(read, info);
  48. }
  49. PNGReader::~PNGReader() {
  50. if(file != nullptr) {
  51. fclose(file);
  52. }
  53. if(rowPointers != nullptr) {
  54. png_free(read, rowPointers);
  55. }
  56. png_destroy_read_struct(&read, &info, nullptr);
  57. }
  58. int PNGReader::getWidth() const {
  59. return width;
  60. }
  61. int PNGReader::getHeight() const {
  62. return height;
  63. }
  64. int PNGReader::getChannels() const {
  65. return channels;
  66. }
  67. int PNGReader::getBufferSize() const {
  68. return width * height * channels;
  69. }
  70. bool PNGReader::hasError() const {
  71. if(channels < 1 || channels > 4) {
  72. LOG_WARNING(StringBuffer<100>("'")
  73. .append(path)
  74. .append("' has unsupported number of channels: ")
  75. .append(channels));
  76. return true;
  77. } else if(width < 1 || width > 2048 || height < 1 || height > 2048) {
  78. LOG_WARNING(StringBuffer<100>("width and height of '")
  79. .append(path)
  80. .append("' are too big"));
  81. return true;
  82. } else if(bitDepth != 8 && bitDepth != 16) {
  83. LOG_WARNING(StringBuffer<100>("bit depth of '")
  84. .append(path)
  85. .append("' is neither 8 or 16"));
  86. return true;
  87. } else if(getBufferSize() != (rowBytes * height * 8 / bitDepth)) {
  88. LOG_WARNING(StringBuffer<100>("'").append(path).append(
  89. "' needs an unexpected buffer size"));
  90. return true;
  91. }
  92. return false;
  93. }
  94. bool PNGReader::checkSignature() {
  95. png_byte buffer[8];
  96. if(fread(buffer, sizeof(png_byte), 8, file) != 8) {
  97. LOG_WARNING(StringBuffer<100>("cannot read signature of file '")
  98. .append(path)
  99. .append("'"));
  100. return true;
  101. }
  102. if(png_sig_cmp(buffer, 0, 8)) {
  103. LOG_WARNING(
  104. StringBuffer<100>("file '").append(path).append("' is not a png"));
  105. return true;
  106. }
  107. return false;
  108. }
  109. bool PNGReader::readData(ColorChannel* buffer) {
  110. if(setjmp(png_jmpbuf(read))) {
  111. LOG_WARNING(StringBuffer<100>("png file '")
  112. .append(path)
  113. .append("' has used error callback"));
  114. return true;
  115. }
  116. rowPointers = static_cast<ColorChannel**>(
  117. png_malloc(read, height * sizeof(ColorChannel*)));
  118. for(int i = 0; i < height; i++) {
  119. rowPointers[i] = (buffer + i * width * channels);
  120. }
  121. png_set_rows(read, info, reinterpret_cast<png_bytepp>(rowPointers));
  122. png_read_image(read, reinterpret_cast<png_bytepp>(rowPointers));
  123. return false;
  124. }