#ifndef PNG_HPP #define PNG_HPP #include #include #include #include #ifndef __APPLE__ #include #else #include namespace std { using tr1::array; } #endif #include "libpng.hpp" #include "../Canvas.hpp" class PNG : public Canvas { unsigned int width; unsigned int height; unsigned int num_colors; unsigned int* int_array; //std::shared_ptr> int_array; public: double v; PNG(unsigned int width, unsigned int height, unsigned int num_colors = 1) : Canvas(2) , width(width) , height(height) , num_colors(num_colors) , int_array(0) , v(2.0) { //int_array = std::make_shared>(width*height*num_colors); int_array = new unsigned int[width*height*num_colors]; LogInfo("PNG::PNG(): width: %d, height: %d, colors: %d\n", width, height, num_colors); assert(int_array != 0); clear(); LogDebug("New Canvas\n"); } virtual void clear() { std::fill_n(int_array, width*height*num_colors, 0); } virtual void plot(const double* normalizedPosition, const double* normalizedColor) { const double& x = normalizedPosition[0]; const double& y = normalizedPosition[1]; const unsigned int x_int = x*width + width*.5; const unsigned int y_int = y*width + height*.5; const unsigned int index = x_int + width * y_int; if(x_int < width && y_int < height) { if(normalizedColor[0] > 0.0){ int_array[index]++; } else { int_array[index + width*height]++; } } } virtual void output_file(const char* filename_in) const { std::string filename = filename_in; filename += ".png"; unsigned int* max_int = new unsigned int[num_colors]; double* power = new double[num_colors]; for(unsigned int i = 0; i < num_colors; ++i) { max_int[i] = 0; double cumulative = 0; unsigned int n = 0; for(unsigned int j = 0; j < width*height; j++) { if(max_int[i] < int_array[j+i*width*height]) { max_int[i] = int_array[j+i*width*height]; } if(int_array[j+i* width* height] != 0) { cumulative += int_array[j+i*width*height]; n++; } } const double average = cumulative / (double)(width*height); power[i] = -2.5/std::log(average/(double)max_int[i]); if(power[i] < 0) { power[i] = 1; LogInfo("negative power\n"); } if(n < width) { LogInfo("not enough data in dimension %d\n", i); return; } } const double vibrancy = v; double averagePower = 0; for(unsigned int i = 0; i < num_colors; i++) { averagePower += power[i]; } averagePower /= (double)num_colors; for(unsigned int i = 0; i < num_colors; i++) { power[i] = vibrancy*power[i] + (1.0 - vibrancy)*averagePower; } // TODO: find a way to set these things: // pngFile->setcompressionlevel(9); // pngFile->settext("Attractor", "Joshua Moerman", "A awesome attractor", "AwesomeAttractor"); png::image< png::rgb_pixel > image(width, height); std::array power_matrix = {{ 1.0, 1.5, 2.0, 2.5, 3.0, 1.5 }}; std::array output_matrix = {{ 2.0, 2.0, 2.0, 1.5, 2.0, 2.0 }}; for(unsigned int x = 0; x < width; x++) { for(unsigned int y = 0; y < height; y++) { double r = 0.0; double g = 0.0; double b = 0.0; for(unsigned int c = 0; c < num_colors; c++) { const double norm_value = (double)int_array[x + y*width + c*width*height]/max_int[c]; r += (std::pow(norm_value, power[c]*power_matrix[c+0]))*output_matrix[c+0]; g += (std::pow(norm_value, power[c]*power_matrix[c+2]))*output_matrix[c+2]; b += (std::pow(norm_value, power[c]*power_matrix[c+4]))*output_matrix[c+4]; } // TODO: also clamp is below 0 ? r = std::min(1.0, r); b = std::min(1.0, b); g = std::min(1.0, g); image[y][x] = png::rgb_pixel(r*255, g*255, b*255); } } delete[] max_int; delete[] power; LogInfo("Writing %s\n", filename.c_str()); image.write(filename); LogMoreInfo("File written"); } private: PNG(PNG const &); PNG & operator=(PNG const &); }; #endif // PNG_HPP