The prototype of Zen Zoom. Made on ubuntu, I guess.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
This repo is archived. You can view files and clone it, but cannot push or open issues/pull-requests.
 
 
 
 

4328 lines
132 KiB

//********** 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];
should_free = true;
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; hhh<width_; hhh++) {
for(int vhhh = 0; vhhh<height_; vhhh++) {
//graph_[vhhh][6*hhh + i] where i goes from 0 to 5
tempindex = 6*hhh;
graph_[vhhh][tempindex] = (char) floor(((double)backgroundcolour_)/256);
graph_[vhhh][tempindex+1] = (char)(backgroundcolour_%256);
graph_[vhhh][tempindex+2] = (char) floor(((double)backgroundcolour_)/256);
graph_[vhhh][tempindex+3] = (char)(backgroundcolour_%256);
graph_[vhhh][tempindex+4] = (char) floor(((double)backgroundcolour_)/256);
graph_[vhhh][tempindex+5] = (char)(backgroundcolour_%256);
}
}
};
//Copy Constructor
//////////////////////////////////////////////////////////////////////////
pngwriter::pngwriter(const pngwriter& rhs) {
width_ = rhs.width_;
height_ = rhs.height_;
backgroundcolour_ = rhs.backgroundcolour_;
compressionlevel_ = rhs.compressionlevel_;
filegamma_ = rhs.filegamma_;
transformation_ = rhs.transformation_;;
should_free = true;
filename_ = new char[strlen(rhs.filename_)+1];
textauthor_ = new char[strlen(rhs.textauthor_)+1];
textdescription_ = new char[strlen(rhs.textdescription_)+1];
textsoftware_ = new char[strlen(rhs.textsoftware_)+1];
texttitle_ = new char[strlen(rhs.texttitle_)+1];
strcpy(filename_, rhs.filename_);
strcpy(textauthor_, rhs.textauthor_);
strcpy(textdescription_, rhs.textdescription_);
strcpy(textsoftware_,rhs.textsoftware_);
strcpy(texttitle_, rhs.texttitle_);
int kkkk;
bit_depth_ = rhs.bit_depth_;
colortype_= rhs.colortype_;
screengamma_ = rhs.screengamma_;
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; hhh<width_; hhh++) {
for(int vhhh = 0; vhhh<height_; vhhh++) {
// graph_[vhhh][6*hhh + i ] i=0 to 5
tempindex=6*hhh;
graph_[vhhh][tempindex] = rhs.graph_[vhhh][tempindex];
graph_[vhhh][tempindex+1] = rhs.graph_[vhhh][tempindex+1];
graph_[vhhh][tempindex+2] = rhs.graph_[vhhh][tempindex+2];
graph_[vhhh][tempindex+3] = rhs.graph_[vhhh][tempindex+3];
graph_[vhhh][tempindex+4] = rhs.graph_[vhhh][tempindex+4];
graph_[vhhh][tempindex+5] = rhs.graph_[vhhh][tempindex+5];
}
}
};
//Constructor for int colour levels, char * filename
//////////////////////////////////////////////////////////////////////////
pngwriter::pngwriter(int x, int y, int backgroundcolour, char* filename) {
width_ = x;
height_ = y;
backgroundcolour_ = backgroundcolour;
compressionlevel_ = 1;
filegamma_ = 0.6;
transformation_ = 0;
should_free = true;
textauthor_ = new char[255];
textdescription_ = new char[255];
texttitle_ = new char[strlen(filename)+1];
textsoftware_ = new char[255];
filename_ = new char[strlen(filename)+1];
strcpy(textauthor_, "PNGwriter Author: Paul Blackburn");
strcpy(textdescription_, "http://pngwriter.sourceforge.net/");
strcpy(textsoftware_, "PNGwriter: An easy to use graphics library.");
strcpy(texttitle_, filename);
strcpy(filename_, filename);
if((width_<0)||(height_<0)) {
std::cerr << " PNGwriter::pngwriter - ERROR **: Constructor called with negative height or width. Setting width and height to 1." << std::endl;
width_ = 1;
height_ = 1;
}
if(backgroundcolour_ >65535) {
std::cerr << " PNGwriter::pngwriter - WARNING **: Constructor called with background colour greater than 65535. Setting to 65535."<<std::endl;
backgroundcolour_ = 65535;
}
if(backgroundcolour_ <0) {
std::cerr << " PNGwriter::pngwriter - WARNING **: Constructor called with background colour lower than 0. Setting to 0."<<std::endl;
backgroundcolour_ = 0;
}
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; hhh<width_; hhh++) {
for(int vhhh = 0; vhhh<height_; vhhh++) {
//graph_[vhhh][6*hhh + i] i = 0 to 5
tempindex = 6*hhh;
graph_[vhhh][tempindex] = (char) floor(((double)backgroundcolour_)/256);
graph_[vhhh][tempindex+1] = (char)(backgroundcolour_%256);
graph_[vhhh][tempindex+2] = (char) floor(((double)backgroundcolour_)/256);
graph_[vhhh][tempindex+3] = (char)(backgroundcolour_%256);
graph_[vhhh][tempindex+4] = (char) floor(((double)backgroundcolour_)/256);
graph_[vhhh][tempindex+5] = (char)(backgroundcolour_%256);
}
}
};
pngwriter::pngwriter(int x, int y, unsigned char * data, char const * filename) {
width_ = x;
height_ = y;
compressionlevel_ = -2;
filegamma_ = 0.6;
transformation_ = 0;
should_free = false;
textauthor_ = new char[255];
textdescription_ = new char[255];
texttitle_ = new char[strlen(filename)+1];
textsoftware_ = new char[255];
filename_ = new char[strlen(filename)+1];
strcpy(textauthor_, "Joshua Moerman");
strcpy(textdescription_, "");
strcpy(textsoftware_, "");
strcpy(texttitle_, filename);
strcpy(filename_, filename);
if((width_<0)||(height_<0)) {
std::cerr << " PNGwriter::pngwriter - ERROR **: Constructor called with negative height or width. Setting width and height to 1." << std::endl;
width_ = 1;
height_ = 1;
}
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] = &data[kkkk*width_*6];
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;
}
};
//Constructor for double levels, char * filename
/////////////////////////////////////////////////////////////////////////
pngwriter::pngwriter(int x, int y, double backgroundcolour, char* filename) {
width_ = x;
height_ = y;
compressionlevel_ = -2;
filegamma_ = 0.6;
transformation_ = 0;
backgroundcolour_ = int(backgroundcolour*65535);
should_free = true;
textauthor_ = new char[255];
textdescription_ = new char[255];
texttitle_ = new char[strlen(filename)+1];
textsoftware_ = new char[255];
filename_ = new char[strlen(filename)+1];
strcpy(textauthor_, "PNGwriter Author: Paul Blackburn");
strcpy(textdescription_, "http://pngwriter.sourceforge.net/");
strcpy(textsoftware_, "PNGwriter: An easy to use graphics library.");
strcpy(texttitle_, filename);
strcpy(filename_, filename);
if((width_<0)||(height_<0)) {
std::cerr << " PNGwriter::pngwriter - ERROR **: Constructor called with negative height or width. Setting width and height to 1." << std::endl;
width_ = 1;
height_ = 1;
}
if(backgroundcolour_ >65535) {
std::cerr << " PNGwriter::pngwriter - WARNING **: Constructor called with background colour greater than 1.0. Setting to 1.0."<<std::endl;
backgroundcolour_ = 65535;
}
if(backgroundcolour_ < 0) {
std::cerr << " PNGwriter::pngwriter - WARNING **: Constructor called with background colour lower than 0.0. Setting to 0.0."<<std::endl;
backgroundcolour_ = 0;
}
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; hhh<width_; hhh++) {
for(int vhhh = 0; vhhh<height_; vhhh++) {
// graph_[vhhh][tempindex + i] where i = 0 to 5
tempindex = 6*hhh;
graph_[vhhh][tempindex] = (char) floor(((double)backgroundcolour_)/256);
graph_[vhhh][tempindex+1] = (char)(backgroundcolour_%256);
graph_[vhhh][tempindex+2] = (char) floor(((double)backgroundcolour_)/256);
graph_[vhhh][tempindex+3] = (char)(backgroundcolour_%256);
graph_[vhhh][tempindex+4] = (char) floor(((double)backgroundcolour_)/256);
graph_[vhhh][tempindex+5] = (char)(backgroundcolour_%256);
}
}
};
//Destructor
///////////////////////////////////////
pngwriter::~pngwriter() {
delete [] filename_;
delete [] textauthor_;
delete [] textdescription_;
delete [] texttitle_;
delete [] textsoftware_;
if(should_free){
for(int jjj = 0; jjj < height_; jjj++) free(graph_[jjj]);
free(graph_);
}
};
//Constructor for int levels, const char * filename
//////////////////////////////////////////////////////////////
pngwriter::pngwriter(int x, int y, int backgroundcolour, const char* filename) {
width_ = x;
height_ = y;
backgroundcolour_ = backgroundcolour;
compressionlevel_ = -2;
filegamma_ = 0.6;
transformation_ = 0;
should_free = true;
textauthor_ = new char[255];
textdescription_ = new char[255];
texttitle_ = new char[strlen(filename)+1];
textsoftware_ = new char[255];
filename_ = new char[strlen(filename)+1];
strcpy(textauthor_, "PNGwriter Author: Paul Blackburn");
strcpy(textdescription_, "http://pngwriter.sourceforge.net/");
strcpy(textsoftware_, "PNGwriter: An easy to use graphics library.");
strcpy(texttitle_, filename);
strcpy(filename_, filename);
if((width_<0)||(height_<0)) {
std::cerr << " PNGwriter::pngwriter - ERROR **: Constructor called with negative height or width. Setting width and height to 1." << std::endl;
height_ = 1;
width_ = 1;
}
if(backgroundcolour_ >65535) {
std::cerr << " PNGwriter::pngwriter - WARNING **: Constructor called with background colour greater than 65535. Setting to 65535."<<std::endl;
backgroundcolour_ = 65535;
}
if(backgroundcolour_ <0) {
std::cerr << " PNGwriter::pngwriter - WARNING **: Constructor called with background colour lower than 0. Setting to 0."<<std::endl;
backgroundcolour_ = 0;
}
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; hhh<width_; hhh++) {
for(int vhhh = 0; vhhh<height_; vhhh++) {
//graph_[vhhh][6*hhh + i] where i = 0 to 5
tempindex=6*hhh;
graph_[vhhh][tempindex] = (char) floor(((double)backgroundcolour_)/256);
graph_[vhhh][tempindex+1] = (char)(backgroundcolour_%256);
graph_[vhhh][tempindex+2] = (char) floor(((double)backgroundcolour_)/256);
graph_[vhhh][tempindex+3] = (char)(backgroundcolour_%256);
graph_[vhhh][tempindex+4] = (char) floor(((double)backgroundcolour_)/256);
graph_[vhhh][tempindex+5] = (char)(backgroundcolour_%256);
}
}
};
//Constructor for double levels, const char * filename
/////////////////////////////////////////////////////////////////////////
pngwriter::pngwriter(int x, int y, double backgroundcolour, const char* filename) {
width_ = x;
height_ = y;
compressionlevel_ = -2;
backgroundcolour_ = int(backgroundcolour*65535);
filegamma_ = 0.6;
transformation_ = 0;
textauthor_ = new char[255];
textdescription_ = new char[255];
texttitle_ = new char[strlen(filename)+1];
textsoftware_ = new char[255];
filename_ = new char[strlen(filename)+1];
strcpy(textauthor_, "PNGwriter Author: Paul Blackburn");
strcpy(textdescription_, "http://pngwriter.sourceforge.net/");
strcpy(textsoftware_, "PNGwriter: An easy to use graphics library.");
strcpy(texttitle_, filename);
strcpy(filename_, filename);
if((width_<0)||(height_<0)) {
std::cerr << " PNGwriter::pngwriter - ERROR **: Constructor called with negative height or width. Setting width and height to 1." << std::endl;
width_ = 1;
height_ = 1;
}
if(backgroundcolour_ >65535) {
std::cerr << " PNGwriter::pngwriter - WARNING **: Constructor called with background colour greater than 65535. Setting to 65535."<<std::endl;
backgroundcolour_ = 65535;
}
if(backgroundcolour_ <0) {
std::cerr << " PNGwriter::pngwriter - WARNING **: Constructor called with background colour lower than 0. Setting to 0."<<std::endl;
backgroundcolour_ = 0;
}
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; hhh<width_; hhh++) {
for(int vhhh = 0; vhhh<height_; vhhh++) {
//etc
tempindex = 6*hhh;
graph_[vhhh][tempindex] = (char) floor(((double)backgroundcolour_)/256);
graph_[vhhh][tempindex+1] = (char)(backgroundcolour_%256);
graph_[vhhh][tempindex+2] = (char) floor(((double)backgroundcolour_)/256);
graph_[vhhh][tempindex+3] = (char)(backgroundcolour_%256);
graph_[vhhh][tempindex+4] = (char) floor(((double)backgroundcolour_)/256);
graph_[vhhh][tempindex+5] = (char)(backgroundcolour_%256);
}
}
};
// Overloading operator =
/////////////////////////////////////////////////////////
pngwriter& pngwriter::operator = (const pngwriter& rhs) {
if(this==&rhs) {
return *this;
}
width_ = rhs.width_;
height_ = rhs.height_;
backgroundcolour_ = rhs.backgroundcolour_;
compressionlevel_ = rhs.compressionlevel_;
filegamma_ = rhs.filegamma_;
transformation_ = rhs.transformation_;
filename_ = new char[strlen(rhs.filename_)+1];
textauthor_ = new char[strlen(rhs.textauthor_)+1];
textdescription_ = new char[strlen(rhs.textdescription_)+1];
textsoftware_ = new char[strlen(rhs.textsoftware_)+1];
texttitle_ = new char[strlen(rhs.texttitle_)+1];
strcpy(textauthor_, rhs.textauthor_);
strcpy(textdescription_, rhs.textdescription_);
strcpy(textsoftware_,rhs.textsoftware_);
strcpy(texttitle_, rhs.texttitle_);
strcpy(filename_, rhs.filename_);
int kkkk;
bit_depth_ = rhs.bit_depth_;
colortype_= rhs.colortype_;
screengamma_ = rhs.screengamma_;
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; hhh<width_; hhh++) {
for(int vhhh = 0; vhhh<height_; vhhh++) {
tempindex=6*hhh;
graph_[vhhh][tempindex] = rhs.graph_[vhhh][tempindex];
graph_[vhhh][tempindex+1] = rhs.graph_[vhhh][tempindex+1];
graph_[vhhh][tempindex+2] = rhs.graph_[vhhh][tempindex+2];
graph_[vhhh][tempindex+3] = rhs.graph_[vhhh][tempindex+3];
graph_[vhhh][tempindex+4] = rhs.graph_[vhhh][tempindex+4];
graph_[vhhh][tempindex+5] = rhs.graph_[vhhh][tempindex+5];
}
}
return *this;
}
///////////////////////////////////////////////////////////////
void pngwriter::plot(int x, int y, int red, int green, int blue) {
int tempindex;
if(red > 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 <height_) && (6*(x-1) >-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 <height_) && (6*(x-1) >-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 <height_) && (3*(x-1) >-1) && (3*(x-1)+5<3*width_) )
if((y<height_+1) && (y>0) && (x>0) && (x<width_+1)) {
// graph_[height_-y][3*(x-1) + i] where i goes from 0 to 2
tempindex = 3*x-3;
graph_[height_-y][tempindex] = (char)(floor(((double)red)/257.0));
graph_[height_-y][tempindex+1] = (char)(floor(((double)green)/257.0));
graph_[height_-y][tempindex+2] = (char)(floor(((double)blue)/257.0));
};
/*
if(!( (height_-y >-1) && (height_-y <height_) && (6*(x-1) >-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<width_; pen++) {
for(pencil = 0; pencil<height_; pencil++) {
tempindex=6*pen;
graph_[pencil][tempindex] = 0;
graph_[pencil][tempindex+1] = 0;
graph_[pencil][tempindex+2] = 0;
graph_[pencil][tempindex+3] = 0;
graph_[pencil][tempindex+4] = 0;
graph_[pencil][tempindex+5] = 0;
}
}
}
if(bit_depth_==8) {
for(pen = 0; pen<width_; pen++) {
for(pencil = 0; pencil<height_; pencil++) {
tempindex=3*pen;
graph_[pencil][tempindex] = 0;
graph_[pencil][tempindex+1] = 0;
graph_[pencil][tempindex+2] = 0;
}
}
}
};
/////////////////////////////////////////////////////
void pngwriter::pngwriter_rename(char* newname) {
delete [] filename_;
delete [] texttitle_;
filename_ = new char[strlen(newname)+1];
texttitle_ = new char[strlen(newname)+1];
strcpy(filename_,newname);
strcpy(texttitle_,newname);
};
///////////////////////////////////////////////////////
void pngwriter::pngwriter_rename(const char* newname) {
delete [] filename_;
delete [] texttitle_;
filename_ = new char[strlen(newname)+1];
texttitle_ = new char[strlen(newname)+1];
strcpy(filename_,newname);
strcpy(texttitle_,newname);
};
///////////////////////////////////////////////////////
void pngwriter::pngwriter_rename(long unsigned int index) {
char buffer[255];
// %[flags][width][.precision][modifiers]type
//
if((index > 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 <xto+1; caca++) {
this->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 <<std::flush;
std::cerr << "\"." << std::endl << std::flush;
perror(" PNGwriter::readfromfile - ERROR **");
return;
}
if(!check_if_png(name, &fp)) {
std::cerr << " PNGwriter::readfromfile - ERROR **: Error opening file " << name << ". This may not be a valid png file. (check_if_png() failed)." << std::endl;
// fp has been closed already if check_if_png() fails.
return;
}
// Code as it was before Sven's patch
/* if(!read_png_info(fp, &png_ptr, &info_ptr))
{
std::cerr << " PNGwriter::readfromfile - ERROR **: Error opening file " << name << ". read_png_info() failed." << std::endl;
// fp has been closed already if read_png_info() fails.
return;
}
if(!read_png_image(fp, png_ptr, info_ptr, &image, &width, &height))
{
std::cerr << " PNGwriter::readfromfile - ERROR **: Error opening file " << name << ". read_png_image() failed." << std::endl;
// fp has been closed already if read_png_image() fails.
return;
}
//stuff should now be in image[][].
*/ //End of code as it was before Sven's patch.
//Sven's patch starts here
////////////////////////////////////
/*
if(!read_png_info(fp, &png_ptr, &info_ptr))
{
std::cerr << " PNGwriter::readfromfile - ERROR **: Error opening file " << name << ". read_png_info() failed." << std::endl;
// fp has been closed already if read_png_info() fails.
return;
}
// UPDATE: Query info struct to get header info BEFORE reading the image
png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL);
bit_depth_ = bit_depth;
colortype_ = color_type;
if(color_type == PNG_COLOR_TYPE_PALETTE)
{
png_set_expand(png_ptr);
png_read_update_info(png_ptr, info_ptr);
}
if(!read_png_image(fp, png_ptr, info_ptr, &image, &width, &height))
{
std::cerr << " PNGwriter::readfromfile - ERROR **: Error opening file " << name << ". read_png_image() failed." << std::endl;
// fp has been closed already if read_png_image() fails.
return;
}
//stuff should now be in image[][].
*/
//Sven's patch ends here.
////////////////////////////////
// Mikkel's patch starts here
// ///////////////////////////////////
if(!read_png_info(fp, &png_ptr, &info_ptr)) {
std::cerr << " PNGwriter::readfromfile - ERROR **: Error opening file " << name << ". read_png_info() failed." << std::endl;
// fp has been closed already if read_png_info() fails.
return;
}
//Input transformations
png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL);
bit_depth_ = bit_depth;
colortype_ = color_type;
// Changes palletted image to RGB
if(color_type == PNG_COLOR_TYPE_PALETTE /*&& bit_depth<8*/) {
// png_set_expand(png_ptr);
png_set_palette_to_rgb(png_ptr); // Just an alias of png_set_expand()
transformation_ = 1;
}
// Transforms grescale images of less than 8 bits to 8 bits.
if(color_type == PNG_COLOR_TYPE_GRAY && bit_depth<8) {
// png_set_expand(png_ptr);
png_set_gray_1_2_4_to_8(png_ptr); // Just an alias of the above.
transformation_ = 1;
}
// Completely strips the alpha channel.
if(color_type & PNG_COLOR_MASK_ALPHA) {
png_set_strip_alpha(png_ptr);
transformation_ = 1;
}
// Converts greyscale images to RGB.
if(color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { // Used to be RGB, fixed it.
png_set_gray_to_rgb(png_ptr);
transformation_ = 1;
}
// If any of the above were applied,
if(transformation_) {
// png_set_gray_to_rgb(png_ptr); //Is this really needed here?
// After setting the transformations, libpng can update your png_info structure to reflect any transformations
// you've requested with this call. This is most useful to update the info structure's rowbytes field so you can
// use it to allocate your image memory. This function will also update your palette with the correct screen_gamma
// and background if these have been given with the calls above.
png_read_update_info(png_ptr, info_ptr);
// Just in case any of these have changed?
png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL);
bit_depth_ = bit_depth;
colortype_ = color_type;
}
if(!read_png_image(fp, png_ptr, info_ptr, &image, &width, &height)) {
std::cerr << " PNGwriter::readfromfile - ERROR **: Error opening file " << name << ". read_png_image() failed." << std::endl;
// fp has been closed already if read_png_image() fails.
return;
}
//stuff should now be in image[][].
// Mikkel's patch ends here
// //////////////////////////////
//
if(image == NULL) {
std::cerr << " PNGwriter::readfromfile - ERROR **: Error opening file " << name << ". Can't assign memory (after read_png_image(), image is NULL)." << std::endl;
fclose(fp);
return;
}
//First we must get rid of the image already there, and free the memory.
int jjj;
for(jjj = 0; jjj < height_; jjj++) free(graph_[jjj]);
free(graph_);
//Must reassign the new size of the read image
width_ = width;
height_ = height;
//Graph now is the image.
graph_ = image;
rowbytes_ = png_get_rowbytes(png_ptr, info_ptr);
// This was part of the original source, but has been moved up.
/*
png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL);
bit_depth_ = bit_depth;
colortype_ = color_type;
*/
// if(color_type == PNG_COLOR_TYPE_PALETTE /*&& bit_depth<8*/ )
/* {
png_set_expand(png_ptr);
}
if(color_type == PNG_COLOR_TYPE_GRAY && bit_depth<8)
{
png_set_expand(png_ptr);
}
if(color_type & PNG_COLOR_MASK_ALPHA)
{
png_set_strip_alpha(png_ptr);
}
if(color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_RGB_ALPHA)
{
png_set_gray_to_rgb(png_ptr);
}
*/
if((bit_depth_ !=16)&&(bit_depth_ !=8)) {
std::cerr << " PNGwriter::readfromfile() - WARNING **: Input file is of unsupported type (bad bit_depth). Output will be unpredictable.\n";
}
// Thanks to Mikkel's patch, PNGwriter should now be able to handle these color types:
/*
color_type - describes which color/alpha channels are present.
PNG_COLOR_TYPE_GRAY (bit depths 1, 2, 4, 8, 16)
PNG_COLOR_TYPE_GRAY_ALPHA (bit depths 8, 16)
PNG_COLOR_TYPE_PALETTE (bit depths 1, 2, 4, 8)
PNG_COLOR_TYPE_RGB (bit_depths 8, 16)
PNG_COLOR_TYPE_RGB_ALPHA (bit_depths 8, 16)
PNG_COLOR_MASK_PALETTE
PNG_COLOR_MASK_COLOR
color types. Note that not all combinations are legal
#define PNG_COLOR_TYPE_GRAY 0
#define PNG_COLOR_TYPE_PALETTE (PNG_COLOR_MASK_COLOR (2) | PNG_COLOR_MASK_PALETTE (1) )
#define PNG_COLOR_TYPE_RGB (PNG_COLOR_MASK_COLOR (2) )
#define PNG_COLOR_TYPE_RGB_ALPHA (PNG_COLOR_MASK_COLOR (2) | PNG_COLOR_MASK_ALPHA (4) )
#define PNG_COLOR_TYPE_GRAY_ALPHA (PNG_COLOR_MASK_ALPHA (4) )
aliases
#define PNG_COLOR_TYPE_RGBA PNG_COLOR_TYPE_RGB_ALPHA
#define PNG_COLOR_TYPE_GA PNG_COLOR_TYPE_GRAY_ALPHA
These describe the color_type field in png_info.
color type masks
#define PNG_COLOR_MASK_PALETTE 1
#define PNG_COLOR_MASK_COLOR 2
#define PNG_COLOR_MASK_ALPHA 4
*/
if(colortype_ !=2) {
std::cerr << " PNGwriter::readfromfile() - WARNING **: Input file is of unsupported type (bad color_type). Output will be unpredictable.\n";
}
screengamma_ = 2.2;
double file_gamma,screen_gamma;
screen_gamma = screengamma_;
if(png_get_gAMA(png_ptr, info_ptr, &file_gamma)) {
png_set_gamma(png_ptr,screen_gamma,file_gamma);
} else {
png_set_gamma(png_ptr, screen_gamma,0.45);
}
filegamma_ = file_gamma;
fclose(fp);
}
///////////////////////////////////////////////////////
void pngwriter::readfromfile(const char* name) {
this->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(iii<num_bytes) {
z = text[iii];
if(z<=127) {
ucs4text[num_chars] = z;
}
if((192<=z)&&(z<=223)) {
iii++;
y = text[iii];
ucs4text[num_chars] = (z-192)*64 + (y -128);
}
if((224<=z)&&(z<=239)) {
iii++;
y = text[iii];
iii++;
x = text[iii];
ucs4text[num_chars] = (z-224)*4096 + (y -128)*64 + (x-128);
}
if((240<=z)&&(z<=247)) {
iii++;
y = text[iii];
iii++;
x = text[iii];
iii++;
w = text[iii];
ucs4text[num_chars] = (z-240)*262144 + (y -128)*4096 + (x-128)*64 + (w-128);
}
if((248<=z)&&(z<=251)) {
iii++;
y = text[iii];
iii++;
x = text[iii];
iii++;
w = text[iii];
iii++;
v = text[iii];
ucs4text[num_chars] = (z-248)*16777216 + (y -128)*262144 + (x-128)*4096 + (w-128)*64 +(v-128);
}
if((252==z)||(z==253)) {
iii++;
y = text[iii];
iii++;
x = text[iii];
iii++;
w = text[iii];
iii++;
v = text[iii];
u = text[iii];
ucs4text[num_chars] = (z-252)*1073741824 + (y -128)*16777216 + (x-128)*262144 + (w-128)*4096 +(v-128)*64 + (u-128);
}
if((z==254)||(z==255)) {
std::cerr << " PNGwriter::plot_text_utf8 - ERROR **: Problem with character: invalid UTF-8 data."<< std::endl;
}
// std::cerr << "\nProblem at " << iii << ".\n";
//
iii++;
num_chars++;
}
// num_chars now contains the number of characters in the string.
/*
std::cout << "Num chars is: "<< num_chars << std::endl;
*/
/* Initialize FT Library object */
error = FT_Init_FreeType(&library);
if(error) { std::cerr << " PNGwriter::plot_text_utf8 - 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_utf8 - 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, 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; j<bitmap->rows+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(iii<num_bytes) {
z = text[iii];
if(z<=127) {
ucs4text[num_chars] = z;
}
if((192<=z)&&(z<=223)) {
iii++;
y = text[iii];
ucs4text[num_chars] = (z-192)*64 + (y -128);
}
if((224<=z)&&(z<=239)) {
iii++;
y = text[iii];
iii++;
x = text[iii];
ucs4text[num_chars] = (z-224)*4096 + (y -128)*64 + (x-128);
}
if((240<=z)&&(z<=247)) {
iii++;
y = text[iii];
iii++;
x = text[iii];
iii++;
w = text[iii];
ucs4text[num_chars] = (z-240)*262144 + (y -128)*4096 + (x-128)*64 + (w-128);
}
if((248<=z)&&(z<=251)) {
iii++;
y = text[iii];
iii++;
x = text[iii];
iii++;
w = text[iii];
iii++;
v = text[iii];
ucs4text[num_chars] = (z-248)*16777216 + (y -128)*262144 + (x-128)*4096 + (w-128)*64 +(v-128);
}
if((252==z)||(z==253)) {
iii++;
y = text[iii];
iii++;
x = text[iii];
iii++;
w = text[iii];
iii++;
v = text[iii];
u = text[iii];
ucs4text[num_chars] = (z-252)*1073741824 + (y -128)*16777216 + (x-128)*262144 + (w-128)*4096 +(v-128)*64 + (u-128);
}
if((z==254)||(z==255)) {
std::cerr << " PNGwriter::get_text_width_utf8 - ERROR **: Problem with character: invalid UTF-8 data."<< std::endl;
}
// std::cerr << "\nProblem at " << iii << ".\n";
//
iii++;
num_chars++;
}
// num_chars now contains the number of characters in the string.
/*
std::cout << "Num chars is: "<< num_chars << std::endl;
*/
/* Initialize FT Library object */
error = FT_Init_FreeType(&library);
if(error) { std::cerr << " PNGwriter::get_text_width_utf8 - 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_utf8 - ERROR **: FreeType: Font was opened, but type not supported."<< std::endl; return 0; } else if(error) { std::cerr << " PNGwriter::plot_text - 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, 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; hhh<width_; hhh++) {
for(int vhhh = 0; vhhh<height_; vhhh++) {
//graph_[vhhh][6*hhh + i] where i goes from 0 to 5
tempindex = 6*hhh;
graph_[vhhh][tempindex] = (char) floor(((double)backgroundcolour_)/256);
graph_[vhhh][tempindex+1] = (char)(backgroundcolour_%256);
graph_[vhhh][tempindex+2] = (char) floor(((double)backgroundcolour_)/256);
graph_[vhhh][tempindex+3] = (char)(backgroundcolour_%256);
graph_[vhhh][tempindex+4] = (char) floor(((double)backgroundcolour_)/256);
graph_[vhhh][tempindex+5] = (char)(backgroundcolour_%256);
}
}
}
void pngwriter::boundary_fill(int xstart, int ystart, 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(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((igreen<ired)&&(igreen<iblue)) {
black = igreen;
}
if((iblue<igreen)&&(iblue<ired)) {
black = iblue;
}
iblack = 1.0 - black;
if(colour == 1) {
return ((ired-black)/(iblack));
}
if(colour == 2) {
return ((igreen-black)/(iblack));
}
if(colour == 3) {
return ((iblue-black)/(iblack));
}
if(colour == 4) {
return black;
}
return 0.0;
}
int pngwriter::readCMYK(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::readCMYK - 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((igreen<ired)&&(igreen<iblue)) {
black = igreen;
}
if((iblue<igreen)&&(iblue<ired)) {
black = iblue;
}
iblack = 1.0 - black;
if(colour == 1) {
return (int)(((ired-black)/(iblack))*65535);
}
if(colour == 2) {
return (int)(((igreen-black)/(iblack))*65535);
}
if(colour == 3) {
return (int)(((iblue-black)/(iblack))*65535);
}
if(colour == 4) {
return (int)((black)*65535);
}
return 0;
}
void pngwriter::scale_k(double k) {
if(k <= 0.0) {
std::cerr << " PNGwriter::scale_k - ERROR **: scale_k() called with negative or zero scale factor. Was: " << k << "." << std::endl;
}
// Calculate the new scaled height and width
int scaledh, scaledw;
scaledw = (int) ceil(k*width_);
scaledh = (int) ceil(k*height_);
// Create image storage.
pngwriter temp(scaledw,scaledh,0,"temp");
int red, green, blue;
double spacingx = ((double)width_)/(2*scaledw);
double spacingy = ((double)height_)/(2*scaledh);
double readx, ready;
for(int x = 1; x<= scaledw; x++) {
for(int y = 1; y <= scaledh; y++) {
readx = (2*x-1)*spacingx;
ready = (2*y-1)*spacingy;
red = this->bilinear_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; hhh<width_; hhh++) {
for(int vhhh = 0; vhhh<height_; vhhh++) {
tempindex=6*hhh;
graph_[vhhh][tempindex] = temp.graph_[vhhh][tempindex];
graph_[vhhh][tempindex+1] = temp.graph_[vhhh][tempindex+1];
graph_[vhhh][tempindex+2] = temp.graph_[vhhh][tempindex+2];
graph_[vhhh][tempindex+3] = temp.graph_[vhhh][tempindex+3];
graph_[vhhh][tempindex+4] = temp.graph_[vhhh][tempindex+4];
graph_[vhhh][tempindex+5] = temp.graph_[vhhh][tempindex+5];
}
}
// this should now contain the new, scaled image data.
//
}
void pngwriter::scale_kxky(double kx, double ky) {
if((kx <= 0.0)||(ky <= 0.0)) {
std::cerr << " PNGwriter::scale_kxky - ERROR **: scale_kxky() called with negative or zero scale factor. Was: " << kx << ", " << ky << "." << std::endl;
}
int scaledh, scaledw;
scaledw = (int) ceil(kx*width_);
scaledh = (int) ceil(ky*height_);
pngwriter temp(scaledw, scaledh, 0, "temp");
int red, green, blue;
double spacingx = ((double)width_)/(2*scaledw);
double spacingy = ((double)height_)/(2*scaledh);
double readx, ready;
for(int x = 1; x<= scaledw; x++) {
for(int y = 1; y <= scaledh; y++) {
readx = (2*x-1)*spacingx;
ready = (2*y-1)*spacingy;
red = this->bilinear_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; hhh<width_; hhh++) {
for(int vhhh = 0; vhhh<height_; vhhh++) {
tempindex=6*hhh;
graph_[vhhh][tempindex] = temp.graph_[vhhh][tempindex];
graph_[vhhh][tempindex+1] = temp.graph_[vhhh][tempindex+1];
graph_[vhhh][tempindex+2] = temp.graph_[vhhh][tempindex+2];
graph_[vhhh][tempindex+3] = temp.graph_[vhhh][tempindex+3];
graph_[vhhh][tempindex+4] = temp.graph_[vhhh][tempindex+4];
graph_[vhhh][tempindex+5] = temp.graph_[vhhh][tempindex+5];
}
}
// this should now contain the new, scaled image data.
//
//
}
void pngwriter::scale_wh(int finalwidth, int finalheight) {
if((finalwidth <= 0)||(finalheight <= 0)) {
std::cerr << " PNGwriter::scale_wh - ERROR **: Negative or zero final width or height not allowed." << std::endl;
}
double kx;
double ky;
kx = ((double)finalwidth)/((double)width_);
ky = ((double)finalheight)/((double)height_);
pngwriter temp(finalwidth, finalheight, 0, "temp");
int red, green, blue;
double spacingx = ((double)width_)/(2*finalwidth);
double spacingy = ((double)height_)/(2*finalheight);
double readx, ready;
for(int x = 1; x<= finalwidth; x++) {
for(int y = 1; y <= finalheight; y++) {
readx = (2*x-1)*spacingx;
ready = (2*y-1)*spacingy;
red = this->bilinear_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; hhh<width_; hhh++) {
for(int vhhh = 0; vhhh<height_; vhhh++) {
tempindex=6*hhh;
graph_[vhhh][tempindex] = temp.graph_[vhhh][tempindex];
graph_[vhhh][tempindex+1] = temp.graph_[vhhh][tempindex+1];
graph_[vhhh][tempindex+2] = temp.graph_[vhhh][tempindex+2];
graph_[vhhh][tempindex+3] = temp.graph_[vhhh][tempindex+3];
graph_[vhhh][tempindex+4] = temp.graph_[vhhh][tempindex+4];
graph_[vhhh][tempindex+5] = temp.graph_[vhhh][tempindex+5];
}
}
// this should now contain the new, scaled image data.
//
//
}
// Blended functions
//
void pngwriter::plotHSV_blend(int x, int y, double opacity, 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_blend(x,y,opacity, red,green,blue);
}
void pngwriter::plotHSV_blend(int x, int y, double opacity, int hue, int saturation, int value) {
plotHSV_blend(x, y, opacity, double(hue)/65535.0, double(saturation)/65535.0, double(value)/65535.0);
}
void pngwriter::line_blend(int xfrom, int yfrom, int xto, int yto, double opacity, 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_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 <xto+1; caca++) {
this->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(iii<num_bytes) {
z = text[iii];
if(z<=127) {
ucs4text[num_chars] = z;
}
if((192<=z)&&(z<=223)) {
iii++;
y = text[iii];
ucs4text[num_chars] = (z-192)*64 + (y -128);
}
if((224<=z)&&(z<=239)) {
iii++;
y = text[iii];
iii++;
x = text[iii];
ucs4text[num_chars] = (z-224)*4096 + (y -128)*64 + (x-128);
}
if((240<=z)&&(z<=247)) {
iii++;
y = text[iii];
iii++;
x = text[iii];
iii++;
w = text[iii];
ucs4text[num_chars] = (z-240)*262144 + (y -128)*4096 + (x-128)*64 + (w-128);
}
if((248<=z)&&(z<=251)) {
iii++;
y = text[iii];
iii++;
x = text[iii];
iii++;
w = text[iii];
iii++;
v = text[iii];
ucs4text[num_chars] = (z-248)*16777216 + (y -128)*262144 + (x-128)*4096 + (w-128)*64 +(v-128);
}
if((252==z)||(z==253)) {
iii++;
y = text[iii];
iii++;
x = text[iii];
iii++;
w = text[iii];
iii++;
v = text[iii];
u = text[iii];
ucs4text[num_chars] = (z-252)*1073741824 + (y -128)*16777216 + (x-128)*262144 + (w-128)*4096 +(v-128)*64 + (u-128);
}
if((z==254)||(z==255)) {
std::cerr << " PNGwriter::plot_text_utf8_blend - ERROR **: Problem with character: invalid UTF-8 data."<< std::endl;
}
// std::cerr << "\nProblem at " << iii << ".\n";
//
iii++;
num_chars++;
}
// num_chars now contains the number of characters in the string.
/*
std::cout << "Num chars is: "<< num_chars << std::endl;
*/
/* Initialize FT Library object */
error = FT_Init_FreeType(&library);
if(error) { std::cerr << " PNGwriter::plot_text_utf8_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_utf8_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, 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; j<bitmap->rows+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
// ( <gurkan@linuks.mine.nu>, 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; y<y2; y++) {
this->line(posl/256, y, posr/256, y, red, green, blue);
posl+=cl;
posr+=cr;
}
}
// drwatop(), drawbottom() and filledtriangle() were contributed by Gurkan Sengun
// ( <gurkan@linuks.mine.nu>, 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; y<y3; y++) {
this->line(posl/256, y, posr/256, y, red, green, blue);
posl+=cl;
posr+=cr;
}
}
// drwatop(), drawbottom() and filledtriangle() were contributed by Gurkan Sengun
// ( <gurkan@linuks.mine.nu>, 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(y2<y1) {
// x2^=x1^=x2^=x1;
x2^=x1;
x1^=x2;
x2^=x1;
// y2^=y1^=y2^=y1;
y2^=y1;
y1^=x2;
y2^=y1;
}
if(y3<y1) {
//x3^=x1^=x3^=x1;
x3^=x1;
x1^=x3;
x3^=x1;
//y3^=y1^=y3^=y1;
y3^=y1;
y1^=y3;
y3^=y1;
}
if(y3<y2) {
//x2^=x3^=x2^=x3;
x2^=x3;
x3^=x2;
x2^=x3;
//y2^=y3^=y2^=y3;
y2^=y3;
y3^=y2;
y2^=y3;
}
if(y2==y3) {
this->drawtop(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(y2<y1)
{
x2^=x1^=x2^=x1;
y2^=y1^=y2^=y1;
}
if(y3<y1)
{
x3^=x1^=x3^=x1;
y3^=y1^=y3^=y1;
}
if(y3<y2)
{
x2^=x3^=x2^=x3;
y2^=y3^=y2^=y3;
}
*/
if(y2<y1) {
// x2^=x1^=x2^=x1;
x2^=x1;
x1^=x2;
x2^=x1;
// y2^=y1^=y2^=y1;
y2^=y1;
y1^=x2;
y2^=y1;
}
if(y3<y1) {
//x3^=x1^=x3^=x1;
x3^=x1;
x1^=x3;
x3^=x1;
//y3^=y1^=y3^=y1;
y3^=y1;
y1^=y3;
y3^=y1;
}
if(y3<y2) {
//x2^=x3^=x2^=x3;
x2^=x3;
x3^=x2;
x2^=x3;
//y2^=y3^=y2^=y3;
y2^=y3;
y3^=y2;
y2^=y3;
}
if(y2==y3) {
this->drawtop_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; y<y3; y++) {
this->line_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; y<y2; y++) {
this->line_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));
}