//********** pngwriter.cc ********************************************** // Author: Paul Blackburn // // Email: individual61@users.sourceforge.net // // Version: 0.5.4 (19 / II / 2009) // // Description: Library that allows plotting a 48 bit // PNG image pixel by pixel, which can // then be opened with a graphics program. // // License: GNU General Public License // Copyright 2002, 2003, 2004, 2005, 2006, 2007, // 2008, 2009 Paul Blackburn // // Website: Main: http://pngwriter.sourceforge.net/ // Sourceforge.net: http://sourceforge.net/projects/pngwriter/ // Freshmeat.net: http://freshmeat.net/projects/pngwriter/ // // Documentation: The header file (pngwriter.h) is commented, but for a // quick reference document, and support, // take a look at the website. // //************************************************************************* /* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * */ #include "pngwriter.h" // Default Constructor //////////////////////////////////////////////////////////////////////////// pngwriter::pngwriter() { filename_ = new char[255]; textauthor_ = new char[255]; textdescription_ = new char[255]; texttitle_ = new char[255]; textsoftware_ = new char[255]; should_free = true; strcpy(filename_, "out.png"); width_ = 250; height_ = 250; backgroundcolour_ = 65535; compressionlevel_ = -2; filegamma_ = 0.5; transformation_ = 0; strcpy(textauthor_, "PNGwriter Author: Paul Blackburn"); strcpy(textdescription_, "http://pngwriter.sourceforge.net/"); strcpy(textsoftware_, "PNGwriter: An easy to use graphics library."); strcpy(texttitle_, "out.png"); int kkkk; bit_depth_ = 16; //Default bit depth for new images colortype_=2; screengamma_ = 2.2; graph_ = (png_bytepp)malloc(height_ * sizeof(png_bytep)); if(graph_ == NULL) { std::cerr << " PNGwriter::pngwriter - ERROR **: Not able to allocate memory for image." << std::endl; } for(kkkk = 0; kkkk < height_; kkkk++) { graph_[kkkk] = (png_bytep)malloc(6*width_ * sizeof(png_byte)); if(graph_[kkkk] == NULL) { std::cerr << " PNGwriter::pngwriter - ERROR **: Not able to allocate memory for image." << std::endl; } } if(graph_ == NULL) { std::cerr << " PNGwriter::pngwriter - ERROR **: Not able to allocate memory for image." << std::endl; } int tempindex; for(int hhh = 0; hhh65535) { std::cerr << " PNGwriter::pngwriter - WARNING **: Constructor called with background colour greater than 65535. Setting to 65535."<65535) { std::cerr << " PNGwriter::pngwriter - WARNING **: Constructor called with background colour greater than 1.0. Setting to 1.0."<65535) { std::cerr << " PNGwriter::pngwriter - WARNING **: Constructor called with background colour greater than 65535. Setting to 65535."<65535) { std::cerr << " PNGwriter::pngwriter - WARNING **: Constructor called with background colour greater than 65535. Setting to 65535."< 65535) { red = 65535; } if(green > 65535) { green = 65535; } if(blue > 65535) { blue = 65535; } if(red < 0) { red = 0; } if(green < 0) { green = 0; } if(blue < 0) { blue = 0; } if((bit_depth_ == 16)) { // if( (height_-y >-1) && (height_-y -1) && (6*(x-1)+5<6*width_) ) if((y<=height_) && (y>0) && (x>0) && (x<=width_)) { //graph_[height_-y][6*(x-1) + i] where i goes from 0 to 5 tempindex= 6*x-6; graph_[height_-y][tempindex] = (char) floor(((double)red)/256); graph_[height_-y][tempindex+1] = (char)(red%256); graph_[height_-y][tempindex+2] = (char) floor(((double)green)/256); graph_[height_-y][tempindex+3] = (char)(green%256); graph_[height_-y][tempindex+4] = (char) floor(((double)blue)/256); graph_[height_-y][tempindex+5] = (char)(blue%256); }; /* if(!( (height_-y >-1) && (height_-y -1) && (6*(x-1)+5<6*width_) )) { std::cerr << " PNGwriter::plot-- Plotting out of range! " << y << " " << x << std::endl; } */ } if((bit_depth_ == 8)) { // if( (height_-y >-1) && (height_-y -1) && (3*(x-1)+5<3*width_) ) if((y0) && (x>0) && (x-1) && (height_-y -1) && (6*(x-1)+5<6*width_) )) { std::cerr << " PNGwriter::plot-- Plotting out of range! " << y << " " << x << std::endl; } */ } }; void pngwriter::plot(int x, int y, double red, double green, double blue) { this->plot(x,y,int(red*65535),int(green*65535),int(blue*65535)); }; /////////////////////////////////////////////////////////////// int pngwriter::read(int x, int y, int colour) { int temp1,temp2; if((colour !=1)&&(colour !=2)&&(colour !=3)) { std::cerr << " PNGwriter::read - WARNING **: Invalid argument: should be 1, 2 or 3, is " << colour << std::endl; return 0; } if((x>0) && (x <= (this->width_)) && (y>0) && (y <= (this->height_))) { if(bit_depth_ == 16) { temp2=6*(x-1); if(colour == 1) { temp1 = (graph_[(height_-y)][temp2])*256 + graph_[height_-y][temp2+1]; return temp1; } if(colour == 2) { temp1 = (graph_[height_-y][temp2+2])*256 + graph_[height_-y][temp2+3]; return temp1; } if(colour == 3) { temp1 = (graph_[height_-y][temp2+4])*256 + graph_[height_-y][temp2+5]; return temp1; } } if(bit_depth_ == 8) { temp2=3*(x-1); if(colour == 1) { temp1 = graph_[height_-y][temp2]; return temp1*256; } if(colour == 2) { temp1 = graph_[height_-y][temp2+1]; return temp1*256; } if(colour == 3) { temp1 = graph_[height_-y][temp2+2]; return temp1*256; } } } else { return 0; } std::cerr << " PNGwriter::read - WARNING **: Returning 0 because of bitdepth/colour type mismatch."<< std::endl; return 0; } /////////////////////////////////////////////////////////////// int pngwriter::read(int xxx, int yyy) { int temp1,temp2,temp3,temp4,temp5; if( (xxx>0) && (xxx <= (this->width_)) && (yyy>0) && (yyy <= (this->height_)) ) { if(bit_depth_ == 16) { // temp1 = (graph_[(height_-yyy)][6*(xxx-1)])*256 + graph_[height_-yyy][6*(xxx-1)+1]; temp5=6*xxx; temp1 = (graph_[(height_-yyy)][temp5-6])*256 + graph_[height_-yyy][temp5-5]; temp2 = (graph_[height_-yyy][temp5-4])*256 + graph_[height_-yyy][temp5-3]; temp3 = (graph_[height_-yyy][temp5-2])*256 + graph_[height_-yyy][temp5-1]; temp4 = int((temp1+temp2+temp3)/3.0); } else if(bit_depth_ == 8) { // temp1 = graph_[height_-yyy][3*(xxx-1)]; temp5 = 3*xxx; temp1 = graph_[height_-yyy][temp5-3]; temp2 = graph_[height_-yyy][temp5-2]; temp3 = graph_[height_-yyy][temp5-1]; temp4 = int((temp1+temp2+temp3)/3.0); } else { std::cerr << " PNGwriter::read - WARNING **: Invalid bit depth! Returning 0 as average value." << std::endl; temp4 = 0; } return temp4; } else { return 0; } } ///////////////////////////////////////////////////// double pngwriter::dread(int x, int y, int colour) { return double(this->read(x,y,colour))/65535.0; } double pngwriter::dread(int x, int y) { return double(this->read(x,y))/65535.0; } /////////////////////////////////////////////////////// void pngwriter::clear() { int pen = 0; int pencil = 0; int tempindex; if(bit_depth_==16) { for(pen = 0; pen 999999999)||(index < 0)) { std::cerr << " PNGwriter::pngwriter_rename - ERROR **: Numerical name is out of 0 - 999 999 999 range (" << index <<")." << std::endl; return; } if(0> sprintf(buffer, "%9.9lu.png",index)) { std::cerr << " PNGwriter::pngwriter_rename - ERROR **: Error creating numerical filename." << std::endl; return; } delete [] filename_; delete [] texttitle_; filename_ = new char[strlen(buffer)+1]; texttitle_ = new char[strlen(buffer)+1]; strcpy(filename_,buffer); strcpy(texttitle_,buffer); }; /////////////////////////////////////////////////////// void pngwriter::settext(char* title, char* author, char* description, char* software) { delete [] textauthor_; delete [] textdescription_; delete [] texttitle_; delete [] textsoftware_; textauthor_ = new char[strlen(author)+1]; textdescription_ = new char[strlen(description)+1]; textsoftware_ = new char[strlen(software)+1]; texttitle_ = new char[strlen(title)+1]; strcpy(texttitle_, title); strcpy(textauthor_, author); strcpy(textdescription_, description); strcpy(textsoftware_, software); }; /////////////////////////////////////////////////////// void pngwriter::settext(const char* title, const char* author, const char* description, const char* software) { delete [] textauthor_; delete [] textdescription_; delete [] texttitle_; delete [] textsoftware_; textauthor_ = new char[strlen(author)+1]; textdescription_ = new char[strlen(description)+1]; textsoftware_ = new char[strlen(software)+1]; texttitle_ = new char[strlen(title)+1]; strcpy(texttitle_, title); strcpy(textauthor_, author); strcpy(textdescription_, description); strcpy(textsoftware_, software); }; /////////////////////////////////////////////////////// void pngwriter::close() { FILE* fp; png_structp png_ptr; png_infop info_ptr; fp = fopen(filename_, "wb"); if(fp == NULL) { std::cerr << " PNGwriter::close - ERROR **: Error creating file (fopen() returned NULL pointer)." << std::endl; perror(" PNGwriter::close - ERROR **"); return; } png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); info_ptr = png_create_info_struct(png_ptr); png_init_io(png_ptr, fp); if(compressionlevel_ != -2) { png_set_compression_level(png_ptr, compressionlevel_); } else { png_set_compression_level(png_ptr, PNGWRITER_DEFAULT_COMPRESSION); } png_set_IHDR(png_ptr, info_ptr, width_, height_, bit_depth_, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); if(filegamma_ < 1.0e-1) { filegamma_ = 0.5; // Modified in 0.5.4 so as to be the same as the usual gamma. } png_set_gAMA(png_ptr, info_ptr, filegamma_); time_t gmt; png_time mod_time; png_text text_ptr[5]; time(&gmt); png_convert_from_time_t(&mod_time, gmt); png_set_tIME(png_ptr, info_ptr, &mod_time); text_ptr[0].key = "Title"; text_ptr[0].text = texttitle_; text_ptr[0].compression = PNG_TEXT_COMPRESSION_NONE; text_ptr[1].key = "Author"; text_ptr[1].text = textauthor_; text_ptr[1].compression = PNG_TEXT_COMPRESSION_NONE; text_ptr[2].key = "Description"; text_ptr[2].text = textdescription_; text_ptr[2].compression = PNG_TEXT_COMPRESSION_NONE; text_ptr[3].key = "Creation Time"; text_ptr[3].text = png_convert_to_rfc1123(png_ptr, &mod_time); text_ptr[3].compression = PNG_TEXT_COMPRESSION_NONE; text_ptr[4].key = "Software"; text_ptr[4].text = textsoftware_; text_ptr[4].compression = PNG_TEXT_COMPRESSION_NONE; png_set_text(png_ptr, info_ptr, text_ptr, 5); png_write_info(png_ptr, info_ptr); png_write_image(png_ptr, graph_); png_write_end(png_ptr, info_ptr); png_destroy_write_struct(&png_ptr, &info_ptr); fclose(fp); } ////////////////////////////////////////////////////// void pngwriter::line(int xfrom, int yfrom, int xto, int yto, int red, int green,int blue) { // Bresenham Algorithm. // int dy = yto - yfrom; int dx = xto - xfrom; int stepx, stepy; if(dy < 0) { dy = -dy; stepy = -1; } else { stepy = 1; } if(dx < 0) { dx = -dx; stepx = -1; } else { stepx = 1; } dy <<= 1; // dy is now 2*dy dx <<= 1; // dx is now 2*dx this->plot(xfrom,yfrom,red,green,blue); if(dx > dy) { int fraction = dy - (dx >> 1); while(xfrom != xto) { if(fraction >= 0) { yfrom += stepy; fraction -= dx; } xfrom += stepx; fraction += dy; this->plot(xfrom,yfrom,red,green,blue); } } else { int fraction = dx - (dy >> 1); while(yfrom != yto) { if(fraction >= 0) { xfrom += stepx; fraction -= dy; } yfrom += stepy; fraction += dx; this->plot(xfrom,yfrom,red,green,blue); } } } void pngwriter::line(int xfrom, int yfrom, int xto, int yto, double red, double green,double blue) { this->line(xfrom, yfrom, xto, yto, int (red*65535), int (green*65535), int (blue*65535) ); } /////////////////////////////////////////////////////////////////////////////////////////// void pngwriter::square(int xfrom, int yfrom, int xto, int yto, int red, int green, int blue) { this->line(xfrom, yfrom, xfrom, yto, red, green, blue); this->line(xto, yfrom, xto, yto, red, green, blue); this->line(xfrom, yfrom, xto, yfrom, red, green, blue); this->line(xfrom, yto, xto, yto, red, green, blue); } void pngwriter::square(int xfrom, int yfrom, int xto, int yto, double red, double green, double blue) { this->square(xfrom, yfrom, xto, yto, int(red*65535), int(green*65535), int(blue*65535)); } ////////////////////////////////////////////////////////////////////////////////////////////////// void pngwriter::filledsquare(int xfrom, int yfrom, int xto, int yto, int red, int green, int blue) { for(int caca = xfrom; caca line(caca, yfrom, caca, yto, red, green, blue); } } void pngwriter::filledsquare(int xfrom, int yfrom, int xto, int yto, double red, double green, double blue) { this->filledsquare(xfrom, yfrom, xto, yto, int(red*65535), int(green*65535), int(blue*65535)); } ////////////////////////////////////////////////////////////////////////////////////////////////// void pngwriter::circle(int xcentre, int ycentre, int radius, int red, int green, int blue) { int x = 0; int y = radius; int p = (5 - radius*4)/4; circle_aux(xcentre, ycentre, x, y, red, green, blue); while(x < y) { x++; if(p < 0) { p += 2*x+1; } else { y--; p += 2*(x-y)+1; } circle_aux(xcentre, ycentre, x, y, red, green, blue); } } void pngwriter::circle(int xcentre, int ycentre, int radius, double red, double green, double blue) { this->circle(xcentre,ycentre,radius, int(red*65535), int(green*65535), int(blue*65535)); } //////////////////////////////////////////////////////////// void pngwriter::circle_aux(int xcentre, int ycentre, int x, int y, int red, int green, int blue) { if(x == 0) { this->plot(xcentre, ycentre + y, red, green, blue); this->plot(xcentre, ycentre - y, red, green, blue); this->plot(xcentre + y, ycentre, red, green, blue); this->plot(xcentre - y, ycentre, red, green, blue); } else if(x == y) { this->plot(xcentre + x, ycentre + y, red, green, blue); this->plot(xcentre - x, ycentre + y, red, green, blue); this->plot(xcentre + x, ycentre - y, red, green, blue); this->plot(xcentre - x, ycentre - y, red, green, blue); } else if(x < y) { this->plot(xcentre + x, ycentre + y, red, green, blue); this->plot(xcentre - x, ycentre + y, red, green, blue); this->plot(xcentre + x, ycentre - y, red, green, blue); this->plot(xcentre - x, ycentre - y, red, green, blue); this->plot(xcentre + y, ycentre + x, red, green, blue); this->plot(xcentre - y, ycentre + x, red, green, blue); this->plot(xcentre + y, ycentre - x, red, green, blue); this->plot(xcentre - y, ycentre - x, red, green, blue); } } //////////////////////////////////////////////////////////// void pngwriter::filledcircle(int xcentre, int ycentre, int radius, int red, int green, int blue) { for(int jjj = ycentre-radius; jjj< ycentre+radius+1; jjj++) { this->line(xcentre - int(sqrt((double)(radius*radius) - (-ycentre + jjj)*(-ycentre + jjj))), jjj, xcentre + int(sqrt((double)(radius*radius) - (-ycentre + jjj)*(-ycentre + jjj))),jjj,red,green,blue); } } void pngwriter::filledcircle(int xcentre, int ycentre, int radius, double red, double green, double blue) { this->filledcircle(xcentre, ycentre, radius, int(red*65535), int(green*65535), int(blue*65535)); } ////////////////Reading routines///////////////////// ///////////////////////////////////////////////// // Modified with Mikkel's patch void pngwriter::readfromfile(char* name) { FILE* fp; png_structp png_ptr; png_infop info_ptr; unsigned char** image; unsigned long width, height; int bit_depth, color_type, interlace_type; // png_uint_32 i; // fp = fopen(name,"rb"); if(fp==NULL) { std::cerr << " PNGwriter::readfromfile - ERROR **: Error opening file \"" << std::flush; std::cerr << name <readfromfile((char *)(name)); } ///////////////////////////////////////////////////////// int pngwriter::check_if_png(char* file_name, FILE** fp) { char sig[PNG_BYTES_TO_CHECK]; if(/*(*fp = fopen(file_name, "rb")) */ *fp == NULL) { // Fixed 10 10 04 // exit(EXIT_FAILURE); std::cerr << " PNGwriter::check_if_png - ERROR **: Could not open file " << file_name << " to read." << std::endl; perror(" PNGwriter::check_if_png - ERROR **"); return 0; } if(fread(sig, 1, PNG_BYTES_TO_CHECK, *fp) != PNG_BYTES_TO_CHECK) { //exit(EXIT_FAILURE); std::cerr << " PNGwriter::check_if_png - ERROR **: File " << file_name << " does not appear to be a valid PNG file." << std::endl; perror(" PNGwriter::check_if_png - ERROR **"); fclose(*fp); return 0; } if(png_sig_cmp((png_bytep) sig, (png_size_t)0, PNG_BYTES_TO_CHECK) /*png_check_sig((png_bytep) sig, PNG_BYTES_TO_CHECK)*/) { std::cerr << " PNGwriter::check_if_png - ERROR **: File " << file_name << " does not appear to be a valid PNG file. png_check_sig() failed." << std::endl; fclose(*fp); return 0; } return 1; //Success } /////////////////////////////////////////////////////// int pngwriter::read_png_info(FILE* fp, png_structp* png_ptr, png_infop* info_ptr) { *png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if(*png_ptr == NULL) { std::cerr << " PNGwriter::read_png_info - ERROR **: Could not create read_struct." << std::endl; fclose(fp); return 0; //exit(EXIT_FAILURE); } *info_ptr = png_create_info_struct(*png_ptr); if(*info_ptr == NULL) { png_destroy_read_struct(png_ptr, (png_infopp)NULL, (png_infopp)NULL); std::cerr << " PNGwriter::read_png_info - ERROR **: Could not create info_struct." << std::endl; //exit(EXIT_FAILURE); fclose(fp); return 0; } if(setjmp((*png_ptr)->jmpbuf)) /*(setjmp(png_jmpbuf(*png_ptr)) )*/ ///////////////////////////////////// { png_destroy_read_struct(png_ptr, info_ptr, (png_infopp)NULL); std::cerr << " PNGwriter::read_png_info - ERROR **: This file may be a corrupted PNG file. (setjmp(*png_ptr)->jmpbf) failed)." << std::endl; fclose(fp); return 0; //exit(EXIT_FAILURE); } png_init_io(*png_ptr, fp); png_set_sig_bytes(*png_ptr, PNG_BYTES_TO_CHECK); png_read_info(*png_ptr, *info_ptr); return 1; } //////////////////////////////////////////////////////////// int pngwriter::read_png_image(FILE* fp, png_structp png_ptr, png_infop info_ptr, png_bytepp* image, png_uint_32* width, png_uint_32* height) { unsigned int i,j; *width = png_get_image_width(png_ptr, info_ptr); *height = png_get_image_height(png_ptr, info_ptr); if(width == NULL) { std::cerr << " PNGwriter::read_png_image - ERROR **: png_get_image_width() returned NULL pointer." << std::endl; fclose(fp); return 0; } if(height == NULL) { std::cerr << " PNGwriter::read_png_image - ERROR **: png_get_image_height() returned NULL pointer." << std::endl; fclose(fp); return 0; } if((*image = (png_bytepp)malloc(*height * sizeof(png_bytep))) == NULL) { std::cerr << " PNGwriter::read_png_image - ERROR **: Could not allocate memory for reading image." << std::endl; fclose(fp); return 0; //exit(EXIT_FAILURE); } for(i = 0; i < *height; i++) { (*image)[i] = (png_bytep)malloc(png_get_rowbytes(png_ptr, info_ptr)); if((*image)[i] == NULL) { for(j = 0; j < i; j++) free((*image)[j]); free(*image); fclose(fp); std::cerr << " PNGwriter::read_png_image - ERROR **: Could not allocate memory for reading image." << std::endl; return 0; //exit(EXIT_FAILURE); } } png_read_image(png_ptr, *image); return 1; } /////////////////////////////////// int pngwriter::getheight(void) { return height_; } int pngwriter::getwidth(void) { return width_; } int pngwriter::getbitdepth(void) { return bit_depth_; } int pngwriter::getcolortype(void) { return colortype_; } double pngwriter::getgamma(void) { return filegamma_; } void pngwriter::setgamma(double gamma) { filegamma_ = gamma; } // The algorithms HSVtoRGB and RGBtoHSV were found at http://www.cs.rit.edu/~ncs/ // which is a page that belongs to Nan C. Schaller, though // these algorithms appear to be the work of Eugene Vishnevsky. ////////////////////////////////////////////// void pngwriter::HSVtoRGB(double* r, double* g, double* b, double h, double s, double v) { // r,g,b values are from 0 to 1 // h = [0,1], s = [0,1], v = [0,1] // if s == 0, then h = -1 (undefined) // h = h*360.0; int i; double f, p, q, t; if(s == 0) { // achromatic (grey) *r = *g = *b = v; return; } h /= 60; // sector 0 to 5 i = int(floor(h)); f = h - i; // factorial part of h p = v * (1 - s); q = v * (1 - s * f); t = v * (1 - s * (1 - f)); switch(i) { case 0: *r = v; *g = t; *b = p; break; case 1: *r = q; *g = v; *b = p; break; case 2: *r = p; *g = v; *b = t; break; case 3: *r = p; *g = q; *b = v; break; case 4: *r = t; *g = p; *b = v; break; default: // case 5: *r = v; *g = p; *b = q; break; } } void pngwriter::RGBtoHSV(float r, float g, float b, float* h, float* s, float* v) { float min=0.0; //These values are not used. float max=1.0; float delta; if((r>=g)&&(r>=b)) { max = r; } if((g>=r)&&(g>=b)) { max = g; } if((b>=g)&&(b>=r)) { max = b; } if((r<=g)&&(r<=b)) { min = r; } if((g<=r)&&(g<=b)) { min = g; } if((b<=g)&&(b<=r)) { min = b; } *v = max; // v delta = max - min; if(max != 0) *s = delta / max; // s else { r = g = b = 0; // s = 0, v is undefined *s = 0; *h = -1; return; } if(r == max) *h = (g - b) / delta; // between yellow & magenta else if(g == max) *h = 2 + (b - r) / delta; // between cyan & yellow else *h = 4 + (r - g) / delta; // between magenta & cyan *h *= 60; // degrees if(*h < 0) *h += 360; } // ////////////////////////////////////////////////////////////////////////////////// void pngwriter::plotHSV(int x, int y, double hue, double saturation, double value) { double red,green,blue; double* redp; double* greenp; double* bluep; redp = &red; greenp = &green; bluep = &blue; HSVtoRGB(redp,greenp,bluep,hue,saturation,value); plot(x,y,red,green,blue); } void pngwriter::plotHSV(int x, int y, int hue, int saturation, int value) { plotHSV(x, y, double(hue)/65535.0, double(saturation)/65535.0, double(value)/65535.0); } // ////////////////////////////////////////////////////////////////////////////////// double pngwriter::dreadHSV(int x, int y, int colour) { if((x>0)&&(x<=width_)&&(y>0)&&(y<=height_)) { float* huep; float* saturationp; float* valuep; float red,green,blue; float hue, saturation, value; red = float(dread(x,y,1)); green = float(dread(x,y,2)); blue = float(dread(x,y,3)); huep = &hue; saturationp = &saturation; valuep = &value; RGBtoHSV(red, green, blue, huep, saturationp, valuep); if(colour == 1) { return double(hue)/360.0; } else if(colour == 2) { return saturation; } else if(colour == 3) { return value; } std::cerr << " PNGwriter::dreadHSV - ERROR **: Called with wrong colour argument: should be 1, 2 or 3; was: " << colour << "." << std::endl; } return 0.0; } // ////////////////////////////////////////////////////////////////////////////////// int pngwriter::readHSV(int x, int y, int colour) { if((x>0)&&(x<=width_)&&(y>0)&&(y<=height_)) { float* huep; float* saturationp; float* valuep; float red,green,blue; float hue, saturation, value; red = float(dread(x,y,1)); green = float(dread(x,y,2)); blue = float(dread(x,y,3)); huep = &hue; saturationp = &saturation; valuep = &value; RGBtoHSV(red, green, blue, huep, saturationp, valuep); if(colour == 1) { return int(65535*(double(hue)/360.0)); } else if(colour == 2) { return int(65535*saturation); } else if(colour == 3) { return int(65535*value); } std::cerr << " PNGwriter::readHSV - ERROR **: Called with wrong colour argument: should be 1, 2 or 3; was: " << colour << "." << std::endl; return 0; } else { return 0; } } void pngwriter::setcompressionlevel(int level) { if((level < -1)||(level > 9)) { std::cerr << " PNGwriter::setcompressionlevel - ERROR **: Called with wrong compression level: should be -1 to 9, was: " << level << "." << std::endl; } compressionlevel_ = level; } // An implementation of a Bezier curve. void pngwriter::bezier(int startPtX, int startPtY, int startControlX, int startControlY, int endPtX, int endPtY, int endControlX, int endControlY, double red, double green, double blue) { double cx = 3.0*(startControlX - startPtX); double bx = 3.0*(endControlX - startControlX) - cx; double ax = double(endPtX - startPtX - cx - bx); double cy = 3.0*(startControlY - startPtY); double by = 3.0*(endControlY - startControlY) - cy; double ay = double(endPtY - startPtY - cy - by); double x,y,newx,newy; x = startPtX; y = startPtY; for(double t = 0.0; t<=1.005; t += 0.005) { newx = startPtX + t*(double(cx) + t*(double(bx) + t*(double(ax)))); newy = startPtY + t*(double(cy) + t*(double(by) + t*(double(ay)))); this->line(int(x),int(y),int(newx),int(newy),red,green,blue); x = newx; y = newy; } } //int version of bezier void pngwriter::bezier(int startPtX, int startPtY, int startControlX, int startControlY, int endPtX, int endPtY, int endControlX, int endControlY, int red, int green, int blue) { this->bezier(startPtX, startPtY, startControlX, startControlY, endPtX, endPtY, endControlX, endControlY, double(red)/65535.0, double(green)/65535.0, double(blue)/65535.0); } /* int pngwriter::getcompressionlevel(void) { return png_get_compression_level(png_ptr); } */ double pngwriter::version(void) { const char* a = "Jeramy Webb (jeramyw@gmail.com), Mike Heller (mkheller@gmail.com)"; // For their generosity ;-) char b = a[27]; b++; return (PNGWRITER_VERSION); } void pngwriter::write_png(void) { this->close(); } #ifndef NO_FREETYPE // Freetype-based text rendering functions. /////////////////////////////////////////// void pngwriter::plot_text(char* face_path, int fontsize, int x_start, int y_start, double angle, char* text, double red, double green, double blue) { FT_Library library; FT_Face face; FT_Matrix matrix; // transformation matrix FT_Vector pen; FT_UInt glyph_index; FT_Error error; FT_Bool use_kerning; FT_UInt previous = 0; /* Set up transformation Matrix */ matrix.xx = (FT_Fixed)(cos(angle)*0x10000); /* It would make more sense to do this (below), but, bizzarely, */ matrix.xy = (FT_Fixed)(-sin(angle)*0x10000); /* if one does, FT_Load_Glyph fails consistently. */ matrix.yx = (FT_Fixed)(sin(angle)*0x10000); // matrix.yx = - matrix.xy; matrix.yy = (FT_Fixed)(cos(angle)*0x10000); // matrix.yy = matrix.xx; /* Place starting coordinates in adequate form. */ pen.x = x_start*64 ; pen.y = (int)(y_start/64.0); /*Count the length of the string */ int num_chars = strlen(text); /* Initialize FT Library object */ error = FT_Init_FreeType(&library); if(error) { std::cerr << " PNGwriter::plot_text - ERROR **: FreeType: Could not init Library."<< std::endl; return;} /* Initialize FT face object */ error = FT_New_Face(library,face_path,0,&face); if(error == FT_Err_Unknown_File_Format) { std::cerr << " PNGwriter::plot_text - ERROR **: FreeType: Font was opened, but type not supported."<< std::endl; return; } else if(error) { std::cerr << " PNGwriter::plot_text - ERROR **: FreeType: Could not find or load font file."<< std::endl; return; } /* Set the Char size */ error = FT_Set_Char_Size(face, /* handle to face object */ 0, /* char_width in 1/64th of points */ fontsize*64, /* char_height in 1/64th of points */ 100, /* horizontal device resolution */ 100); /* vertical device resolution */ /* A way of accesing the glyph directly */ FT_GlyphSlot slot = face->glyph; // a small shortcut /* Does the font file support kerning? */ use_kerning = FT_HAS_KERNING(face); int n; for(n = 0; n < num_chars; n++) { /* Convert character code to glyph index */ glyph_index = FT_Get_Char_Index(face, text[n]); /* Retrieve kerning distance and move pen position */ if(use_kerning && previous&& glyph_index) { FT_Vector delta; FT_Get_Kerning(face, previous, glyph_index, ft_kerning_default, //FT_KERNING_DEFAULT, &delta); /* Transform this kerning distance into rotated space */ pen.x += (int)(((double) delta.x)*cos(angle)); pen.y += (int)(((double) delta.x)*(sin(angle))); } /* Set transform */ FT_Set_Transform(face, &matrix, &pen); /*set char size*/ if(error) { std::cerr << " PNGwriter::plot_text - ERROR **: FreeType: Set char size error." << std::endl; return;}; /* Retrieve glyph index from character code */ glyph_index = FT_Get_Char_Index(face, text[n]); /* Load glyph image into the slot (erase previous one) */ error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT); if(error) { std::cerr << " PNGwriter::plot_text - ERROR **: FreeType: Could not load glyph (in loop). (FreeType error "<< std::hex << error <<")." << std::endl; return;} /* Convert to an anti-aliased bitmap */ // error = FT_Render_Glyph( face->glyph, FT_RENDER_MODE_NORMAL ); error = FT_Render_Glyph(face->glyph, ft_render_mode_normal); if(error) { std::cerr << " PNGwriter::plot_text - ERROR **: FreeType: Render glyph error." << std::endl; return;} /* Now, draw to our target surface */ my_draw_bitmap(&slot->bitmap, slot->bitmap_left, y_start + slot->bitmap_top, red, green, blue); /* Advance to the next position */ pen.x += slot->advance.x; pen.y += slot->advance.y; /* record current glyph index */ previous = glyph_index; } /* Free the face and the library objects */ FT_Done_Face(face); FT_Done_FreeType(library); } void pngwriter::plot_text_utf8(char* face_path, int fontsize, int x_start, int y_start, double angle, char* text, double red, double green, double blue) { FT_Library library; FT_Face face; FT_Matrix matrix; // transformation matrix FT_Vector pen; FT_UInt glyph_index; FT_Error error; FT_Bool use_kerning; FT_UInt previous = 0; /* Set up transformation Matrix */ matrix.xx = (FT_Fixed)(cos(angle)*0x10000); /* It would make more sense to do this (below), but, bizzarely, */ matrix.xy = (FT_Fixed)(-sin(angle)*0x10000); /* if one does, FT_Load_Glyph fails consistently. */ matrix.yx = (FT_Fixed)(sin(angle)*0x10000); // matrix.yx = - matrix.xy; matrix.yy = (FT_Fixed)(cos(angle)*0x10000); // matrix.yy = matrix.xx; /* Place starting coordinates in adequate form. */ pen.x = x_start*64 ; pen.y = (int)(y_start/64.0); /*Count the length of the string */ int num_bytes=0; while(text[num_bytes]!=0) { num_bytes++; } /* std::cout << "Num bytes is: "<< num_bytes << std::endl; */ //The array of ucs4 glyph indexes, which will by at most the number of bytes in the utf-8 file. long* ucs4text; ucs4text = new long[num_bytes+1]; unsigned char u,v,w,x,y,z; int num_chars=0; long iii=0; while(iiiglyph; // a small shortcut /* Does the font file support kerning? */ use_kerning = FT_HAS_KERNING(face); int n; for(n = 0; n < num_chars; n++) { /* Convert character code to glyph index */ glyph_index = FT_Get_Char_Index(face, ucs4text[n]); /* Retrieve kerning distance and move pen position */ if(use_kerning && previous&& glyph_index) { FT_Vector delta; FT_Get_Kerning(face, previous, glyph_index, ft_kerning_default, //FT_KERNING_DEFAULT, &delta); /* Transform this kerning distance into rotated space */ pen.x += (int)(((double) delta.x)*cos(angle)); pen.y += (int)(((double) delta.x)*(sin(angle))); } /* Set transform */ FT_Set_Transform(face, &matrix, &pen); /*set char size*/ if(error) { std::cerr << " PNGwriter::plot_text_utf8 - ERROR **: FreeType: Set char size error." << std::endl; return;}; /* Retrieve glyph index from character code */ glyph_index = FT_Get_Char_Index(face, ucs4text[n]); /* Load glyph image into the slot (erase previous one) */ error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT); if(error) { std::cerr << " PNGwriter::plot_text_utf8 - ERROR **: FreeType: Could not load glyph (in loop). (FreeType error "<< std::hex << error <<")." << std::endl; return;} /* Convert to an anti-aliased bitmap */ error = FT_Render_Glyph(face->glyph, ft_render_mode_normal); if(error) { std::cerr << " PNGwriter::plot_text_utf8 - ERROR **: FreeType: Render glyph error." << std::endl; return;} /* Now, draw to our target surface */ my_draw_bitmap(&slot->bitmap, slot->bitmap_left, y_start + slot->bitmap_top, red, green, blue); /* Advance to the next position */ pen.x += slot->advance.x; pen.y += slot->advance.y; /* record current glyph index */ previous = glyph_index; } /* Free the face and the library objects */ FT_Done_Face(face); FT_Done_FreeType(library); delete[] ucs4text; } void pngwriter::plot_text(char* face_path, int fontsize, int x_start, int y_start, double angle, char* text, int red, int green, int blue) { plot_text(face_path, fontsize, x_start, y_start, angle, text, ((double) red)/65535.0, ((double) green)/65535.0, ((double) blue)/65535.0); } void pngwriter::plot_text_utf8(char* face_path, int fontsize, int x_start, int y_start, double angle, char* text, int red, int green, int blue) { plot_text_utf8(face_path, fontsize, x_start, y_start, angle, text, ((double) red)/65535.0, ((double) green)/65535.0, ((double) blue)/65535.0); } void pngwriter::my_draw_bitmap(FT_Bitmap* bitmap, int x, int y, double red, double green, double blue) { double temp; for(int j=1; jrows+1; j++) { for(int i=1; i< bitmap->width + 1; i++) { temp = (double)(bitmap->buffer[(j-1)*bitmap->width + (i-1)])/255.0; if(temp) { this->plot(x + i, y - j, temp*red + (1-temp)*(this->dread(x+i,y-j,1)), temp*green + (1-temp)*(this->dread(x+i,y-j,2)), temp*blue + (1-temp)*(this->dread(x+i,y-j,3)) ); } } } } //////////// Get text width //put in freetype section int pngwriter::get_text_width(char* face_path, int fontsize, char* text) { FT_Library library; FT_Face face; FT_Matrix matrix; // transformation matrix FT_Vector pen; FT_UInt glyph_index; FT_Error error; FT_Bool use_kerning; FT_UInt previous = 0; /* Set up transformation Matrix */ matrix.xx = (FT_Fixed)(1.0*0x10000); /* It would make more sense to do this (below), but, bizzarely, */ matrix.xy = (FT_Fixed)(0.0*0x10000); /* if one does, FT_Load_Glyph fails consistently. */ matrix.yx = (FT_Fixed)(0.0*0x10000); // matrix.yx = - matrix.xy; matrix.yy = (FT_Fixed)(1.0*0x10000); // matrix.yy = matrix.xx; /* Place starting coordinates in adequate form. */ pen.x = 0; pen.y = 0; /*Count the length of the string */ int num_chars = strlen(text); /* Initialize FT Library object */ error = FT_Init_FreeType(&library); if(error) { std::cerr << " PNGwriter::get_text_width - ERROR **: FreeType: Could not init Library."<< std::endl; return 0;} /* Initialize FT face object */ error = FT_New_Face(library,face_path,0,&face); if(error == FT_Err_Unknown_File_Format) { std::cerr << " PNGwriter::get_text_width - ERROR **: FreeType: Font was opened, but type not supported."<< std::endl; return 0; } else if(error) { std::cerr << " PNGwriter::get_text_width - ERROR **: FreeType: Could not find or load font file." << std::endl; return 0; } /* Set the Char size */ error = FT_Set_Char_Size(face, /* handle to face object */ 0, /* char_width in 1/64th of points */ fontsize*64, /* char_height in 1/64th of points */ 100, /* horizontal device resolution */ 100); /* vertical device resolution */ /* A way of accesing the glyph directly */ FT_GlyphSlot slot = face->glyph; // a small shortcut /* Does the font file support kerning? */ use_kerning = FT_HAS_KERNING(face); int n; for(n = 0; n < num_chars; n++) { /* Convert character code to glyph index */ glyph_index = FT_Get_Char_Index(face, text[n]); /* Retrieve kerning distance and move pen position */ if(use_kerning && previous&& glyph_index) { FT_Vector delta; FT_Get_Kerning(face, previous, glyph_index, ft_kerning_default, //FT_KERNING_DEFAULT, &delta); /* Transform this kerning distance into rotated space */ pen.x += (int)(delta.x); pen.y += 0; } /* Set transform */ FT_Set_Transform(face, &matrix, &pen); /*set char size*/ if(error) { std::cerr << " PNGwriter::get_text_width - ERROR **: FreeType: Set char size error." << std::endl; return 0;}; /* Retrieve glyph index from character code */ glyph_index = FT_Get_Char_Index(face, text[n]); /* Load glyph image into the slot (erase previous one) */ error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT); if(error) { std::cerr << " PNGwriter::get_text_width - ERROR **: FreeType: Could not load glyph (in loop). (FreeType error "<< std::hex << error <<")." << std::endl; return 0;} /* Convert to an anti-aliased bitmap */ // error = FT_Render_Glyph( face->glyph, FT_RENDER_MODE_NORMAL ); error = FT_Render_Glyph(face->glyph, ft_render_mode_normal); if(error) { std::cerr << " PNGwriter::get_text_width - ERROR **: FreeType: Render glyph error." << std::endl; return 0;} /* Now, draw to our target surface */ /* my_draw_bitmap( &slot->bitmap, slot->bitmap_left, slot->bitmap_top, red, green, blue ); */ /* Advance to the next position */ pen.x += slot->advance.x; // std::cout << ((double) pen.x)/64.0 << std::endl; pen.y += slot->advance.y; /* record current glyph index */ previous = glyph_index; } /* Free the face and the library objects */ FT_Done_Face(face); FT_Done_FreeType(library); return (int)(((double)pen.x)/64.0); } int pngwriter::get_text_width_utf8(char* face_path, int fontsize, char* text) { FT_Library library; FT_Face face; FT_Matrix matrix; // transformation matrix FT_Vector pen; FT_UInt glyph_index; FT_Error error; FT_Bool use_kerning; FT_UInt previous = 0; /* Set up transformation Matrix */ matrix.xx = (FT_Fixed)(0x10000); /* It would make more sense to do this (below), but, bizzarely, */ matrix.xy = (FT_Fixed)(0*0x10000); /* if one does, FT_Load_Glyph fails consistently. */ matrix.yx = (FT_Fixed)(0*0x10000); // matrix.yx = - matrix.xy; matrix.yy = (FT_Fixed)(0x10000); // matrix.yy = matrix.xx; /* Place starting coordinates in adequate form. */ pen.x = 0 ; pen.y = 0; /*Count the length of the string */ int num_bytes=0; while(text[num_bytes]!=0) { num_bytes++; } /* std::cout << "Num bytes is: "<< num_bytes << std::endl; */ //The array of ucs4 glyph indexes, which will by at most the number of bytes in the utf-8 file. long* ucs4text; ucs4text = new long[num_bytes+1]; unsigned char u,v,w,x,y,z; int num_chars=0; long iii=0; while(iiiglyph; // a small shortcut /* Does the font file support kerning? */ use_kerning = FT_HAS_KERNING(face); int n; for(n = 0; n < num_chars; n++) { /* Convert character code to glyph index */ glyph_index = FT_Get_Char_Index(face, ucs4text[n]); /* Retrieve kerning distance and move pen position */ if(use_kerning && previous&& glyph_index) { FT_Vector delta; FT_Get_Kerning(face, previous, glyph_index, ft_kerning_default, //FT_KERNING_DEFAULT, &delta); /* Transform this kerning distance into rotated space */ pen.x += (int)(delta.x); pen.y += 0; } /* Set transform */ FT_Set_Transform(face, &matrix, &pen); /*set char size*/ if(error) { std::cerr << " PNGwriter::get_text_width_utf8 - ERROR **: FreeType: Set char size error." << std::endl; return 0;}; /* Retrieve glyph index from character code */ glyph_index = FT_Get_Char_Index(face, ucs4text[n]); /* Load glyph image into the slot (erase previous one) */ error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT); if(error) { std::cerr << " PNGwriter::get_text_width_utf8 - ERROR **: FreeType: Could not load glyph (in loop). (FreeType error "<< std::hex << error <<")." << std::endl; return 0;} /* Convert to an anti-aliased bitmap */ error = FT_Render_Glyph(face->glyph, ft_render_mode_normal); if(error) { std::cerr << " PNGwriter::get_text_width_utf8 - ERROR **: FreeType: Render glyph error." << std::endl; return 0;} /* Now, draw to our target surface */ /* my_draw_bitmap( &slot->bitmap, slot->bitmap_left, y_start + slot->bitmap_top, red, green, blue ); */ /* Advance to the next position */ pen.x += slot->advance.x; pen.y += slot->advance.y; /* record current glyph index */ previous = glyph_index; } /* Free the face and the library objects */ FT_Done_Face(face); FT_Done_FreeType(library); delete[] ucs4text; return (int)(((double) pen.x)/64.0); } /////////////// #endif #ifdef NO_FREETYPE void pngwriter::plot_text(char* face_path, int fontsize, int x_start, int y_start, double angle, char* text, int red, int green, int blue) { std::cerr << " PNGwriter::plot_text - ERROR **: PNGwriter was compiled without Freetype support! Recompile PNGwriter with Freetype support (once you have Freetype installed, that is. Websites: www.freetype.org and pngwriter.sourceforge.net)." << std::endl; return; } void pngwriter::plot_text(char* face_path, int fontsize, int x_start, int y_start, double angle, char* text, double red, double green, double blue) { std::cerr << " PNGwriter::plot_text - ERROR **: PNGwriter was compiled without Freetype support! Recompile PNGwriter with Freetype support (once you have Freetype installed, that is. Websites: www.freetype.org and pngwriter.sourceforge.net)." << std::endl; return; } void pngwriter::plot_text_utf8(char* face_path, int fontsize, int x_start, int y_start, double angle, char* text, int red, int green, int blue) { std::cerr << " PNGwriter::plot_text_utf8 - ERROR **: PNGwriter was compiled without Freetype support! Recompile PNGwriter with Freetype support (once you have Freetype installed, that is. Websites: www.freetype.org and pngwriter.sourceforge.net)." << std::endl; return; } void pngwriter::plot_text_utf8(char* face_path, int fontsize, int x_start, int y_start, double angle, char* text, double red, double green, double blue) { std::cerr << " PNGwriter::plot_text_utf8 - ERROR **: PNGwriter was compiled without Freetype support! Recompile PNGwriter with Freetype support (once you have Freetype installed, that is. Websites: www.freetype.org and pngwriter.sourceforge.net)." << std::endl; return; } //////////// Get text width int pngwriter::get_text_width(char* face_path, int fontsize, char* text) { std::cerr << " PNGwriter::get_text_width - ERROR **: PNGwriter was compiled without Freetype support! Recompile PNGwriter with Freetype support (once you have Freetype installed, that is. Websites: www.freetype.org and pngwriter.sourceforge.net)." << std::endl; return 0; } int pngwriter::get_text_width_utf8(char* face_path, int fontsize, char* text) { std::cerr << " PNGwriter::get_text_width_utf8 - ERROR **: PNGwriter was compiled without Freetype support! Recompile PNGwriter with Freetype support (once you have Freetype installed, that is. Websites: www.freetype.org and pngwriter.sourceforge.net)." << std::endl; return 0; } /////////////// #endif ///////////////////////////////////// int pngwriter::bilinear_interpolation_read(double x, double y, int colour) { int inty, intx; inty = (int) ceil(y); intx = (int) ceil(x); //inty = (int) floor(y) +1; // intx = (int) floor(x) +1; // bool attop, atright; attop = inty==this->height_; atright = intx==this->width_; /* if( intx==this->width_ +1) { intx--; // std::cout << "intx--" << std::endl; } */ /* if(inty == this->height_ +1) { inty--; // std::cout << "inty--" << std::endl; } */ if((!attop)&&(!atright)) { double f,g,f1,g1; f = 1.0 + x - ((double) intx); g = 1.0 + y - ((double) inty); f1 = 1.0 - f; g1 = 1.0 - g; return (int)( f1*g1*this->read(intx, inty,colour) + f*g1*this->read(intx+1,inty,colour) +f1*g*this->read(intx,inty+1,colour) + f*g*(this->read(intx+1,inty+1,colour)) ); } if((atright)&&(!attop)) { double f,g,f1,g1; f = 1.0 + x - ((double) intx); g = 1.0 + y - ((double) inty); f1 = 1.0 - f; g1 = 1.0 - g; return (int)( f1*g1*this->read(intx, inty,colour) + f*g1*(2*(this->read(intx,inty,colour)) - (this->read(intx-1,inty,colour))) +f1*g*this->read(intx,inty+1,colour) + f*g*(2*(this->read(intx,inty+1,colour)) - (this->read(intx-1,inty+1,colour))) ); } if((attop)&&(!atright)) { double f,g,f1,g1; f = 1.0 + x - ((double) intx); g = 1.0 + y - ((double) inty); f1 = 1.0 - f; g1 = 1.0 - g; return (int)( f1*g1*this->read(intx, inty,colour) + f*g1*this->read(intx+1,inty,colour) +f1*g*(2*(this->read(intx,inty,colour)) - this->read(intx,inty-1,colour)) + f*g*(2*(this->read(intx+1,inty,colour)) - this->read(intx+1,inty-1,colour)) ); } double f,g,f1,g1; f = 1.0 + x - ((double) intx); g = 1.0 + y - ((double) inty); f1 = 1.0 - f; g1 = 1.0 - g; return (int)( f1*g1*this->read(intx, inty,colour) + f*g1*(2*(this->read(intx,inty,colour)) - (this->read(intx-1,inty,colour))) +f1*g*(2*(this->read(intx,inty,colour)) - this->read(intx,inty-1,colour)) + f*g*(2*(2*(this->read(intx,inty,colour)) - (this->read(intx-1,inty,colour))) - (2*(this->read(intx,inty-1,colour)) - (this->read(intx-1,inty-1,colour)))) ); /* return (int) ( f1*g1*this->read(intx, inty,colour) + f*g1*this->read(intx+1,inty,colour) +f1*g*this->read(intx,inty+1,colour) + f*g*this->read(intx+1, inty+1,colour) ); * */ }; double pngwriter::bilinear_interpolation_dread(double x, double y, int colour) { return double(this->bilinear_interpolation_read(x,y,colour))/65535.0; }; void pngwriter::plot_blend(int x, int y, double opacity, int red, int green, int blue) { this->plot(x, y, (int)(opacity*red + this->read(x,y,1)*(1.0-opacity)), (int)(opacity*green + this->read(x,y,2)*(1.0-opacity)), (int)(opacity*blue + this->read(x,y,3)*(1.0-opacity)) ); }; void pngwriter::plot_blend(int x, int y, double opacity, double red, double green, double blue) { this->plot_blend(x, y, opacity, (int)(65535*red), (int)(65535*green), (int)(65535*blue)); }; void pngwriter::invert(void) { // int temp1, temp2, temp3; double temp11, temp22, temp33; for(int jjj = 1; jjj <= (this->height_); jjj++) { for(int iii = 1; iii <= (this->width_); iii++) { /* temp11 = (this->read(iii,jjj,1)); temp22 = (this->read(iii,jjj,2)); temp33 = (this->read(iii,jjj,3)); * this->plot(iii,jjj, ((double)(65535 - temp11))/65535.0, ((double)(65535 - temp22))/65535.0, ((double)(65535 - temp33))/65535.0 ); * */ temp11 = (this->read(iii,jjj,1)); temp22 = (this->read(iii,jjj,2)); temp33 = (this->read(iii,jjj,3)); this->plot(iii,jjj, (int)(65535 - temp11), (int)(65535 - temp22), (int)(65535 - temp33) ); } } } void pngwriter::resize(int width, int height) { for(int jjj = 0; jjj < height_; jjj++) free(graph_[jjj]); free(graph_); width_ = width; height_ = height; backgroundcolour_ = 0; graph_ = (png_bytepp)malloc(height_ * sizeof(png_bytep)); if(graph_ == NULL) { std::cerr << " PNGwriter::resize - ERROR **: Not able to allocate memory for image." << std::endl; } for(int kkkk = 0; kkkk < height_; kkkk++) { graph_[kkkk] = (png_bytep)malloc(6*width_ * sizeof(png_byte)); if(graph_[kkkk] == NULL) { std::cerr << " PNGwriter::resize - ERROR **: Not able to allocate memory for image." << std::endl; } } if(graph_ == NULL) { std::cerr << " PNGwriter::resize - ERROR **: Not able to allocate memory for image." << std::endl; } int tempindex; for(int hhh = 0; hhhdread(xstart,ystart,1) != boundary_red) || (this->dread(xstart,ystart,2) != boundary_green) || (this->dread(xstart,ystart,3) != boundary_blue) ) && ( (this->dread(xstart,ystart,1) != fill_red) || (this->dread(xstart,ystart,2) != fill_green) || (this->dread(xstart,ystart,3) != fill_blue) ) && (xstart >0)&&(xstart <= width_)&&(ystart >0)&&(ystart <= height_) ) { this->plot(xstart, ystart, fill_red, fill_green, fill_blue); boundary_fill(xstart+1, ystart, boundary_red, boundary_green, boundary_blue, fill_red, fill_green, fill_blue) ; boundary_fill(xstart, ystart+1, boundary_red, boundary_green, boundary_blue, fill_red, fill_green, fill_blue) ; boundary_fill(xstart, ystart-1, boundary_red, boundary_green, boundary_blue, fill_red, fill_green, fill_blue) ; boundary_fill(xstart-1, ystart, boundary_red, boundary_green, boundary_blue, fill_red, fill_green, fill_blue) ; } } //no int version needed void pngwriter::flood_fill_internal(int xstart, int ystart, double start_red, double start_green, double start_blue, double fill_red, double fill_green, double fill_blue) { if(( (this->dread(xstart,ystart,1) == start_red) && (this->dread(xstart,ystart,2) == start_green) && (this->dread(xstart,ystart,3) == start_blue) ) && ( (this->dread(xstart,ystart,1) != fill_red) || (this->dread(xstart,ystart,2) != fill_green) || (this->dread(xstart,ystart,3) != fill_blue) ) && (xstart >0)&&(xstart <= width_)&&(ystart >0)&&(ystart <= height_) ) { this->plot(xstart, ystart, fill_red, fill_green, fill_blue); flood_fill_internal(xstart+1, ystart, start_red, start_green, start_blue, fill_red, fill_green, fill_blue); flood_fill_internal(xstart-1, ystart, start_red, start_green, start_blue, fill_red, fill_green, fill_blue); flood_fill_internal(xstart, ystart+1, start_red, start_green, start_blue, fill_red, fill_green, fill_blue); flood_fill_internal(xstart, ystart-1, start_red, start_green, start_blue, fill_red, fill_green, fill_blue); } } //int version void pngwriter::boundary_fill(int xstart, int ystart, int boundary_red,int boundary_green,int boundary_blue,int fill_red, int fill_green, int fill_blue) { this->boundary_fill(xstart, ystart, ((double) boundary_red)/65535.0, ((double) boundary_green)/65535.0, ((double) boundary_blue)/65535.0, ((double) fill_red)/65535.0, ((double) fill_green)/65535.0, ((double) fill_blue)/65535.0 ); } void pngwriter::flood_fill(int xstart, int ystart, double fill_red, double fill_green, double fill_blue) { flood_fill_internal(xstart, ystart, this->dread(xstart,ystart,1),this->dread(xstart,ystart,2),this->dread(xstart,ystart,3), fill_red, fill_green, fill_blue); } //int version void pngwriter::flood_fill(int xstart, int ystart, int fill_red, int fill_green, int fill_blue) { this->flood_fill(xstart, ystart, ((double) fill_red)/65535.0, ((double) fill_green)/65535.0, ((double) fill_blue)/65535.0 ); } void pngwriter::polygon(int* points, int number_of_points, double red, double green, double blue) { if((number_of_points<1)||(points ==NULL)) { std::cerr << " PNGwriter::polygon - ERROR **: Number of points is zero or negative, or array is NULL." << std::endl; return; } for(int k=0; k< number_of_points-1; k++) { this->line(points[2*k],points[2*k+1],points[2*k+2],points[2*k+3], red, green, blue); } } //int version void pngwriter::polygon(int* points, int number_of_points, int red, int green, int blue) { this->polygon(points, number_of_points, ((double) red)/65535.0, ((double) green)/65535.0, ((double) blue)/65535.0 ); } void pngwriter::plotCMYK(int x, int y, double cyan, double magenta, double yellow, double black) { /*CMYK to RGB: * ----------- * red = 255 - minimum(255,((cyan/255) * (255 - black) + black)) * green = 255 - minimum(255,((magenta/255) * (255 - black) + black)) * blue = 255 - minimum(255,((yellow/255) * (255 - black) + black)) * */ if(cyan<0.0) { cyan = 0.0; } if(magenta<0.0) { magenta = 0.0; } if(yellow<0.0) { yellow = 0.0; } if(black<0.0) { black = 0.0; } if(cyan>1.0) { cyan = 1.0; } if(magenta>1.0) { magenta = 1.0; } if(yellow>1.0) { yellow = 1.0; } if(black>1.0) { black = 1.0; } double red, green, blue, minr, ming, minb, iblack; iblack = 1.0 - black; minr = 1.0; ming = 1.0; minb = 1.0; if((cyan*iblack + black)<1.0) { minr = cyan*iblack + black; } if((magenta*iblack + black)<1.0) { ming = magenta*iblack + black; } if((yellow*iblack + black)<1.0) { minb = yellow*iblack + black; } red = 1.0 - minr; green = 1.0 - ming; blue = 1.0 - minb; this->plot(x,y,red, green, blue); } //int version void pngwriter::plotCMYK(int x, int y, int cyan, int magenta, int yellow, int black) { this->plotCMYK(x, y, ((double) cyan)/65535.0, ((double) magenta)/65535.0, ((double) yellow)/65535.0, ((double) black)/65535.0 ); } double pngwriter::dreadCMYK(int x, int y, int colour) { /* * Black = minimum(1-Red,1-Green,1-Blue) * Cyan = (1-Red-Black)/(1-Black) * Magenta = (1-Green-Black)/(1-Black) * Yellow = (1-Blue-Black)/(1-Black) * * */ if((colour !=1)&&(colour !=2)&&(colour !=3)&&(colour !=4)) { std::cerr << " PNGwriter::dreadCMYK - WARNING **: Invalid argument: should be 1, 2, 3 or 4, is " << colour << std::endl; return 0; } double black, red, green, blue, ired, igreen, iblue, iblack; //add error detection here // not much to detect, really red = this->dread(x, y, 1); green = this->dread(x, y, 2); blue = this->dread(x, y, 3); ired = 1.0 - red; igreen = 1.0 - green; iblue = 1.0 - blue; black = ired; //black is the mimimum of inverse RGB colours, and if they are all equal, it is the inverse of red. if((igreendread(x, y, 1); green = this->dread(x, y, 2); blue = this->dread(x, y, 3); ired = 1.0 - red; igreen = 1.0 - green; iblue = 1.0 - blue; black = ired; //black is the mimimum of inverse RGB colours, and if they are all equal, it is the inverse of red. if((igreenbilinear_interpolation_read(readx, ready, 1); green = this->bilinear_interpolation_read(readx, ready, 2); blue = this->bilinear_interpolation_read(readx, ready, 3); temp.plot(x, y, red, green, blue); } } // From here on, the process is the same for all scale functions. //Get data out of temp and into this's storage. //Resize this instance // Delete current storage. for(int jjj = 0; jjj < height_; jjj++) free(graph_[jjj]); free(graph_); //New image will have bit depth 16, regardless of original bit depth. bit_depth_ = 16; // New width and height will be the scaled width and height width_ = scaledw; height_ = scaledh; backgroundcolour_ = 0; graph_ = (png_bytepp)malloc(height_ * sizeof(png_bytep)); if(graph_ == NULL) { std::cerr << " PNGwriter::scale_k - ERROR **: Not able to allocate memory for image." << std::endl; } for(int kkkk = 0; kkkk < height_; kkkk++) { graph_[kkkk] = (png_bytep)malloc(6*width_ * sizeof(png_byte)); if(graph_[kkkk] == NULL) { std::cerr << " PNGwriter::scale_k - ERROR **: Not able to allocate memory for image." << std::endl; } } if(graph_ == NULL) { std::cerr << " PNGwriter::scale_k - ERROR **: Not able to allocate memory for image." << std::endl; } //This instance now has a new, resized storage space. //Copy the temp date into this's storage. int tempindex; for(int hhh = 0; hhhbilinear_interpolation_read(readx, ready, 1); green = this->bilinear_interpolation_read(readx, ready, 2); blue = this->bilinear_interpolation_read(readx, ready, 3); temp.plot(x, y, red, green, blue); } } // From here on, the process is the same for all scale functions. //Get data out of temp and into this's storage. //Resize this instance // Delete current storage. for(int jjj = 0; jjj < height_; jjj++) free(graph_[jjj]); free(graph_); //New image will have bit depth 16, regardless of original bit depth. bit_depth_ = 16; // New width and height will be the scaled width and height width_ = scaledw; height_ = scaledh; backgroundcolour_ = 0; graph_ = (png_bytepp)malloc(height_ * sizeof(png_bytep)); if(graph_ == NULL) { std::cerr << " PNGwriter::scale_kxky - ERROR **: Not able to allocate memory for image." << std::endl; } for(int kkkk = 0; kkkk < height_; kkkk++) { graph_[kkkk] = (png_bytep)malloc(6*width_ * sizeof(png_byte)); if(graph_[kkkk] == NULL) { std::cerr << " PNGwriter::scale_kxky - ERROR **: Not able to allocate memory for image." << std::endl; } } if(graph_ == NULL) { std::cerr << " PNGwriter::scale_kxky - ERROR **: Not able to allocate memory for image." << std::endl; } //This instance now has a new, resized storage space. //Copy the temp date into this's storage. int tempindex; for(int hhh = 0; hhhbilinear_interpolation_read(readx, ready, 1); green = this->bilinear_interpolation_read(readx, ready, 2); blue = this->bilinear_interpolation_read(readx, ready, 3); temp.plot(x, y, red, green, blue); } } // From here on, the process is the same for all scale functions. //Get data out of temp and into this's storage. //Resize this instance // Delete current storage. for(int jjj = 0; jjj < height_; jjj++) free(graph_[jjj]); free(graph_); //New image will have bit depth 16, regardless of original bit depth. bit_depth_ = 16; // New width and height will be the scaled width and height width_ = finalwidth; height_ = finalheight; backgroundcolour_ = 0; graph_ = (png_bytepp)malloc(height_ * sizeof(png_bytep)); if(graph_ == NULL) { std::cerr << " PNGwriter::scale_wh - ERROR **: Not able to allocate memory for image." << std::endl; } for(int kkkk = 0; kkkk < height_; kkkk++) { graph_[kkkk] = (png_bytep)malloc(6*width_ * sizeof(png_byte)); if(graph_[kkkk] == NULL) { std::cerr << " PNGwriter::scale_wh - ERROR **: Not able to allocate memory for image." << std::endl; } } if(graph_ == NULL) { std::cerr << " PNGwriter::scale_wh - ERROR **: Not able to allocate memory for image." << std::endl; } //This instance now has a new, resized storage space. //Copy the temp date into this's storage. int tempindex; for(int hhh = 0; hhhplot_blend(xfrom,yfrom,opacity, red,green,blue); if(dx > dy) { int fraction = dy - (dx >> 1); while(xfrom != xto) { if(fraction >= 0) { yfrom += stepy; fraction -= dx; } xfrom += stepx; fraction += dy; this->plot_blend(xfrom,yfrom,opacity, red,green,blue); } } else { int fraction = dx - (dy >> 1); while(yfrom != yto) { if(fraction >= 0) { xfrom += stepx; fraction -= dy; } yfrom += stepy; fraction += dx; this->plot_blend(xfrom,yfrom, opacity, red,green,blue); } } } void pngwriter::line_blend(int xfrom, int yfrom, int xto, int yto, double opacity, double red, double green,double blue) { this->line_blend(xfrom, yfrom, xto, yto, opacity, int (red*65535), int (green*65535), int (blue*65535) ); } void pngwriter::square_blend(int xfrom, int yfrom, int xto, int yto, double opacity, int red, int green,int blue) { this->line_blend(xfrom, yfrom, xfrom, yto, opacity, red, green, blue); this->line_blend(xto, yfrom, xto, yto, opacity, red, green, blue); this->line_blend(xfrom, yfrom, xto, yfrom, opacity, red, green, blue); this->line_blend(xfrom, yto, xto, yto, opacity, red, green, blue); } void pngwriter::square_blend(int xfrom, int yfrom, int xto, int yto, double opacity, double red, double green,double blue) { this->square_blend(xfrom, yfrom, xto, yto, opacity, int(red*65535), int(green*65535), int(blue*65535)); } void pngwriter::filledsquare_blend(int xfrom, int yfrom, int xto, int yto, double opacity, int red, int green,int blue) { for(int caca = xfrom; caca line_blend(caca, yfrom, caca, yto, opacity, red, green, blue); } } void pngwriter::filledsquare_blend(int xfrom, int yfrom, int xto, int yto, double opacity, double red, double green,double blue) { this->filledsquare_blend(xfrom, yfrom, xto, yto, opacity, int(red*65535), int(green*65535), int(blue*65535)); } void pngwriter::circle_aux_blend(int xcentre, int ycentre, int x, int y, double opacity, int red, int green, int blue) { if(x == 0) { this->plot_blend(xcentre, ycentre + y, opacity, red, green, blue); this->plot_blend(xcentre, ycentre - y, opacity, red, green, blue); this->plot_blend(xcentre + y, ycentre, opacity, red, green, blue); this->plot_blend(xcentre - y, ycentre, opacity, red, green, blue); } else if(x == y) { this->plot_blend(xcentre + x, ycentre + y, opacity, red, green, blue); this->plot_blend(xcentre - x, ycentre + y, opacity, red, green, blue); this->plot_blend(xcentre + x, ycentre - y, opacity, red, green, blue); this->plot_blend(xcentre - x, ycentre - y, opacity, red, green, blue); } else if(x < y) { this->plot_blend(xcentre + x, ycentre + y, opacity, red, green, blue); this->plot_blend(xcentre - x, ycentre + y, opacity, red, green, blue); this->plot_blend(xcentre + x, ycentre - y, opacity, red, green, blue); this->plot_blend(xcentre - x, ycentre - y, opacity, red, green, blue); this->plot_blend(xcentre + y, ycentre + x, opacity, red, green, blue); this->plot_blend(xcentre - y, ycentre + x, opacity, red, green, blue); this->plot_blend(xcentre + y, ycentre - x, opacity, red, green, blue); this->plot_blend(xcentre - y, ycentre - x, opacity, red, green, blue); } } // void pngwriter::circle_blend(int xcentre, int ycentre, int radius, double opacity, int red, int green, int blue) { int x = 0; int y = radius; int p = (5 - radius*4)/4; circle_aux_blend(xcentre, ycentre, x, y, opacity, red, green, blue); while(x < y) { x++; if(p < 0) { p += 2*x+1; } else { y--; p += 2*(x-y)+1; } circle_aux_blend(xcentre, ycentre, x, y, opacity, red, green, blue); } } void pngwriter::circle_blend(int xcentre, int ycentre, int radius, double opacity, double red, double green, double blue) { this->circle_blend(xcentre,ycentre,radius, opacity, int(red*65535), int(green*65535), int(blue*65535)); } void pngwriter::filledcircle_blend(int xcentre, int ycentre, int radius, double opacity, int red, int green, int blue) { for(int jjj = ycentre-radius; jjj< ycentre+radius+1; jjj++) { this->line_blend(xcentre - int(sqrt((double)(radius*radius) - (-ycentre + jjj)*(-ycentre + jjj))), jjj, xcentre + int(sqrt((double)(radius*radius) - (-ycentre + jjj)*(-ycentre + jjj))),jjj, opacity, red,green,blue); } } void pngwriter::filledcircle_blend(int xcentre, int ycentre, int radius, double opacity, double red, double green, double blue) { this->filledcircle_blend(xcentre, ycentre, radius, opacity, int(red*65535), int(green*65535), int(blue*65535)); } void pngwriter::bezier_blend(int startPtX, int startPtY, int startControlX, int startControlY, int endPtX, int endPtY, int endControlX, int endControlY, double opacity, double red, double green, double blue) { double cx = 3.0*(startControlX - startPtX); double bx = 3.0*(endControlX - startControlX) - cx; double ax = double(endPtX - startPtX - cx - bx); double cy = 3.0*(startControlY - startPtY); double by = 3.0*(endControlY - startControlY) - cy; double ay = double(endPtY - startPtY - cy - by); double x,y,newx,newy; x = startPtX; y = startPtY; for(double t = 0.0; t<=1.005; t += 0.005) { newx = startPtX + t*(double(cx) + t*(double(bx) + t*(double(ax)))); newy = startPtY + t*(double(cy) + t*(double(by) + t*(double(ay)))); this->line_blend(int(x),int(y),int(newx),int(newy),opacity, red,green,blue); x = newx; y = newy; } } void pngwriter::bezier_blend(int startPtX, int startPtY, int startControlX, int startControlY, int endPtX, int endPtY, int endControlX, int endControlY, double opacity, int red, int green, int blue) { this->bezier_blend(startPtX, startPtY, startControlX, startControlY, endPtX, endPtY, endControlX, endControlY, opacity, double(red)/65535.0, double(green)/65535.0, double(blue)/65535.0); } ///////////////////////////// #ifndef NO_FREETYPE // Freetype-based text rendering functions. /////////////////////////////////////////// void pngwriter::plot_text_blend(char* face_path, int fontsize, int x_start, int y_start, double angle, char* text, double opacity, double red, double green, double blue) { FT_Library library; FT_Face face; FT_Matrix matrix; // transformation matrix FT_Vector pen; FT_UInt glyph_index; FT_Error error; FT_Bool use_kerning; FT_UInt previous = 0; /* Set up transformation Matrix */ matrix.xx = (FT_Fixed)(cos(angle)*0x10000); /* It would make more sense to do this (below), but, bizzarely, */ matrix.xy = (FT_Fixed)(-sin(angle)*0x10000); /* if one does, FT_Load_Glyph fails consistently. */ matrix.yx = (FT_Fixed)(sin(angle)*0x10000); // matrix.yx = - matrix.xy; matrix.yy = (FT_Fixed)(cos(angle)*0x10000); // matrix.yy = matrix.xx; /* Place starting coordinates in adequate form. */ pen.x = x_start*64 ; pen.y = (int)(y_start/64.0); /*Count the length of the string */ int num_chars = strlen(text); /* Initialize FT Library object */ error = FT_Init_FreeType(&library); if(error) { std::cerr << " PNGwriter::plot_text_blend - ERROR **: FreeType: Could not init Library."<< std::endl; return;} /* Initialize FT face object */ error = FT_New_Face(library,face_path,0,&face); if(error == FT_Err_Unknown_File_Format) { std::cerr << " PNGwriter::plot_text_blend - ERROR **: FreeType: Font was opened, but type not supported."<< std::endl; return; } else if(error) { std::cerr << " PNGwriter::plot_text - ERROR **: FreeType: Could not find or load font file."<< std::endl; return; } /* Set the Char size */ error = FT_Set_Char_Size(face, /* handle to face object */ 0, /* char_width in 1/64th of points */ fontsize*64, /* char_height in 1/64th of points */ 100, /* horizontal device resolution */ 100); /* vertical device resolution */ /* A way of accesing the glyph directly */ FT_GlyphSlot slot = face->glyph; // a small shortcut /* Does the font file support kerning? */ use_kerning = FT_HAS_KERNING(face); int n; for(n = 0; n < num_chars; n++) { /* Convert character code to glyph index */ glyph_index = FT_Get_Char_Index(face, text[n]); /* Retrieve kerning distance and move pen position */ if(use_kerning && previous&& glyph_index) { FT_Vector delta; FT_Get_Kerning(face, previous, glyph_index, ft_kerning_default, //FT_KERNING_DEFAULT, &delta); /* Transform this kerning distance into rotated space */ pen.x += (int)(((double) delta.x)*cos(angle)); pen.y += (int)(((double) delta.x)*(sin(angle))); } /* Set transform */ FT_Set_Transform(face, &matrix, &pen); /*set char size*/ if(error) { std::cerr << " PNGwriter::plot_text_blend - ERROR **: FreeType: Set char size error." << std::endl; return;}; /* Retrieve glyph index from character code */ glyph_index = FT_Get_Char_Index(face, text[n]); /* Load glyph image into the slot (erase previous one) */ error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT); if(error) { std::cerr << " PNGwriter::plot_text_blend - ERROR **: FreeType: Could not load glyph (in loop). (FreeType error "<< std::hex << error <<")." << std::endl; return;} /* Convert to an anti-aliased bitmap */ // error = FT_Render_Glyph( face->glyph, FT_RENDER_MODE_NORMAL ); error = FT_Render_Glyph(face->glyph, ft_render_mode_normal); if(error) { std::cerr << " PNGwriter::plot_text_blend - ERROR **: FreeType: Render glyph error." << std::endl; return;} /* Now, draw to our target surface */ my_draw_bitmap_blend(&slot->bitmap, slot->bitmap_left, y_start + slot->bitmap_top, opacity, red, green, blue); /* Advance to the next position */ pen.x += slot->advance.x; pen.y += slot->advance.y; /* record current glyph index */ previous = glyph_index; } /* Free the face and the library objects */ FT_Done_Face(face); FT_Done_FreeType(library); } void pngwriter::plot_text_utf8_blend(char* face_path, int fontsize, int x_start, int y_start, double angle, char* text, double opacity, double red, double green, double blue) { FT_Library library; FT_Face face; FT_Matrix matrix; // transformation matrix FT_Vector pen; FT_UInt glyph_index; FT_Error error; FT_Bool use_kerning; FT_UInt previous = 0; /* Set up transformation Matrix */ matrix.xx = (FT_Fixed)(cos(angle)*0x10000); /* It would make more sense to do this (below), but, bizzarely, */ matrix.xy = (FT_Fixed)(-sin(angle)*0x10000); /* if one does, FT_Load_Glyph fails consistently. */ matrix.yx = (FT_Fixed)(sin(angle)*0x10000); // matrix.yx = - matrix.xy; matrix.yy = (FT_Fixed)(cos(angle)*0x10000); // matrix.yy = matrix.xx; /* Place starting coordinates in adequate form. */ pen.x = x_start*64 ; pen.y = (int)(y_start/64.0); /*Count the length of the string */ int num_bytes=0; while(text[num_bytes]!=0) { num_bytes++; } /* std::cout << "Num bytes is: "<< num_bytes << std::endl; */ //The array of ucs4 glyph indexes, which will by at most the number of bytes in the utf-8 file. long* ucs4text; ucs4text = new long[num_bytes+1]; unsigned char u,v,w,x,y,z; int num_chars=0; long iii=0; while(iiiglyph; // a small shortcut /* Does the font file support kerning? */ use_kerning = FT_HAS_KERNING(face); int n; for(n = 0; n < num_chars; n++) { /* Convert character code to glyph index */ glyph_index = FT_Get_Char_Index(face, ucs4text[n]); /* Retrieve kerning distance and move pen position */ if(use_kerning && previous&& glyph_index) { FT_Vector delta; FT_Get_Kerning(face, previous, glyph_index, ft_kerning_default, //FT_KERNING_DEFAULT, &delta); /* Transform this kerning distance into rotated space */ pen.x += (int)(((double) delta.x)*cos(angle)); pen.y += (int)(((double) delta.x)*(sin(angle))); } /* Set transform */ FT_Set_Transform(face, &matrix, &pen); /*set char size*/ if(error) { std::cerr << " PNGwriter::plot_text_utf8_blend - ERROR **: FreeType: Set char size error." << std::endl; return;}; /* Retrieve glyph index from character code */ glyph_index = FT_Get_Char_Index(face, ucs4text[n]); /* Load glyph image into the slot (erase previous one) */ error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT); if(error) { std::cerr << " PNGwriter::plot_text_utf8_blend - ERROR **: FreeType: Could not load glyph (in loop). (FreeType error "<< std::hex << error <<")." << std::endl; return;} /* Convert to an anti-aliased bitmap */ error = FT_Render_Glyph(face->glyph, ft_render_mode_normal); if(error) { std::cerr << " PNGwriter::plot_text_utf8_blend - ERROR **: FreeType: Render glyph error." << std::endl; return;} /* Now, draw to our target surface */ my_draw_bitmap_blend(&slot->bitmap, slot->bitmap_left, y_start + slot->bitmap_top, opacity, red, green, blue); /* Advance to the next position */ pen.x += slot->advance.x; pen.y += slot->advance.y; /* record current glyph index */ previous = glyph_index; } /* Free the face and the library objects */ FT_Done_Face(face); FT_Done_FreeType(library); delete[] ucs4text; } void pngwriter::plot_text_blend(char* face_path, int fontsize, int x_start, int y_start, double angle, char* text, double opacity, int red, int green, int blue) { plot_text_blend(face_path, fontsize, x_start, y_start, angle, text, opacity, ((double) red)/65535.0, ((double) green)/65535.0, ((double) blue)/65535.0); } void pngwriter::plot_text_utf8_blend(char* face_path, int fontsize, int x_start, int y_start, double angle, char* text, double opacity, int red, int green, int blue) { plot_text_utf8_blend(face_path, fontsize, x_start, y_start, angle, text, opacity, ((double) red)/65535.0, ((double) green)/65535.0, ((double) blue)/65535.0); } void pngwriter::my_draw_bitmap_blend(FT_Bitmap* bitmap, int x, int y, double opacity, double red, double green, double blue) { double temp; for(int j=1; jrows+1; j++) { for(int i=1; i< bitmap->width + 1; i++) { temp = (double)(bitmap->buffer[(j-1)*bitmap->width + (i-1)])/255.0; if(temp) { this->plot_blend(x + i, y - j, opacity, temp*red + (1-temp)*(this->dread(x+i,y-j,1)), temp*green + (1-temp)*(this->dread(x+i,y-j,2)), temp*blue + (1-temp)*(this->dread(x+i,y-j,3)) ); } } } } #endif #ifdef NO_FREETYPE void pngwriter::plot_text_blend(char* face_path, int fontsize, int x_start, int y_start, double angle, char* text, double opacity, int red, int green, int blue) { std::cerr << " PNGwriter::plot_text_blend - ERROR **: PNGwriter was compiled without Freetype support! Recompile PNGwriter with Freetype support (once you have Freetype installed, that is. Websites: www.freetype.org and pngwriter.sourceforge.net)." << std::endl; return; } void pngwriter::plot_text_blend(char* face_path, int fontsize, int x_start, int y_start, double angle, char* text, double opacity, double red, double green, double blue) { std::cerr << " PNGwriter::plot_text_blend - ERROR **: PNGwriter was compiled without Freetype support! Recompile PNGwriter with Freetype support (once you have Freetype installed, that is. Websites: www.freetype.org and pngwriter.sourceforge.net)." << std::endl; return; } void pngwriter::plot_text_utf8_blend(char* face_path, int fontsize, int x_start, int y_start, double angle, char* text, double opacity, int red, int green, int blue) { std::cerr << " PNGwriter::plot_text_utf8_blend - ERROR **: PNGwriter was compiled without Freetype support! Recompile PNGwriter with Freetype support (once you have Freetype installed, that is. Websites: www.freetype.org and pngwriter.sourceforge.net)." << std::endl; return; } void pngwriter::plot_text_utf8_blend(char* face_path, int fontsize, int x_start, int y_start, double angle, char* text, double opacity, double red, double green, double blue) { std::cerr << " PNGwriter::plot_text_utf8_blend - ERROR **: PNGwriter was compiled without Freetype support! Recompile PNGwriter with Freetype support (once you have Freetype installed, that is. Websites: www.freetype.org and pngwriter.sourceforge.net)." << std::endl; return; } #endif /////////////////////////// void pngwriter::boundary_fill_blend(int xstart, int ystart, double opacity, double boundary_red,double boundary_green,double boundary_blue,double fill_red, double fill_green, double fill_blue) { if(( (this->dread(xstart,ystart,1) != boundary_red) || (this->dread(xstart,ystart,2) != boundary_green) || (this->dread(xstart,ystart,3) != boundary_blue) ) && ( (this->dread(xstart,ystart,1) != fill_red) || (this->dread(xstart,ystart,2) != fill_green) || (this->dread(xstart,ystart,3) != fill_blue) ) && (xstart >0)&&(xstart <= width_)&&(ystart >0)&&(ystart <= height_) ) { this->plot_blend(xstart, ystart, opacity, fill_red, fill_green, fill_blue); boundary_fill_blend(xstart+1, ystart, opacity, boundary_red, boundary_green, boundary_blue, fill_red, fill_green, fill_blue) ; boundary_fill_blend(xstart, ystart+1, opacity, boundary_red, boundary_green, boundary_blue, fill_red, fill_green, fill_blue) ; boundary_fill_blend(xstart, ystart-1, opacity, boundary_red, boundary_green, boundary_blue, fill_red, fill_green, fill_blue) ; boundary_fill_blend(xstart-1, ystart, opacity, boundary_red, boundary_green, boundary_blue, fill_red, fill_green, fill_blue) ; } } //no int version needed void pngwriter::flood_fill_internal_blend(int xstart, int ystart, double opacity, double start_red, double start_green, double start_blue, double fill_red, double fill_green, double fill_blue) { if(( (this->dread(xstart,ystart,1) == start_red) && (this->dread(xstart,ystart,2) == start_green) && (this->dread(xstart,ystart,3) == start_blue) ) && ( (this->dread(xstart,ystart,1) != fill_red) || (this->dread(xstart,ystart,2) != fill_green) || (this->dread(xstart,ystart,3) != fill_blue) ) && (xstart >0)&&(xstart <= width_)&&(ystart >0)&&(ystart <= height_) ) { this->plot_blend(xstart, ystart, opacity, fill_red, fill_green, fill_blue); flood_fill_internal_blend(xstart+1, ystart, opacity, start_red, start_green, start_blue, fill_red, fill_green, fill_blue); flood_fill_internal_blend(xstart-1, ystart,opacity, start_red, start_green, start_blue, fill_red, fill_green, fill_blue); flood_fill_internal_blend(xstart, ystart+1, opacity, start_red, start_green, start_blue, fill_red, fill_green, fill_blue); flood_fill_internal_blend(xstart, ystart-1, opacity, start_red, start_green, start_blue, fill_red, fill_green, fill_blue); } } //int version void pngwriter::boundary_fill_blend(int xstart, int ystart, double opacity, int boundary_red,int boundary_green,int boundary_blue,int fill_red, int fill_green, int fill_blue) { this->boundary_fill_blend(xstart, ystart, opacity, ((double) boundary_red)/65535.0, ((double) boundary_green)/65535.0, ((double) boundary_blue)/65535.0, ((double) fill_red)/65535.0, ((double) fill_green)/65535.0, ((double) fill_blue)/65535.0 ); } void pngwriter::flood_fill_blend(int xstart, int ystart, double opacity, double fill_red, double fill_green, double fill_blue) { flood_fill_internal_blend(xstart, ystart, opacity, this->dread(xstart,ystart,1),this->dread(xstart,ystart,2),this->dread(xstart,ystart,3), fill_red, fill_green, fill_blue); } //int version void pngwriter::flood_fill_blend(int xstart, int ystart, double opacity, int fill_red, int fill_green, int fill_blue) { this->flood_fill_blend(xstart, ystart, opacity, ((double) fill_red)/65535.0, ((double) fill_green)/65535.0, ((double) fill_blue)/65535.0 ); } void pngwriter::polygon_blend(int* points, int number_of_points, double opacity, double red, double green, double blue) { if((number_of_points<1)||(points ==NULL)) { std::cerr << " PNGwriter::polygon_blend - ERROR **: Number of points is zero or negative, or array is NULL." << std::endl; return; } for(int k=0; k< number_of_points-1; k++) { this->line_blend(points[2*k],points[2*k+1],points[2*k+2],points[2*k+3], opacity, red, green, blue); } } //int version void pngwriter::polygon_blend(int* points, int number_of_points, double opacity, int red, int green, int blue) { this->polygon_blend(points, number_of_points, opacity, ((double) red)/65535.0, ((double) green)/65535.0, ((double) blue)/65535.0 ); } void pngwriter::plotCMYK_blend(int x, int y, double opacity, double cyan, double magenta, double yellow, double black) { /*CMYK to RGB: * ----------- * red = 255 - minimum(255,((cyan/255) * (255 - black) + black)) * green = 255 - minimum(255,((magenta/255) * (255 - black) + black)) * blue = 255 - minimum(255,((yellow/255) * (255 - black) + black)) * */ if(cyan<0.0) { cyan = 0.0; } if(magenta<0.0) { magenta = 0.0; } if(yellow<0.0) { yellow = 0.0; } if(black<0.0) { black = 0.0; } if(cyan>1.0) { cyan = 1.0; } if(magenta>1.0) { magenta = 1.0; } if(yellow>1.0) { yellow = 1.0; } if(black>1.0) { black = 1.0; } double red, green, blue, minr, ming, minb, iblack; iblack = 1.0 - black; minr = 1.0; ming = 1.0; minb = 1.0; if((cyan*iblack + black)<1.0) { minr = cyan*iblack + black; } if((magenta*iblack + black)<1.0) { ming = magenta*iblack + black; } if((yellow*iblack + black)<1.0) { minb = yellow*iblack + black; } red = 1.0 - minr; green = 1.0 - ming; blue = 1.0 - minb; this->plot_blend(x,y,opacity, red, green, blue); } //int version void pngwriter::plotCMYK_blend(int x, int y, double opacity, int cyan, int magenta, int yellow, int black) { this->plotCMYK_blend(x, y, opacity, ((double) cyan)/65535.0, ((double) magenta)/65535.0, ((double) yellow)/65535.0, ((double) black)/65535.0 ); } void pngwriter::laplacian(double k, double offset) { // Create image storage. pngwriter temp(width_,height_,0,"temp"); double red, green, blue; for(int x = 1; x <= width_; x++) { for(int y = 1; y <= height_; y++) { red = 8.0*this->dread(x,y,1) - (this->dread(x+1, y-1, 1) + this->dread(x, y-1, 1) + this->dread(x-1, y-1, 1) + this->dread(x-1, y, 1) + this->dread(x+1, y, 1) + this->dread(x+1, y+1, 1) + this->dread(x, y+1, 1) + this->dread(x-1, y+1, 1)); green = 8.0*this->dread(x,y,2) - (this->dread(x+1, y-1, 2) + this->dread(x, y-1, 2) + this->dread(x-1, y-1, 2) + this->dread(x-1, y, 2) + this->dread(x+1, y, 2) + this->dread(x+1, y+1, 2) + this->dread(x, y+1, 2) + this->dread(x-1, y+1, 2)); blue = 8.0*this->dread(x,y,3) - (this->dread(x+1, y-1, 3) + this->dread(x, y-1, 3) + this->dread(x-1, y-1, 3) + this->dread(x-1, y, 3) + this->dread(x+1, y, 3) + this->dread(x+1, y+1, 3) + this->dread(x, y+1, 3) + this->dread(x-1, y+1, 3)); temp.plot(x,y,offset+k*red,offset+k*green,offset+k*blue); } } for(int xx = 1; xx <= width_; xx++) { for(int yy = 1; yy <= height_; yy++) { this->plot(xx,yy, temp.read(xx,yy,1), temp.read(xx,yy,2), temp.read(xx,yy,3)); } } } // drwatop(), drawbottom() and filledtriangle() were contributed by Gurkan Sengun // ( , http://www.linuks.mine.nu/ ) void pngwriter::drawtop(long x1,long y1,long x2,long y2,long x3, int red, int green, int blue) { // This swaps x2 and x3 // if(x2>x3) x2^=x3^=x2^=x3; if(x2>x3) { x2^=x3; x3^=x2; x2^=x3; } long posl = x1*256; long posr = posl; long cl=((x2-x1)*256)/(y2-y1); long cr=((x3-x1)*256)/(y2-y1); for(int y=y1; yline(posl/256, y, posr/256, y, red, green, blue); posl+=cl; posr+=cr; } } // drwatop(), drawbottom() and filledtriangle() were contributed by Gurkan Sengun // ( , http://www.linuks.mine.nu/ ) void pngwriter::drawbottom(long x1,long y1,long x2,long x3,long y3, int red, int green, int blue) { //Swap x1 and x2 //if(x1>x2) x2^=x1^=x2^=x1; if(x1>x2) { x2^=x1; x1^=x2; x2^=x1; } long posl=x1*256; long posr=x2*256; long cl=((x3-x1)*256)/(y3-y1); long cr=((x3-x2)*256)/(y3-y1); for(int y=y1; yline(posl/256, y, posr/256, y, red, green, blue); posl+=cl; posr+=cr; } } // drwatop(), drawbottom() and filledtriangle() were contributed by Gurkan Sengun // ( , http://www.linuks.mine.nu/ ) void pngwriter::filledtriangle(int x1,int y1,int x2,int y2,int x3,int y3, int red, int green, int blue) { if((x1==x2 && x2==x3) || (y1==y2 && y2==y3)) return; if(y2drawtop(x1, y1, x2, y2, x3, red, green, blue); } else { if(y1==y3 || y1==y2) { this->drawbottom(x1, y1, x2, x3, y3, red, green, blue); } else { int new_x = x1 + (int)((double)(y2-y1)*(double)(x3-x1)/(double)(y3-y1)); this->drawtop(x1, y1, new_x, y2, x2, red, green, blue); this->drawbottom(x2, y2, new_x, x3, y3, red, green, blue); } } } //Double (bug found by Dave Wilks. Was: (int) red*65535, should have been (int) (red*65535). void pngwriter::filledtriangle(int x1,int y1,int x2,int y2,int x3,int y3, double red, double green, double blue) { this->filledtriangle(x1, y1, x2, y2, x3, y3, (int)(red*65535), (int)(green*65535), (int)(blue*65535)); } //Blend, double. (bug found by Dave Wilks. Was: (int) red*65535, should have been (int) (red*65535). void pngwriter::filledtriangle_blend(int x1,int y1,int x2,int y2,int x3,int y3, double opacity, double red, double green, double blue) { this->filledtriangle_blend(x1, y1, x2, y2, x3, y3, opacity, (int)(red*65535), (int)(green*65535), (int)(blue*65535)); } //Blend, int void pngwriter::filledtriangle_blend(int x1,int y1,int x2,int y2,int x3,int y3, double opacity, int red, int green, int blue) { if((x1==x2 && x2==x3) || (y1==y2 && y2==y3)) return; /*if(y2drawtop_blend(x1, y1, x2, y2, x3, opacity, red, green, blue); } else { if(y1==y3 || y1==y2) { this->drawbottom_blend(x1, y1, x2, x3, y3, opacity, red, green, blue); } else { int new_x = x1 + (int)((double)(y2-y1)*(double)(x3-x1)/(double)(y3-y1)); this->drawtop_blend(x1, y1, new_x, y2, x2, opacity, red, green, blue); this->drawbottom_blend(x2, y2, new_x, x3, y3, opacity, red, green, blue); } } } //Blend, int void pngwriter::drawbottom_blend(long x1,long y1,long x2,long x3,long y3, double opacity, int red, int green, int blue) { //Swap x1 and x2 if(x1>x2) { x2^=x1; x1^=x2; x2^=x1; } long posl=x1*256; long posr=x2*256; long cl=((x3-x1)*256)/(y3-y1); long cr=((x3-x2)*256)/(y3-y1); for(int y=y1; yline_blend(posl/256, y, posr/256, y, opacity, red, green, blue); posl+=cl; posr+=cr; } } //Blend, int void pngwriter::drawtop_blend(long x1,long y1,long x2,long y2,long x3, double opacity, int red, int green, int blue) { // This swaps x2 and x3 if(x2>x3) { x2^=x3; x3^=x2; x2^=x3; } long posl = x1*256; long posr = posl; long cl=((x2-x1)*256)/(y2-y1); long cr=((x3-x1)*256)/(y2-y1); for(int y=y1; yline_blend(posl/256, y, posr/256, y, opacity, red, green, blue); posl+=cl; posr+=cr; } } void pngwriter::triangle(int x1, int y1, int x2, int y2, int x3, int y3, int red, int green, int blue) { this->line(x1, y1, x2, y2, red, green, blue); this->line(x2, y2, x3, y3, red, green, blue); this->line(x3, y3, x1, y1, red, green, blue); } void pngwriter::triangle(int x1, int y1, int x2, int y2, int x3, int y3, double red, double green, double blue) { this->line(x1, y1, x2, y2, ((int)65535*red), ((int)65535*green), ((int)65535*blue)); this->line(x2, y2, x3, y3, ((int)65535*red), ((int)65535*green), ((int)65535*blue)); this->line(x3, y3, x1, y1, ((int)65535*red), ((int)65535*green), ((int)65535*blue)); } void pngwriter::arrow(int x1,int y1,int x2,int y2,int size, double head_angle, double red, double green, double blue) { this->line(x1, y1, x2, y2, red, green, blue); // double th = 3.141592653589793 + (head_angle)*3.141592653589793/180.0; //degrees double th = 3.141592653589793 + head_angle; double costh = cos(th); double sinth = sin(th); double t1, t2, r; t1 = ((x2-x1)*costh - (y2-y1)*sinth); t2 = ((x2-x1)*sinth + (y2-y1)*costh); r = sqrt(t1*t1 + t2*t2); double advancex = size*t1/r; double advancey = size*t2/r; this->line(x2, y2, int(x2 + advancex), int(y2 + advancey), red, green, blue); t1 = (x2-x1)*costh + (y2-y1)*sinth; t2 = (y2-y1)*costh - (x2-x1)*sinth; advancex = size*t1/r; advancey = size*t2/r; this->line(x2, y2, int(x2 + advancex), int(y2 + advancey), red, green, blue); } void pngwriter::filledarrow(int x1,int y1,int x2,int y2,int size, double head_angle, double red, double green, double blue) { int p1x, p2x, p3x, p1y, p2y, p3y; this->line(x1, y1, x2, y2, red, green, blue); double th = 3.141592653589793 + head_angle; double costh = cos(th); double sinth = sin(th); double t11, t12, t21, t22, r1, r2; t11 = ((x2-x1)*costh - (y2-y1)*sinth); t21 = ((x2-x1)*sinth + (y2-y1)*costh); t12 = (x2-x1)*costh + (y2-y1)*sinth; t22 = (y2-y1)*costh - (x2-x1)*sinth; r1 = sqrt(t11*t11 + t21*t21); r2 = sqrt(t12*t12 + t22*t22); double advancex1 = size*t11/r1; double advancey1 = size*t21/r1; double advancex2 = size*t12/r2; double advancey2 = size*t22/r2; p1x = x2; p1y = y2; p2x = int(x2 + advancex1); p2y = int(y2 + advancey1); p3x = int(x2 + advancex2); p3y = int(y2 + advancey2); this->filledtriangle(p1x, p1y, p2x, p2y, p3x, p3y, red, green, blue); } void pngwriter::arrow(int x1,int y1,int x2,int y2,int size, double head_angle, int red, int green, int blue) { this->arrow(x1, y1, x2, y2, size, head_angle, (double(red))/65535.0, (double(green))/65535.0, (double(blue))/65535.0); } void pngwriter::filledarrow(int x1,int y1,int x2,int y2,int size, double head_angle, int red, int green, int blue) { this->filledarrow(x1, y1, x2, y2, size, head_angle, (double(red))/65535.0, (double(green))/65535.0, (double(blue))/65535.0); } void pngwriter::cross(int x, int y, int xwidth, int yheight, int red, int green, int blue) { this->line(int(x - xwidth/2.0), y, int(x + xwidth/2.0), y, red, green, blue); this->line(x, int(y - yheight/2.0), x, int(y + yheight/2.0), red, green, blue); } void pngwriter::maltesecross(int x, int y, int xwidth, int yheight, int x_bar_height, int y_bar_width, int red, int green, int blue) { this->line(int(x - xwidth/2.0), y, int(x + xwidth/2.0), y, red, green, blue); this->line(x, int(y - yheight/2.0), x, int(y + yheight/2.0), red, green, blue); // Bars on ends of vertical line this->line(int(x - y_bar_width/2.0), int(y + yheight/2.0), int(x + y_bar_width/2.0), int(y + yheight/2.0), red, green, blue); this->line(int(x - y_bar_width/2.0), int(y - yheight/2.0), int(x + y_bar_width/2.0), int(y - yheight/2.0), red, green, blue); // Bars on ends of horizontal line. this->line(int(x - xwidth/2.0), int(y - x_bar_height/2.0), int(x - xwidth/2.0), int(y + x_bar_height/2.0), red, green, blue); this->line(int(x + xwidth/2.0), int(y - x_bar_height/2.0), int(x + xwidth/2.0), int(y + x_bar_height/2.0), red, green, blue); } void pngwriter::cross(int x, int y, int xwidth, int yheight, double red, double green, double blue) { this->cross(x, y, xwidth, yheight, int(65535*red), int(65535*green), int(65535*blue)); } void pngwriter::maltesecross(int x, int y, int xwidth, int yheight, int x_bar_height, int y_bar_width, double red, double green, double blue) { this->maltesecross(x, y, xwidth, yheight, x_bar_height, y_bar_width, int(65535*red), int(65535*green), int(65535*blue)); } void pngwriter::filleddiamond(int x, int y, int width, int height, int red, int green, int blue) { this->filledtriangle(int(x - width/2.0), y, x, y, x, int(y + height/2.0), red, green, blue); this->filledtriangle(int(x + width/2.0), y, x, y, x, int(y + height/2.0), red, green, blue); this->filledtriangle(int(x - width/2.0), y, x, y, x, int(y - height/2.0), red, green, blue); this->filledtriangle(int(x + width/2.0), y, x, y, x, int(y - height/2.0), red, green, blue); } void pngwriter::diamond(int x, int y, int width, int height, int red, int green, int blue) { this->line(int(x - width/2.0), y, x, int(y + height/2.0), red, green, blue); this->line(int(x + width/2.0), y, x, int(y + height/2.0), red, green, blue); this->line(int(x - width/2.0), y, x, int(y - height/2.0), red, green, blue); this->line(int(x + width/2.0), y, x, int(y - height/2.0), red, green, blue); } void pngwriter::filleddiamond(int x, int y, int width, int height, double red, double green, double blue) { this->filleddiamond(x, y, width, height, int(red*65535), int(green*65535), int(blue*65535)); } void pngwriter::diamond(int x, int y, int width, int height, double red, double green, double blue) { this->diamond(x, y, width, height, int(red*65535), int(green*65535), int(blue*65535)); }