polaroid-pp

Schlieren and contour plot tool
git clone https://git.0xfab.ch/polaroid-pp.git
Log | Files | Refs | Submodules | README | LICENSE

pngwriter.cc (139365B)


      1 //**********  pngwriter.cc   **********************************************
      2 //  Author:                    Paul Blackburn
      3 //
      4 //  Email:                     individual61@users.sourceforge.net
      5 //
      6 //  Version:                   0.5.4   (19 / II / 2009)
      7 //
      8 //  Description:               Library that allows plotting a 48 bit
      9 //                             PNG image pixel by pixel, which can
     10 //                             then be opened with a graphics program.
     11 //
     12 //  License:                   GNU General Public License
     13 //                             Copyright 2002, 2003, 2004, 2005, 2006, 2007,
     14 //                             2008, 2009 Paul Blackburn
     15 //
     16 //  Website: Main:             http://pngwriter.sourceforge.net/
     17 //           Sourceforge.net:  http://sourceforge.net/projects/pngwriter/
     18 //           Freshmeat.net:    http://freshmeat.net/projects/pngwriter/
     19 //
     20 //  Documentation:             The header file (pngwriter.h) is commented, but for a
     21 //                             quick reference document, and support,
     22 //                             take a look at the website.
     23 //
     24 //*************************************************************************
     25 
     26 /*
     27  *     This program is free software; you can redistribute it and/or modify
     28  *     it under the terms of the GNU General Public License as published by
     29  *     the Free Software Foundation; either version 2 of the License, or
     30  *     (at your option) any later version.
     31  *
     32  *     This program is distributed in the hope that it will be useful,
     33  *     but WITHOUT ANY WARRANTY; without even the implied warranty of
     34  *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     35  *     GNU General Public License for more details.
     36  *
     37  *     You should have received a copy of the GNU General Public License
     38  *     along with this program; if not, write to the Free Software
     39  *     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
     40  *
     41  * */
     42 
     43 #include "pngwriter.h"
     44 
     45 // Default Constructor
     46 ////////////////////////////////////////////////////////////////////////////
     47 pngwriter::pngwriter()
     48 {
     49 
     50    filename_ = new char[255];
     51    textauthor_ = new char[255];
     52    textdescription_ = new char[255];
     53    texttitle_  = new char[255];
     54    textsoftware_ = new char[255];
     55 
     56    strcpy(filename_, "out.png");
     57    width_ = 250;
     58    height_ = 250;
     59    backgroundcolour_ = 65535;
     60    compressionlevel_ = -2;
     61    filegamma_ = 0.5;
     62    transformation_ = 0;
     63 
     64    strcpy(textauthor_, "PNGwriter Author: Paul Blackburn");
     65    strcpy(textdescription_, "http://pngwriter.sourceforge.net/");
     66    strcpy(textsoftware_, "PNGwriter: An easy to use graphics library.");
     67    strcpy(texttitle_, "out.png");
     68 
     69    int kkkk;
     70 
     71    bit_depth_ = 16; //Default bit depth for new images
     72    colortype_=2;
     73    screengamma_ = 2.2;
     74 
     75    graph_ = (png_bytepp)malloc(height_ * sizeof(png_bytep));
     76    if(graph_ == NULL)
     77      {
     78 	std::cerr << " PNGwriter::pngwriter - ERROR **:  Not able to allocate memory for image." << std::endl;
     79      }
     80 
     81    for (kkkk = 0; kkkk < height_; kkkk++)
     82      {
     83         graph_[kkkk] = (png_bytep)malloc(6*width_ * sizeof(png_byte));
     84 	if(graph_[kkkk] == NULL)
     85 	  {
     86 	     std::cerr << " PNGwriter::pngwriter - ERROR **:  Not able to allocate memory for image." << std::endl;
     87 	  }
     88      }
     89 
     90    if(graph_ == NULL)
     91      {
     92 	std::cerr << " PNGwriter::pngwriter - ERROR **:  Not able to allocate memory for image." << std::endl;
     93      }
     94 
     95    int tempindex;
     96    for(int hhh = 0; hhh<width_;hhh++)
     97      {
     98 	for(int vhhh = 0; vhhh<height_;vhhh++)
     99 	  {
    100 	     //graph_[vhhh][6*hhh + i] where i goes from 0 to 5
    101 	     tempindex = 6*hhh;
    102 	     graph_[vhhh][tempindex] = (char) floor(((double)backgroundcolour_)/256);
    103 	     graph_[vhhh][tempindex+1] = (char)(backgroundcolour_%256);
    104 	     graph_[vhhh][tempindex+2] = (char) floor(((double)backgroundcolour_)/256);
    105 	     graph_[vhhh][tempindex+3] = (char)(backgroundcolour_%256);
    106 	     graph_[vhhh][tempindex+4] = (char) floor(((double)backgroundcolour_)/256);
    107 	     graph_[vhhh][tempindex+5] = (char)(backgroundcolour_%256);
    108 	  }
    109      }
    110 
    111 };
    112 
    113 //Copy Constructor
    114 //////////////////////////////////////////////////////////////////////////
    115 pngwriter::pngwriter(const pngwriter &rhs)
    116 {
    117    width_ = rhs.width_;
    118    height_ = rhs.height_;
    119    backgroundcolour_ = rhs.backgroundcolour_;
    120    compressionlevel_ = rhs.compressionlevel_;
    121    filegamma_ = rhs.filegamma_;
    122    transformation_ = rhs.transformation_;;
    123 
    124    filename_ = new char[strlen(rhs.filename_)+1];
    125    textauthor_ = new char[strlen(rhs.textauthor_)+1];
    126    textdescription_ = new char[strlen(rhs.textdescription_)+1];
    127    textsoftware_ = new char[strlen(rhs.textsoftware_)+1];
    128    texttitle_ = new char[strlen(rhs.texttitle_)+1];
    129 
    130    strcpy(filename_, rhs.filename_);
    131    strcpy(textauthor_, rhs.textauthor_);
    132    strcpy(textdescription_, rhs.textdescription_);
    133    strcpy(textsoftware_,rhs.textsoftware_);
    134    strcpy(texttitle_, rhs.texttitle_);
    135 
    136    int kkkk;
    137 
    138    bit_depth_ = rhs.bit_depth_;
    139    colortype_= rhs.colortype_;
    140    screengamma_ = rhs.screengamma_;
    141 
    142    graph_ = (png_bytepp)malloc(height_ * sizeof(png_bytep));
    143    if(graph_ == NULL)
    144      {
    145 	std::cerr << " PNGwriter::pngwriter - ERROR **:  Not able to allocate memory for image." << std::endl;
    146      }
    147 
    148    for (kkkk = 0; kkkk < height_; kkkk++)
    149      {
    150         graph_[kkkk] = (png_bytep)malloc(6*width_ * sizeof(png_byte));
    151 	if(graph_[kkkk] == NULL)
    152 	  {
    153 	     std::cerr << " PNGwriter::pngwriter - ERROR **:  Not able to allocate memory for image." << std::endl;
    154 	  }
    155      }
    156 
    157    if(graph_ == NULL)
    158      {
    159 	std::cerr << " PNGwriter::pngwriter - ERROR **:  Not able to allocate memory for image." << std::endl;
    160      }
    161    int tempindex;
    162    for(int hhh = 0; hhh<width_;hhh++)
    163      {
    164 	for(int vhhh = 0; vhhh<height_;vhhh++)
    165 	  {
    166 	     //   graph_[vhhh][6*hhh + i ] i=0 to 5
    167 	     tempindex=6*hhh;
    168 	     graph_[vhhh][tempindex] = rhs.graph_[vhhh][tempindex];
    169 	     graph_[vhhh][tempindex+1] = rhs.graph_[vhhh][tempindex+1];
    170 	     graph_[vhhh][tempindex+2] = rhs.graph_[vhhh][tempindex+2];
    171 	     graph_[vhhh][tempindex+3] = rhs.graph_[vhhh][tempindex+3];
    172 	     graph_[vhhh][tempindex+4] = rhs.graph_[vhhh][tempindex+4];
    173 	     graph_[vhhh][tempindex+5] = rhs.graph_[vhhh][tempindex+5];
    174 	  }
    175      }
    176 
    177 };
    178 
    179 //Constructor for int colour levels, char * filename
    180 //////////////////////////////////////////////////////////////////////////
    181 pngwriter::pngwriter(int x, int y, int backgroundcolour, char * filename)
    182 {
    183    width_ = x;
    184    height_ = y;
    185    backgroundcolour_ = backgroundcolour;
    186    compressionlevel_ = -2;
    187    filegamma_ = 0.6;
    188    transformation_ = 0;
    189 
    190    textauthor_ = new char[255];
    191    textdescription_ = new char[255];
    192    texttitle_ = new char[strlen(filename)+1];
    193    textsoftware_ = new char[255];
    194    filename_ = new char[strlen(filename)+1];
    195 
    196    strcpy(textauthor_, "PNGwriter Author: Paul Blackburn");
    197    strcpy(textdescription_, "http://pngwriter.sourceforge.net/");
    198    strcpy(textsoftware_, "PNGwriter: An easy to use graphics library.");
    199    strcpy(texttitle_, filename);
    200    strcpy(filename_, filename);
    201 
    202    if((width_<0)||(height_<0))
    203      {
    204 	std::cerr << " PNGwriter::pngwriter - ERROR **: Constructor called with negative height or width. Setting width and height to 1." << std::endl;
    205 	width_ = 1;
    206 	height_ = 1;
    207      }
    208 
    209    if(backgroundcolour_ >65535)
    210      {
    211 	std::cerr << " PNGwriter::pngwriter - WARNING **: Constructor called with background colour greater than 65535. Setting to 65535."<<std::endl;
    212 	backgroundcolour_ = 65535;
    213      }
    214 
    215    if(backgroundcolour_ <0)
    216      {
    217 	std::cerr << " PNGwriter::pngwriter - WARNING **: Constructor called with background colour lower than 0. Setting to 0."<<std::endl;
    218 	backgroundcolour_ = 0;
    219      }
    220 
    221    int kkkk;
    222 
    223    bit_depth_ = 16; //Default bit depth for new images
    224    colortype_=2;
    225    screengamma_ = 2.2;
    226 
    227    graph_ = (png_bytepp)malloc(height_ * sizeof(png_bytep));
    228    if(graph_ == NULL)
    229      {
    230 	std::cerr << " PNGwriter::pngwriter - ERROR **:  Not able to allocate memory for image." << std::endl;
    231      }
    232 
    233    for (kkkk = 0; kkkk < height_; kkkk++)
    234      {
    235         graph_[kkkk] = (png_bytep)malloc(6*width_ * sizeof(png_byte));
    236 	if(graph_[kkkk] == NULL)
    237 	  {
    238 	     std::cerr << " PNGwriter::pngwriter - ERROR **:  Not able to allocate memory for image." << std::endl;
    239 	  }
    240      }
    241 
    242    if(graph_ == NULL)
    243      {
    244 	std::cerr << " PNGwriter::pngwriter - ERROR **:  Not able to allocate memory for image." << std::endl;
    245      }
    246 
    247    int tempindex;
    248    for(int hhh = 0; hhh<width_;hhh++)
    249      {
    250 	for(int vhhh = 0; vhhh<height_;vhhh++)
    251 	  {
    252 	     //graph_[vhhh][6*hhh + i] i = 0  to 5
    253 	     tempindex = 6*hhh;
    254 	     graph_[vhhh][tempindex] = (char) floor(((double)backgroundcolour_)/256);
    255 	     graph_[vhhh][tempindex+1] = (char)(backgroundcolour_%256);
    256 	     graph_[vhhh][tempindex+2] = (char) floor(((double)backgroundcolour_)/256);
    257 	     graph_[vhhh][tempindex+3] = (char)(backgroundcolour_%256);
    258 	     graph_[vhhh][tempindex+4] = (char) floor(((double)backgroundcolour_)/256);
    259 	     graph_[vhhh][tempindex+5] = (char)(backgroundcolour_%256);
    260 	  }
    261      }
    262 
    263 };
    264 
    265 //Constructor for double levels, char * filename
    266 /////////////////////////////////////////////////////////////////////////
    267 pngwriter::pngwriter(int x, int y, double backgroundcolour, char * filename)
    268 {
    269    width_ = x;
    270    height_ = y;
    271    compressionlevel_ = -2;
    272    filegamma_ = 0.6;
    273    transformation_ = 0;
    274    backgroundcolour_ = int(backgroundcolour*65535);
    275 
    276    textauthor_ = new char[255];
    277    textdescription_ = new char[255];
    278    texttitle_ = new char[strlen(filename)+1];
    279    textsoftware_ = new char[255];
    280    filename_ = new char[strlen(filename)+1];
    281 
    282    strcpy(textauthor_, "PNGwriter Author: Paul Blackburn");
    283    strcpy(textdescription_, "http://pngwriter.sourceforge.net/");
    284    strcpy(textsoftware_, "PNGwriter: An easy to use graphics library.");
    285    strcpy(texttitle_, filename);
    286    strcpy(filename_, filename);
    287 
    288    if((width_<0)||(height_<0))
    289      {
    290 	std::cerr << " PNGwriter::pngwriter - ERROR **: Constructor called with negative height or width. Setting width and height to 1." << std::endl;
    291 	width_ = 1;
    292 	height_ = 1;
    293      }
    294 
    295    if(backgroundcolour_ >65535)
    296      {
    297 	std::cerr << " PNGwriter::pngwriter - WARNING **: Constructor called with background colour greater than 1.0. Setting to 1.0."<<std::endl;
    298 	backgroundcolour_ = 65535;
    299      }
    300 
    301    if(backgroundcolour_ < 0)
    302      {
    303 	std::cerr << " PNGwriter::pngwriter - WARNING **: Constructor called with background colour lower than 0.0. Setting to 0.0."<<std::endl;
    304 	backgroundcolour_ = 0;
    305      }
    306 
    307    int kkkk;
    308 
    309    bit_depth_ = 16; //Default bit depth for new images
    310    colortype_=2;
    311    screengamma_ = 2.2;
    312 
    313    graph_ = (png_bytepp)malloc(height_ * sizeof(png_bytep));
    314    if(graph_ == NULL)
    315      {
    316 	std::cerr << " PNGwriter::pngwriter - ERROR **:  Not able to allocate memory for image." << std::endl;
    317      }
    318 
    319    for (kkkk = 0; kkkk < height_; kkkk++)
    320      {
    321         graph_[kkkk] = (png_bytep)malloc(6*width_ * sizeof(png_byte));
    322 	if(graph_[kkkk] == NULL)
    323 	  {
    324 	     std::cerr << " PNGwriter::pngwriter - ERROR **:  Not able to allocate memory for image." << std::endl;
    325 	  }
    326      }
    327 
    328    if(graph_ == NULL)
    329      {
    330 	std::cerr << " PNGwriter::pngwriter - ERROR **:  Not able to allocate memory for image." << std::endl;
    331      }
    332 
    333    int tempindex;
    334    for(int hhh = 0; hhh<width_;hhh++)
    335      {
    336 	for(int vhhh = 0; vhhh<height_;vhhh++)
    337 	  {
    338 	     // graph_[vhhh][tempindex + i] where i = 0 to 5
    339 	     tempindex = 6*hhh;
    340 	     graph_[vhhh][tempindex] = (char) floor(((double)backgroundcolour_)/256);
    341 	     graph_[vhhh][tempindex+1] = (char)(backgroundcolour_%256);
    342 	     graph_[vhhh][tempindex+2] = (char) floor(((double)backgroundcolour_)/256);
    343 	     graph_[vhhh][tempindex+3] = (char)(backgroundcolour_%256);
    344 	     graph_[vhhh][tempindex+4] = (char) floor(((double)backgroundcolour_)/256);
    345 	     graph_[vhhh][tempindex+5] = (char)(backgroundcolour_%256);
    346 	  }
    347      }
    348 
    349 };
    350 
    351 //Destructor
    352 ///////////////////////////////////////
    353 pngwriter::~pngwriter()
    354 {
    355    delete [] filename_;
    356    delete [] textauthor_;
    357    delete [] textdescription_;
    358    delete [] texttitle_;
    359    delete [] textsoftware_;
    360 
    361    for (int jjj = 0; jjj < height_; jjj++) free(graph_[jjj]);
    362    free(graph_);
    363 };
    364 
    365 //Constructor for int levels, const char * filename
    366 //////////////////////////////////////////////////////////////
    367 pngwriter::pngwriter(int x, int y, int backgroundcolour, const char * filename)
    368 {
    369    width_ = x;
    370    height_ = y;
    371    backgroundcolour_ = backgroundcolour;
    372    compressionlevel_ = -2;
    373    filegamma_ = 0.6;
    374    transformation_ = 0;
    375 
    376    textauthor_ = new char[255];
    377    textdescription_ = new char[255];
    378    texttitle_ = new char[strlen(filename)+1];
    379    textsoftware_ = new char[255];
    380    filename_ = new char[strlen(filename)+1];
    381 
    382    strcpy(textauthor_, "PNGwriter Author: Paul Blackburn");
    383    strcpy(textdescription_, "http://pngwriter.sourceforge.net/");
    384    strcpy(textsoftware_, "PNGwriter: An easy to use graphics library.");
    385    strcpy(texttitle_, filename);
    386    strcpy(filename_, filename);
    387 
    388    if((width_<0)||(height_<0))
    389      {
    390 	std::cerr << " PNGwriter::pngwriter - ERROR **: Constructor called with negative height or width. Setting width and height to 1." << std::endl;
    391 	height_ = 1;
    392 	width_ = 1;
    393      }
    394 
    395    if(backgroundcolour_ >65535)
    396      {
    397 	std::cerr << " PNGwriter::pngwriter - WARNING **: Constructor called with background colour greater than 65535. Setting to 65535."<<std::endl;
    398 	backgroundcolour_ = 65535;
    399      }
    400 
    401    if(backgroundcolour_ <0)
    402      {
    403 	std::cerr << " PNGwriter::pngwriter - WARNING **: Constructor called with background colour lower than 0. Setting to 0."<<std::endl;
    404 	backgroundcolour_ = 0;
    405      }
    406 
    407    int kkkk;
    408 
    409    bit_depth_ = 16; //Default bit depth for new images
    410    colortype_=2;
    411    screengamma_ = 2.2;
    412 
    413    graph_ = (png_bytepp)malloc(height_ * sizeof(png_bytep));
    414    if(graph_ == NULL)
    415      {
    416 	std::cerr << " PNGwriter::pngwriter - ERROR **:  Not able to allocate memory for image." << std::endl;
    417      }
    418 
    419    for (kkkk = 0; kkkk < height_; kkkk++)
    420      {
    421         graph_[kkkk] = (png_bytep)malloc(6*width_ * sizeof(png_byte));
    422 	if(graph_[kkkk] == NULL)
    423 	  {
    424 	     std::cerr << " PNGwriter::pngwriter - ERROR **:  Not able to allocate memory for image." << std::endl;
    425 	  }
    426      }
    427 
    428    if(graph_ == NULL)
    429      {
    430 	std::cerr << " PNGwriter::pngwriter - ERROR **:  Not able to allocate memory for image." << std::endl;
    431      }
    432 
    433    int tempindex;
    434    for(int hhh = 0; hhh<width_;hhh++)
    435      {
    436 	for(int vhhh = 0; vhhh<height_;vhhh++)
    437 	  {
    438 	     //graph_[vhhh][6*hhh + i] where i = 0 to 5
    439 	     tempindex=6*hhh;
    440 	     graph_[vhhh][tempindex] = (char) floor(((double)backgroundcolour_)/256);
    441 	     graph_[vhhh][tempindex+1] = (char)(backgroundcolour_%256);
    442 	     graph_[vhhh][tempindex+2] = (char) floor(((double)backgroundcolour_)/256);
    443 	     graph_[vhhh][tempindex+3] = (char)(backgroundcolour_%256);
    444 	     graph_[vhhh][tempindex+4] = (char) floor(((double)backgroundcolour_)/256);
    445 	     graph_[vhhh][tempindex+5] = (char)(backgroundcolour_%256);
    446 	  }
    447      }
    448 
    449 };
    450 
    451 //Constructor for double levels, const char * filename
    452 /////////////////////////////////////////////////////////////////////////
    453 pngwriter::pngwriter(int x, int y, double backgroundcolour, const char * filename)
    454 {
    455    width_ = x;
    456    height_ = y;
    457    compressionlevel_ = -2;
    458    backgroundcolour_ = int(backgroundcolour*65535);
    459    filegamma_ = 0.6;
    460    transformation_ = 0;
    461 
    462    textauthor_ = new char[255];
    463    textdescription_ = new char[255];
    464    texttitle_ = new char[strlen(filename)+1];
    465    textsoftware_ = new char[255];
    466    filename_ = new char[strlen(filename)+1];
    467 
    468    strcpy(textauthor_, "PNGwriter Author: Paul Blackburn");
    469    strcpy(textdescription_, "http://pngwriter.sourceforge.net/");
    470    strcpy(textsoftware_, "PNGwriter: An easy to use graphics library.");
    471    strcpy(texttitle_, filename);
    472    strcpy(filename_, filename);
    473 
    474    if((width_<0)||(height_<0))
    475      {
    476 	std::cerr << " PNGwriter::pngwriter - ERROR **: Constructor called with negative height or width. Setting width and height to 1." << std::endl;
    477 	width_ = 1;
    478 	height_ = 1;
    479      }
    480 
    481    if(backgroundcolour_ >65535)
    482      {
    483 	std::cerr << " PNGwriter::pngwriter - WARNING **: Constructor called with background colour greater than 65535. Setting to 65535."<<std::endl;
    484 	backgroundcolour_ = 65535;
    485      }
    486 
    487    if(backgroundcolour_ <0)
    488      {
    489 	std::cerr << " PNGwriter::pngwriter - WARNING **: Constructor called with background colour lower than 0. Setting to 0."<<std::endl;
    490 	backgroundcolour_ = 0;
    491      }
    492 
    493    int kkkk;
    494 
    495    bit_depth_ = 16; //Default bit depth for new images
    496    colortype_=2;
    497    screengamma_ = 2.2;
    498 
    499    graph_ = (png_bytepp)malloc(height_ * sizeof(png_bytep));
    500    if(graph_ == NULL)
    501      {
    502 	std::cerr << " PNGwriter::pngwriter - ERROR **:  Not able to allocate memory for image." << std::endl;
    503      }
    504 
    505    for (kkkk = 0; kkkk < height_; kkkk++)
    506      {
    507         graph_[kkkk] = (png_bytep)malloc(6*width_ * sizeof(png_byte));
    508 	if(graph_[kkkk] == NULL)
    509 	  {
    510 	     std::cerr << " PNGwriter::pngwriter - ERROR **:  Not able to allocate memory for image." << std::endl;
    511 	  }
    512      }
    513 
    514    if(graph_ == NULL)
    515      {
    516 	std::cerr << " PNGwriter::pngwriter - ERROR **:  Not able to allocate memory for image." << std::endl;
    517      }
    518 
    519    int tempindex;
    520    for(int hhh = 0; hhh<width_;hhh++)
    521      {
    522 	for(int vhhh = 0; vhhh<height_;vhhh++)
    523 	  {
    524 	     //etc
    525 	     tempindex = 6*hhh;
    526 	     graph_[vhhh][tempindex] = (char) floor(((double)backgroundcolour_)/256);
    527 	     graph_[vhhh][tempindex+1] = (char)(backgroundcolour_%256);
    528 	     graph_[vhhh][tempindex+2] = (char) floor(((double)backgroundcolour_)/256);
    529 	     graph_[vhhh][tempindex+3] = (char)(backgroundcolour_%256);
    530 	     graph_[vhhh][tempindex+4] = (char) floor(((double)backgroundcolour_)/256);
    531 	     graph_[vhhh][tempindex+5] = (char)(backgroundcolour_%256);
    532 	  }
    533      }
    534 
    535 };
    536 
    537 // Overloading operator =
    538 /////////////////////////////////////////////////////////
    539 pngwriter & pngwriter::operator = (const pngwriter & rhs)
    540 {
    541    if( this==&rhs)
    542      {
    543 	return *this;
    544      }
    545 
    546    width_ = rhs.width_;
    547    height_ = rhs.height_;
    548    backgroundcolour_ = rhs.backgroundcolour_;
    549    compressionlevel_ = rhs.compressionlevel_;
    550    filegamma_ = rhs.filegamma_;
    551    transformation_ = rhs.transformation_;
    552 
    553    filename_ = new char[strlen(rhs.filename_)+1];
    554    textauthor_ = new char[strlen(rhs.textauthor_)+1];
    555    textdescription_ = new char[strlen(rhs.textdescription_)+1];
    556    textsoftware_ = new char[strlen(rhs.textsoftware_)+1];
    557    texttitle_ = new char[strlen(rhs.texttitle_)+1];
    558 
    559    strcpy(textauthor_, rhs.textauthor_);
    560    strcpy(textdescription_, rhs.textdescription_);
    561    strcpy(textsoftware_,rhs.textsoftware_);
    562    strcpy(texttitle_, rhs.texttitle_);
    563    strcpy(filename_, rhs.filename_);
    564 
    565    int kkkk;
    566 
    567    bit_depth_ = rhs.bit_depth_;
    568    colortype_= rhs.colortype_;
    569    screengamma_ = rhs.screengamma_;
    570 
    571    graph_ = (png_bytepp)malloc(height_ * sizeof(png_bytep));
    572    if(graph_ == NULL)
    573      {
    574 	std::cerr << " PNGwriter::pngwriter - ERROR **:  Not able to allocate memory for image." << std::endl;
    575      }
    576 
    577    for (kkkk = 0; kkkk < height_; kkkk++)
    578      {
    579         graph_[kkkk] = (png_bytep)malloc(6*width_ * sizeof(png_byte));
    580 	if(graph_[kkkk] == NULL)
    581 	  {
    582 	     std::cerr << " PNGwriter::pngwriter - ERROR **:  Not able to allocate memory for image." << std::endl;
    583 	  }
    584      }
    585 
    586    if(graph_ == NULL)
    587      {
    588 	std::cerr << " PNGwriter::pngwriter - ERROR **:  Not able to allocate memory for image." << std::endl;
    589      }
    590 
    591    int tempindex;
    592    for(int hhh = 0; hhh<width_;hhh++)
    593      {
    594 	for(int vhhh = 0; vhhh<height_;vhhh++)
    595 	  {
    596 	     tempindex=6*hhh;
    597 	     graph_[vhhh][tempindex] = rhs.graph_[vhhh][tempindex];
    598 	     graph_[vhhh][tempindex+1] = rhs.graph_[vhhh][tempindex+1];
    599 	     graph_[vhhh][tempindex+2] = rhs.graph_[vhhh][tempindex+2];
    600 	     graph_[vhhh][tempindex+3] = rhs.graph_[vhhh][tempindex+3];
    601 	     graph_[vhhh][tempindex+4] = rhs.graph_[vhhh][tempindex+4];
    602 	     graph_[vhhh][tempindex+5] = rhs.graph_[vhhh][tempindex+5];
    603 	  }
    604      }
    605 
    606    return *this;
    607 }
    608 
    609 ///////////////////////////////////////////////////////////////
    610 void pngwriter::plot(int x, int y, int red, int green, int blue)
    611 {
    612    int tempindex;
    613 
    614    if(red > 65535)
    615      {
    616 	red = 65535;
    617      }
    618    if(green > 65535)
    619      {
    620 	green = 65535;
    621      }
    622    if(blue > 65535)
    623      {
    624 	blue = 65535;
    625      }
    626 
    627    if(red < 0)
    628      {
    629 	red = 0;
    630      }
    631    if(green < 0)
    632      {
    633 	green = 0;
    634      }
    635    if(blue < 0)
    636      {
    637 	blue = 0;
    638      }
    639 
    640    if((bit_depth_ == 16))
    641      {
    642 	//	if( (height_-y >-1) && (height_-y <height_) && (6*(x-1) >-1) && (6*(x-1)+5<6*width_) )
    643 	if( (y<=height_) && (y>0) && (x>0) && (x<=width_) )
    644 	  {
    645 	     //graph_[height_-y][6*(x-1) + i] where i goes from 0 to 5
    646 	     tempindex= 6*x-6;
    647 	     graph_[height_-y][tempindex] = (char) floor(((double)red)/256);
    648 	     graph_[height_-y][tempindex+1] = (char)(red%256);
    649 	     graph_[height_-y][tempindex+2] = (char) floor(((double)green)/256);
    650 	     graph_[height_-y][tempindex+3] = (char)(green%256);
    651 	     graph_[height_-y][tempindex+4] = (char) floor(((double)blue)/256);
    652 	     graph_[height_-y][tempindex+5] = (char)(blue%256);
    653 	  };
    654 
    655 	/*
    656 	 if(!( (height_-y >-1) && (height_-y <height_) && (6*(x-1) >-1) && (6*(x-1)+5<6*width_) ))
    657 	 {
    658 	 std::cerr << " PNGwriter::plot-- Plotting out of range! " << y << "   " << x << std::endl;
    659 	 }
    660 	 */
    661      }
    662 
    663    if((bit_depth_ == 8))
    664      {
    665 	//	 if( (height_-y >-1) && (height_-y <height_) && (3*(x-1) >-1) && (3*(x-1)+5<3*width_) )
    666 	if( (y<height_+1) && (y>0) && (x>0) && (x<width_+1) )
    667 	  {
    668 	     //	     graph_[height_-y][3*(x-1) + i] where i goes from 0 to 2
    669 	     tempindex = 3*x-3;
    670 	     graph_[height_-y][tempindex] = (char)(floor(((double)red)/257.0));
    671 	     graph_[height_-y][tempindex+1] = (char)(floor(((double)green)/257.0));
    672 	     graph_[height_-y][tempindex+2] = (char)(floor(((double)blue)/257.0));
    673 
    674 	  };
    675 
    676 	/*
    677 	 if(!( (height_-y >-1) && (height_-y <height_) && (6*(x-1) >-1) && (6*(x-1)+5<6*width_) ))
    678 	 {
    679 	 std::cerr << " PNGwriter::plot-- Plotting out of range! " << y << "   " << x << std::endl;
    680 	 }
    681 	 */
    682      }
    683 };
    684 
    685 void pngwriter::plot(int x, int y, double red, double green, double blue)
    686 {
    687    this->plot(x,y,int(red*65535),int(green*65535),int(blue*65535));
    688 };
    689 
    690 ///////////////////////////////////////////////////////////////
    691 int pngwriter::read(int x, int y, int colour)
    692 {
    693    int temp1,temp2;
    694 
    695    if((colour !=1)&&(colour !=2)&&(colour !=3))
    696      {
    697 	std::cerr << " PNGwriter::read - WARNING **: Invalid argument: should be 1, 2 or 3, is " << colour << std::endl;
    698 	return 0;
    699      }
    700 
    701    if( ( x>0 ) && ( x <= (this->width_) ) && ( y>0 ) && ( y <= (this->height_) ) )
    702      {
    703 
    704 	if(bit_depth_ == 16)
    705 	  {
    706 	     temp2=6*(x-1);
    707 	     if(colour == 1)
    708 	       {
    709 		  temp1 = (graph_[(height_-y)][temp2])*256 + graph_[height_-y][temp2+1];
    710 		  return temp1;
    711 	       }
    712 
    713 	     if(colour == 2)
    714 	       {
    715 		  temp1 = (graph_[height_-y][temp2+2])*256 + graph_[height_-y][temp2+3];
    716 		  return temp1;
    717 	       }
    718 
    719 	     if(colour == 3)
    720 	       {
    721 		  temp1 = (graph_[height_-y][temp2+4])*256 + graph_[height_-y][temp2+5];
    722 		  return temp1;
    723 	       }
    724 	  }
    725 
    726 	if(bit_depth_ == 8)
    727 	  {
    728 	     temp2=3*(x-1);
    729 	     if(colour == 1)
    730 	       {
    731 		  temp1 = graph_[height_-y][temp2];
    732 		  return temp1*256;
    733 	       }
    734 
    735 	     if(colour == 2)
    736 	       {
    737 		  temp1 =  graph_[height_-y][temp2+1];
    738 		  return temp1*256;
    739 	       }
    740 
    741 	     if(colour == 3)
    742 	       {
    743 		  temp1 =  graph_[height_-y][temp2+2];
    744 		  return temp1*256;
    745 	       }
    746 	  }
    747      }
    748    else
    749      {
    750 	return 0;
    751      }
    752 
    753    std::cerr << " PNGwriter::read - WARNING **: Returning 0 because of bitdepth/colour type mismatch."<< std::endl;
    754    return 0;
    755 }
    756 
    757 ///////////////////////////////////////////////////////////////
    758 int pngwriter::read(int xxx, int yyy)
    759 {
    760    int temp1,temp2,temp3,temp4,temp5;
    761 
    762    if(
    763       ( xxx>0 ) &&
    764       ( xxx <= (this->width_) ) &&
    765       ( yyy>0 ) &&
    766       ( yyy <= (this->height_) )
    767       )
    768      {
    769 	if(bit_depth_ == 16)
    770 	  {
    771 	     //	temp1 = (graph_[(height_-yyy)][6*(xxx-1)])*256 + graph_[height_-yyy][6*(xxx-1)+1];
    772 	     temp5=6*xxx;
    773 	     temp1 = (graph_[(height_-yyy)][temp5-6])*256 + graph_[height_-yyy][temp5-5];
    774 	     temp2 = (graph_[height_-yyy][temp5-4])*256 + graph_[height_-yyy][temp5-3];
    775 	     temp3 = (graph_[height_-yyy][temp5-2])*256 + graph_[height_-yyy][temp5-1];
    776 	     temp4 =  int((temp1+temp2+temp3)/3.0);
    777 	  }
    778 	else if(bit_depth_ == 8)
    779 	  {
    780 	     //	temp1 = graph_[height_-yyy][3*(xxx-1)];
    781 	     temp5 = 3*xxx;
    782 	     temp1 = graph_[height_-yyy][temp5-3];
    783 	     temp2 =  graph_[height_-yyy][temp5-2];
    784 	     temp3 =  graph_[height_-yyy][temp5-1];
    785 	     temp4 =  int((temp1+temp2+temp3)/3.0);
    786 	  }
    787 	else
    788 	  {
    789 	     std::cerr << " PNGwriter::read - WARNING **: Invalid bit depth! Returning 0 as average value." << std::endl;
    790 	     temp4 = 0;
    791 	  }
    792 
    793 	return temp4;
    794 
    795      }
    796    else
    797      {
    798 	return 0;
    799      }
    800 }
    801 
    802 /////////////////////////////////////////////////////
    803 double  pngwriter::dread(int x, int y, int colour)
    804 {
    805    return double(this->read(x,y,colour))/65535.0;
    806 }
    807 
    808 double  pngwriter::dread(int x, int y)
    809 {
    810    return double(this->read(x,y))/65535.0;
    811 }
    812 
    813 ///////////////////////////////////////////////////////
    814 void pngwriter::clear()
    815 {
    816    int pen = 0;
    817    int pencil = 0;
    818    int tempindex;
    819 
    820    if(bit_depth_==16)
    821      {
    822 	for(pen = 0; pen<width_;pen++)
    823 	  {
    824 	     for(pencil = 0; pencil<height_;pencil++)
    825 	       {
    826 		  tempindex=6*pen;
    827 		  graph_[pencil][tempindex] = 0;
    828 		  graph_[pencil][tempindex+1] = 0;
    829 		  graph_[pencil][tempindex+2] = 0;
    830 		  graph_[pencil][tempindex+3] = 0;
    831 		  graph_[pencil][tempindex+4] = 0;
    832 		  graph_[pencil][tempindex+5] = 0;
    833 	       }
    834 	  }
    835      }
    836 
    837    if(bit_depth_==8)
    838      {
    839 	for(pen = 0; pen<width_;pen++)
    840 	  {
    841 	     for(pencil = 0; pencil<height_;pencil++)
    842 	       {
    843 		  tempindex=3*pen;
    844 		  graph_[pencil][tempindex] = 0;
    845 		  graph_[pencil][tempindex+1] = 0;
    846 		  graph_[pencil][tempindex+2] = 0;
    847 	       }
    848 	  }
    849      }
    850 
    851 };
    852 
    853 /////////////////////////////////////////////////////
    854 void pngwriter::pngwriter_rename(char * newname)
    855 {
    856    delete [] filename_;
    857    delete [] texttitle_;
    858 
    859    filename_ = new char[strlen(newname)+1];
    860    texttitle_ = new char[strlen(newname)+1];
    861 
    862    strcpy(filename_,newname);
    863    strcpy(texttitle_,newname);
    864 };
    865 
    866 ///////////////////////////////////////////////////////
    867 void pngwriter::pngwriter_rename(const char * newname)
    868 {
    869    delete [] filename_;
    870    delete [] texttitle_;
    871 
    872    filename_ = new char[strlen(newname)+1];
    873    texttitle_ = new char[strlen(newname)+1];
    874 
    875    strcpy(filename_,newname);
    876    strcpy(texttitle_,newname);
    877 };
    878 
    879 ///////////////////////////////////////////////////////
    880 void pngwriter::pngwriter_rename(long unsigned int index)
    881 {
    882    char buffer[255];
    883 
    884    //   %[flags][width][.precision][modifiers]type
    885    //
    886    if((index > 999999999)||(index < 0))
    887      {
    888 	std::cerr << " PNGwriter::pngwriter_rename - ERROR **: Numerical name is out of 0 - 999 999 999 range (" << index <<")." << std::endl;
    889 	return;
    890      }
    891 
    892    if( 0>  sprintf(buffer, "%9.9lu.png",index))
    893      {
    894 	std::cerr << " PNGwriter::pngwriter_rename - ERROR **: Error creating numerical filename." << std::endl;
    895 	return;
    896      }
    897 
    898    delete [] filename_;
    899    delete [] texttitle_;
    900 
    901    filename_ = new char[strlen(buffer)+1];
    902    texttitle_ = new char[strlen(buffer)+1];
    903 
    904    strcpy(filename_,buffer);
    905    strcpy(texttitle_,buffer);
    906 
    907 };
    908 
    909 ///////////////////////////////////////////////////////
    910 void pngwriter::settext(char * title, char * author, char * description, char * software)
    911 {
    912    delete [] textauthor_;
    913    delete [] textdescription_;
    914    delete [] texttitle_;
    915    delete [] textsoftware_;
    916 
    917    textauthor_ = new char[strlen(author)+1];
    918    textdescription_ = new char[strlen(description)+1];
    919    textsoftware_ = new char[strlen(software)+1];
    920    texttitle_ = new char[strlen(title)+1];
    921 
    922    strcpy(texttitle_, title);
    923    strcpy(textauthor_, author);
    924    strcpy(textdescription_, description);
    925    strcpy(textsoftware_, software);
    926 };
    927 
    928 ///////////////////////////////////////////////////////
    929 void pngwriter::settext(const char * title, const char * author, const char * description, const char * software)
    930 {
    931    delete [] textauthor_;
    932    delete [] textdescription_;
    933    delete [] texttitle_;
    934    delete [] textsoftware_;
    935 
    936    textauthor_ = new char[strlen(author)+1];
    937    textdescription_ = new char[strlen(description)+1];
    938    textsoftware_ = new char[strlen(software)+1];
    939    texttitle_ = new char[strlen(title)+1];
    940 
    941    strcpy(texttitle_, title);
    942    strcpy(textauthor_, author);
    943    strcpy(textdescription_, description);
    944    strcpy(textsoftware_, software);
    945 };
    946 
    947 ///////////////////////////////////////////////////////
    948 void pngwriter::close()
    949 {
    950    FILE            *fp;
    951    png_structp     png_ptr;
    952    png_infop       info_ptr;
    953 
    954    fp = fopen(filename_, "wb");
    955    if( fp == NULL)
    956      {
    957 	std::cerr << " PNGwriter::close - ERROR **: Error creating file (fopen() returned NULL pointer)." << std::endl;
    958 	perror(" PNGwriter::close - ERROR **");
    959 	return;
    960      }
    961 
    962    png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    963    info_ptr = png_create_info_struct(png_ptr);
    964    png_init_io(png_ptr, fp);
    965    if(compressionlevel_ != -2)
    966      {
    967 	png_set_compression_level(png_ptr, compressionlevel_);
    968      }
    969    else
    970      {
    971 	png_set_compression_level(png_ptr, PNGWRITER_DEFAULT_COMPRESSION);
    972      }
    973 
    974    png_set_IHDR(png_ptr, info_ptr, width_, height_,
    975 		bit_depth_, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
    976 		PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
    977 
    978    if(filegamma_ < 1.0e-1)
    979      {
    980 	filegamma_ = 0.5;  // Modified in 0.5.4 so as to be the same as the usual gamma.
    981      }
    982 
    983    png_set_gAMA(png_ptr, info_ptr, filegamma_);
    984 
    985    time_t          gmt;
    986    png_time        mod_time;
    987    png_text        text_ptr[5];
    988    time(&gmt);
    989    png_convert_from_time_t(&mod_time, gmt);
    990    png_set_tIME(png_ptr, info_ptr, &mod_time);
    991    text_ptr[0].key = "Title";
    992    text_ptr[0].text = texttitle_;
    993    text_ptr[0].compression = PNG_TEXT_COMPRESSION_NONE;
    994    text_ptr[1].key = "Author";
    995    text_ptr[1].text = textauthor_;
    996    text_ptr[1].compression = PNG_TEXT_COMPRESSION_NONE;
    997    text_ptr[2].key = "Description";
    998    text_ptr[2].text = textdescription_;
    999    text_ptr[2].compression = PNG_TEXT_COMPRESSION_NONE;
   1000    text_ptr[3].key = "Creation Time";
   1001    text_ptr[3].text = png_convert_to_rfc1123(png_ptr, &mod_time);
   1002    text_ptr[3].compression = PNG_TEXT_COMPRESSION_NONE;
   1003    text_ptr[4].key = "Software";
   1004    text_ptr[4].text = textsoftware_;
   1005    text_ptr[4].compression = PNG_TEXT_COMPRESSION_NONE;
   1006    png_set_text(png_ptr, info_ptr, text_ptr, 5);
   1007 
   1008    png_write_info(png_ptr, info_ptr);
   1009    png_write_image(png_ptr, graph_);
   1010    png_write_end(png_ptr, info_ptr);
   1011    png_destroy_write_struct(&png_ptr, &info_ptr);
   1012    fclose(fp);
   1013 }
   1014 
   1015 //////////////////////////////////////////////////////
   1016 void pngwriter::line(int xfrom, int yfrom, int xto, int yto, int red, int green,int  blue)
   1017 {
   1018    //  Bresenham Algorithm.
   1019    //
   1020    int dy = yto - yfrom;
   1021    int dx = xto - xfrom;
   1022    int stepx, stepy;
   1023 
   1024    if (dy < 0)
   1025      {
   1026 	dy = -dy;  stepy = -1;
   1027      }
   1028    else
   1029      {
   1030 	stepy = 1;
   1031      }
   1032 
   1033    if (dx < 0)
   1034      {
   1035 	dx = -dx;  stepx = -1;
   1036      }
   1037    else
   1038      {
   1039 	stepx = 1;
   1040      }
   1041    dy <<= 1;     // dy is now 2*dy
   1042    dx <<= 1;     // dx is now 2*dx
   1043 
   1044    this->plot(xfrom,yfrom,red,green,blue);
   1045 
   1046    if (dx > dy)
   1047      {
   1048 	int fraction = dy - (dx >> 1);
   1049 
   1050 	while (xfrom != xto)
   1051 	  {
   1052 	     if (fraction >= 0)
   1053 	       {
   1054 		  yfrom += stepy;
   1055 		  fraction -= dx;
   1056 	       }
   1057 	     xfrom += stepx;
   1058 	     fraction += dy;
   1059 	     this->plot(xfrom,yfrom,red,green,blue);
   1060 	  }
   1061      }
   1062    else
   1063      {
   1064 	int fraction = dx - (dy >> 1);
   1065 	while (yfrom != yto)
   1066 	  {
   1067 	     if (fraction >= 0)
   1068 	       {
   1069 		  xfrom += stepx;
   1070 		  fraction -= dy;
   1071 	       }
   1072 	     yfrom += stepy;
   1073 	     fraction += dx;
   1074 	     this->plot(xfrom,yfrom,red,green,blue);
   1075 	  }
   1076      }
   1077 
   1078 }
   1079 
   1080 void pngwriter::line(int xfrom, int yfrom, int xto, int yto, double red, double green,double  blue)
   1081 {
   1082    this->line( xfrom,
   1083 	       yfrom,
   1084 	       xto,
   1085 	       yto,
   1086 	       int (red*65535),
   1087 	       int (green*65535),
   1088 	       int (blue*65535)
   1089 	       );
   1090 }
   1091 
   1092 ///////////////////////////////////////////////////////////////////////////////////////////
   1093 void pngwriter::square(int xfrom, int yfrom, int xto, int yto, int red, int green, int blue)
   1094 {
   1095    this->line(xfrom, yfrom, xfrom, yto, red, green, blue);
   1096    this->line(xto, yfrom, xto, yto, red, green, blue);
   1097    this->line(xfrom, yfrom, xto, yfrom, red, green, blue);
   1098    this->line(xfrom, yto, xto, yto, red, green, blue);
   1099 }
   1100 
   1101 void pngwriter::square(int xfrom, int yfrom, int xto, int yto, double red, double green, double blue)
   1102 {
   1103    this->square( xfrom,  yfrom,  xto,  yto, int(red*65535), int(green*65535), int(blue*65535));
   1104 }
   1105 
   1106 //////////////////////////////////////////////////////////////////////////////////////////////////
   1107 void pngwriter::filledsquare(int xfrom, int yfrom, int xto, int yto, int red, int green, int blue)
   1108 {
   1109    for(int caca = xfrom; caca <xto+1; caca++)
   1110      {
   1111 	this->line(caca, yfrom, caca, yto, red, green, blue);
   1112      }
   1113 }
   1114 
   1115 void pngwriter::filledsquare(int xfrom, int yfrom, int xto, int yto, double red, double green, double blue)
   1116 {
   1117    this->filledsquare( xfrom,  yfrom,  xto,  yto, int(red*65535), int(green*65535), int(blue*65535));
   1118 }
   1119 
   1120 //////////////////////////////////////////////////////////////////////////////////////////////////
   1121 void pngwriter::circle(int xcentre, int ycentre, int radius, int red, int green, int blue)
   1122 {
   1123    int x = 0;
   1124    int y = radius;
   1125    int p = (5 - radius*4)/4;
   1126 
   1127    circle_aux(xcentre, ycentre, x, y, red, green, blue);
   1128    while (x < y)
   1129      {
   1130 	x++;
   1131 	if (p < 0)
   1132 	  {
   1133 	     p += 2*x+1;
   1134 	  }
   1135 	else
   1136 	  {
   1137 	     y--;
   1138 	     p += 2*(x-y)+1;
   1139 	  }
   1140 	circle_aux(xcentre, ycentre, x, y, red, green, blue);
   1141      }
   1142 }
   1143 
   1144 void pngwriter::circle(int xcentre, int ycentre, int radius, double red, double green, double blue)
   1145 {
   1146    this->circle(xcentre,ycentre,radius, int(red*65535), int(green*65535), int(blue*65535));
   1147 }
   1148 
   1149 ////////////////////////////////////////////////////////////
   1150 
   1151 void pngwriter::circle_aux(int xcentre, int ycentre, int x, int y, int red, int green, int blue)
   1152 {
   1153    if (x == 0)
   1154      {
   1155 	this->plot( xcentre, ycentre + y, red, green, blue);
   1156 	this->plot( xcentre, ycentre - y, red, green, blue);
   1157 	this->plot( xcentre + y, ycentre, red, green, blue);
   1158 	this->plot( xcentre - y, ycentre, red, green, blue);
   1159      }
   1160    else
   1161      if (x == y)
   1162        {
   1163 	  this->plot( xcentre + x, ycentre + y, red, green, blue);
   1164 	  this->plot( xcentre - x, ycentre + y, red, green, blue);
   1165 	  this->plot( xcentre + x, ycentre - y, red, green, blue);
   1166 	  this->plot( xcentre - x, ycentre - y, red, green, blue);
   1167        }
   1168    else
   1169      if (x < y)
   1170        {
   1171 	  this->plot( xcentre + x, ycentre + y, red, green, blue);
   1172 	  this->plot( xcentre - x, ycentre + y, red, green, blue);
   1173 	  this->plot( xcentre + x, ycentre - y, red, green, blue);
   1174 	  this->plot( xcentre - x, ycentre - y, red, green, blue);
   1175 	  this->plot( xcentre + y, ycentre + x, red, green, blue);
   1176 	  this->plot( xcentre - y, ycentre + x, red, green, blue);
   1177 	  this->plot( xcentre + y, ycentre - x, red, green, blue);
   1178 	  this->plot( xcentre - y, ycentre - x, red, green, blue);
   1179        }
   1180 
   1181 }
   1182 
   1183 ////////////////////////////////////////////////////////////
   1184 void pngwriter::filledcircle(int xcentre, int ycentre, int radius, int red, int green, int blue)
   1185 {
   1186    for(int jjj = ycentre-radius; jjj< ycentre+radius+1; jjj++)
   1187      {
   1188 	this->line(xcentre - int(sqrt((double)(radius*radius) - (-ycentre + jjj)*(-ycentre + jjj ))), jjj,
   1189 		   xcentre + int(sqrt((double)(radius*radius) - (-ycentre + jjj)*(-ycentre + jjj ))),jjj,red,green,blue);
   1190      }
   1191 }
   1192 
   1193 void pngwriter::filledcircle(int xcentre, int ycentre, int radius, double red, double green, double blue)
   1194 {
   1195    this->filledcircle( xcentre, ycentre,  radius, int(red*65535), int(green*65535), int(blue*65535));
   1196 }
   1197 
   1198 ////////////////Reading routines/////////////////////
   1199 /////////////////////////////////////////////////
   1200 
   1201 // Modified with Mikkel's patch
   1202 void pngwriter::readfromfile(char * name)
   1203 {
   1204    FILE            *fp;
   1205    png_structp     png_ptr;
   1206    png_infop       info_ptr;
   1207    unsigned char   **image;
   1208    unsigned long   width, height;
   1209    int bit_depth, color_type, interlace_type;
   1210    //   png_uint_32     i;
   1211    //
   1212    fp = fopen (name,"rb");
   1213    if (fp==NULL)
   1214      {
   1215 	std::cerr << " PNGwriter::readfromfile - ERROR **: Error opening file \"" << std::flush;
   1216 	std::cerr << name <<std::flush;
   1217 	std::cerr << "\"." << std::endl << std::flush;
   1218 	perror(" PNGwriter::readfromfile - ERROR **");
   1219 	return;
   1220      }
   1221 
   1222    if(!check_if_png(name, &fp))
   1223      {
   1224 	std::cerr << " PNGwriter::readfromfile - ERROR **: Error opening file " << name << ". This may not be a valid png file. (check_if_png() failed)." << std::endl;
   1225 	// fp has been closed already if check_if_png() fails.
   1226 	return;
   1227      }
   1228 
   1229 //   Code as it was before Sven's patch
   1230 /*   if(!read_png_info(fp, &png_ptr, &info_ptr))
   1231      {
   1232 	std::cerr << " PNGwriter::readfromfile - ERROR **: Error opening file " << name << ". read_png_info() failed." << std::endl;
   1233 	// fp has been closed already if read_png_info() fails.
   1234 	return;
   1235      }
   1236 
   1237    if(!read_png_image(fp, png_ptr, info_ptr, &image, &width, &height))
   1238      {
   1239 	std::cerr << " PNGwriter::readfromfile - ERROR **: Error opening file " << name << ". read_png_image() failed." << std::endl;
   1240 	// fp has been closed already if read_png_image() fails.
   1241 	return;
   1242      }
   1243 
   1244    //stuff should now be in image[][].
   1245 
   1246  */ //End of code as it was before Sven's patch.
   1247 
   1248    //Sven's patch starts here
   1249    ////////////////////////////////////
   1250 
   1251    /*
   1252 
   1253    if(!read_png_info(fp, &png_ptr, &info_ptr))
   1254      {
   1255 
   1256 	std::cerr << " PNGwriter::readfromfile - ERROR **: Error opening file " << name << ". read_png_info() failed." << std::endl;
   1257 	// fp has been closed already if read_png_info() fails.
   1258 	return;
   1259      }
   1260 
   1261    // UPDATE: Query info struct to get header info BEFORE reading the image
   1262 
   1263    png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL);
   1264    bit_depth_ = bit_depth;
   1265    colortype_ = color_type;
   1266 
   1267    if(color_type == PNG_COLOR_TYPE_PALETTE)
   1268      {
   1269 	png_set_expand(png_ptr);
   1270 	png_read_update_info(png_ptr, info_ptr);
   1271      }
   1272 
   1273    if(!read_png_image(fp, png_ptr, info_ptr, &image, &width, &height))
   1274      {
   1275 	std::cerr << " PNGwriter::readfromfile - ERROR **: Error opening file " << name << ". read_png_image() failed." << std::endl;
   1276 	// fp has been closed already if read_png_image() fails.
   1277 	return;
   1278      }
   1279 
   1280    //stuff should now be in image[][].
   1281    */
   1282    //Sven's patch ends here.
   1283    ////////////////////////////////
   1284 
   1285    // Mikkel's patch starts here
   1286    // ///////////////////////////////////
   1287 
   1288    if(!read_png_info(fp, &png_ptr, &info_ptr))
   1289      {
   1290 
   1291 	std::cerr << " PNGwriter::readfromfile - ERROR **: Error opening file " << name << ". read_png_info() failed." << std::endl;
   1292 	// fp has been closed already if read_png_info() fails.
   1293 	  return;
   1294      }
   1295 
   1296    //Input transformations
   1297    png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL);
   1298    bit_depth_ = bit_depth;
   1299    colortype_ = color_type;
   1300 
   1301 
   1302    // Changes palletted image to RGB
   1303    if(color_type == PNG_COLOR_TYPE_PALETTE /*&& bit_depth<8*/)
   1304      {
   1305 	// png_set_expand(png_ptr);
   1306 	png_set_palette_to_rgb(png_ptr);  // Just an alias of png_set_expand()
   1307 	transformation_ = 1;
   1308      }
   1309 
   1310    // Transforms grescale images of less than 8 bits to 8 bits.
   1311    if(color_type == PNG_COLOR_TYPE_GRAY && bit_depth<8)
   1312      {
   1313 	// png_set_expand(png_ptr);
   1314 	png_set_gray_1_2_4_to_8(png_ptr);  // Just an alias of the above.
   1315 	transformation_ = 1;
   1316      }
   1317 
   1318    // Completely strips the alpha channel.
   1319    if(color_type & PNG_COLOR_MASK_ALPHA)
   1320      {
   1321 	png_set_strip_alpha(png_ptr);
   1322 	transformation_ = 1;
   1323      }
   1324 
   1325    // Converts greyscale images to RGB.
   1326    if(color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) // Used to be RGB, fixed it.
   1327      {
   1328 	png_set_gray_to_rgb(png_ptr);
   1329 	transformation_ = 1;
   1330      }
   1331 
   1332 	 // If any of the above were applied,
   1333    if(transformation_)
   1334      {
   1335 	 // png_set_gray_to_rgb(png_ptr);   //Is this really needed here?
   1336 
   1337 	 // After setting the transformations, libpng can update your png_info structure to reflect any transformations
   1338 	 // you've requested with this call. This is most useful to update the info structure's rowbytes field so you can
   1339 	 // use it to allocate your image memory. This function will also update your palette with the correct screen_gamma
   1340 	 // and background if these have been given with the calls above.
   1341 
   1342 	png_read_update_info(png_ptr, info_ptr);
   1343 
   1344 	// Just in case any of these have changed?
   1345 	png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL);
   1346 	bit_depth_ = bit_depth;
   1347 	colortype_ = color_type;
   1348      }
   1349 
   1350    if(!read_png_image(fp, png_ptr, info_ptr, &image, &width, &height))
   1351      {
   1352 	std::cerr << " PNGwriter::readfromfile - ERROR **: Error opening file " << name << ". read_png_image() failed." << std::endl;
   1353 	// fp has been closed already if read_png_image() fails.
   1354 	return;
   1355      }
   1356 
   1357    //stuff should now be in image[][].
   1358 
   1359    // Mikkel's patch ends here
   1360    // //////////////////////////////
   1361    //
   1362    if( image == NULL)
   1363      {
   1364 	std::cerr << " PNGwriter::readfromfile - ERROR **: Error opening file " << name << ". Can't assign memory (after read_png_image(), image is NULL)." << std::endl;
   1365 	fclose(fp);
   1366 	return;
   1367      }
   1368 
   1369    //First we must get rid of the image already there, and free the memory.
   1370    int jjj;
   1371    for (jjj = 0; jjj < height_; jjj++) free(graph_[jjj]);
   1372    free(graph_);
   1373 
   1374    //Must reassign the new size of the read image
   1375    width_ = width;
   1376    height_ = height;
   1377 
   1378    //Graph now is the image.
   1379    graph_ = image;
   1380 
   1381    rowbytes_ = png_get_rowbytes(png_ptr, info_ptr);
   1382 
   1383 	// This was part of the original source, but has been moved up.
   1384 /*
   1385    png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL);
   1386    bit_depth_ = bit_depth;
   1387    colortype_ = color_type;
   1388 */
   1389   // if(color_type == PNG_COLOR_TYPE_PALETTE /*&& bit_depth<8*/   )
   1390  /*    {
   1391 	png_set_expand(png_ptr);
   1392      }
   1393 
   1394    if(color_type == PNG_COLOR_TYPE_GRAY && bit_depth<8)
   1395      {
   1396 	png_set_expand(png_ptr);
   1397      }
   1398 
   1399    if(color_type & PNG_COLOR_MASK_ALPHA)
   1400      {
   1401 	png_set_strip_alpha(png_ptr);
   1402      }
   1403 
   1404    if(color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_RGB_ALPHA)
   1405      {
   1406 	png_set_gray_to_rgb(png_ptr);
   1407      }
   1408 
   1409 */
   1410 
   1411    if((bit_depth_ !=16)&&(bit_depth_ !=8))
   1412      {
   1413 	std::cerr << " PNGwriter::readfromfile() - WARNING **: Input file is of unsupported type (bad bit_depth). Output will be unpredictable.\n";
   1414      }
   1415 
   1416 // Thanks to Mikkel's patch, PNGwriter should now be able to handle these color types:
   1417 
   1418 /*
   1419 color_type     - describes which color/alpha channels are present.
   1420                      PNG_COLOR_TYPE_GRAY                        (bit depths 1, 2, 4, 8, 16)
   1421                      PNG_COLOR_TYPE_GRAY_ALPHA                        (bit depths 8, 16)
   1422 					 PNG_COLOR_TYPE_PALETTE                        (bit depths 1, 2, 4, 8)
   1423                      PNG_COLOR_TYPE_RGB                        (bit_depths 8, 16)
   1424                      PNG_COLOR_TYPE_RGB_ALPHA                        (bit_depths 8, 16)
   1425 
   1426                      PNG_COLOR_MASK_PALETTE
   1427                      PNG_COLOR_MASK_COLOR
   1428 
   1429 color types.  Note that not all combinations are legal
   1430 #define PNG_COLOR_TYPE_GRAY 0
   1431 #define PNG_COLOR_TYPE_PALETTE  (PNG_COLOR_MASK_COLOR (2) | PNG_COLOR_MASK_PALETTE (1) )
   1432 #define PNG_COLOR_TYPE_RGB        (PNG_COLOR_MASK_COLOR (2) )
   1433 #define PNG_COLOR_TYPE_RGB_ALPHA  (PNG_COLOR_MASK_COLOR (2) | PNG_COLOR_MASK_ALPHA (4) )
   1434 #define PNG_COLOR_TYPE_GRAY_ALPHA (PNG_COLOR_MASK_ALPHA (4) )
   1435 
   1436 aliases
   1437 #define PNG_COLOR_TYPE_RGBA  PNG_COLOR_TYPE_RGB_ALPHA
   1438 #define PNG_COLOR_TYPE_GA  PNG_COLOR_TYPE_GRAY_ALPHA
   1439 
   1440  These describe the color_type field in png_info.
   1441  color type masks
   1442 #define PNG_COLOR_MASK_PALETTE    1
   1443 #define PNG_COLOR_MASK_COLOR      2
   1444 #define PNG_COLOR_MASK_ALPHA      4
   1445 
   1446 
   1447 					 */
   1448 
   1449 
   1450    if(colortype_ !=2)
   1451      {
   1452 	std::cerr << " PNGwriter::readfromfile() - WARNING **: Input file is of unsupported type (bad color_type). Output will be unpredictable.\n";
   1453      }
   1454 
   1455    screengamma_ = 2.2;
   1456    double          file_gamma,screen_gamma;
   1457    screen_gamma = screengamma_;
   1458    if (png_get_gAMA(png_ptr, info_ptr, &file_gamma))
   1459      {
   1460 	png_set_gamma(png_ptr,screen_gamma,file_gamma);
   1461      }
   1462    else
   1463      {
   1464 	png_set_gamma(png_ptr, screen_gamma,0.45);
   1465      }
   1466 
   1467    filegamma_ = file_gamma;
   1468 
   1469    fclose(fp);
   1470 }
   1471 
   1472 ///////////////////////////////////////////////////////
   1473 
   1474 void pngwriter::readfromfile(const char * name)
   1475 {
   1476    this->readfromfile((char *)(name));
   1477 }
   1478 
   1479 /////////////////////////////////////////////////////////
   1480 int pngwriter::check_if_png(char *file_name, FILE **fp)
   1481 {
   1482    char    sig[PNG_BYTES_TO_CHECK];
   1483 
   1484    if ( /*(*fp = fopen(file_name, "rb")) */  *fp == NULL) // Fixed 10 10 04
   1485      {
   1486 	//   exit(EXIT_FAILURE);
   1487 	std::cerr << " PNGwriter::check_if_png - ERROR **: Could not open file  " << file_name << " to read." << std::endl;
   1488 	perror(" PNGwriter::check_if_png - ERROR **");
   1489 	return 0;
   1490      }
   1491 
   1492    if (fread(sig, 1, PNG_BYTES_TO_CHECK, *fp) != PNG_BYTES_TO_CHECK)
   1493      {
   1494 	//exit(EXIT_FAILURE);
   1495 	std::cerr << " PNGwriter::check_if_png - ERROR **: File " << file_name << " does not appear to be a valid PNG file." << std::endl;
   1496 	perror(" PNGwriter::check_if_png - ERROR **");
   1497 	fclose(*fp);
   1498 	return 0;
   1499      }
   1500 
   1501    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)*/ )
   1502      {
   1503 	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;
   1504 	fclose(*fp);
   1505 	return 0;
   1506      }
   1507 
   1508 
   1509 
   1510    return 1; //Success
   1511 }
   1512 
   1513 ///////////////////////////////////////////////////////
   1514 int pngwriter::read_png_info(FILE *fp, png_structp *png_ptr, png_infop *info_ptr)
   1515 {
   1516    *png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
   1517    if (*png_ptr == NULL)
   1518      {
   1519 	std::cerr << " PNGwriter::read_png_info - ERROR **: Could not create read_struct." << std::endl;
   1520 	fclose(fp);
   1521 	return 0;
   1522 	//exit(EXIT_FAILURE);
   1523      }
   1524    *info_ptr = png_create_info_struct(*png_ptr);
   1525    if (*info_ptr == NULL)
   1526      {
   1527 	png_destroy_read_struct(png_ptr, (png_infopp)NULL, (png_infopp)NULL);
   1528 	std::cerr << " PNGwriter::read_png_info - ERROR **: Could not create info_struct." << std::endl;
   1529 	//exit(EXIT_FAILURE);
   1530 	fclose(fp);
   1531 	return 0;
   1532      }
   1533    if (setjmp((*png_ptr)->jmpbuf)) /*(setjmp(png_jmpbuf(*png_ptr)) )*//////////////////////////////////////
   1534      {
   1535 	png_destroy_read_struct(png_ptr, info_ptr, (png_infopp)NULL);
   1536 	std::cerr << " PNGwriter::read_png_info - ERROR **: This file may be a corrupted PNG file. (setjmp(*png_ptr)->jmpbf) failed)." << std::endl;
   1537 	fclose(fp);
   1538 	return 0;
   1539 	//exit(EXIT_FAILURE);
   1540      }
   1541    png_init_io(*png_ptr, fp);
   1542    png_set_sig_bytes(*png_ptr, PNG_BYTES_TO_CHECK);
   1543    png_read_info(*png_ptr, *info_ptr);
   1544 
   1545    return 1;
   1546 }
   1547 
   1548 ////////////////////////////////////////////////////////////
   1549 int pngwriter::read_png_image(FILE *fp, png_structp png_ptr, png_infop info_ptr,
   1550 			      png_bytepp *image, png_uint_32 *width, png_uint_32 *height)
   1551 {
   1552    unsigned int i,j;
   1553 
   1554    *width = png_get_image_width(png_ptr, info_ptr);
   1555    *height = png_get_image_height(png_ptr, info_ptr);
   1556 
   1557    if( width == NULL)
   1558      {
   1559 	std::cerr << " PNGwriter::read_png_image - ERROR **: png_get_image_width() returned NULL pointer." << std::endl;
   1560 	fclose(fp);
   1561 	return 0;
   1562      }
   1563 
   1564    if( height == NULL)
   1565      {
   1566 	std::cerr << " PNGwriter::read_png_image - ERROR **: png_get_image_height() returned NULL pointer." << std::endl;
   1567 	fclose(fp);
   1568 	return 0;
   1569      }
   1570 
   1571    if ((*image = (png_bytepp)malloc(*height * sizeof(png_bytep))) == NULL)
   1572      {
   1573 	std::cerr << " PNGwriter::read_png_image - ERROR **: Could not allocate memory for reading image." << std::endl;
   1574 	fclose(fp);
   1575 	return 0;
   1576 	//exit(EXIT_FAILURE);
   1577      }
   1578    for (i = 0; i < *height; i++)
   1579      {
   1580 	(*image)[i] = (png_bytep)malloc(png_get_rowbytes(png_ptr, info_ptr));
   1581 	if ((*image)[i] == NULL)
   1582 	  {
   1583 	     for (j = 0; j < i; j++) free((*image)[j]);
   1584 	     free(*image);
   1585 	     fclose(fp);
   1586 	     std::cerr << " PNGwriter::read_png_image - ERROR **: Could not allocate memory for reading image." << std::endl;
   1587 	     return 0;
   1588 	     //exit(EXIT_FAILURE);
   1589 	  }
   1590      }
   1591    png_read_image(png_ptr, *image);
   1592 
   1593    return 1;
   1594 }
   1595 
   1596 ///////////////////////////////////
   1597 int pngwriter::getheight(void)
   1598 {
   1599    return height_;
   1600 }
   1601 
   1602 int pngwriter::getwidth(void)
   1603 {
   1604    return width_;
   1605 }
   1606 
   1607 
   1608 int pngwriter::getbitdepth(void)
   1609 {
   1610    return bit_depth_;
   1611 }
   1612 
   1613 int pngwriter::getcolortype(void)
   1614 {
   1615    return colortype_;
   1616 }
   1617 
   1618 double pngwriter::getgamma(void)
   1619 {
   1620    return filegamma_;
   1621 }
   1622 
   1623 void pngwriter::setgamma(double gamma)
   1624 {
   1625    filegamma_ = gamma;
   1626 }
   1627 
   1628 // The algorithms HSVtoRGB and RGBtoHSV were found at http://www.cs.rit.edu/~ncs/
   1629 //  which is a page that belongs to Nan C. Schaller, though
   1630 //  these algorithms appear to be the work of Eugene Vishnevsky.
   1631 //////////////////////////////////////////////
   1632 void pngwriter::HSVtoRGB( double *r, double *g, double *b, double h, double s, double v )
   1633 {
   1634    // r,g,b values are from 0 to 1
   1635    // h = [0,1], s = [0,1], v = [0,1]
   1636    // if s == 0, then h = -1 (undefined)
   1637    //
   1638    h = h*360.0;
   1639 
   1640    int i;
   1641    double f, p, q, t;
   1642    if( s == 0 )
   1643      {
   1644 	// achromatic (grey)
   1645 	*r = *g = *b = v;
   1646 	return;
   1647      }
   1648 
   1649    h /= 60;                        // sector 0 to 5
   1650    i = int(floor( h ));
   1651    f = h - i;                      // factorial part of h
   1652    p = v * ( 1 - s );
   1653    q = v * ( 1 - s * f );
   1654    t = v * ( 1 - s * ( 1 - f ) );
   1655 
   1656    switch( i )
   1657      {
   1658       case 0:
   1659 	*r = v;
   1660 	*g = t;
   1661 	*b = p;
   1662 	break;
   1663       case 1:
   1664 	*r = q;
   1665 	*g = v;
   1666 	*b = p;
   1667 	break;
   1668       case 2:
   1669 	*r = p;
   1670 	*g = v;
   1671 	*b = t;
   1672 	break;
   1673       case 3:
   1674 	*r = p;
   1675 	*g = q;
   1676 	*b = v;
   1677 	break;
   1678       case 4:
   1679 	*r = t;
   1680 	*g = p;
   1681 	*b = v;
   1682 	break;
   1683       default:                // case 5:
   1684 	*r = v;
   1685 	*g = p;
   1686 	*b = q;
   1687 	break;
   1688      }
   1689 }
   1690 
   1691 void pngwriter::RGBtoHSV( float r, float g, float b, float *h, float *s, float *v )
   1692 {
   1693 
   1694    float min=0.0; //These values are not used.
   1695    float max=1.0;
   1696    float delta;
   1697 
   1698    if( (r>=g)&&(r>=b) )
   1699      {
   1700 	max = r;
   1701      }
   1702    if( (g>=r)&&(g>=b) )
   1703      {
   1704 	max = g;
   1705      }
   1706    if( (b>=g)&&(b>=r) )
   1707      {
   1708 	max = b;
   1709      }
   1710 
   1711    if( (r<=g)&&(r<=b) )
   1712      {
   1713 	min = r;
   1714      }
   1715    if( (g<=r)&&(g<=b) )
   1716      {
   1717 	min = g;
   1718      }
   1719    if( (b<=g)&&(b<=r) )
   1720      {
   1721 	min = b;
   1722      }
   1723 
   1724    *v = max;                               // v
   1725 
   1726    delta = max - min;
   1727 
   1728    if( max != 0 )
   1729      *s = delta / max;               // s
   1730    else
   1731      {
   1732 
   1733 	r = g = b = 0;                // s = 0, v is undefined
   1734 	*s = 0;
   1735 	*h = -1;
   1736 	return;
   1737      }
   1738 
   1739    if( r == max )
   1740      *h = ( g - b ) / delta;         // between yellow & magenta
   1741    else if( g == max )
   1742      *h = 2 + ( b - r ) / delta;     // between cyan & yellow
   1743    else
   1744      *h = 4 + ( r - g ) / delta;     // between magenta & cyan
   1745 
   1746    *h *= 60;                               // degrees
   1747    if( *h < 0 )
   1748      *h += 360;
   1749 
   1750 }
   1751 
   1752 //
   1753 //////////////////////////////////////////////////////////////////////////////////
   1754 void pngwriter::plotHSV(int x, int y, double hue, double saturation, double value)
   1755 {
   1756    double red,green,blue;
   1757    double *redp;
   1758    double *greenp;
   1759    double *bluep;
   1760 
   1761    redp = &red;
   1762    greenp = &green;
   1763    bluep = &blue;
   1764 
   1765    HSVtoRGB(redp,greenp,bluep,hue,saturation,value);
   1766    plot(x,y,red,green,blue);
   1767 }
   1768 
   1769 void pngwriter::plotHSV(int x, int y, int hue, int saturation, int value)
   1770 {
   1771    plotHSV(x, y, double(hue)/65535.0, double(saturation)/65535.0,  double(value)/65535.0);
   1772 }
   1773 
   1774 //
   1775 //////////////////////////////////////////////////////////////////////////////////
   1776 double pngwriter::dreadHSV(int x, int y, int colour)
   1777 {
   1778    if( (x>0)&&(x<=width_)&&(y>0)&&(y<=height_) )
   1779      {
   1780 
   1781 	float * huep;
   1782 	float * saturationp;
   1783 	float * valuep;
   1784 	float red,green,blue;
   1785 	float hue, saturation, value;
   1786 
   1787 	red = float(dread(x,y,1));
   1788 	green = float(dread(x,y,2));
   1789 	blue = float(dread(x,y,3));
   1790 
   1791 	huep = &hue;
   1792 	saturationp = &saturation;
   1793 	valuep = &value;
   1794 
   1795 	RGBtoHSV( red,  green,  blue, huep,  saturationp, valuep );
   1796 
   1797 	if(colour == 1)
   1798 	  {
   1799 	     return double(hue)/360.0;
   1800 	  }
   1801 
   1802 	else if(colour == 2)
   1803 	  {
   1804 	     return saturation;
   1805 	  }
   1806 
   1807 	else if(colour == 3)
   1808 	  {
   1809 	     return value;
   1810 	  }
   1811 
   1812 	std::cerr << " PNGwriter::dreadHSV - ERROR **: Called with wrong colour argument: should be 1, 2 or 3; was: " << colour << "." << std::endl;
   1813      }
   1814    return 0.0;
   1815 }
   1816 
   1817 //
   1818 //////////////////////////////////////////////////////////////////////////////////
   1819 int pngwriter::readHSV(int x, int y, int colour)
   1820 {
   1821    if( (x>0)&&(x<=width_)&&(y>0)&&(y<=height_) )
   1822      {
   1823 
   1824 	float * huep;
   1825 	float * saturationp;
   1826 	float * valuep;
   1827 	float red,green,blue;
   1828 	float hue, saturation, value;
   1829 
   1830 	red = float(dread(x,y,1));
   1831 	green = float(dread(x,y,2));
   1832 	blue = float(dread(x,y,3));
   1833 
   1834 	huep = &hue;
   1835 	saturationp = &saturation;
   1836 	valuep = &value;
   1837 
   1838 	RGBtoHSV( red,  green,  blue, huep,  saturationp, valuep );
   1839 
   1840 	if(colour == 1)
   1841 	  {
   1842 	     return int(65535*(double(hue)/360.0));
   1843 	  }
   1844 
   1845 	else if(colour == 2)
   1846 	  {
   1847 	     return int(65535*saturation);
   1848 	  }
   1849 
   1850 	else if(colour == 3)
   1851 	  {
   1852 	     return int(65535*value);
   1853 	  }
   1854 
   1855 	std::cerr << " PNGwriter::readHSV - ERROR **: Called with wrong colour argument: should be 1, 2 or 3; was: " << colour << "." << std::endl;
   1856 	return 0;
   1857      }
   1858    else
   1859      {
   1860 	return 0;
   1861      }
   1862 }
   1863 
   1864 void pngwriter::setcompressionlevel(int level)
   1865 {
   1866    if( (level < -1)||(level > 9) )
   1867      {
   1868 	std::cerr << " PNGwriter::setcompressionlevel - ERROR **: Called with wrong compression level: should be -1 to 9, was: " << level << "." << std::endl;
   1869      }
   1870    compressionlevel_ = level;
   1871 }
   1872 
   1873 // An implementation of a Bezier curve.
   1874 void pngwriter::bezier(  int startPtX, int startPtY,
   1875 			 int startControlX, int startControlY,
   1876 			 int endPtX, int endPtY,
   1877 			 int endControlX, int endControlY,
   1878 			 double red, double green, double blue)
   1879 {
   1880 
   1881    double cx = 3.0*(startControlX - startPtX);
   1882    double bx = 3.0*(endControlX - startControlX) - cx;
   1883    double ax = double(endPtX - startPtX - cx - bx);
   1884 
   1885    double cy = 3.0*(startControlY - startPtY);
   1886    double by = 3.0*(endControlY - startControlY) - cy;
   1887    double ay = double(endPtY - startPtY - cy - by);
   1888 
   1889    double x,y,newx,newy;
   1890    x = startPtX;
   1891    y = startPtY;
   1892 
   1893    for(double t = 0.0; t<=1.005; t += 0.005)
   1894      {
   1895 	newx = startPtX + t*(double(cx) + t*(double(bx) + t*(double(ax))));
   1896 	newy = startPtY + t*(double(cy) + t*(double(by) + t*(double(ay))));
   1897 	this->line(int(x),int(y),int(newx),int(newy),red,green,blue);
   1898 	x = newx;
   1899 	y = newy;
   1900      }
   1901 }
   1902 
   1903 //int version of bezier
   1904 void pngwriter::bezier(  int startPtX, int startPtY,
   1905 			 int startControlX, int startControlY,
   1906 			 int endPtX, int endPtY,
   1907 			 int endControlX, int endControlY,
   1908 			 int  red, int  green, int blue)
   1909 {
   1910    this->bezier(   startPtX,  startPtY,
   1911 		   startControlX, startControlY,
   1912 		   endPtX, endPtY,
   1913 		   endControlX,  endControlY,
   1914 		   double(red)/65535.0,  double(green)/65535.0,  double(blue)/65535.0);
   1915 }
   1916 
   1917 /*
   1918 int pngwriter::getcompressionlevel(void)
   1919 {
   1920    return png_get_compression_level(png_ptr);
   1921 }
   1922 */
   1923 
   1924 double pngwriter::version(void)
   1925 {
   1926    const char *a = "Jeramy Webb (jeramyw@gmail.com), Mike Heller (mkheller@gmail.com)"; // For their generosity ;-)
   1927    char b = a[27];
   1928    b++;
   1929    return (PNGWRITER_VERSION);
   1930 }
   1931 
   1932 void pngwriter::write_png(void)
   1933 {
   1934    this->close();
   1935 }
   1936 
   1937 #ifndef NO_FREETYPE
   1938 
   1939 // Freetype-based text rendering functions.
   1940 ///////////////////////////////////////////
   1941 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)
   1942 {
   1943    FT_Library  library;
   1944    FT_Face     face;
   1945    FT_Matrix   matrix;      // transformation matrix
   1946    FT_Vector   pen;
   1947 
   1948    FT_UInt glyph_index;
   1949    FT_Error error;
   1950 
   1951    FT_Bool use_kerning;
   1952    FT_UInt previous = 0;
   1953 
   1954    /* Set up transformation Matrix */
   1955    matrix.xx = (FT_Fixed)( cos(angle)*0x10000);   /* It would make more sense to do this (below), but, bizzarely, */
   1956    matrix.xy = (FT_Fixed)(-sin(angle)*0x10000);   /* if one does, FT_Load_Glyph fails consistently.               */
   1957    matrix.yx = (FT_Fixed)( sin(angle)*0x10000);  //   matrix.yx = - matrix.xy;
   1958    matrix.yy = (FT_Fixed)( cos(angle)*0x10000);  //   matrix.yy = matrix.xx;
   1959 
   1960    /* Place starting coordinates in adequate form. */
   1961    pen.x = x_start*64 ;
   1962    pen.y =   (int)(y_start/64.0);
   1963 
   1964    /*Count the length of the string */
   1965    int num_chars = strlen(text);
   1966 
   1967    /* Initialize FT Library object */
   1968    error = FT_Init_FreeType( &library );
   1969    if (error) { std::cerr << " PNGwriter::plot_text - ERROR **: FreeType: Could not init Library."<< std::endl; return;}
   1970 
   1971    /* Initialize FT face object */
   1972    error = FT_New_Face( library,face_path,0,&face );
   1973    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; }
   1974 
   1975    /* Set the Char size */
   1976    error = FT_Set_Char_Size( face,          /* handle to face object           */
   1977 			     0,             /* char_width in 1/64th of points  */
   1978 			     fontsize*64,   /* char_height in 1/64th of points */
   1979 			     100,           /* horizontal device resolution    */
   1980 			     100 );         /* vertical device resolution      */
   1981 
   1982    /* A way of accesing the glyph directly */
   1983    FT_GlyphSlot  slot = face->glyph;  // a small shortcut
   1984 
   1985    /* Does the font file support kerning? */
   1986    use_kerning = FT_HAS_KERNING( face );
   1987 
   1988    int n;
   1989    for ( n = 0; n < num_chars; n++ )
   1990      {
   1991 	/* Convert character code to glyph index */
   1992 	glyph_index = FT_Get_Char_Index( face, text[n] );
   1993 
   1994 	/* Retrieve kerning distance and move pen position */
   1995 	if ( use_kerning && previous&& glyph_index )
   1996 	  {
   1997 	     FT_Vector  delta;
   1998 	     FT_Get_Kerning( face,
   1999 			     previous,
   2000 			     glyph_index,
   2001 			     ft_kerning_default, //FT_KERNING_DEFAULT,
   2002 			     &delta );
   2003 
   2004 	     /* Transform this kerning distance into rotated space */
   2005 	     pen.x += (int) (((double) delta.x)*cos(angle));
   2006 	     pen.y +=  (int) (((double) delta.x)*( sin(angle)));
   2007 	  }
   2008 
   2009 	/* Set transform */
   2010 	FT_Set_Transform( face, &matrix, &pen );
   2011 
   2012 /*set char size*/
   2013 
   2014 	if (error) { std::cerr << " PNGwriter::plot_text - ERROR **: FreeType: Set char size error." << std::endl; return;};
   2015 
   2016 	/* Retrieve glyph index from character code */
   2017 	glyph_index = FT_Get_Char_Index( face, text[n] );
   2018 
   2019 	/* Load glyph image into the slot (erase previous one) */
   2020 	error = FT_Load_Glyph( face, glyph_index, FT_LOAD_DEFAULT );
   2021 	if (error) { std::cerr << " PNGwriter::plot_text - ERROR **: FreeType: Could not load glyph (in loop). (FreeType error "<< std::hex << error <<")." << std::endl; return;}
   2022 
   2023 	/* Convert to an anti-aliased bitmap */
   2024 	//	error = FT_Render_Glyph( face->glyph, FT_RENDER_MODE_NORMAL );
   2025 	error = FT_Render_Glyph( face->glyph, ft_render_mode_normal );
   2026 	if (error) { std::cerr << " PNGwriter::plot_text - ERROR **: FreeType: Render glyph error." << std::endl; return;}
   2027 
   2028 	/* Now, draw to our target surface */
   2029 	my_draw_bitmap( &slot->bitmap,
   2030 			slot->bitmap_left,
   2031 			y_start + slot->bitmap_top,
   2032 			red,
   2033 			green,
   2034 			blue );
   2035 
   2036 	/* Advance to the next position */
   2037 	pen.x += slot->advance.x;
   2038 	pen.y += slot->advance.y;
   2039 
   2040 	/* record current glyph index */
   2041 	previous = glyph_index;
   2042      }
   2043 
   2044    /* Free the face and the library objects */
   2045    FT_Done_Face    ( face );
   2046    FT_Done_FreeType( library );
   2047 }
   2048 
   2049 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)
   2050 {
   2051    FT_Library  library;
   2052    FT_Face     face;
   2053    FT_Matrix   matrix;      // transformation matrix
   2054    FT_Vector   pen;
   2055 
   2056    FT_UInt glyph_index;
   2057    FT_Error error;
   2058 
   2059    FT_Bool use_kerning;
   2060    FT_UInt previous = 0;
   2061 
   2062    /* Set up transformation Matrix */
   2063    matrix.xx = (FT_Fixed)( cos(angle)*0x10000);   /* It would make more sense to do this (below), but, bizzarely, */
   2064    matrix.xy = (FT_Fixed)(-sin(angle)*0x10000);   /* if one does, FT_Load_Glyph fails consistently.               */
   2065    matrix.yx = (FT_Fixed)( sin(angle)*0x10000);  //   matrix.yx = - matrix.xy;
   2066    matrix.yy = (FT_Fixed)( cos(angle)*0x10000);  //   matrix.yy = matrix.xx;
   2067 
   2068    /* Place starting coordinates in adequate form. */
   2069    pen.x = x_start*64 ;
   2070    pen.y = (int)(y_start/64.0);
   2071 
   2072    /*Count the length of the string */
   2073    int num_bytes=0;
   2074    while(text[num_bytes]!=0)
   2075      {
   2076 	num_bytes++;
   2077      }
   2078 
   2079 	 /*
   2080    std::cout << "Num bytes is: "<< num_bytes << std::endl;
   2081    */
   2082 
   2083    //The array of ucs4 glyph indexes, which will by at most the number of bytes in the utf-8 file.
   2084    long * ucs4text;
   2085    ucs4text = new long[num_bytes+1];
   2086 
   2087    unsigned char u,v,w,x,y,z;
   2088 
   2089    int num_chars=0;
   2090 
   2091    long iii=0;
   2092 
   2093    while(iii<num_bytes)
   2094      {
   2095 	z = text[iii];
   2096 
   2097 	if(z<=127)
   2098 	  {
   2099 	     ucs4text[num_chars] = z;
   2100 	  }
   2101 
   2102 	if((192<=z)&&(z<=223))
   2103 	  {
   2104 	     iii++; y = text[iii];
   2105 	     ucs4text[num_chars] = (z-192)*64 + (y -128);
   2106 	  }
   2107 
   2108 	if((224<=z)&&(z<=239))
   2109 	  {
   2110 	     iii++; y = text[iii];
   2111 	     iii++; x = text[iii];
   2112 	     ucs4text[num_chars] = (z-224)*4096 + (y -128)*64 + (x-128);
   2113 	  }
   2114 
   2115 	if((240<=z)&&(z<=247))
   2116 	  {
   2117 	     iii++; y = text[iii];
   2118 	     iii++; x = text[iii];
   2119 	     iii++; w = text[iii];
   2120 	     ucs4text[num_chars] = (z-240)*262144 + (y -128)*4096 + (x-128)*64 + (w-128);
   2121 	  }
   2122 
   2123 	if((248<=z)&&(z<=251))
   2124 	  {
   2125 	     iii++; y = text[iii];
   2126 	     iii++; x = text[iii];
   2127 	     iii++; w = text[iii];
   2128 	     iii++; v = text[iii];
   2129 	     ucs4text[num_chars] = (z-248)*16777216 + (y -128)*262144 + (x-128)*4096 + (w-128)*64 +(v-128);
   2130 	  }
   2131 
   2132 	if((252==z)||(z==253))
   2133 	  {
   2134 	     iii++; y = text[iii];
   2135 	     iii++; x = text[iii];
   2136 	     iii++; w = text[iii];
   2137 	     iii++; v = text[iii];
   2138 	     u = text[iii];
   2139 	     ucs4text[num_chars] = (z-252)*1073741824 + (y -128)*16777216   + (x-128)*262144 + (w-128)*4096 +(v-128)*64 + (u-128);
   2140 	  }
   2141 
   2142 	if((z==254)||(z==255))
   2143 	  {
   2144 	     std::cerr << " PNGwriter::plot_text_utf8 - ERROR **: Problem with character: invalid UTF-8 data."<< std::endl;
   2145 	  }
   2146 	// std::cerr << "\nProblem at " << iii << ".\n";
   2147 	//
   2148 	iii++;
   2149 	num_chars++;
   2150      }
   2151 
   2152    // num_chars now contains the number of characters in the string.
   2153    /*
   2154    std::cout << "Num chars is: "<< num_chars << std::endl;
   2155    */
   2156 
   2157    /* Initialize FT Library object */
   2158    error = FT_Init_FreeType( &library );
   2159    if (error) { std::cerr << " PNGwriter::plot_text_utf8 - ERROR **: FreeType: Could not init Library."<< std::endl; return;}
   2160 
   2161    /* Initialize FT face object */
   2162    error = FT_New_Face( library,face_path,0,&face );
   2163    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; }
   2164 
   2165    /* Set the Char size */
   2166    error = FT_Set_Char_Size( face,          /* handle to face object           */
   2167 			     0,             /* char_width in 1/64th of points  */
   2168 			     fontsize*64,   /* char_height in 1/64th of points */
   2169 			     100,           /* horizontal device resolution    */
   2170 			     100 );         /* vertical device resolution      */
   2171 
   2172    /* A way of accesing the glyph directly */
   2173    FT_GlyphSlot  slot = face->glyph;  // a small shortcut
   2174 
   2175    /* Does the font file support kerning? */
   2176    use_kerning = FT_HAS_KERNING( face );
   2177 
   2178    int n;
   2179    for ( n = 0; n < num_chars; n++ )
   2180      {
   2181 	/* Convert character code to glyph index */
   2182 	glyph_index = FT_Get_Char_Index( face, ucs4text[n] );
   2183 
   2184 	/* Retrieve kerning distance and move pen position */
   2185 	if ( use_kerning && previous&& glyph_index )
   2186 	  {
   2187 	     FT_Vector  delta;
   2188 	     FT_Get_Kerning( face,
   2189 			     previous,
   2190 			     glyph_index,
   2191 			     ft_kerning_default, //FT_KERNING_DEFAULT,
   2192 			     &delta );
   2193 
   2194 	     /* Transform this kerning distance into rotated space */
   2195 	     pen.x += (int) (((double) delta.x)*cos(angle));
   2196 	     pen.y +=  (int) (((double) delta.x)*( sin(angle)));
   2197 	  }
   2198 
   2199 	/* Set transform */
   2200 	FT_Set_Transform( face, &matrix, &pen );
   2201 
   2202 /*set char size*/
   2203 
   2204 	if (error) { std::cerr << " PNGwriter::plot_text_utf8 - ERROR **: FreeType: Set char size error." << std::endl; return;};
   2205 
   2206 	/* Retrieve glyph index from character code */
   2207 	glyph_index = FT_Get_Char_Index( face, ucs4text[n] );
   2208 
   2209 	/* Load glyph image into the slot (erase previous one) */
   2210 	error = FT_Load_Glyph( face, glyph_index, FT_LOAD_DEFAULT );
   2211 	if (error) { std::cerr << " PNGwriter::plot_text_utf8 - ERROR **: FreeType: Could not load glyph (in loop). (FreeType error "<< std::hex << error <<")." << std::endl; return;}
   2212 
   2213 	/* Convert to an anti-aliased bitmap */
   2214 	error = FT_Render_Glyph( face->glyph, ft_render_mode_normal );
   2215 	if (error) { std::cerr << " PNGwriter::plot_text_utf8 - ERROR **: FreeType: Render glyph error." << std::endl; return;}
   2216 
   2217 	/* Now, draw to our target surface */
   2218 	my_draw_bitmap( &slot->bitmap,
   2219 			slot->bitmap_left,
   2220 			y_start + slot->bitmap_top,
   2221 			red,
   2222 			green,
   2223 			blue );
   2224 
   2225 	/* Advance to the next position */
   2226 	pen.x += slot->advance.x;
   2227 	pen.y += slot->advance.y;
   2228 
   2229 	/* record current glyph index */
   2230 	previous = glyph_index;
   2231      }
   2232 
   2233    /* Free the face and the library objects */
   2234    FT_Done_Face    ( face );
   2235    FT_Done_FreeType( library );
   2236 
   2237    delete[] ucs4text;
   2238 }
   2239 
   2240 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)
   2241 {
   2242    plot_text( face_path, fontsize, x_start, y_start,  angle,  text,  ((double) red)/65535.0,  ((double) green)/65535.0,  ((double) blue)/65535.0   );
   2243 }
   2244 
   2245 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)
   2246 {
   2247    plot_text_utf8( face_path, fontsize, x_start, y_start,  angle,  text,  ((double) red)/65535.0,  ((double) green)/65535.0,  ((double) blue)/65535.0   );
   2248 }
   2249 
   2250 void pngwriter::my_draw_bitmap( FT_Bitmap * bitmap, int x, int y, double red, double green, double blue)
   2251 {
   2252    double temp;
   2253    for(int j=1; j<bitmap->rows+1; j++)
   2254      {
   2255 	for(int i=1; i< bitmap->width + 1; i++)
   2256 	  {
   2257 	     temp = (double)(bitmap->buffer[(j-1)*bitmap->width + (i-1)] )/255.0;
   2258 
   2259 	     if(temp)
   2260 	       {
   2261 		  this->plot(x + i,
   2262 			     y  - j,
   2263 			     temp*red + (1-temp)*(this->dread(x+i,y-j,1)),
   2264 			     temp*green + (1-temp)*(this->dread(x+i,y-j,2)),
   2265 			     temp*blue + (1-temp)*(this->dread(x+i,y-j,3))
   2266 			     );
   2267 	       }
   2268 	  }
   2269      }
   2270 }
   2271 
   2272 
   2273 
   2274 //////////// Get text width
   2275 
   2276 //put in freetype section
   2277 
   2278 int pngwriter::get_text_width(char * face_path, int fontsize, char * text)
   2279 {
   2280 
   2281    FT_Library  library;
   2282    FT_Face     face;
   2283    FT_Matrix   matrix;      // transformation matrix
   2284    FT_Vector   pen;
   2285 
   2286    FT_UInt glyph_index;
   2287    FT_Error error;
   2288 
   2289    FT_Bool use_kerning;
   2290    FT_UInt previous = 0;
   2291 
   2292    /* Set up transformation Matrix */
   2293    matrix.xx = (FT_Fixed)( 1.0*0x10000);   /* It would make more sense to do this (below), but, bizzarely, */
   2294    matrix.xy = (FT_Fixed)( 0.0*0x10000);   /* if one does, FT_Load_Glyph fails consistently.               */
   2295    matrix.yx = (FT_Fixed)( 0.0*0x10000);  //   matrix.yx = - matrix.xy;
   2296    matrix.yy = (FT_Fixed)( 1.0*0x10000);  //   matrix.yy = matrix.xx;
   2297 
   2298    /* Place starting coordinates in adequate form. */
   2299    pen.x = 0;
   2300    pen.y = 0;
   2301 
   2302    /*Count the length of the string */
   2303    int num_chars = strlen(text);
   2304 
   2305    /* Initialize FT Library object */
   2306    error = FT_Init_FreeType( &library );
   2307    if (error) { std::cerr << " PNGwriter::get_text_width - ERROR **: FreeType: Could not init Library."<< std::endl; return 0;}
   2308 
   2309    /* Initialize FT face object */
   2310    error = FT_New_Face( library,face_path,0,&face );
   2311    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; }
   2312 
   2313    /* Set the Char size */
   2314    error = FT_Set_Char_Size( face,          /* handle to face object           */
   2315 			     0,             /* char_width in 1/64th of points  */
   2316 			     fontsize*64,   /* char_height in 1/64th of points */
   2317 			     100,           /* horizontal device resolution    */
   2318 			     100 );         /* vertical device resolution      */
   2319 
   2320    /* A way of accesing the glyph directly */
   2321    FT_GlyphSlot  slot = face->glyph;  // a small shortcut
   2322 
   2323    /* Does the font file support kerning? */
   2324    use_kerning = FT_HAS_KERNING( face );
   2325 
   2326    int n;
   2327    for ( n = 0; n < num_chars; n++ )
   2328      {
   2329 	/* Convert character code to glyph index */
   2330 	glyph_index = FT_Get_Char_Index( face, text[n] );
   2331 
   2332 	/* Retrieve kerning distance and move pen position */
   2333 	if ( use_kerning && previous&& glyph_index )
   2334 	  {
   2335 	     FT_Vector  delta;
   2336 	     FT_Get_Kerning( face,
   2337 			     previous,
   2338 			     glyph_index,
   2339 			     ft_kerning_default, //FT_KERNING_DEFAULT,
   2340 			     &delta );
   2341 
   2342 	     /* Transform this kerning distance into rotated space */
   2343 	     pen.x += (int) ( delta.x);
   2344 	     pen.y +=  0;
   2345 	  }
   2346 
   2347 	/* Set transform */
   2348 	FT_Set_Transform( face, &matrix, &pen );
   2349 
   2350 /*set char size*/
   2351 
   2352 	if (error) { std::cerr << " PNGwriter::get_text_width - ERROR **: FreeType: Set char size error." << std::endl; return 0;};
   2353 
   2354 	/* Retrieve glyph index from character code */
   2355 	glyph_index = FT_Get_Char_Index( face, text[n] );
   2356 
   2357 	/* Load glyph image into the slot (erase previous one) */
   2358 	error = FT_Load_Glyph( face, glyph_index, FT_LOAD_DEFAULT );
   2359 	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;}
   2360 
   2361 	/* Convert to an anti-aliased bitmap */
   2362 	//	error = FT_Render_Glyph( face->glyph, FT_RENDER_MODE_NORMAL );
   2363 	error = FT_Render_Glyph( face->glyph, ft_render_mode_normal );
   2364 	if (error) { std::cerr << " PNGwriter::get_text_width - ERROR **: FreeType: Render glyph error." << std::endl; return 0;}
   2365 
   2366 	/* Now, draw to our target surface */
   2367 /*	my_draw_bitmap( &slot->bitmap,
   2368 			slot->bitmap_left,
   2369 			slot->bitmap_top,
   2370 			red,
   2371 			green,
   2372 			blue );
   2373 */
   2374 	/* Advance to the next position */
   2375 	pen.x += slot->advance.x;
   2376 //	std::cout << ((double) pen.x)/64.0 << std::endl;
   2377 	pen.y += slot->advance.y;
   2378 
   2379 	/* record current glyph index */
   2380 	previous = glyph_index;
   2381      }
   2382 
   2383 
   2384    /* Free the face and the library objects */
   2385    FT_Done_Face    ( face );
   2386    FT_Done_FreeType( library );
   2387 
   2388    return (int)( ((double)pen.x)/64.0 );
   2389 }
   2390 
   2391 
   2392 int pngwriter::get_text_width_utf8(char * face_path, int fontsize,  char * text)
   2393 {
   2394    FT_Library  library;
   2395    FT_Face     face;
   2396    FT_Matrix   matrix;      // transformation matrix
   2397    FT_Vector   pen;
   2398 
   2399    FT_UInt glyph_index;
   2400    FT_Error error;
   2401 
   2402    FT_Bool use_kerning;
   2403    FT_UInt previous = 0;
   2404 
   2405    /* Set up transformation Matrix */
   2406    matrix.xx = (FT_Fixed)( 0x10000);   /* It would make more sense to do this (below), but, bizzarely, */
   2407    matrix.xy = (FT_Fixed)( 0*0x10000);   /* if one does, FT_Load_Glyph fails consistently.               */
   2408    matrix.yx = (FT_Fixed)( 0*0x10000);  //   matrix.yx = - matrix.xy;
   2409    matrix.yy = (FT_Fixed)( 0x10000);  //   matrix.yy = matrix.xx;
   2410 
   2411    /* Place starting coordinates in adequate form. */
   2412    pen.x = 0 ;
   2413    pen.y = 0;
   2414 
   2415    /*Count the length of the string */
   2416    int num_bytes=0;
   2417    while(text[num_bytes]!=0)
   2418      {
   2419 	num_bytes++;
   2420      }
   2421 
   2422 	 /*
   2423    std::cout << "Num bytes is: "<< num_bytes << std::endl;
   2424    */
   2425 
   2426    //The array of ucs4 glyph indexes, which will by at most the number of bytes in the utf-8 file.
   2427    long * ucs4text;
   2428    ucs4text = new long[num_bytes+1];
   2429 
   2430    unsigned char u,v,w,x,y,z;
   2431 
   2432    int num_chars=0;
   2433 
   2434    long iii=0;
   2435 
   2436    while(iii<num_bytes)
   2437      {
   2438 	z = text[iii];
   2439 
   2440 	if(z<=127)
   2441 	  {
   2442 	     ucs4text[num_chars] = z;
   2443 	  }
   2444 
   2445 	if((192<=z)&&(z<=223))
   2446 	  {
   2447 	     iii++; y = text[iii];
   2448 	     ucs4text[num_chars] = (z-192)*64 + (y -128);
   2449 	  }
   2450 
   2451 	if((224<=z)&&(z<=239))
   2452 	  {
   2453 	     iii++; y = text[iii];
   2454 	     iii++; x = text[iii];
   2455 	     ucs4text[num_chars] = (z-224)*4096 + (y -128)*64 + (x-128);
   2456 	  }
   2457 
   2458 	if((240<=z)&&(z<=247))
   2459 	  {
   2460 	     iii++; y = text[iii];
   2461 	     iii++; x = text[iii];
   2462 	     iii++; w = text[iii];
   2463 	     ucs4text[num_chars] = (z-240)*262144 + (y -128)*4096 + (x-128)*64 + (w-128);
   2464 	  }
   2465 
   2466 	if((248<=z)&&(z<=251))
   2467 	  {
   2468 	     iii++; y = text[iii];
   2469 	     iii++; x = text[iii];
   2470 	     iii++; w = text[iii];
   2471 	     iii++; v = text[iii];
   2472 	     ucs4text[num_chars] = (z-248)*16777216 + (y -128)*262144 + (x-128)*4096 + (w-128)*64 +(v-128);
   2473 	  }
   2474 
   2475 	if((252==z)||(z==253))
   2476 	  {
   2477 	     iii++; y = text[iii];
   2478 	     iii++; x = text[iii];
   2479 	     iii++; w = text[iii];
   2480 	     iii++; v = text[iii];
   2481 	     u = text[iii];
   2482 	     ucs4text[num_chars] = (z-252)*1073741824 + (y -128)*16777216   + (x-128)*262144 + (w-128)*4096 +(v-128)*64 + (u-128);
   2483 	  }
   2484 
   2485 	if((z==254)||(z==255))
   2486 	  {
   2487 	     std::cerr << " PNGwriter::get_text_width_utf8 - ERROR **: Problem with character: invalid UTF-8 data."<< std::endl;
   2488 	  }
   2489 	// std::cerr << "\nProblem at " << iii << ".\n";
   2490 	//
   2491 	iii++;
   2492 	num_chars++;
   2493      }
   2494 
   2495    // num_chars now contains the number of characters in the string.
   2496    /*
   2497    std::cout << "Num chars is: "<< num_chars << std::endl;
   2498    */
   2499 
   2500    /* Initialize FT Library object */
   2501    error = FT_Init_FreeType( &library );
   2502    if (error) { std::cerr << " PNGwriter::get_text_width_utf8 - ERROR **: FreeType: Could not init Library."<< std::endl; return 0;}
   2503 
   2504    /* Initialize FT face object */
   2505    error = FT_New_Face( library,face_path,0,&face );
   2506    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; }
   2507 
   2508    /* Set the Char size */
   2509    error = FT_Set_Char_Size( face,          /* handle to face object           */
   2510 			     0,             /* char_width in 1/64th of points  */
   2511 			     fontsize*64,   /* char_height in 1/64th of points */
   2512 			     100,           /* horizontal device resolution    */
   2513 			     100 );         /* vertical device resolution      */
   2514 
   2515    /* A way of accesing the glyph directly */
   2516    FT_GlyphSlot  slot = face->glyph;  // a small shortcut
   2517 
   2518    /* Does the font file support kerning? */
   2519    use_kerning = FT_HAS_KERNING( face );
   2520 
   2521    int n;
   2522    for ( n = 0; n < num_chars; n++ )
   2523      {
   2524 	/* Convert character code to glyph index */
   2525 	glyph_index = FT_Get_Char_Index( face, ucs4text[n] );
   2526 
   2527 	/* Retrieve kerning distance and move pen position */
   2528 	if ( use_kerning && previous&& glyph_index )
   2529 	  {
   2530 	     FT_Vector  delta;
   2531 	     FT_Get_Kerning( face,
   2532 			     previous,
   2533 			     glyph_index,
   2534 			     ft_kerning_default, //FT_KERNING_DEFAULT,
   2535 			     &delta );
   2536 
   2537 	     /* Transform this kerning distance into rotated space */
   2538 	     pen.x += (int) (delta.x);
   2539 	     pen.y +=  0;
   2540 	  }
   2541 
   2542 	/* Set transform */
   2543 	FT_Set_Transform( face, &matrix, &pen );
   2544 
   2545 /*set char size*/
   2546 
   2547 	if (error) { std::cerr << " PNGwriter::get_text_width_utf8 - ERROR **: FreeType: Set char size error." << std::endl; return 0;};
   2548 
   2549 	/* Retrieve glyph index from character code */
   2550 	glyph_index = FT_Get_Char_Index( face, ucs4text[n] );
   2551 
   2552 	/* Load glyph image into the slot (erase previous one) */
   2553 	error = FT_Load_Glyph( face, glyph_index, FT_LOAD_DEFAULT );
   2554 	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;}
   2555 
   2556 	/* Convert to an anti-aliased bitmap */
   2557 	error = FT_Render_Glyph( face->glyph, ft_render_mode_normal );
   2558 	if (error) { std::cerr << " PNGwriter::get_text_width_utf8 - ERROR **: FreeType: Render glyph error." << std::endl; return 0;}
   2559 
   2560 	/* Now, draw to our target surface */
   2561 /*	my_draw_bitmap( &slot->bitmap,
   2562 			slot->bitmap_left,
   2563 			y_start + slot->bitmap_top,
   2564 			red,
   2565 			green,
   2566 			blue );
   2567 */
   2568 	/* Advance to the next position */
   2569 	pen.x += slot->advance.x;
   2570 	pen.y += slot->advance.y;
   2571 
   2572 	/* record current glyph index */
   2573 	previous = glyph_index;
   2574      }
   2575 
   2576    /* Free the face and the library objects */
   2577    FT_Done_Face    ( face );
   2578    FT_Done_FreeType( library );
   2579 
   2580    delete[] ucs4text;
   2581 
   2582    return (int) (((double) pen.x)/64.0);
   2583 }
   2584 
   2585 ///////////////
   2586 #endif
   2587 #ifdef NO_FREETYPE
   2588 
   2589 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)
   2590 {
   2591    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;
   2592    return;
   2593 }
   2594 
   2595 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)
   2596 {
   2597    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;
   2598    return;
   2599 
   2600 }
   2601 
   2602 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)
   2603 {
   2604    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;
   2605    return;
   2606 }
   2607 
   2608 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)
   2609 {
   2610    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;
   2611    return;
   2612 }
   2613 
   2614 //////////// Get text width
   2615 int pngwriter::get_text_width(char * face_path, int fontsize, char * text)
   2616 {
   2617    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;
   2618    return 0;
   2619 }
   2620 
   2621 
   2622 int pngwriter::get_text_width_utf8(char * face_path, int fontsize,  char * text)
   2623 {
   2624    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;
   2625    return 0;
   2626 }
   2627 
   2628 ///////////////
   2629 #endif
   2630 
   2631 /////////////////////////////////////
   2632 int pngwriter::bilinear_interpolation_read(double x, double y, int colour)
   2633 {
   2634 
   2635    int inty, intx;
   2636    inty = (int) ceil(y);
   2637    intx = (int) ceil(x);
   2638 
   2639    //inty = (int) floor(y) +1;
   2640    // intx = (int) floor(x) +1;
   2641    //
   2642    bool attop, atright;
   2643    attop = inty==this->height_;
   2644    atright =  intx==this->width_;
   2645 /*
   2646    if( intx==this->width_ +1)
   2647      {
   2648 	intx--;
   2649 	//	std::cout << "intx--" << std::endl;
   2650 
   2651      }
   2652   */
   2653    /*
   2654    if(inty == this->height_ +1)
   2655      {
   2656 	inty--;
   2657 	//	std::cout << "inty--" << std::endl;
   2658      }
   2659    */
   2660 
   2661    if( (!attop)&&(!atright) )
   2662      {
   2663 
   2664 	double f,g,f1,g1;
   2665 	f = 1.0 + x - ((double) intx);
   2666 	g = 1.0 + y - ((double) inty);
   2667 	f1 = 1.0 - f;
   2668 	g1 = 1.0 - g;
   2669 
   2670 	return (int) (
   2671 		      f1*g1*this->read(intx, inty,colour)
   2672 		      + f*g1*this->read(intx+1,inty,colour)
   2673 		      +f1*g*this->read(intx,inty+1,colour)
   2674 		      + f*g*(this->read(intx+1,inty+1,colour))
   2675 		      );
   2676      }
   2677 
   2678    if( (atright)&&(!attop))
   2679      {
   2680 
   2681 	double f,g,f1,g1;
   2682 	f = 1.0 + x - ((double) intx);
   2683 	g = 1.0 + y - ((double) inty);
   2684 	f1 = 1.0 - f;
   2685 	g1 = 1.0 - g;
   2686 
   2687 	return (int) (
   2688 		      f1*g1*this->read(intx, inty,colour)
   2689 		      + f*g1*( 2*(this->read(intx,inty,colour)) - (this->read(intx-1,inty,colour)) )
   2690 		      +f1*g*this->read(intx,inty+1,colour)
   2691 		      + f*g*(2*(this->read(intx,inty+1,colour)) - (this->read(intx-1,inty+1,colour)))
   2692 		      );
   2693      }
   2694 
   2695    if((attop)&&(!atright))
   2696      {
   2697 	double f,g,f1,g1;
   2698 	f = 1.0 + x - ((double) intx);
   2699 	g = 1.0 + y - ((double) inty);
   2700 	f1 = 1.0 - f;
   2701 	g1 = 1.0 - g;
   2702 
   2703 	return (int) (
   2704 		      f1*g1*this->read(intx, inty,colour)
   2705 		      + f*g1*this->read(intx+1,inty,colour)
   2706 		      +f1*g*( 2*(this->read(intx,inty,colour))  - this->read(intx,inty-1,colour) )
   2707 		      + f*g*( 2*(this->read(intx+1,inty,colour))  - this->read(intx+1,inty-1,colour))
   2708 		      );
   2709      }
   2710 
   2711    double f,g,f1,g1;
   2712    f = 1.0 + x - ((double) intx);
   2713    g = 1.0 + y - ((double) inty);
   2714    f1 = 1.0 - f;
   2715    g1 = 1.0 - g;
   2716 
   2717    return (int) (
   2718 		 f1*g1*this->read(intx, inty,colour)
   2719 		 + f*g1*( 2*(this->read(intx,inty,colour)) - (this->read(intx-1,inty,colour)) )
   2720 		 +f1*g*( 2*(this->read(intx,inty,colour))  - this->read(intx,inty-1,colour) )
   2721 		 + 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)) ))
   2722 		 );
   2723 
   2724    /*
   2725     return (int) (
   2726     f1*g1*this->read(intx, inty,colour)
   2727     + f*g1*this->read(intx+1,inty,colour)
   2728     +f1*g*this->read(intx,inty+1,colour)
   2729     + f*g*this->read(intx+1, inty+1,colour)
   2730     );
   2731     * */
   2732 
   2733 };
   2734 
   2735 double pngwriter::bilinear_interpolation_dread(double x, double y, int colour)
   2736 {
   2737    return double(this->bilinear_interpolation_read(x,y,colour))/65535.0;
   2738 };
   2739 
   2740 void pngwriter::plot_blend(int x, int y, double opacity, int red, int green, int blue)
   2741 {
   2742    this->plot(x, y,
   2743 	      (int)(  opacity*red   +  this->read(x,y,1)*(1.0-opacity)),
   2744 	      (int)( opacity*green +  this->read(x,y,2)*(1.0-opacity)),
   2745 	      (int)( opacity*blue  +  this->read(x,y,3)*(1.0-opacity))
   2746 	      );
   2747 };
   2748 
   2749 void pngwriter::plot_blend(int x, int y, double opacity, double red, double green, double blue)
   2750 {
   2751    this->plot_blend(x, y, opacity, (int)  (65535*red), (int)  (65535*green),  (int)  (65535*blue));
   2752 };
   2753 
   2754 void pngwriter::invert(void)
   2755 {
   2756    //   int temp1, temp2, temp3;
   2757    double temp11, temp22, temp33;
   2758 
   2759    for(int jjj = 1; jjj <= (this->height_); jjj++)
   2760      {
   2761 	for(int iii = 1; iii <= (this->width_); iii++)
   2762 	  {
   2763 	     /*	     temp11 = (this->read(iii,jjj,1));
   2764 	      temp22 = (this->read(iii,jjj,2));
   2765 	      temp33 = (this->read(iii,jjj,3));
   2766 	      *
   2767 	      this->plot(iii,jjj,
   2768 	      ((double)(65535 - temp11))/65535.0,
   2769 	      ((double)(65535 - temp22))/65535.0,
   2770 	      ((double)(65535 - temp33))/65535.0
   2771 	      );
   2772 	      *
   2773 	      */
   2774 	     temp11 = (this->read(iii,jjj,1));
   2775 	     temp22 = (this->read(iii,jjj,2));
   2776 	     temp33 = (this->read(iii,jjj,3));
   2777 
   2778 	     this->plot(iii,jjj,
   2779 			(int)(65535 - temp11),
   2780 			(int)(65535 - temp22),
   2781 			(int)(65535 - temp33)
   2782 			);
   2783 
   2784 	  }
   2785      }
   2786 }
   2787 
   2788 void pngwriter::resize(int width, int height)
   2789 {
   2790 
   2791    for (int jjj = 0; jjj < height_; jjj++) free(graph_[jjj]);
   2792    free(graph_);
   2793 
   2794    width_ = width;
   2795    height_ = height;
   2796    backgroundcolour_ = 0;
   2797 
   2798    graph_ = (png_bytepp)malloc(height_ * sizeof(png_bytep));
   2799    if(graph_ == NULL)
   2800      {
   2801 	std::cerr << " PNGwriter::resize - ERROR **:  Not able to allocate memory for image." << std::endl;
   2802      }
   2803 
   2804    for (int kkkk = 0; kkkk < height_; kkkk++)
   2805      {
   2806 	graph_[kkkk] = (png_bytep)malloc(6*width_ * sizeof(png_byte));
   2807 	if(graph_[kkkk] == NULL)
   2808 	  {
   2809 	     std::cerr << " PNGwriter::resize - ERROR **:  Not able to allocate memory for image." << std::endl;
   2810 	  }
   2811      }
   2812 
   2813    if(graph_ == NULL)
   2814      {
   2815 	std::cerr << " PNGwriter::resize - ERROR **:  Not able to allocate memory for image." << std::endl;
   2816      }
   2817 
   2818    int tempindex;
   2819    for(int hhh = 0; hhh<width_;hhh++)
   2820      {
   2821 	for(int vhhh = 0; vhhh<height_;vhhh++)
   2822 	  {
   2823 	     //graph_[vhhh][6*hhh + i] where i goes from 0 to 5
   2824 	     tempindex = 6*hhh;
   2825 	     graph_[vhhh][tempindex] = (char) floor(((double)backgroundcolour_)/256);
   2826 	     graph_[vhhh][tempindex+1] = (char)(backgroundcolour_%256);
   2827 	     graph_[vhhh][tempindex+2] = (char) floor(((double)backgroundcolour_)/256);
   2828 	     graph_[vhhh][tempindex+3] = (char)(backgroundcolour_%256);
   2829 	     graph_[vhhh][tempindex+4] = (char) floor(((double)backgroundcolour_)/256);
   2830 	     graph_[vhhh][tempindex+5] = (char)(backgroundcolour_%256);
   2831 	  }
   2832      }
   2833 }
   2834 
   2835 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)
   2836 {
   2837    if( (
   2838 	(this->dread(xstart,ystart,1) != boundary_red) ||
   2839 	(this->dread(xstart,ystart,2) != boundary_green) ||
   2840 	(this->dread(xstart,ystart,3) != boundary_blue)
   2841 	)
   2842        &&
   2843        (
   2844 	(this->dread(xstart,ystart,1) != fill_red) ||
   2845 	(this->dread(xstart,ystart,2) != fill_green) ||
   2846 	(this->dread(xstart,ystart,3) != fill_blue)
   2847 	)
   2848        &&
   2849        (xstart >0)&&(xstart <= width_)&&(ystart >0)&&(ystart <= height_)
   2850        )
   2851      {
   2852 	this->plot(xstart, ystart, fill_red, fill_green, fill_blue);
   2853 	boundary_fill(xstart+1,  ystart,  boundary_red, boundary_green, boundary_blue, fill_red,  fill_green,  fill_blue) ;
   2854 	boundary_fill(xstart,  ystart+1,  boundary_red, boundary_green, boundary_blue, fill_red,  fill_green,  fill_blue) ;
   2855 	boundary_fill(xstart,  ystart-1,  boundary_red, boundary_green, boundary_blue, fill_red,  fill_green,  fill_blue) ;
   2856 	boundary_fill(xstart-1,  ystart,  boundary_red, boundary_green, boundary_blue, fill_red,  fill_green,  fill_blue) ;
   2857      }
   2858 }
   2859 
   2860 //no int version needed
   2861 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)
   2862 {
   2863    if( (
   2864 	(this->dread(xstart,ystart,1) == start_red) &&
   2865 	(this->dread(xstart,ystart,2) == start_green) &&
   2866 	(this->dread(xstart,ystart,3) == start_blue)
   2867 	)
   2868        &&
   2869        (
   2870 	(this->dread(xstart,ystart,1) != fill_red) ||
   2871 	(this->dread(xstart,ystart,2) != fill_green) ||
   2872 	(this->dread(xstart,ystart,3) != fill_blue)
   2873 	)
   2874        &&
   2875        (xstart >0)&&(xstart <= width_)&&(ystart >0)&&(ystart <= height_)
   2876        )
   2877      {
   2878 	this->plot(xstart, ystart, fill_red, fill_green, fill_blue);
   2879 	flood_fill_internal(  xstart+1,  ystart,   start_red,  start_green,  start_blue,  fill_red,  fill_green,  fill_blue);
   2880 	flood_fill_internal(  xstart-1,  ystart,   start_red,  start_green,  start_blue,  fill_red,  fill_green,  fill_blue);
   2881 	flood_fill_internal(  xstart,  ystart+1,   start_red,  start_green,  start_blue,  fill_red,  fill_green,  fill_blue);
   2882 	flood_fill_internal(  xstart,  ystart-1,   start_red,  start_green,  start_blue,  fill_red,  fill_green,  fill_blue);
   2883      }
   2884 
   2885 }
   2886 
   2887 //int version
   2888 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)
   2889 {
   2890 
   2891    this->boundary_fill( xstart, ystart,
   2892 			((double) boundary_red)/65535.0,
   2893 			((double) boundary_green)/65535.0,
   2894 			((double) boundary_blue)/65535.0,
   2895 			((double) fill_red)/65535.0,
   2896 			((double) fill_green)/65535.0,
   2897 			((double) fill_blue)/65535.0
   2898 			);
   2899 }
   2900 
   2901 void pngwriter::flood_fill(int xstart, int ystart, double fill_red, double fill_green, double fill_blue)
   2902 {
   2903    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);
   2904 }
   2905 
   2906 //int version
   2907 void pngwriter::flood_fill(int xstart, int ystart, int fill_red, int fill_green, int fill_blue)
   2908 {
   2909    this->flood_fill( xstart,  ystart,
   2910 		     ((double)  fill_red)/65535.0,
   2911 		     ((double) fill_green)/65535.0,
   2912 		     ((double)  fill_blue)/65535.0
   2913 		     );
   2914 }
   2915 
   2916 void pngwriter::polygon( int * points, int number_of_points, double red, double green, double blue)
   2917 {
   2918    if( (number_of_points<1)||(points ==NULL))
   2919      {
   2920 	std::cerr << " PNGwriter::polygon - ERROR **:  Number of points is zero or negative, or array is NULL." << std::endl;
   2921 	return;
   2922      }
   2923 
   2924    for(int k=0;k< number_of_points-1; k++)
   2925      {
   2926 	this->line(points[2*k],points[2*k+1],points[2*k+2],points[2*k+3], red, green, blue);
   2927      }
   2928 }
   2929 
   2930 //int version
   2931 void pngwriter::polygon( int * points, int number_of_points, int red, int green, int blue)
   2932 {
   2933    this->polygon(points, number_of_points,
   2934 		 ((double) red)/65535.0,
   2935 		 ((double) green)/65535.0,
   2936 		 ((double) blue)/65535.0
   2937 		 );
   2938 }
   2939 
   2940 void pngwriter::plotCMYK(int x, int y, double cyan, double magenta, double yellow, double black)
   2941 {
   2942 /*CMYK to RGB:
   2943  *  -----------
   2944  *  red   = 255 - minimum(255,((cyan/255)    * (255 - black) + black))
   2945  *  green = 255 - minimum(255,((magenta/255) * (255 - black) + black))
   2946  *  blue  = 255 - minimum(255,((yellow/255)  * (255 - black) + black))
   2947  * */
   2948 
   2949    if(cyan<0.0)
   2950      {
   2951 	cyan = 0.0;
   2952      }
   2953    if(magenta<0.0)
   2954      {
   2955 	magenta = 0.0;
   2956      }
   2957    if(yellow<0.0)
   2958      {
   2959 	yellow = 0.0;
   2960      }
   2961    if(black<0.0)
   2962      {
   2963 	black = 0.0;
   2964      }
   2965 
   2966    if(cyan>1.0)
   2967      {
   2968 	cyan = 1.0;
   2969      }
   2970    if(magenta>1.0)
   2971      {
   2972 	magenta = 1.0;
   2973      }
   2974    if(yellow>1.0)
   2975      {
   2976 	yellow = 1.0;
   2977      }
   2978    if(black>1.0)
   2979      {
   2980 	black = 1.0;
   2981      }
   2982 
   2983    double  red, green, blue, minr, ming, minb, iblack;
   2984 
   2985    iblack = 1.0 - black;
   2986 
   2987    minr = 1.0;
   2988    ming = 1.0;
   2989    minb = 1.0;
   2990 
   2991    if( (cyan*iblack + black)<1.0 )
   2992      {
   2993 	minr = cyan*iblack + black;
   2994      }
   2995 
   2996    if( (magenta*iblack + black)<1.0 )
   2997      {
   2998 	ming = magenta*iblack + black;
   2999      }
   3000 
   3001    if( (yellow*iblack + black)<1.0 )
   3002      {
   3003 	minb = yellow*iblack + black;
   3004      }
   3005 
   3006    red = 1.0 - minr;
   3007    green = 1.0 - ming;
   3008    blue = 1.0 - minb;
   3009 
   3010    this->plot(x,y,red, green, blue);
   3011 
   3012 }
   3013 
   3014 //int version
   3015 void pngwriter::plotCMYK(int x, int y, int cyan, int magenta, int yellow, int black)
   3016 {
   3017    this->plotCMYK( x, y,
   3018 		   ((double) cyan)/65535.0,
   3019 		   ((double) magenta)/65535.0,
   3020 		   ((double) yellow)/65535.0,
   3021 		   ((double) black)/65535.0
   3022 		   );
   3023 }
   3024 
   3025 double pngwriter::dreadCMYK(int x, int y, int colour)
   3026 {
   3027 /*
   3028  * Black   = minimum(1-Red,1-Green,1-Blue)
   3029  *     Cyan    = (1-Red-Black)/(1-Black)
   3030  *     Magenta = (1-Green-Black)/(1-Black)
   3031  *     Yellow  = (1-Blue-Black)/(1-Black)
   3032  *
   3033  * */
   3034    if((colour !=1)&&(colour !=2)&&(colour !=3)&&(colour !=4))
   3035      {
   3036 	std::cerr << " PNGwriter::dreadCMYK - WARNING **: Invalid argument: should be 1, 2, 3 or 4, is " << colour << std::endl;
   3037 	return 0;
   3038      }
   3039 
   3040    double black, red, green, blue, ired, igreen, iblue, iblack;
   3041    //add error detection here
   3042    // not much to detect, really
   3043    red = this->dread(x, y, 1);
   3044    green = this->dread(x, y, 2);
   3045    blue = this->dread(x, y, 3);
   3046 
   3047    ired = 1.0 - red;
   3048    igreen = 1.0 - green;
   3049    iblue = 1.0 - blue;
   3050 
   3051    black = ired;
   3052 
   3053    //black is the mimimum of inverse RGB colours, and if they are all equal, it is the inverse of red.
   3054    if( (igreen<ired)&&(igreen<iblue) )
   3055      {
   3056 	black = igreen;
   3057      }
   3058 
   3059    if( (iblue<igreen)&&(iblue<ired) )
   3060      {
   3061 	black = iblue;
   3062      }
   3063 
   3064    iblack = 1.0 - black;
   3065 
   3066    if(colour == 1)
   3067      {
   3068 	return ((ired-black)/(iblack));
   3069      }
   3070 
   3071    if(colour == 2)
   3072      {
   3073 	return ((igreen-black)/(iblack));
   3074      }
   3075 
   3076    if(colour == 3)
   3077      {
   3078 	return ((iblue-black)/(iblack));
   3079      }
   3080 
   3081    if(colour == 4)
   3082      {
   3083 	return black;
   3084      }
   3085 
   3086    return 0.0;
   3087 }
   3088 
   3089 int pngwriter::readCMYK(int x, int y, int colour)
   3090 {
   3091 /*
   3092  * Black   = minimum(1-Red,1-Green,1-Blue)
   3093  *     Cyan    = (1-Red-Black)/(1-Black)
   3094  *     Magenta = (1-Green-Black)/(1-Black)
   3095  *     Yellow  = (1-Blue-Black)/(1-Black)
   3096  *
   3097  * */
   3098    if((colour !=1)&&(colour !=2)&&(colour !=3)&&(colour !=4))
   3099      {
   3100 	std::cerr << " PNGwriter::readCMYK - WARNING **: Invalid argument: should be 1, 2, 3 or 4, is " << colour << std::endl;
   3101 	return 0;
   3102      }
   3103 
   3104    double black, red, green, blue, ired, igreen, iblue, iblack;
   3105    //add error detection here
   3106    // not much to detect, really
   3107    red = this->dread(x, y, 1);
   3108    green = this->dread(x, y, 2);
   3109    blue = this->dread(x, y, 3);
   3110 
   3111    ired = 1.0 - red;
   3112    igreen = 1.0 - green;
   3113    iblue = 1.0 - blue;
   3114 
   3115    black = ired;
   3116 
   3117    //black is the mimimum of inverse RGB colours, and if they are all equal, it is the inverse of red.
   3118    if( (igreen<ired)&&(igreen<iblue) )
   3119      {
   3120 	black = igreen;
   3121      }
   3122 
   3123    if( (iblue<igreen)&&(iblue<ired) )
   3124      {
   3125 	black = iblue;
   3126      }
   3127 
   3128    iblack = 1.0 - black;
   3129 
   3130    if(colour == 1)
   3131      {
   3132 	return (int)( ((ired-black)/(iblack))*65535);
   3133      }
   3134 
   3135    if(colour == 2)
   3136      {
   3137 	return (int)( ((igreen-black)/(iblack))*65535);
   3138      }
   3139 
   3140    if(colour == 3)
   3141      {
   3142 	return (int)( ((iblue-black)/(iblack))*65535);
   3143      }
   3144 
   3145    if(colour == 4)
   3146      {
   3147 	return (int)( (black)*65535);
   3148      }
   3149 
   3150    return 0;
   3151 
   3152 }
   3153 
   3154 void pngwriter::scale_k(double k)
   3155 {
   3156    if(k <= 0.0)
   3157      {
   3158 	std::cerr << " PNGwriter::scale_k - ERROR **:  scale_k() called with negative or zero scale factor. Was: " << k << "." << std::endl;
   3159      }
   3160 
   3161    // Calculate the new scaled height and width
   3162    int scaledh, scaledw;
   3163    scaledw = (int) ceil(k*width_);
   3164    scaledh = (int) ceil(k*height_);
   3165 
   3166    // Create image storage.
   3167    pngwriter temp(scaledw,scaledh,0,"temp");
   3168 
   3169    int red, green, blue;
   3170 
   3171    double spacingx = ((double)width_)/(2*scaledw);
   3172    double spacingy = ((double)height_)/(2*scaledh);
   3173 
   3174    double readx, ready;
   3175 
   3176    for(int x = 1; x<= scaledw; x++)
   3177      {
   3178 	for(int y = 1; y <= scaledh; y++)
   3179 	  {
   3180 	     readx = (2*x-1)*spacingx;
   3181 	     ready = (2*y-1)*spacingy;
   3182 	     red = this->bilinear_interpolation_read(readx, ready, 1);
   3183 	     green = this->bilinear_interpolation_read(readx, ready, 2);
   3184 	     blue = this->bilinear_interpolation_read(readx, ready, 3);
   3185 	     temp.plot(x, y, red, green, blue);
   3186 
   3187 	  }
   3188      }
   3189 
   3190    // From here on, the process is the same for all scale functions.
   3191    //Get data out of temp and into this's storage.
   3192 
   3193    //Resize this instance
   3194    // Delete current storage.
   3195    for (int jjj = 0; jjj < height_; jjj++) free(graph_[jjj]);
   3196    free(graph_);
   3197 
   3198    //New image will have bit depth 16, regardless of original bit depth.
   3199    bit_depth_ = 16;
   3200 
   3201    // New width and height will be the scaled width and height
   3202    width_ = scaledw;
   3203    height_ = scaledh;
   3204    backgroundcolour_ = 0;
   3205 
   3206    graph_ = (png_bytepp)malloc(height_ * sizeof(png_bytep));
   3207    if(graph_ == NULL)
   3208      {
   3209 	std::cerr << " PNGwriter::scale_k - ERROR **:  Not able to allocate memory for image." << std::endl;
   3210      }
   3211 
   3212    for (int kkkk = 0; kkkk < height_; kkkk++)
   3213      {
   3214 	graph_[kkkk] = (png_bytep)malloc(6*width_ * sizeof(png_byte));
   3215 	if(graph_[kkkk] == NULL)
   3216 	  {
   3217 	     std::cerr << " PNGwriter::scale_k - ERROR **:  Not able to allocate memory for image." << std::endl;
   3218 	  }
   3219      }
   3220 
   3221    if(graph_ == NULL)
   3222      {
   3223 	std::cerr << " PNGwriter::scale_k - ERROR **:  Not able to allocate memory for image." << std::endl;
   3224      }
   3225 
   3226    //This instance now has a new, resized storage space.
   3227 
   3228    //Copy the temp date into this's storage.
   3229    int tempindex;
   3230    for(int hhh = 0; hhh<width_;hhh++)
   3231      {
   3232 	for(int vhhh = 0; vhhh<height_;vhhh++)
   3233 	  {
   3234 	     tempindex=6*hhh;
   3235 	     graph_[vhhh][tempindex] = temp.graph_[vhhh][tempindex];
   3236 	     graph_[vhhh][tempindex+1] = temp.graph_[vhhh][tempindex+1];
   3237 	     graph_[vhhh][tempindex+2] = temp.graph_[vhhh][tempindex+2];
   3238 	     graph_[vhhh][tempindex+3] = temp.graph_[vhhh][tempindex+3];
   3239 	     graph_[vhhh][tempindex+4] = temp.graph_[vhhh][tempindex+4];
   3240 	     graph_[vhhh][tempindex+5] = temp.graph_[vhhh][tempindex+5];
   3241 	  }
   3242      }
   3243 
   3244    // this should now contain the new, scaled image data.
   3245    //
   3246 }
   3247 
   3248 void pngwriter::scale_kxky(double kx, double ky)
   3249 {
   3250    if((kx <= 0.0)||(ky <= 0.0))
   3251      {
   3252 	std::cerr << " PNGwriter::scale_kxky - ERROR **:  scale_kxky() called with negative or zero scale factor. Was: " << kx << ", " << ky << "." << std::endl;
   3253      }
   3254 
   3255    int scaledh, scaledw;
   3256    scaledw = (int) ceil(kx*width_);
   3257    scaledh = (int) ceil(ky*height_);
   3258 
   3259    pngwriter temp(scaledw, scaledh, 0, "temp");
   3260 
   3261    int red, green, blue;
   3262 
   3263    double spacingx = ((double)width_)/(2*scaledw);
   3264    double spacingy = ((double)height_)/(2*scaledh);
   3265 
   3266    double readx, ready;
   3267 
   3268    for(int x = 1; x<= scaledw; x++)
   3269      {
   3270 	for(int y = 1; y <= scaledh; y++)
   3271 	  {
   3272 	     readx = (2*x-1)*spacingx;
   3273 	     ready = (2*y-1)*spacingy;
   3274 	     red = this->bilinear_interpolation_read(readx, ready, 1);
   3275 	     green = this->bilinear_interpolation_read(readx, ready, 2);
   3276 	     blue = this->bilinear_interpolation_read(readx, ready, 3);
   3277 	     temp.plot(x, y, red, green, blue);
   3278 
   3279 	  }
   3280      }
   3281    // From here on, the process is the same for all scale functions.
   3282    //Get data out of temp and into this's storage.
   3283 
   3284    //Resize this instance
   3285    // Delete current storage.
   3286    for (int jjj = 0; jjj < height_; jjj++) free(graph_[jjj]);
   3287    free(graph_);
   3288 
   3289    //New image will have bit depth 16, regardless of original bit depth.
   3290    bit_depth_ = 16;
   3291 
   3292    // New width and height will be the scaled width and height
   3293    width_ = scaledw;
   3294    height_ = scaledh;
   3295    backgroundcolour_ = 0;
   3296 
   3297    graph_ = (png_bytepp)malloc(height_ * sizeof(png_bytep));
   3298    if(graph_ == NULL)
   3299      {
   3300 	std::cerr << " PNGwriter::scale_kxky - ERROR **:  Not able to allocate memory for image." << std::endl;
   3301      }
   3302 
   3303    for (int kkkk = 0; kkkk < height_; kkkk++)
   3304      {
   3305 	graph_[kkkk] = (png_bytep)malloc(6*width_ * sizeof(png_byte));
   3306 	if(graph_[kkkk] == NULL)
   3307 	  {
   3308 	     std::cerr << " PNGwriter::scale_kxky - ERROR **:  Not able to allocate memory for image." << std::endl;
   3309 	  }
   3310      }
   3311 
   3312    if(graph_ == NULL)
   3313      {
   3314 	std::cerr << " PNGwriter::scale_kxky - ERROR **:  Not able to allocate memory for image." << std::endl;
   3315      }
   3316 
   3317    //This instance now has a new, resized storage space.
   3318 
   3319    //Copy the temp date into this's storage.
   3320    int tempindex;
   3321    for(int hhh = 0; hhh<width_;hhh++)
   3322      {
   3323 	for(int vhhh = 0; vhhh<height_;vhhh++)
   3324 	  {
   3325 	     tempindex=6*hhh;
   3326 	     graph_[vhhh][tempindex] = temp.graph_[vhhh][tempindex];
   3327 	     graph_[vhhh][tempindex+1] = temp.graph_[vhhh][tempindex+1];
   3328 	     graph_[vhhh][tempindex+2] = temp.graph_[vhhh][tempindex+2];
   3329 	     graph_[vhhh][tempindex+3] = temp.graph_[vhhh][tempindex+3];
   3330 	     graph_[vhhh][tempindex+4] = temp.graph_[vhhh][tempindex+4];
   3331 	     graph_[vhhh][tempindex+5] = temp.graph_[vhhh][tempindex+5];
   3332 	  }
   3333      }
   3334 
   3335    // this should now contain the new, scaled image data.
   3336    //
   3337    //
   3338 }
   3339 
   3340 void pngwriter::scale_wh(int finalwidth, int finalheight)
   3341 {
   3342    if((finalwidth <= 0)||(finalheight <= 0))
   3343      {
   3344 	std::cerr << " PNGwriter::scale_wh - ERROR **: Negative or zero final width or height not allowed." << std::endl;
   3345      }
   3346 
   3347    double kx;
   3348    double ky;
   3349 
   3350    kx = ((double)finalwidth)/((double)width_);
   3351    ky = ((double)finalheight)/((double)height_);
   3352 
   3353    pngwriter temp(finalwidth, finalheight, 0, "temp");
   3354 
   3355    int red, green, blue;
   3356 
   3357    double spacingx = ((double)width_)/(2*finalwidth);
   3358    double spacingy = ((double)height_)/(2*finalheight);
   3359 
   3360    double readx, ready;
   3361 
   3362    for(int x = 1; x<= finalwidth; x++)
   3363      {
   3364 	for(int y = 1; y <= finalheight; y++)
   3365 	  {
   3366 	     readx = (2*x-1)*spacingx;
   3367 	     ready = (2*y-1)*spacingy;
   3368 	     red = this->bilinear_interpolation_read(readx, ready, 1);
   3369 	     green = this->bilinear_interpolation_read(readx, ready, 2);
   3370 	     blue = this->bilinear_interpolation_read(readx, ready, 3);
   3371 	     temp.plot(x, y, red, green, blue);
   3372 
   3373 	  }
   3374      }
   3375 
   3376    // From here on, the process is the same for all scale functions.
   3377    //Get data out of temp and into this's storage.
   3378 
   3379    //Resize this instance
   3380    // Delete current storage.
   3381    for (int jjj = 0; jjj < height_; jjj++) free(graph_[jjj]);
   3382    free(graph_);
   3383 
   3384    //New image will have bit depth 16, regardless of original bit depth.
   3385    bit_depth_ = 16;
   3386 
   3387    // New width and height will be the scaled width and height
   3388    width_ = finalwidth;
   3389    height_ = finalheight;
   3390    backgroundcolour_ = 0;
   3391 
   3392    graph_ = (png_bytepp)malloc(height_ * sizeof(png_bytep));
   3393    if(graph_ == NULL)
   3394      {
   3395 	std::cerr << " PNGwriter::scale_wh - ERROR **:  Not able to allocate memory for image." << std::endl;
   3396      }
   3397 
   3398    for (int kkkk = 0; kkkk < height_; kkkk++)
   3399      {
   3400 	graph_[kkkk] = (png_bytep)malloc(6*width_ * sizeof(png_byte));
   3401 	if(graph_[kkkk] == NULL)
   3402 	  {
   3403 	     std::cerr << " PNGwriter::scale_wh - ERROR **:  Not able to allocate memory for image." << std::endl;
   3404 	  }
   3405      }
   3406 
   3407    if(graph_ == NULL)
   3408      {
   3409 	std::cerr << " PNGwriter::scale_wh - ERROR **:  Not able to allocate memory for image." << std::endl;
   3410      }
   3411 
   3412    //This instance now has a new, resized storage space.
   3413 
   3414    //Copy the temp date into this's storage.
   3415    int tempindex;
   3416    for(int hhh = 0; hhh<width_;hhh++)
   3417      {
   3418 	for(int vhhh = 0; vhhh<height_;vhhh++)
   3419 	  {
   3420 	     tempindex=6*hhh;
   3421 	     graph_[vhhh][tempindex] = temp.graph_[vhhh][tempindex];
   3422 	     graph_[vhhh][tempindex+1] = temp.graph_[vhhh][tempindex+1];
   3423 	     graph_[vhhh][tempindex+2] = temp.graph_[vhhh][tempindex+2];
   3424 	     graph_[vhhh][tempindex+3] = temp.graph_[vhhh][tempindex+3];
   3425 	     graph_[vhhh][tempindex+4] = temp.graph_[vhhh][tempindex+4];
   3426 	     graph_[vhhh][tempindex+5] = temp.graph_[vhhh][tempindex+5];
   3427 	  }
   3428      }
   3429 
   3430    // this should now contain the new, scaled image data.
   3431    //
   3432    //
   3433 }
   3434 
   3435 // Blended functions
   3436 //
   3437 void pngwriter::plotHSV_blend(int x, int y, double opacity, double hue, double saturation, double value)
   3438 {
   3439    double red,green,blue;
   3440    double *redp;
   3441    double *greenp;
   3442    double *bluep;
   3443 
   3444    redp = &red;
   3445    greenp = &green;
   3446    bluep = &blue;
   3447 
   3448    HSVtoRGB(redp,greenp,bluep,hue,saturation,value);
   3449    plot_blend(x,y,opacity, red,green,blue);
   3450 
   3451 }
   3452 
   3453 void pngwriter::plotHSV_blend(int x, int y, double opacity, int hue, int saturation, int value)
   3454 {
   3455    plotHSV_blend(x, y, opacity, double(hue)/65535.0, double(saturation)/65535.0,  double(value)/65535.0);
   3456 }
   3457 
   3458 void pngwriter::line_blend(int xfrom, int yfrom, int xto, int yto,  double opacity, int red, int green,int  blue)
   3459 {
   3460    //  Bresenham Algorithm.
   3461    //
   3462    int dy = yto - yfrom;
   3463    int dx = xto - xfrom;
   3464    int stepx, stepy;
   3465 
   3466    if (dy < 0)
   3467      {
   3468 	dy = -dy;  stepy = -1;
   3469      }
   3470    else
   3471      {
   3472 	stepy = 1;
   3473      }
   3474 
   3475    if (dx < 0)
   3476      {
   3477 	dx = -dx;  stepx = -1;
   3478      }
   3479    else
   3480      {
   3481 	stepx = 1;
   3482      }
   3483    dy <<= 1;     // dy is now 2*dy
   3484    dx <<= 1;     // dx is now 2*dx
   3485 
   3486    this->plot_blend(xfrom,yfrom,opacity, red,green,blue);
   3487 
   3488    if (dx > dy)
   3489      {
   3490 	int fraction = dy - (dx >> 1);
   3491 
   3492 	while (xfrom != xto)
   3493 	  {
   3494 	     if (fraction >= 0)
   3495 	       {
   3496 		  yfrom += stepy;
   3497 		  fraction -= dx;
   3498 	       }
   3499 	     xfrom += stepx;
   3500 	     fraction += dy;
   3501 	     this->plot_blend(xfrom,yfrom,opacity, red,green,blue);
   3502 	  }
   3503      }
   3504    else
   3505      {
   3506 	int fraction = dx - (dy >> 1);
   3507 	while (yfrom != yto)
   3508 	  {
   3509 	     if (fraction >= 0)
   3510 	       {
   3511 		  xfrom += stepx;
   3512 		  fraction -= dy;
   3513 	       }
   3514 	     yfrom += stepy;
   3515 	     fraction += dx;
   3516 	     this->plot_blend(xfrom,yfrom, opacity, red,green,blue);
   3517 	  }
   3518      }
   3519 
   3520 }
   3521 
   3522 void pngwriter::line_blend(int xfrom, int yfrom, int xto, int yto, double opacity, double red, double green,double  blue)
   3523 {
   3524    this->line_blend( xfrom,
   3525 		     yfrom,
   3526 		     xto,
   3527 		     yto,
   3528 		     opacity,
   3529 		     int (red*65535),
   3530 		     int (green*65535),
   3531 		     int (blue*65535)
   3532 		     );
   3533 
   3534 }
   3535 
   3536 void pngwriter::square_blend(int xfrom, int yfrom, int xto, int yto, double opacity, int red, int green,int  blue)
   3537 {
   3538    this->line_blend(xfrom, yfrom, xfrom, yto, opacity, red, green, blue);
   3539    this->line_blend(xto, yfrom, xto, yto, opacity, red, green, blue);
   3540    this->line_blend(xfrom, yfrom, xto, yfrom, opacity, red, green, blue);
   3541    this->line_blend(xfrom, yto, xto, yto, opacity,  red, green, blue);
   3542 }
   3543 
   3544 void pngwriter::square_blend(int xfrom, int yfrom, int xto, int yto, double opacity, double red, double green,double  blue)
   3545 {
   3546    this->square_blend( xfrom,  yfrom,  xto,  yto, opacity, int(red*65535), int(green*65535), int(blue*65535));
   3547 }
   3548 
   3549 void pngwriter::filledsquare_blend(int xfrom, int yfrom, int xto, int yto, double opacity, int red, int green,int  blue)
   3550 {
   3551    for(int caca = xfrom; caca <xto+1; caca++)
   3552      {
   3553 	this->line_blend(caca, yfrom, caca, yto, opacity, red, green, blue);
   3554      }
   3555 
   3556 }
   3557 
   3558 void pngwriter::filledsquare_blend(int xfrom, int yfrom, int xto, int yto, double opacity, double red, double green,double  blue)
   3559 {
   3560    this->filledsquare_blend( xfrom,  yfrom,  xto,  yto, opacity, int(red*65535), int(green*65535), int(blue*65535));
   3561 }
   3562 
   3563 void pngwriter::circle_aux_blend(int xcentre, int ycentre, int x, int y, double opacity, int red, int green, int blue)
   3564 {
   3565    if (x == 0)
   3566      {
   3567 	this->plot_blend( xcentre, ycentre + y, opacity, red, green, blue);
   3568 	this->plot_blend( xcentre, ycentre - y, opacity, red, green, blue);
   3569 	this->plot_blend( xcentre + y, ycentre, opacity, red, green, blue);
   3570 	this->plot_blend( xcentre - y, ycentre, opacity, red, green, blue);
   3571      }
   3572    else
   3573      if (x == y)
   3574        {
   3575 	  this->plot_blend( xcentre + x, ycentre + y, opacity, red, green, blue);
   3576 	  this->plot_blend( xcentre - x, ycentre + y, opacity, red, green, blue);
   3577 	  this->plot_blend( xcentre + x, ycentre - y, opacity, red, green, blue);
   3578 	  this->plot_blend( xcentre - x, ycentre - y, opacity, red, green, blue);
   3579        }
   3580    else
   3581      if (x < y)
   3582        {
   3583 	  this->plot_blend( xcentre + x, ycentre + y, opacity, red, green, blue);
   3584 	  this->plot_blend( xcentre - x, ycentre + y, opacity, red, green, blue);
   3585 	  this->plot_blend( xcentre + x, ycentre - y, opacity, red, green, blue);
   3586 	  this->plot_blend( xcentre - x, ycentre - y, opacity, red, green, blue);
   3587 	  this->plot_blend( xcentre + y, ycentre + x, opacity, red, green, blue);
   3588 	  this->plot_blend( xcentre - y, ycentre + x, opacity, red, green, blue);
   3589 	  this->plot_blend( xcentre + y, ycentre - x, opacity, red, green, blue);
   3590 	  this->plot_blend( xcentre - y, ycentre - x, opacity, red, green, blue);
   3591        }
   3592 
   3593 }
   3594 //
   3595 
   3596 void pngwriter::circle_blend(int xcentre, int ycentre, int radius, double opacity, int red, int green, int blue)
   3597 {
   3598    int x = 0;
   3599    int y = radius;
   3600    int p = (5 - radius*4)/4;
   3601 
   3602    circle_aux_blend(xcentre, ycentre, x, y, opacity, red, green, blue);
   3603    while (x < y)
   3604      {
   3605 	x++;
   3606 	if (p < 0)
   3607 	  {
   3608 	     p += 2*x+1;
   3609 	  }
   3610 	else
   3611 	  {
   3612 	     y--;
   3613 	     p += 2*(x-y)+1;
   3614 	  }
   3615 	circle_aux_blend(xcentre, ycentre, x, y, opacity, red, green, blue);
   3616      }
   3617 
   3618 }
   3619 
   3620 void pngwriter::circle_blend(int xcentre, int ycentre, int radius, double opacity, double red, double green, double blue)
   3621 {
   3622    this->circle_blend(xcentre,ycentre,radius, opacity,  int(red*65535), int(green*65535), int(blue*65535));
   3623 }
   3624 
   3625 void pngwriter::filledcircle_blend(int xcentre, int ycentre, int radius, double opacity, int red, int green, int blue)
   3626 {
   3627    for(int jjj = ycentre-radius; jjj< ycentre+radius+1; jjj++)
   3628      {
   3629 	this->line_blend(xcentre - int(sqrt((double)(radius*radius) - (-ycentre + jjj)*(-ycentre + jjj ))), jjj,
   3630 			 xcentre + int(sqrt((double)(radius*radius) - (-ycentre + jjj)*(-ycentre + jjj ))),jjj, opacity, red,green,blue);
   3631      }
   3632 
   3633 }
   3634 
   3635 void pngwriter::filledcircle_blend(int xcentre, int ycentre, int radius, double opacity, double red, double green, double blue)
   3636 {
   3637    this->filledcircle_blend( xcentre, ycentre,  radius, opacity, int(red*65535), int(green*65535), int(blue*65535));
   3638 }
   3639 
   3640 void pngwriter::bezier_blend(  int startPtX, int startPtY,
   3641 			       int startControlX, int startControlY,
   3642 			       int endPtX, int endPtY,
   3643 			       int endControlX, int endControlY,
   3644 			       double opacity,
   3645 			       double red, double green, double blue)
   3646 {
   3647 
   3648    double cx = 3.0*(startControlX - startPtX);
   3649    double bx = 3.0*(endControlX - startControlX) - cx;
   3650    double ax = double(endPtX - startPtX - cx - bx);
   3651 
   3652    double cy = 3.0*(startControlY - startPtY);
   3653    double by = 3.0*(endControlY - startControlY) - cy;
   3654    double ay = double(endPtY - startPtY - cy - by);
   3655 
   3656    double x,y,newx,newy;
   3657    x = startPtX;
   3658    y = startPtY;
   3659 
   3660    for(double t = 0.0; t<=1.005; t += 0.005)
   3661      {
   3662 	newx = startPtX + t*(double(cx) + t*(double(bx) + t*(double(ax))));
   3663 	newy = startPtY + t*(double(cy) + t*(double(by) + t*(double(ay))));
   3664 	this->line_blend(int(x),int(y),int(newx),int(newy),opacity, red,green,blue);
   3665 	x = newx;
   3666 	y = newy;
   3667      }
   3668 }
   3669 
   3670 void pngwriter::bezier_blend(  int startPtX, int startPtY,
   3671 			       int startControlX, int startControlY,
   3672 			       int endPtX, int endPtY,
   3673 			       int endControlX, int endControlY,
   3674 			       double opacity,
   3675 			       int red, int green, int blue)
   3676 {
   3677    this->bezier_blend(   startPtX,  startPtY,
   3678 			 startControlX, startControlY,
   3679 			 endPtX, endPtY,
   3680 			 endControlX,  endControlY,
   3681 			 opacity,
   3682 			 double(red)/65535.0,  double(green)/65535.0,  double(blue)/65535.0);
   3683 
   3684 }
   3685 
   3686 /////////////////////////////
   3687 #ifndef NO_FREETYPE
   3688 
   3689 // Freetype-based text rendering functions.
   3690 ///////////////////////////////////////////
   3691 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)
   3692 {
   3693    FT_Library  library;
   3694    FT_Face     face;
   3695    FT_Matrix   matrix;      // transformation matrix
   3696    FT_Vector   pen;
   3697 
   3698    FT_UInt glyph_index;
   3699    FT_Error error;
   3700 
   3701    FT_Bool use_kerning;
   3702    FT_UInt previous = 0;
   3703 
   3704    /* Set up transformation Matrix */
   3705    matrix.xx = (FT_Fixed)( cos(angle)*0x10000);   /* It would make more sense to do this (below), but, bizzarely, */
   3706    matrix.xy = (FT_Fixed)(-sin(angle)*0x10000);   /* if one does, FT_Load_Glyph fails consistently.               */
   3707    matrix.yx = (FT_Fixed)( sin(angle)*0x10000);  //   matrix.yx = - matrix.xy;
   3708    matrix.yy = (FT_Fixed)( cos(angle)*0x10000);  //   matrix.yy = matrix.xx;
   3709 
   3710    /* Place starting coordinates in adequate form. */
   3711    pen.x = x_start*64 ;
   3712    pen.y =   (int)(y_start/64.0);
   3713 
   3714    /*Count the length of the string */
   3715    int num_chars = strlen(text);
   3716 
   3717    /* Initialize FT Library object */
   3718    error = FT_Init_FreeType( &library );
   3719    if (error) { std::cerr << " PNGwriter::plot_text_blend - ERROR **: FreeType: Could not init Library."<< std::endl; return;}
   3720 
   3721    /* Initialize FT face object */
   3722    error = FT_New_Face( library,face_path,0,&face );
   3723    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; }
   3724 
   3725    /* Set the Char size */
   3726    error = FT_Set_Char_Size( face,          /* handle to face object           */
   3727 			     0,             /* char_width in 1/64th of points  */
   3728 			     fontsize*64,   /* char_height in 1/64th of points */
   3729 			     100,           /* horizontal device resolution    */
   3730 			     100 );         /* vertical device resolution      */
   3731 
   3732    /* A way of accesing the glyph directly */
   3733    FT_GlyphSlot  slot = face->glyph;  // a small shortcut
   3734 
   3735    /* Does the font file support kerning? */
   3736    use_kerning = FT_HAS_KERNING( face );
   3737 
   3738    int n;
   3739    for ( n = 0; n < num_chars; n++ )
   3740      {
   3741 	/* Convert character code to glyph index */
   3742 	glyph_index = FT_Get_Char_Index( face, text[n] );
   3743 
   3744 	/* Retrieve kerning distance and move pen position */
   3745 	if ( use_kerning && previous&& glyph_index )
   3746 	  {
   3747 	     FT_Vector  delta;
   3748 	     FT_Get_Kerning( face,
   3749 			     previous,
   3750 			     glyph_index,
   3751 			     ft_kerning_default, //FT_KERNING_DEFAULT,
   3752 			     &delta );
   3753 
   3754 	     /* Transform this kerning distance into rotated space */
   3755 	     pen.x += (int) (((double) delta.x)*cos(angle));
   3756 	     pen.y +=  (int) (((double) delta.x)*( sin(angle)));
   3757 	  }
   3758 
   3759 	/* Set transform */
   3760 	FT_Set_Transform( face, &matrix, &pen );
   3761 
   3762 /*set char size*/
   3763 
   3764 	if (error) { std::cerr << " PNGwriter::plot_text_blend - ERROR **: FreeType: Set char size error." << std::endl; return;};
   3765 
   3766 	/* Retrieve glyph index from character code */
   3767 	glyph_index = FT_Get_Char_Index( face, text[n] );
   3768 
   3769 	/* Load glyph image into the slot (erase previous one) */
   3770 	error = FT_Load_Glyph( face, glyph_index, FT_LOAD_DEFAULT );
   3771 	if (error) { std::cerr << " PNGwriter::plot_text_blend - ERROR **: FreeType: Could not load glyph (in loop). (FreeType error "<< std::hex << error <<")." << std::endl; return;}
   3772 
   3773 	/* Convert to an anti-aliased bitmap */
   3774 	//	error = FT_Render_Glyph( face->glyph, FT_RENDER_MODE_NORMAL );
   3775 	error = FT_Render_Glyph( face->glyph, ft_render_mode_normal );
   3776 	if (error) { std::cerr << " PNGwriter::plot_text_blend - ERROR **: FreeType: Render glyph error." << std::endl; return;}
   3777 
   3778 	/* Now, draw to our target surface */
   3779 	my_draw_bitmap_blend( &slot->bitmap,
   3780 			      slot->bitmap_left,
   3781 			      y_start + slot->bitmap_top,
   3782 			      opacity,
   3783 			      red,
   3784 			      green,
   3785 			      blue );
   3786 
   3787 	/* Advance to the next position */
   3788 	pen.x += slot->advance.x;
   3789 	pen.y += slot->advance.y;
   3790 
   3791 	/* record current glyph index */
   3792 	previous = glyph_index;
   3793      }
   3794 
   3795    /* Free the face and the library objects */
   3796    FT_Done_Face    ( face );
   3797    FT_Done_FreeType( library );
   3798 }
   3799 
   3800 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)
   3801 {
   3802    FT_Library  library;
   3803    FT_Face     face;
   3804    FT_Matrix   matrix;      // transformation matrix
   3805    FT_Vector   pen;
   3806 
   3807    FT_UInt glyph_index;
   3808    FT_Error error;
   3809 
   3810    FT_Bool use_kerning;
   3811    FT_UInt previous = 0;
   3812 
   3813    /* Set up transformation Matrix */
   3814    matrix.xx = (FT_Fixed)( cos(angle)*0x10000);   /* It would make more sense to do this (below), but, bizzarely, */
   3815    matrix.xy = (FT_Fixed)(-sin(angle)*0x10000);   /* if one does, FT_Load_Glyph fails consistently.               */
   3816    matrix.yx = (FT_Fixed)( sin(angle)*0x10000);  //   matrix.yx = - matrix.xy;
   3817    matrix.yy = (FT_Fixed)( cos(angle)*0x10000);  //   matrix.yy = matrix.xx;
   3818 
   3819    /* Place starting coordinates in adequate form. */
   3820    pen.x = x_start*64 ;
   3821    pen.y = (int)(y_start/64.0);
   3822 
   3823    /*Count the length of the string */
   3824    int num_bytes=0;
   3825    while(text[num_bytes]!=0)
   3826      {
   3827 	num_bytes++;
   3828      }
   3829 
   3830 	 /*
   3831    std::cout << "Num bytes is: "<< num_bytes << std::endl;
   3832    */
   3833 
   3834    //The array of ucs4 glyph indexes, which will by at most the number of bytes in the utf-8 file.
   3835    long * ucs4text;
   3836    ucs4text = new long[num_bytes+1];
   3837 
   3838    unsigned char u,v,w,x,y,z;
   3839 
   3840    int num_chars=0;
   3841 
   3842    long iii=0;
   3843 
   3844    while(iii<num_bytes)
   3845      {
   3846 	z = text[iii];
   3847 
   3848 	if(z<=127)
   3849 	  {
   3850 	     ucs4text[num_chars] = z;
   3851 	  }
   3852 
   3853 	if((192<=z)&&(z<=223))
   3854 	  {
   3855 	     iii++; y = text[iii];
   3856 	     ucs4text[num_chars] = (z-192)*64 + (y -128);
   3857 	  }
   3858 
   3859 	if((224<=z)&&(z<=239))
   3860 	  {
   3861 	     iii++; y = text[iii];
   3862 	     iii++; x = text[iii];
   3863 	     ucs4text[num_chars] = (z-224)*4096 + (y -128)*64 + (x-128);
   3864 	  }
   3865 
   3866 	if((240<=z)&&(z<=247))
   3867 	  {
   3868 	     iii++; y = text[iii];
   3869 	     iii++; x = text[iii];
   3870 	     iii++; w = text[iii];
   3871 	     ucs4text[num_chars] = (z-240)*262144 + (y -128)*4096 + (x-128)*64 + (w-128);
   3872 	  }
   3873 
   3874 	if((248<=z)&&(z<=251))
   3875 	  {
   3876 	     iii++; y = text[iii];
   3877 	     iii++; x = text[iii];
   3878 	     iii++; w = text[iii];
   3879 	     iii++; v = text[iii];
   3880 	     ucs4text[num_chars] = (z-248)*16777216 + (y -128)*262144 + (x-128)*4096 + (w-128)*64 +(v-128);
   3881 	  }
   3882 
   3883 	if((252==z)||(z==253))
   3884 	  {
   3885 	     iii++; y = text[iii];
   3886 	     iii++; x = text[iii];
   3887 	     iii++; w = text[iii];
   3888 	     iii++; v = text[iii];
   3889 	     u = text[iii];
   3890 	     ucs4text[num_chars] = (z-252)*1073741824 + (y -128)*16777216   + (x-128)*262144 + (w-128)*4096 +(v-128)*64 + (u-128);
   3891 	  }
   3892 
   3893 	if((z==254)||(z==255))
   3894 	  {
   3895 	     std::cerr << " PNGwriter::plot_text_utf8_blend - ERROR **: Problem with character: invalid UTF-8 data."<< std::endl;
   3896 	  }
   3897 	// std::cerr << "\nProblem at " << iii << ".\n";
   3898 	//
   3899 	iii++;
   3900 	num_chars++;
   3901      }
   3902 
   3903    // num_chars now contains the number of characters in the string.
   3904    /*
   3905    std::cout << "Num chars is: "<< num_chars << std::endl;
   3906    */
   3907 
   3908    /* Initialize FT Library object */
   3909    error = FT_Init_FreeType( &library );
   3910    if (error) { std::cerr << " PNGwriter::plot_text_utf8_blend - ERROR **: FreeType: Could not init Library."<< std::endl; return;}
   3911 
   3912    /* Initialize FT face object */
   3913    error = FT_New_Face( library,face_path,0,&face );
   3914    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; }
   3915 
   3916    /* Set the Char size */
   3917    error = FT_Set_Char_Size( face,          /* handle to face object           */
   3918 			     0,             /* char_width in 1/64th of points  */
   3919 			     fontsize*64,   /* char_height in 1/64th of points */
   3920 			     100,           /* horizontal device resolution    */
   3921 			     100 );         /* vertical device resolution      */
   3922 
   3923    /* A way of accesing the glyph directly */
   3924    FT_GlyphSlot  slot = face->glyph;  // a small shortcut
   3925 
   3926    /* Does the font file support kerning? */
   3927    use_kerning = FT_HAS_KERNING( face );
   3928 
   3929    int n;
   3930    for ( n = 0; n < num_chars; n++ )
   3931      {
   3932 	/* Convert character code to glyph index */
   3933 	glyph_index = FT_Get_Char_Index( face, ucs4text[n] );
   3934 
   3935 	/* Retrieve kerning distance and move pen position */
   3936 	if ( use_kerning && previous&& glyph_index )
   3937 	  {
   3938 	     FT_Vector  delta;
   3939 	     FT_Get_Kerning( face,
   3940 			     previous,
   3941 			     glyph_index,
   3942 			     ft_kerning_default, //FT_KERNING_DEFAULT,
   3943 			     &delta );
   3944 
   3945 	     /* Transform this kerning distance into rotated space */
   3946 	     pen.x += (int) (((double) delta.x)*cos(angle));
   3947 	     pen.y +=  (int) (((double) delta.x)*( sin(angle)));
   3948 	  }
   3949 
   3950 	/* Set transform */
   3951 	FT_Set_Transform( face, &matrix, &pen );
   3952 
   3953 /*set char size*/
   3954 
   3955 	if (error) { std::cerr << " PNGwriter::plot_text_utf8_blend - ERROR **: FreeType: Set char size error." << std::endl; return;};
   3956 
   3957 	/* Retrieve glyph index from character code */
   3958 	glyph_index = FT_Get_Char_Index( face, ucs4text[n] );
   3959 
   3960 	/* Load glyph image into the slot (erase previous one) */
   3961 	error = FT_Load_Glyph( face, glyph_index, FT_LOAD_DEFAULT );
   3962 	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;}
   3963 
   3964 	/* Convert to an anti-aliased bitmap */
   3965 	error = FT_Render_Glyph( face->glyph, ft_render_mode_normal );
   3966 	if (error) { std::cerr << " PNGwriter::plot_text_utf8_blend - ERROR **: FreeType: Render glyph error." << std::endl; return;}
   3967 
   3968 	/* Now, draw to our target surface */
   3969 	my_draw_bitmap_blend( &slot->bitmap,
   3970 			      slot->bitmap_left,
   3971 			      y_start + slot->bitmap_top,
   3972 			      opacity,
   3973 			      red,
   3974 			      green,
   3975 			      blue );
   3976 
   3977 	/* Advance to the next position */
   3978 	pen.x += slot->advance.x;
   3979 	pen.y += slot->advance.y;
   3980 
   3981 	/* record current glyph index */
   3982 	previous = glyph_index;
   3983      }
   3984 
   3985    /* Free the face and the library objects */
   3986    FT_Done_Face    ( face );
   3987    FT_Done_FreeType( library );
   3988 
   3989    delete[] ucs4text;
   3990 }
   3991 
   3992 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)
   3993 {
   3994    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   );
   3995 }
   3996 
   3997 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)
   3998 {
   3999    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   );
   4000 }
   4001 
   4002 void pngwriter::my_draw_bitmap_blend( FT_Bitmap * bitmap, int x, int y, double opacity, double red, double green, double blue)
   4003 {
   4004    double temp;
   4005    for(int j=1; j<bitmap->rows+1; j++)
   4006      {
   4007 	for(int i=1; i< bitmap->width + 1; i++)
   4008 	  {
   4009 	     temp = (double)(bitmap->buffer[(j-1)*bitmap->width + (i-1)] )/255.0;
   4010 
   4011 	     if(temp)
   4012 	       {
   4013 		  this->plot_blend(x + i,
   4014 				   y  - j,
   4015 				   opacity,
   4016 				   temp*red + (1-temp)*(this->dread(x+i,y-j,1)),
   4017 				   temp*green + (1-temp)*(this->dread(x+i,y-j,2)),
   4018 				   temp*blue + (1-temp)*(this->dread(x+i,y-j,3))
   4019 				   );
   4020 	       }
   4021 	  }
   4022      }
   4023 }
   4024 
   4025 #endif
   4026 #ifdef NO_FREETYPE
   4027 
   4028 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)
   4029 {
   4030    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;
   4031    return;
   4032 }
   4033 
   4034 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)
   4035 {
   4036    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;
   4037    return;
   4038 
   4039 }
   4040 
   4041 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)
   4042 {
   4043    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;
   4044    return;
   4045 }
   4046 
   4047 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)
   4048 {
   4049    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;
   4050    return;
   4051 }
   4052 
   4053 #endif
   4054 
   4055 ///////////////////////////
   4056 
   4057 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)
   4058 {
   4059    if( (
   4060 	(this->dread(xstart,ystart,1) != boundary_red) ||
   4061 	(this->dread(xstart,ystart,2) != boundary_green) ||
   4062 	(this->dread(xstart,ystart,3) != boundary_blue)
   4063 	)
   4064        &&
   4065        (
   4066 	(this->dread(xstart,ystart,1) != fill_red) ||
   4067 	(this->dread(xstart,ystart,2) != fill_green) ||
   4068 	(this->dread(xstart,ystart,3) != fill_blue)
   4069 	)
   4070        &&
   4071        (xstart >0)&&(xstart <= width_)&&(ystart >0)&&(ystart <= height_)
   4072        )
   4073      {
   4074 	this->plot_blend(xstart, ystart, opacity,  fill_red, fill_green, fill_blue);
   4075 	boundary_fill_blend(xstart+1,  ystart, opacity,  boundary_red, boundary_green, boundary_blue, fill_red,  fill_green,  fill_blue) ;
   4076 	boundary_fill_blend(xstart,  ystart+1, opacity,  boundary_red, boundary_green, boundary_blue, fill_red,  fill_green,  fill_blue) ;
   4077 	boundary_fill_blend(xstart,  ystart-1, opacity,  boundary_red, boundary_green, boundary_blue, fill_red,  fill_green,  fill_blue) ;
   4078 	boundary_fill_blend(xstart-1,  ystart, opacity,  boundary_red, boundary_green, boundary_blue, fill_red,  fill_green,  fill_blue) ;
   4079      }
   4080 }
   4081 
   4082 //no int version needed
   4083 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)
   4084 {
   4085    if( (
   4086 	(this->dread(xstart,ystart,1) == start_red) &&
   4087 	(this->dread(xstart,ystart,2) == start_green) &&
   4088 	(this->dread(xstart,ystart,3) == start_blue)
   4089 	)
   4090        &&
   4091        (
   4092 	(this->dread(xstart,ystart,1) != fill_red) ||
   4093 	(this->dread(xstart,ystart,2) != fill_green) ||
   4094 	(this->dread(xstart,ystart,3) != fill_blue)
   4095 	)
   4096        &&
   4097        (xstart >0)&&(xstart <= width_)&&(ystart >0)&&(ystart <= height_)
   4098        )
   4099      {
   4100 	this->plot_blend(xstart, ystart, opacity, fill_red, fill_green, fill_blue);
   4101 	flood_fill_internal_blend(  xstart+1,  ystart, opacity,   start_red,  start_green,  start_blue,  fill_red,  fill_green,  fill_blue);
   4102 	flood_fill_internal_blend(  xstart-1,  ystart,opacity,   start_red,  start_green,  start_blue,  fill_red,  fill_green,  fill_blue);
   4103 	flood_fill_internal_blend(  xstart,  ystart+1, opacity,  start_red,  start_green,  start_blue,  fill_red,  fill_green,  fill_blue);
   4104 	flood_fill_internal_blend(  xstart,  ystart-1, opacity,  start_red,  start_green,  start_blue,  fill_red,  fill_green,  fill_blue);
   4105      }
   4106 
   4107 }
   4108 
   4109 //int version
   4110 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)
   4111 {
   4112 
   4113    this->boundary_fill_blend( xstart, ystart,
   4114 			      opacity,
   4115 			      ((double) boundary_red)/65535.0,
   4116 			      ((double) boundary_green)/65535.0,
   4117 			      ((double) boundary_blue)/65535.0,
   4118 			      ((double) fill_red)/65535.0,
   4119 			      ((double) fill_green)/65535.0,
   4120 			      ((double) fill_blue)/65535.0
   4121 			      );
   4122 }
   4123 
   4124 void pngwriter::flood_fill_blend(int xstart, int ystart, double opacity, double fill_red, double fill_green, double fill_blue)
   4125 {
   4126    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);
   4127 }
   4128 
   4129 //int version
   4130 void pngwriter::flood_fill_blend(int xstart, int ystart, double opacity, int fill_red, int fill_green, int fill_blue)
   4131 {
   4132    this->flood_fill_blend( xstart,  ystart,
   4133 			   opacity,
   4134 			   ((double)  fill_red)/65535.0,
   4135 			   ((double) fill_green)/65535.0,
   4136 			   ((double)  fill_blue)/65535.0
   4137 			   );
   4138 }
   4139 
   4140 void pngwriter::polygon_blend( int * points, int number_of_points, double opacity,  double red, double green, double blue)
   4141 {
   4142    if( (number_of_points<1)||(points ==NULL))
   4143      {
   4144 	std::cerr << " PNGwriter::polygon_blend - ERROR **:  Number of points is zero or negative, or array is NULL." << std::endl;
   4145 	return;
   4146      }
   4147 
   4148    for(int k=0;k< number_of_points-1; k++)
   4149      {
   4150 	this->line_blend(points[2*k],points[2*k+1],points[2*k+2],points[2*k+3], opacity,  red, green, blue);
   4151      }
   4152 }
   4153 
   4154 //int version
   4155 void pngwriter::polygon_blend( int * points, int number_of_points, double opacity, int red, int green, int blue)
   4156 {
   4157    this->polygon_blend(points, number_of_points,
   4158 		       opacity,
   4159 		       ((double) red)/65535.0,
   4160 		       ((double) green)/65535.0,
   4161 		       ((double) blue)/65535.0
   4162 		       );
   4163 }
   4164 
   4165 void pngwriter::plotCMYK_blend(int x, int y, double opacity, double cyan, double magenta, double yellow, double black)
   4166 {
   4167 /*CMYK to RGB:
   4168  *  -----------
   4169  *  red   = 255 - minimum(255,((cyan/255)    * (255 - black) + black))
   4170  *  green = 255 - minimum(255,((magenta/255) * (255 - black) + black))
   4171  *  blue  = 255 - minimum(255,((yellow/255)  * (255 - black) + black))
   4172  * */
   4173 
   4174    if(cyan<0.0)
   4175      {
   4176 	cyan = 0.0;
   4177      }
   4178    if(magenta<0.0)
   4179      {
   4180 	magenta = 0.0;
   4181      }
   4182    if(yellow<0.0)
   4183      {
   4184 	yellow = 0.0;
   4185      }
   4186    if(black<0.0)
   4187      {
   4188 	black = 0.0;
   4189      }
   4190 
   4191    if(cyan>1.0)
   4192      {
   4193 	cyan = 1.0;
   4194      }
   4195    if(magenta>1.0)
   4196      {
   4197 	magenta = 1.0;
   4198      }
   4199    if(yellow>1.0)
   4200      {
   4201 	yellow = 1.0;
   4202      }
   4203    if(black>1.0)
   4204      {
   4205 	black = 1.0;
   4206      }
   4207 
   4208    double  red, green, blue, minr, ming, minb, iblack;
   4209 
   4210    iblack = 1.0 - black;
   4211 
   4212    minr = 1.0;
   4213    ming = 1.0;
   4214    minb = 1.0;
   4215 
   4216    if( (cyan*iblack + black)<1.0 )
   4217      {
   4218 	minr = cyan*iblack + black;
   4219      }
   4220 
   4221    if( (magenta*iblack + black)<1.0 )
   4222      {
   4223 	ming = magenta*iblack + black;
   4224      }
   4225 
   4226    if( (yellow*iblack + black)<1.0 )
   4227      {
   4228 	minb = yellow*iblack + black;
   4229      }
   4230 
   4231    red = 1.0 - minr;
   4232    green = 1.0 - ming;
   4233    blue = 1.0 - minb;
   4234 
   4235    this->plot_blend(x,y,opacity, red, green, blue);
   4236 
   4237 }
   4238 
   4239 //int version
   4240 void pngwriter::plotCMYK_blend(int x, int y, double opacity, int cyan, int magenta, int yellow, int black)
   4241 {
   4242    this->plotCMYK_blend( x, y,
   4243 			 opacity,
   4244 			 ((double) cyan)/65535.0,
   4245 			 ((double) magenta)/65535.0,
   4246 			 ((double) yellow)/65535.0,
   4247 			 ((double) black)/65535.0
   4248 			 );
   4249 }
   4250 
   4251 void pngwriter::laplacian(double k, double offset)
   4252 {
   4253 
   4254    // Create image storage.
   4255    pngwriter temp(width_,height_,0,"temp");
   4256 
   4257    double red, green, blue;
   4258 
   4259    for(int x = 1; x <= width_; x++)
   4260      {
   4261 	for(int y = 1; y <= height_; y++)
   4262 	  {
   4263 	     red =
   4264 	       8.0*this->dread(x,y,1) -
   4265 	       ( this->dread(x+1, y-1, 1) +
   4266 		 this->dread(x,   y-1, 1) +
   4267 		 this->dread(x-1, y-1, 1) +
   4268 		 this->dread(x-1, y,   1) +
   4269 		 this->dread(x+1, y,   1) +
   4270 		 this->dread(x+1, y+1, 1) +
   4271 		 this->dread(x,   y+1, 1) +
   4272 		 this->dread(x-1, y+1, 1) );
   4273 
   4274 	     green =
   4275 	       8.0*this->dread(x,y,2) -
   4276 	       ( this->dread(x+1, y-1, 2) +
   4277 		 this->dread(x,   y-1, 2) +
   4278 		 this->dread(x-1, y-1, 2) +
   4279 		 this->dread(x-1, y,   2) +
   4280 		 this->dread(x+1, y,   2) +
   4281 		 this->dread(x+1, y+1, 2) +
   4282 		 this->dread(x,   y+1, 2) +
   4283 		 this->dread(x-1, y+1, 2));
   4284 
   4285 	     blue =
   4286 	       8.0*this->dread(x,y,3) -
   4287 	       ( this->dread(x+1, y-1, 3) +
   4288 		 this->dread(x,   y-1, 3) +
   4289 		 this->dread(x-1, y-1, 3) +
   4290 		 this->dread(x-1, y,   3) +
   4291 		 this->dread(x+1, y,   3) +
   4292 		 this->dread(x+1, y+1, 3) +
   4293 		 this->dread(x,   y+1, 3) +
   4294 		 this->dread(x-1, y+1, 3));
   4295 
   4296 	     temp.plot(x,y,offset+k*red,offset+k*green,offset+k*blue);
   4297 
   4298 	  }
   4299      }
   4300 
   4301    for(int xx = 1; xx <= width_; xx++)
   4302      {
   4303 	for(int yy = 1; yy <= height_; yy++)
   4304 	  {
   4305 	     this->plot(xx,yy,  temp.read(xx,yy,1), temp.read(xx,yy,2), temp.read(xx,yy,3));
   4306 	  }
   4307      }
   4308 }
   4309 
   4310 
   4311 
   4312 // drwatop(), drawbottom() and filledtriangle() were contributed by Gurkan Sengun
   4313 // ( <gurkan@linuks.mine.nu>, http://www.linuks.mine.nu/ )
   4314 void pngwriter::drawtop(long x1,long y1,long x2,long y2,long x3, int red, int green, int blue)
   4315 {
   4316    // This swaps x2 and x3
   4317    // if(x2>x3) x2^=x3^=x2^=x3;
   4318    if(x2>x3)
   4319    {
   4320    x2^=x3;
   4321    x3^=x2;
   4322    x2^=x3;
   4323    }
   4324 
   4325    long posl = x1*256;
   4326    long posr = posl;
   4327 
   4328    long cl=((x2-x1)*256)/(y2-y1);
   4329    long cr=((x3-x1)*256)/(y2-y1);
   4330 
   4331    for(int y=y1; y<y2; y++)
   4332      {
   4333 	this->line(posl/256, y, posr/256, y, red, green, blue);
   4334 	posl+=cl;
   4335 	posr+=cr;
   4336      }
   4337 }
   4338 
   4339 // drwatop(), drawbottom() and filledtriangle() were contributed by Gurkan Sengun
   4340 // ( <gurkan@linuks.mine.nu>, http://www.linuks.mine.nu/ )
   4341 void pngwriter::drawbottom(long x1,long y1,long x2,long x3,long y3, int red, int green, int blue)
   4342 {
   4343    //Swap x1 and x2
   4344    //if(x1>x2) x2^=x1^=x2^=x1;
   4345    if(x1>x2)
   4346    {
   4347    x2^=x1;
   4348    x1^=x2;
   4349    x2^=x1;
   4350     }
   4351 
   4352    long posl=x1*256;
   4353    long posr=x2*256;
   4354 
   4355    long cl=((x3-x1)*256)/(y3-y1);
   4356    long cr=((x3-x2)*256)/(y3-y1);
   4357 
   4358    for(int y=y1; y<y3; y++)
   4359      {
   4360 	this->line(posl/256, y, posr/256, y, red, green, blue);
   4361 
   4362 	posl+=cl;
   4363 	posr+=cr;
   4364      }
   4365 }
   4366 
   4367 // drwatop(), drawbottom() and filledtriangle() were contributed by Gurkan Sengun
   4368 // ( <gurkan@linuks.mine.nu>, http://www.linuks.mine.nu/ )
   4369 void pngwriter::filledtriangle(int x1,int y1,int x2,int y2,int x3,int y3, int red, int green, int blue)
   4370 {
   4371    if((x1==x2 && x2==x3) || (y1==y2 && y2==y3)) return;
   4372 
   4373    if(y2<y1)
   4374      {
   4375 	// x2^=x1^=x2^=x1;
   4376 	x2^=x1;
   4377 	x1^=x2;
   4378 	x2^=x1;
   4379 	// y2^=y1^=y2^=y1;
   4380 	y2^=y1;
   4381 	y1^=x2;
   4382 	y2^=y1;
   4383      }
   4384 
   4385    if(y3<y1)
   4386      {
   4387 	//x3^=x1^=x3^=x1;
   4388 	x3^=x1;
   4389 	x1^=x3;
   4390 	x3^=x1;
   4391 	//y3^=y1^=y3^=y1;
   4392 	y3^=y1;
   4393 	y1^=y3;
   4394 	y3^=y1;
   4395      }
   4396 
   4397    if(y3<y2)
   4398      {
   4399 	//x2^=x3^=x2^=x3;
   4400 	x2^=x3;
   4401 	x3^=x2;
   4402 	x2^=x3;
   4403 	//y2^=y3^=y2^=y3;
   4404 	y2^=y3;
   4405 	y3^=y2;
   4406 	y2^=y3;
   4407      }
   4408 
   4409    if(y2==y3)
   4410      {
   4411 	this->drawtop(x1, y1, x2, y2, x3, red, green, blue);
   4412      }
   4413    else
   4414      {
   4415 	if(y1==y3 || y1==y2)
   4416 	  {
   4417 	     this->drawbottom(x1, y1, x2, x3, y3, red, green, blue);
   4418 	  }
   4419 	else
   4420 	  {
   4421 	     int new_x = x1 + (int)((double)(y2-y1)*(double)(x3-x1)/(double)(y3-y1));
   4422 	     this->drawtop(x1, y1, new_x, y2, x2, red, green, blue);
   4423 	     this->drawbottom(x2, y2, new_x, x3, y3, red, green, blue);
   4424 	  }
   4425      }
   4426 
   4427 }
   4428 
   4429 //Double (bug found by Dave Wilks. Was: (int) red*65535, should have been (int) (red*65535).
   4430 void pngwriter::filledtriangle(int x1,int y1,int x2,int y2,int x3,int y3, double red, double green, double blue)
   4431 {
   4432    this->filledtriangle(x1, y1, x2, y2, x3, y3, (int) (red*65535), (int) (green*65535),  (int) (blue*65535));
   4433 }
   4434 
   4435 //Blend, double. (bug found by Dave Wilks. Was: (int) red*65535, should have been (int) (red*65535).
   4436 void pngwriter::filledtriangle_blend(int x1,int y1,int x2,int y2,int x3,int y3, double opacity, double red, double green, double blue)
   4437 {
   4438    this->filledtriangle_blend( x1, y1, x2, y2, x3, y3,  opacity,  (int) (red*65535), (int) (green*65535),  (int) (blue*65535));
   4439 }
   4440 
   4441 //Blend, int
   4442 void pngwriter::filledtriangle_blend(int x1,int y1,int x2,int y2,int x3,int y3, double opacity, int red, int green, int blue)
   4443 {
   4444    if((x1==x2 && x2==x3) || (y1==y2 && y2==y3)) return;
   4445 
   4446    /*if(y2<y1)
   4447      {
   4448 	x2^=x1^=x2^=x1;
   4449 	y2^=y1^=y2^=y1;
   4450      }
   4451 
   4452    if(y3<y1)
   4453      {
   4454 	x3^=x1^=x3^=x1;
   4455 	y3^=y1^=y3^=y1;
   4456      }
   4457 
   4458    if(y3<y2)
   4459      {
   4460 	x2^=x3^=x2^=x3;
   4461 	y2^=y3^=y2^=y3;
   4462      }
   4463 	 */
   4464 
   4465 	 if(y2<y1)
   4466      {
   4467 	// x2^=x1^=x2^=x1;
   4468 	x2^=x1;
   4469 	x1^=x2;
   4470 	x2^=x1;
   4471 	// y2^=y1^=y2^=y1;
   4472 	y2^=y1;
   4473 	y1^=x2;
   4474 	y2^=y1;
   4475      }
   4476 
   4477    if(y3<y1)
   4478      {
   4479 	//x3^=x1^=x3^=x1;
   4480 	x3^=x1;
   4481 	x1^=x3;
   4482 	x3^=x1;
   4483 	//y3^=y1^=y3^=y1;
   4484 	y3^=y1;
   4485 	y1^=y3;
   4486 	y3^=y1;
   4487      }
   4488 
   4489    if(y3<y2)
   4490      {
   4491 	//x2^=x3^=x2^=x3;
   4492 	x2^=x3;
   4493 	x3^=x2;
   4494 	x2^=x3;
   4495 	//y2^=y3^=y2^=y3;
   4496 	y2^=y3;
   4497 	y3^=y2;
   4498 	y2^=y3;
   4499      }
   4500 
   4501 
   4502    if(y2==y3)
   4503      {
   4504 	this->drawtop_blend(x1, y1, x2, y2, x3, opacity, red, green, blue);
   4505      }
   4506    else
   4507      {
   4508 	if(y1==y3 || y1==y2)
   4509 	  {
   4510 	     this->drawbottom_blend(x1, y1, x2, x3, y3, opacity, red, green, blue);
   4511 	  }
   4512 	else
   4513 	  {
   4514 	     int new_x = x1 + (int)((double)(y2-y1)*(double)(x3-x1)/(double)(y3-y1));
   4515 	     this->drawtop_blend(x1, y1, new_x, y2, x2, opacity,  red, green, blue);
   4516 	     this->drawbottom_blend(x2, y2, new_x, x3, y3, opacity, red, green, blue);
   4517 	  }
   4518      }
   4519 
   4520 }
   4521 
   4522 //Blend, int
   4523 void pngwriter::drawbottom_blend(long x1,long y1,long x2,long x3,long y3, double opacity, int red, int green, int blue)
   4524 {
   4525    //Swap x1 and x2
   4526    if(x1>x2)
   4527    {
   4528    x2^=x1;
   4529    x1^=x2;
   4530    x2^=x1;
   4531    }
   4532 
   4533    long posl=x1*256;
   4534    long posr=x2*256;
   4535 
   4536    long cl=((x3-x1)*256)/(y3-y1);
   4537    long cr=((x3-x2)*256)/(y3-y1);
   4538 
   4539    for(int y=y1; y<y3; y++)
   4540      {
   4541 	this->line_blend(posl/256, y, posr/256, y, opacity, red, green, blue);
   4542 
   4543 	posl+=cl;
   4544 	posr+=cr;
   4545      }
   4546 
   4547 }
   4548 
   4549 //Blend, int
   4550 void pngwriter::drawtop_blend(long x1,long y1,long x2,long y2,long x3, double opacity, int red, int green, int blue)
   4551 {
   4552    // This swaps x2 and x3
   4553    if(x2>x3)
   4554    {
   4555    x2^=x3;
   4556    x3^=x2;
   4557    x2^=x3;
   4558 }
   4559 
   4560    long posl = x1*256;
   4561    long posr = posl;
   4562 
   4563    long cl=((x2-x1)*256)/(y2-y1);
   4564    long cr=((x3-x1)*256)/(y2-y1);
   4565 
   4566    for(int y=y1; y<y2; y++)
   4567      {
   4568 	this->line_blend(posl/256, y, posr/256, y, opacity, red, green, blue);
   4569 	posl+=cl;
   4570 	posr+=cr;
   4571      }
   4572 
   4573 }
   4574 
   4575 void pngwriter::triangle(int x1, int y1, int x2, int y2, int x3, int y3, int red, int green, int blue)
   4576 {
   4577    this->line(x1, y1, x2, y2, red, green, blue);
   4578    this->line(x2, y2, x3, y3, red, green, blue);
   4579    this->line(x3, y3, x1, y1, red, green, blue);
   4580 }
   4581 
   4582 void pngwriter::triangle(int x1, int y1, int x2, int y2, int x3, int y3, double red, double green, double blue)
   4583 {
   4584 
   4585    this->line(x1, y1, x2, y2, ((int)65535*red), ((int)65535*green), ((int)65535*blue));
   4586    this->line(x2, y2, x3, y3, ((int)65535*red), ((int)65535*green), ((int)65535*blue));
   4587    this->line(x3, y3, x1, y1, ((int)65535*red), ((int)65535*green), ((int)65535*blue));
   4588 
   4589 }
   4590 
   4591 
   4592 
   4593 
   4594 
   4595 void pngwriter::arrow( int x1,int y1,int x2,int y2,int size, double head_angle, double red, double green, double blue)
   4596 {
   4597 
   4598    this->line(x1, y1, x2, y2, red, green, blue);
   4599    //   double th = 3.141592653589793 + (head_angle)*3.141592653589793/180.0;  //degrees
   4600    double th = 3.141592653589793 + head_angle;
   4601    double costh = cos(th);
   4602    double sinth = sin(th);
   4603    double t1, t2, r;
   4604    t1 = ((x2-x1)*costh - (y2-y1)*sinth);
   4605    t2 = ((x2-x1)*sinth + (y2-y1)*costh);
   4606    r = sqrt(t1*t1 + t2*t2);
   4607 
   4608    double advancex  = size*t1/r;
   4609    double advancey  = size*t2/r;
   4610    this->line(x2, y2, int(x2 + advancex), int(y2 + advancey), red, green, blue);
   4611    t1 = (x2-x1)*costh + (y2-y1)*sinth;
   4612    t2 =   (y2-y1)*costh - (x2-x1)*sinth;
   4613 
   4614    advancex  = size*t1/r;
   4615    advancey  = size*t2/r;
   4616    this->line(x2, y2, int(x2 + advancex), int(y2 + advancey), red, green, blue);
   4617 }
   4618 
   4619 void pngwriter::filledarrow( int x1,int y1,int x2,int y2,int size, double head_angle, double red, double green, double blue)
   4620 {
   4621    int p1x, p2x, p3x, p1y, p2y, p3y;
   4622 
   4623    this->line(x1, y1, x2, y2, red, green, blue);
   4624    double th = 3.141592653589793 + head_angle;
   4625    double costh = cos(th);
   4626    double sinth = sin(th);
   4627    double t11, t12, t21, t22, r1, r2;
   4628    t11 = ((x2-x1)*costh - (y2-y1)*sinth);
   4629    t21 = ((x2-x1)*sinth + (y2-y1)*costh);
   4630    t12 = (x2-x1)*costh + (y2-y1)*sinth;
   4631    t22 =   (y2-y1)*costh - (x2-x1)*sinth;
   4632 
   4633    r1 = sqrt(t11*t11 + t21*t21);
   4634    r2 = sqrt(t12*t12 + t22*t22);
   4635 
   4636    double advancex1  = size*t11/r1;
   4637    double advancey1  = size*t21/r1;
   4638    double advancex2  = size*t12/r2;
   4639    double advancey2  = size*t22/r2;
   4640 
   4641    p1x = x2;
   4642    p1y = y2;
   4643 
   4644    p2x = int(x2 + advancex1);
   4645    p2y = int(y2 + advancey1);
   4646 
   4647    p3x = int(x2 + advancex2);
   4648    p3y = int(y2 + advancey2);
   4649 
   4650 
   4651    this->filledtriangle( p1x,  p1y,  p2x,  p2y,  p3x,  p3y, red, green,  blue);
   4652 
   4653 }
   4654 
   4655 void pngwriter::arrow( int x1,int y1,int x2,int y2,int size, double head_angle, int red, int green, int blue)
   4656 {
   4657    this->arrow(  x1, y1, x2, y2, size,  head_angle,  (double (red))/65535.0,  (double (green))/65535.0,  (double (blue))/65535.0 );
   4658 }
   4659 
   4660 void pngwriter::filledarrow( int x1,int y1,int x2,int y2,int size, double head_angle, int red, int green, int blue)
   4661 {
   4662    this->filledarrow(  x1, y1, x2, y2, size,  head_angle, (double (red))/65535.0,  (double (green))/65535.0, (double (blue))/65535.0 );
   4663 }
   4664 
   4665 
   4666 void pngwriter::cross( int x, int y, int xwidth, int yheight, int red, int green, int blue)
   4667 {
   4668    this->line(int(x - xwidth/2.0), y, int(x + xwidth/2.0), y, red, green, blue);
   4669    this->line(x, int(y - yheight/2.0), x, int(y + yheight/2.0), red, green, blue);
   4670 }
   4671 
   4672 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)
   4673 {
   4674    this->line(int(x - xwidth/2.0), y, int(x + xwidth/2.0), y, red, green, blue);
   4675    this->line(x, int(y - yheight/2.0), x, int(y + yheight/2.0), red, green, blue);
   4676    // Bars on ends of vertical line
   4677    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);
   4678    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);
   4679    // Bars on ends of horizontal line.
   4680    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);
   4681    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);
   4682 }
   4683 
   4684 void pngwriter::cross( int x, int y, int xwidth, int yheight, double red, double green, double blue)
   4685 {
   4686    this->cross( x, y, xwidth, yheight, int(65535*red), int(65535*green), int(65535*blue));
   4687 }
   4688 
   4689 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)
   4690 {
   4691    this->maltesecross( x, y, xwidth, yheight, x_bar_height, y_bar_width, int(65535*red), int(65535*green), int(65535*blue));
   4692 }
   4693 
   4694 
   4695 void pngwriter::filleddiamond( int x, int y, int width, int height, int red, int green, int blue)
   4696 {
   4697    this->filledtriangle( int(x - width/2.0), y, x, y, x, int(y + height/2.0), red, green, blue);
   4698    this->filledtriangle( int(x + width/2.0), y, x, y, x, int(y + height/2.0), red, green, blue);
   4699    this->filledtriangle( int(x - width/2.0), y, x, y, x, int(y - height/2.0), red, green, blue);
   4700    this->filledtriangle( int(x + width/2.0), y, x, y, x, int(y - height/2.0), red, green, blue);
   4701 }
   4702 
   4703 void pngwriter::diamond( int x, int y, int width, int height, int red, int green, int blue)
   4704 {
   4705    this->line( int(x - width/2.0), y, x, int(y + height/2.0), red, green, blue);
   4706    this->line( int(x + width/2.0), y, x, int(y + height/2.0), red, green, blue);
   4707    this->line( int(x - width/2.0), y, x, int(y - height/2.0), red, green, blue);
   4708    this->line( int(x + width/2.0), y, x, int(y - height/2.0), red, green, blue);
   4709 }
   4710 
   4711 
   4712 void pngwriter::filleddiamond( int x, int y, int width, int height, double red, double green, double blue)
   4713 {
   4714    this->filleddiamond(  x, y,  width,  height, int(red*65535), int(green*65535), int(blue*65535) );
   4715 }
   4716 
   4717 void pngwriter::diamond( int x, int y, int width, int height, double red, double green, double blue)
   4718 {
   4719    this->diamond(  x,  y,  width,  height, int(red*65535), int(green*65535), int(blue*65535) );
   4720 }
   4721