#include <cstdlib>
#include <cmath>
#include <iostream>
#include <string>
#include <vector>
#include <png.h>
int main(int argc, const char **argv)
{
if (argc != 8) {
std::cerr <<"Usage: <width> <height> <iters> <left> <bottom> <right> <top>" << std::endl;
std::cerr <<"PNG file is written to stdout." << std::endl;
exit(EXIT_FAILURE);
}
unsigned long width = strtoul(argv[1], NULL, 10);
unsigned long height = strtoul(argv[2], NULL, 10);
unsigned long iterations = strtoul(argv[3], NULL, 10);
double left = strtod(argv[4], NULL);
double bottom = strtod(argv[5], NULL);
double right = strtod(argv[6], NULL);
double top = strtod(argv[7], NULL);
struct Exception {
const std::string &msg;
Exception(const std::string &msg) : msg(msg) { }
};
int code = EXIT_SUCCESS;
png_structp png_write_struct = NULL;
volatile png_infop info_ptr = NULL;
try {
png_write_struct = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (png_write_struct == NULL)
throw Exception("Could not allocate libpng write_struct.");
info_ptr = png_create_info_struct(png_write_struct);
if (info_ptr == NULL)
throw Exception("Could not allocate libpng info_struct.");
if (setjmp(png_jmpbuf(png_write_struct)))
throw Exception("Exception from libpng");
png_init_io(png_write_struct, stdout);
png_set_IHDR(png_write_struct, info_ptr, width, height, 8, PNG_COLOR_TYPE_RGB,
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
png_write_info(png_write_struct, info_ptr);
std::vector<png_byte> row(3 * width);
for (unsigned long y=0 ; y<height ; y++) {
const double scalar_y = double(y) / height;
const double mb_y = scalar_y * bottom + (1-scalar_y) * top; for (unsigned long x=0 ; x<width ; x++) {
const double scalar_x = double(x) / width;
const double mb_x = scalar_x * right + (1-scalar_x) * left;
row[3*x + 0] = 255;
row[3*x + 1] = 255;
row[3*x + 2] = 255;
double c_x = mb_x;
double c_y = mb_y;
for (unsigned i=1 ; i<iterations ; ++i) {
const double len2 = c_x*c_x + c_y*c_y;
if (len2 > 4) {
float escape_vel = i + 1 - ::log2f(::logf(::sqrtf(len2)));
float tonemapped = escape_vel / (20 + escape_vel);
row[3*x + 0] = png_byte(powf(tonemapped, 10) * 255);
row[3*x + 1] = png_byte(powf(tonemapped, 2.5) * 255);
row[3*x + 2] = png_byte(tonemapped * 255);
break;
}
const double o_x = c_x;
c_x = c_x*c_x - c_y*c_y + mb_x;
c_y = 2 * o_x * c_y + mb_y;
}
}
png_write_row(png_write_struct, &row[0]);
}
png_write_end(png_write_struct, NULL);
} catch (const Exception &e) {
std::cerr << e.msg << std::endl;
code = EXIT_FAILURE;
}
if (png_write_struct != NULL) png_destroy_write_struct(&png_write_struct, (png_infopp)NULL);
if (info_ptr != NULL) png_free_data(png_write_struct, info_ptr, PNG_FREE_ALL, -1);
return code;
}