ImageExport.cpp 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. #include "ImageExport.h"
  2. #include "Bitmap.h"
  3. #include <png.h>
  4. #include <cstdio>
  5. namespace alm
  6. {
  7. void exportPng(const ImageExportInfo& iei, std::function<void(float)> progressCallback)
  8. {
  9. if (iei.generator == nullptr) {
  10. throw "no generator";
  11. }
  12. progressCallback(0.0f);
  13. mnd::MandelGenerator& generator = *iei.generator;
  14. FILE* file = fopen(iei.path.c_str(), "wb");
  15. if(!file) exit(1);
  16. png_structp png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
  17. if (!png) exit(1);
  18. png_infop info = png_create_info_struct(png);
  19. if (!info) exit(1);
  20. if (setjmp(png_jmpbuf(png))) exit(1);
  21. png_init_io(png, file);
  22. const long width = iei.drawInfo.bWidth;
  23. const long height = iei.drawInfo.bHeight;
  24. png_set_IHDR(
  25. png,
  26. info,
  27. width, height,
  28. 8,
  29. PNG_COLOR_TYPE_RGB,
  30. PNG_INTERLACE_NONE,
  31. PNG_COMPRESSION_TYPE_DEFAULT,
  32. PNG_FILTER_TYPE_DEFAULT
  33. );
  34. png_write_info(png, info);
  35. long chunkHeight = height / 20;
  36. if (chunkHeight < 1)
  37. chunkHeight = 1;
  38. if (width >= 4096 && chunkHeight > 64)
  39. chunkHeight = 64;
  40. auto rowPointers = std::make_unique<png_byte*[]>(chunkHeight);
  41. for (long chunkY = 0; chunkY < height; chunkY += chunkHeight) {
  42. auto minimum = [] (const auto& a, const auto& b) { return a < b ? a : b; };
  43. long tmpHeight = minimum(chunkHeight, height - chunkY);
  44. mnd::MandelInfo chunkInfo = iei.drawInfo;
  45. chunkInfo.bHeight = tmpHeight;
  46. chunkInfo.view.y += chunkInfo.view.height * chunkY / height;
  47. chunkInfo.view.height *= mnd::Real(tmpHeight) / height;
  48. Bitmap<float> chunk(width, tmpHeight);
  49. generator.generate(chunkInfo, chunk.pixels.get());
  50. Bitmap<RGBColor> coloredChunk = chunk.map<RGBColor>([&iei] (float i) {
  51. return i >= iei.drawInfo.maxIter ? RGBColor{ 0, 0, 0 } : iei.gradient.get(i);
  52. });
  53. for (long i = 0; i < tmpHeight; i++) {
  54. rowPointers[i] = reinterpret_cast<png_byte*>(&coloredChunk.get(0, i));
  55. }
  56. png_write_rows(png, &rowPointers[0], tmpHeight);
  57. if (chunkY < height)
  58. progressCallback(100.0f * chunkY / height);
  59. }
  60. png_write_end(png, NULL);
  61. fclose(file);
  62. png_destroy_write_struct(&png, &info);
  63. progressCallback(100.0f);
  64. }
  65. }