commit 8c57b315af118a6a159da57b6bf85d5194eb44ab
Author: Joshua
Date: Sat Mar 27 21:46:59 2010 +0100
initial state, going to make AwesomeAttractor more OO
diff --git a/Attractor.cpp b/Attractor.cpp
new file mode 100644
index 0000000..5685ebd
--- /dev/null
+++ b/Attractor.cpp
@@ -0,0 +1,345 @@
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+using namespace std;
+
+#include "Attractor.hpp"
+
+
+/*
+ Constructors & initialisers
+*/
+Attractor::Attractor():
+ dim(3), par(4), formula(LORENZ), param(NULL), point(NULL), new_point(NULL) {
+ // Default attractor: 3D Lorenz attrractor
+ init_vector();
+ init_param();
+
+ param[0] = 0.001; //dt
+ param[1] = 10; //sigma
+ param[2] = 28; //rho
+ param[3] = 8.0/3.0; //beta
+
+}
+
+Attractor::Attractor(unsigned int dimensions, FormulaChoice formula, unsigned int orde):
+ dim(dimensions), formula(formula), orde(orde), param(NULL), point(NULL), new_point(NULL) {
+
+ init(dimensions, formula, orde);
+}
+
+Attractor::Attractor(const char* const filename) {
+ ifstream file(filename);
+
+ cout << "Reading file " << filename << "..." << endl;
+
+ if ( !file ) {
+ cout << " Error reading file '" << filename << "' dying now..." << endl;
+ exit(2);
+ }
+
+ /*
+ file.attr:
+ lorenz
+ 3
+ 0
+
+ 3.24454
+ 1.25
+ ....
+ */
+
+ string fileFormula;
+ file >> fileFormula;
+
+ for ( unsigned int i = 0; fileFormula[i] != '\0'; i++ ) {
+ fileFormula[i] = tolower(fileFormula[i]);
+ }
+
+ unsigned int fileDim;
+ file >> fileDim;
+
+ unsigned int fileOrde;
+ file >> fileOrde;
+
+ cout << " Formula: " << fileFormula << endl;
+ cout << " Dimensions: " << fileDim << endl;
+ cout << " Orde: " << fileOrde << endl;
+
+ if ( fileFormula == "lorenz" )
+ init(fileDim, LORENZ, fileOrde);
+ else if ( fileFormula == "poly_n" )
+ init(fileDim, POLY_N, fileOrde);
+ else if ( fileFormula == "poly_a" )
+ init(fileDim, POLY_A, fileOrde);
+ else if ( fileFormula == "logistic" )
+ init(fileDim, LOGISTIC, fileOrde);
+ else if ( fileFormula == "unravel" )
+ init(fileDim, UNRAVEL, fileOrde);
+ else {
+ cout << " Formula not (yet) supported" << endl;
+ exit(3);
+ }
+
+ for ( unsigned int i = 0; i < par; i++ ) {
+ file >> param[i];
+ cout << " Parameter " << i << " set to " << param[i] << ", ";
+ }
+
+ cout << endl << " Reading file complete" << endl;
+}
+
+void Attractor::init(unsigned int dim_in, FormulaChoice formula_in, unsigned int orde_in) {
+
+ dim = dim_in;
+ formula = formula_in;
+ orde = orde_in;
+
+ switch (formula) {
+ case POLY_N: {
+ double n_coef = orde + 1;
+ for (unsigned int i = 2; i <= dim; i++) {
+ n_coef = n_coef*(orde + i)/(i - 1);
+ }
+
+ par = (unsigned int) n_coef;
+ break;
+ }
+ case LORENZ: {
+ assert(dim == 3 || dim == 4);
+ par = dim + 1;
+ break;
+ }
+ case POLY_A: {
+ par = dim;
+ break;
+ }
+ case LOGISTIC: {
+ par = dim;
+ break;
+ }
+ case UNRAVEL: {
+ assert(dim == 3);
+ par = 7;
+ break;
+ }
+ default: {
+ cout << "Formula not recognized" << endl;
+ exit(1);
+ break;
+ }
+ }
+
+ init_vector();
+ init_param();
+}
+
+void Attractor::init_vector() {
+ point = new double[dim];
+ new_point = new double[dim];
+
+ assert(point != NULL);
+ assert(new_point != NULL);
+
+ for ( unsigned int i = 0; i < dim; i++ ) {
+ point[i] = new_point[i] = 0.9;
+ }
+}
+
+void Attractor::init_param() {
+ param = new double[par];
+
+ assert(param != NULL);
+
+ for ( unsigned int i = 0; i < dim; i++ ) {
+ param[i] = 0.0;
+ }
+}
+
+void Attractor::init_range() {
+
+ // stabilize attractor
+ for ( unsigned int i = 0; i < 100000; i++ ) {
+ iterate();
+ if ( !is_chaos() ) {
+ cout << "Attractor died after " << i << " iterations" << endl;
+ exit(0);
+ }
+ }
+
+ // initialize ranges
+ for ( vector::iterator it = projectors.begin(); it != projectors.end(); it++ ) {
+ (*it)->extern_dim = dim;
+ (*it)->intern_dim = 2;
+ (*it)->init(point);
+ }
+
+ // update ranges
+ for ( unsigned int i = 0; i < 100000; i++ ) {
+ iterate();
+ if ( !is_chaos() ) {
+ cout << "Attractor died after " << i << " iterations" << endl;
+ exit(0);
+ }
+
+ for ( vector::iterator it = projectors.begin(); it != projectors.end(); it++ ) {
+ (*it)->update_range(point);
+ }
+
+ }
+ for ( vector::iterator it = projectors.begin(); it != projectors.end(); it++ ) {
+ (*it)->finish_range();
+ }
+}
+
+bool Attractor::is_chaos() {
+ /*
+ check existence of attractor:
+ Escaping
+ Single point attractor
+ Lyapunov exponent
+ */
+
+ double sum = 0;
+ for ( unsigned int i = 0; i < dim; i++ ) {
+ const double dist = new_point[i] - point[i];
+ sum += dist*dist;
+ }
+ if ( sum >= 1.0e7 ) {
+ // big change => Escaping
+ return false;
+ }
+ if ( sum <= 1.0e-7 ) {
+ // small change => singularity
+ return false;
+ }
+ return true;
+}
+
+/*
+ Iteration & Math
+*/
+void Attractor::iterate() {
+ // pointer swap
+ double * temp = point;
+ point = new_point;
+ new_point = temp;
+
+ // calculations
+ switch (formula) {
+ case POLY_N:
+ polynome();
+ break;
+
+ case POLY_A:
+ poly_A();
+ break;
+
+ case POLY_2:
+ poly_2();
+ break;
+
+ case LOGISTIC:
+ logistic();
+ break;
+
+ default:
+ cout << "Formula not recognized" << endl;
+ exit(1);
+ break;
+ }
+
+#ifdef HARDDEBUG
+ cout << "Formula " << formula << " is done" << endl;
+ cout << "Old Vector: ";
+ for ( unsigned int i = 0; i < dim; i++ ) {
+ cout << point[i] << " ";
+ }
+ cout << endl << "Fresh Vector: ";
+ for ( unsigned int i = 0; i < dim; i++ ) {
+ cout << new_point[i] << " ";
+ }
+ cout << endl;
+#endif
+}
+
+void Attractor::polynome() {
+ unsigned int m = 0;
+ for ( unsigned int i = 0; i < dim; i++ ) {
+
+#ifdef HARDDEBUG
+ cout << "Entering new dimension: " << i << " With m = " << m << endl;
+#endif
+
+ new_point[i] = param[m];
+ m++;
+ recur(i, 0, 1, m);
+ }
+
+}
+
+void Attractor::recur(unsigned int curr_dimension, unsigned int prev_i, unsigned int n, unsigned int& m, double prev_product) {
+ double product;
+ for (unsigned int i = prev_i; i < dim; i++) {
+
+#ifdef HARDDEBUG
+ for ( unsigned int j = 0; j < n; j++ )
+ cout << " ";
+ cout << "Calculation in dimension: " << i << " With m = " << m << " And depth = " << n << endl;
+#endif
+
+ product = prev_product * point[i];
+ new_point[curr_dimension] += param[m] * product;
+ m++;
+ if (n < orde) {
+ recur(curr_dimension, i, n+1, m, product);
+ }
+ }
+}
+
+void Attractor::poly_A() {
+ switch (dim) {
+ case 3:
+ new_point[0] = param[0] + point[1] - point[1]*point[2];
+ new_point[1] = param[1] + point[2] - point[2]*point[0];
+ new_point[2] = param[2] + point[0] - point[0]*point[1];
+ break;
+ default:
+ for ( unsigned int i = 0; i < dim; i++ ) {
+ new_point[i] = param[i] + point[(i+1) % dim] - point[(i+1) % dim]*point[(i+2) % dim];
+ }
+ break;
+ }
+}
+
+void Attractor::poly_2() {
+ exit(2);
+}
+
+void Attractor::logistic() {
+ for ( unsigned int i = 0; i < dim; i++ ) {
+ new_point[i] = param[i]*point[i]*(1.0 - point[i]);
+ }
+}
+
+
+void Attractor::plot() {
+ for ( vector::iterator it = projectors.begin(); it != projectors.end(); it++ ) {
+ (*it)->plot(point);
+ }
+}
+
+
+/*
+ IO & control
+*/
+void Attractor::output() {
+ for ( unsigned int i = 0; i < dim; i++ ) {
+ cout << point[i] << " ";
+ }
+ cout << endl;
+}
diff --git a/Attractor.hpp b/Attractor.hpp
new file mode 100644
index 0000000..3a6e116
--- /dev/null
+++ b/Attractor.hpp
@@ -0,0 +1,61 @@
+#ifndef ATTRACTOR_HPP
+#define ATTRACTOR_HPP
+
+#include
+
+//#include "Vector.hpp"
+//#include "Parameters.hpp"
+#include "Projector.hpp"
+#include "AttractorKernel.hpp"
+
+enum FormulaChoice {
+ POLY_N, LORENZ, POLY_A, POLY_2, LOGISTIC, UNRAVEL
+};
+
+class Projector;
+
+// TODO : Verschillende classas AttractorSystem en Attractor maken?
+
+class Attractor {
+public:
+ unsigned int dim;
+ unsigned int par;
+ unsigned int orde;
+ FormulaChoice formula;
+
+ double * param;
+ double * point;
+ double * new_point;
+
+
+ vector projectors;
+
+ public:
+ Attractor();
+ Attractor(unsigned int dimensions, FormulaChoice formula, unsigned int orde = 3);
+ Attractor(const char* const filename);
+
+ void init(unsigned int dimensions, FormulaChoice formula, unsigned int orde);
+
+ void init_vector();
+ void init_param();
+ void init_range();
+
+ // TODO : lyapunov exponent uit rekenen
+ bool is_chaos();
+
+
+ // TODO : optimaliseren voor lage graads veeltermen
+ void iterate();
+ void polynome();
+ void recur(unsigned int curr_dimension, unsigned int prev_i, unsigned int n, unsigned int& m, double prev_product = 1.0);
+ void poly_A();
+ void poly_2();
+ void logistic();
+
+ void plot();
+ void output();
+};
+
+#endif // ATTRACTOR_HPP
+
diff --git a/AttractorKernel.hpp b/AttractorKernel.hpp
new file mode 100644
index 0000000..850c09f
--- /dev/null
+++ b/AttractorKernel.hpp
@@ -0,0 +1,33 @@
+#ifndef ATTRACTORKERNEL_HPP
+#define ATTRACTORKERNEL_HPP
+
+#include
+using namespace std;
+
+class AttractorKernel {
+ public:
+
+ // AttractorKernel protocol
+
+ // parameters are stored in a array of doubles
+ // if you want to use other types, use the properties
+ virtual double& parameter(const unsigned int index) = 0;
+ virtual double*& parameters() = 0;
+
+ // get properties of the attractor
+ // such as the dimension
+ // you should delete the void pointer if you used it
+ virtual void * getProperty(const string identifier) = 0;
+ virtual void setProperty(const string identifier, const void * value) = 0;
+
+ // iterate his formula
+ // vector pointers will be swapped! so new remains new and old remains old
+ virtual void iterate() = 0;
+
+ // getter functions for teh resulta
+ virtual double * & vector() = 0;
+ virtual double * & previousVector() = 0;
+};
+
+#endif // ATTRACTORKERNEL_HPP
+
diff --git a/AwesomeAttractor.cbp b/AwesomeAttractor.cbp
new file mode 100644
index 0000000..0f63995
--- /dev/null
+++ b/AwesomeAttractor.cbp
@@ -0,0 +1,64 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/AwesomeAttractor.layout b/AwesomeAttractor.layout
new file mode 100644
index 0000000..270d711
--- /dev/null
+++ b/AwesomeAttractor.layout
@@ -0,0 +1,52 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/AwesomeAttractor.layout.save b/AwesomeAttractor.layout.save
new file mode 100644
index 0000000..ffebfd3
--- /dev/null
+++ b/AwesomeAttractor.layout.save
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Canvas.cpp b/Canvas.cpp
new file mode 100644
index 0000000..2072b56
--- /dev/null
+++ b/Canvas.cpp
@@ -0,0 +1,238 @@
+#include
+#include
+#include
+#include
+#include
+#include
+using namespace std;
+
+#include "pngwriter/pngwriter.h"
+
+#include "Canvas.hpp"
+
+
+Canvas::Canvas(unsigned int width, unsigned int height, unsigned int num_colors):
+ dim(2), width(width), height(height), num_colors(num_colors), v(0) {
+
+ int_array = new unsigned int[width*height*num_colors];
+ size = new unsigned int[2];
+ size[0] = width;
+ size[1] = height;
+
+ assert(int_array != NULL);
+
+ clear();
+
+#ifdef HARDDEBUG
+ cout << "New canvas" << endl;
+#endif
+}
+
+void Canvas::clear() {
+ for ( unsigned int i = 0; i < width*height*num_colors; i++ ) {
+ int_array[i] = 0;
+ }
+}
+
+
+
+//void Canvas::update_viewwindow() {
+//
+// //width and height of attractor
+// const double dx = xmax - xmin;
+// const double dy = ymax - ymin;
+//
+// //fix aspect ratio
+// if ( dx > dy * ((float)width / height) ) {
+// const double height2 = dx * ((float)height / width);
+// const double middle = 0.5 * (ymax + ymin);
+// ymax = middle + 0.5 * height2;
+// ymin = middle - 0.5 * height2;
+//
+// } else {
+// const double width2 = dy * ((float)width / height);
+// const double middle = 0.5 * (xmax + xmin);
+// xmax = middle + 0.5 * width2;
+// xmin = middle - 0.5 * width2;
+// }
+//
+// //add a 4% marge
+// xmin -= 0.02 * dx;
+// xmax += 0.02 * dx;
+// ymin -= 0.02 * dy;
+// ymax += 0.02 * dy;
+//
+// //constants for speed
+// constant1 = width / (xmax - xmin);
+// constant2 = height / (ymax - ymin);
+//}
+
+void Canvas::plot(double x, double y) {
+ // gets x and y coordinate
+ // ranges [-1, 1] and [-1, 1]
+ // so how to do the aspect shiz, i don't know
+ 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) {
+ int_array[index]++;
+ }
+}
+
+void Canvas::plot(double x, double y, unsigned int c) {
+ // same as plot(double x, double y)
+ // now with color control
+ 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 + width*height*c;
+
+ if(x_int < width && y_int < height) {
+ int_array[index]++;
+ }
+}
+
+void Canvas::plot(double x, double y, unsigned int c, double intensity) {
+ // same as plot(double x, double y, unsigned int c)
+ // but now uses the float array (not yet implemented
+}
+
+/*
+ I/O functions
+*/
+void Canvas::output() {
+ cout << "Canvas: " << endl;
+ cout << "Dimensions: " << width << " x " << height << " x " << num_colors << endl;
+}
+
+void Canvas::output_file(const char * filename){
+ 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] ) {
+ cumulative += int_array[j+i*width*height];
+ n++;
+ }
+ }
+
+ if ( n > 100 ) {
+ const double average = cumulative / (double)n;
+ power[i] = -2.5/log(average/(double)max_int[i]);
+ if ( power[i] < 0 )
+ power[i] = 1;
+ } else {
+ power[i] = 1;
+ }
+
+ if ( n <= 10 ) {
+ cout << "not enough data" << endl;
+ }
+ }
+
+ const double vibrancy = v;
+ double averagePower = 0;
+ for ( unsigned int i = 0; i < num_colors; i++ ) {
+ averagePower += power[i];
+ }
+ averagePower /= num_colors;
+ for ( unsigned int i = 0; i < num_colors; i++ ) {
+ power[i] = vibrancy*power[i] + (1.0 - vibrancy*averagePower);
+ }
+
+ pngwriter * pngFile = new pngwriter(width, height, 0.0, filename);
+ pngFile->setcompressionlevel(9);
+ pngFile->settext("Attractor", "Joshua Moerman", "A awesome attractor", "AwesomeAttractor");
+
+ 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];
+ switch(c){
+ case 0: {
+ r = (pow(norm_value, power[c]))*3.0;
+ break;
+ }
+ case 1: {
+ g = (pow(norm_value, power[c]))*3.0;
+ break;
+ }
+ case 2: {
+ b = (pow(norm_value, power[c]))*3.0;
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ //pngwriter clips values for me
+ pngFile->plot(x, y, r, g, b);
+ }
+ }
+
+
+ delete max_int;
+ delete power;
+
+ pngFile->close();
+
+}
+
+void Canvas::output_file(){
+ char filename[50];
+ time_t t = time(0);
+ struct tm* lt = localtime(&t);
+ int r = rand() % 10;
+
+ sprintf(filename, "render/attractor_%04d-%02d-%02d_%02d-%02d-%02d-%01d.png", lt->tm_year + 1900, lt->tm_mon + 1, lt->tm_mday, lt->tm_hour, lt->tm_min, lt->tm_sec, r);
+
+ output_file(filename);
+}
+
+
+void Canvas::output_raw(const char * filename){
+
+ ofstream outfile (filename, ofstream::binary);
+
+ outfile.write(reinterpret_cast(int_array), sizeof(unsigned int)*width*height*num_colors);
+
+}
+
+void Canvas::output_raw(){
+ char filename[52];
+ time_t t = time(0);
+ struct tm* lt = localtime(&t);
+ int r = rand() % 10;
+
+ sprintf(filename, "render/canv%dx%d_%04d-%02d-%02d_%02d-%02d-%02d-%01d.canv", width, height, lt->tm_year + 1900, lt->tm_mon + 1, lt->tm_mday, lt->tm_hour, lt->tm_min, lt->tm_sec, r);
+
+ output_raw(filename);
+}
+
+void Canvas::input_raw(const char * filename){
+ ifstream infile(filename, ifstream::binary);
+
+ if ( ! infile ) {
+ cout << "poep" << endl;
+ return;
+ }
+
+ infile.seekg (0, ios::end);
+ int length = infile.tellg();
+ infile.seekg (0, ios::beg);
+
+ cout << "length: " << length << " =? " << static_cast(width*height*num_colors*sizeof(unsigned int)) << endl;
+
+ infile.read (reinterpret_cast(int_array), sizeof (unsigned int)*width*height*num_colors);
+}
diff --git a/Canvas.hpp b/Canvas.hpp
new file mode 100644
index 0000000..2e82d8f
--- /dev/null
+++ b/Canvas.hpp
@@ -0,0 +1,50 @@
+#ifndef CANVAS_HPP
+#define CANVAS_HPP
+
+
+//#include "Vector.hpp"
+#include "Attractor.hpp"
+#include "Projector.hpp"
+
+// TODO : Canvas class abstraheren (zodat er makkelijk verschillende soorten canvae gemaakt kunnen worden)
+
+class Canvas{
+ friend class Projector;
+
+ unsigned int dim;
+ unsigned int width;
+ unsigned int height;
+ unsigned int num_colors;
+
+ unsigned int * size;
+
+ unsigned int * int_array;
+
+ public:
+
+ double v;
+
+ Canvas(unsigned int width, unsigned int height, unsigned int num_colors = 1);
+
+ void clear();
+
+ void plot(double x, double y);
+ void plot(double x, double y, unsigned int c);
+ // TODO : make double array in canvas (ander soort canvas)
+ // TODO : subpixel sampling (anders soort canvas)
+ void plot(double x, double y, unsigned int c, double intensity);
+
+ void output();
+ //void output(Vector& point);
+
+ void output_file(const char * filename);
+ void output_file();
+ void output_raw(const char * filename);
+ void output_raw();
+ void input_raw(const char * filename);
+};
+
+
+
+#endif // CANVAS_HPP
+
diff --git a/Parameters.cpp b/Parameters.cpp
new file mode 100644
index 0000000..441d523
--- /dev/null
+++ b/Parameters.cpp
@@ -0,0 +1,110 @@
+#include
+using namespace std;
+
+#include "Parameters.hpp"
+
+
+Parameters::Parameters(unsigned int num_parameters, float default_val):
+ num_parameters(num_parameters) {
+ begin = new (nothrow) Vector(num_parameters, default_val);
+ eind = new (nothrow) Vector(num_parameters, default_val);
+ interpolated = new (nothrow) Vector(num_parameters, default_val);
+ // *interpolated = *begin
+
+ check_pointers();
+
+#ifdef HARDDEBUG
+ cout << "New Parameters with one default val:" << endl << *this << endl;
+#endif
+}
+
+/*Parameters::Parameters(unsigned int num_parameters, float default_val1, float default_val2):
+ num_parameters(num_parameters) {
+ begin = new (nothrow) Vector(num_parameters, default_val1);
+ eind = new (nothrow) Vector(num_parameters, default_val2);
+ interpolated = new (nothrow) Vector(num_parameters, default_val1);
+ // *interpolated = *begin
+
+ check_pointers();
+
+#ifdef HARDDEBUG
+ cout << "New Parameters with two default vals:" << endl << *this << endl;
+#endif
+}*/
+
+Parameters::~Parameters() {
+ delete begin;
+ delete eind;
+ delete interpolated;
+
+#ifdef HARDDEBUG
+ cout << "Parameters deleted" << endl;
+#endif
+}
+
+void Parameters::check_pointers() {
+ assert(begin != NULL);
+ assert(eind != NULL);
+ assert(interpolated != NULL);
+}
+
+void Parameters::set(unsigned int parameter, float val1, float val2) {
+ assert(parameter < num_parameters);
+
+ begin->coordinates[parameter] = val1;
+ eind->coordinates[parameter] = val2;
+ interpolated->coordinates[parameter] = val1;
+
+#ifdef HARDDEBUG
+ cout << "Parameter " << parameter << " set to: " << val1 << " - " << val2 << endl;
+#endif
+}
+
+void Parameters::set(unsigned int parameter, float val) {
+ assert(parameter < num_parameters);
+
+ begin->coordinates[parameter] = val;
+ eind->coordinates[parameter] = val;
+ interpolated->coordinates[parameter] = val;
+
+#ifdef HARDDEBUG
+ cout << "Parameter " << parameter << " set to: " << val << endl;
+#endif
+}
+
+float Parameters::get(unsigned int parameter) {
+ assert(parameter < num_parameters);
+
+#ifdef HARDDEBUG
+ cout << "Asked for parameter " << parameter << " with value:" << interpolated->coordinates[parameter] << endl;
+#endif
+
+ return interpolated->coordinates[parameter];
+
+}
+
+void Parameters::interpolate(float time) {
+ /*
+ Dit is mogelijk met vector rekenen:
+ (*interpolated) = (*begin) * ( 1.0 - time ) + (*eind) * time;
+ Maar we doen het per element, zodat we simpelere code hebben,
+ geen vectoren hoeven te returnen en makkelijker kunnen optimaliseren
+ */
+ const float invtime = 1.0 - time;
+ for ( unsigned int i = 0; i < num_parameters; i++ ) {
+ interpolated->coordinates[i] = invtime * begin->coordinates[i] + time * eind->coordinates[i];
+ }
+
+#ifdef HARDDEBUG
+ cout << "interpolate() result" << endl << *interpolated << endl;
+#endif
+}
+
+ostream& operator<<(ostream& os, const Parameters& param) {
+ os << param.num_parameters << endl;
+ os << "Begin:" << endl << *param.begin << endl;
+ os << "Eind:" << endl << *param.eind << endl;
+ os << "Interpolated:" << endl << *param.interpolated << endl;
+ os <
+#include
+#include
+#include
+using namespace std;
+
+#include "Projector.hpp"
+#include "Canvas.hpp"
+#include "myMath.hpp"
+
+void Projector::init(double * point) {
+ init_vector();
+
+ project(point);
+ init_range();
+}
+
+void Projector::init_vector() {
+ project_point = new double[intern_dim];
+ offset = new double[intern_dim];
+
+ assert(project_point != NULL);
+ assert(offset != NULL);
+}
+
+void Projector::init_range() {
+ range_min = new double[intern_dim];
+ range_max = new double[intern_dim];
+
+ assert(range_min != NULL);
+ assert(range_max != NULL);
+
+ for ( unsigned int i = 0; i < intern_dim; i++ ) {
+ range_min[i] = range_max[i] = project_point[i];
+ }
+}
+
+void Projector::update_range(double * point) {
+ project(point);
+ for ( unsigned int i = 0; i < intern_dim; i++ ) {
+ if ( project_point[i] < range_min[i] ) {
+ range_min[i] = project_point[i];
+ } else if ( project_point[i] > range_max[i] ) {
+ range_max[i] = project_point[i];
+ }
+ }
+}
+
+void Projector::finish_range() {
+// double max_dist = 0.0;
+// for ( unsigned int i = 0; i < intern_dim; i++ ) {
+// const double dist = range_max[i] - range_min[i];
+// if ( dist > max_dist )
+// max_dist = dist;
+// }
+//
+// factor = 0.9/max_dist;
+// for ( unsigned int i = 0; i < intern_dim; i++ ) {
+// offset[i] = -0.5*factor*(range_min[i] + range_max[i]);
+// }
+
+ factor = canvas->size[0] / (range_max[0] - range_min[0]);
+ unsigned int teh_size = canvas->size[0];
+ for ( unsigned int i = 1; i < intern_dim; i++ ) {
+ double dist = range_max[i] - range_min[i];
+ if ( factor * dist > (double)canvas->size[i] ) {
+ factor = (double)canvas->size[i] / dist;
+ //teh_size = canvas->size[i];
+ cout << "crap for dim" << i << endl;
+ }
+ }
+
+ factor /= (double)teh_size;
+
+ for ( unsigned int i = 0; i < intern_dim; i++ ) {
+ offset[i] = -0.5*factor*(range_min[i] + range_max[i]);
+ }
+}
+
+
+void Projector::project(double * point) {
+ assert(extern_dim >= 2);
+ project_point[0] = point[0];
+ project_point[1] = point[1];
+}
+
+
+void Projector::plot(double * point) {
+ project(point);
+
+ const double x = project_point[0]*factor + offset[0];
+ const double y = project_point[1]*factor + offset[1];
+
+ //cout << x << ", " << y << endl;
+
+ canvas->plot(x, y);
+ if ( even(point[2]*4.0) )
+ canvas->plot(x, y, 1);
+ else
+ canvas->plot(x, y, 2);
+}
+
+
+void Projector::output(){
+ cout << "Projector properties: " << endl;
+ cout << " factor: " << factor << endl;
+ for ( unsigned int i = 0; i < intern_dim; i++ ) {
+ cout << " dimension " << i << ": offset: " << offset[i] << ", range: [" << range_min[i] << ", " << range_max[i] << "]" << endl;
+ }
+}
+
diff --git a/Projector.hpp b/Projector.hpp
new file mode 100644
index 0000000..b6b86c8
--- /dev/null
+++ b/Projector.hpp
@@ -0,0 +1,45 @@
+#ifndef PROJECTOR_HPP
+#define PROJECTOR_HPP
+
+#include
+
+#include "Canvas.hpp"
+
+class Canvas;
+
+class Projector{
+ public:
+
+ unsigned int extern_dim;
+ unsigned int intern_dim;
+
+ Canvas * canvas;
+ double * project_point;
+
+ double * range_min;
+ double * range_max;
+ double factor;
+ double * offset;
+
+ void init(double * point);
+ void init_vector();
+ void init_range();
+ void update_range(double * point);
+ void finish_range();
+
+
+ // TODO : Matrix gebruiken voor lineaire afbeelding
+ // TODO : Over kleuren nadenken
+ /*
+ Kleurmodi:
+ -genormalizeerde coordinaten als kleurintensiteit (gebruikt fp canvas)
+ -kleurbanden, dus met een periodieke functie (gebruikt int canvas)
+ */
+ void project(double * point);
+ void plot(double * point);
+
+ void output();
+};
+
+#endif // PROJECTOR_HPP
+
diff --git a/Vector.cpp b/Vector.cpp
new file mode 100644
index 0000000..76ca201
--- /dev/null
+++ b/Vector.cpp
@@ -0,0 +1,126 @@
+#include
+using namespace std;
+
+#include "Vector.hpp"
+
+Vector::Vector():
+ dimension(0) {
+
+ coordinates = new (nothrow) float[0];
+
+ assert(coordinates != NULL);
+
+#ifdef HARDDEBUG
+ cout << "New vector (without elements)" << endl;
+#endif
+}
+
+Vector::Vector(unsigned int d):
+ dimension(d) {
+
+ coordinates = new (nothrow) float[dimension];
+
+ assert(coordinates != NULL);
+
+#ifdef HARDDEBUG
+ cout << "New vector:" << endl << *this << endl;
+#endif
+}
+
+Vector::Vector(unsigned int d, float default_val):
+ dimension(d) {
+
+ coordinates = new (nothrow) float[dimension];
+
+ assert(coordinates != NULL);
+
+ for (unsigned int i = 0; i < dimension; i++) {
+ coordinates[i] = default_val;
+ }
+
+#ifdef HARDDEBUG
+ cout << "New vector with default values:" << endl << *this << endl;
+#endif
+}
+
+
+Vector::~Vector() {
+ delete[] coordinates;
+
+#ifdef HARDDEBUG
+ cout << "coordinates deleted" << endl;
+#endif
+}
+
+
+Vector& Vector::operator=(const Vector& a) {
+ if ( dimension != a.dimension ) {
+ dimension = a.dimension;
+ delete[] coordinates;
+ coordinates = new float[dimension];
+
+#ifdef HARDDEBUG
+ cout << "Dimensions were not equal, made new vector" << endl;
+#endif
+ }
+
+ for ( unsigned int i = 0; i < dimension; i++ ) {
+ coordinates[i] = a.coordinates[i];
+ }
+
+#ifdef HARDDEBUG
+ cout << "operator= result" << endl << *this << endl;
+#endif
+
+ return *this;
+}
+
+
+ostream& operator<<(ostream& os, const Vector& a) {
+ os << a.dimension << endl;
+ for ( unsigned int i = 0; i < a.dimension; i++ ) {
+ os << a.coordinates[i] << " ";
+ }
+
+ os << endl;
+ return os;
+}
+
+
+float& Vector::operator[](const unsigned int index) {
+ assert(index < dimension);
+ return coordinates[index];
+}
+
+// matig werkende optelling en scalaire vermenigvuldiging van vectoren
+/*
+Vector Vector::operator+(const Vector a) const {
+ if ( dimension != a.dimension ) {
+ cout << "WARNING: dimensions not equal in vector addition" << endl;
+ exit(1);
+ } else {
+ static Vector ret(dimension);
+ for ( unsigned int i = 0; i < dimension; i++ ) {
+ ret.coordinates[i] = coordinates[i] + a.coordinates[i];
+ }
+
+#ifdef HARDDEBUG
+ cout << "operator+ result" << endl << ret << endl;
+#endif
+ return ret;
+ }
+}
+
+
+Vector Vector::operator*(const float a) const {
+ static Vector ret(dimension);
+ for ( unsigned int i = 0; i < dimension; i++ ) {
+ ret.coordinates[i] = coordinates[i] * a;
+ }
+
+#ifdef HARDDEBUG
+ cout << "operator* result" << endl << ret << endl;
+#endif
+ return ret;
+}
+*/
diff --git a/Vector.hpp b/Vector.hpp
new file mode 100644
index 0000000..e7f846f
--- /dev/null
+++ b/Vector.hpp
@@ -0,0 +1,31 @@
+#ifndef VECTOR_HPP
+#define VECTOR_HPP
+
+class Vector {
+ public:
+
+ unsigned int dimension;
+ float * coordinates;
+
+ // const, dest
+ Vector();
+ Vector(unsigned int d);
+ Vector(unsigned int d, float default_val);
+ ~Vector();
+
+ // output operator
+ friend ostream& operator<<(ostream& os, const Vector& a);
+
+ // easy access
+ float& Vector::operator[](const unsigned int index);
+
+ // vector rekenen
+ Vector& operator=(const Vector& a);
+ // faaloperatoren
+ // Vector operator+(const Vector a) const;
+ // Vector operator*(const float a) const;
+};
+
+
+#endif // VECTOR_HPP
+
diff --git a/batchexport.sh b/batchexport.sh
new file mode 100644
index 0000000..4ea537c
--- /dev/null
+++ b/batchexport.sh
@@ -0,0 +1,14 @@
+CANVEXT=".canv"
+PNGEXT=".png"
+CANVPATH="canvas/"
+PNGPATH="render/"
+
+cd $CANVPATH
+
+for FILE in `ls *$CANVEXT | sed -e 's/'$CANVEXT'$//'`
+do
+ ../bin/Debug/AwesomeAttractor -c ../$CANVPATH$FILE$CANVEXT 3200 3200 3 ../$PNGPATH$FILE$PNGEXT
+ #Do other stuff with file
+done
+
+
diff --git a/batchrender.sh b/batchrender.sh
new file mode 100644
index 0000000..f4bd865
--- /dev/null
+++ b/batchrender.sh
@@ -0,0 +1,17 @@
+ATTREXT=".attr"
+CANVEXT=".canv"
+ATTRPATH="attr/"
+CANVPATH="canvas/"
+
+cd $ATTRPATH
+
+for FILE in `ls *$ATTREXT | sed -e 's/'$ATTREXT'$//'`
+do
+ ../bin/Debug/AwesomeAttractor -a ../$ATTRPATH$FILE$ATTREXT 500 ../$CANVPATH$FILE$CANVEXT 800 600 3
+ #Do other stuff with file
+done
+
+cd ..
+
+zip -r canvae.zip $CANVPATH*$CANVEXT
+
diff --git a/kernels/Lorenz.cpp b/kernels/Lorenz.cpp
new file mode 100644
index 0000000..1b869a2
--- /dev/null
+++ b/kernels/Lorenz.cpp
@@ -0,0 +1,73 @@
+#include "Lorenz.hpp"
+
+Lorenz::Lorenz() {
+ init();
+}
+
+void Lorenz::init() {
+ // allocation
+ myParameters = new double[4];
+ vectorNew = new double[3];
+ vectorOld = new double[3];
+
+ // initialisation
+ assert(myParameters != NULL);
+ assert(vectorNew != NULL);
+ assert(vectorOld != NULL);
+ for ( unsigned int i = 0; i < 4; i++ ) {
+ myParameters[i] = 0.0;
+ }
+ for ( unsigned int i = 0; i < 3; i++ ) {
+ vectorNew[i] = vectorOld[i] = 1.0;
+ }
+}
+
+// the main function
+void Lorenz::iterate() {
+ swap(vectorNew, vectorOld);
+
+ vectorNew[0] = vectorOld[0] + myParameters[0] * myParameters[1] * (vectorOld[1] - vectorOld[0]);
+ vectorNew[1] = vectorOld[1] + myParameters[0] * (vectorOld[0] * (myParameters[2] - vectorOld[2]) - vectorOld[1]);
+ vectorNew[2] = vectorOld[2] + myParameters[0] * (vectorOld[0] * vectorOld[1] - myParameters[3] * vectorOld[2]);
+}
+
+/*
+4D:
+ new_point[0] = point[0] + param[0] * param[1] * (point[1] - point[0]);
+ new_point[1] = point[1] + param[0] * (point[0] * (param[2] - point[2]) - point[1] + point[3]);
+ new_point[2] = point[2] + param[0] * (point[0] * point[1] - param[3] * point[2]);
+ new_point[3] = point[3] - param[0] * param[4] * point[0];
+ break;
+*/
+
+// setters, getters, all i/o to other classes/objects
+void * Lorenz::getProperty(const string identifier) {
+ if ( identifier == "dimension" ) {
+ unsigned int * _return = new unsigned int;
+ *_return = 3;
+ return _return;
+ }
+ return NULL;
+}
+
+void Lorenz::setProperty(const string identifier, const void * value) {
+ return;
+}
+
+double * & Lorenz::parameters() {
+ return myParameters;
+}
+
+double & Lorenz::parameter(const unsigned int index) {
+ return myParameters[index];
+}
+
+double * & Lorenz::vector() {
+ return vectorNew;
+}
+
+double * & Lorenz::previousVector() {
+ return vectorOld;
+}
+
+
diff --git a/kernels/Lorenz.hpp b/kernels/Lorenz.hpp
new file mode 100644
index 0000000..dce9fab
--- /dev/null
+++ b/kernels/Lorenz.hpp
@@ -0,0 +1,48 @@
+#ifndef LORENZ_HPP
+#define LORENZ_HPP
+
+#include
+#include
+#include
+#include
+using namespace std;
+
+#include "../AttractorKernel.hpp"
+
+class Lorenz : public AttractorKernel {
+
+ double * myParameters;
+
+ double * vectorNew;
+ double * vectorOld;
+
+ void init();
+
+ public:
+
+ Lorenz();
+ Lorenz(const unsigned int dimensions);
+
+ // parameters are stored in a array of doubles
+ // if you want to use other types, use the properties
+ virtual double& parameter(const unsigned int index);
+ virtual double*& parameters();
+
+ // get properties of the attractor
+ // such as the dimension
+ // you should delete the void pointer if you used it
+ virtual void * getProperty(const string identifier);
+ virtual void setProperty(const string identifier, const void * value);
+
+ // iterate his formula
+ // vector pointers will be swapped! so new remains new and old remains old
+ virtual void iterate();
+
+ // getter functions for teh resulta
+ virtual double * & vector();
+ virtual double * & previousVector();
+
+};
+
+#endif // LORENZ_HPP
+
diff --git a/kernels/Unravel.cpp b/kernels/Unravel.cpp
new file mode 100644
index 0000000..939dc85
--- /dev/null
+++ b/kernels/Unravel.cpp
@@ -0,0 +1,71 @@
+#include "Unravel.hpp"
+
+Unravel::Unravel(){
+ init();
+}
+
+void Unravel::init() {
+ // allocation
+ myParameters = new double[4];
+ vectorNew = new double[3];
+ vectorOld = new double[3];
+
+ // initialisation
+ assert(myParameters != NULL);
+ assert(vectorNew != NULL);
+ assert(vectorOld != NULL);
+ for ( unsigned int i = 0; i < 7; i++ ) {
+ myParameters[i] = 0.0;
+ }
+ for ( unsigned int i = 0; i < 3; i++ ) {
+ vectorNew[i] = vectorOld[i] = 0.0;
+ }
+}
+
+void Unravel::iterate() {
+ swap(vectorNew, vectorOld);
+
+ vectorNew[0] = myParameters[0]*(vectorOld[2] + myParameters[1]);
+ vectorNew[1] = myParameters[2]*(vectorOld[0] + myParameters[3]);
+ vectorNew[2] = myParameters[4]*(vectorOld[1] + myParameters[5]);
+
+ const double dist = vectorNew[0]*vectorNew[0] + vectorNew[1]*vectorNew[1] + vectorNew[2]*vectorNew[2];
+
+ if ( dist > myParameters[6]*myParameters[6] ) {
+ const double sqrtDist = sqrt(dist);
+ const double p = 1.0 - myParameters[6] * ( static_cast ( sqrtDist / myParameters[6] ) + 1.0 ) / sqrtDist;
+ vectorNew[0] *= p;
+ vectorNew[1] *= p;
+ vectorNew[2] *= p;
+ }
+}
+
+// setters, getters, all i/o to other classes/objects
+void * Unravel::getProperty(const string identifier) {
+ if ( identifier == "dimension" ) {
+ unsigned int * _return = new unsigned int;
+ *_return = 3;
+ return _return;
+ }
+ return NULL;
+}
+
+void Unravel::setProperty(const string identifier, const void * value) {
+ return;
+}
+
+double * & Unravel::parameters() {
+ return myParameters;
+}
+
+double & Unravel::parameter(const unsigned int index) {
+ return myParameters[index];
+}
+
+double * & Unravel::vector() {
+ return vectorNew;
+}
+
+double * & Unravel::previousVector() {
+ return vectorOld;
+}
diff --git a/kernels/Unravel.hpp b/kernels/Unravel.hpp
new file mode 100644
index 0000000..3464c87
--- /dev/null
+++ b/kernels/Unravel.hpp
@@ -0,0 +1,49 @@
+#ifndef UNRAVEL_HPP
+#define UNRAVEL_HPP
+
+#include
+#include
+#include
+#include
+#include
+using namespace std;
+
+#include "../AttractorKernel.hpp"
+
+class Unravel : public AttractorKernel {
+
+ double * myParameters;
+
+ double * vectorNew;
+ double * vectorOld;
+
+ void init();
+
+ public:
+
+ Unravel();
+ Unravel(const unsigned int dimensions);
+
+ // parameters are stored in a array of doubles
+ // if you want to use other types, use the properties
+ virtual double& parameter(const unsigned int index);
+ virtual double*& parameters();
+
+ // get properties of the attractor
+ // such as the dimension
+ // you should delete the void pointer if you used it
+ virtual void * getProperty(const string identifier);
+ virtual void setProperty(const string identifier, const void * value);
+
+ // iterate his formula
+ // vector pointers will be swapped! so new remains new and old remains old
+ virtual void iterate();
+
+ // getter functions for teh resulta
+ virtual double * & vector();
+ virtual double * & previousVector();
+
+};
+
+#endif // UNRAVEL_HPP
+
diff --git a/main.cpp b/main.cpp
new file mode 100644
index 0000000..075417e
--- /dev/null
+++ b/main.cpp
@@ -0,0 +1,133 @@
+#include
+using namespace std;
+
+#include "Attractor.hpp"
+#include "Canvas.hpp"
+#include "Projector.hpp"
+
+#include "AttractorKernel.hpp"
+#include "kernels/Lorenz.hpp"
+
+// TODO : Allemaal files inlezen, voor makkelijker gebruik
+
+int main(int argc, char *argv[]) {
+
+
+ AttractorKernel * mijnAttractortje;
+ mijnAttractortje = new Lorenz();
+ AttractorKernel &attractor = *mijnAttractortje;
+
+ attractor.parameter(0) = 1.0;
+ attractor.parameter(2) = 2.0;
+
+ double * & vector = attractor.vector();
+
+ unsigned int * _dimension = (unsigned int*)mijnAttractortje->getProperty("dimension");
+ unsigned int dimension = *_dimension;
+ delete _dimension;
+
+ cout << "Dimension = " << dimension << endl;
+
+ for ( unsigned int i = 0; i < 20; i++ ) {
+ mijnAttractortje->iterate();
+ cout << "vector = ";
+ for ( unsigned int i = 0; i < dimension; i++ ) {
+ cout << " " << vector[i];
+ }
+ cout << endl;
+ }
+
+
+ /*if ( argc <= 2 ) {
+ cout << endl << "nothing to do..." << endl;
+ cout << "usage:" << endl;
+ cout << " rendering to canvas: -a my_attractor.attr 500000000 my_attractor.canv 800 600 3" << endl;
+ cout << " canvas to png: -c my_attractor.canv 800 600 3 my_atttractor.png" << endl << endl;
+ exit(0);
+ }
+
+ int mode;
+ string argv1 = argv[1];
+ if ( argv1 == "-a" ) {
+ cout << "rendermode" << endl;
+ mode = 1;
+ } else if ( argv1 == "-c" ) {
+ cout << "canvasmode" << endl;
+ mode = 2;
+ } else {
+ cout << "i do.. i do... i do not understand... \"" << argv1 << "\""<< endl;
+ exit(0);
+ }
+
+ switch ( mode ) {
+ case 1: {
+ if ( argc != 8 ) {
+ cout << "all parameters must be set..." << endl;
+ exit(0);
+ }
+
+ string attractorFile = argv[2];
+ unsigned int iterations = atoi(argv[3]);
+ string canvasFile = argv[4];
+ unsigned int width = atoi(argv[5]);
+ unsigned int height = atoi(argv[6]);
+ unsigned int numColors = atoi(argv[7]);
+
+ Attractor attract(attractorFile.c_str());
+ cout << attractorFile << " is read" << endl;
+
+ Projector projection;
+ Canvas canvas(width, height, numColors);
+ projection.canvas = &canvas;
+
+ attract.projectors.push_back(&projection);
+ attract.init_range();
+
+ projection.output();
+
+ for ( unsigned int j = 1; j <= 100; j++ ) {
+ for ( unsigned int i = 0; 100*i <= iterations; i++ ) {
+ attract.iterate();
+ attract.plot();
+ }
+ cout << j << "% done" << endl;
+ }
+
+ canvas.output_raw(canvasFile.c_str());
+ cout << canvasFile << " is outputted" << endl;
+
+ break;
+ }
+ case 2: {
+ if ( argc != 7 ) {
+ cout << "all parameters must be set..." << endl;
+ exit(0);
+ }
+
+ string canvasFile = argv[2];
+ unsigned int width = atoi(argv[3]);
+ unsigned int height = atoi(argv[4]);
+ unsigned int numColors = atoi(argv[5]);
+ string pngFile = argv[6];
+
+ Canvas canvas(width, height, numColors);
+ canvas.input_raw(canvasFile.c_str());
+ cout << canvasFile << " is read" << endl;
+ for ( double v = -1.5; v < 1.6; v += 1.5 ) {
+ canvas.v = v;
+ canvas.output_file();
+ }
+ cout << pngFile << " was exported" << endl;
+ break;
+ }
+
+ default: {
+ cout << "WTF" << endl;
+ break;
+ }
+ }*/
+
+
+ return 0;
+}
+
diff --git a/myMath.hpp b/myMath.hpp
new file mode 100644
index 0000000..db88044
--- /dev/null
+++ b/myMath.hpp
@@ -0,0 +1,12 @@
+#ifndef MYMATH_HPP
+#define MYMATH_HPP
+
+#include
+using namespace std;
+
+bool even(double x) {
+ return (((int)floor(x)) % 2 == 0);
+}
+
+#endif // MYMATH_HPP
+
diff --git a/pngwriter/.DS_Store b/pngwriter/.DS_Store
new file mode 100644
index 0000000..f483b62
Binary files /dev/null and b/pngwriter/.DS_Store differ
diff --git a/pngwriter/._.DS_Store b/pngwriter/._.DS_Store
new file mode 100644
index 0000000..460d887
Binary files /dev/null and b/pngwriter/._.DS_Store differ
diff --git a/pngwriter/._Makefile b/pngwriter/._Makefile
new file mode 100644
index 0000000..033041d
Binary files /dev/null and b/pngwriter/._Makefile differ
diff --git a/pngwriter/._pngwriter.cc b/pngwriter/._pngwriter.cc
new file mode 100644
index 0000000..0d44057
Binary files /dev/null and b/pngwriter/._pngwriter.cc differ
diff --git a/pngwriter/._pngwriter.h b/pngwriter/._pngwriter.h
new file mode 100644
index 0000000..6f1f292
Binary files /dev/null and b/pngwriter/._pngwriter.h differ
diff --git a/pngwriter/Makefile b/pngwriter/Makefile
new file mode 100644
index 0000000..698646e
--- /dev/null
+++ b/pngwriter/Makefile
@@ -0,0 +1,32 @@
+############ PARTIAL MAKEFILE FOR PNGWRITER ######################################
+#
+# Website: Main: http://pngwriter.sourceforge.net/
+# Author: Paul Blackburn
+# Email: individual61@users.sourceforge.net
+# Version: 0.5.4 (19 / II / 2009)
+# License: GNU General Public License
+# Copyright 2002, 2003, 2004, 2005, 2006, 2007,
+# 2008, 2009 Paul Blackburn
+#
+##################################################################################
+
+
+include ../make.include
+
+OBJECTS=pngwriter.o
+all: libpngwriter.a
+
+libpngwriter.a: $(OBJECTS)
+ ar rv $@ $^
+ ranlib $@
+
+pngwriter.o: pngwriter.cc pngwriter.h
+ $(CXX) $(CXXFLAGS) $(INC) -g -c -o pngwriter.o pngwriter.cc
+
+clean :
+ rm -f $(OBJECTS) libpngwriter.a pngtest.cc~ pngwriter.cc~
+ rm -f pngwriter.h~ Makefile~
+ rm -f .DS_Store
+
+
+
diff --git a/pngwriter/pngwriter.cc b/pngwriter/pngwriter.cc
new file mode 100644
index 0000000..bf5e269
--- /dev/null
+++ b/pngwriter/pngwriter.cc
@@ -0,0 +1,4721 @@
+//********** pngwriter.cc **********************************************
+// Author: Paul Blackburn
+//
+// Email: individual61@users.sourceforge.net
+//
+// Version: 0.5.4 (19 / II / 2009)
+//
+// Description: Library that allows plotting a 48 bit
+// PNG image pixel by pixel, which can
+// then be opened with a graphics program.
+//
+// License: GNU General Public License
+// Copyright 2002, 2003, 2004, 2005, 2006, 2007,
+// 2008, 2009 Paul Blackburn
+//
+// Website: Main: http://pngwriter.sourceforge.net/
+// Sourceforge.net: http://sourceforge.net/projects/pngwriter/
+// Freshmeat.net: http://freshmeat.net/projects/pngwriter/
+//
+// Documentation: The header file (pngwriter.h) is commented, but for a
+// quick reference document, and support,
+// take a look at the website.
+//
+//*************************************************************************
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * */
+
+#include "pngwriter.h"
+
+// Default Constructor
+////////////////////////////////////////////////////////////////////////////
+pngwriter::pngwriter()
+{
+
+ filename_ = new char[255];
+ textauthor_ = new char[255];
+ textdescription_ = new char[255];
+ texttitle_ = new char[255];
+ textsoftware_ = new char[255];
+
+ strcpy(filename_, "out.png");
+ width_ = 250;
+ height_ = 250;
+ backgroundcolour_ = 65535;
+ compressionlevel_ = -2;
+ filegamma_ = 0.5;
+ transformation_ = 0;
+
+ strcpy(textauthor_, "PNGwriter Author: Paul Blackburn");
+ strcpy(textdescription_, "http://pngwriter.sourceforge.net/");
+ strcpy(textsoftware_, "PNGwriter: An easy to use graphics library.");
+ strcpy(texttitle_, "out.png");
+
+ int kkkk;
+
+ bit_depth_ = 16; //Default bit depth for new images
+ colortype_=2;
+ screengamma_ = 2.2;
+
+ graph_ = (png_bytepp)malloc(height_ * sizeof(png_bytep));
+ if(graph_ == NULL)
+ {
+ std::cerr << " PNGwriter::pngwriter - ERROR **: Not able to allocate memory for image." << std::endl;
+ }
+
+ for (kkkk = 0; kkkk < height_; kkkk++)
+ {
+ graph_[kkkk] = (png_bytep)malloc(6*width_ * sizeof(png_byte));
+ if(graph_[kkkk] == NULL)
+ {
+ std::cerr << " PNGwriter::pngwriter - ERROR **: Not able to allocate memory for image." << std::endl;
+ }
+ }
+
+ if(graph_ == NULL)
+ {
+ std::cerr << " PNGwriter::pngwriter - ERROR **: Not able to allocate memory for image." << std::endl;
+ }
+
+ int tempindex;
+ for(int hhh = 0; hhh65535)
+ {
+ std::cerr << " PNGwriter::pngwriter - WARNING **: Constructor called with background colour greater than 65535. Setting to 65535."<65535)
+ {
+ std::cerr << " PNGwriter::pngwriter - WARNING **: Constructor called with background colour greater than 1.0. Setting to 1.0."<65535)
+ {
+ std::cerr << " PNGwriter::pngwriter - WARNING **: Constructor called with background colour greater than 65535. Setting to 65535."<65535)
+ {
+ std::cerr << " PNGwriter::pngwriter - WARNING **: Constructor called with background colour greater than 65535. Setting to 65535."< 65535)
+ {
+ red = 65535;
+ }
+ if(green > 65535)
+ {
+ green = 65535;
+ }
+ if(blue > 65535)
+ {
+ blue = 65535;
+ }
+
+ if(red < 0)
+ {
+ red = 0;
+ }
+ if(green < 0)
+ {
+ green = 0;
+ }
+ if(blue < 0)
+ {
+ blue = 0;
+ }
+
+ if((bit_depth_ == 16))
+ {
+ // if( (height_-y >-1) && (height_-y -1) && (6*(x-1)+5<6*width_) )
+ if( (y<=height_) && (y>0) && (x>0) && (x<=width_) )
+ {
+ //graph_[height_-y][6*(x-1) + i] where i goes from 0 to 5
+ tempindex= 6*x-6;
+ graph_[height_-y][tempindex] = (char) floor(((double)red)/256);
+ graph_[height_-y][tempindex+1] = (char)(red%256);
+ graph_[height_-y][tempindex+2] = (char) floor(((double)green)/256);
+ graph_[height_-y][tempindex+3] = (char)(green%256);
+ graph_[height_-y][tempindex+4] = (char) floor(((double)blue)/256);
+ graph_[height_-y][tempindex+5] = (char)(blue%256);
+ };
+
+ /*
+ if(!( (height_-y >-1) && (height_-y -1) && (6*(x-1)+5<6*width_) ))
+ {
+ std::cerr << " PNGwriter::plot-- Plotting out of range! " << y << " " << x << std::endl;
+ }
+ */
+ }
+
+ if((bit_depth_ == 8))
+ {
+ // if( (height_-y >-1) && (height_-y -1) && (3*(x-1)+5<3*width_) )
+ if( (y0) && (x>0) && (x-1) && (height_-y -1) && (6*(x-1)+5<6*width_) ))
+ {
+ std::cerr << " PNGwriter::plot-- Plotting out of range! " << y << " " << x << std::endl;
+ }
+ */
+ }
+};
+
+void pngwriter::plot(int x, int y, double red, double green, double blue)
+{
+ this->plot(x,y,int(red*65535),int(green*65535),int(blue*65535));
+};
+
+///////////////////////////////////////////////////////////////
+int pngwriter::read(int x, int y, int colour)
+{
+ int temp1,temp2;
+
+ if((colour !=1)&&(colour !=2)&&(colour !=3))
+ {
+ std::cerr << " PNGwriter::read - WARNING **: Invalid argument: should be 1, 2 or 3, is " << colour << std::endl;
+ return 0;
+ }
+
+ if( ( x>0 ) && ( x <= (this->width_) ) && ( y>0 ) && ( y <= (this->height_) ) )
+ {
+
+ if(bit_depth_ == 16)
+ {
+ temp2=6*(x-1);
+ if(colour == 1)
+ {
+ temp1 = (graph_[(height_-y)][temp2])*256 + graph_[height_-y][temp2+1];
+ return temp1;
+ }
+
+ if(colour == 2)
+ {
+ temp1 = (graph_[height_-y][temp2+2])*256 + graph_[height_-y][temp2+3];
+ return temp1;
+ }
+
+ if(colour == 3)
+ {
+ temp1 = (graph_[height_-y][temp2+4])*256 + graph_[height_-y][temp2+5];
+ return temp1;
+ }
+ }
+
+ if(bit_depth_ == 8)
+ {
+ temp2=3*(x-1);
+ if(colour == 1)
+ {
+ temp1 = graph_[height_-y][temp2];
+ return temp1*256;
+ }
+
+ if(colour == 2)
+ {
+ temp1 = graph_[height_-y][temp2+1];
+ return temp1*256;
+ }
+
+ if(colour == 3)
+ {
+ temp1 = graph_[height_-y][temp2+2];
+ return temp1*256;
+ }
+ }
+ }
+ else
+ {
+ return 0;
+ }
+
+ std::cerr << " PNGwriter::read - WARNING **: Returning 0 because of bitdepth/colour type mismatch."<< std::endl;
+ return 0;
+}
+
+///////////////////////////////////////////////////////////////
+int pngwriter::read(int xxx, int yyy)
+{
+ int temp1,temp2,temp3,temp4,temp5;
+
+ if(
+ ( xxx>0 ) &&
+ ( xxx <= (this->width_) ) &&
+ ( yyy>0 ) &&
+ ( yyy <= (this->height_) )
+ )
+ {
+ if(bit_depth_ == 16)
+ {
+ // temp1 = (graph_[(height_-yyy)][6*(xxx-1)])*256 + graph_[height_-yyy][6*(xxx-1)+1];
+ temp5=6*xxx;
+ temp1 = (graph_[(height_-yyy)][temp5-6])*256 + graph_[height_-yyy][temp5-5];
+ temp2 = (graph_[height_-yyy][temp5-4])*256 + graph_[height_-yyy][temp5-3];
+ temp3 = (graph_[height_-yyy][temp5-2])*256 + graph_[height_-yyy][temp5-1];
+ temp4 = int((temp1+temp2+temp3)/3.0);
+ }
+ else if(bit_depth_ == 8)
+ {
+ // temp1 = graph_[height_-yyy][3*(xxx-1)];
+ temp5 = 3*xxx;
+ temp1 = graph_[height_-yyy][temp5-3];
+ temp2 = graph_[height_-yyy][temp5-2];
+ temp3 = graph_[height_-yyy][temp5-1];
+ temp4 = int((temp1+temp2+temp3)/3.0);
+ }
+ else
+ {
+ std::cerr << " PNGwriter::read - WARNING **: Invalid bit depth! Returning 0 as average value." << std::endl;
+ temp4 = 0;
+ }
+
+ return temp4;
+
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+/////////////////////////////////////////////////////
+double pngwriter::dread(int x, int y, int colour)
+{
+ return double(this->read(x,y,colour))/65535.0;
+}
+
+double pngwriter::dread(int x, int y)
+{
+ return double(this->read(x,y))/65535.0;
+}
+
+///////////////////////////////////////////////////////
+void pngwriter::clear()
+{
+ int pen = 0;
+ int pencil = 0;
+ int tempindex;
+
+ if(bit_depth_==16)
+ {
+ for(pen = 0; pen 999999999)||(index < 0))
+ {
+ std::cerr << " PNGwriter::pngwriter_rename - ERROR **: Numerical name is out of 0 - 999 999 999 range (" << index <<")." << std::endl;
+ return;
+ }
+
+ if( 0> sprintf(buffer, "%9.9lu.png",index))
+ {
+ std::cerr << " PNGwriter::pngwriter_rename - ERROR **: Error creating numerical filename." << std::endl;
+ return;
+ }
+
+ delete [] filename_;
+ delete [] texttitle_;
+
+ filename_ = new char[strlen(buffer)+1];
+ texttitle_ = new char[strlen(buffer)+1];
+
+ strcpy(filename_,buffer);
+ strcpy(texttitle_,buffer);
+
+};
+
+///////////////////////////////////////////////////////
+void pngwriter::settext(char * title, char * author, char * description, char * software)
+{
+ delete [] textauthor_;
+ delete [] textdescription_;
+ delete [] texttitle_;
+ delete [] textsoftware_;
+
+ textauthor_ = new char[strlen(author)+1];
+ textdescription_ = new char[strlen(description)+1];
+ textsoftware_ = new char[strlen(software)+1];
+ texttitle_ = new char[strlen(title)+1];
+
+ strcpy(texttitle_, title);
+ strcpy(textauthor_, author);
+ strcpy(textdescription_, description);
+ strcpy(textsoftware_, software);
+};
+
+///////////////////////////////////////////////////////
+void pngwriter::settext(const char * title, const char * author, const char * description, const char * software)
+{
+ delete [] textauthor_;
+ delete [] textdescription_;
+ delete [] texttitle_;
+ delete [] textsoftware_;
+
+ textauthor_ = new char[strlen(author)+1];
+ textdescription_ = new char[strlen(description)+1];
+ textsoftware_ = new char[strlen(software)+1];
+ texttitle_ = new char[strlen(title)+1];
+
+ strcpy(texttitle_, title);
+ strcpy(textauthor_, author);
+ strcpy(textdescription_, description);
+ strcpy(textsoftware_, software);
+};
+
+///////////////////////////////////////////////////////
+void pngwriter::close()
+{
+ FILE *fp;
+ png_structp png_ptr;
+ png_infop info_ptr;
+
+ fp = fopen(filename_, "wb");
+ if( fp == NULL)
+ {
+ std::cerr << " PNGwriter::close - ERROR **: Error creating file (fopen() returned NULL pointer)." << std::endl;
+ perror(" PNGwriter::close - ERROR **");
+ return;
+ }
+
+ png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+ info_ptr = png_create_info_struct(png_ptr);
+ png_init_io(png_ptr, fp);
+ if(compressionlevel_ != -2)
+ {
+ png_set_compression_level(png_ptr, compressionlevel_);
+ }
+ else
+ {
+ png_set_compression_level(png_ptr, PNGWRITER_DEFAULT_COMPRESSION);
+ }
+
+ png_set_IHDR(png_ptr, info_ptr, width_, height_,
+ bit_depth_, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
+ PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
+
+ if(filegamma_ < 1.0e-1)
+ {
+ filegamma_ = 0.5; // Modified in 0.5.4 so as to be the same as the usual gamma.
+ }
+
+ png_set_gAMA(png_ptr, info_ptr, filegamma_);
+
+ time_t gmt;
+ png_time mod_time;
+ png_text text_ptr[5];
+ time(&gmt);
+ png_convert_from_time_t(&mod_time, gmt);
+ png_set_tIME(png_ptr, info_ptr, &mod_time);
+ text_ptr[0].key = "Title";
+ text_ptr[0].text = texttitle_;
+ text_ptr[0].compression = PNG_TEXT_COMPRESSION_NONE;
+ text_ptr[1].key = "Author";
+ text_ptr[1].text = textauthor_;
+ text_ptr[1].compression = PNG_TEXT_COMPRESSION_NONE;
+ text_ptr[2].key = "Description";
+ text_ptr[2].text = textdescription_;
+ text_ptr[2].compression = PNG_TEXT_COMPRESSION_NONE;
+ text_ptr[3].key = "Creation Time";
+ text_ptr[3].text = png_convert_to_rfc1123(png_ptr, &mod_time);
+ text_ptr[3].compression = PNG_TEXT_COMPRESSION_NONE;
+ text_ptr[4].key = "Software";
+ text_ptr[4].text = textsoftware_;
+ text_ptr[4].compression = PNG_TEXT_COMPRESSION_NONE;
+ png_set_text(png_ptr, info_ptr, text_ptr, 5);
+
+ png_write_info(png_ptr, info_ptr);
+ png_write_image(png_ptr, graph_);
+ png_write_end(png_ptr, info_ptr);
+ png_destroy_write_struct(&png_ptr, &info_ptr);
+ fclose(fp);
+}
+
+//////////////////////////////////////////////////////
+void pngwriter::line(int xfrom, int yfrom, int xto, int yto, int red, int green,int blue)
+{
+ // Bresenham Algorithm.
+ //
+ int dy = yto - yfrom;
+ int dx = xto - xfrom;
+ int stepx, stepy;
+
+ if (dy < 0)
+ {
+ dy = -dy; stepy = -1;
+ }
+ else
+ {
+ stepy = 1;
+ }
+
+ if (dx < 0)
+ {
+ dx = -dx; stepx = -1;
+ }
+ else
+ {
+ stepx = 1;
+ }
+ dy <<= 1; // dy is now 2*dy
+ dx <<= 1; // dx is now 2*dx
+
+ this->plot(xfrom,yfrom,red,green,blue);
+
+ if (dx > dy)
+ {
+ int fraction = dy - (dx >> 1);
+
+ while (xfrom != xto)
+ {
+ if (fraction >= 0)
+ {
+ yfrom += stepy;
+ fraction -= dx;
+ }
+ xfrom += stepx;
+ fraction += dy;
+ this->plot(xfrom,yfrom,red,green,blue);
+ }
+ }
+ else
+ {
+ int fraction = dx - (dy >> 1);
+ while (yfrom != yto)
+ {
+ if (fraction >= 0)
+ {
+ xfrom += stepx;
+ fraction -= dy;
+ }
+ yfrom += stepy;
+ fraction += dx;
+ this->plot(xfrom,yfrom,red,green,blue);
+ }
+ }
+
+}
+
+void pngwriter::line(int xfrom, int yfrom, int xto, int yto, double red, double green,double blue)
+{
+ this->line( xfrom,
+ yfrom,
+ xto,
+ yto,
+ int (red*65535),
+ int (green*65535),
+ int (blue*65535)
+ );
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////
+void pngwriter::square(int xfrom, int yfrom, int xto, int yto, int red, int green, int blue)
+{
+ this->line(xfrom, yfrom, xfrom, yto, red, green, blue);
+ this->line(xto, yfrom, xto, yto, red, green, blue);
+ this->line(xfrom, yfrom, xto, yfrom, red, green, blue);
+ this->line(xfrom, yto, xto, yto, red, green, blue);
+}
+
+void pngwriter::square(int xfrom, int yfrom, int xto, int yto, double red, double green, double blue)
+{
+ this->square( xfrom, yfrom, xto, yto, int(red*65535), int(green*65535), int(blue*65535));
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////////
+void pngwriter::filledsquare(int xfrom, int yfrom, int xto, int yto, int red, int green, int blue)
+{
+ for(int caca = xfrom; caca line(caca, yfrom, caca, yto, red, green, blue);
+ }
+}
+
+void pngwriter::filledsquare(int xfrom, int yfrom, int xto, int yto, double red, double green, double blue)
+{
+ this->filledsquare( xfrom, yfrom, xto, yto, int(red*65535), int(green*65535), int(blue*65535));
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////////
+void pngwriter::circle(int xcentre, int ycentre, int radius, int red, int green, int blue)
+{
+ int x = 0;
+ int y = radius;
+ int p = (5 - radius*4)/4;
+
+ circle_aux(xcentre, ycentre, x, y, red, green, blue);
+ while (x < y)
+ {
+ x++;
+ if (p < 0)
+ {
+ p += 2*x+1;
+ }
+ else
+ {
+ y--;
+ p += 2*(x-y)+1;
+ }
+ circle_aux(xcentre, ycentre, x, y, red, green, blue);
+ }
+}
+
+void pngwriter::circle(int xcentre, int ycentre, int radius, double red, double green, double blue)
+{
+ this->circle(xcentre,ycentre,radius, int(red*65535), int(green*65535), int(blue*65535));
+}
+
+////////////////////////////////////////////////////////////
+
+void pngwriter::circle_aux(int xcentre, int ycentre, int x, int y, int red, int green, int blue)
+{
+ if (x == 0)
+ {
+ this->plot( xcentre, ycentre + y, red, green, blue);
+ this->plot( xcentre, ycentre - y, red, green, blue);
+ this->plot( xcentre + y, ycentre, red, green, blue);
+ this->plot( xcentre - y, ycentre, red, green, blue);
+ }
+ else
+ if (x == y)
+ {
+ this->plot( xcentre + x, ycentre + y, red, green, blue);
+ this->plot( xcentre - x, ycentre + y, red, green, blue);
+ this->plot( xcentre + x, ycentre - y, red, green, blue);
+ this->plot( xcentre - x, ycentre - y, red, green, blue);
+ }
+ else
+ if (x < y)
+ {
+ this->plot( xcentre + x, ycentre + y, red, green, blue);
+ this->plot( xcentre - x, ycentre + y, red, green, blue);
+ this->plot( xcentre + x, ycentre - y, red, green, blue);
+ this->plot( xcentre - x, ycentre - y, red, green, blue);
+ this->plot( xcentre + y, ycentre + x, red, green, blue);
+ this->plot( xcentre - y, ycentre + x, red, green, blue);
+ this->plot( xcentre + y, ycentre - x, red, green, blue);
+ this->plot( xcentre - y, ycentre - x, red, green, blue);
+ }
+
+}
+
+////////////////////////////////////////////////////////////
+void pngwriter::filledcircle(int xcentre, int ycentre, int radius, int red, int green, int blue)
+{
+ for(int jjj = ycentre-radius; jjj< ycentre+radius+1; jjj++)
+ {
+ this->line(xcentre - int(sqrt((double)(radius*radius) - (-ycentre + jjj)*(-ycentre + jjj ))), jjj,
+ xcentre + int(sqrt((double)(radius*radius) - (-ycentre + jjj)*(-ycentre + jjj ))),jjj,red,green,blue);
+ }
+}
+
+void pngwriter::filledcircle(int xcentre, int ycentre, int radius, double red, double green, double blue)
+{
+ this->filledcircle( xcentre, ycentre, radius, int(red*65535), int(green*65535), int(blue*65535));
+}
+
+////////////////Reading routines/////////////////////
+/////////////////////////////////////////////////
+
+// Modified with Mikkel's patch
+void pngwriter::readfromfile(char * name)
+{
+ FILE *fp;
+ png_structp png_ptr;
+ png_infop info_ptr;
+ unsigned char **image;
+ unsigned long width, height;
+ int bit_depth, color_type, interlace_type;
+ // png_uint_32 i;
+ //
+ fp = fopen (name,"rb");
+ if (fp==NULL)
+ {
+ std::cerr << " PNGwriter::readfromfile - ERROR **: Error opening file \"" << std::flush;
+ std::cerr << name <readfromfile((char *)(name));
+}
+
+/////////////////////////////////////////////////////////
+int pngwriter::check_if_png(char *file_name, FILE **fp)
+{
+ char sig[PNG_BYTES_TO_CHECK];
+
+ if ( /*(*fp = fopen(file_name, "rb")) */ *fp == NULL) // Fixed 10 10 04
+ {
+ // exit(EXIT_FAILURE);
+ std::cerr << " PNGwriter::check_if_png - ERROR **: Could not open file " << file_name << " to read." << std::endl;
+ perror(" PNGwriter::check_if_png - ERROR **");
+ return 0;
+ }
+
+ if (fread(sig, 1, PNG_BYTES_TO_CHECK, *fp) != PNG_BYTES_TO_CHECK)
+ {
+ //exit(EXIT_FAILURE);
+ std::cerr << " PNGwriter::check_if_png - ERROR **: File " << file_name << " does not appear to be a valid PNG file." << std::endl;
+ perror(" PNGwriter::check_if_png - ERROR **");
+ fclose(*fp);
+ return 0;
+ }
+
+ if (png_sig_cmp( (png_bytep) sig, (png_size_t)0, PNG_BYTES_TO_CHECK) /*png_check_sig((png_bytep) sig, PNG_BYTES_TO_CHECK)*/ )
+ {
+ std::cerr << " PNGwriter::check_if_png - ERROR **: File " << file_name << " does not appear to be a valid PNG file. png_check_sig() failed." << std::endl;
+ fclose(*fp);
+ return 0;
+ }
+
+
+
+ return 1; //Success
+}
+
+///////////////////////////////////////////////////////
+int pngwriter::read_png_info(FILE *fp, png_structp *png_ptr, png_infop *info_ptr)
+{
+ *png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+ if (*png_ptr == NULL)
+ {
+ std::cerr << " PNGwriter::read_png_info - ERROR **: Could not create read_struct." << std::endl;
+ fclose(fp);
+ return 0;
+ //exit(EXIT_FAILURE);
+ }
+ *info_ptr = png_create_info_struct(*png_ptr);
+ if (*info_ptr == NULL)
+ {
+ png_destroy_read_struct(png_ptr, (png_infopp)NULL, (png_infopp)NULL);
+ std::cerr << " PNGwriter::read_png_info - ERROR **: Could not create info_struct." << std::endl;
+ //exit(EXIT_FAILURE);
+ fclose(fp);
+ return 0;
+ }
+ if (setjmp((*png_ptr)->jmpbuf)) /*(setjmp(png_jmpbuf(*png_ptr)) )*//////////////////////////////////////
+ {
+ png_destroy_read_struct(png_ptr, info_ptr, (png_infopp)NULL);
+ std::cerr << " PNGwriter::read_png_info - ERROR **: This file may be a corrupted PNG file. (setjmp(*png_ptr)->jmpbf) failed)." << std::endl;
+ fclose(fp);
+ return 0;
+ //exit(EXIT_FAILURE);
+ }
+ png_init_io(*png_ptr, fp);
+ png_set_sig_bytes(*png_ptr, PNG_BYTES_TO_CHECK);
+ png_read_info(*png_ptr, *info_ptr);
+
+ return 1;
+}
+
+////////////////////////////////////////////////////////////
+int pngwriter::read_png_image(FILE *fp, png_structp png_ptr, png_infop info_ptr,
+ png_bytepp *image, png_uint_32 *width, png_uint_32 *height)
+{
+ unsigned int i,j;
+
+ *width = png_get_image_width(png_ptr, info_ptr);
+ *height = png_get_image_height(png_ptr, info_ptr);
+
+ if( width == NULL)
+ {
+ std::cerr << " PNGwriter::read_png_image - ERROR **: png_get_image_width() returned NULL pointer." << std::endl;
+ fclose(fp);
+ return 0;
+ }
+
+ if( height == NULL)
+ {
+ std::cerr << " PNGwriter::read_png_image - ERROR **: png_get_image_height() returned NULL pointer." << std::endl;
+ fclose(fp);
+ return 0;
+ }
+
+ if ((*image = (png_bytepp)malloc(*height * sizeof(png_bytep))) == NULL)
+ {
+ std::cerr << " PNGwriter::read_png_image - ERROR **: Could not allocate memory for reading image." << std::endl;
+ fclose(fp);
+ return 0;
+ //exit(EXIT_FAILURE);
+ }
+ for (i = 0; i < *height; i++)
+ {
+ (*image)[i] = (png_bytep)malloc(png_get_rowbytes(png_ptr, info_ptr));
+ if ((*image)[i] == NULL)
+ {
+ for (j = 0; j < i; j++) free((*image)[j]);
+ free(*image);
+ fclose(fp);
+ std::cerr << " PNGwriter::read_png_image - ERROR **: Could not allocate memory for reading image." << std::endl;
+ return 0;
+ //exit(EXIT_FAILURE);
+ }
+ }
+ png_read_image(png_ptr, *image);
+
+ return 1;
+}
+
+///////////////////////////////////
+int pngwriter::getheight(void)
+{
+ return height_;
+}
+
+int pngwriter::getwidth(void)
+{
+ return width_;
+}
+
+
+int pngwriter::getbitdepth(void)
+{
+ return bit_depth_;
+}
+
+int pngwriter::getcolortype(void)
+{
+ return colortype_;
+}
+
+double pngwriter::getgamma(void)
+{
+ return filegamma_;
+}
+
+void pngwriter::setgamma(double gamma)
+{
+ filegamma_ = gamma;
+}
+
+// The algorithms HSVtoRGB and RGBtoHSV were found at http://www.cs.rit.edu/~ncs/
+// which is a page that belongs to Nan C. Schaller, though
+// these algorithms appear to be the work of Eugene Vishnevsky.
+//////////////////////////////////////////////
+void pngwriter::HSVtoRGB( double *r, double *g, double *b, double h, double s, double v )
+{
+ // r,g,b values are from 0 to 1
+ // h = [0,1], s = [0,1], v = [0,1]
+ // if s == 0, then h = -1 (undefined)
+ //
+ h = h*360.0;
+
+ int i;
+ double f, p, q, t;
+ if( s == 0 )
+ {
+ // achromatic (grey)
+ *r = *g = *b = v;
+ return;
+ }
+
+ h /= 60; // sector 0 to 5
+ i = int(floor( h ));
+ f = h - i; // factorial part of h
+ p = v * ( 1 - s );
+ q = v * ( 1 - s * f );
+ t = v * ( 1 - s * ( 1 - f ) );
+
+ switch( i )
+ {
+ case 0:
+ *r = v;
+ *g = t;
+ *b = p;
+ break;
+ case 1:
+ *r = q;
+ *g = v;
+ *b = p;
+ break;
+ case 2:
+ *r = p;
+ *g = v;
+ *b = t;
+ break;
+ case 3:
+ *r = p;
+ *g = q;
+ *b = v;
+ break;
+ case 4:
+ *r = t;
+ *g = p;
+ *b = v;
+ break;
+ default: // case 5:
+ *r = v;
+ *g = p;
+ *b = q;
+ break;
+ }
+}
+
+void pngwriter::RGBtoHSV( float r, float g, float b, float *h, float *s, float *v )
+{
+
+ float min=0.0; //These values are not used.
+ float max=1.0;
+ float delta;
+
+ if( (r>=g)&&(r>=b) )
+ {
+ max = r;
+ }
+ if( (g>=r)&&(g>=b) )
+ {
+ max = g;
+ }
+ if( (b>=g)&&(b>=r) )
+ {
+ max = b;
+ }
+
+ if( (r<=g)&&(r<=b) )
+ {
+ min = r;
+ }
+ if( (g<=r)&&(g<=b) )
+ {
+ min = g;
+ }
+ if( (b<=g)&&(b<=r) )
+ {
+ min = b;
+ }
+
+ *v = max; // v
+
+ delta = max - min;
+
+ if( max != 0 )
+ *s = delta / max; // s
+ else
+ {
+
+ r = g = b = 0; // s = 0, v is undefined
+ *s = 0;
+ *h = -1;
+ return;
+ }
+
+ if( r == max )
+ *h = ( g - b ) / delta; // between yellow & magenta
+ else if( g == max )
+ *h = 2 + ( b - r ) / delta; // between cyan & yellow
+ else
+ *h = 4 + ( r - g ) / delta; // between magenta & cyan
+
+ *h *= 60; // degrees
+ if( *h < 0 )
+ *h += 360;
+
+}
+
+//
+//////////////////////////////////////////////////////////////////////////////////
+void pngwriter::plotHSV(int x, int y, double hue, double saturation, double value)
+{
+ double red,green,blue;
+ double *redp;
+ double *greenp;
+ double *bluep;
+
+ redp = &red;
+ greenp = &green;
+ bluep = &blue;
+
+ HSVtoRGB(redp,greenp,bluep,hue,saturation,value);
+ plot(x,y,red,green,blue);
+}
+
+void pngwriter::plotHSV(int x, int y, int hue, int saturation, int value)
+{
+ plotHSV(x, y, double(hue)/65535.0, double(saturation)/65535.0, double(value)/65535.0);
+}
+
+//
+//////////////////////////////////////////////////////////////////////////////////
+double pngwriter::dreadHSV(int x, int y, int colour)
+{
+ if( (x>0)&&(x<=width_)&&(y>0)&&(y<=height_) )
+ {
+
+ float * huep;
+ float * saturationp;
+ float * valuep;
+ float red,green,blue;
+ float hue, saturation, value;
+
+ red = float(dread(x,y,1));
+ green = float(dread(x,y,2));
+ blue = float(dread(x,y,3));
+
+ huep = &hue;
+ saturationp = &saturation;
+ valuep = &value;
+
+ RGBtoHSV( red, green, blue, huep, saturationp, valuep );
+
+ if(colour == 1)
+ {
+ return double(hue)/360.0;
+ }
+
+ else if(colour == 2)
+ {
+ return saturation;
+ }
+
+ else if(colour == 3)
+ {
+ return value;
+ }
+
+ std::cerr << " PNGwriter::dreadHSV - ERROR **: Called with wrong colour argument: should be 1, 2 or 3; was: " << colour << "." << std::endl;
+ }
+ return 0.0;
+}
+
+//
+//////////////////////////////////////////////////////////////////////////////////
+int pngwriter::readHSV(int x, int y, int colour)
+{
+ if( (x>0)&&(x<=width_)&&(y>0)&&(y<=height_) )
+ {
+
+ float * huep;
+ float * saturationp;
+ float * valuep;
+ float red,green,blue;
+ float hue, saturation, value;
+
+ red = float(dread(x,y,1));
+ green = float(dread(x,y,2));
+ blue = float(dread(x,y,3));
+
+ huep = &hue;
+ saturationp = &saturation;
+ valuep = &value;
+
+ RGBtoHSV( red, green, blue, huep, saturationp, valuep );
+
+ if(colour == 1)
+ {
+ return int(65535*(double(hue)/360.0));
+ }
+
+ else if(colour == 2)
+ {
+ return int(65535*saturation);
+ }
+
+ else if(colour == 3)
+ {
+ return int(65535*value);
+ }
+
+ std::cerr << " PNGwriter::readHSV - ERROR **: Called with wrong colour argument: should be 1, 2 or 3; was: " << colour << "." << std::endl;
+ return 0;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+void pngwriter::setcompressionlevel(int level)
+{
+ if( (level < -1)||(level > 9) )
+ {
+ std::cerr << " PNGwriter::setcompressionlevel - ERROR **: Called with wrong compression level: should be -1 to 9, was: " << level << "." << std::endl;
+ }
+ compressionlevel_ = level;
+}
+
+// An implementation of a Bezier curve.
+void pngwriter::bezier( int startPtX, int startPtY,
+ int startControlX, int startControlY,
+ int endPtX, int endPtY,
+ int endControlX, int endControlY,
+ double red, double green, double blue)
+{
+
+ double cx = 3.0*(startControlX - startPtX);
+ double bx = 3.0*(endControlX - startControlX) - cx;
+ double ax = double(endPtX - startPtX - cx - bx);
+
+ double cy = 3.0*(startControlY - startPtY);
+ double by = 3.0*(endControlY - startControlY) - cy;
+ double ay = double(endPtY - startPtY - cy - by);
+
+ double x,y,newx,newy;
+ x = startPtX;
+ y = startPtY;
+
+ for(double t = 0.0; t<=1.005; t += 0.005)
+ {
+ newx = startPtX + t*(double(cx) + t*(double(bx) + t*(double(ax))));
+ newy = startPtY + t*(double(cy) + t*(double(by) + t*(double(ay))));
+ this->line(int(x),int(y),int(newx),int(newy),red,green,blue);
+ x = newx;
+ y = newy;
+ }
+}
+
+//int version of bezier
+void pngwriter::bezier( int startPtX, int startPtY,
+ int startControlX, int startControlY,
+ int endPtX, int endPtY,
+ int endControlX, int endControlY,
+ int red, int green, int blue)
+{
+ this->bezier( startPtX, startPtY,
+ startControlX, startControlY,
+ endPtX, endPtY,
+ endControlX, endControlY,
+ double(red)/65535.0, double(green)/65535.0, double(blue)/65535.0);
+}
+
+/*
+int pngwriter::getcompressionlevel(void)
+{
+ return png_get_compression_level(png_ptr);
+}
+*/
+
+double pngwriter::version(void)
+{
+ const char *a = "Jeramy Webb (jeramyw@gmail.com), Mike Heller (mkheller@gmail.com)"; // For their generosity ;-)
+ char b = a[27];
+ b++;
+ return (PNGWRITER_VERSION);
+}
+
+void pngwriter::write_png(void)
+{
+ this->close();
+}
+
+#ifndef NO_FREETYPE
+
+// Freetype-based text rendering functions.
+///////////////////////////////////////////
+void pngwriter::plot_text( char * face_path, int fontsize, int x_start, int y_start, double angle, char * text, double red, double green, double blue)
+{
+ FT_Library library;
+ FT_Face face;
+ FT_Matrix matrix; // transformation matrix
+ FT_Vector pen;
+
+ FT_UInt glyph_index;
+ FT_Error error;
+
+ FT_Bool use_kerning;
+ FT_UInt previous = 0;
+
+ /* Set up transformation Matrix */
+ matrix.xx = (FT_Fixed)( cos(angle)*0x10000); /* It would make more sense to do this (below), but, bizzarely, */
+ matrix.xy = (FT_Fixed)(-sin(angle)*0x10000); /* if one does, FT_Load_Glyph fails consistently. */
+ matrix.yx = (FT_Fixed)( sin(angle)*0x10000); // matrix.yx = - matrix.xy;
+ matrix.yy = (FT_Fixed)( cos(angle)*0x10000); // matrix.yy = matrix.xx;
+
+ /* Place starting coordinates in adequate form. */
+ pen.x = x_start*64 ;
+ pen.y = (int)(y_start/64.0);
+
+ /*Count the length of the string */
+ int num_chars = strlen(text);
+
+ /* Initialize FT Library object */
+ error = FT_Init_FreeType( &library );
+ if (error) { std::cerr << " PNGwriter::plot_text - ERROR **: FreeType: Could not init Library."<< std::endl; return;}
+
+ /* Initialize FT face object */
+ error = FT_New_Face( library,face_path,0,&face );
+ if ( error == FT_Err_Unknown_File_Format ) { std::cerr << " PNGwriter::plot_text - ERROR **: FreeType: Font was opened, but type not supported."<< std::endl; return; } else if (error){ std::cerr << " PNGwriter::plot_text - ERROR **: FreeType: Could not find or load font file."<< std::endl; return; }
+
+ /* Set the Char size */
+ error = FT_Set_Char_Size( face, /* handle to face object */
+ 0, /* char_width in 1/64th of points */
+ fontsize*64, /* char_height in 1/64th of points */
+ 100, /* horizontal device resolution */
+ 100 ); /* vertical device resolution */
+
+ /* A way of accesing the glyph directly */
+ FT_GlyphSlot slot = face->glyph; // a small shortcut
+
+ /* Does the font file support kerning? */
+ use_kerning = FT_HAS_KERNING( face );
+
+ int n;
+ for ( n = 0; n < num_chars; n++ )
+ {
+ /* Convert character code to glyph index */
+ glyph_index = FT_Get_Char_Index( face, text[n] );
+
+ /* Retrieve kerning distance and move pen position */
+ if ( use_kerning && previous&& glyph_index )
+ {
+ FT_Vector delta;
+ FT_Get_Kerning( face,
+ previous,
+ glyph_index,
+ ft_kerning_default, //FT_KERNING_DEFAULT,
+ &delta );
+
+ /* Transform this kerning distance into rotated space */
+ pen.x += (int) (((double) delta.x)*cos(angle));
+ pen.y += (int) (((double) delta.x)*( sin(angle)));
+ }
+
+ /* Set transform */
+ FT_Set_Transform( face, &matrix, &pen );
+
+/*set char size*/
+
+ if (error) { std::cerr << " PNGwriter::plot_text - ERROR **: FreeType: Set char size error." << std::endl; return;};
+
+ /* Retrieve glyph index from character code */
+ glyph_index = FT_Get_Char_Index( face, text[n] );
+
+ /* Load glyph image into the slot (erase previous one) */
+ error = FT_Load_Glyph( face, glyph_index, FT_LOAD_DEFAULT );
+ if (error) { std::cerr << " PNGwriter::plot_text - ERROR **: FreeType: Could not load glyph (in loop). (FreeType error "<< std::hex << error <<")." << std::endl; return;}
+
+ /* Convert to an anti-aliased bitmap */
+ // error = FT_Render_Glyph( face->glyph, FT_RENDER_MODE_NORMAL );
+ error = FT_Render_Glyph( face->glyph, ft_render_mode_normal );
+ if (error) { std::cerr << " PNGwriter::plot_text - ERROR **: FreeType: Render glyph error." << std::endl; return;}
+
+ /* Now, draw to our target surface */
+ my_draw_bitmap( &slot->bitmap,
+ slot->bitmap_left,
+ y_start + slot->bitmap_top,
+ red,
+ green,
+ blue );
+
+ /* Advance to the next position */
+ pen.x += slot->advance.x;
+ pen.y += slot->advance.y;
+
+ /* record current glyph index */
+ previous = glyph_index;
+ }
+
+ /* Free the face and the library objects */
+ FT_Done_Face ( face );
+ FT_Done_FreeType( library );
+}
+
+void pngwriter::plot_text_utf8( char * face_path, int fontsize, int x_start, int y_start, double angle, char * text, double red, double green, double blue)
+{
+ FT_Library library;
+ FT_Face face;
+ FT_Matrix matrix; // transformation matrix
+ FT_Vector pen;
+
+ FT_UInt glyph_index;
+ FT_Error error;
+
+ FT_Bool use_kerning;
+ FT_UInt previous = 0;
+
+ /* Set up transformation Matrix */
+ matrix.xx = (FT_Fixed)( cos(angle)*0x10000); /* It would make more sense to do this (below), but, bizzarely, */
+ matrix.xy = (FT_Fixed)(-sin(angle)*0x10000); /* if one does, FT_Load_Glyph fails consistently. */
+ matrix.yx = (FT_Fixed)( sin(angle)*0x10000); // matrix.yx = - matrix.xy;
+ matrix.yy = (FT_Fixed)( cos(angle)*0x10000); // matrix.yy = matrix.xx;
+
+ /* Place starting coordinates in adequate form. */
+ pen.x = x_start*64 ;
+ pen.y = (int)(y_start/64.0);
+
+ /*Count the length of the string */
+ int num_bytes=0;
+ while(text[num_bytes]!=0)
+ {
+ num_bytes++;
+ }
+
+ /*
+ std::cout << "Num bytes is: "<< num_bytes << std::endl;
+ */
+
+ //The array of ucs4 glyph indexes, which will by at most the number of bytes in the utf-8 file.
+ long * ucs4text;
+ ucs4text = new long[num_bytes+1];
+
+ unsigned char u,v,w,x,y,z;
+
+ int num_chars=0;
+
+ long iii=0;
+
+ while(iiiglyph; // a small shortcut
+
+ /* Does the font file support kerning? */
+ use_kerning = FT_HAS_KERNING( face );
+
+ int n;
+ for ( n = 0; n < num_chars; n++ )
+ {
+ /* Convert character code to glyph index */
+ glyph_index = FT_Get_Char_Index( face, ucs4text[n] );
+
+ /* Retrieve kerning distance and move pen position */
+ if ( use_kerning && previous&& glyph_index )
+ {
+ FT_Vector delta;
+ FT_Get_Kerning( face,
+ previous,
+ glyph_index,
+ ft_kerning_default, //FT_KERNING_DEFAULT,
+ &delta );
+
+ /* Transform this kerning distance into rotated space */
+ pen.x += (int) (((double) delta.x)*cos(angle));
+ pen.y += (int) (((double) delta.x)*( sin(angle)));
+ }
+
+ /* Set transform */
+ FT_Set_Transform( face, &matrix, &pen );
+
+/*set char size*/
+
+ if (error) { std::cerr << " PNGwriter::plot_text_utf8 - ERROR **: FreeType: Set char size error." << std::endl; return;};
+
+ /* Retrieve glyph index from character code */
+ glyph_index = FT_Get_Char_Index( face, ucs4text[n] );
+
+ /* Load glyph image into the slot (erase previous one) */
+ error = FT_Load_Glyph( face, glyph_index, FT_LOAD_DEFAULT );
+ if (error) { std::cerr << " PNGwriter::plot_text_utf8 - ERROR **: FreeType: Could not load glyph (in loop). (FreeType error "<< std::hex << error <<")." << std::endl; return;}
+
+ /* Convert to an anti-aliased bitmap */
+ error = FT_Render_Glyph( face->glyph, ft_render_mode_normal );
+ if (error) { std::cerr << " PNGwriter::plot_text_utf8 - ERROR **: FreeType: Render glyph error." << std::endl; return;}
+
+ /* Now, draw to our target surface */
+ my_draw_bitmap( &slot->bitmap,
+ slot->bitmap_left,
+ y_start + slot->bitmap_top,
+ red,
+ green,
+ blue );
+
+ /* Advance to the next position */
+ pen.x += slot->advance.x;
+ pen.y += slot->advance.y;
+
+ /* record current glyph index */
+ previous = glyph_index;
+ }
+
+ /* Free the face and the library objects */
+ FT_Done_Face ( face );
+ FT_Done_FreeType( library );
+
+ delete[] ucs4text;
+}
+
+void pngwriter::plot_text( char * face_path, int fontsize, int x_start, int y_start, double angle, char * text, int red, int green, int blue)
+{
+ plot_text( face_path, fontsize, x_start, y_start, angle, text, ((double) red)/65535.0, ((double) green)/65535.0, ((double) blue)/65535.0 );
+}
+
+void pngwriter::plot_text_utf8( char * face_path, int fontsize, int x_start, int y_start, double angle, char * text, int red, int green, int blue)
+{
+ plot_text_utf8( face_path, fontsize, x_start, y_start, angle, text, ((double) red)/65535.0, ((double) green)/65535.0, ((double) blue)/65535.0 );
+}
+
+void pngwriter::my_draw_bitmap( FT_Bitmap * bitmap, int x, int y, double red, double green, double blue)
+{
+ double temp;
+ for(int j=1; jrows+1; j++)
+ {
+ for(int i=1; i< bitmap->width + 1; i++)
+ {
+ temp = (double)(bitmap->buffer[(j-1)*bitmap->width + (i-1)] )/255.0;
+
+ if(temp)
+ {
+ this->plot(x + i,
+ y - j,
+ temp*red + (1-temp)*(this->dread(x+i,y-j,1)),
+ temp*green + (1-temp)*(this->dread(x+i,y-j,2)),
+ temp*blue + (1-temp)*(this->dread(x+i,y-j,3))
+ );
+ }
+ }
+ }
+}
+
+
+
+//////////// Get text width
+
+//put in freetype section
+
+int pngwriter::get_text_width(char * face_path, int fontsize, char * text)
+{
+
+ FT_Library library;
+ FT_Face face;
+ FT_Matrix matrix; // transformation matrix
+ FT_Vector pen;
+
+ FT_UInt glyph_index;
+ FT_Error error;
+
+ FT_Bool use_kerning;
+ FT_UInt previous = 0;
+
+ /* Set up transformation Matrix */
+ matrix.xx = (FT_Fixed)( 1.0*0x10000); /* It would make more sense to do this (below), but, bizzarely, */
+ matrix.xy = (FT_Fixed)( 0.0*0x10000); /* if one does, FT_Load_Glyph fails consistently. */
+ matrix.yx = (FT_Fixed)( 0.0*0x10000); // matrix.yx = - matrix.xy;
+ matrix.yy = (FT_Fixed)( 1.0*0x10000); // matrix.yy = matrix.xx;
+
+ /* Place starting coordinates in adequate form. */
+ pen.x = 0;
+ pen.y = 0;
+
+ /*Count the length of the string */
+ int num_chars = strlen(text);
+
+ /* Initialize FT Library object */
+ error = FT_Init_FreeType( &library );
+ if (error) { std::cerr << " PNGwriter::get_text_width - ERROR **: FreeType: Could not init Library."<< std::endl; return 0;}
+
+ /* Initialize FT face object */
+ error = FT_New_Face( library,face_path,0,&face );
+ if ( error == FT_Err_Unknown_File_Format ) { std::cerr << " PNGwriter::get_text_width - ERROR **: FreeType: Font was opened, but type not supported."<< std::endl; return 0; } else if (error){ std::cerr << " PNGwriter::get_text_width - ERROR **: FreeType: Could not find or load font file." << std::endl; return 0; }
+
+ /* Set the Char size */
+ error = FT_Set_Char_Size( face, /* handle to face object */
+ 0, /* char_width in 1/64th of points */
+ fontsize*64, /* char_height in 1/64th of points */
+ 100, /* horizontal device resolution */
+ 100 ); /* vertical device resolution */
+
+ /* A way of accesing the glyph directly */
+ FT_GlyphSlot slot = face->glyph; // a small shortcut
+
+ /* Does the font file support kerning? */
+ use_kerning = FT_HAS_KERNING( face );
+
+ int n;
+ for ( n = 0; n < num_chars; n++ )
+ {
+ /* Convert character code to glyph index */
+ glyph_index = FT_Get_Char_Index( face, text[n] );
+
+ /* Retrieve kerning distance and move pen position */
+ if ( use_kerning && previous&& glyph_index )
+ {
+ FT_Vector delta;
+ FT_Get_Kerning( face,
+ previous,
+ glyph_index,
+ ft_kerning_default, //FT_KERNING_DEFAULT,
+ &delta );
+
+ /* Transform this kerning distance into rotated space */
+ pen.x += (int) ( delta.x);
+ pen.y += 0;
+ }
+
+ /* Set transform */
+ FT_Set_Transform( face, &matrix, &pen );
+
+/*set char size*/
+
+ if (error) { std::cerr << " PNGwriter::get_text_width - ERROR **: FreeType: Set char size error." << std::endl; return 0;};
+
+ /* Retrieve glyph index from character code */
+ glyph_index = FT_Get_Char_Index( face, text[n] );
+
+ /* Load glyph image into the slot (erase previous one) */
+ error = FT_Load_Glyph( face, glyph_index, FT_LOAD_DEFAULT );
+ if (error) { std::cerr << " PNGwriter::get_text_width - ERROR **: FreeType: Could not load glyph (in loop). (FreeType error "<< std::hex << error <<")." << std::endl; return 0;}
+
+ /* Convert to an anti-aliased bitmap */
+ // error = FT_Render_Glyph( face->glyph, FT_RENDER_MODE_NORMAL );
+ error = FT_Render_Glyph( face->glyph, ft_render_mode_normal );
+ if (error) { std::cerr << " PNGwriter::get_text_width - ERROR **: FreeType: Render glyph error." << std::endl; return 0;}
+
+ /* Now, draw to our target surface */
+/* my_draw_bitmap( &slot->bitmap,
+ slot->bitmap_left,
+ slot->bitmap_top,
+ red,
+ green,
+ blue );
+*/
+ /* Advance to the next position */
+ pen.x += slot->advance.x;
+// std::cout << ((double) pen.x)/64.0 << std::endl;
+ pen.y += slot->advance.y;
+
+ /* record current glyph index */
+ previous = glyph_index;
+ }
+
+
+ /* Free the face and the library objects */
+ FT_Done_Face ( face );
+ FT_Done_FreeType( library );
+
+ return (int)( ((double)pen.x)/64.0 );
+}
+
+
+int pngwriter::get_text_width_utf8(char * face_path, int fontsize, char * text)
+{
+ FT_Library library;
+ FT_Face face;
+ FT_Matrix matrix; // transformation matrix
+ FT_Vector pen;
+
+ FT_UInt glyph_index;
+ FT_Error error;
+
+ FT_Bool use_kerning;
+ FT_UInt previous = 0;
+
+ /* Set up transformation Matrix */
+ matrix.xx = (FT_Fixed)( 0x10000); /* It would make more sense to do this (below), but, bizzarely, */
+ matrix.xy = (FT_Fixed)( 0*0x10000); /* if one does, FT_Load_Glyph fails consistently. */
+ matrix.yx = (FT_Fixed)( 0*0x10000); // matrix.yx = - matrix.xy;
+ matrix.yy = (FT_Fixed)( 0x10000); // matrix.yy = matrix.xx;
+
+ /* Place starting coordinates in adequate form. */
+ pen.x = 0 ;
+ pen.y = 0;
+
+ /*Count the length of the string */
+ int num_bytes=0;
+ while(text[num_bytes]!=0)
+ {
+ num_bytes++;
+ }
+
+ /*
+ std::cout << "Num bytes is: "<< num_bytes << std::endl;
+ */
+
+ //The array of ucs4 glyph indexes, which will by at most the number of bytes in the utf-8 file.
+ long * ucs4text;
+ ucs4text = new long[num_bytes+1];
+
+ unsigned char u,v,w,x,y,z;
+
+ int num_chars=0;
+
+ long iii=0;
+
+ while(iiiglyph; // a small shortcut
+
+ /* Does the font file support kerning? */
+ use_kerning = FT_HAS_KERNING( face );
+
+ int n;
+ for ( n = 0; n < num_chars; n++ )
+ {
+ /* Convert character code to glyph index */
+ glyph_index = FT_Get_Char_Index( face, ucs4text[n] );
+
+ /* Retrieve kerning distance and move pen position */
+ if ( use_kerning && previous&& glyph_index )
+ {
+ FT_Vector delta;
+ FT_Get_Kerning( face,
+ previous,
+ glyph_index,
+ ft_kerning_default, //FT_KERNING_DEFAULT,
+ &delta );
+
+ /* Transform this kerning distance into rotated space */
+ pen.x += (int) (delta.x);
+ pen.y += 0;
+ }
+
+ /* Set transform */
+ FT_Set_Transform( face, &matrix, &pen );
+
+/*set char size*/
+
+ if (error) { std::cerr << " PNGwriter::get_text_width_utf8 - ERROR **: FreeType: Set char size error." << std::endl; return 0;};
+
+ /* Retrieve glyph index from character code */
+ glyph_index = FT_Get_Char_Index( face, ucs4text[n] );
+
+ /* Load glyph image into the slot (erase previous one) */
+ error = FT_Load_Glyph( face, glyph_index, FT_LOAD_DEFAULT );
+ if (error) { std::cerr << " PNGwriter::get_text_width_utf8 - ERROR **: FreeType: Could not load glyph (in loop). (FreeType error "<< std::hex << error <<")." << std::endl; return 0;}
+
+ /* Convert to an anti-aliased bitmap */
+ error = FT_Render_Glyph( face->glyph, ft_render_mode_normal );
+ if (error) { std::cerr << " PNGwriter::get_text_width_utf8 - ERROR **: FreeType: Render glyph error." << std::endl; return 0;}
+
+ /* Now, draw to our target surface */
+/* my_draw_bitmap( &slot->bitmap,
+ slot->bitmap_left,
+ y_start + slot->bitmap_top,
+ red,
+ green,
+ blue );
+*/
+ /* Advance to the next position */
+ pen.x += slot->advance.x;
+ pen.y += slot->advance.y;
+
+ /* record current glyph index */
+ previous = glyph_index;
+ }
+
+ /* Free the face and the library objects */
+ FT_Done_Face ( face );
+ FT_Done_FreeType( library );
+
+ delete[] ucs4text;
+
+ return (int) (((double) pen.x)/64.0);
+}
+
+///////////////
+#endif
+#ifdef NO_FREETYPE
+
+void pngwriter::plot_text( char * face_path, int fontsize, int x_start, int y_start, double angle, char * text, int red, int green, int blue)
+{
+ std::cerr << " PNGwriter::plot_text - ERROR **: PNGwriter was compiled without Freetype support! Recompile PNGwriter with Freetype support (once you have Freetype installed, that is. Websites: www.freetype.org and pngwriter.sourceforge.net)." << std::endl;
+ return;
+}
+
+void pngwriter::plot_text( char * face_path, int fontsize, int x_start, int y_start, double angle, char * text, double red, double green, double blue)
+{
+ std::cerr << " PNGwriter::plot_text - ERROR **: PNGwriter was compiled without Freetype support! Recompile PNGwriter with Freetype support (once you have Freetype installed, that is. Websites: www.freetype.org and pngwriter.sourceforge.net)." << std::endl;
+ return;
+
+}
+
+void pngwriter::plot_text_utf8( char * face_path, int fontsize, int x_start, int y_start, double angle, char * text, int red, int green, int blue)
+{
+ std::cerr << " PNGwriter::plot_text_utf8 - ERROR **: PNGwriter was compiled without Freetype support! Recompile PNGwriter with Freetype support (once you have Freetype installed, that is. Websites: www.freetype.org and pngwriter.sourceforge.net)." << std::endl;
+ return;
+}
+
+void pngwriter::plot_text_utf8( char * face_path, int fontsize, int x_start, int y_start, double angle, char * text, double red, double green, double blue)
+{
+ std::cerr << " PNGwriter::plot_text_utf8 - ERROR **: PNGwriter was compiled without Freetype support! Recompile PNGwriter with Freetype support (once you have Freetype installed, that is. Websites: www.freetype.org and pngwriter.sourceforge.net)." << std::endl;
+ return;
+}
+
+//////////// Get text width
+int pngwriter::get_text_width(char * face_path, int fontsize, char * text)
+{
+ std::cerr << " PNGwriter::get_text_width - ERROR **: PNGwriter was compiled without Freetype support! Recompile PNGwriter with Freetype support (once you have Freetype installed, that is. Websites: www.freetype.org and pngwriter.sourceforge.net)." << std::endl;
+ return 0;
+}
+
+
+int pngwriter::get_text_width_utf8(char * face_path, int fontsize, char * text)
+{
+ std::cerr << " PNGwriter::get_text_width_utf8 - ERROR **: PNGwriter was compiled without Freetype support! Recompile PNGwriter with Freetype support (once you have Freetype installed, that is. Websites: www.freetype.org and pngwriter.sourceforge.net)." << std::endl;
+ return 0;
+}
+
+///////////////
+#endif
+
+/////////////////////////////////////
+int pngwriter::bilinear_interpolation_read(double x, double y, int colour)
+{
+
+ int inty, intx;
+ inty = (int) ceil(y);
+ intx = (int) ceil(x);
+
+ //inty = (int) floor(y) +1;
+ // intx = (int) floor(x) +1;
+ //
+ bool attop, atright;
+ attop = inty==this->height_;
+ atright = intx==this->width_;
+/*
+ if( intx==this->width_ +1)
+ {
+ intx--;
+ // std::cout << "intx--" << std::endl;
+
+ }
+ */
+ /*
+ if(inty == this->height_ +1)
+ {
+ inty--;
+ // std::cout << "inty--" << std::endl;
+ }
+ */
+
+ if( (!attop)&&(!atright) )
+ {
+
+ double f,g,f1,g1;
+ f = 1.0 + x - ((double) intx);
+ g = 1.0 + y - ((double) inty);
+ f1 = 1.0 - f;
+ g1 = 1.0 - g;
+
+ return (int) (
+ f1*g1*this->read(intx, inty,colour)
+ + f*g1*this->read(intx+1,inty,colour)
+ +f1*g*this->read(intx,inty+1,colour)
+ + f*g*(this->read(intx+1,inty+1,colour))
+ );
+ }
+
+ if( (atright)&&(!attop))
+ {
+
+ double f,g,f1,g1;
+ f = 1.0 + x - ((double) intx);
+ g = 1.0 + y - ((double) inty);
+ f1 = 1.0 - f;
+ g1 = 1.0 - g;
+
+ return (int) (
+ f1*g1*this->read(intx, inty,colour)
+ + f*g1*( 2*(this->read(intx,inty,colour)) - (this->read(intx-1,inty,colour)) )
+ +f1*g*this->read(intx,inty+1,colour)
+ + f*g*(2*(this->read(intx,inty+1,colour)) - (this->read(intx-1,inty+1,colour)))
+ );
+ }
+
+ if((attop)&&(!atright))
+ {
+ double f,g,f1,g1;
+ f = 1.0 + x - ((double) intx);
+ g = 1.0 + y - ((double) inty);
+ f1 = 1.0 - f;
+ g1 = 1.0 - g;
+
+ return (int) (
+ f1*g1*this->read(intx, inty,colour)
+ + f*g1*this->read(intx+1,inty,colour)
+ +f1*g*( 2*(this->read(intx,inty,colour)) - this->read(intx,inty-1,colour) )
+ + f*g*( 2*(this->read(intx+1,inty,colour)) - this->read(intx+1,inty-1,colour))
+ );
+ }
+
+ double f,g,f1,g1;
+ f = 1.0 + x - ((double) intx);
+ g = 1.0 + y - ((double) inty);
+ f1 = 1.0 - f;
+ g1 = 1.0 - g;
+
+ return (int) (
+ f1*g1*this->read(intx, inty,colour)
+ + f*g1*( 2*(this->read(intx,inty,colour)) - (this->read(intx-1,inty,colour)) )
+ +f1*g*( 2*(this->read(intx,inty,colour)) - this->read(intx,inty-1,colour) )
+ + f*g*( 2*( 2*(this->read(intx,inty,colour)) - (this->read(intx-1,inty,colour)) ) - ( 2*(this->read(intx,inty-1,colour)) - (this->read(intx-1,inty-1,colour)) ))
+ );
+
+ /*
+ return (int) (
+ f1*g1*this->read(intx, inty,colour)
+ + f*g1*this->read(intx+1,inty,colour)
+ +f1*g*this->read(intx,inty+1,colour)
+ + f*g*this->read(intx+1, inty+1,colour)
+ );
+ * */
+
+};
+
+double pngwriter::bilinear_interpolation_dread(double x, double y, int colour)
+{
+ return double(this->bilinear_interpolation_read(x,y,colour))/65535.0;
+};
+
+void pngwriter::plot_blend(int x, int y, double opacity, int red, int green, int blue)
+{
+ this->plot(x, y,
+ (int)( opacity*red + this->read(x,y,1)*(1.0-opacity)),
+ (int)( opacity*green + this->read(x,y,2)*(1.0-opacity)),
+ (int)( opacity*blue + this->read(x,y,3)*(1.0-opacity))
+ );
+};
+
+void pngwriter::plot_blend(int x, int y, double opacity, double red, double green, double blue)
+{
+ this->plot_blend(x, y, opacity, (int) (65535*red), (int) (65535*green), (int) (65535*blue));
+};
+
+void pngwriter::invert(void)
+{
+ // int temp1, temp2, temp3;
+ double temp11, temp22, temp33;
+
+ for(int jjj = 1; jjj <= (this->height_); jjj++)
+ {
+ for(int iii = 1; iii <= (this->width_); iii++)
+ {
+ /* temp11 = (this->read(iii,jjj,1));
+ temp22 = (this->read(iii,jjj,2));
+ temp33 = (this->read(iii,jjj,3));
+ *
+ this->plot(iii,jjj,
+ ((double)(65535 - temp11))/65535.0,
+ ((double)(65535 - temp22))/65535.0,
+ ((double)(65535 - temp33))/65535.0
+ );
+ *
+ */
+ temp11 = (this->read(iii,jjj,1));
+ temp22 = (this->read(iii,jjj,2));
+ temp33 = (this->read(iii,jjj,3));
+
+ this->plot(iii,jjj,
+ (int)(65535 - temp11),
+ (int)(65535 - temp22),
+ (int)(65535 - temp33)
+ );
+
+ }
+ }
+}
+
+void pngwriter::resize(int width, int height)
+{
+
+ for (int jjj = 0; jjj < height_; jjj++) free(graph_[jjj]);
+ free(graph_);
+
+ width_ = width;
+ height_ = height;
+ backgroundcolour_ = 0;
+
+ graph_ = (png_bytepp)malloc(height_ * sizeof(png_bytep));
+ if(graph_ == NULL)
+ {
+ std::cerr << " PNGwriter::resize - ERROR **: Not able to allocate memory for image." << std::endl;
+ }
+
+ for (int kkkk = 0; kkkk < height_; kkkk++)
+ {
+ graph_[kkkk] = (png_bytep)malloc(6*width_ * sizeof(png_byte));
+ if(graph_[kkkk] == NULL)
+ {
+ std::cerr << " PNGwriter::resize - ERROR **: Not able to allocate memory for image." << std::endl;
+ }
+ }
+
+ if(graph_ == NULL)
+ {
+ std::cerr << " PNGwriter::resize - ERROR **: Not able to allocate memory for image." << std::endl;
+ }
+
+ int tempindex;
+ for(int hhh = 0; hhhdread(xstart,ystart,1) != boundary_red) ||
+ (this->dread(xstart,ystart,2) != boundary_green) ||
+ (this->dread(xstart,ystart,3) != boundary_blue)
+ )
+ &&
+ (
+ (this->dread(xstart,ystart,1) != fill_red) ||
+ (this->dread(xstart,ystart,2) != fill_green) ||
+ (this->dread(xstart,ystart,3) != fill_blue)
+ )
+ &&
+ (xstart >0)&&(xstart <= width_)&&(ystart >0)&&(ystart <= height_)
+ )
+ {
+ this->plot(xstart, ystart, fill_red, fill_green, fill_blue);
+ boundary_fill(xstart+1, ystart, boundary_red, boundary_green, boundary_blue, fill_red, fill_green, fill_blue) ;
+ boundary_fill(xstart, ystart+1, boundary_red, boundary_green, boundary_blue, fill_red, fill_green, fill_blue) ;
+ boundary_fill(xstart, ystart-1, boundary_red, boundary_green, boundary_blue, fill_red, fill_green, fill_blue) ;
+ boundary_fill(xstart-1, ystart, boundary_red, boundary_green, boundary_blue, fill_red, fill_green, fill_blue) ;
+ }
+}
+
+//no int version needed
+void pngwriter::flood_fill_internal(int xstart, int ystart, double start_red, double start_green, double start_blue, double fill_red, double fill_green, double fill_blue)
+{
+ if( (
+ (this->dread(xstart,ystart,1) == start_red) &&
+ (this->dread(xstart,ystart,2) == start_green) &&
+ (this->dread(xstart,ystart,3) == start_blue)
+ )
+ &&
+ (
+ (this->dread(xstart,ystart,1) != fill_red) ||
+ (this->dread(xstart,ystart,2) != fill_green) ||
+ (this->dread(xstart,ystart,3) != fill_blue)
+ )
+ &&
+ (xstart >0)&&(xstart <= width_)&&(ystart >0)&&(ystart <= height_)
+ )
+ {
+ this->plot(xstart, ystart, fill_red, fill_green, fill_blue);
+ flood_fill_internal( xstart+1, ystart, start_red, start_green, start_blue, fill_red, fill_green, fill_blue);
+ flood_fill_internal( xstart-1, ystart, start_red, start_green, start_blue, fill_red, fill_green, fill_blue);
+ flood_fill_internal( xstart, ystart+1, start_red, start_green, start_blue, fill_red, fill_green, fill_blue);
+ flood_fill_internal( xstart, ystart-1, start_red, start_green, start_blue, fill_red, fill_green, fill_blue);
+ }
+
+}
+
+//int version
+void pngwriter::boundary_fill(int xstart, int ystart, int boundary_red,int boundary_green,int boundary_blue,int fill_red, int fill_green, int fill_blue)
+{
+
+ this->boundary_fill( xstart, ystart,
+ ((double) boundary_red)/65535.0,
+ ((double) boundary_green)/65535.0,
+ ((double) boundary_blue)/65535.0,
+ ((double) fill_red)/65535.0,
+ ((double) fill_green)/65535.0,
+ ((double) fill_blue)/65535.0
+ );
+}
+
+void pngwriter::flood_fill(int xstart, int ystart, double fill_red, double fill_green, double fill_blue)
+{
+ flood_fill_internal( xstart, ystart, this->dread(xstart,ystart,1),this->dread(xstart,ystart,2),this->dread(xstart,ystart,3), fill_red, fill_green, fill_blue);
+}
+
+//int version
+void pngwriter::flood_fill(int xstart, int ystart, int fill_red, int fill_green, int fill_blue)
+{
+ this->flood_fill( xstart, ystart,
+ ((double) fill_red)/65535.0,
+ ((double) fill_green)/65535.0,
+ ((double) fill_blue)/65535.0
+ );
+}
+
+void pngwriter::polygon( int * points, int number_of_points, double red, double green, double blue)
+{
+ if( (number_of_points<1)||(points ==NULL))
+ {
+ std::cerr << " PNGwriter::polygon - ERROR **: Number of points is zero or negative, or array is NULL." << std::endl;
+ return;
+ }
+
+ for(int k=0;k< number_of_points-1; k++)
+ {
+ this->line(points[2*k],points[2*k+1],points[2*k+2],points[2*k+3], red, green, blue);
+ }
+}
+
+//int version
+void pngwriter::polygon( int * points, int number_of_points, int red, int green, int blue)
+{
+ this->polygon(points, number_of_points,
+ ((double) red)/65535.0,
+ ((double) green)/65535.0,
+ ((double) blue)/65535.0
+ );
+}
+
+void pngwriter::plotCMYK(int x, int y, double cyan, double magenta, double yellow, double black)
+{
+/*CMYK to RGB:
+ * -----------
+ * red = 255 - minimum(255,((cyan/255) * (255 - black) + black))
+ * green = 255 - minimum(255,((magenta/255) * (255 - black) + black))
+ * blue = 255 - minimum(255,((yellow/255) * (255 - black) + black))
+ * */
+
+ if(cyan<0.0)
+ {
+ cyan = 0.0;
+ }
+ if(magenta<0.0)
+ {
+ magenta = 0.0;
+ }
+ if(yellow<0.0)
+ {
+ yellow = 0.0;
+ }
+ if(black<0.0)
+ {
+ black = 0.0;
+ }
+
+ if(cyan>1.0)
+ {
+ cyan = 1.0;
+ }
+ if(magenta>1.0)
+ {
+ magenta = 1.0;
+ }
+ if(yellow>1.0)
+ {
+ yellow = 1.0;
+ }
+ if(black>1.0)
+ {
+ black = 1.0;
+ }
+
+ double red, green, blue, minr, ming, minb, iblack;
+
+ iblack = 1.0 - black;
+
+ minr = 1.0;
+ ming = 1.0;
+ minb = 1.0;
+
+ if( (cyan*iblack + black)<1.0 )
+ {
+ minr = cyan*iblack + black;
+ }
+
+ if( (magenta*iblack + black)<1.0 )
+ {
+ ming = magenta*iblack + black;
+ }
+
+ if( (yellow*iblack + black)<1.0 )
+ {
+ minb = yellow*iblack + black;
+ }
+
+ red = 1.0 - minr;
+ green = 1.0 - ming;
+ blue = 1.0 - minb;
+
+ this->plot(x,y,red, green, blue);
+
+}
+
+//int version
+void pngwriter::plotCMYK(int x, int y, int cyan, int magenta, int yellow, int black)
+{
+ this->plotCMYK( x, y,
+ ((double) cyan)/65535.0,
+ ((double) magenta)/65535.0,
+ ((double) yellow)/65535.0,
+ ((double) black)/65535.0
+ );
+}
+
+double pngwriter::dreadCMYK(int x, int y, int colour)
+{
+/*
+ * Black = minimum(1-Red,1-Green,1-Blue)
+ * Cyan = (1-Red-Black)/(1-Black)
+ * Magenta = (1-Green-Black)/(1-Black)
+ * Yellow = (1-Blue-Black)/(1-Black)
+ *
+ * */
+ if((colour !=1)&&(colour !=2)&&(colour !=3)&&(colour !=4))
+ {
+ std::cerr << " PNGwriter::dreadCMYK - WARNING **: Invalid argument: should be 1, 2, 3 or 4, is " << colour << std::endl;
+ return 0;
+ }
+
+ double black, red, green, blue, ired, igreen, iblue, iblack;
+ //add error detection here
+ // not much to detect, really
+ red = this->dread(x, y, 1);
+ green = this->dread(x, y, 2);
+ blue = this->dread(x, y, 3);
+
+ ired = 1.0 - red;
+ igreen = 1.0 - green;
+ iblue = 1.0 - blue;
+
+ black = ired;
+
+ //black is the mimimum of inverse RGB colours, and if they are all equal, it is the inverse of red.
+ if( (igreendread(x, y, 1);
+ green = this->dread(x, y, 2);
+ blue = this->dread(x, y, 3);
+
+ ired = 1.0 - red;
+ igreen = 1.0 - green;
+ iblue = 1.0 - blue;
+
+ black = ired;
+
+ //black is the mimimum of inverse RGB colours, and if they are all equal, it is the inverse of red.
+ if( (igreenbilinear_interpolation_read(readx, ready, 1);
+ green = this->bilinear_interpolation_read(readx, ready, 2);
+ blue = this->bilinear_interpolation_read(readx, ready, 3);
+ temp.plot(x, y, red, green, blue);
+
+ }
+ }
+
+ // From here on, the process is the same for all scale functions.
+ //Get data out of temp and into this's storage.
+
+ //Resize this instance
+ // Delete current storage.
+ for (int jjj = 0; jjj < height_; jjj++) free(graph_[jjj]);
+ free(graph_);
+
+ //New image will have bit depth 16, regardless of original bit depth.
+ bit_depth_ = 16;
+
+ // New width and height will be the scaled width and height
+ width_ = scaledw;
+ height_ = scaledh;
+ backgroundcolour_ = 0;
+
+ graph_ = (png_bytepp)malloc(height_ * sizeof(png_bytep));
+ if(graph_ == NULL)
+ {
+ std::cerr << " PNGwriter::scale_k - ERROR **: Not able to allocate memory for image." << std::endl;
+ }
+
+ for (int kkkk = 0; kkkk < height_; kkkk++)
+ {
+ graph_[kkkk] = (png_bytep)malloc(6*width_ * sizeof(png_byte));
+ if(graph_[kkkk] == NULL)
+ {
+ std::cerr << " PNGwriter::scale_k - ERROR **: Not able to allocate memory for image." << std::endl;
+ }
+ }
+
+ if(graph_ == NULL)
+ {
+ std::cerr << " PNGwriter::scale_k - ERROR **: Not able to allocate memory for image." << std::endl;
+ }
+
+ //This instance now has a new, resized storage space.
+
+ //Copy the temp date into this's storage.
+ int tempindex;
+ for(int hhh = 0; hhhbilinear_interpolation_read(readx, ready, 1);
+ green = this->bilinear_interpolation_read(readx, ready, 2);
+ blue = this->bilinear_interpolation_read(readx, ready, 3);
+ temp.plot(x, y, red, green, blue);
+
+ }
+ }
+ // From here on, the process is the same for all scale functions.
+ //Get data out of temp and into this's storage.
+
+ //Resize this instance
+ // Delete current storage.
+ for (int jjj = 0; jjj < height_; jjj++) free(graph_[jjj]);
+ free(graph_);
+
+ //New image will have bit depth 16, regardless of original bit depth.
+ bit_depth_ = 16;
+
+ // New width and height will be the scaled width and height
+ width_ = scaledw;
+ height_ = scaledh;
+ backgroundcolour_ = 0;
+
+ graph_ = (png_bytepp)malloc(height_ * sizeof(png_bytep));
+ if(graph_ == NULL)
+ {
+ std::cerr << " PNGwriter::scale_kxky - ERROR **: Not able to allocate memory for image." << std::endl;
+ }
+
+ for (int kkkk = 0; kkkk < height_; kkkk++)
+ {
+ graph_[kkkk] = (png_bytep)malloc(6*width_ * sizeof(png_byte));
+ if(graph_[kkkk] == NULL)
+ {
+ std::cerr << " PNGwriter::scale_kxky - ERROR **: Not able to allocate memory for image." << std::endl;
+ }
+ }
+
+ if(graph_ == NULL)
+ {
+ std::cerr << " PNGwriter::scale_kxky - ERROR **: Not able to allocate memory for image." << std::endl;
+ }
+
+ //This instance now has a new, resized storage space.
+
+ //Copy the temp date into this's storage.
+ int tempindex;
+ for(int hhh = 0; hhhbilinear_interpolation_read(readx, ready, 1);
+ green = this->bilinear_interpolation_read(readx, ready, 2);
+ blue = this->bilinear_interpolation_read(readx, ready, 3);
+ temp.plot(x, y, red, green, blue);
+
+ }
+ }
+
+ // From here on, the process is the same for all scale functions.
+ //Get data out of temp and into this's storage.
+
+ //Resize this instance
+ // Delete current storage.
+ for (int jjj = 0; jjj < height_; jjj++) free(graph_[jjj]);
+ free(graph_);
+
+ //New image will have bit depth 16, regardless of original bit depth.
+ bit_depth_ = 16;
+
+ // New width and height will be the scaled width and height
+ width_ = finalwidth;
+ height_ = finalheight;
+ backgroundcolour_ = 0;
+
+ graph_ = (png_bytepp)malloc(height_ * sizeof(png_bytep));
+ if(graph_ == NULL)
+ {
+ std::cerr << " PNGwriter::scale_wh - ERROR **: Not able to allocate memory for image." << std::endl;
+ }
+
+ for (int kkkk = 0; kkkk < height_; kkkk++)
+ {
+ graph_[kkkk] = (png_bytep)malloc(6*width_ * sizeof(png_byte));
+ if(graph_[kkkk] == NULL)
+ {
+ std::cerr << " PNGwriter::scale_wh - ERROR **: Not able to allocate memory for image." << std::endl;
+ }
+ }
+
+ if(graph_ == NULL)
+ {
+ std::cerr << " PNGwriter::scale_wh - ERROR **: Not able to allocate memory for image." << std::endl;
+ }
+
+ //This instance now has a new, resized storage space.
+
+ //Copy the temp date into this's storage.
+ int tempindex;
+ for(int hhh = 0; hhhplot_blend(xfrom,yfrom,opacity, red,green,blue);
+
+ if (dx > dy)
+ {
+ int fraction = dy - (dx >> 1);
+
+ while (xfrom != xto)
+ {
+ if (fraction >= 0)
+ {
+ yfrom += stepy;
+ fraction -= dx;
+ }
+ xfrom += stepx;
+ fraction += dy;
+ this->plot_blend(xfrom,yfrom,opacity, red,green,blue);
+ }
+ }
+ else
+ {
+ int fraction = dx - (dy >> 1);
+ while (yfrom != yto)
+ {
+ if (fraction >= 0)
+ {
+ xfrom += stepx;
+ fraction -= dy;
+ }
+ yfrom += stepy;
+ fraction += dx;
+ this->plot_blend(xfrom,yfrom, opacity, red,green,blue);
+ }
+ }
+
+}
+
+void pngwriter::line_blend(int xfrom, int yfrom, int xto, int yto, double opacity, double red, double green,double blue)
+{
+ this->line_blend( xfrom,
+ yfrom,
+ xto,
+ yto,
+ opacity,
+ int (red*65535),
+ int (green*65535),
+ int (blue*65535)
+ );
+
+}
+
+void pngwriter::square_blend(int xfrom, int yfrom, int xto, int yto, double opacity, int red, int green,int blue)
+{
+ this->line_blend(xfrom, yfrom, xfrom, yto, opacity, red, green, blue);
+ this->line_blend(xto, yfrom, xto, yto, opacity, red, green, blue);
+ this->line_blend(xfrom, yfrom, xto, yfrom, opacity, red, green, blue);
+ this->line_blend(xfrom, yto, xto, yto, opacity, red, green, blue);
+}
+
+void pngwriter::square_blend(int xfrom, int yfrom, int xto, int yto, double opacity, double red, double green,double blue)
+{
+ this->square_blend( xfrom, yfrom, xto, yto, opacity, int(red*65535), int(green*65535), int(blue*65535));
+}
+
+void pngwriter::filledsquare_blend(int xfrom, int yfrom, int xto, int yto, double opacity, int red, int green,int blue)
+{
+ for(int caca = xfrom; caca line_blend(caca, yfrom, caca, yto, opacity, red, green, blue);
+ }
+
+}
+
+void pngwriter::filledsquare_blend(int xfrom, int yfrom, int xto, int yto, double opacity, double red, double green,double blue)
+{
+ this->filledsquare_blend( xfrom, yfrom, xto, yto, opacity, int(red*65535), int(green*65535), int(blue*65535));
+}
+
+void pngwriter::circle_aux_blend(int xcentre, int ycentre, int x, int y, double opacity, int red, int green, int blue)
+{
+ if (x == 0)
+ {
+ this->plot_blend( xcentre, ycentre + y, opacity, red, green, blue);
+ this->plot_blend( xcentre, ycentre - y, opacity, red, green, blue);
+ this->plot_blend( xcentre + y, ycentre, opacity, red, green, blue);
+ this->plot_blend( xcentre - y, ycentre, opacity, red, green, blue);
+ }
+ else
+ if (x == y)
+ {
+ this->plot_blend( xcentre + x, ycentre + y, opacity, red, green, blue);
+ this->plot_blend( xcentre - x, ycentre + y, opacity, red, green, blue);
+ this->plot_blend( xcentre + x, ycentre - y, opacity, red, green, blue);
+ this->plot_blend( xcentre - x, ycentre - y, opacity, red, green, blue);
+ }
+ else
+ if (x < y)
+ {
+ this->plot_blend( xcentre + x, ycentre + y, opacity, red, green, blue);
+ this->plot_blend( xcentre - x, ycentre + y, opacity, red, green, blue);
+ this->plot_blend( xcentre + x, ycentre - y, opacity, red, green, blue);
+ this->plot_blend( xcentre - x, ycentre - y, opacity, red, green, blue);
+ this->plot_blend( xcentre + y, ycentre + x, opacity, red, green, blue);
+ this->plot_blend( xcentre - y, ycentre + x, opacity, red, green, blue);
+ this->plot_blend( xcentre + y, ycentre - x, opacity, red, green, blue);
+ this->plot_blend( xcentre - y, ycentre - x, opacity, red, green, blue);
+ }
+
+}
+//
+
+void pngwriter::circle_blend(int xcentre, int ycentre, int radius, double opacity, int red, int green, int blue)
+{
+ int x = 0;
+ int y = radius;
+ int p = (5 - radius*4)/4;
+
+ circle_aux_blend(xcentre, ycentre, x, y, opacity, red, green, blue);
+ while (x < y)
+ {
+ x++;
+ if (p < 0)
+ {
+ p += 2*x+1;
+ }
+ else
+ {
+ y--;
+ p += 2*(x-y)+1;
+ }
+ circle_aux_blend(xcentre, ycentre, x, y, opacity, red, green, blue);
+ }
+
+}
+
+void pngwriter::circle_blend(int xcentre, int ycentre, int radius, double opacity, double red, double green, double blue)
+{
+ this->circle_blend(xcentre,ycentre,radius, opacity, int(red*65535), int(green*65535), int(blue*65535));
+}
+
+void pngwriter::filledcircle_blend(int xcentre, int ycentre, int radius, double opacity, int red, int green, int blue)
+{
+ for(int jjj = ycentre-radius; jjj< ycentre+radius+1; jjj++)
+ {
+ this->line_blend(xcentre - int(sqrt((double)(radius*radius) - (-ycentre + jjj)*(-ycentre + jjj ))), jjj,
+ xcentre + int(sqrt((double)(radius*radius) - (-ycentre + jjj)*(-ycentre + jjj ))),jjj, opacity, red,green,blue);
+ }
+
+}
+
+void pngwriter::filledcircle_blend(int xcentre, int ycentre, int radius, double opacity, double red, double green, double blue)
+{
+ this->filledcircle_blend( xcentre, ycentre, radius, opacity, int(red*65535), int(green*65535), int(blue*65535));
+}
+
+void pngwriter::bezier_blend( int startPtX, int startPtY,
+ int startControlX, int startControlY,
+ int endPtX, int endPtY,
+ int endControlX, int endControlY,
+ double opacity,
+ double red, double green, double blue)
+{
+
+ double cx = 3.0*(startControlX - startPtX);
+ double bx = 3.0*(endControlX - startControlX) - cx;
+ double ax = double(endPtX - startPtX - cx - bx);
+
+ double cy = 3.0*(startControlY - startPtY);
+ double by = 3.0*(endControlY - startControlY) - cy;
+ double ay = double(endPtY - startPtY - cy - by);
+
+ double x,y,newx,newy;
+ x = startPtX;
+ y = startPtY;
+
+ for(double t = 0.0; t<=1.005; t += 0.005)
+ {
+ newx = startPtX + t*(double(cx) + t*(double(bx) + t*(double(ax))));
+ newy = startPtY + t*(double(cy) + t*(double(by) + t*(double(ay))));
+ this->line_blend(int(x),int(y),int(newx),int(newy),opacity, red,green,blue);
+ x = newx;
+ y = newy;
+ }
+}
+
+void pngwriter::bezier_blend( int startPtX, int startPtY,
+ int startControlX, int startControlY,
+ int endPtX, int endPtY,
+ int endControlX, int endControlY,
+ double opacity,
+ int red, int green, int blue)
+{
+ this->bezier_blend( startPtX, startPtY,
+ startControlX, startControlY,
+ endPtX, endPtY,
+ endControlX, endControlY,
+ opacity,
+ double(red)/65535.0, double(green)/65535.0, double(blue)/65535.0);
+
+}
+
+/////////////////////////////
+#ifndef NO_FREETYPE
+
+// Freetype-based text rendering functions.
+///////////////////////////////////////////
+void pngwriter::plot_text_blend( char * face_path, int fontsize, int x_start, int y_start, double angle, char * text, double opacity, double red, double green, double blue)
+{
+ FT_Library library;
+ FT_Face face;
+ FT_Matrix matrix; // transformation matrix
+ FT_Vector pen;
+
+ FT_UInt glyph_index;
+ FT_Error error;
+
+ FT_Bool use_kerning;
+ FT_UInt previous = 0;
+
+ /* Set up transformation Matrix */
+ matrix.xx = (FT_Fixed)( cos(angle)*0x10000); /* It would make more sense to do this (below), but, bizzarely, */
+ matrix.xy = (FT_Fixed)(-sin(angle)*0x10000); /* if one does, FT_Load_Glyph fails consistently. */
+ matrix.yx = (FT_Fixed)( sin(angle)*0x10000); // matrix.yx = - matrix.xy;
+ matrix.yy = (FT_Fixed)( cos(angle)*0x10000); // matrix.yy = matrix.xx;
+
+ /* Place starting coordinates in adequate form. */
+ pen.x = x_start*64 ;
+ pen.y = (int)(y_start/64.0);
+
+ /*Count the length of the string */
+ int num_chars = strlen(text);
+
+ /* Initialize FT Library object */
+ error = FT_Init_FreeType( &library );
+ if (error) { std::cerr << " PNGwriter::plot_text_blend - ERROR **: FreeType: Could not init Library."<< std::endl; return;}
+
+ /* Initialize FT face object */
+ error = FT_New_Face( library,face_path,0,&face );
+ if ( error == FT_Err_Unknown_File_Format ) { std::cerr << " PNGwriter::plot_text_blend - ERROR **: FreeType: Font was opened, but type not supported."<< std::endl; return; } else if (error){ std::cerr << " PNGwriter::plot_text - ERROR **: FreeType: Could not find or load font file."<< std::endl; return; }
+
+ /* Set the Char size */
+ error = FT_Set_Char_Size( face, /* handle to face object */
+ 0, /* char_width in 1/64th of points */
+ fontsize*64, /* char_height in 1/64th of points */
+ 100, /* horizontal device resolution */
+ 100 ); /* vertical device resolution */
+
+ /* A way of accesing the glyph directly */
+ FT_GlyphSlot slot = face->glyph; // a small shortcut
+
+ /* Does the font file support kerning? */
+ use_kerning = FT_HAS_KERNING( face );
+
+ int n;
+ for ( n = 0; n < num_chars; n++ )
+ {
+ /* Convert character code to glyph index */
+ glyph_index = FT_Get_Char_Index( face, text[n] );
+
+ /* Retrieve kerning distance and move pen position */
+ if ( use_kerning && previous&& glyph_index )
+ {
+ FT_Vector delta;
+ FT_Get_Kerning( face,
+ previous,
+ glyph_index,
+ ft_kerning_default, //FT_KERNING_DEFAULT,
+ &delta );
+
+ /* Transform this kerning distance into rotated space */
+ pen.x += (int) (((double) delta.x)*cos(angle));
+ pen.y += (int) (((double) delta.x)*( sin(angle)));
+ }
+
+ /* Set transform */
+ FT_Set_Transform( face, &matrix, &pen );
+
+/*set char size*/
+
+ if (error) { std::cerr << " PNGwriter::plot_text_blend - ERROR **: FreeType: Set char size error." << std::endl; return;};
+
+ /* Retrieve glyph index from character code */
+ glyph_index = FT_Get_Char_Index( face, text[n] );
+
+ /* Load glyph image into the slot (erase previous one) */
+ error = FT_Load_Glyph( face, glyph_index, FT_LOAD_DEFAULT );
+ if (error) { std::cerr << " PNGwriter::plot_text_blend - ERROR **: FreeType: Could not load glyph (in loop). (FreeType error "<< std::hex << error <<")." << std::endl; return;}
+
+ /* Convert to an anti-aliased bitmap */
+ // error = FT_Render_Glyph( face->glyph, FT_RENDER_MODE_NORMAL );
+ error = FT_Render_Glyph( face->glyph, ft_render_mode_normal );
+ if (error) { std::cerr << " PNGwriter::plot_text_blend - ERROR **: FreeType: Render glyph error." << std::endl; return;}
+
+ /* Now, draw to our target surface */
+ my_draw_bitmap_blend( &slot->bitmap,
+ slot->bitmap_left,
+ y_start + slot->bitmap_top,
+ opacity,
+ red,
+ green,
+ blue );
+
+ /* Advance to the next position */
+ pen.x += slot->advance.x;
+ pen.y += slot->advance.y;
+
+ /* record current glyph index */
+ previous = glyph_index;
+ }
+
+ /* Free the face and the library objects */
+ FT_Done_Face ( face );
+ FT_Done_FreeType( library );
+}
+
+void pngwriter::plot_text_utf8_blend( char * face_path, int fontsize, int x_start, int y_start, double angle, char * text, double opacity, double red, double green, double blue)
+{
+ FT_Library library;
+ FT_Face face;
+ FT_Matrix matrix; // transformation matrix
+ FT_Vector pen;
+
+ FT_UInt glyph_index;
+ FT_Error error;
+
+ FT_Bool use_kerning;
+ FT_UInt previous = 0;
+
+ /* Set up transformation Matrix */
+ matrix.xx = (FT_Fixed)( cos(angle)*0x10000); /* It would make more sense to do this (below), but, bizzarely, */
+ matrix.xy = (FT_Fixed)(-sin(angle)*0x10000); /* if one does, FT_Load_Glyph fails consistently. */
+ matrix.yx = (FT_Fixed)( sin(angle)*0x10000); // matrix.yx = - matrix.xy;
+ matrix.yy = (FT_Fixed)( cos(angle)*0x10000); // matrix.yy = matrix.xx;
+
+ /* Place starting coordinates in adequate form. */
+ pen.x = x_start*64 ;
+ pen.y = (int)(y_start/64.0);
+
+ /*Count the length of the string */
+ int num_bytes=0;
+ while(text[num_bytes]!=0)
+ {
+ num_bytes++;
+ }
+
+ /*
+ std::cout << "Num bytes is: "<< num_bytes << std::endl;
+ */
+
+ //The array of ucs4 glyph indexes, which will by at most the number of bytes in the utf-8 file.
+ long * ucs4text;
+ ucs4text = new long[num_bytes+1];
+
+ unsigned char u,v,w,x,y,z;
+
+ int num_chars=0;
+
+ long iii=0;
+
+ while(iiiglyph; // a small shortcut
+
+ /* Does the font file support kerning? */
+ use_kerning = FT_HAS_KERNING( face );
+
+ int n;
+ for ( n = 0; n < num_chars; n++ )
+ {
+ /* Convert character code to glyph index */
+ glyph_index = FT_Get_Char_Index( face, ucs4text[n] );
+
+ /* Retrieve kerning distance and move pen position */
+ if ( use_kerning && previous&& glyph_index )
+ {
+ FT_Vector delta;
+ FT_Get_Kerning( face,
+ previous,
+ glyph_index,
+ ft_kerning_default, //FT_KERNING_DEFAULT,
+ &delta );
+
+ /* Transform this kerning distance into rotated space */
+ pen.x += (int) (((double) delta.x)*cos(angle));
+ pen.y += (int) (((double) delta.x)*( sin(angle)));
+ }
+
+ /* Set transform */
+ FT_Set_Transform( face, &matrix, &pen );
+
+/*set char size*/
+
+ if (error) { std::cerr << " PNGwriter::plot_text_utf8_blend - ERROR **: FreeType: Set char size error." << std::endl; return;};
+
+ /* Retrieve glyph index from character code */
+ glyph_index = FT_Get_Char_Index( face, ucs4text[n] );
+
+ /* Load glyph image into the slot (erase previous one) */
+ error = FT_Load_Glyph( face, glyph_index, FT_LOAD_DEFAULT );
+ if (error) { std::cerr << " PNGwriter::plot_text_utf8_blend - ERROR **: FreeType: Could not load glyph (in loop). (FreeType error "<< std::hex << error <<")." << std::endl; return;}
+
+ /* Convert to an anti-aliased bitmap */
+ error = FT_Render_Glyph( face->glyph, ft_render_mode_normal );
+ if (error) { std::cerr << " PNGwriter::plot_text_utf8_blend - ERROR **: FreeType: Render glyph error." << std::endl; return;}
+
+ /* Now, draw to our target surface */
+ my_draw_bitmap_blend( &slot->bitmap,
+ slot->bitmap_left,
+ y_start + slot->bitmap_top,
+ opacity,
+ red,
+ green,
+ blue );
+
+ /* Advance to the next position */
+ pen.x += slot->advance.x;
+ pen.y += slot->advance.y;
+
+ /* record current glyph index */
+ previous = glyph_index;
+ }
+
+ /* Free the face and the library objects */
+ FT_Done_Face ( face );
+ FT_Done_FreeType( library );
+
+ delete[] ucs4text;
+}
+
+void pngwriter::plot_text_blend( char * face_path, int fontsize, int x_start, int y_start, double angle, char * text, double opacity, int red, int green, int blue)
+{
+ plot_text_blend( face_path, fontsize, x_start, y_start, angle, text, opacity, ((double) red)/65535.0, ((double) green)/65535.0, ((double) blue)/65535.0 );
+}
+
+void pngwriter::plot_text_utf8_blend( char * face_path, int fontsize, int x_start, int y_start, double angle, char * text, double opacity, int red, int green, int blue)
+{
+ plot_text_utf8_blend( face_path, fontsize, x_start, y_start, angle, text, opacity, ((double) red)/65535.0, ((double) green)/65535.0, ((double) blue)/65535.0 );
+}
+
+void pngwriter::my_draw_bitmap_blend( FT_Bitmap * bitmap, int x, int y, double opacity, double red, double green, double blue)
+{
+ double temp;
+ for(int j=1; jrows+1; j++)
+ {
+ for(int i=1; i< bitmap->width + 1; i++)
+ {
+ temp = (double)(bitmap->buffer[(j-1)*bitmap->width + (i-1)] )/255.0;
+
+ if(temp)
+ {
+ this->plot_blend(x + i,
+ y - j,
+ opacity,
+ temp*red + (1-temp)*(this->dread(x+i,y-j,1)),
+ temp*green + (1-temp)*(this->dread(x+i,y-j,2)),
+ temp*blue + (1-temp)*(this->dread(x+i,y-j,3))
+ );
+ }
+ }
+ }
+}
+
+#endif
+#ifdef NO_FREETYPE
+
+void pngwriter::plot_text_blend( char * face_path, int fontsize, int x_start, int y_start, double angle, char * text, double opacity, int red, int green, int blue)
+{
+ std::cerr << " PNGwriter::plot_text_blend - ERROR **: PNGwriter was compiled without Freetype support! Recompile PNGwriter with Freetype support (once you have Freetype installed, that is. Websites: www.freetype.org and pngwriter.sourceforge.net)." << std::endl;
+ return;
+}
+
+void pngwriter::plot_text_blend( char * face_path, int fontsize, int x_start, int y_start, double angle, char * text, double opacity, double red, double green, double blue)
+{
+ std::cerr << " PNGwriter::plot_text_blend - ERROR **: PNGwriter was compiled without Freetype support! Recompile PNGwriter with Freetype support (once you have Freetype installed, that is. Websites: www.freetype.org and pngwriter.sourceforge.net)." << std::endl;
+ return;
+
+}
+
+void pngwriter::plot_text_utf8_blend( char * face_path, int fontsize, int x_start, int y_start, double angle, char * text, double opacity, int red, int green, int blue)
+{
+ std::cerr << " PNGwriter::plot_text_utf8_blend - ERROR **: PNGwriter was compiled without Freetype support! Recompile PNGwriter with Freetype support (once you have Freetype installed, that is. Websites: www.freetype.org and pngwriter.sourceforge.net)." << std::endl;
+ return;
+}
+
+void pngwriter::plot_text_utf8_blend( char * face_path, int fontsize, int x_start, int y_start, double angle, char * text, double opacity, double red, double green, double blue)
+{
+ std::cerr << " PNGwriter::plot_text_utf8_blend - ERROR **: PNGwriter was compiled without Freetype support! Recompile PNGwriter with Freetype support (once you have Freetype installed, that is. Websites: www.freetype.org and pngwriter.sourceforge.net)." << std::endl;
+ return;
+}
+
+#endif
+
+///////////////////////////
+
+void pngwriter::boundary_fill_blend(int xstart, int ystart, double opacity, double boundary_red,double boundary_green,double boundary_blue,double fill_red, double fill_green, double fill_blue)
+{
+ if( (
+ (this->dread(xstart,ystart,1) != boundary_red) ||
+ (this->dread(xstart,ystart,2) != boundary_green) ||
+ (this->dread(xstart,ystart,3) != boundary_blue)
+ )
+ &&
+ (
+ (this->dread(xstart,ystart,1) != fill_red) ||
+ (this->dread(xstart,ystart,2) != fill_green) ||
+ (this->dread(xstart,ystart,3) != fill_blue)
+ )
+ &&
+ (xstart >0)&&(xstart <= width_)&&(ystart >0)&&(ystart <= height_)
+ )
+ {
+ this->plot_blend(xstart, ystart, opacity, fill_red, fill_green, fill_blue);
+ boundary_fill_blend(xstart+1, ystart, opacity, boundary_red, boundary_green, boundary_blue, fill_red, fill_green, fill_blue) ;
+ boundary_fill_blend(xstart, ystart+1, opacity, boundary_red, boundary_green, boundary_blue, fill_red, fill_green, fill_blue) ;
+ boundary_fill_blend(xstart, ystart-1, opacity, boundary_red, boundary_green, boundary_blue, fill_red, fill_green, fill_blue) ;
+ boundary_fill_blend(xstart-1, ystart, opacity, boundary_red, boundary_green, boundary_blue, fill_red, fill_green, fill_blue) ;
+ }
+}
+
+//no int version needed
+void pngwriter::flood_fill_internal_blend(int xstart, int ystart, double opacity, double start_red, double start_green, double start_blue, double fill_red, double fill_green, double fill_blue)
+{
+ if( (
+ (this->dread(xstart,ystart,1) == start_red) &&
+ (this->dread(xstart,ystart,2) == start_green) &&
+ (this->dread(xstart,ystart,3) == start_blue)
+ )
+ &&
+ (
+ (this->dread(xstart,ystart,1) != fill_red) ||
+ (this->dread(xstart,ystart,2) != fill_green) ||
+ (this->dread(xstart,ystart,3) != fill_blue)
+ )
+ &&
+ (xstart >0)&&(xstart <= width_)&&(ystart >0)&&(ystart <= height_)
+ )
+ {
+ this->plot_blend(xstart, ystart, opacity, fill_red, fill_green, fill_blue);
+ flood_fill_internal_blend( xstart+1, ystart, opacity, start_red, start_green, start_blue, fill_red, fill_green, fill_blue);
+ flood_fill_internal_blend( xstart-1, ystart,opacity, start_red, start_green, start_blue, fill_red, fill_green, fill_blue);
+ flood_fill_internal_blend( xstart, ystart+1, opacity, start_red, start_green, start_blue, fill_red, fill_green, fill_blue);
+ flood_fill_internal_blend( xstart, ystart-1, opacity, start_red, start_green, start_blue, fill_red, fill_green, fill_blue);
+ }
+
+}
+
+//int version
+void pngwriter::boundary_fill_blend(int xstart, int ystart, double opacity, int boundary_red,int boundary_green,int boundary_blue,int fill_red, int fill_green, int fill_blue)
+{
+
+ this->boundary_fill_blend( xstart, ystart,
+ opacity,
+ ((double) boundary_red)/65535.0,
+ ((double) boundary_green)/65535.0,
+ ((double) boundary_blue)/65535.0,
+ ((double) fill_red)/65535.0,
+ ((double) fill_green)/65535.0,
+ ((double) fill_blue)/65535.0
+ );
+}
+
+void pngwriter::flood_fill_blend(int xstart, int ystart, double opacity, double fill_red, double fill_green, double fill_blue)
+{
+ flood_fill_internal_blend( xstart, ystart, opacity, this->dread(xstart,ystart,1),this->dread(xstart,ystart,2),this->dread(xstart,ystart,3), fill_red, fill_green, fill_blue);
+}
+
+//int version
+void pngwriter::flood_fill_blend(int xstart, int ystart, double opacity, int fill_red, int fill_green, int fill_blue)
+{
+ this->flood_fill_blend( xstart, ystart,
+ opacity,
+ ((double) fill_red)/65535.0,
+ ((double) fill_green)/65535.0,
+ ((double) fill_blue)/65535.0
+ );
+}
+
+void pngwriter::polygon_blend( int * points, int number_of_points, double opacity, double red, double green, double blue)
+{
+ if( (number_of_points<1)||(points ==NULL))
+ {
+ std::cerr << " PNGwriter::polygon_blend - ERROR **: Number of points is zero or negative, or array is NULL." << std::endl;
+ return;
+ }
+
+ for(int k=0;k< number_of_points-1; k++)
+ {
+ this->line_blend(points[2*k],points[2*k+1],points[2*k+2],points[2*k+3], opacity, red, green, blue);
+ }
+}
+
+//int version
+void pngwriter::polygon_blend( int * points, int number_of_points, double opacity, int red, int green, int blue)
+{
+ this->polygon_blend(points, number_of_points,
+ opacity,
+ ((double) red)/65535.0,
+ ((double) green)/65535.0,
+ ((double) blue)/65535.0
+ );
+}
+
+void pngwriter::plotCMYK_blend(int x, int y, double opacity, double cyan, double magenta, double yellow, double black)
+{
+/*CMYK to RGB:
+ * -----------
+ * red = 255 - minimum(255,((cyan/255) * (255 - black) + black))
+ * green = 255 - minimum(255,((magenta/255) * (255 - black) + black))
+ * blue = 255 - minimum(255,((yellow/255) * (255 - black) + black))
+ * */
+
+ if(cyan<0.0)
+ {
+ cyan = 0.0;
+ }
+ if(magenta<0.0)
+ {
+ magenta = 0.0;
+ }
+ if(yellow<0.0)
+ {
+ yellow = 0.0;
+ }
+ if(black<0.0)
+ {
+ black = 0.0;
+ }
+
+ if(cyan>1.0)
+ {
+ cyan = 1.0;
+ }
+ if(magenta>1.0)
+ {
+ magenta = 1.0;
+ }
+ if(yellow>1.0)
+ {
+ yellow = 1.0;
+ }
+ if(black>1.0)
+ {
+ black = 1.0;
+ }
+
+ double red, green, blue, minr, ming, minb, iblack;
+
+ iblack = 1.0 - black;
+
+ minr = 1.0;
+ ming = 1.0;
+ minb = 1.0;
+
+ if( (cyan*iblack + black)<1.0 )
+ {
+ minr = cyan*iblack + black;
+ }
+
+ if( (magenta*iblack + black)<1.0 )
+ {
+ ming = magenta*iblack + black;
+ }
+
+ if( (yellow*iblack + black)<1.0 )
+ {
+ minb = yellow*iblack + black;
+ }
+
+ red = 1.0 - minr;
+ green = 1.0 - ming;
+ blue = 1.0 - minb;
+
+ this->plot_blend(x,y,opacity, red, green, blue);
+
+}
+
+//int version
+void pngwriter::plotCMYK_blend(int x, int y, double opacity, int cyan, int magenta, int yellow, int black)
+{
+ this->plotCMYK_blend( x, y,
+ opacity,
+ ((double) cyan)/65535.0,
+ ((double) magenta)/65535.0,
+ ((double) yellow)/65535.0,
+ ((double) black)/65535.0
+ );
+}
+
+void pngwriter::laplacian(double k, double offset)
+{
+
+ // Create image storage.
+ pngwriter temp(width_,height_,0,"temp");
+
+ double red, green, blue;
+
+ for(int x = 1; x <= width_; x++)
+ {
+ for(int y = 1; y <= height_; y++)
+ {
+ red =
+ 8.0*this->dread(x,y,1) -
+ ( this->dread(x+1, y-1, 1) +
+ this->dread(x, y-1, 1) +
+ this->dread(x-1, y-1, 1) +
+ this->dread(x-1, y, 1) +
+ this->dread(x+1, y, 1) +
+ this->dread(x+1, y+1, 1) +
+ this->dread(x, y+1, 1) +
+ this->dread(x-1, y+1, 1) );
+
+ green =
+ 8.0*this->dread(x,y,2) -
+ ( this->dread(x+1, y-1, 2) +
+ this->dread(x, y-1, 2) +
+ this->dread(x-1, y-1, 2) +
+ this->dread(x-1, y, 2) +
+ this->dread(x+1, y, 2) +
+ this->dread(x+1, y+1, 2) +
+ this->dread(x, y+1, 2) +
+ this->dread(x-1, y+1, 2));
+
+ blue =
+ 8.0*this->dread(x,y,3) -
+ ( this->dread(x+1, y-1, 3) +
+ this->dread(x, y-1, 3) +
+ this->dread(x-1, y-1, 3) +
+ this->dread(x-1, y, 3) +
+ this->dread(x+1, y, 3) +
+ this->dread(x+1, y+1, 3) +
+ this->dread(x, y+1, 3) +
+ this->dread(x-1, y+1, 3));
+
+ temp.plot(x,y,offset+k*red,offset+k*green,offset+k*blue);
+
+ }
+ }
+
+ for(int xx = 1; xx <= width_; xx++)
+ {
+ for(int yy = 1; yy <= height_; yy++)
+ {
+ this->plot(xx,yy, temp.read(xx,yy,1), temp.read(xx,yy,2), temp.read(xx,yy,3));
+ }
+ }
+}
+
+
+
+// drwatop(), drawbottom() and filledtriangle() were contributed by Gurkan Sengun
+// ( , http://www.linuks.mine.nu/ )
+void pngwriter::drawtop(long x1,long y1,long x2,long y2,long x3, int red, int green, int blue)
+{
+ // This swaps x2 and x3
+ // if(x2>x3) x2^=x3^=x2^=x3;
+ if(x2>x3)
+ {
+ x2^=x3;
+ x3^=x2;
+ x2^=x3;
+ }
+
+ long posl = x1*256;
+ long posr = posl;
+
+ long cl=((x2-x1)*256)/(y2-y1);
+ long cr=((x3-x1)*256)/(y2-y1);
+
+ for(int y=y1; yline(posl/256, y, posr/256, y, red, green, blue);
+ posl+=cl;
+ posr+=cr;
+ }
+}
+
+// drwatop(), drawbottom() and filledtriangle() were contributed by Gurkan Sengun
+// ( , http://www.linuks.mine.nu/ )
+void pngwriter::drawbottom(long x1,long y1,long x2,long x3,long y3, int red, int green, int blue)
+{
+ //Swap x1 and x2
+ //if(x1>x2) x2^=x1^=x2^=x1;
+ if(x1>x2)
+ {
+ x2^=x1;
+ x1^=x2;
+ x2^=x1;
+ }
+
+ long posl=x1*256;
+ long posr=x2*256;
+
+ long cl=((x3-x1)*256)/(y3-y1);
+ long cr=((x3-x2)*256)/(y3-y1);
+
+ for(int y=y1; yline(posl/256, y, posr/256, y, red, green, blue);
+
+ posl+=cl;
+ posr+=cr;
+ }
+}
+
+// drwatop(), drawbottom() and filledtriangle() were contributed by Gurkan Sengun
+// ( , http://www.linuks.mine.nu/ )
+void pngwriter::filledtriangle(int x1,int y1,int x2,int y2,int x3,int y3, int red, int green, int blue)
+{
+ if((x1==x2 && x2==x3) || (y1==y2 && y2==y3)) return;
+
+ if(y2drawtop(x1, y1, x2, y2, x3, red, green, blue);
+ }
+ else
+ {
+ if(y1==y3 || y1==y2)
+ {
+ this->drawbottom(x1, y1, x2, x3, y3, red, green, blue);
+ }
+ else
+ {
+ int new_x = x1 + (int)((double)(y2-y1)*(double)(x3-x1)/(double)(y3-y1));
+ this->drawtop(x1, y1, new_x, y2, x2, red, green, blue);
+ this->drawbottom(x2, y2, new_x, x3, y3, red, green, blue);
+ }
+ }
+
+}
+
+//Double (bug found by Dave Wilks. Was: (int) red*65535, should have been (int) (red*65535).
+void pngwriter::filledtriangle(int x1,int y1,int x2,int y2,int x3,int y3, double red, double green, double blue)
+{
+ this->filledtriangle(x1, y1, x2, y2, x3, y3, (int) (red*65535), (int) (green*65535), (int) (blue*65535));
+}
+
+//Blend, double. (bug found by Dave Wilks. Was: (int) red*65535, should have been (int) (red*65535).
+void pngwriter::filledtriangle_blend(int x1,int y1,int x2,int y2,int x3,int y3, double opacity, double red, double green, double blue)
+{
+ this->filledtriangle_blend( x1, y1, x2, y2, x3, y3, opacity, (int) (red*65535), (int) (green*65535), (int) (blue*65535));
+}
+
+//Blend, int
+void pngwriter::filledtriangle_blend(int x1,int y1,int x2,int y2,int x3,int y3, double opacity, int red, int green, int blue)
+{
+ if((x1==x2 && x2==x3) || (y1==y2 && y2==y3)) return;
+
+ /*if(y2drawtop_blend(x1, y1, x2, y2, x3, opacity, red, green, blue);
+ }
+ else
+ {
+ if(y1==y3 || y1==y2)
+ {
+ this->drawbottom_blend(x1, y1, x2, x3, y3, opacity, red, green, blue);
+ }
+ else
+ {
+ int new_x = x1 + (int)((double)(y2-y1)*(double)(x3-x1)/(double)(y3-y1));
+ this->drawtop_blend(x1, y1, new_x, y2, x2, opacity, red, green, blue);
+ this->drawbottom_blend(x2, y2, new_x, x3, y3, opacity, red, green, blue);
+ }
+ }
+
+}
+
+//Blend, int
+void pngwriter::drawbottom_blend(long x1,long y1,long x2,long x3,long y3, double opacity, int red, int green, int blue)
+{
+ //Swap x1 and x2
+ if(x1>x2)
+ {
+ x2^=x1;
+ x1^=x2;
+ x2^=x1;
+ }
+
+ long posl=x1*256;
+ long posr=x2*256;
+
+ long cl=((x3-x1)*256)/(y3-y1);
+ long cr=((x3-x2)*256)/(y3-y1);
+
+ for(int y=y1; yline_blend(posl/256, y, posr/256, y, opacity, red, green, blue);
+
+ posl+=cl;
+ posr+=cr;
+ }
+
+}
+
+//Blend, int
+void pngwriter::drawtop_blend(long x1,long y1,long x2,long y2,long x3, double opacity, int red, int green, int blue)
+{
+ // This swaps x2 and x3
+ if(x2>x3)
+ {
+ x2^=x3;
+ x3^=x2;
+ x2^=x3;
+}
+
+ long posl = x1*256;
+ long posr = posl;
+
+ long cl=((x2-x1)*256)/(y2-y1);
+ long cr=((x3-x1)*256)/(y2-y1);
+
+ for(int y=y1; yline_blend(posl/256, y, posr/256, y, opacity, red, green, blue);
+ posl+=cl;
+ posr+=cr;
+ }
+
+}
+
+void pngwriter::triangle(int x1, int y1, int x2, int y2, int x3, int y3, int red, int green, int blue)
+{
+ this->line(x1, y1, x2, y2, red, green, blue);
+ this->line(x2, y2, x3, y3, red, green, blue);
+ this->line(x3, y3, x1, y1, red, green, blue);
+}
+
+void pngwriter::triangle(int x1, int y1, int x2, int y2, int x3, int y3, double red, double green, double blue)
+{
+
+ this->line(x1, y1, x2, y2, ((int)65535*red), ((int)65535*green), ((int)65535*blue));
+ this->line(x2, y2, x3, y3, ((int)65535*red), ((int)65535*green), ((int)65535*blue));
+ this->line(x3, y3, x1, y1, ((int)65535*red), ((int)65535*green), ((int)65535*blue));
+
+}
+
+
+
+
+
+void pngwriter::arrow( int x1,int y1,int x2,int y2,int size, double head_angle, double red, double green, double blue)
+{
+
+ this->line(x1, y1, x2, y2, red, green, blue);
+ // double th = 3.141592653589793 + (head_angle)*3.141592653589793/180.0; //degrees
+ double th = 3.141592653589793 + head_angle;
+ double costh = cos(th);
+ double sinth = sin(th);
+ double t1, t2, r;
+ t1 = ((x2-x1)*costh - (y2-y1)*sinth);
+ t2 = ((x2-x1)*sinth + (y2-y1)*costh);
+ r = sqrt(t1*t1 + t2*t2);
+
+ double advancex = size*t1/r;
+ double advancey = size*t2/r;
+ this->line(x2, y2, int(x2 + advancex), int(y2 + advancey), red, green, blue);
+ t1 = (x2-x1)*costh + (y2-y1)*sinth;
+ t2 = (y2-y1)*costh - (x2-x1)*sinth;
+
+ advancex = size*t1/r;
+ advancey = size*t2/r;
+ this->line(x2, y2, int(x2 + advancex), int(y2 + advancey), red, green, blue);
+}
+
+void pngwriter::filledarrow( int x1,int y1,int x2,int y2,int size, double head_angle, double red, double green, double blue)
+{
+ int p1x, p2x, p3x, p1y, p2y, p3y;
+
+ this->line(x1, y1, x2, y2, red, green, blue);
+ double th = 3.141592653589793 + head_angle;
+ double costh = cos(th);
+ double sinth = sin(th);
+ double t11, t12, t21, t22, r1, r2;
+ t11 = ((x2-x1)*costh - (y2-y1)*sinth);
+ t21 = ((x2-x1)*sinth + (y2-y1)*costh);
+ t12 = (x2-x1)*costh + (y2-y1)*sinth;
+ t22 = (y2-y1)*costh - (x2-x1)*sinth;
+
+ r1 = sqrt(t11*t11 + t21*t21);
+ r2 = sqrt(t12*t12 + t22*t22);
+
+ double advancex1 = size*t11/r1;
+ double advancey1 = size*t21/r1;
+ double advancex2 = size*t12/r2;
+ double advancey2 = size*t22/r2;
+
+ p1x = x2;
+ p1y = y2;
+
+ p2x = int(x2 + advancex1);
+ p2y = int(y2 + advancey1);
+
+ p3x = int(x2 + advancex2);
+ p3y = int(y2 + advancey2);
+
+
+ this->filledtriangle( p1x, p1y, p2x, p2y, p3x, p3y, red, green, blue);
+
+}
+
+void pngwriter::arrow( int x1,int y1,int x2,int y2,int size, double head_angle, int red, int green, int blue)
+{
+ this->arrow( x1, y1, x2, y2, size, head_angle, (double (red))/65535.0, (double (green))/65535.0, (double (blue))/65535.0 );
+}
+
+void pngwriter::filledarrow( int x1,int y1,int x2,int y2,int size, double head_angle, int red, int green, int blue)
+{
+ this->filledarrow( x1, y1, x2, y2, size, head_angle, (double (red))/65535.0, (double (green))/65535.0, (double (blue))/65535.0 );
+}
+
+
+void pngwriter::cross( int x, int y, int xwidth, int yheight, int red, int green, int blue)
+{
+ this->line(int(x - xwidth/2.0), y, int(x + xwidth/2.0), y, red, green, blue);
+ this->line(x, int(y - yheight/2.0), x, int(y + yheight/2.0), red, green, blue);
+}
+
+void pngwriter::maltesecross( int x, int y, int xwidth, int yheight, int x_bar_height, int y_bar_width, int red, int green, int blue)
+{
+ this->line(int(x - xwidth/2.0), y, int(x + xwidth/2.0), y, red, green, blue);
+ this->line(x, int(y - yheight/2.0), x, int(y + yheight/2.0), red, green, blue);
+ // Bars on ends of vertical line
+ this->line(int(x - y_bar_width/2.0), int(y + yheight/2.0), int(x + y_bar_width/2.0), int(y + yheight/2.0), red, green, blue);
+ this->line(int(x - y_bar_width/2.0), int(y - yheight/2.0), int(x + y_bar_width/2.0), int(y - yheight/2.0), red, green, blue);
+ // Bars on ends of horizontal line.
+ this->line(int(x - xwidth/2.0), int(y - x_bar_height/2.0), int(x - xwidth/2.0), int(y + x_bar_height/2.0), red, green, blue);
+ this->line(int(x + xwidth/2.0), int(y - x_bar_height/2.0), int(x + xwidth/2.0), int(y + x_bar_height/2.0), red, green, blue);
+}
+
+void pngwriter::cross( int x, int y, int xwidth, int yheight, double red, double green, double blue)
+{
+ this->cross( x, y, xwidth, yheight, int(65535*red), int(65535*green), int(65535*blue));
+}
+
+void pngwriter::maltesecross( int x, int y, int xwidth, int yheight, int x_bar_height, int y_bar_width, double red, double green, double blue)
+{
+ this->maltesecross( x, y, xwidth, yheight, x_bar_height, y_bar_width, int(65535*red), int(65535*green), int(65535*blue));
+}
+
+
+void pngwriter::filleddiamond( int x, int y, int width, int height, int red, int green, int blue)
+{
+ this->filledtriangle( int(x - width/2.0), y, x, y, x, int(y + height/2.0), red, green, blue);
+ this->filledtriangle( int(x + width/2.0), y, x, y, x, int(y + height/2.0), red, green, blue);
+ this->filledtriangle( int(x - width/2.0), y, x, y, x, int(y - height/2.0), red, green, blue);
+ this->filledtriangle( int(x + width/2.0), y, x, y, x, int(y - height/2.0), red, green, blue);
+}
+
+void pngwriter::diamond( int x, int y, int width, int height, int red, int green, int blue)
+{
+ this->line( int(x - width/2.0), y, x, int(y + height/2.0), red, green, blue);
+ this->line( int(x + width/2.0), y, x, int(y + height/2.0), red, green, blue);
+ this->line( int(x - width/2.0), y, x, int(y - height/2.0), red, green, blue);
+ this->line( int(x + width/2.0), y, x, int(y - height/2.0), red, green, blue);
+}
+
+
+void pngwriter::filleddiamond( int x, int y, int width, int height, double red, double green, double blue)
+{
+ this->filleddiamond( x, y, width, height, int(red*65535), int(green*65535), int(blue*65535) );
+}
+
+void pngwriter::diamond( int x, int y, int width, int height, double red, double green, double blue)
+{
+ this->diamond( x, y, width, height, int(red*65535), int(green*65535), int(blue*65535) );
+}
+
diff --git a/pngwriter/pngwriter.h b/pngwriter/pngwriter.h
new file mode 100644
index 0000000..9a2269b
--- /dev/null
+++ b/pngwriter/pngwriter.h
@@ -0,0 +1,747 @@
+//********** pngwriter.h **********************************************
+// Author: Paul Blackburn
+//
+// Email: individual61@users.sourceforge.net
+//
+// Version: 0.5.4 (19 / II / 2009)
+//
+// Description: Library that allows plotting a 48 bit
+// PNG image pixel by pixel, which can
+// then be opened with a graphics program.
+//
+// License: GNU General Public License
+// Copyright 2002, 2003, 2004, 2005, 2006, 2007,
+// 2008, 2009 Paul Blackburn
+//
+// Website: Main: http://pngwriter.sourceforge.net/
+// Sourceforge.net: http://sourceforge.net/projects/pngwriter/
+// Freshmeat.net: http://freshmeat.net/projects/pngwriter/
+//
+// Documentation: This header file is commented, but for a
+// quick reference document, and support,
+// take a look at the website.
+//
+//*************************************************************************
+
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * */
+
+#ifndef PNGWRITER_H
+#define PNGWRITER_H 1
+
+#define PNGWRITER_VERSION 0.54
+
+#define NO_FREETYPE
+
+#include
+
+// REMEMBER TO ADD -DNO_FREETYPE TO YOUR COMPILATION FLAGS IF PNGwriter WAS
+// COMPILED WITHOUT FREETYPE SUPPORT!!!
+//
+// RECUERDA AGREGAR -DNO_FREETYPE A TUS OPCIONES DE COMPILACION SI PNGwriter
+// FUE COMPILADO SIN SOPORTE PARA FREETYPE!!!
+//
+#ifndef NO_FREETYPE
+#include
+#include FT_FREETYPE_H
+#endif
+
+
+
+#ifdef OLD_CPP // For compatibility with older compilers.
+#include
+#include
+#include
+#include
+using namespace std;
+#endif // from ifdef OLD_CPP
+
+#ifndef OLD_CPP // Default situation.
+#include
+#include
+#include
+#include
+#endif // from ifndef OLD_CPP
+
+
+//png.h must be included before FreeType headers.
+#include
+#include
+#include
+
+
+
+
+#define PNG_BYTES_TO_CHECK (4)
+#define PNGWRITER_DEFAULT_COMPRESSION (6)
+
+class pngwriter
+{
+ private:
+
+ char * filename_;
+ char * textauthor_;
+ char * textdescription_;
+ char * texttitle_;
+ char * textsoftware_;
+
+
+
+ int height_;
+ int width_;
+ int backgroundcolour_;
+ int bit_depth_;
+ int rowbytes_;
+ int colortype_;
+ int compressionlevel_;
+ bool transformation_; // Required by Mikkel's patch
+
+ unsigned char * * graph_;
+ double filegamma_;
+ double screengamma_;
+ void circle_aux(int xcentre, int ycentre, int x, int y, int red, int green, int blue);
+ void circle_aux_blend(int xcentre, int ycentre, int x, int y, double opacity, int red, int green, int blue);
+ int check_if_png(char *file_name, FILE **fp);
+ int read_png_info(FILE *fp, png_structp *png_ptr, png_infop *info_ptr);
+ int read_png_image(FILE *fp, png_structp png_ptr, png_infop info_ptr,
+ png_bytepp *image, png_uint_32 *width, png_uint_32 *height);
+ void flood_fill_internal( int xstart, int ystart, double start_red, double start_green, double start_blue, double fill_red, double fill_green, double fill_blue);
+ void flood_fill_internal_blend( int xstart, int ystart, double opacity, double start_red, double start_green, double start_blue, double fill_red, double fill_green, double fill_blue);
+
+#ifndef NO_FREETYPE
+ void my_draw_bitmap( FT_Bitmap * bitmap, int x, int y, double red, double green, double blue);
+ void my_draw_bitmap_blend( FT_Bitmap * bitmap, int x, int y,double opacity, double red, double green, double blue);
+#endif
+
+ /* The algorithms HSVtoRGB and RGBtoHSV were found at http://www.cs.rit.edu/~ncs/
+ * which is a page that belongs to Nan C. Schaller, though
+ * these algorithms appear to be the work of Eugene Vishnevsky.
+ * */
+ void HSVtoRGB( double *r, double *g, double *b, double h, double s, double v );
+ void RGBtoHSV( float r, float g, float b, float *h, float *s, float *v );
+
+ /* drwatop(), drawbottom() and filledtriangle() were contributed by Gurkan Sengun
+ * ( , http://www.linuks.mine.nu/ )
+ * */
+ void drawtop(long x1,long y1,long x2,long y2,long x3, int red, int green, int blue);
+ void drawbottom(long x1,long y1,long x2,long x3,long y3, int red, int green, int blue);
+ void drawbottom_blend(long x1,long y1,long x2,long x3,long y3, double opacity, int red, int green, int blue);
+ void drawtop_blend(long x1,long y1,long x2,long y2,long x3, double opacity, int red, int green, int blue);
+
+ public:
+
+ /* General Notes
+ * It is important to remember that all functions that accept an argument of type "const char *" will also
+ * accept "char *", this is done so you can have a changing filename (to make many PNG images in series
+ * with a different name, for example), and to allow you to use string type objects which can be easily
+ * turned into const char * (if theString is an object of type string, then it can be used as a const char *
+ * by saying theString.c_str()).
+ * It is also important to remember that whenever a function has a colour coeffiecient as its argument,
+ * that argument can be either an int from 0 to 65535 or a double from 0.0 to 1.0.
+ * It is important to make sure that you are calling the function with the type that you want.
+ * Remember that 1 is an int, while 1.0 is a double, and will thus determine what version of the function
+ * will be used. Similarly, do not make the mistake of calling for example plot(x, y, 0.0, 0.0, 65535),
+ * because
+ * there is no plot(int, int, double, double, int).
+ * Also, please note that plot() and read() (and the functions that use them internally)
+ * are protected against entering, for example, a colour coefficient that is over 65535
+ * or over 1.0. Similarly, they are protected against negative coefficients. read() will return 0
+ * when called outside the image range. This is actually useful as zero-padding should you need it.
+ * */
+
+ /* Compilation
+ * A typical compilation would look like this:
+ *
+ * g++ my_program.cc -o my_program freetype-config --cflags \
+ * -I/usr/local/include -L/usr/local/lib -lpng -lpngwriter -lz -lfreetype
+ *
+ * If you did not compile PNGwriter with FreeType support, then remove the
+ * FreeType-related flags and add -DNO_FREETYPE above.
+ * */
+
+ /* Constructor
+ * The constructor requires the width and the height of the image, the background colour for the
+ * image and the filename of the file (a pointer or simple "myfile.png"). The background colour
+ * can only be initialized to a shade of grey (once the object has been created you can do whatever
+ * you want, though), because generally one wants either a white (65535 or 1.0) or a black (0 or 0.0)
+ * background to start with.
+ * The default constructor creates a PNGwriter instance that is 250x250, white background,
+ * and filename "out.png".
+ * Tip: The filename can be given as easily as:
+ * pngwriter mypng(300, 300, 0.0, "myfile.png");
+ * Tip: If you are going to create a PNGwriter instance for reading in a file that already exists,
+ * then width and height can be 1 pixel, and the size will be automatically adjusted once you use
+ * readfromfile().
+ * */
+ pngwriter();
+ pngwriter(const pngwriter &rhs);
+ pngwriter(int width, int height, int backgroundcolour, char * filename);
+ pngwriter(int width, int height, double backgroundcolour, char * filename);
+ pngwriter(int width, int height, int backgroundcolour, const char * filename);
+ pngwriter(int width, int height, double backgroundcolour, const char * filename);
+
+ /* Destructor
+ * */
+ ~pngwriter();
+
+ /* Assignment Operator
+ * */
+ pngwriter & operator = (const pngwriter & rhs);
+
+ /* Plot
+ * With this function a pixel at coordinates (x, y) can be set to the desired colour.
+ * The pixels are numbered starting from (1, 1) and go to (width, height).
+ * As with most functions in PNGwriter, it has been overloaded to accept either int arguments
+ * for the colour coefficients, or those of type double. If they are of type int,
+ * they go from 0 to 65535. If they are of type double, they go from 0.0 to 1.0.
+ * Tip: To plot using red, then specify plot(x, y, 1.0, 0.0, 0.0). To make pink,
+ * just add a constant value to all three coefficients, like this:
+ * plot(x, y, 1.0, 0.4, 0.4).
+ * Tip: If nothing is being plotted to your PNG file, make sure that you remember
+ * to close() the instance before your program is finished, and that the x and y position
+ * is actually within the bounds of your image. If either is not, then PNGwriter will
+ * not complain-- it is up to you to check for this!
+ * Tip: If you try to plot with a colour coefficient out of range, a maximum or minimum
+ * coefficient will be assumed, according to the given coefficient. For example, attempting
+ * to plot plot(x, y, 1.0,-0.2,3.7) will set the green coefficient to 0 and the red coefficient
+ * to 1.0.
+ * */
+ void plot(int x, int y, int red, int green, int blue);
+ void plot(int x, int y, double red, double green, double blue);
+
+ /* Plot HSV
+ * With this function a pixel at coordinates (x, y) can be set to the desired colour,
+ * but with the colour coefficients given in the Hue, Saturation, Value colourspace.
+ * This has the advantage that one can determine the colour that will be plotted with
+ * only one parameter, the Hue. The colour coefficients must go from 0 to 65535 and
+ * be of type int, or be of type double and go from 0.0 to 1.0.
+ * */
+ void plotHSV(int x, int y, double hue, double saturation, double value);
+ void plotHSV(int x, int y, int hue, int saturation, int value);
+
+ /* Read
+ * With this function we find out what colour the pixel (x, y) is. If "colour" is 1,
+ * it will return the red coefficient, if it is set to 2, the green one, and if
+ * it set to 3, the blue colour coefficient will be returned,
+ * and this returned value will be of type int and be between 0 and 65535.
+ * Note that if you call read() on a pixel outside the image range, the value returned
+ * will be 0.
+ * */
+ int read(int x, int y, int colour);
+
+ /* Read, Average
+ * Same as the above, only that the average of the three colour coefficients is returned.
+ */
+ int read(int x, int y);
+
+ /* dRead
+ * With this function we find out what colour the pixel (x, y) is. If "colour" is 1,
+ * it will return the red coefficient, if it is set to 2, the green one, and if
+ * it set to 3, the blue colour coefficient will be returned,
+ * and this returned value will be of type double and be between 0.0 and 1.0.
+ * Note that if you call dread() outside the image range, the value returned will be 0.0
+ * */
+ double dread(int x, int y, int colour);
+
+ /* dRead, Average
+ * Same as the above, only that the average of the three colour coefficients is returned.
+ */
+ double dread(int x, int y);
+
+ /* Read HSV
+ * With this function we find out what colour the pixel (x, y) is, but in the Hue,
+ * Saturation, Value colourspace. If "colour" is 1,
+ * it will return the Hue coefficient, if it is set to 2, the Saturation one, and if
+ * it set to 3, the Value colour coefficient will be returned, and this returned
+ * value will be of type int and be between 0 and 65535. Important: If you attempt
+ * to read the Hue of a pixel that is a shade of grey, the value returned will be
+ * nonsensical or even NaN. This is just the way the RGB -> HSV algorithm works:
+ * the Hue of grey is not defined. You might want to check whether the pixel
+ * you are reading is grey before attempting a readHSV().
+ * Tip: This is especially useful for categorizing sections of the image according
+ * to their colour.
+ * */
+ int readHSV(int x, int y, int colour);
+
+ /* dRead HSV
+ * With this function we find out what colour the pixel (x, y) is, but in the Hue,
+ * Saturation, Value colourspace. If "colour" is 1,
+ * it will return the Hue coefficient, if it is set to 2, the Saturation one, and if
+ * it set to 3, the Value colour coefficient will be returned,
+ * and this returned value will be of type double and be between 0.0 and 1.0.
+ * */
+ double dreadHSV(int x, int y, int colour);
+
+ /* Clear
+ * The whole image is set to black.
+ * */
+ void clear(void);
+
+ /* Close
+ * Close the instance of the class, and write the image to disk.
+ * Tip: If you do not call this function before your program ends, no image
+ * will be written to disk.
+ * */
+ void close(void);
+
+ /* Rename
+ * To rename the file once an instance of pngwriter has been created.
+ * Useful for assigning names to files based upon their content.
+ * Tip: This is as easy as calling pngwriter_rename("newname.png")
+ * If the argument is a long unsigned int, for example 77, the filename will be changed to
+ * 0000000077.png
+ * Tip: Use this to create sequences of images for movie generation.
+ * */
+ void pngwriter_rename(char * newname);
+ void pngwriter_rename(const char * newname);
+ void pngwriter_rename(long unsigned int index);
+
+ /* Figures
+ * These functions draw basic shapes. Available in both int and double versions.
+ * The line functions use the fast Bresenham algorithm. Despite the name,
+ * the square functions draw rectangles. The circle functions use a fast
+ * integer math algorithm. The filled circle functions make use of sqrt().
+ * */
+ void line(int xfrom, int yfrom, int xto, int yto, int red, int green,int blue);
+ void line(int xfrom, int yfrom, int xto, int yto, double red, double green,double blue);
+
+ void triangle(int x1, int y1, int x2, int y2, int x3, int y3, int red, int green, int blue);
+ void triangle(int x1, int y1, int x2, int y2, int x3, int y3, double red, double green, double blue);
+
+ void square(int xfrom, int yfrom, int xto, int yto, int red, int green,int blue);
+ void square(int xfrom, int yfrom, int xto, int yto, double red, double green,double blue);
+
+ void filledsquare(int xfrom, int yfrom, int xto, int yto, int red, int green,int blue);
+ void filledsquare(int xfrom, int yfrom, int xto, int yto, double red, double green,double blue);
+
+ void circle(int xcentre, int ycentre, int radius, int red, int green, int blue);
+ void circle(int xcentre, int ycentre, int radius, double red, double green, double blue);
+
+ void filledcircle(int xcentre, int ycentre, int radius, int red, int green, int blue);
+ void filledcircle(int xcentre, int ycentre, int radius, double red, double green, double blue);
+
+
+ /* Read From File
+ * Open the existing PNG image, and copy it into this instance of the class. It is important to mention
+ * that PNG variants are supported. Very generally speaking, most PNG files can now be read (as of version 0.5.4),
+ * but if they have an alpha channel it will be completely stripped. If the PNG file uses GIF-style transparency
+ * (where one colour is chosen to be transparent), PNGwriter will not read the image properly, but will not
+ * complain. Also, if any ancillary chunks are included in the PNG file (chroma, filter, etc.), it will render
+ * with a slightly different tonality. For the vast majority of PNGs, this should not be an issue. Note:
+ * If you read an 8-bit PNG, the internal representation of that instance of PNGwriter will be 8-bit (PNG
+ * files of less than 8 bits will be upscaled to 8 bits). To convert it to 16-bit, just loop over all pixels,
+ * reading them into a new instance of PNGwriter. New instances of PNGwriter are 16-bit by default.
+ * */
+
+ void readfromfile(char * name);
+ void readfromfile(const char * name);
+
+ /* Get Height
+ * When you open a PNG with readfromfile() you can find out its height with this function.
+ * */
+ int getheight(void);
+
+ /* Get Width
+ * When you open a PNG with readfromfile() you can find out its width with this function.
+ * */
+ int getwidth(void);
+
+ /* Set Compression Level
+ * Set the compression level that will be used for the image. -1 is to use the default,
+ * 0 is none, 9 is best compression.
+ * Remember that this will affect how long it will take to close() the image. A value of 2 or 3
+ * is good enough for regular use, but for storage or transmission you might want to take the time
+ * to set it at 9.
+ * */
+ void setcompressionlevel(int level);
+
+ /* Get Bit Depth
+ * When you open a PNG with readfromfile() you can find out its bit depth with this function.
+ * Mostly for troubleshooting uses.
+ * */
+ int getbitdepth(void);
+
+ /* Get Colour Type
+ * When you open a PNG with readfromfile() you can find out its colour type (libpng categorizes
+ * different styles of image data with this number).
+ * Mostly for troubleshooting uses.
+ * */
+ int getcolortype(void);
+
+ /* Set Gamma Coeff
+ * Set the image's gamma (file gamma) coefficient. This is experimental, but use it if your image's colours seem too bright
+ * or too dark. The default value of 0.5 should be fine. The standard disclaimer about Mac and PC gamma
+ * settings applies.
+ * */
+ void setgamma(double gamma);
+
+
+ /* Get Gamma Coeff
+ * Get the image's gamma coefficient. This is experimental.
+ * */
+ double getgamma(void);
+
+ /* Bezier Curve
+ * (After Frenchman Pierre Bˇzier from Regie Renault)
+ * A collection of formulae for describing curved lines
+ * and surfaces, first used in 1972 to model automobile surfaces.
+ * (from the The Free On-line Dictionary of Computing)
+ * See http://www.moshplant.com/direct-or/bezier/ for one of many
+ * available descriptions of bezier curves.
+ * There are four points used to define the curve: the two endpoints
+ * of the curve are called the anchor points, while the other points,
+ * which define the actual curvature, are called handles or control points.
+ * Moving the handles lets you modify the shape of the curve.
+ * */
+
+ void bezier( int startPtX, int startPtY,
+ int startControlX, int startControlY,
+ int endPtX, int endPtY,
+ int endControlX, int endControlY,
+ double red, double green, double blue);
+
+ void bezier( int startPtX, int startPtY,
+ int startControlX, int startControlY,
+ int endPtX, int endPtY,
+ int endControlX, int endControlY,
+ int red, int green, int blue);
+
+ /* Set Text
+ * Sets the text information in the PNG header. If it is not called, the default is used.
+ */
+ void settext(char * title, char * author, char * description, char * software);
+ void settext(const char * title, const char * author, const char * description, const char * software);
+
+
+ /* Version Number
+ * Returns the PNGwriter version number.
+ */
+ static double version(void);
+
+ /* Write PNG
+ * Writes the PNG image to disk. You can still change the PNGwriter instance after this.
+ * Tip: This is exactly the same as close(), but easier to remember.
+ * Tip: To make a sequence of images using only one instance of PNGwriter, alter the image, change its name,
+ * write_png(), then alter the image, change its name, write_png(), etc.
+ */
+ void write_png(void);
+
+ /* Plot Text
+ * Uses the Freetype2 library to set text in the image. face_path is the file path to a
+ * TrueType font file (.ttf) (FreeType2 can also handle other types). fontsize specifices the approximate
+ * height of the rendered font in pixels. x_start and y_start specify the placement of the
+ * lower, left corner of the text string. angle is the text angle in radians. text is the text to be rendered.
+ * The colour coordinates can be doubles from 0.0 to 1.0 or ints from 0 to 65535.
+ * Tip: PNGwriter installs a few fonts in /usr/local/share/pngwriter/fonts to get you started.
+ * Tip: Remember to add -DNO_FREETYPE to your compilation flags if PNGwriter was compiled without FreeType support.
+ * */
+ void plot_text(char * face_path, int fontsize, int x_start, int y_start, double angle, char * text, double red, double green, double blue);
+ void plot_text(char * face_path, int fontsize, int x_start, int y_start, double angle, char * text, int red, int green, int blue);
+
+
+ /* Plot UTF-8 Text
+ * Same as the above, but the text to be plotted is encoded in UTF-8. Why would you want this? To be able to plot
+ * all characters available in a large TrueType font, for example: for rendering Japenese, Chinese and other
+ * languages not restricted to the standard 128 character ASCII space.
+ * Tip: The quickest way to get a string into UTF-8 is to write it in an adequate text editor, and save it as a file
+ * in UTF-8 encoding, which can then be read in in binary mode.
+ * */
+ void plot_text_utf8(char * face_path, int fontsize, int x_start, int y_start, double angle, char * text, double red, double green, double blue);
+ void plot_text_utf8(char * face_path, int fontsize, int x_start, int y_start, double angle, char * text, int red, int green, int blue);
+
+
+ /* Bilinear Interpolation of Image
+ * Given a floating point coordinate (x from 0.0 to width, y from 0.0 to height),
+ * this function will return the interpolated colour intensity specified by
+ * colour (where red = 1, green = 2, blue = 3).
+ * bilinear_interpolate_read() returns an int from 0 to 65535, and
+ * bilinear_interpolate_dread() returns a double from 0.0 to 1.0.
+ * Tip: Especially useful for enlarging an image.
+ * */
+ int bilinear_interpolation_read(double x, double y, int colour);
+ double bilinear_interpolation_dread(double x, double y, int colour);
+
+ /* Plot Blend
+ * Plots the colour given by red, green blue, but blended with the existing pixel
+ * value at that position. opacity is a double that goes from 0.0 to 1.0.
+ * 0.0 will not change the pixel at all, and 1.0 will plot the given colour.
+ * Anything in between will be a blend of both pixel levels. Please note: This is neither
+ * alpha channel nor PNG transparency chunk support. This merely blends the plotted pixels.
+ * */
+
+ void plot_blend(int x, int y, double opacity, int red, int green, int blue);
+ void plot_blend(int x, int y, double opacity, double red, double green, double blue);
+
+
+ /* Invert
+ * Inverts the image in RGB colourspace.
+ * */
+ void invert(void);
+
+ /* Resize Image
+ * Resizes the PNGwriter instance. Note: All image data is set to black (this is
+ * a resizing, not a scaling, of the image).
+ * */
+ void resize(int width, int height);
+
+ /* Boundary Fill
+ * All pixels adjacent to the start pixel will be filled with the fill colour, until the boundary colour is encountered.
+ * For example, calling boundary_fill() with the boundary colour set to red, on a pixel somewhere inside a red circle,
+ * will fill the entire circle with the desired fill colour. If, on the other hand, the circle is not the boundary colour,
+ * the rest of the image will be filled.
+ * The colour components are either doubles from 0.0 to 1.0 or ints from 0 to 65535.
+ * */
+ void boundary_fill(int xstart, int ystart, double boundary_red,double boundary_green,double boundary_blue,double fill_red, double fill_green, double fill_blue) ;
+ void boundary_fill(int xstart, int ystart, int boundary_red,int boundary_green,int boundary_blue,int fill_red, int fill_green, int fill_blue) ;
+
+ /* Flood Fill
+ * All pixels adjacent to the start pixel will be filled with the fill colour, if they are the same colour as the
+ * start pixel. For example, calling flood_fill() somewhere in the interior of a solid blue rectangle will colour
+ * the entire rectangle the fill colour. The colour components are either doubles from 0.0 to 1.0 or ints from 0 to 65535.
+ * */
+ void flood_fill(int xstart, int ystart, double fill_red, double fill_green, double fill_blue) ;
+ void flood_fill(int xstart, int ystart, int fill_red, int fill_green, int fill_blue) ;
+
+ /* Polygon
+ * This function takes an array of integer values containing the coordinates of the vertexes of a polygon.
+ * Note that if you want a closed polygon, you must repeat the first point's coordinates for the last point.
+ * It also requires the number of points contained in the array. For example, if you wish to plot a triangle,
+ * the array will contain 6 elements, and the number of points is 3. Be very careful about this; if you specify the wrong number
+ * of points, your program will either segfault or produce points at nonsensical coordinates.
+ * The colour components are either doubles from 0.0 to 1.0 or ints from 0 to 65535.
+ * */
+ void polygon(int * points, int number_of_points, double red, double green, double blue);
+ void polygon(int * points, int number_of_points, int red, int green, int blue);
+
+ /* Plot CMYK
+ * Plot a point in the Cyan, Magenta, Yellow, Black colourspace. Please note that this colourspace is
+ * lossy, i.e. it cannot reproduce all colours on screen that RGB can. The difference, however, is
+ * barely noticeable. The algorithm used is a standard one. The colour components are either
+ * doubles from 0.0 to 1.0 or ints from 0 to 65535.
+ * */
+ void plotCMYK(int x, int y, double cyan, double magenta, double yellow, double black);
+ void plotCMYK(int x, int y, int cyan, int magenta, int yellow, int black);
+
+ /* Read CMYK, Double version
+ * Get a pixel in the Cyan, Magenta, Yellow, Black colourspace. if 'colour' is 1, the Cyan component will be returned
+ * as a double from 0.0 to 1.0. If 'colour is 2, the Magenta colour component will be returned, and so on, up to 4.
+ * */
+ double dreadCMYK(int x, int y, int colour);
+
+ /* Read CMYK
+ * Same as the above, but the colour components returned are an int from 0 to 65535.
+ * */
+ int readCMYK(int x, int y, int colour);
+
+ /* Scale Proportional
+ * Scale the image using bilinear interpolation. If k is greater than 1.0, the image will be enlarged.
+ * If k is less than 1.0, the image will be shrunk. Negative or null values of k are not allowed.
+ * The image will be resized and the previous content will be replaced by the scaled image.
+ * Tip: use getheight() and getwidth() to find out the new width and height of the scaled image.
+ * Note: After scaling, all images will have a bit depth of 16, even if the original image had
+ * a bit depth of 8.
+ * */
+ void scale_k(double k);
+
+ /* Scale Non-Proportional
+ * Scale the image using bilinear interpolation, with different horizontal and vertical scale factors.
+ * */
+ void scale_kxky(double kx, double ky);
+
+ /* Scale To Target Width and Height
+ * Scale the image in such a way as to meet the target width and height.
+ * Tip: if you want to keep the image proportional, scale_k() might be more appropriate.
+ * */
+ void scale_wh(int finalwidth, int finalheight);
+
+
+ /* Blended Functions
+ * All these functions are identical to their non-blended types. They take an extra argument, opacity, which is
+ * a double from 0.0 to 1.0 and represents how much of the original pixel value is retained when plotting the
+ * new pixel. In other words, if opacity is 0.7, then after plotting, the new pixel will be 30% of the
+ * original colour the pixel was, and 70% of the new colour, whatever that may be. As usual, each function
+ * is available in int or double versions. Please note: This is neither alpha channel nor PNG transparency chunk support. This merely blends the plotted pixels.
+ * */
+
+ // Start Blended Functions
+
+ void plotHSV_blend(int x, int y, double opacity, double hue, double saturation, double value);
+ void plotHSV_blend(int x, int y, double opacity, int hue, int saturation, int value);
+
+ void line_blend(int xfrom, int yfrom, int xto, int yto, double opacity, int red, int green,int blue);
+ void line_blend(int xfrom, int yfrom, int xto, int yto, double opacity, double red, double green,double blue);
+
+ void square_blend(int xfrom, int yfrom, int xto, int yto, double opacity, int red, int green,int blue);
+ void square_blend(int xfrom, int yfrom, int xto, int yto, double opacity, double red, double green,double blue);
+
+ void filledsquare_blend(int xfrom, int yfrom, int xto, int yto, double opacity, int red, int green,int blue);
+ void filledsquare_blend(int xfrom, int yfrom, int xto, int yto, double opacity, double red, double green,double blue);
+
+ void circle_blend(int xcentre, int ycentre, int radius, double opacity, int red, int green, int blue);
+ void circle_blend(int xcentre, int ycentre, int radius, double opacity, double red, double green, double blue);
+
+ void filledcircle_blend(int xcentre, int ycentre, int radius, double opacity, int red, int green, int blue);
+ void filledcircle_blend(int xcentre, int ycentre, int radius, double opacity, double red, double green, double blue);
+
+ void bezier_blend( int startPtX, int startPtY,
+ int startControlX, int startControlY,
+ int endPtX, int endPtY,
+ int endControlX, int endControlY,
+ double opacity,
+ double red, double green, double blue);
+
+ void bezier_blend( int startPtX, int startPtY,
+ int startControlX, int startControlY,
+ int endPtX, int endPtY,
+ int endControlX, int endControlY,
+ double opacity,
+ int red, int green, int blue);
+
+ void plot_text_blend(char * face_path, int fontsize, int x_start, int y_start, double angle, char * text, double opacity, double red, double green, double blue);
+ void plot_text_blend(char * face_path, int fontsize, int x_start, int y_start, double angle, char * text, double opacity, int red, int green, int blue);
+
+ void plot_text_utf8_blend(char * face_path, int fontsize, int x_start, int y_start, double angle, char * text, double opacity, double red, double green, double blue);
+ void plot_text_utf8_blend(char * face_path, int fontsize, int x_start, int y_start, double angle, char * text, double opacity, int red, int green, int blue);
+
+ void boundary_fill_blend(int xstart, int ystart, double opacity, double boundary_red,double boundary_green,double boundary_blue,double fill_red, double fill_green, double fill_blue) ;
+ void boundary_fill_blend(int xstart, int ystart, double opacity, int boundary_red,int boundary_green,int boundary_blue,int fill_red, int fill_green, int fill_blue) ;
+
+ void flood_fill_blend(int xstart, int ystart, double opacity, double fill_red, double fill_green, double fill_blue) ;
+ void flood_fill_blend(int xstart, int ystart, double opacity, int fill_red, int fill_green, int fill_blue) ;
+
+ void polygon_blend(int * points, int number_of_points, double opacity, double red, double green, double blue);
+ void polygon_blend(int * points, int number_of_points, double opacity, int red, int green, int blue);
+
+ void plotCMYK_blend(int x, int y, double opacity, double cyan, double magenta, double yellow, double black);
+ void plotCMYK_blend(int x, int y, double opacity, int cyan, int magenta, int yellow, int black);
+
+ // End of Blended Functions
+
+ /* Laplacian
+ * This function applies a discrete laplacian to the image, multiplied by a constant factor.
+ * The kernel used in this case is:
+ * 1.0 1.0 1.0
+ * 1.0 -8.0 1.0
+ * 1.0 1.0 1.0
+ * Basically, this works as an edge detector. The current pixel is assigned the sum of all neighbouring
+ * pixels, multiplied by the corresponding kernel element. For example, imagine a pixel and its 8 neighbours:
+ * 1.0 1.0 0.0 0.0
+ * 1.0 ->1.0<- 0.0 0.0
+ * 1.0 1.0 0.0 0.0
+ * This represents a border between white and black, black is on the right. Applying the laplacian to
+ * the pixel specified above pixel gives:
+ * 1.0*1.0 + 1.0*1.0 + 0.0*1.0 +
+ * 1.0*1.0 + 1.0*-8.0 + 0.0*1.0 +
+ * 1.0*1.0 + 1.0*1.0 + 0.0*1.0 = -3.0
+ * Applying this to the pixel to the right of the pixel considered previously, we get a sum of 3.0.
+ * That is, after passing over an edge, we get a high value for the pixel adjacent to the edge. Since
+ * PNGwriter limits the colour components if they are off-scale, and the result of the laplacian
+ * may be negative, a scale factor and an offset value are included. This might be useful for
+ * keeping things within range or for bringing out more detail in the edge detection. The
+ * final pixel value will be given by:
+ * final value = laplacian(original pixel)*k + offset
+ * Tip: Try a value of 1.0 for k to start with, and then experiment with other values.
+ * */
+ void laplacian(double k, double offset);
+
+ /* Filled Triangle
+ * Draws the triangle specified by the three pairs of points in the colour specified
+ * by the colour coefficients. The colour components are either doubles from 0.0 to
+ * 1.0 or ints from 0 to 65535.
+ * */
+ void filledtriangle(int x1,int y1,int x2,int y2,int x3,int y3, int red, int green, int blue);
+ void filledtriangle(int x1,int y1,int x2,int y2,int x3,int y3, double red, double green, double blue);
+
+ /* Filled Triangle, Blended
+ * Draws the triangle specified by the three pairs of points in the colour specified
+ * by the colour coefficients, and blended with the background. See the description for Blended Functions.
+ * The colour components are either doubles from 0.0 to 1.0 or ints from 0 to 65535.
+ * */
+ void filledtriangle_blend(int x1,int y1,int x2,int y2,int x3,int y3, double opacity, int red, int green, int blue);
+ void filledtriangle_blend(int x1,int y1,int x2,int y2,int x3,int y3, double opacity, double red, double green, double blue);
+
+ /* Arrow, Filled Arrow
+ * Plots an arrow from (x1, y1) to (x2, y2) with the arrowhead at the second point, given the size in pixels
+ * and the angle in radians of the arrowhead. The plotted arrow consists of one main line, and two smaller
+ * lines originating from the second point. Filled Arrow plots the same, but the arrowhead is a solid triangle.
+ * Tip: An angle of 10 to 30 degrees looks OK.
+ * */
+
+ void arrow( int x1,int y1,int x2,int y2,int size, double head_angle, double red, double green, double blue);
+ void arrow( int x1,int y1,int x2,int y2,int size, double head_angle, int red, int green, int blue);
+
+ void filledarrow( int x1,int y1,int x2,int y2,int size, double head_angle, double red, double green, double blue);
+ void filledarrow( int x1,int y1,int x2,int y2,int size, double head_angle, int red, int green, int blue);
+
+ /* Cross, Maltese Cross
+ * Plots a simple cross at x, y, with the specified height and width, and in the specified colour.
+ * Maltese cross plots a cross, as before, but adds bars at the end of each arm of the cross.
+ * The size of these bars is specified with x_bar_height and y_bar_width.
+ * The cross will look something like this:
+ *
+ * ----- <-- ( y_bar_width)
+ * |
+ * |
+ * |-------| <-- ( x_bar_height )
+ * |
+ * |
+ * -----
+ * */
+
+ void cross( int x, int y, int xwidth, int yheight, double red, double green, double blue);
+ void cross( int x, int y, int xwidth, int yheight, int red, int green, int blue);
+
+ void maltesecross( int x, int y, int xwidth, int yheight, int x_bar_height, int y_bar_width, double red, double green, double blue);
+ void maltesecross( int x, int y, int xwidth, int yheight, int x_bar_height, int y_bar_width, int red, int green, int blue);
+
+ /* Diamond and filled diamond
+ * Plots a diamond shape, given the x, y position, the width and height, and the colour.
+ * Filled diamond plots a filled diamond.
+ * */
+
+ void filleddiamond( int x, int y, int width, int height, int red, int green, int blue);
+ void diamond(int x, int y, int width, int height, int red, int green, int blue);
+
+ void filleddiamond( int x, int y, int width, int height, double red, double green, double blue);
+ void diamond(int x, int y, int width, int height, double red, double green, double blue);
+
+ /* Get Text Width, Get Text Width UTF8
+ * Returns the approximate width, in pixels, of the specified *unrotated* text. It is calculated by adding
+ * each letter's width and kerning value (as specified in the TTF file). Note that this will not
+ * give the position of the farthest pixel, but it will give a pretty good idea of what area the
+ * text will occupy. Tip: The text, when plotted unrotated, will fit approximately in a box with its lower left corner at
+ * (x_start, y_start) and upper right at (x_start + width, y_start + size), where width is given by get_text_width()
+ * and size is the specified size of the text to be plotted. Tip: Text plotted at position
+ * (x_start, y_start), rotated with a given 'angle', and of a given 'size'
+ * whose width is 'width', will fit approximately inside a rectangle whose corners are at
+ * 1 (x_start, y_start)
+ * 2 (x_start + width*cos(angle), y_start + width*sin(angle))
+ * 3 (x_start + width*cos(angle) - size*sin(angle), y_start + width*sin(angle) + size*cos(angle))
+ * 4 (x_start - size*sin(angle), y_start + size*cos(angle))
+ * */
+
+ int get_text_width(char * face_path, int fontsize, char * text);
+
+ int get_text_width_utf8(char * face_path, int fontsize, char * text);
+
+
+};
+
+
+#endif
+
diff --git a/quick.sh b/quick.sh
new file mode 100644
index 0000000..b0100af
--- /dev/null
+++ b/quick.sh
@@ -0,0 +1,2 @@
+./bin/Debug/AwesomeAttractor -a attr/quick.attr 15000000 canvas/quick.canv 600 600 3
+./bin/Debug/AwesomeAttractor -c canvas/quick.canv 600 600 3 quick.png
diff --git a/stfu/ExampleProgramOutput.stf b/stfu/ExampleProgramOutput.stf
new file mode 100644
index 0000000..d28131a
--- /dev/null
+++ b/stfu/ExampleProgramOutput.stf
@@ -0,0 +1,11 @@
+Screen options: {
+ Brightness: "1.5"
+ Contrast: "70.1"
+ heigth: "1200"
+ rendermode: "OpenGL"
+ width: "1920"
+}
+Sound options: {
+ max soundfx: "128"
+ outputmode: "5.1"
+}
diff --git a/stfu/LICENSE.txt b/stfu/LICENSE.txt
new file mode 100644
index 0000000..835cfb3
--- /dev/null
+++ b/stfu/LICENSE.txt
@@ -0,0 +1,28 @@
+Copyright (c) 2009 Maurice Bos and Nick Overdijk
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * The names of the authors may not be used to endorse or promote
+ products derived from this software without specific prior written
+ permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
+EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+- Maurice Bos (maurice@bosbyte.nl)
+- Nick Overdijk (nick@dotsimplicity.net)
+
diff --git a/stfu/STFU.cbp b/stfu/STFU.cbp
new file mode 100644
index 0000000..53de290
--- /dev/null
+++ b/stfu/STFU.cbp
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/stfu/STFU.depend b/stfu/STFU.depend
new file mode 100644
index 0000000..a22e8b9
--- /dev/null
+++ b/stfu/STFU.depend
@@ -0,0 +1,21 @@
+# depslib dependency file v1.0
+1241021944 source:/media/Data/Code/C/AwesomeAttractor/stfu/main.cpp
+
+
+ "stf.hpp"
+
+1241022258 /media/Data/Code/C/AwesomeAttractor/stfu/stf.hpp
+
+
+
+
+
+
Comments
+
+Don't want to have a very long descriptive name, but do want a bit of extra info? Comments (or anything really) can be place in between the name-terminator and the type-specifier.
+
+name: This text will be ignore by the parser "First value in the file."
+childnode: This text will too, be ignored {
+ value: You probably already guessed it
+
+ But this text will to be ignored. Anything here is allowed, except for a type-specifier of course! ;-)
+
+ "This is another value, inside a child node with the name ""childnode""."
+}
+
+
Getting more interesting
+
+This example shows what characters are allowed inside names and values.
+
+firstnode: {
+ subnode: {
+ blah: "xyz"
+ blah: "names of values/childs don't have to be unique!"
+ }
+}
+secondnode: {
+ name with space: "names can contain spaces"
+name
+with
+newlines: "names can contain newlines"
+ blah: "values can contain
+newlines too!"
+}
+
+
+
+NOTE: Take a look at the other .stf files included with this project for more examples.
+
+
+
STFU - Simple Tree Format Utility
+
+STFU is the first C++ implementation for STF.
+
+
+This example will show you some of the basic features of STFU:
+
+#include
+#include "stf.hpp"
+using namespace std;
+using stfu::node;
+
+int main(){
+ node n,f;
+ if (n.read("blah.stf")){ //could also do: 'if ("blah.stf" >> n){'
+ cout << n.value("test"); // Read a value
+
+ cout << n.child("subnode").value("hi",0); //Read the first value
+ cout << n.child("subnode").value("hi",1); //Read the second value
+
+ n.child("subnode").value("test") = "blah"; //Add a value
+
+ if (f.read("another_file.stf")){
+ n.child("secondnode") = f; //add a child
+ }
+
+ n.write("blah.stf"); //Write changes back to the file
+ // "blah.stf" << n; would also be valid.
+
+ cout << n; //output the file to the console instead of a file.
+
+ } else {
+ cout << "ERROR!" << endl;
+ }
+}
+//NOTE: For more detailed examples, please take a look at the 'main.cpp' file of this project.
+
+
+
+As you see, the .child() and .value() functions can be used to read, create and change values/childs. More advanced functions are available, 'main.cpp' contains examples to explain all of them.
+
+
+
+
+
+
+
+
diff --git a/stfu/soundoptions.stf b/stfu/soundoptions.stf
new file mode 100644
index 0000000..bfa4ba2
--- /dev/null
+++ b/stfu/soundoptions.stf
@@ -0,0 +1,9 @@
+
+max soundfx:
+ A value between 0 and 255
+ "128"
+
+outputmode:
+ Options are: 2.0, 4.0, 4.1, 5.1, 7.1 and 412.28
+ "5.1"
+
diff --git a/stfu/stf.cpp b/stfu/stf.cpp
new file mode 100644
index 0000000..4d1febd
--- /dev/null
+++ b/stfu/stf.cpp
@@ -0,0 +1,276 @@
+/*
+Copyright (c) 2009 Maurice Bos and Nick Overdijk
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * The names of the authors may not be used to endorse or promote
+ products derived from this software without specific prior written
+ permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
+EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+- Maurice Bos (maurice@bosbyte.nl)
+- Nick Overdijk (nick@dotsimplicity.net)
+
+*/
+
+#include
+#include
+#include
+#include
+#include
+
+#include "stf.hpp"
+
+using namespace std;
+using stfu::node;
+using stfu::child;
+using stfu::value;
+
+ostream &stfu::operator<< (ostream &out, const node &root) {
+ root.write(out);
+ return out;
+}
+
+bool stfu:: operator<< (const char *filename, const node &root){
+ return root.write(filename);
+}
+
+bool stfu::operator<< (ofstream &out, const node &root) {
+ return root.write(out);
+}
+
+bool stfu::operator>> (istream &in, node &root) {
+ return root.read(in);
+}
+
+bool stfu::operator>> (const char *filename, node &root) {
+ return root.read(filename);
+}
+
+const string &node::getValue(const string &name, size_t index) const throw (out_of_range) {
+ return get_indexed(values, name, index);
+}
+
+/*Function is const, but shouldn't be called on const objects since it returns a nonconst-reference to a member*/
+string &node::getValue(const string &name, size_t index) throw (out_of_range) {
+ return get_indexed(values, name, index);
+}
+
+string &node::addValue(const string &name) {
+ return values.insert(pair(name, string()))->second;
+}
+
+string &node::value(const string &name, size_t index) {
+ try {
+ return getValue(name, index);
+ } catch (out_of_range &e) {
+ //it doesn't exist: create it
+ return addValue(name);
+ }
+}
+
+void node::removeValue(const string &name, size_t index) throw (out_of_range) {
+ values.erase(get_indexed_it(values, name, index));
+ return;
+}
+
+void node::renameValue(const string &oldName, const string &newName, size_t index) {
+ addValue(newName) = value(oldName, index);
+ removeValue(oldName, index);
+}
+
+
+const node &node::getChild(const string &name, size_t index) const throw (out_of_range) {
+ return get_indexed(children, name, index);
+}
+
+node &node::getChild(const string &name, size_t index) throw (out_of_range) {
+ return get_indexed(children, name, index);
+}
+
+node &node::addChild(const string &name) {
+ return children.insert(pair(name, node()))->second;
+}
+
+node &node::addChild(const string &name, node &newNode) {
+ return children.insert(pair(name, newNode))->second;
+}
+
+node &node::child(const string &name, size_t index) {
+ //if there's no such child, add one
+ try {
+ return getChild(name, index);
+ } catch (out_of_range &e) {
+ //it doesn't exist: create it
+ return addChild(name);
+ }
+}
+
+void node::renameChild(const string &oldName, const string &newName, size_t index) {
+ node copy = child(oldName, index);
+ removeChild(oldName, index);
+ addChild(newName) = copy;
+}
+
+void node::removeChild(const string &name, size_t index) throw (out_of_range) {
+ children.erase(get_indexed_it(children, name, index));
+ return;
+}
+
+bool node::read(const char *filename) {
+ ifstream f(filename);
+
+ if (!f.good()) return false;
+
+ bool success = read(f);
+ f.close();
+
+ return success;
+}
+
+bool node::read(istream &in) {
+ while (1) {
+ in >> ws; //Skip whitespace
+
+ //if end of node is reached, return
+ if (in.peek() == '}') {
+ in.ignore();
+ return true;
+ }
+
+ if (in.eof()) {
+ return true; //End of the file is reached
+ }
+
+ string name;
+ char type; // '{' or '"'
+ streamRead(in, name, ':'); //Read name (all chars before ':')
+ type = streamSkip(in,"\"{"); //Skip everything until '{' or '"'
+
+ switch (type) {
+
+ //in case of value
+ case '"': {
+ string value;
+ while (1) {
+ if (streamRead(in, value, '"') == 0) { //Read to the closing-"
+ return false;
+ }
+ if (in.peek() == '"') {
+ in.ignore();
+ value += '"';
+ continue;
+ } else {
+ break;
+ }
+ }
+ this->values.insert(pair(name, value));
+ break;
+ }
+
+ //in case of child
+ case '{': {
+ node sub;
+ if (!sub.read(in)) { //Recursively read the subnode
+ return false;
+ }
+ this->children.insert(pair(name,sub));
+ break;
+ }
+
+ default:
+ return false;
+ }
+ }
+}
+
+/*Writes to a file using it's overloaded self*/
+bool node::write(const char *filename) const {
+ ofstream f(filename);
+
+ if (!f.good()) {
+ return false;
+ }
+
+ bool success = write(f);
+ f.close();
+
+ return success;
+}
+
+// TODO (Nick#1#): Make write() not put unnamed values on a new line, children are okay.
+bool node::write(ostream &out, size_t depth, string indent) const {
+ string indentation;
+ for (size_t i = 0; i < depth; i++) {
+ indentation += indent;
+ }
+
+ for (multimap::const_iterator value_it = values.begin(); value_it != values.end(); value_it++) {
+ //Escape all the '"' by adding a second '"'
+ string value(value_it->second);
+ size_t found = value.find('"');
+
+ //while there are more ", insert second "s
+ while (found != value.npos) {
+ value.insert(found, 1, '"');
+ found = value.find('"', found+2);
+ }
+ out << indentation << value_it->first << ": \"" << value << '"' << endl;
+ }
+
+ for (multimap::const_iterator child_it = children.begin(); child_it != children.end(); child_it++) {
+ out << indentation << child_it->first << ": {" << endl;
+ child_it->second.write(out, depth+1);
+ out << indentation << '}' << endl;
+ }
+
+ return true;
+}
+
+char node::streamSkip(istream &in, const string &delimiters) {
+ char cur;
+
+ //Return if the current char is part of delimiters[]
+ while (in >> noskipws >> cur) {
+ if (delimiters.find_first_of(cur) != delimiters.npos) return cur;
+ }
+ return 0;
+}
+
+char node::streamRead(istream &in, string &out, const string &delimiters) {
+ char cur;
+
+ //Return if the current char is part of delimiters[]
+ while (in >> noskipws >> cur) {
+ if (delimiters.find(cur) != delimiters.npos) return cur;
+ out += cur;
+ }
+ return 0;
+}
+
+char node::streamRead(istream &in, string &out, const char delimiter) {
+ char cur;
+
+ //Return if the current char is delimiter
+ while (in >> noskipws >> cur) {
+ if (delimiter == cur) return cur;
+ out += cur;
+ }
+ return 0;
+}
diff --git a/stfu/stf.hpp b/stfu/stf.hpp
new file mode 100644
index 0000000..8a25538
--- /dev/null
+++ b/stfu/stf.hpp
@@ -0,0 +1,358 @@
+/*
+Copyright (c) 2009 Maurice Bos and Nick Overdijk
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * The names of the authors may not be used to endorse or promote
+ products derived from this software without specific prior written
+ permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
+EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+- Maurice Bos (maurice@bosbyte.nl)
+- Nick Overdijk (nick@dotsimplicity.net)
+
+*/
+
+#include
+#include
+#include
+#include
+#include
+
+#ifndef STFU_HPP
+#define STFU_HPP
+
+namespace stfu {
+ using namespace std;
+ const static string not_found("search->No such child/value");
+
+ /*! \class node
+ * \brief A node in an STF tree.
+ * \author Maurice Bos
+ * \author Nick Overdijk
+ * \version 1.0
+ * \date 2009-04-25
+ *
+ * When you read an STF file through a node (with read() for example), this node will be the root node, without a name. See the examples for more information.
+ */
+ class node {
+
+ /** Overloaded ostream's operator<< */
+ friend ostream &operator<< (ostream &out, const node &root);
+
+ /** Returns whether it was succesful or not*/
+ friend bool operator<< (ofstream &out, const node &root);
+
+ /** Acts like write(), but looks like this: "filename" << node */
+ friend bool operator<< (const char *filename, const node &root);
+
+ /** Overloaded istream's operator>> */
+ friend bool operator>> (istream &in, node &root);
+
+ /** Acts like read(), but looks like this: "filename" >> node */
+ friend bool operator>> (const char *filename, node &root);
+
+ public:
+ //@{
+ /** The values and children belonging to this node. To add, remove, do whatever: you CAN use these variables directly. To use indexing, use the member functions below*/
+ multimap values;
+ multimap children;
+ //@}
+
+ /**
+ Clears the whole node recursively.
+ */
+ void clear() {
+ values.clear();
+ children.clear();
+ }
+ /**
+ Gets the string value from a variable
+ \param name The name of the value you wish to retrieve
+ \param index If there are more values with the same name, they are indexed. Here you can supply its indexnumber.
+ \return The retrieved value
+ */
+ string &value(const string &name, size_t index = 0);
+
+ /**
+ Same as value(), but for unnamed values
+ \note same as value("", index)
+ \param index If there are more unnamed values, they are indexed. Here you can supply its indexnumber.
\return Same as value
+ */
+ string &value(size_t index){
+ return value("", index);
+ }
+
+ /**
+ Creates and adds a value.
+ \param name The name of the value to be created
+ \return A reference to the value of the created value.
+ */
+ string &addValue(const string &name = "");
+
+ /**
+ Const function for const objects to get a value. It's NOT possible to call value() on constant objects for value() isn't const.
+ \param name Name of the value to be retrieved
+ \param index If there are > 1 values with the same name, they are indexed. Here you can supply an indexnumber.
+ \return Returns a const string& to the value of value with the name and index specified
+ */
+ const string &getValue(const string &name, size_t index) const throw (out_of_range);
+
+ /**
+ Same as getValue() const, but for unnamed values
+ \note same as getValue("", index) const
+ \param index If there are > 1 unnamed values, they are indexed. Here you can supply an indexnumber.
+ \return Returns a const string& to the value of value with the name and index specified
+ */
+ const string &getValue(size_t index) const throw (out_of_range){
+ return getValue("", index);
+ }
+
+ /**
+ Same as getValue() const, but for non-const objects. The returned string& can safely be modified.
+ \param name Name of the value to be retrieved
+ \param index If there are > 1 values with the same name, they are indexed. Here you can supply an indexnumber.
+ \return Returns a string& to the value of value with the name and index specified
+ */
+ string &getValue(const string &name, size_t index = 0) throw (out_of_range);
+
+ /**
+ Same as getValue(), but for unnamed values
+ \note same as getValue("", index)
+ \param index If there are > 1 unnamed values, they are indexed. Here you can supply an indexnumber.
+ \return Returns a string& to the value of value with the name and index specified
+ */
+ string &getValue(size_t index) throw (out_of_range){
+ return getValue("", index);
+ }
+
+ /**
+ Removes a value. Surprise huh?
+ \param name Name of the value to be removed
+ \param index If there are > 1 values with the same name, they are indexed. Here you can supply an indexnumber.
+ */
+ void removeValue(const string &name, size_t index = 0) throw (out_of_range);
+
+ /**
+ Removes an unnamed value.
+ \note same as removeValue("", index);
+ \param index If there are > 1 unnamed values, they are indexed. Here you can supply an indexnumber.
+ */
+ void removeValue(size_t index) throw (out_of_range){
+ removeValue("", index);
+ }
+
+ /**
+ Renames a value.
+ \param oldName Name of the value to be renamed
+ \param newName The name that the oldName-value should have
+ \param index If there are > 1 values with the same name, they are indexed. Here you can supply an indexnumber.
+ */
+ void renameValue(const string &oldName, const string &newName, size_t index = 0);
+
+ /**
+ Changes, adds or retrieves node
+ \param name The name of the child you wish to retrieve, change or add.
+ \param index If there are > 1 children with the same name, they are indexed. Here you can supply an indexnumber.
+ \return The retrieved node
+
+ If this index number is > the number of variables with that name, a new variable with that name is created with index = current number of same name variables + 1.
+ So say you have 4 variables named "tree", you call child("tree", 10), another tree gets made with index 5, NOT 10.
+ */
+ node &child(const string &name, size_t index = 0);
+
+ /**
+ Same as child(), but for unnamed children.
+ \note same as child("", index)
+ \param index If there are > 1 unnamed children, they are indexed. Here you can supply an indexnumber.
+ \return The retrieved node
+ */
+ node &child(size_t index = 0){
+ return child("", index);
+ }
+
+ /**
+ Guarranteed to add a child
+ \param name Name for the child
+ \return A reference to the created node
+ */
+ node &addChild(const string &name = "");
+
+ /**
+ As addChild(name), but copies data from newChild as well.
+ \param name Name for the child
+ \param newChild Data to copy from the child.
+ \return A reference to the created node
+ */
+ node &addChild(const string &name, node &newChild);
+
+ /**
+ As addChild(name, newChild), but without name, for unnamed children
+ \note same as addChild("", newChild);
+ \param newChild Data to copy from the child.
+ \return A reference to the created node
+ */
+ node &addChild(node &newChild){
+ return addChild("", newChild);
+ }
+
+ /**
+ Const function for const objects to get a node. It's NOT possible to call child() for this, for child() isn't const.
+ \param name Name of the child to be retrieved
+ \param index If there are > 1 children with the same name, they are indexed. Here you can supply an indexnumber.
+ \return Returns a const node& to the node with the name and index specified
+ */
+ const node &getChild(const string &name, size_t index = 0) const throw (out_of_range);
+
+ /**
+ Const function for const objects to get an unnamed const node&.
+ \note same as getChild("", index) const;
+ \param index If there are > 1 unnamed children, they are indexed. Here you can supply an indexnumber.
+ \return Returns a const node& to the node with the name and index specified
+ */
+ const node &getChild(size_t index = 0) const throw (out_of_range){
+ return getChild("", index);
+ }
+
+ /**
+ Same as getChild() const, but for non-const objects. The returned child & can be modified
+ \param name Name of the child to be retrieved
+ \param index If there are > 1 children with the same name, they are indexed. Here you can supply an indexnumber.
+ \return Returns a node& to the node with the name and index specified
+ */
+ node &getChild(const string &name, size_t index = 0) throw (out_of_range);
+
+ /**
+ Same as getChild() const, but for non-const objects.
+ \note same as getChild("", index);
+ \param index If there are > 1 unnamed children, they are indexed. Here you can supply an indexnumber.
+ \return Returns a node& to the node with the name and index specified
+ */
+ node &getChild(size_t index = 0) throw (out_of_range){
+ return getChild("", index);
+ }
+
+ /**
+ Removes a child. Surprise huh?
+ \param name Name of the child to be removed
+ \param index If there are > 1 children with the same name, they are indexed. Here you can supply an indexnumber.
+ */
+ void removeChild(const string &name, size_t index = 0) throw (out_of_range);
+
+ /**
+ As removeChild() for unnamed children.
+ \param index If there are > 1 unnamed children, they are indexed. Here you can supply an indexnumber.
+ */
+ void removeChild(size_t index = 0) throw (out_of_range){
+ removeChild("", index);
+ }
+
+ /**
+ Renames a child.
+ \param oldName Name of the child to be renamed
+ \param newName The name that the oldName-child should have
+ \param index If there are > 1 children with the same name, they are indexed. Here you can supply an indexnumber.
+ */
+ void renameChild(const string &oldName, const string &newName, size_t index = 0);
+
+
+ /**
+ Reads the STF from an istream
+
+ \return Returns whether it was succesful
+ */
+ bool read(istream &in);
+
+ /**
+ Reads the STF from a file
+
+ \return Returns whether it was succesful
+ */
+ bool read(const char *filename);
+
+ /**
+ Writes the STF to an ostream with optional indentation
+ \param out ostream to write to
+ \param depth how much indentation to start with
+ \param indent What string to use as indenation
+ \return Returns whether it was succesful
+ */
+ bool write(ostream &out, size_t depth = 0, string indent = "\t") const;
+
+ /**
+ Writes to a file. Simply first opens a file and passes that ostream to itself.
+ \param filename File to write to
+ \return Returns whether it was succesful
+ */
+ bool write(const char *filename) const;
+
+ private:
+ char streamRead(istream &in,string &out, const string &delim);
+ char streamRead(istream &in, string &out, const char delim);
+ char streamSkip(istream &in, const string &delim);
+
+ /*
+ returns a T2&, not a const T2&. The functions getValue/getChild make sure this will be done correctly for const objects
+ this function can NOT use get_indexed_it, because that function can't be const:
+ const_iterators can not be transformed into iterators, and the iterator is needed for erase(), which wants an iterator.
+ */
+ template
+ T2& get_indexed(const multimap &container, const T1 &key, size_t index = 0) const throw (out_of_range) {
+ size_t count = container.count(key);
+
+ if (count != 0 && count-1 >= index) {
+ typename multimap::const_iterator it = container.find(key);
+ while (index--) it++;
+ return const_cast(it->second);
+ } else {
+ throw out_of_range((string)"get_indexed->"+"Element " + key + "doesn't exist!");
+ }
+ }
+
+// template
+// typename multimap::iterator get_indexed_it(multimap &container, const T1 &key, size_t index = 0) throw (out_of_range) {
+// size_t count = container.count(key);
+//
+// if (count != 0 && count-1 >= index) {
+// typename multimap::iterator it = container.find(key);
+// while (index--) it++;
+// return it;
+// } else {
+// throw out_of_range((string)"get_indexed_it->"+"Element " + key + "doesn't exist!");
+// }
+// }
+
+ template
+ typename Container::iterator get_indexed_it(Container& container, const T& key, size_t index = 0)
+ throw (out_of_range) {
+ typename Container::iterator it = container.find(key);
+ while (index-- && it != container.end() && it->first==key) it++;
+ if (it == container.end()) throw out_of_range("get_indexed_it(Container&, const T&, size_t)");
+ return it;
+ }
+ };
+
+ typedef pair value;
+ typedef pair child;
+
+ typedef multimap::iterator valueiterator;
+ typedef multimap::iterator childiterator;
+}
+
+#endif // STFU_HPP
diff --git a/stfu/test.stf b/stfu/test.stf
new file mode 100644
index 0000000..be26df5
--- /dev/null
+++ b/stfu/test.stf
@@ -0,0 +1,4 @@
+imthefirst: "The first value inside root!"
+child: {
+ blah: "The value of [root].child.blah"
+}
\ No newline at end of file