|
|
|
#ifndef PNG_HPP
|
|
|
|
#define PNG_HPP
|
|
|
|
|
|
|
|
#include <memory>
|
|
|
|
#include <vector>
|
|
|
|
#include <cassert>
|
|
|
|
#include <cmath>
|
|
|
|
|
|
|
|
#ifndef __APPLE__
|
|
|
|
#include <array>
|
|
|
|
#else
|
|
|
|
#include <tr1/array>
|
|
|
|
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<std::vector<unsigned int>> 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<vstd::vector<unsigned int>>(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<double, 6> power_matrix = {{
|
|
|
|
1.0, 1.5,
|
|
|
|
2.0, 2.5,
|
|
|
|
3.0, 1.5
|
|
|
|
}};
|
|
|
|
std::array<double, 6> 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
|
|
|
|
|