pngwriter.cc 132 KB

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