save-png.cpp 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. #ifndef _CRT_SECURE_NO_WARNINGS
  2. #define _CRT_SECURE_NO_WARNINGS
  3. #endif
  4. #include "save-png.h"
  5. #include <cstdio>
  6. #include <cstring>
  7. #include <vector>
  8. #include "../core/pixel-conversion.hpp"
  9. #ifdef MSDFGEN_USE_LIBPNG
  10. #include <png.h>
  11. namespace msdfgen {
  12. class PngGuard {
  13. png_structp png;
  14. png_infop info;
  15. FILE *file;
  16. public:
  17. inline PngGuard(png_structp png, png_infop info) : png(png), info(info), file(NULL) { }
  18. inline ~PngGuard() {
  19. png_destroy_write_struct(&png, &info);
  20. if (file)
  21. fclose(file);
  22. }
  23. inline void setFile(FILE *file) {
  24. this->file = file;
  25. }
  26. };
  27. static void pngIgnoreError(png_structp, png_const_charp) { }
  28. static void pngWrite(png_structp png, png_bytep data, png_size_t length) {
  29. if (fwrite(data, 1, length, reinterpret_cast<FILE *>(png_get_io_ptr(png))) != length)
  30. png_error(png, "File write error");
  31. }
  32. static void pngFlush(png_structp png) {
  33. fflush(reinterpret_cast<FILE *>(png_get_io_ptr(png)));
  34. }
  35. static bool pngSave(const byte *pixels, int width, int height, int rowStride, int colorType, const char *filename) {
  36. if (!(pixels && width && height))
  37. return false;
  38. png_structp png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, &pngIgnoreError, &pngIgnoreError);
  39. if (!png)
  40. return false;
  41. png_infop info = png_create_info_struct(png);
  42. PngGuard guard(png, info);
  43. if (!info)
  44. return false;
  45. FILE *file = fopen(filename, "wb");
  46. if (!file)
  47. return false;
  48. guard.setFile(file);
  49. std::vector<const byte *> rows(height);
  50. for (int y = 0; y < height; ++y)
  51. rows[y] = pixels+rowStride*y;
  52. if (setjmp(png_jmpbuf(png)))
  53. return false;
  54. png_set_write_fn(png, file, &pngWrite, &pngFlush);
  55. png_set_IHDR(png, info, width, height, 8, colorType, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
  56. png_set_compression_level(png, 9);
  57. png_set_rows(png, info, const_cast<png_bytepp>(&rows[0]));
  58. png_write_png(png, info, PNG_TRANSFORM_IDENTITY, NULL);
  59. return true;
  60. }
  61. static bool pngSave(const float *pixels, int width, int height, int rowStride, int channels, int colorType, const char *filename) {
  62. if (!(pixels && width && height))
  63. return false;
  64. std::vector<byte> bytePixels(channels*width*height);
  65. byte *dst = &bytePixels[0];
  66. const float *rowStart = pixels;
  67. for (int y = 0; y < height; ++y) {
  68. for (const float *src = rowStart, *end = rowStart+channels*width; src < end; ++src)
  69. *dst++ = pixelFloatToByte(*src);
  70. rowStart += rowStride;
  71. }
  72. return pngSave(&bytePixels[0], width, height, channels*width, colorType, filename);
  73. }
  74. bool savePng(BitmapConstSection<byte, 1> bitmap, const char *filename) {
  75. bitmap.reorient(Y_DOWNWARD);
  76. return pngSave(bitmap.pixels, bitmap.width, bitmap.height, bitmap.rowStride, PNG_COLOR_TYPE_GRAY, filename);
  77. }
  78. bool savePng(BitmapConstSection<byte, 3> bitmap, const char *filename) {
  79. bitmap.reorient(Y_DOWNWARD);
  80. return pngSave(bitmap.pixels, bitmap.width, bitmap.height, bitmap.rowStride, PNG_COLOR_TYPE_RGB, filename);
  81. }
  82. bool savePng(BitmapConstSection<byte, 4> bitmap, const char *filename) {
  83. bitmap.reorient(Y_DOWNWARD);
  84. return pngSave(bitmap.pixels, bitmap.width, bitmap.height, bitmap.rowStride, PNG_COLOR_TYPE_RGB_ALPHA, filename);
  85. }
  86. bool savePng(BitmapConstSection<float, 1> bitmap, const char *filename) {
  87. bitmap.reorient(Y_DOWNWARD);
  88. return pngSave(bitmap.pixels, bitmap.width, bitmap.height, bitmap.rowStride, 1, PNG_COLOR_TYPE_GRAY, filename);
  89. }
  90. bool savePng(BitmapConstSection<float, 3> bitmap, const char *filename) {
  91. bitmap.reorient(Y_DOWNWARD);
  92. return pngSave(bitmap.pixels, bitmap.width, bitmap.height, bitmap.rowStride, 3, PNG_COLOR_TYPE_RGB, filename);
  93. }
  94. bool savePng(BitmapConstSection<float, 4> bitmap, const char *filename) {
  95. bitmap.reorient(Y_DOWNWARD);
  96. return pngSave(bitmap.pixels, bitmap.width, bitmap.height, bitmap.rowStride, 4, PNG_COLOR_TYPE_RGB_ALPHA, filename);
  97. }
  98. }
  99. #endif
  100. #ifdef MSDFGEN_USE_LODEPNG
  101. #include <lodepng.h>
  102. namespace msdfgen {
  103. bool savePng(BitmapConstSection<byte, 1> bitmap, const char *filename) {
  104. std::vector<byte> pixels(bitmap.width*bitmap.height);
  105. bitmap.reorient(Y_DOWNWARD);
  106. for (int y = 0; y < bitmap.height; ++y)
  107. memcpy(&pixels[bitmap.width*y], bitmap(0, y), 1*bitmap.width);
  108. return !lodepng::encode(filename, pixels, bitmap.width, bitmap.height, LCT_GREY);
  109. }
  110. bool savePng(BitmapConstSection<byte, 3> bitmap, const char *filename) {
  111. std::vector<byte> pixels(3*bitmap.width*bitmap.height);
  112. bitmap.reorient(Y_DOWNWARD);
  113. for (int y = 0; y < bitmap.height; ++y)
  114. memcpy(&pixels[3*bitmap.width*y], bitmap(0, y), 3*bitmap.width);
  115. return !lodepng::encode(filename, pixels, bitmap.width, bitmap.height, LCT_RGB);
  116. }
  117. bool savePng(BitmapConstSection<byte, 4> bitmap, const char *filename) {
  118. std::vector<byte> pixels(4*bitmap.width*bitmap.height);
  119. bitmap.reorient(Y_DOWNWARD);
  120. for (int y = 0; y < bitmap.height; ++y)
  121. memcpy(&pixels[4*bitmap.width*y], bitmap(0, y), 4*bitmap.width);
  122. return !lodepng::encode(filename, pixels, bitmap.width, bitmap.height, LCT_RGBA);
  123. }
  124. bool savePng(BitmapConstSection<float, 1> bitmap, const char *filename) {
  125. std::vector<byte> pixels(bitmap.width*bitmap.height);
  126. std::vector<byte>::iterator it = pixels.begin();
  127. bitmap.reorient(Y_DOWNWARD);
  128. for (int y = 0; y < bitmap.height; ++y) {
  129. for (int x = 0; x < bitmap.width; ++x)
  130. *it++ = pixelFloatToByte(*bitmap(x, y));
  131. }
  132. return !lodepng::encode(filename, pixels, bitmap.width, bitmap.height, LCT_GREY);
  133. }
  134. bool savePng(BitmapConstSection<float, 3> bitmap, const char *filename) {
  135. std::vector<byte> pixels(3*bitmap.width*bitmap.height);
  136. std::vector<byte>::iterator it = pixels.begin();
  137. bitmap.reorient(Y_DOWNWARD);
  138. for (int y = 0; y < bitmap.height; ++y) {
  139. for (int x = 0; x < bitmap.width; ++x) {
  140. *it++ = pixelFloatToByte(bitmap(x, y)[0]);
  141. *it++ = pixelFloatToByte(bitmap(x, y)[1]);
  142. *it++ = pixelFloatToByte(bitmap(x, y)[2]);
  143. }
  144. }
  145. return !lodepng::encode(filename, pixels, bitmap.width, bitmap.height, LCT_RGB);
  146. }
  147. bool savePng(BitmapConstSection<float, 4> bitmap, const char *filename) {
  148. std::vector<byte> pixels(4*bitmap.width*bitmap.height);
  149. std::vector<byte>::iterator it = pixels.begin();
  150. bitmap.reorient(Y_DOWNWARD);
  151. for (int y = 0; y < bitmap.height; ++y) {
  152. for (int x = 0; x < bitmap.width; ++x) {
  153. *it++ = pixelFloatToByte(bitmap(x, y)[0]);
  154. *it++ = pixelFloatToByte(bitmap(x, y)[1]);
  155. *it++ = pixelFloatToByte(bitmap(x, y)[2]);
  156. *it++ = pixelFloatToByte(bitmap(x, y)[3]);
  157. }
  158. }
  159. return !lodepng::encode(filename, pixels, bitmap.width, bitmap.height, LCT_RGBA);
  160. }
  161. }
  162. #endif