pngwriter.cc 132 KB

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