save-png.cpp 6.2 KB

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