fpdf.go 147 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007
  1. /*
  2. * Copyright (c) 2013-2014 Kurt Jung (Gmail: kurt.w.jung)
  3. *
  4. * Permission to use, copy, modify, and distribute this software for any
  5. * purpose with or without fee is hereby granted, provided that the above
  6. * copyright notice and this permission notice appear in all copies.
  7. *
  8. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  9. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  10. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  11. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  12. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  13. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  14. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15. */
  16. package gofpdf
  17. // Version: 1.7
  18. // Date: 2011-06-18
  19. // Author: Olivier PLATHEY
  20. // Port to Go: Kurt Jung, 2013-07-15
  21. import (
  22. "bytes"
  23. "encoding/binary"
  24. "encoding/json"
  25. "fmt"
  26. "image"
  27. "image/color"
  28. "image/gif"
  29. "image/jpeg"
  30. "image/png"
  31. "io"
  32. "io/ioutil"
  33. "math"
  34. "os"
  35. "path"
  36. "sort"
  37. "strconv"
  38. "strings"
  39. "time"
  40. )
  41. var gl struct {
  42. catalogSort bool
  43. noCompress bool // Initial zero value indicates compression
  44. creationDate time.Time
  45. modDate time.Time
  46. }
  47. type fmtBuffer struct {
  48. bytes.Buffer
  49. }
  50. func (b *fmtBuffer) printf(fmtStr string, args ...interface{}) {
  51. b.Buffer.WriteString(fmt.Sprintf(fmtStr, args...))
  52. }
  53. func fpdfNew(orientationStr, unitStr, sizeStr, fontDirStr string, size SizeType) (f *Fpdf) {
  54. f = new(Fpdf)
  55. if orientationStr == "" {
  56. orientationStr = "p"
  57. } else {
  58. orientationStr = strings.ToLower(orientationStr)
  59. }
  60. if unitStr == "" {
  61. unitStr = "mm"
  62. }
  63. if sizeStr == "" {
  64. sizeStr = "A4"
  65. }
  66. if fontDirStr == "" {
  67. fontDirStr = "."
  68. }
  69. f.page = 0
  70. f.n = 2
  71. f.pages = make([]*bytes.Buffer, 0, 8)
  72. f.pages = append(f.pages, bytes.NewBufferString("")) // pages[0] is unused (1-based)
  73. f.pageSizes = make(map[int]SizeType)
  74. f.pageBoxes = make(map[int]map[string]PageBox)
  75. f.defPageBoxes = make(map[string]PageBox)
  76. f.state = 0
  77. f.fonts = make(map[string]fontDefType)
  78. f.fontFiles = make(map[string]fontFileType)
  79. f.diffs = make([]string, 0, 8)
  80. f.templates = make(map[string]Template)
  81. f.templateObjects = make(map[string]int)
  82. f.importedObjs = make(map[string][]byte, 0)
  83. f.importedObjPos = make(map[string]map[int]string, 0)
  84. f.importedTplObjs = make(map[string]string)
  85. f.importedTplIDs = make(map[string]int, 0)
  86. f.images = make(map[string]*ImageInfoType)
  87. f.pageLinks = make([][]linkType, 0, 8)
  88. f.pageLinks = append(f.pageLinks, make([]linkType, 0, 0)) // pageLinks[0] is unused (1-based)
  89. f.links = make([]intLinkType, 0, 8)
  90. f.links = append(f.links, intLinkType{}) // links[0] is unused (1-based)
  91. f.pageAttachments = make([][]annotationAttach, 0, 8)
  92. f.pageAttachments = append(f.pageAttachments, []annotationAttach{}) //
  93. f.aliasMap = make(map[string]string)
  94. f.inHeader = false
  95. f.inFooter = false
  96. f.lasth = 0
  97. f.fontFamily = ""
  98. f.fontStyle = ""
  99. f.SetFontSize(12)
  100. f.underline = false
  101. f.strikeout = false
  102. f.setDrawColor(0, 0, 0)
  103. f.setFillColor(0, 0, 0)
  104. f.setTextColor(0, 0, 0)
  105. f.colorFlag = false
  106. f.ws = 0
  107. f.fontpath = fontDirStr
  108. // Core fonts
  109. f.coreFonts = map[string]bool{
  110. "courier": true,
  111. "helvetica": true,
  112. "times": true,
  113. "symbol": true,
  114. "zapfdingbats": true,
  115. }
  116. // Scale factor
  117. switch unitStr {
  118. case "pt", "point":
  119. f.k = 1.0
  120. case "mm":
  121. f.k = 72.0 / 25.4
  122. case "cm":
  123. f.k = 72.0 / 2.54
  124. case "in", "inch":
  125. f.k = 72.0
  126. default:
  127. f.err = fmt.Errorf("incorrect unit %s", unitStr)
  128. return
  129. }
  130. f.unitStr = unitStr
  131. // Page sizes
  132. f.stdPageSizes = make(map[string]SizeType)
  133. f.stdPageSizes["a3"] = SizeType{841.89, 1190.55}
  134. f.stdPageSizes["a4"] = SizeType{595.28, 841.89}
  135. f.stdPageSizes["a5"] = SizeType{420.94, 595.28}
  136. f.stdPageSizes["a6"] = SizeType{297.64, 420.94}
  137. f.stdPageSizes["a2"] = SizeType{1190.55, 1683.78}
  138. f.stdPageSizes["a1"] = SizeType{1683.78, 2383.94}
  139. f.stdPageSizes["letter"] = SizeType{612, 792}
  140. f.stdPageSizes["legal"] = SizeType{612, 1008}
  141. f.stdPageSizes["tabloid"] = SizeType{792, 1224}
  142. if size.Wd > 0 && size.Ht > 0 {
  143. f.defPageSize = size
  144. } else {
  145. f.defPageSize = f.getpagesizestr(sizeStr)
  146. if f.err != nil {
  147. return
  148. }
  149. }
  150. f.curPageSize = f.defPageSize
  151. // Page orientation
  152. switch orientationStr {
  153. case "p", "portrait":
  154. f.defOrientation = "P"
  155. f.w = f.defPageSize.Wd
  156. f.h = f.defPageSize.Ht
  157. // dbg("Assign h: %8.2f", f.h)
  158. case "l", "landscape":
  159. f.defOrientation = "L"
  160. f.w = f.defPageSize.Ht
  161. f.h = f.defPageSize.Wd
  162. default:
  163. f.err = fmt.Errorf("incorrect orientation: %s", orientationStr)
  164. return
  165. }
  166. f.curOrientation = f.defOrientation
  167. f.wPt = f.w * f.k
  168. f.hPt = f.h * f.k
  169. // Page margins (1 cm)
  170. margin := 28.35 / f.k
  171. f.SetMargins(margin, margin, margin)
  172. // Interior cell margin (1 mm)
  173. f.cMargin = margin / 10
  174. // Line width (0.2 mm)
  175. f.lineWidth = 0.567 / f.k
  176. // Automatic page break
  177. f.SetAutoPageBreak(true, 2*margin)
  178. // Default display mode
  179. f.SetDisplayMode("default", "default")
  180. if f.err != nil {
  181. return
  182. }
  183. f.acceptPageBreak = func() bool {
  184. return f.autoPageBreak
  185. }
  186. // Enable compression
  187. f.SetCompression(!gl.noCompress)
  188. f.spotColorMap = make(map[string]spotColorType)
  189. f.blendList = make([]blendModeType, 0, 8)
  190. f.blendList = append(f.blendList, blendModeType{}) // blendList[0] is unused (1-based)
  191. f.blendMap = make(map[string]int)
  192. f.blendMode = "Normal"
  193. f.alpha = 1
  194. f.gradientList = make([]gradientType, 0, 8)
  195. f.gradientList = append(f.gradientList, gradientType{}) // gradientList[0] is unused
  196. // Set default PDF version number
  197. f.pdfVersion = "1.3"
  198. f.SetProducer("FPDF "+cnFpdfVersion, true)
  199. f.layerInit()
  200. f.catalogSort = gl.catalogSort
  201. f.creationDate = gl.creationDate
  202. f.modDate = gl.modDate
  203. f.userUnderlineThickness = 1
  204. return
  205. }
  206. // NewCustom returns a pointer to a new Fpdf instance. Its methods are
  207. // subsequently called to produce a single PDF document. NewCustom() is an
  208. // alternative to New() that provides additional customization. The PageSize()
  209. // example demonstrates this method.
  210. func NewCustom(init *InitType) (f *Fpdf) {
  211. return fpdfNew(init.OrientationStr, init.UnitStr, init.SizeStr, init.FontDirStr, init.Size)
  212. }
  213. // New returns a pointer to a new Fpdf instance. Its methods are subsequently
  214. // called to produce a single PDF document.
  215. //
  216. // orientationStr specifies the default page orientation. For portrait mode,
  217. // specify "P" or "Portrait". For landscape mode, specify "L" or "Landscape".
  218. // An empty string will be replaced with "P".
  219. //
  220. // unitStr specifies the unit of length used in size parameters for elements
  221. // other than fonts, which are always measured in points. Specify "pt" for
  222. // point, "mm" for millimeter, "cm" for centimeter, or "in" for inch. An empty
  223. // string will be replaced with "mm".
  224. //
  225. // sizeStr specifies the page size. Acceptable values are "A3", "A4", "A5",
  226. // "Letter", "Legal", or "Tabloid". An empty string will be replaced with "A4".
  227. //
  228. // fontDirStr specifies the file system location in which font resources will
  229. // be found. An empty string is replaced with ".". This argument only needs to
  230. // reference an actual directory if a font other than one of the core
  231. // fonts is used. The core fonts are "courier", "helvetica" (also called
  232. // "arial"), "times", and "zapfdingbats" (also called "symbol").
  233. func New(orientationStr, unitStr, sizeStr, fontDirStr string) (f *Fpdf) {
  234. return fpdfNew(orientationStr, unitStr, sizeStr, fontDirStr, SizeType{0, 0})
  235. }
  236. // Ok returns true if no processing errors have occurred.
  237. func (f *Fpdf) Ok() bool {
  238. return f.err == nil
  239. }
  240. // Err returns true if a processing error has occurred.
  241. func (f *Fpdf) Err() bool {
  242. return f.err != nil
  243. }
  244. // ClearError unsets the internal Fpdf error. This method should be used with
  245. // care, as an internal error condition usually indicates an unrecoverable
  246. // problem with the generation of a document. It is intended to deal with cases
  247. // in which an error is used to select an alternate form of the document.
  248. func (f *Fpdf) ClearError() {
  249. f.err = nil
  250. }
  251. // SetErrorf sets the internal Fpdf error with formatted text to halt PDF
  252. // generation; this may facilitate error handling by application. If an error
  253. // condition is already set, this call is ignored.
  254. //
  255. // See the documentation for printing in the standard fmt package for details
  256. // about fmtStr and args.
  257. func (f *Fpdf) SetErrorf(fmtStr string, args ...interface{}) {
  258. if f.err == nil {
  259. f.err = fmt.Errorf(fmtStr, args...)
  260. }
  261. }
  262. // String satisfies the fmt.Stringer interface and summarizes the Fpdf
  263. // instance.
  264. func (f *Fpdf) String() string {
  265. return "Fpdf " + cnFpdfVersion
  266. }
  267. // SetError sets an error to halt PDF generation. This may facilitate error
  268. // handling by application. See also Ok(), Err() and Error().
  269. func (f *Fpdf) SetError(err error) {
  270. if f.err == nil && err != nil {
  271. f.err = err
  272. }
  273. }
  274. // Error returns the internal Fpdf error; this will be nil if no error has occurred.
  275. func (f *Fpdf) Error() error {
  276. return f.err
  277. }
  278. // GetPageSize returns the current page's width and height. This is the paper's
  279. // size. To compute the size of the area being used, subtract the margins (see
  280. // GetMargins()).
  281. func (f *Fpdf) GetPageSize() (width, height float64) {
  282. width = f.w
  283. height = f.h
  284. return
  285. }
  286. // GetMargins returns the left, top, right, and bottom margins. The first three
  287. // are set with the SetMargins() method. The bottom margin is set with the
  288. // SetAutoPageBreak() method.
  289. func (f *Fpdf) GetMargins() (left, top, right, bottom float64) {
  290. left = f.lMargin
  291. top = f.tMargin
  292. right = f.rMargin
  293. bottom = f.bMargin
  294. return
  295. }
  296. // SetMargins defines the left, top and right margins. By default, they equal 1
  297. // cm. Call this method to change them. If the value of the right margin is
  298. // less than zero, it is set to the same as the left margin.
  299. func (f *Fpdf) SetMargins(left, top, right float64) {
  300. f.lMargin = left
  301. f.tMargin = top
  302. if right < 0 {
  303. right = left
  304. }
  305. f.rMargin = right
  306. }
  307. // SetLeftMargin defines the left margin. The method can be called before
  308. // creating the first page. If the current abscissa gets out of page, it is
  309. // brought back to the margin.
  310. func (f *Fpdf) SetLeftMargin(margin float64) {
  311. f.lMargin = margin
  312. if f.page > 0 && f.x < margin {
  313. f.x = margin
  314. }
  315. }
  316. // GetCellMargin returns the cell margin. This is the amount of space before
  317. // and after the text within a cell that's left blank, and is in units passed
  318. // to New(). It defaults to 1mm.
  319. func (f *Fpdf) GetCellMargin() float64 {
  320. return f.cMargin
  321. }
  322. // SetCellMargin sets the cell margin. This is the amount of space before and
  323. // after the text within a cell that's left blank, and is in units passed to
  324. // New().
  325. func (f *Fpdf) SetCellMargin(margin float64) {
  326. f.cMargin = margin
  327. }
  328. // SetPageBoxRec sets the page box for the current page, and any following
  329. // pages. Allowable types are trim, trimbox, crop, cropbox, bleed, bleedbox,
  330. // art and artbox box types are case insensitive. See SetPageBox() for a method
  331. // that specifies the coordinates and extent of the page box individually.
  332. func (f *Fpdf) SetPageBoxRec(t string, pb PageBox) {
  333. switch strings.ToLower(t) {
  334. case "trim":
  335. fallthrough
  336. case "trimbox":
  337. t = "TrimBox"
  338. case "crop":
  339. fallthrough
  340. case "cropbox":
  341. t = "CropBox"
  342. case "bleed":
  343. fallthrough
  344. case "bleedbox":
  345. t = "BleedBox"
  346. case "art":
  347. fallthrough
  348. case "artbox":
  349. t = "ArtBox"
  350. default:
  351. f.err = fmt.Errorf("%s is not a valid page box type", t)
  352. return
  353. }
  354. pb.X = pb.X * f.k
  355. pb.Y = pb.Y * f.k
  356. pb.Wd = (pb.Wd * f.k) + pb.X
  357. pb.Ht = (pb.Ht * f.k) + pb.Y
  358. if f.page > 0 {
  359. f.pageBoxes[f.page][t] = pb
  360. }
  361. // always override. page defaults are supplied in addPage function
  362. f.defPageBoxes[t] = pb
  363. }
  364. // SetPageBox sets the page box for the current page, and any following pages.
  365. // Allowable types are trim, trimbox, crop, cropbox, bleed, bleedbox, art and
  366. // artbox box types are case insensitive.
  367. func (f *Fpdf) SetPageBox(t string, x, y, wd, ht float64) {
  368. f.SetPageBoxRec(t, PageBox{SizeType{Wd: wd, Ht: ht}, PointType{X: x, Y: y}})
  369. }
  370. // SetPage sets the current page to that of a valid page in the PDF document.
  371. // pageNum is one-based. The SetPage() example demonstrates this method.
  372. func (f *Fpdf) SetPage(pageNum int) {
  373. if (pageNum > 0) && (pageNum < len(f.pages)) {
  374. f.page = pageNum
  375. }
  376. }
  377. // PageCount returns the number of pages currently in the document. Since page
  378. // numbers in gofpdf are one-based, the page count is the same as the page
  379. // number of the current last page.
  380. func (f *Fpdf) PageCount() int {
  381. return len(f.pages) - 1
  382. }
  383. // SetFontLocation sets the location in the file system of the font and font
  384. // definition files.
  385. func (f *Fpdf) SetFontLocation(fontDirStr string) {
  386. f.fontpath = fontDirStr
  387. }
  388. // SetFontLoader sets a loader used to read font files (.json and .z) from an
  389. // arbitrary source. If a font loader has been specified, it is used to load
  390. // the named font resources when AddFont() is called. If this operation fails,
  391. // an attempt is made to load the resources from the configured font directory
  392. // (see SetFontLocation()).
  393. func (f *Fpdf) SetFontLoader(loader FontLoader) {
  394. f.fontLoader = loader
  395. }
  396. // SetHeaderFuncMode sets the function that lets the application render the
  397. // page header. See SetHeaderFunc() for more details. The value for homeMode
  398. // should be set to true to have the current position set to the left and top
  399. // margin after the header function is called.
  400. func (f *Fpdf) SetHeaderFuncMode(fnc func(), homeMode bool) {
  401. f.headerFnc = fnc
  402. f.headerHomeMode = homeMode
  403. }
  404. // SetHeaderFunc sets the function that lets the application render the page
  405. // header. The specified function is automatically called by AddPage() and
  406. // should not be called directly by the application. The implementation in Fpdf
  407. // is empty, so you have to provide an appropriate function if you want page
  408. // headers. fnc will typically be a closure that has access to the Fpdf
  409. // instance and other document generation variables.
  410. //
  411. // A header is a convenient place to put background content that repeats on
  412. // each page such as a watermark. When this is done, remember to reset the X
  413. // and Y values so the normal content begins where expected. Including a
  414. // watermark on each page is demonstrated in the example for TransformRotate.
  415. //
  416. // This method is demonstrated in the example for AddPage().
  417. func (f *Fpdf) SetHeaderFunc(fnc func()) {
  418. f.headerFnc = fnc
  419. }
  420. // SetFooterFunc sets the function that lets the application render the page
  421. // footer. The specified function is automatically called by AddPage() and
  422. // Close() and should not be called directly by the application. The
  423. // implementation in Fpdf is empty, so you have to provide an appropriate
  424. // function if you want page footers. fnc will typically be a closure that has
  425. // access to the Fpdf instance and other document generation variables. See
  426. // SetFooterFuncLpi for a similar function that passes a last page indicator.
  427. //
  428. // This method is demonstrated in the example for AddPage().
  429. func (f *Fpdf) SetFooterFunc(fnc func()) {
  430. f.footerFnc = fnc
  431. f.footerFncLpi = nil
  432. }
  433. // SetFooterFuncLpi sets the function that lets the application render the page
  434. // footer. The specified function is automatically called by AddPage() and
  435. // Close() and should not be called directly by the application. It is passed a
  436. // boolean that is true if the last page of the document is being rendered. The
  437. // implementation in Fpdf is empty, so you have to provide an appropriate
  438. // function if you want page footers. fnc will typically be a closure that has
  439. // access to the Fpdf instance and other document generation variables.
  440. func (f *Fpdf) SetFooterFuncLpi(fnc func(lastPage bool)) {
  441. f.footerFncLpi = fnc
  442. f.footerFnc = nil
  443. }
  444. // SetTopMargin defines the top margin. The method can be called before
  445. // creating the first page.
  446. func (f *Fpdf) SetTopMargin(margin float64) {
  447. f.tMargin = margin
  448. }
  449. // SetRightMargin defines the right margin. The method can be called before
  450. // creating the first page.
  451. func (f *Fpdf) SetRightMargin(margin float64) {
  452. f.rMargin = margin
  453. }
  454. // GetAutoPageBreak returns true if automatic pages breaks are enabled, false
  455. // otherwise. This is followed by the triggering limit from the bottom of the
  456. // page. This value applies only if automatic page breaks are enabled.
  457. func (f *Fpdf) GetAutoPageBreak() (auto bool, margin float64) {
  458. auto = f.autoPageBreak
  459. margin = f.bMargin
  460. return
  461. }
  462. // SetAutoPageBreak enables or disables the automatic page breaking mode. When
  463. // enabling, the second parameter is the distance from the bottom of the page
  464. // that defines the triggering limit. By default, the mode is on and the margin
  465. // is 2 cm.
  466. func (f *Fpdf) SetAutoPageBreak(auto bool, margin float64) {
  467. f.autoPageBreak = auto
  468. f.bMargin = margin
  469. f.pageBreakTrigger = f.h - margin
  470. }
  471. // SetDisplayMode sets advisory display directives for the document viewer.
  472. // Pages can be displayed entirely on screen, occupy the full width of the
  473. // window, use real size, be scaled by a specific zooming factor or use viewer
  474. // default (configured in the Preferences menu of Adobe Reader). The page
  475. // layout can be specified so that pages are displayed individually or in
  476. // pairs.
  477. //
  478. // zoomStr can be "fullpage" to display the entire page on screen, "fullwidth"
  479. // to use maximum width of window, "real" to use real size (equivalent to 100%
  480. // zoom) or "default" to use viewer default mode.
  481. //
  482. // layoutStr can be "single" (or "SinglePage") to display one page at once,
  483. // "continuous" (or "OneColumn") to display pages continuously, "two" (or
  484. // "TwoColumnLeft") to display two pages on two columns with odd-numbered pages
  485. // on the left, or "TwoColumnRight" to display two pages on two columns with
  486. // odd-numbered pages on the right, or "TwoPageLeft" to display pages two at a
  487. // time with odd-numbered pages on the left, or "TwoPageRight" to display pages
  488. // two at a time with odd-numbered pages on the right, or "default" to use
  489. // viewer default mode.
  490. func (f *Fpdf) SetDisplayMode(zoomStr, layoutStr string) {
  491. if f.err != nil {
  492. return
  493. }
  494. if layoutStr == "" {
  495. layoutStr = "default"
  496. }
  497. switch zoomStr {
  498. case "fullpage", "fullwidth", "real", "default":
  499. f.zoomMode = zoomStr
  500. default:
  501. f.err = fmt.Errorf("incorrect zoom display mode: %s", zoomStr)
  502. return
  503. }
  504. switch layoutStr {
  505. case "single", "continuous", "two", "default", "SinglePage", "OneColumn",
  506. "TwoColumnLeft", "TwoColumnRight", "TwoPageLeft", "TwoPageRight":
  507. f.layoutMode = layoutStr
  508. default:
  509. f.err = fmt.Errorf("incorrect layout display mode: %s", layoutStr)
  510. return
  511. }
  512. }
  513. // SetDefaultCompression controls the default setting of the internal
  514. // compression flag. See SetCompression() for more details. Compression is on
  515. // by default.
  516. func SetDefaultCompression(compress bool) {
  517. gl.noCompress = !compress
  518. }
  519. // SetCompression activates or deactivates page compression with zlib. When
  520. // activated, the internal representation of each page is compressed, which
  521. // leads to a compression ratio of about 2 for the resulting document.
  522. // Compression is on by default.
  523. func (f *Fpdf) SetCompression(compress bool) {
  524. f.compress = compress
  525. }
  526. // SetProducer defines the producer of the document. isUTF8 indicates if the string
  527. // is encoded in ISO-8859-1 (false) or UTF-8 (true).
  528. func (f *Fpdf) SetProducer(producerStr string, isUTF8 bool) {
  529. if isUTF8 {
  530. producerStr = utf8toutf16(producerStr)
  531. }
  532. f.producer = producerStr
  533. }
  534. // SetTitle defines the title of the document. isUTF8 indicates if the string
  535. // is encoded in ISO-8859-1 (false) or UTF-8 (true).
  536. func (f *Fpdf) SetTitle(titleStr string, isUTF8 bool) {
  537. if isUTF8 {
  538. titleStr = utf8toutf16(titleStr)
  539. }
  540. f.title = titleStr
  541. }
  542. // SetSubject defines the subject of the document. isUTF8 indicates if the
  543. // string is encoded in ISO-8859-1 (false) or UTF-8 (true).
  544. func (f *Fpdf) SetSubject(subjectStr string, isUTF8 bool) {
  545. if isUTF8 {
  546. subjectStr = utf8toutf16(subjectStr)
  547. }
  548. f.subject = subjectStr
  549. }
  550. // SetAuthor defines the author of the document. isUTF8 indicates if the string
  551. // is encoded in ISO-8859-1 (false) or UTF-8 (true).
  552. func (f *Fpdf) SetAuthor(authorStr string, isUTF8 bool) {
  553. if isUTF8 {
  554. authorStr = utf8toutf16(authorStr)
  555. }
  556. f.author = authorStr
  557. }
  558. // SetKeywords defines the keywords of the document. keywordStr is a
  559. // space-delimited string, for example "invoice August". isUTF8 indicates if
  560. // the string is encoded
  561. func (f *Fpdf) SetKeywords(keywordsStr string, isUTF8 bool) {
  562. if isUTF8 {
  563. keywordsStr = utf8toutf16(keywordsStr)
  564. }
  565. f.keywords = keywordsStr
  566. }
  567. // SetCreator defines the creator of the document. isUTF8 indicates if the
  568. // string is encoded in ISO-8859-1 (false) or UTF-8 (true).
  569. func (f *Fpdf) SetCreator(creatorStr string, isUTF8 bool) {
  570. if isUTF8 {
  571. creatorStr = utf8toutf16(creatorStr)
  572. }
  573. f.creator = creatorStr
  574. }
  575. // SetXmpMetadata defines XMP metadata that will be embedded with the document.
  576. func (f *Fpdf) SetXmpMetadata(xmpStream []byte) {
  577. f.xmp = xmpStream
  578. }
  579. // AliasNbPages defines an alias for the total number of pages. It will be
  580. // substituted as the document is closed. An empty string is replaced with the
  581. // string "{nb}".
  582. //
  583. // See the example for AddPage() for a demonstration of this method.
  584. func (f *Fpdf) AliasNbPages(aliasStr string) {
  585. if aliasStr == "" {
  586. aliasStr = "{nb}"
  587. }
  588. f.aliasNbPagesStr = aliasStr
  589. }
  590. // RTL enables right-to-left mode
  591. func (f *Fpdf) RTL() {
  592. f.isRTL = true
  593. }
  594. // LTR disables right-to-left mode
  595. func (f *Fpdf) LTR() {
  596. f.isRTL = false
  597. }
  598. // open begins a document
  599. func (f *Fpdf) open() {
  600. f.state = 1
  601. }
  602. // Close terminates the PDF document. It is not necessary to call this method
  603. // explicitly because Output(), OutputAndClose() and OutputFileAndClose() do it
  604. // automatically. If the document contains no page, AddPage() is called to
  605. // prevent the generation of an invalid document.
  606. func (f *Fpdf) Close() {
  607. if f.err == nil {
  608. if f.clipNest > 0 {
  609. f.err = fmt.Errorf("clip procedure must be explicitly ended")
  610. } else if f.transformNest > 0 {
  611. f.err = fmt.Errorf("transformation procedure must be explicitly ended")
  612. }
  613. }
  614. if f.err != nil {
  615. return
  616. }
  617. if f.state == 3 {
  618. return
  619. }
  620. if f.page == 0 {
  621. f.AddPage()
  622. if f.err != nil {
  623. return
  624. }
  625. }
  626. // Page footer
  627. f.inFooter = true
  628. if f.footerFnc != nil {
  629. f.footerFnc()
  630. } else if f.footerFncLpi != nil {
  631. f.footerFncLpi(true)
  632. }
  633. f.inFooter = false
  634. // Close page
  635. f.endpage()
  636. // Close document
  637. f.enddoc()
  638. return
  639. }
  640. // PageSize returns the width and height of the specified page in the units
  641. // established in New(). These return values are followed by the unit of
  642. // measure itself. If pageNum is zero or otherwise out of bounds, it returns
  643. // the default page size, that is, the size of the page that would be added by
  644. // AddPage().
  645. func (f *Fpdf) PageSize(pageNum int) (wd, ht float64, unitStr string) {
  646. sz, ok := f.pageSizes[pageNum]
  647. if ok {
  648. sz.Wd, sz.Ht = sz.Wd/f.k, sz.Ht/f.k
  649. } else {
  650. sz = f.defPageSize // user units
  651. }
  652. return sz.Wd, sz.Ht, f.unitStr
  653. }
  654. // AddPageFormat adds a new page with non-default orientation or size. See
  655. // AddPage() for more details.
  656. //
  657. // See New() for a description of orientationStr.
  658. //
  659. // size specifies the size of the new page in the units established in New().
  660. //
  661. // The PageSize() example demonstrates this method.
  662. func (f *Fpdf) AddPageFormat(orientationStr string, size SizeType) {
  663. if f.err != nil {
  664. return
  665. }
  666. if f.page != len(f.pages)-1 {
  667. f.page = len(f.pages) - 1
  668. }
  669. if f.state == 0 {
  670. f.open()
  671. }
  672. familyStr := f.fontFamily
  673. style := f.fontStyle
  674. if f.underline {
  675. style += "U"
  676. }
  677. if f.strikeout {
  678. style += "S"
  679. }
  680. fontsize := f.fontSizePt
  681. lw := f.lineWidth
  682. dc := f.color.draw
  683. fc := f.color.fill
  684. tc := f.color.text
  685. cf := f.colorFlag
  686. if f.page > 0 {
  687. f.inFooter = true
  688. // Page footer avoid double call on footer.
  689. if f.footerFnc != nil {
  690. f.footerFnc()
  691. } else if f.footerFncLpi != nil {
  692. f.footerFncLpi(false) // not last page.
  693. }
  694. f.inFooter = false
  695. // Close page
  696. f.endpage()
  697. }
  698. // Start new page
  699. f.beginpage(orientationStr, size)
  700. // Set line cap style to current value
  701. // f.out("2 J")
  702. f.outf("%d J", f.capStyle)
  703. // Set line join style to current value
  704. f.outf("%d j", f.joinStyle)
  705. // Set line width
  706. f.lineWidth = lw
  707. f.outf("%.2f w", lw*f.k)
  708. // Set dash pattern
  709. if len(f.dashArray) > 0 {
  710. f.outputDashPattern()
  711. }
  712. // Set font
  713. if familyStr != "" {
  714. f.SetFont(familyStr, style, fontsize)
  715. if f.err != nil {
  716. return
  717. }
  718. }
  719. // Set colors
  720. f.color.draw = dc
  721. if dc.str != "0 G" {
  722. f.out(dc.str)
  723. }
  724. f.color.fill = fc
  725. if fc.str != "0 g" {
  726. f.out(fc.str)
  727. }
  728. f.color.text = tc
  729. f.colorFlag = cf
  730. // Page header
  731. if f.headerFnc != nil {
  732. f.inHeader = true
  733. f.headerFnc()
  734. f.inHeader = false
  735. if f.headerHomeMode {
  736. f.SetHomeXY()
  737. }
  738. }
  739. // Restore line width
  740. if f.lineWidth != lw {
  741. f.lineWidth = lw
  742. f.outf("%.2f w", lw*f.k)
  743. }
  744. // Restore font
  745. if familyStr != "" {
  746. f.SetFont(familyStr, style, fontsize)
  747. if f.err != nil {
  748. return
  749. }
  750. }
  751. // Restore colors
  752. if f.color.draw.str != dc.str {
  753. f.color.draw = dc
  754. f.out(dc.str)
  755. }
  756. if f.color.fill.str != fc.str {
  757. f.color.fill = fc
  758. f.out(fc.str)
  759. }
  760. f.color.text = tc
  761. f.colorFlag = cf
  762. return
  763. }
  764. // AddPage adds a new page to the document. If a page is already present, the
  765. // Footer() method is called first to output the footer. Then the page is
  766. // added, the current position set to the top-left corner according to the left
  767. // and top margins, and Header() is called to display the header.
  768. //
  769. // The font which was set before calling is automatically restored. There is no
  770. // need to call SetFont() again if you want to continue with the same font. The
  771. // same is true for colors and line width.
  772. //
  773. // The origin of the coordinate system is at the top-left corner and increasing
  774. // ordinates go downwards.
  775. //
  776. // See AddPageFormat() for a version of this method that allows the page size
  777. // and orientation to be different than the default.
  778. func (f *Fpdf) AddPage() {
  779. if f.err != nil {
  780. return
  781. }
  782. // dbg("AddPage")
  783. f.AddPageFormat(f.defOrientation, f.defPageSize)
  784. return
  785. }
  786. // PageNo returns the current page number.
  787. //
  788. // See the example for AddPage() for a demonstration of this method.
  789. func (f *Fpdf) PageNo() int {
  790. return f.page
  791. }
  792. func colorComp(v int) (int, float64) {
  793. if v < 0 {
  794. v = 0
  795. } else if v > 255 {
  796. v = 255
  797. }
  798. return v, float64(v) / 255.0
  799. }
  800. func rgbColorValue(r, g, b int, grayStr, fullStr string) (clr colorType) {
  801. clr.ir, clr.r = colorComp(r)
  802. clr.ig, clr.g = colorComp(g)
  803. clr.ib, clr.b = colorComp(b)
  804. clr.mode = colorModeRGB
  805. clr.gray = clr.ir == clr.ig && clr.r == clr.b
  806. if len(grayStr) > 0 {
  807. if clr.gray {
  808. clr.str = sprintf("%.3f %s", clr.r, grayStr)
  809. } else {
  810. clr.str = sprintf("%.3f %.3f %.3f %s", clr.r, clr.g, clr.b, fullStr)
  811. }
  812. } else {
  813. clr.str = sprintf("%.3f %.3f %.3f", clr.r, clr.g, clr.b)
  814. }
  815. return
  816. }
  817. // SetDrawColor defines the color used for all drawing operations (lines,
  818. // rectangles and cell borders). It is expressed in RGB components (0 - 255).
  819. // The method can be called before the first page is created. The value is
  820. // retained from page to page.
  821. func (f *Fpdf) SetDrawColor(r, g, b int) {
  822. f.setDrawColor(r, g, b)
  823. }
  824. func (f *Fpdf) setDrawColor(r, g, b int) {
  825. f.color.draw = rgbColorValue(r, g, b, "G", "RG")
  826. if f.page > 0 {
  827. f.out(f.color.draw.str)
  828. }
  829. }
  830. // GetDrawColor returns the most recently set draw color as RGB components (0 -
  831. // 255). This will not be the current value if a draw color of some other type
  832. // (for example, spot) has been more recently set.
  833. func (f *Fpdf) GetDrawColor() (int, int, int) {
  834. return f.color.draw.ir, f.color.draw.ig, f.color.draw.ib
  835. }
  836. // SetFillColor defines the color used for all filling operations (filled
  837. // rectangles and cell backgrounds). It is expressed in RGB components (0
  838. // -255). The method can be called before the first page is created and the
  839. // value is retained from page to page.
  840. func (f *Fpdf) SetFillColor(r, g, b int) {
  841. f.setFillColor(r, g, b)
  842. }
  843. func (f *Fpdf) setFillColor(r, g, b int) {
  844. f.color.fill = rgbColorValue(r, g, b, "g", "rg")
  845. f.colorFlag = f.color.fill.str != f.color.text.str
  846. if f.page > 0 {
  847. f.out(f.color.fill.str)
  848. }
  849. }
  850. // GetFillColor returns the most recently set fill color as RGB components (0 -
  851. // 255). This will not be the current value if a fill color of some other type
  852. // (for example, spot) has been more recently set.
  853. func (f *Fpdf) GetFillColor() (int, int, int) {
  854. return f.color.fill.ir, f.color.fill.ig, f.color.fill.ib
  855. }
  856. // SetTextColor defines the color used for text. It is expressed in RGB
  857. // components (0 - 255). The method can be called before the first page is
  858. // created. The value is retained from page to page.
  859. func (f *Fpdf) SetTextColor(r, g, b int) {
  860. f.setTextColor(r, g, b)
  861. }
  862. func (f *Fpdf) setTextColor(r, g, b int) {
  863. f.color.text = rgbColorValue(r, g, b, "g", "rg")
  864. f.colorFlag = f.color.fill.str != f.color.text.str
  865. }
  866. // GetTextColor returns the most recently set text color as RGB components (0 -
  867. // 255). This will not be the current value if a text color of some other type
  868. // (for example, spot) has been more recently set.
  869. func (f *Fpdf) GetTextColor() (int, int, int) {
  870. return f.color.text.ir, f.color.text.ig, f.color.text.ib
  871. }
  872. // GetStringWidth returns the length of a string in user units. A font must be
  873. // currently selected.
  874. func (f *Fpdf) GetStringWidth(s string) float64 {
  875. if f.err != nil {
  876. return 0
  877. }
  878. w := f.GetStringSymbolWidth(s)
  879. return float64(w) * f.fontSize / 1000
  880. }
  881. // GetStringSymbolWidth returns the length of a string in glyf units. A font must be
  882. // currently selected.
  883. func (f *Fpdf) GetStringSymbolWidth(s string) int {
  884. if f.err != nil {
  885. return 0
  886. }
  887. w := 0
  888. if f.isCurrentUTF8 {
  889. unicode := []rune(s)
  890. for _, char := range unicode {
  891. intChar := int(char)
  892. if len(f.currentFont.Cw) >= intChar && f.currentFont.Cw[intChar] > 0 {
  893. if f.currentFont.Cw[intChar] != 65535 {
  894. w += f.currentFont.Cw[intChar]
  895. }
  896. } else if f.currentFont.Desc.MissingWidth != 0 {
  897. w += f.currentFont.Desc.MissingWidth
  898. } else {
  899. w += 500
  900. }
  901. }
  902. } else {
  903. for _, ch := range []byte(s) {
  904. if ch == 0 {
  905. break
  906. }
  907. w += f.currentFont.Cw[ch]
  908. }
  909. }
  910. return w
  911. }
  912. // SetLineWidth defines the line width. By default, the value equals 0.2 mm.
  913. // The method can be called before the first page is created. The value is
  914. // retained from page to page.
  915. func (f *Fpdf) SetLineWidth(width float64) {
  916. f.setLineWidth(width)
  917. }
  918. func (f *Fpdf) setLineWidth(width float64) {
  919. f.lineWidth = width
  920. if f.page > 0 {
  921. f.outf("%.2f w", width*f.k)
  922. }
  923. }
  924. // GetLineWidth returns the current line thickness.
  925. func (f *Fpdf) GetLineWidth() float64 {
  926. return f.lineWidth
  927. }
  928. // SetLineCapStyle defines the line cap style. styleStr should be "butt",
  929. // "round" or "square". A square style projects from the end of the line. The
  930. // method can be called before the first page is created. The value is
  931. // retained from page to page.
  932. func (f *Fpdf) SetLineCapStyle(styleStr string) {
  933. var capStyle int
  934. switch styleStr {
  935. case "round":
  936. capStyle = 1
  937. case "square":
  938. capStyle = 2
  939. default:
  940. capStyle = 0
  941. }
  942. f.capStyle = capStyle
  943. if f.page > 0 {
  944. f.outf("%d J", f.capStyle)
  945. }
  946. }
  947. // SetLineJoinStyle defines the line cap style. styleStr should be "miter",
  948. // "round" or "bevel". The method can be called before the first page
  949. // is created. The value is retained from page to page.
  950. func (f *Fpdf) SetLineJoinStyle(styleStr string) {
  951. var joinStyle int
  952. switch styleStr {
  953. case "round":
  954. joinStyle = 1
  955. case "bevel":
  956. joinStyle = 2
  957. default:
  958. joinStyle = 0
  959. }
  960. f.joinStyle = joinStyle
  961. if f.page > 0 {
  962. f.outf("%d j", f.joinStyle)
  963. }
  964. }
  965. // SetDashPattern sets the dash pattern that is used to draw lines. The
  966. // dashArray elements are numbers that specify the lengths, in units
  967. // established in New(), of alternating dashes and gaps. The dash phase
  968. // specifies the distance into the dash pattern at which to start the dash. The
  969. // dash pattern is retained from page to page. Call this method with an empty
  970. // array to restore solid line drawing.
  971. //
  972. // The Beziergon() example demonstrates this method.
  973. func (f *Fpdf) SetDashPattern(dashArray []float64, dashPhase float64) {
  974. scaled := make([]float64, len(dashArray))
  975. for i, value := range dashArray {
  976. scaled[i] = value * f.k
  977. }
  978. dashPhase *= f.k
  979. f.dashArray = scaled
  980. f.dashPhase = dashPhase
  981. if f.page > 0 {
  982. f.outputDashPattern()
  983. }
  984. }
  985. func (f *Fpdf) outputDashPattern() {
  986. var buf bytes.Buffer
  987. buf.WriteByte('[')
  988. for i, value := range f.dashArray {
  989. if i > 0 {
  990. buf.WriteByte(' ')
  991. }
  992. buf.WriteString(strconv.FormatFloat(value, 'f', 2, 64))
  993. }
  994. buf.WriteString("] ")
  995. buf.WriteString(strconv.FormatFloat(f.dashPhase, 'f', 2, 64))
  996. buf.WriteString(" d")
  997. f.outbuf(&buf)
  998. }
  999. // Line draws a line between points (x1, y1) and (x2, y2) using the current
  1000. // draw color, line width and cap style.
  1001. func (f *Fpdf) Line(x1, y1, x2, y2 float64) {
  1002. f.outf("%.2f %.2f m %.2f %.2f l S", x1*f.k, (f.h-y1)*f.k, x2*f.k, (f.h-y2)*f.k)
  1003. }
  1004. // fillDrawOp corrects path painting operators
  1005. func fillDrawOp(styleStr string) (opStr string) {
  1006. switch strings.ToUpper(styleStr) {
  1007. case "", "D":
  1008. // Stroke the path.
  1009. opStr = "S"
  1010. case "F":
  1011. // fill the path, using the nonzero winding number rule
  1012. opStr = "f"
  1013. case "F*":
  1014. // fill the path, using the even-odd rule
  1015. opStr = "f*"
  1016. case "FD", "DF":
  1017. // fill and then stroke the path, using the nonzero winding number rule
  1018. opStr = "B"
  1019. case "FD*", "DF*":
  1020. // fill and then stroke the path, using the even-odd rule
  1021. opStr = "B*"
  1022. default:
  1023. opStr = styleStr
  1024. }
  1025. return
  1026. }
  1027. // Rect outputs a rectangle of width w and height h with the upper left corner
  1028. // positioned at point (x, y).
  1029. //
  1030. // It can be drawn (border only), filled (with no border) or both. styleStr can
  1031. // be "F" for filled, "D" for outlined only, or "DF" or "FD" for outlined and
  1032. // filled. An empty string will be replaced with "D". Drawing uses the current
  1033. // draw color and line width centered on the rectangle's perimeter. Filling
  1034. // uses the current fill color.
  1035. func (f *Fpdf) Rect(x, y, w, h float64, styleStr string) {
  1036. f.outf("%.2f %.2f %.2f %.2f re %s", x*f.k, (f.h-y)*f.k, w*f.k, -h*f.k, fillDrawOp(styleStr))
  1037. }
  1038. // RoundedRect outputs a rectangle of width w and height h with the upper left
  1039. // corner positioned at point (x, y). It can be drawn (border only), filled
  1040. // (with no border) or both. styleStr can be "F" for filled, "D" for outlined
  1041. // only, or "DF" or "FD" for outlined and filled. An empty string will be
  1042. // replaced with "D". Drawing uses the current draw color and line width
  1043. // centered on the rectangle's perimeter. Filling uses the current fill color.
  1044. // The rounded corners of the rectangle are specified by radius r. corners is a
  1045. // string that includes "1" to round the upper left corner, "2" to round the
  1046. // upper right corner, "3" to round the lower right corner, and "4" to round
  1047. // the lower left corner. The RoundedRect example demonstrates this method.
  1048. func (f *Fpdf) RoundedRect(x, y, w, h, r float64, corners string, stylestr string) {
  1049. // This routine was adapted by Brigham Thompson from a script by Christophe Prugnaud
  1050. var rTL, rTR, rBR, rBL float64 // zero means no rounded corner
  1051. if strings.Contains(corners, "1") {
  1052. rTL = r
  1053. }
  1054. if strings.Contains(corners, "2") {
  1055. rTR = r
  1056. }
  1057. if strings.Contains(corners, "3") {
  1058. rBR = r
  1059. }
  1060. if strings.Contains(corners, "4") {
  1061. rBL = r
  1062. }
  1063. f.RoundedRectExt(x, y, w, h, rTL, rTR, rBR, rBL, stylestr)
  1064. }
  1065. // RoundedRectExt behaves the same as RoundedRect() but supports a different
  1066. // radius for each corner. A zero radius means squared corner. See
  1067. // RoundedRect() for more details. This method is demonstrated in the
  1068. // RoundedRect() example.
  1069. func (f *Fpdf) RoundedRectExt(x, y, w, h, rTL, rTR, rBR, rBL float64, stylestr string) {
  1070. f.roundedRectPath(x, y, w, h, rTL, rTR, rBR, rBL)
  1071. f.out(fillDrawOp(stylestr))
  1072. }
  1073. // Circle draws a circle centered on point (x, y) with radius r.
  1074. //
  1075. // styleStr can be "F" for filled, "D" for outlined only, or "DF" or "FD" for
  1076. // outlined and filled. An empty string will be replaced with "D". Drawing uses
  1077. // the current draw color and line width centered on the circle's perimeter.
  1078. // Filling uses the current fill color.
  1079. func (f *Fpdf) Circle(x, y, r float64, styleStr string) {
  1080. f.Ellipse(x, y, r, r, 0, styleStr)
  1081. }
  1082. // Ellipse draws an ellipse centered at point (x, y). rx and ry specify its
  1083. // horizontal and vertical radii.
  1084. //
  1085. // degRotate specifies the counter-clockwise angle in degrees that the ellipse
  1086. // will be rotated.
  1087. //
  1088. // styleStr can be "F" for filled, "D" for outlined only, or "DF" or "FD" for
  1089. // outlined and filled. An empty string will be replaced with "D". Drawing uses
  1090. // the current draw color and line width centered on the ellipse's perimeter.
  1091. // Filling uses the current fill color.
  1092. //
  1093. // The Circle() example demonstrates this method.
  1094. func (f *Fpdf) Ellipse(x, y, rx, ry, degRotate float64, styleStr string) {
  1095. f.arc(x, y, rx, ry, degRotate, 0, 360, styleStr, false)
  1096. }
  1097. // Polygon draws a closed figure defined by a series of vertices specified by
  1098. // points. The x and y fields of the points use the units established in New().
  1099. // The last point in the slice will be implicitly joined to the first to close
  1100. // the polygon.
  1101. //
  1102. // styleStr can be "F" for filled, "D" for outlined only, or "DF" or "FD" for
  1103. // outlined and filled. An empty string will be replaced with "D". Drawing uses
  1104. // the current draw color and line width centered on the ellipse's perimeter.
  1105. // Filling uses the current fill color.
  1106. func (f *Fpdf) Polygon(points []PointType, styleStr string) {
  1107. if len(points) > 2 {
  1108. for j, pt := range points {
  1109. if j == 0 {
  1110. f.point(pt.X, pt.Y)
  1111. } else {
  1112. f.outf("%.5f %.5f l ", pt.X*f.k, (f.h-pt.Y)*f.k)
  1113. }
  1114. }
  1115. f.outf("%.5f %.5f l ", points[0].X*f.k, (f.h-points[0].Y)*f.k)
  1116. f.DrawPath(styleStr)
  1117. }
  1118. }
  1119. // Beziergon draws a closed figure defined by a series of cubic Bézier curve
  1120. // segments. The first point in the slice defines the starting point of the
  1121. // figure. Each three following points p1, p2, p3 represent a curve segment to
  1122. // the point p3 using p1 and p2 as the Bézier control points.
  1123. //
  1124. // The x and y fields of the points use the units established in New().
  1125. //
  1126. // styleStr can be "F" for filled, "D" for outlined only, or "DF" or "FD" for
  1127. // outlined and filled. An empty string will be replaced with "D". Drawing uses
  1128. // the current draw color and line width centered on the ellipse's perimeter.
  1129. // Filling uses the current fill color.
  1130. func (f *Fpdf) Beziergon(points []PointType, styleStr string) {
  1131. // Thanks, Robert Lillack, for contributing this function.
  1132. if len(points) < 4 {
  1133. return
  1134. }
  1135. f.point(points[0].XY())
  1136. points = points[1:]
  1137. for len(points) >= 3 {
  1138. cx0, cy0 := points[0].XY()
  1139. cx1, cy1 := points[1].XY()
  1140. x1, y1 := points[2].XY()
  1141. f.curve(cx0, cy0, cx1, cy1, x1, y1)
  1142. points = points[3:]
  1143. }
  1144. f.DrawPath(styleStr)
  1145. }
  1146. // point outputs current point
  1147. func (f *Fpdf) point(x, y float64) {
  1148. f.outf("%.2f %.2f m", x*f.k, (f.h-y)*f.k)
  1149. }
  1150. // curve outputs a single cubic Bézier curve segment from current point
  1151. func (f *Fpdf) curve(cx0, cy0, cx1, cy1, x, y float64) {
  1152. // Thanks, Robert Lillack, for straightening this out
  1153. f.outf("%.5f %.5f %.5f %.5f %.5f %.5f c", cx0*f.k, (f.h-cy0)*f.k, cx1*f.k,
  1154. (f.h-cy1)*f.k, x*f.k, (f.h-y)*f.k)
  1155. }
  1156. // Curve draws a single-segment quadratic Bézier curve. The curve starts at
  1157. // the point (x0, y0) and ends at the point (x1, y1). The control point (cx,
  1158. // cy) specifies the curvature. At the start point, the curve is tangent to the
  1159. // straight line between the start point and the control point. At the end
  1160. // point, the curve is tangent to the straight line between the end point and
  1161. // the control point.
  1162. //
  1163. // styleStr can be "F" for filled, "D" for outlined only, or "DF" or "FD" for
  1164. // outlined and filled. An empty string will be replaced with "D". Drawing uses
  1165. // the current draw color, line width, and cap style centered on the curve's
  1166. // path. Filling uses the current fill color.
  1167. //
  1168. // The Circle() example demonstrates this method.
  1169. func (f *Fpdf) Curve(x0, y0, cx, cy, x1, y1 float64, styleStr string) {
  1170. f.point(x0, y0)
  1171. f.outf("%.5f %.5f %.5f %.5f v %s", cx*f.k, (f.h-cy)*f.k, x1*f.k, (f.h-y1)*f.k,
  1172. fillDrawOp(styleStr))
  1173. }
  1174. // CurveCubic draws a single-segment cubic Bézier curve. This routine performs
  1175. // the same function as CurveBezierCubic() but has a nonstandard argument order.
  1176. // It is retained to preserve backward compatibility.
  1177. func (f *Fpdf) CurveCubic(x0, y0, cx0, cy0, x1, y1, cx1, cy1 float64, styleStr string) {
  1178. // f.point(x0, y0)
  1179. // f.outf("%.5f %.5f %.5f %.5f %.5f %.5f c %s", cx0*f.k, (f.h-cy0)*f.k,
  1180. // cx1*f.k, (f.h-cy1)*f.k, x1*f.k, (f.h-y1)*f.k, fillDrawOp(styleStr))
  1181. f.CurveBezierCubic(x0, y0, cx0, cy0, cx1, cy1, x1, y1, styleStr)
  1182. }
  1183. // CurveBezierCubic draws a single-segment cubic Bézier curve. The curve starts at
  1184. // the point (x0, y0) and ends at the point (x1, y1). The control points (cx0,
  1185. // cy0) and (cx1, cy1) specify the curvature. At the start point, the curve is
  1186. // tangent to the straight line between the start point and the control point
  1187. // (cx0, cy0). At the end point, the curve is tangent to the straight line
  1188. // between the end point and the control point (cx1, cy1).
  1189. //
  1190. // styleStr can be "F" for filled, "D" for outlined only, or "DF" or "FD" for
  1191. // outlined and filled. An empty string will be replaced with "D". Drawing uses
  1192. // the current draw color, line width, and cap style centered on the curve's
  1193. // path. Filling uses the current fill color.
  1194. //
  1195. // This routine performs the same function as CurveCubic() but uses standard
  1196. // argument order.
  1197. //
  1198. // The Circle() example demonstrates this method.
  1199. func (f *Fpdf) CurveBezierCubic(x0, y0, cx0, cy0, cx1, cy1, x1, y1 float64, styleStr string) {
  1200. f.point(x0, y0)
  1201. f.outf("%.5f %.5f %.5f %.5f %.5f %.5f c %s", cx0*f.k, (f.h-cy0)*f.k,
  1202. cx1*f.k, (f.h-cy1)*f.k, x1*f.k, (f.h-y1)*f.k, fillDrawOp(styleStr))
  1203. }
  1204. // Arc draws an elliptical arc centered at point (x, y). rx and ry specify its
  1205. // horizontal and vertical radii.
  1206. //
  1207. // degRotate specifies the angle that the arc will be rotated. degStart and
  1208. // degEnd specify the starting and ending angle of the arc. All angles are
  1209. // specified in degrees and measured counter-clockwise from the 3 o'clock
  1210. // position.
  1211. //
  1212. // styleStr can be "F" for filled, "D" for outlined only, or "DF" or "FD" for
  1213. // outlined and filled. An empty string will be replaced with "D". Drawing uses
  1214. // the current draw color, line width, and cap style centered on the arc's
  1215. // path. Filling uses the current fill color.
  1216. //
  1217. // The Circle() example demonstrates this method.
  1218. func (f *Fpdf) Arc(x, y, rx, ry, degRotate, degStart, degEnd float64, styleStr string) {
  1219. f.arc(x, y, rx, ry, degRotate, degStart, degEnd, styleStr, false)
  1220. }
  1221. // GetAlpha returns the alpha blending channel, which consists of the
  1222. // alpha transparency value and the blend mode. See SetAlpha for more
  1223. // details.
  1224. func (f *Fpdf) GetAlpha() (alpha float64, blendModeStr string) {
  1225. return f.alpha, f.blendMode
  1226. }
  1227. // SetAlpha sets the alpha blending channel. The blending effect applies to
  1228. // text, drawings and images.
  1229. //
  1230. // alpha must be a value between 0.0 (fully transparent) to 1.0 (fully opaque).
  1231. // Values outside of this range result in an error.
  1232. //
  1233. // blendModeStr must be one of "Normal", "Multiply", "Screen", "Overlay",
  1234. // "Darken", "Lighten", "ColorDodge", "ColorBurn","HardLight", "SoftLight",
  1235. // "Difference", "Exclusion", "Hue", "Saturation", "Color", or "Luminosity". An
  1236. // empty string is replaced with "Normal".
  1237. //
  1238. // To reset normal rendering after applying a blending mode, call this method
  1239. // with alpha set to 1.0 and blendModeStr set to "Normal".
  1240. func (f *Fpdf) SetAlpha(alpha float64, blendModeStr string) {
  1241. if f.err != nil {
  1242. return
  1243. }
  1244. var bl blendModeType
  1245. switch blendModeStr {
  1246. case "Normal", "Multiply", "Screen", "Overlay",
  1247. "Darken", "Lighten", "ColorDodge", "ColorBurn", "HardLight", "SoftLight",
  1248. "Difference", "Exclusion", "Hue", "Saturation", "Color", "Luminosity":
  1249. bl.modeStr = blendModeStr
  1250. case "":
  1251. bl.modeStr = "Normal"
  1252. default:
  1253. f.err = fmt.Errorf("unrecognized blend mode \"%s\"", blendModeStr)
  1254. return
  1255. }
  1256. if alpha < 0.0 || alpha > 1.0 {
  1257. f.err = fmt.Errorf("alpha value (0.0 - 1.0) is out of range: %.3f", alpha)
  1258. return
  1259. }
  1260. f.alpha = alpha
  1261. f.blendMode = blendModeStr
  1262. alphaStr := sprintf("%.3f", alpha)
  1263. keyStr := sprintf("%s %s", alphaStr, blendModeStr)
  1264. pos, ok := f.blendMap[keyStr]
  1265. if !ok {
  1266. pos = len(f.blendList) // at least 1
  1267. f.blendList = append(f.blendList, blendModeType{alphaStr, alphaStr, blendModeStr, 0})
  1268. f.blendMap[keyStr] = pos
  1269. }
  1270. f.outf("/GS%d gs", pos)
  1271. }
  1272. func (f *Fpdf) gradientClipStart(x, y, w, h float64) {
  1273. // Save current graphic state and set clipping area
  1274. f.outf("q %.2f %.2f %.2f %.2f re W n", x*f.k, (f.h-y)*f.k, w*f.k, -h*f.k)
  1275. // Set up transformation matrix for gradient
  1276. f.outf("%.5f 0 0 %.5f %.5f %.5f cm", w*f.k, h*f.k, x*f.k, (f.h-(y+h))*f.k)
  1277. }
  1278. func (f *Fpdf) gradientClipEnd() {
  1279. // Restore previous graphic state
  1280. f.out("Q")
  1281. }
  1282. func (f *Fpdf) gradient(tp, r1, g1, b1, r2, g2, b2 int, x1, y1, x2, y2, r float64) {
  1283. pos := len(f.gradientList)
  1284. clr1 := rgbColorValue(r1, g1, b1, "", "")
  1285. clr2 := rgbColorValue(r2, g2, b2, "", "")
  1286. f.gradientList = append(f.gradientList, gradientType{tp, clr1.str, clr2.str,
  1287. x1, y1, x2, y2, r, 0})
  1288. f.outf("/Sh%d sh", pos)
  1289. }
  1290. // LinearGradient draws a rectangular area with a blending of one color to
  1291. // another. The rectangle is of width w and height h. Its upper left corner is
  1292. // positioned at point (x, y).
  1293. //
  1294. // Each color is specified with three component values, one each for red, green
  1295. // and blue. The values range from 0 to 255. The first color is specified by
  1296. // (r1, g1, b1) and the second color by (r2, g2, b2).
  1297. //
  1298. // The blending is controlled with a gradient vector that uses normalized
  1299. // coordinates in which the lower left corner is position (0, 0) and the upper
  1300. // right corner is (1, 1). The vector's origin and destination are specified by
  1301. // the points (x1, y1) and (x2, y2). In a linear gradient, blending occurs
  1302. // perpendicularly to the vector. The vector does not necessarily need to be
  1303. // anchored on the rectangle edge. Color 1 is used up to the origin of the
  1304. // vector and color 2 is used beyond the vector's end point. Between the points
  1305. // the colors are gradually blended.
  1306. func (f *Fpdf) LinearGradient(x, y, w, h float64, r1, g1, b1, r2, g2, b2 int, x1, y1, x2, y2 float64) {
  1307. f.gradientClipStart(x, y, w, h)
  1308. f.gradient(2, r1, g1, b1, r2, g2, b2, x1, y1, x2, y2, 0)
  1309. f.gradientClipEnd()
  1310. }
  1311. // RadialGradient draws a rectangular area with a blending of one color to
  1312. // another. The rectangle is of width w and height h. Its upper left corner is
  1313. // positioned at point (x, y).
  1314. //
  1315. // Each color is specified with three component values, one each for red, green
  1316. // and blue. The values range from 0 to 255. The first color is specified by
  1317. // (r1, g1, b1) and the second color by (r2, g2, b2).
  1318. //
  1319. // The blending is controlled with a point and a circle, both specified with
  1320. // normalized coordinates in which the lower left corner of the rendered
  1321. // rectangle is position (0, 0) and the upper right corner is (1, 1). Color 1
  1322. // begins at the origin point specified by (x1, y1). Color 2 begins at the
  1323. // circle specified by the center point (x2, y2) and radius r. Colors are
  1324. // gradually blended from the origin to the circle. The origin and the circle's
  1325. // center do not necessarily have to coincide, but the origin must be within
  1326. // the circle to avoid rendering problems.
  1327. //
  1328. // The LinearGradient() example demonstrates this method.
  1329. func (f *Fpdf) RadialGradient(x, y, w, h float64, r1, g1, b1, r2, g2, b2 int, x1, y1, x2, y2, r float64) {
  1330. f.gradientClipStart(x, y, w, h)
  1331. f.gradient(3, r1, g1, b1, r2, g2, b2, x1, y1, x2, y2, r)
  1332. f.gradientClipEnd()
  1333. }
  1334. // ClipRect begins a rectangular clipping operation. The rectangle is of width
  1335. // w and height h. Its upper left corner is positioned at point (x, y). outline
  1336. // is true to draw a border with the current draw color and line width centered
  1337. // on the rectangle's perimeter. Only the outer half of the border will be
  1338. // shown. After calling this method, all rendering operations (for example,
  1339. // Image(), LinearGradient(), etc) will be clipped by the specified rectangle.
  1340. // Call ClipEnd() to restore unclipped operations.
  1341. //
  1342. // This ClipText() example demonstrates this method.
  1343. func (f *Fpdf) ClipRect(x, y, w, h float64, outline bool) {
  1344. f.clipNest++
  1345. f.outf("q %.2f %.2f %.2f %.2f re W %s", x*f.k, (f.h-y)*f.k, w*f.k, -h*f.k, strIf(outline, "S", "n"))
  1346. }
  1347. // ClipText begins a clipping operation in which rendering is confined to the
  1348. // character string specified by txtStr. The origin (x, y) is on the left of
  1349. // the first character at the baseline. The current font is used. outline is
  1350. // true to draw a border with the current draw color and line width centered on
  1351. // the perimeters of the text characters. Only the outer half of the border
  1352. // will be shown. After calling this method, all rendering operations (for
  1353. // example, Image(), LinearGradient(), etc) will be clipped. Call ClipEnd() to
  1354. // restore unclipped operations.
  1355. func (f *Fpdf) ClipText(x, y float64, txtStr string, outline bool) {
  1356. f.clipNest++
  1357. f.outf("q BT %.5f %.5f Td %d Tr (%s) Tj ET", x*f.k, (f.h-y)*f.k, intIf(outline, 5, 7), f.escape(txtStr))
  1358. }
  1359. func (f *Fpdf) clipArc(x1, y1, x2, y2, x3, y3 float64) {
  1360. h := f.h
  1361. f.outf("%.5f %.5f %.5f %.5f %.5f %.5f c ", x1*f.k, (h-y1)*f.k,
  1362. x2*f.k, (h-y2)*f.k, x3*f.k, (h-y3)*f.k)
  1363. }
  1364. // ClipRoundedRect begins a rectangular clipping operation. The rectangle is of
  1365. // width w and height h. Its upper left corner is positioned at point (x, y).
  1366. // The rounded corners of the rectangle are specified by radius r. outline is
  1367. // true to draw a border with the current draw color and line width centered on
  1368. // the rectangle's perimeter. Only the outer half of the border will be shown.
  1369. // After calling this method, all rendering operations (for example, Image(),
  1370. // LinearGradient(), etc) will be clipped by the specified rectangle. Call
  1371. // ClipEnd() to restore unclipped operations.
  1372. //
  1373. // This ClipText() example demonstrates this method.
  1374. func (f *Fpdf) ClipRoundedRect(x, y, w, h, r float64, outline bool) {
  1375. f.ClipRoundedRectExt(x, y, w, h, r, r, r, r, outline)
  1376. }
  1377. // ClipRoundedRectExt behaves the same as ClipRoundedRect() but supports a
  1378. // different radius for each corner, given by rTL (top-left), rTR (top-right)
  1379. // rBR (bottom-right), rBL (bottom-left). See ClipRoundedRect() for more
  1380. // details. This method is demonstrated in the ClipText() example.
  1381. func (f *Fpdf) ClipRoundedRectExt(x, y, w, h, rTL, rTR, rBR, rBL float64, outline bool) {
  1382. f.clipNest++
  1383. f.roundedRectPath(x, y, w, h, rTL, rTR, rBR, rBL)
  1384. f.outf(" W %s", strIf(outline, "S", "n"))
  1385. }
  1386. // add a rectangle path with rounded corners.
  1387. // routine shared by RoundedRect() and ClipRoundedRect(), which add the
  1388. // drawing operation
  1389. func (f *Fpdf) roundedRectPath(x, y, w, h, rTL, rTR, rBR, rBL float64) {
  1390. k := f.k
  1391. hp := f.h
  1392. myArc := (4.0 / 3.0) * (math.Sqrt2 - 1.0)
  1393. f.outf("q %.5f %.5f m", (x+rTL)*k, (hp-y)*k)
  1394. xc := x + w - rTR
  1395. yc := y + rTR
  1396. f.outf("%.5f %.5f l", xc*k, (hp-y)*k)
  1397. if rTR != 0 {
  1398. f.clipArc(xc+rTR*myArc, yc-rTR, xc+rTR, yc-rTR*myArc, xc+rTR, yc)
  1399. }
  1400. xc = x + w - rBR
  1401. yc = y + h - rBR
  1402. f.outf("%.5f %.5f l", (x+w)*k, (hp-yc)*k)
  1403. if rBR != 0 {
  1404. f.clipArc(xc+rBR, yc+rBR*myArc, xc+rBR*myArc, yc+rBR, xc, yc+rBR)
  1405. }
  1406. xc = x + rBL
  1407. yc = y + h - rBL
  1408. f.outf("%.5f %.5f l", xc*k, (hp-(y+h))*k)
  1409. if rBL != 0 {
  1410. f.clipArc(xc-rBL*myArc, yc+rBL, xc-rBL, yc+rBL*myArc, xc-rBL, yc)
  1411. }
  1412. xc = x + rTL
  1413. yc = y + rTL
  1414. f.outf("%.5f %.5f l", x*k, (hp-yc)*k)
  1415. if rTL != 0 {
  1416. f.clipArc(xc-rTL, yc-rTL*myArc, xc-rTL*myArc, yc-rTL, xc, yc-rTL)
  1417. }
  1418. }
  1419. // ClipEllipse begins an elliptical clipping operation. The ellipse is centered
  1420. // at (x, y). Its horizontal and vertical radii are specified by rx and ry.
  1421. // outline is true to draw a border with the current draw color and line width
  1422. // centered on the ellipse's perimeter. Only the outer half of the border will
  1423. // be shown. After calling this method, all rendering operations (for example,
  1424. // Image(), LinearGradient(), etc) will be clipped by the specified ellipse.
  1425. // Call ClipEnd() to restore unclipped operations.
  1426. //
  1427. // This ClipText() example demonstrates this method.
  1428. func (f *Fpdf) ClipEllipse(x, y, rx, ry float64, outline bool) {
  1429. f.clipNest++
  1430. lx := (4.0 / 3.0) * rx * (math.Sqrt2 - 1)
  1431. ly := (4.0 / 3.0) * ry * (math.Sqrt2 - 1)
  1432. k := f.k
  1433. h := f.h
  1434. f.outf("q %.5f %.5f m %.5f %.5f %.5f %.5f %.5f %.5f c",
  1435. (x+rx)*k, (h-y)*k,
  1436. (x+rx)*k, (h-(y-ly))*k,
  1437. (x+lx)*k, (h-(y-ry))*k,
  1438. x*k, (h-(y-ry))*k)
  1439. f.outf("%.5f %.5f %.5f %.5f %.5f %.5f c",
  1440. (x-lx)*k, (h-(y-ry))*k,
  1441. (x-rx)*k, (h-(y-ly))*k,
  1442. (x-rx)*k, (h-y)*k)
  1443. f.outf("%.5f %.5f %.5f %.5f %.5f %.5f c",
  1444. (x-rx)*k, (h-(y+ly))*k,
  1445. (x-lx)*k, (h-(y+ry))*k,
  1446. x*k, (h-(y+ry))*k)
  1447. f.outf("%.5f %.5f %.5f %.5f %.5f %.5f c W %s",
  1448. (x+lx)*k, (h-(y+ry))*k,
  1449. (x+rx)*k, (h-(y+ly))*k,
  1450. (x+rx)*k, (h-y)*k,
  1451. strIf(outline, "S", "n"))
  1452. }
  1453. // ClipCircle begins a circular clipping operation. The circle is centered at
  1454. // (x, y) and has radius r. outline is true to draw a border with the current
  1455. // draw color and line width centered on the circle's perimeter. Only the outer
  1456. // half of the border will be shown. After calling this method, all rendering
  1457. // operations (for example, Image(), LinearGradient(), etc) will be clipped by
  1458. // the specified circle. Call ClipEnd() to restore unclipped operations.
  1459. //
  1460. // The ClipText() example demonstrates this method.
  1461. func (f *Fpdf) ClipCircle(x, y, r float64, outline bool) {
  1462. f.ClipEllipse(x, y, r, r, outline)
  1463. }
  1464. // ClipPolygon begins a clipping operation within a polygon. The figure is
  1465. // defined by a series of vertices specified by points. The x and y fields of
  1466. // the points use the units established in New(). The last point in the slice
  1467. // will be implicitly joined to the first to close the polygon. outline is true
  1468. // to draw a border with the current draw color and line width centered on the
  1469. // polygon's perimeter. Only the outer half of the border will be shown. After
  1470. // calling this method, all rendering operations (for example, Image(),
  1471. // LinearGradient(), etc) will be clipped by the specified polygon. Call
  1472. // ClipEnd() to restore unclipped operations.
  1473. //
  1474. // The ClipText() example demonstrates this method.
  1475. func (f *Fpdf) ClipPolygon(points []PointType, outline bool) {
  1476. f.clipNest++
  1477. var s fmtBuffer
  1478. h := f.h
  1479. k := f.k
  1480. s.printf("q ")
  1481. for j, pt := range points {
  1482. s.printf("%.5f %.5f %s ", pt.X*k, (h-pt.Y)*k, strIf(j == 0, "m", "l"))
  1483. }
  1484. s.printf("h W %s", strIf(outline, "S", "n"))
  1485. f.out(s.String())
  1486. }
  1487. // ClipEnd ends a clipping operation that was started with a call to
  1488. // ClipRect(), ClipRoundedRect(), ClipText(), ClipEllipse(), ClipCircle() or
  1489. // ClipPolygon(). Clipping operations can be nested. The document cannot be
  1490. // successfully output while a clipping operation is active.
  1491. //
  1492. // The ClipText() example demonstrates this method.
  1493. func (f *Fpdf) ClipEnd() {
  1494. if f.err == nil {
  1495. if f.clipNest > 0 {
  1496. f.clipNest--
  1497. f.out("Q")
  1498. } else {
  1499. f.err = fmt.Errorf("error attempting to end clip operation out of sequence")
  1500. }
  1501. }
  1502. }
  1503. // AddFont imports a TrueType, OpenType or Type1 font and makes it available.
  1504. // It is necessary to generate a font definition file first with the makefont
  1505. // utility. It is not necessary to call this function for the core PDF fonts
  1506. // (courier, helvetica, times, zapfdingbats).
  1507. //
  1508. // The JSON definition file (and the font file itself when embedding) must be
  1509. // present in the font directory. If it is not found, the error "Could not
  1510. // include font definition file" is set.
  1511. //
  1512. // family specifies the font family. The name can be chosen arbitrarily. If it
  1513. // is a standard family name, it will override the corresponding font. This
  1514. // string is used to subsequently set the font with the SetFont method.
  1515. //
  1516. // style specifies the font style. Acceptable values are (case insensitive) the
  1517. // empty string for regular style, "B" for bold, "I" for italic, or "BI" or
  1518. // "IB" for bold and italic combined.
  1519. //
  1520. // fileStr specifies the base name with ".json" extension of the font
  1521. // definition file to be added. The file will be loaded from the font directory
  1522. // specified in the call to New() or SetFontLocation().
  1523. func (f *Fpdf) AddFont(familyStr, styleStr, fileStr string) {
  1524. f.addFont(fontFamilyEscape(familyStr), styleStr, fileStr, false)
  1525. }
  1526. // AddUTF8Font imports a TrueType font with utf-8 symbols and makes it available.
  1527. // It is necessary to generate a font definition file first with the makefont
  1528. // utility. It is not necessary to call this function for the core PDF fonts
  1529. // (courier, helvetica, times, zapfdingbats).
  1530. //
  1531. // The JSON definition file (and the font file itself when embedding) must be
  1532. // present in the font directory. If it is not found, the error "Could not
  1533. // include font definition file" is set.
  1534. //
  1535. // family specifies the font family. The name can be chosen arbitrarily. If it
  1536. // is a standard family name, it will override the corresponding font. This
  1537. // string is used to subsequently set the font with the SetFont method.
  1538. //
  1539. // style specifies the font style. Acceptable values are (case insensitive) the
  1540. // empty string for regular style, "B" for bold, "I" for italic, or "BI" or
  1541. // "IB" for bold and italic combined.
  1542. //
  1543. // fileStr specifies the base name with ".json" extension of the font
  1544. // definition file to be added. The file will be loaded from the font directory
  1545. // specified in the call to New() or SetFontLocation().
  1546. func (f *Fpdf) AddUTF8Font(familyStr, styleStr, fileStr string) {
  1547. f.addFont(fontFamilyEscape(familyStr), styleStr, fileStr, true)
  1548. }
  1549. func (f *Fpdf) addFont(familyStr, styleStr, fileStr string, isUTF8 bool) {
  1550. if fileStr == "" {
  1551. if isUTF8 {
  1552. fileStr = strings.Replace(familyStr, " ", "", -1) + strings.ToLower(styleStr) + ".ttf"
  1553. } else {
  1554. fileStr = strings.Replace(familyStr, " ", "", -1) + strings.ToLower(styleStr) + ".json"
  1555. }
  1556. }
  1557. if isUTF8 {
  1558. fontKey := getFontKey(familyStr, styleStr)
  1559. _, ok := f.fonts[fontKey]
  1560. if ok {
  1561. return
  1562. }
  1563. var ttfStat os.FileInfo
  1564. var err error
  1565. fileStr = path.Join(f.fontpath, fileStr)
  1566. ttfStat, err = os.Stat(fileStr)
  1567. if err != nil {
  1568. f.SetError(err)
  1569. return
  1570. }
  1571. originalSize := ttfStat.Size()
  1572. Type := "UTF8"
  1573. var utf8Bytes []byte
  1574. utf8Bytes, err = ioutil.ReadFile(fileStr)
  1575. if err != nil {
  1576. f.SetError(err)
  1577. return
  1578. }
  1579. reader := fileReader{readerPosition: 0, array: utf8Bytes}
  1580. utf8File := newUTF8Font(&reader)
  1581. err = utf8File.parseFile()
  1582. if err != nil {
  1583. f.SetError(err)
  1584. return
  1585. }
  1586. desc := FontDescType{
  1587. Ascent: int(utf8File.Ascent),
  1588. Descent: int(utf8File.Descent),
  1589. CapHeight: utf8File.CapHeight,
  1590. Flags: utf8File.Flags,
  1591. FontBBox: utf8File.Bbox,
  1592. ItalicAngle: utf8File.ItalicAngle,
  1593. StemV: utf8File.StemV,
  1594. MissingWidth: round(utf8File.DefaultWidth),
  1595. }
  1596. var sbarr map[int]int
  1597. if f.aliasNbPagesStr == "" {
  1598. sbarr = makeSubsetRange(57)
  1599. } else {
  1600. sbarr = makeSubsetRange(32)
  1601. }
  1602. def := fontDefType{
  1603. Tp: Type,
  1604. Name: fontKey,
  1605. Desc: desc,
  1606. Up: int(round(utf8File.UnderlinePosition)),
  1607. Ut: round(utf8File.UnderlineThickness),
  1608. Cw: utf8File.CharWidths,
  1609. usedRunes: sbarr,
  1610. File: fileStr,
  1611. utf8File: utf8File,
  1612. }
  1613. def.i, _ = generateFontID(def)
  1614. f.fonts[fontKey] = def
  1615. f.fontFiles[fontKey] = fontFileType{
  1616. length1: originalSize,
  1617. fontType: "UTF8",
  1618. }
  1619. f.fontFiles[fileStr] = fontFileType{
  1620. fontType: "UTF8",
  1621. }
  1622. } else {
  1623. if f.fontLoader != nil {
  1624. reader, err := f.fontLoader.Open(fileStr)
  1625. if err == nil {
  1626. f.AddFontFromReader(familyStr, styleStr, reader)
  1627. if closer, ok := reader.(io.Closer); ok {
  1628. closer.Close()
  1629. }
  1630. return
  1631. }
  1632. }
  1633. fileStr = path.Join(f.fontpath, fileStr)
  1634. file, err := os.Open(fileStr)
  1635. if err != nil {
  1636. f.err = err
  1637. return
  1638. }
  1639. defer file.Close()
  1640. f.AddFontFromReader(familyStr, styleStr, file)
  1641. }
  1642. }
  1643. func makeSubsetRange(end int) map[int]int {
  1644. answer := make(map[int]int)
  1645. for i := 0; i < end; i++ {
  1646. answer[i] = 0
  1647. }
  1648. return answer
  1649. }
  1650. // AddFontFromBytes imports a TrueType, OpenType or Type1 font from static
  1651. // bytes within the executable and makes it available for use in the generated
  1652. // document.
  1653. //
  1654. // family specifies the font family. The name can be chosen arbitrarily. If it
  1655. // is a standard family name, it will override the corresponding font. This
  1656. // string is used to subsequently set the font with the SetFont method.
  1657. //
  1658. // style specifies the font style. Acceptable values are (case insensitive) the
  1659. // empty string for regular style, "B" for bold, "I" for italic, or "BI" or
  1660. // "IB" for bold and italic combined.
  1661. //
  1662. // jsonFileBytes contain all bytes of JSON file.
  1663. //
  1664. // zFileBytes contain all bytes of Z file.
  1665. func (f *Fpdf) AddFontFromBytes(familyStr, styleStr string, jsonFileBytes, zFileBytes []byte) {
  1666. f.addFontFromBytes(fontFamilyEscape(familyStr), styleStr, jsonFileBytes, zFileBytes, nil)
  1667. }
  1668. // AddUTF8FontFromBytes imports a TrueType font with utf-8 symbols from static
  1669. // bytes within the executable and makes it available for use in the generated
  1670. // document.
  1671. //
  1672. // family specifies the font family. The name can be chosen arbitrarily. If it
  1673. // is a standard family name, it will override the corresponding font. This
  1674. // string is used to subsequently set the font with the SetFont method.
  1675. //
  1676. // style specifies the font style. Acceptable values are (case insensitive) the
  1677. // empty string for regular style, "B" for bold, "I" for italic, or "BI" or
  1678. // "IB" for bold and italic combined.
  1679. //
  1680. // jsonFileBytes contain all bytes of JSON file.
  1681. //
  1682. // zFileBytes contain all bytes of Z file.
  1683. func (f *Fpdf) AddUTF8FontFromBytes(familyStr, styleStr string, utf8Bytes []byte) {
  1684. f.addFontFromBytes(fontFamilyEscape(familyStr), styleStr, nil, nil, utf8Bytes)
  1685. }
  1686. func (f *Fpdf) addFontFromBytes(familyStr, styleStr string, jsonFileBytes, zFileBytes, utf8Bytes []byte) {
  1687. if f.err != nil {
  1688. return
  1689. }
  1690. // load font key
  1691. var ok bool
  1692. fontkey := getFontKey(familyStr, styleStr)
  1693. _, ok = f.fonts[fontkey]
  1694. if ok {
  1695. return
  1696. }
  1697. if utf8Bytes != nil {
  1698. // if styleStr == "IB" {
  1699. // styleStr = "BI"
  1700. // }
  1701. Type := "UTF8"
  1702. reader := fileReader{readerPosition: 0, array: utf8Bytes}
  1703. utf8File := newUTF8Font(&reader)
  1704. err := utf8File.parseFile()
  1705. if err != nil {
  1706. fmt.Printf("get metrics Error: %e\n", err)
  1707. return
  1708. }
  1709. desc := FontDescType{
  1710. Ascent: int(utf8File.Ascent),
  1711. Descent: int(utf8File.Descent),
  1712. CapHeight: utf8File.CapHeight,
  1713. Flags: utf8File.Flags,
  1714. FontBBox: utf8File.Bbox,
  1715. ItalicAngle: utf8File.ItalicAngle,
  1716. StemV: utf8File.StemV,
  1717. MissingWidth: round(utf8File.DefaultWidth),
  1718. }
  1719. var sbarr map[int]int
  1720. if f.aliasNbPagesStr == "" {
  1721. sbarr = makeSubsetRange(57)
  1722. } else {
  1723. sbarr = makeSubsetRange(32)
  1724. }
  1725. def := fontDefType{
  1726. Tp: Type,
  1727. Name: fontkey,
  1728. Desc: desc,
  1729. Up: int(round(utf8File.UnderlinePosition)),
  1730. Ut: round(utf8File.UnderlineThickness),
  1731. Cw: utf8File.CharWidths,
  1732. utf8File: utf8File,
  1733. usedRunes: sbarr,
  1734. }
  1735. def.i, _ = generateFontID(def)
  1736. f.fonts[fontkey] = def
  1737. } else {
  1738. // load font definitions
  1739. var info fontDefType
  1740. err := json.Unmarshal(jsonFileBytes, &info)
  1741. if err != nil {
  1742. f.err = err
  1743. }
  1744. if f.err != nil {
  1745. return
  1746. }
  1747. if info.i, err = generateFontID(info); err != nil {
  1748. f.err = err
  1749. return
  1750. }
  1751. // search existing encodings
  1752. if len(info.Diff) > 0 {
  1753. n := -1
  1754. for j, str := range f.diffs {
  1755. if str == info.Diff {
  1756. n = j + 1
  1757. break
  1758. }
  1759. }
  1760. if n < 0 {
  1761. f.diffs = append(f.diffs, info.Diff)
  1762. n = len(f.diffs)
  1763. }
  1764. info.DiffN = n
  1765. }
  1766. // embed font
  1767. if len(info.File) > 0 {
  1768. if info.Tp == "TrueType" {
  1769. f.fontFiles[info.File] = fontFileType{
  1770. length1: int64(info.OriginalSize),
  1771. embedded: true,
  1772. content: zFileBytes,
  1773. }
  1774. } else {
  1775. f.fontFiles[info.File] = fontFileType{
  1776. length1: int64(info.Size1),
  1777. length2: int64(info.Size2),
  1778. embedded: true,
  1779. content: zFileBytes,
  1780. }
  1781. }
  1782. }
  1783. f.fonts[fontkey] = info
  1784. }
  1785. }
  1786. // getFontKey is used by AddFontFromReader and GetFontDesc
  1787. func getFontKey(familyStr, styleStr string) string {
  1788. familyStr = strings.ToLower(familyStr)
  1789. styleStr = strings.ToUpper(styleStr)
  1790. if styleStr == "IB" {
  1791. styleStr = "BI"
  1792. }
  1793. return familyStr + styleStr
  1794. }
  1795. // AddFontFromReader imports a TrueType, OpenType or Type1 font and makes it
  1796. // available using a reader that satisifies the io.Reader interface. See
  1797. // AddFont for details about familyStr and styleStr.
  1798. func (f *Fpdf) AddFontFromReader(familyStr, styleStr string, r io.Reader) {
  1799. if f.err != nil {
  1800. return
  1801. }
  1802. // dbg("Adding family [%s], style [%s]", familyStr, styleStr)
  1803. familyStr = fontFamilyEscape(familyStr)
  1804. var ok bool
  1805. fontkey := getFontKey(familyStr, styleStr)
  1806. _, ok = f.fonts[fontkey]
  1807. if ok {
  1808. return
  1809. }
  1810. var info fontDefType
  1811. info = f.loadfont(r)
  1812. if f.err != nil {
  1813. return
  1814. }
  1815. if len(info.Diff) > 0 {
  1816. // Search existing encodings
  1817. n := -1
  1818. for j, str := range f.diffs {
  1819. if str == info.Diff {
  1820. n = j + 1
  1821. break
  1822. }
  1823. }
  1824. if n < 0 {
  1825. f.diffs = append(f.diffs, info.Diff)
  1826. n = len(f.diffs)
  1827. }
  1828. info.DiffN = n
  1829. }
  1830. // dbg("font [%s], type [%s]", info.File, info.Tp)
  1831. if len(info.File) > 0 {
  1832. // Embedded font
  1833. if info.Tp == "TrueType" {
  1834. f.fontFiles[info.File] = fontFileType{length1: int64(info.OriginalSize)}
  1835. } else {
  1836. f.fontFiles[info.File] = fontFileType{length1: int64(info.Size1), length2: int64(info.Size2)}
  1837. }
  1838. }
  1839. f.fonts[fontkey] = info
  1840. return
  1841. }
  1842. // GetFontDesc returns the font descriptor, which can be used for
  1843. // example to find the baseline of a font. If familyStr is empty
  1844. // current font descriptor will be returned.
  1845. // See FontDescType for documentation about the font descriptor.
  1846. // See AddFont for details about familyStr and styleStr.
  1847. func (f *Fpdf) GetFontDesc(familyStr, styleStr string) FontDescType {
  1848. if familyStr == "" {
  1849. return f.currentFont.Desc
  1850. }
  1851. return f.fonts[getFontKey(fontFamilyEscape(familyStr), styleStr)].Desc
  1852. }
  1853. // SetFont sets the font used to print character strings. It is mandatory to
  1854. // call this method at least once before printing text or the resulting
  1855. // document will not be valid.
  1856. //
  1857. // The font can be either a standard one or a font added via the AddFont()
  1858. // method or AddFontFromReader() method. Standard fonts use the Windows
  1859. // encoding cp1252 (Western Europe).
  1860. //
  1861. // The method can be called before the first page is created and the font is
  1862. // kept from page to page. If you just wish to change the current font size, it
  1863. // is simpler to call SetFontSize().
  1864. //
  1865. // Note: the font definition file must be accessible. An error is set if the
  1866. // file cannot be read.
  1867. //
  1868. // familyStr specifies the font family. It can be either a name defined by
  1869. // AddFont(), AddFontFromReader() or one of the standard families (case
  1870. // insensitive): "Courier" for fixed-width, "Helvetica" or "Arial" for sans
  1871. // serif, "Times" for serif, "Symbol" or "ZapfDingbats" for symbolic.
  1872. //
  1873. // styleStr can be "B" (bold), "I" (italic), "U" (underscore), "S" (strike-out)
  1874. // or any combination. The default value (specified with an empty string) is
  1875. // regular. Bold and italic styles do not apply to Symbol and ZapfDingbats.
  1876. //
  1877. // size is the font size measured in points. The default value is the current
  1878. // size. If no size has been specified since the beginning of the document, the
  1879. // value taken is 12.
  1880. func (f *Fpdf) SetFont(familyStr, styleStr string, size float64) {
  1881. // dbg("SetFont x %.2f, lMargin %.2f", f.x, f.lMargin)
  1882. if f.err != nil {
  1883. return
  1884. }
  1885. // dbg("SetFont")
  1886. familyStr = fontFamilyEscape(familyStr)
  1887. var ok bool
  1888. if familyStr == "" {
  1889. familyStr = f.fontFamily
  1890. } else {
  1891. familyStr = strings.ToLower(familyStr)
  1892. }
  1893. styleStr = strings.ToUpper(styleStr)
  1894. f.underline = strings.Contains(styleStr, "U")
  1895. if f.underline {
  1896. styleStr = strings.Replace(styleStr, "U", "", -1)
  1897. }
  1898. f.strikeout = strings.Contains(styleStr, "S")
  1899. if f.strikeout {
  1900. styleStr = strings.Replace(styleStr, "S", "", -1)
  1901. }
  1902. if styleStr == "IB" {
  1903. styleStr = "BI"
  1904. }
  1905. if size == 0.0 {
  1906. size = f.fontSizePt
  1907. }
  1908. // Test if font is already loaded
  1909. fontKey := familyStr + styleStr
  1910. _, ok = f.fonts[fontKey]
  1911. if !ok {
  1912. // Test if one of the core fonts
  1913. if familyStr == "arial" {
  1914. familyStr = "helvetica"
  1915. }
  1916. _, ok = f.coreFonts[familyStr]
  1917. if ok {
  1918. if familyStr == "symbol" {
  1919. familyStr = "zapfdingbats"
  1920. }
  1921. if familyStr == "zapfdingbats" {
  1922. styleStr = ""
  1923. }
  1924. fontKey = familyStr + styleStr
  1925. _, ok = f.fonts[fontKey]
  1926. if !ok {
  1927. rdr := f.coreFontReader(familyStr, styleStr)
  1928. if f.err == nil {
  1929. f.AddFontFromReader(familyStr, styleStr, rdr)
  1930. }
  1931. if f.err != nil {
  1932. return
  1933. }
  1934. }
  1935. } else {
  1936. f.err = fmt.Errorf("undefined font: %s %s", familyStr, styleStr)
  1937. return
  1938. }
  1939. }
  1940. // Select it
  1941. f.fontFamily = familyStr
  1942. f.fontStyle = styleStr
  1943. f.fontSizePt = size
  1944. f.fontSize = size / f.k
  1945. f.currentFont = f.fonts[fontKey]
  1946. if f.currentFont.Tp == "UTF8" {
  1947. f.isCurrentUTF8 = true
  1948. } else {
  1949. f.isCurrentUTF8 = false
  1950. }
  1951. if f.page > 0 {
  1952. f.outf("BT /F%s %.2f Tf ET", f.currentFont.i, f.fontSizePt)
  1953. }
  1954. return
  1955. }
  1956. // SetFontStyle sets the style of the current font. See also SetFont()
  1957. func (f *Fpdf) SetFontStyle(styleStr string) {
  1958. f.SetFont(f.fontFamily, styleStr, f.fontSizePt)
  1959. }
  1960. // SetFontSize defines the size of the current font. Size is specified in
  1961. // points (1/ 72 inch). See also SetFontUnitSize().
  1962. func (f *Fpdf) SetFontSize(size float64) {
  1963. f.fontSizePt = size
  1964. f.fontSize = size / f.k
  1965. if f.page > 0 {
  1966. f.outf("BT /F%s %.2f Tf ET", f.currentFont.i, f.fontSizePt)
  1967. }
  1968. }
  1969. // SetFontUnitSize defines the size of the current font. Size is specified in
  1970. // the unit of measure specified in New(). See also SetFontSize().
  1971. func (f *Fpdf) SetFontUnitSize(size float64) {
  1972. f.fontSizePt = size * f.k
  1973. f.fontSize = size
  1974. if f.page > 0 {
  1975. f.outf("BT /F%s %.2f Tf ET", f.currentFont.i, f.fontSizePt)
  1976. }
  1977. }
  1978. // GetFontSize returns the size of the current font in points followed by the
  1979. // size in the unit of measure specified in New(). The second value can be used
  1980. // as a line height value in drawing operations.
  1981. func (f *Fpdf) GetFontSize() (ptSize, unitSize float64) {
  1982. return f.fontSizePt, f.fontSize
  1983. }
  1984. // AddLink creates a new internal link and returns its identifier. An internal
  1985. // link is a clickable area which directs to another place within the document.
  1986. // The identifier can then be passed to Cell(), Write(), Image() or Link(). The
  1987. // destination is defined with SetLink().
  1988. func (f *Fpdf) AddLink() int {
  1989. f.links = append(f.links, intLinkType{})
  1990. return len(f.links) - 1
  1991. }
  1992. // SetLink defines the page and position a link points to. See AddLink().
  1993. func (f *Fpdf) SetLink(link int, y float64, page int) {
  1994. if y == -1 {
  1995. y = f.y
  1996. }
  1997. if page == -1 {
  1998. page = f.page
  1999. }
  2000. f.links[link] = intLinkType{page, y}
  2001. }
  2002. // newLink adds a new clickable link on current page
  2003. func (f *Fpdf) newLink(x, y, w, h float64, link int, linkStr string) {
  2004. // linkList, ok := f.pageLinks[f.page]
  2005. // if !ok {
  2006. // linkList = make([]linkType, 0, 8)
  2007. // f.pageLinks[f.page] = linkList
  2008. // }
  2009. f.pageLinks[f.page] = append(f.pageLinks[f.page],
  2010. linkType{x * f.k, f.hPt - y*f.k, w * f.k, h * f.k, link, linkStr})
  2011. }
  2012. // Link puts a link on a rectangular area of the page. Text or image links are
  2013. // generally put via Cell(), Write() or Image(), but this method can be useful
  2014. // for instance to define a clickable area inside an image. link is the value
  2015. // returned by AddLink().
  2016. func (f *Fpdf) Link(x, y, w, h float64, link int) {
  2017. f.newLink(x, y, w, h, link, "")
  2018. }
  2019. // LinkString puts a link on a rectangular area of the page. Text or image
  2020. // links are generally put via Cell(), Write() or Image(), but this method can
  2021. // be useful for instance to define a clickable area inside an image. linkStr
  2022. // is the target URL.
  2023. func (f *Fpdf) LinkString(x, y, w, h float64, linkStr string) {
  2024. f.newLink(x, y, w, h, 0, linkStr)
  2025. }
  2026. // Bookmark sets a bookmark that will be displayed in a sidebar outline. txtStr
  2027. // is the title of the bookmark. level specifies the level of the bookmark in
  2028. // the outline; 0 is the top level, 1 is just below, and so on. y specifies the
  2029. // vertical position of the bookmark destination in the current page; -1
  2030. // indicates the current position.
  2031. func (f *Fpdf) Bookmark(txtStr string, level int, y float64) {
  2032. if y == -1 {
  2033. y = f.y
  2034. }
  2035. if f.isCurrentUTF8 {
  2036. txtStr = utf8toutf16(txtStr)
  2037. }
  2038. f.outlines = append(f.outlines, outlineType{text: txtStr, level: level, y: y, p: f.PageNo(), prev: -1, last: -1, next: -1, first: -1})
  2039. }
  2040. // Text prints a character string. The origin (x, y) is on the left of the
  2041. // first character at the baseline. This method permits a string to be placed
  2042. // precisely on the page, but it is usually easier to use Cell(), MultiCell()
  2043. // or Write() which are the standard methods to print text.
  2044. func (f *Fpdf) Text(x, y float64, txtStr string) {
  2045. var txt2 string
  2046. if f.isCurrentUTF8 {
  2047. if f.isRTL {
  2048. txtStr = reverseText(txtStr)
  2049. x -= f.GetStringWidth(txtStr)
  2050. }
  2051. txt2 = f.escape(utf8toutf16(txtStr, false))
  2052. for _, uni := range []rune(txtStr) {
  2053. f.currentFont.usedRunes[int(uni)] = int(uni)
  2054. }
  2055. } else {
  2056. txt2 = f.escape(txtStr)
  2057. }
  2058. s := sprintf("BT %.2f %.2f Td (%s) Tj ET", x*f.k, (f.h-y)*f.k, txt2)
  2059. if f.underline && txtStr != "" {
  2060. s += " " + f.dounderline(x, y, txtStr)
  2061. }
  2062. if f.strikeout && txtStr != "" {
  2063. s += " " + f.dostrikeout(x, y, txtStr)
  2064. }
  2065. if f.colorFlag {
  2066. s = sprintf("q %s %s Q", f.color.text.str, s)
  2067. }
  2068. f.out(s)
  2069. }
  2070. // SetWordSpacing sets spacing between words of following text. See the
  2071. // WriteAligned() example for a demonstration of its use.
  2072. func (f *Fpdf) SetWordSpacing(space float64) {
  2073. f.out(sprintf("%.5f Tw", space*f.k))
  2074. }
  2075. // SetTextRenderingMode sets the rendering mode of following text.
  2076. // The mode can be as follows:
  2077. // 0: Fill text
  2078. // 1: Stroke text
  2079. // 2: Fill, then stroke text
  2080. // 3: Neither fill nor stroke text (invisible)
  2081. // 4: Fill text and add to path for clipping
  2082. // 5: Stroke text and add to path for clipping
  2083. // 6: Fills then stroke text and add to path for clipping
  2084. // 7: Add text to path for clipping
  2085. // This method is demonstrated in the SetTextRenderingMode example.
  2086. func (f *Fpdf) SetTextRenderingMode(mode int) {
  2087. if mode >= 0 && mode <= 7 {
  2088. f.out(sprintf("%d Tr", mode))
  2089. }
  2090. }
  2091. // SetAcceptPageBreakFunc allows the application to control where page breaks
  2092. // occur.
  2093. //
  2094. // fnc is an application function (typically a closure) that is called by the
  2095. // library whenever a page break condition is met. The break is issued if true
  2096. // is returned. The default implementation returns a value according to the
  2097. // mode selected by SetAutoPageBreak. The function provided should not be
  2098. // called by the application.
  2099. //
  2100. // See the example for SetLeftMargin() to see how this function can be used to
  2101. // manage multiple columns.
  2102. func (f *Fpdf) SetAcceptPageBreakFunc(fnc func() bool) {
  2103. f.acceptPageBreak = fnc
  2104. }
  2105. // CellFormat prints a rectangular cell with optional borders, background color
  2106. // and character string. The upper-left corner of the cell corresponds to the
  2107. // current position. The text can be aligned or centered. After the call, the
  2108. // current position moves to the right or to the next line. It is possible to
  2109. // put a link on the text.
  2110. //
  2111. // An error will be returned if a call to SetFont() has not already taken
  2112. // place before this method is called.
  2113. //
  2114. // If automatic page breaking is enabled and the cell goes beyond the limit, a
  2115. // page break is done before outputting.
  2116. //
  2117. // w and h specify the width and height of the cell. If w is 0, the cell
  2118. // extends up to the right margin. Specifying 0 for h will result in no output,
  2119. // but the current position will be advanced by w.
  2120. //
  2121. // txtStr specifies the text to display.
  2122. //
  2123. // borderStr specifies how the cell border will be drawn. An empty string
  2124. // indicates no border, "1" indicates a full border, and one or more of "L",
  2125. // "T", "R" and "B" indicate the left, top, right and bottom sides of the
  2126. // border.
  2127. //
  2128. // ln indicates where the current position should go after the call. Possible
  2129. // values are 0 (to the right), 1 (to the beginning of the next line), and 2
  2130. // (below). Putting 1 is equivalent to putting 0 and calling Ln() just after.
  2131. //
  2132. // alignStr specifies how the text is to be positioned within the cell.
  2133. // Horizontal alignment is controlled by including "L", "C" or "R" (left,
  2134. // center, right) in alignStr. Vertical alignment is controlled by including
  2135. // "T", "M", "B" or "A" (top, middle, bottom, baseline) in alignStr. The default
  2136. // alignment is left middle.
  2137. //
  2138. // fill is true to paint the cell background or false to leave it transparent.
  2139. //
  2140. // link is the identifier returned by AddLink() or 0 for no internal link.
  2141. //
  2142. // linkStr is a target URL or empty for no external link. A non--zero value for
  2143. // link takes precedence over linkStr.
  2144. func (f *Fpdf) CellFormat(w, h float64, txtStr, borderStr string, ln int,
  2145. alignStr string, fill bool, link int, linkStr string) {
  2146. // dbg("CellFormat. h = %.2f, borderStr = %s", h, borderStr)
  2147. if f.err != nil {
  2148. return
  2149. }
  2150. if f.currentFont.Name == "" {
  2151. f.err = fmt.Errorf("font has not been set; unable to render text")
  2152. return
  2153. }
  2154. borderStr = strings.ToUpper(borderStr)
  2155. k := f.k
  2156. if f.y+h > f.pageBreakTrigger && !f.inHeader && !f.inFooter && f.acceptPageBreak() {
  2157. // Automatic page break
  2158. x := f.x
  2159. ws := f.ws
  2160. // dbg("auto page break, x %.2f, ws %.2f", x, ws)
  2161. if ws > 0 {
  2162. f.ws = 0
  2163. f.out("0 Tw")
  2164. }
  2165. f.AddPageFormat(f.curOrientation, f.curPageSize)
  2166. if f.err != nil {
  2167. return
  2168. }
  2169. f.x = x
  2170. if ws > 0 {
  2171. f.ws = ws
  2172. f.outf("%.3f Tw", ws*k)
  2173. }
  2174. }
  2175. if w == 0 {
  2176. w = f.w - f.rMargin - f.x
  2177. }
  2178. var s fmtBuffer
  2179. if fill || borderStr == "1" {
  2180. var op string
  2181. if fill {
  2182. if borderStr == "1" {
  2183. op = "B"
  2184. // dbg("border is '1', fill")
  2185. } else {
  2186. op = "f"
  2187. // dbg("border is empty, fill")
  2188. }
  2189. } else {
  2190. // dbg("border is '1', no fill")
  2191. op = "S"
  2192. }
  2193. /// dbg("(CellFormat) f.x %.2f f.k %.2f", f.x, f.k)
  2194. s.printf("%.2f %.2f %.2f %.2f re %s ", f.x*k, (f.h-f.y)*k, w*k, -h*k, op)
  2195. }
  2196. if len(borderStr) > 0 && borderStr != "1" {
  2197. // fmt.Printf("border is '%s', no fill\n", borderStr)
  2198. x := f.x
  2199. y := f.y
  2200. left := x * k
  2201. top := (f.h - y) * k
  2202. right := (x + w) * k
  2203. bottom := (f.h - (y + h)) * k
  2204. if strings.Contains(borderStr, "L") {
  2205. s.printf("%.2f %.2f m %.2f %.2f l S ", left, top, left, bottom)
  2206. }
  2207. if strings.Contains(borderStr, "T") {
  2208. s.printf("%.2f %.2f m %.2f %.2f l S ", left, top, right, top)
  2209. }
  2210. if strings.Contains(borderStr, "R") {
  2211. s.printf("%.2f %.2f m %.2f %.2f l S ", right, top, right, bottom)
  2212. }
  2213. if strings.Contains(borderStr, "B") {
  2214. s.printf("%.2f %.2f m %.2f %.2f l S ", left, bottom, right, bottom)
  2215. }
  2216. }
  2217. if len(txtStr) > 0 {
  2218. var dx, dy float64
  2219. // Horizontal alignment
  2220. switch {
  2221. case strings.Contains(alignStr, "R"):
  2222. dx = w - f.cMargin - f.GetStringWidth(txtStr)
  2223. case strings.Contains(alignStr, "C"):
  2224. dx = (w - f.GetStringWidth(txtStr)) / 2
  2225. default:
  2226. dx = f.cMargin
  2227. }
  2228. // Vertical alignment
  2229. switch {
  2230. case strings.Contains(alignStr, "T"):
  2231. dy = (f.fontSize - h) / 2.0
  2232. case strings.Contains(alignStr, "B"):
  2233. dy = (h - f.fontSize) / 2.0
  2234. case strings.Contains(alignStr, "A"):
  2235. var descent float64
  2236. d := f.currentFont.Desc
  2237. if d.Descent == 0 {
  2238. // not defined (standard font?), use average of 19%
  2239. descent = -0.19 * f.fontSize
  2240. } else {
  2241. descent = float64(d.Descent) * f.fontSize / float64(d.Ascent-d.Descent)
  2242. }
  2243. dy = (h-f.fontSize)/2.0 - descent
  2244. default:
  2245. dy = 0
  2246. }
  2247. if f.colorFlag {
  2248. s.printf("q %s ", f.color.text.str)
  2249. }
  2250. //If multibyte, Tw has no effect - do word spacing using an adjustment before each space
  2251. if (f.ws != 0 || alignStr == "J") && f.isCurrentUTF8 { // && f.ws != 0
  2252. if f.isRTL {
  2253. txtStr = reverseText(txtStr)
  2254. }
  2255. wmax := int(math.Ceil((w - 2*f.cMargin) * 1000 / f.fontSize))
  2256. for _, uni := range []rune(txtStr) {
  2257. f.currentFont.usedRunes[int(uni)] = int(uni)
  2258. }
  2259. space := f.escape(utf8toutf16(" ", false))
  2260. strSize := f.GetStringSymbolWidth(txtStr)
  2261. s.printf("BT 0 Tw %.2f %.2f Td [", (f.x+dx)*k, (f.h-(f.y+.5*h+.3*f.fontSize))*k)
  2262. t := strings.Split(txtStr, " ")
  2263. shift := float64((wmax - strSize)) / float64(len(t)-1)
  2264. numt := len(t)
  2265. for i := 0; i < numt; i++ {
  2266. tx := t[i]
  2267. tx = "(" + f.escape(utf8toutf16(tx, false)) + ")"
  2268. s.printf("%s ", tx)
  2269. if (i + 1) < numt {
  2270. s.printf("%.3f(%s) ", -shift, space)
  2271. }
  2272. }
  2273. s.printf("] TJ ET")
  2274. } else {
  2275. var txt2 string
  2276. if f.isCurrentUTF8 {
  2277. if f.isRTL {
  2278. txtStr = reverseText(txtStr)
  2279. }
  2280. txt2 = f.escape(utf8toutf16(txtStr, false))
  2281. for _, uni := range []rune(txtStr) {
  2282. f.currentFont.usedRunes[int(uni)] = int(uni)
  2283. }
  2284. } else {
  2285. txt2 = strings.Replace(txtStr, "\\", "\\\\", -1)
  2286. txt2 = strings.Replace(txt2, "(", "\\(", -1)
  2287. txt2 = strings.Replace(txt2, ")", "\\)", -1)
  2288. }
  2289. bt := (f.x + dx) * k
  2290. td := (f.h - (f.y + dy + .5*h + .3*f.fontSize)) * k
  2291. s.printf("BT %.2f %.2f Td (%s)Tj ET", bt, td, txt2)
  2292. //BT %.2F %.2F Td (%s) Tj ET',(f.x+dx)*k,(f.h-(f.y+.5*h+.3*f.FontSize))*k,txt2);
  2293. }
  2294. if f.underline {
  2295. s.printf(" %s", f.dounderline(f.x+dx, f.y+dy+.5*h+.3*f.fontSize, txtStr))
  2296. }
  2297. if f.strikeout {
  2298. s.printf(" %s", f.dostrikeout(f.x+dx, f.y+dy+.5*h+.3*f.fontSize, txtStr))
  2299. }
  2300. if f.colorFlag {
  2301. s.printf(" Q")
  2302. }
  2303. if link > 0 || len(linkStr) > 0 {
  2304. f.newLink(f.x+dx, f.y+dy+.5*h-.5*f.fontSize, f.GetStringWidth(txtStr), f.fontSize, link, linkStr)
  2305. }
  2306. }
  2307. str := s.String()
  2308. if len(str) > 0 {
  2309. f.out(str)
  2310. }
  2311. f.lasth = h
  2312. if ln > 0 {
  2313. // Go to next line
  2314. f.y += h
  2315. if ln == 1 {
  2316. f.x = f.lMargin
  2317. }
  2318. } else {
  2319. f.x += w
  2320. }
  2321. return
  2322. }
  2323. // Revert string to use in RTL languages
  2324. func reverseText(text string) string {
  2325. oldText := []rune(text)
  2326. newText := make([]rune, len(oldText))
  2327. length := len(oldText) - 1
  2328. for i, r := range oldText {
  2329. newText[length-i] = r
  2330. }
  2331. return string(newText)
  2332. }
  2333. // Cell is a simpler version of CellFormat with no fill, border, links or
  2334. // special alignment. The Cell_strikeout() example demonstrates this method.
  2335. func (f *Fpdf) Cell(w, h float64, txtStr string) {
  2336. f.CellFormat(w, h, txtStr, "", 0, "L", false, 0, "")
  2337. }
  2338. // Cellf is a simpler printf-style version of CellFormat with no fill, border,
  2339. // links or special alignment. See documentation for the fmt package for
  2340. // details on fmtStr and args.
  2341. func (f *Fpdf) Cellf(w, h float64, fmtStr string, args ...interface{}) {
  2342. f.CellFormat(w, h, sprintf(fmtStr, args...), "", 0, "L", false, 0, "")
  2343. }
  2344. // SplitLines splits text into several lines using the current font. Each line
  2345. // has its length limited to a maximum width given by w. This function can be
  2346. // used to determine the total height of wrapped text for vertical placement
  2347. // purposes.
  2348. //
  2349. // This method is useful for codepage-based fonts only. For UTF-8 encoded text,
  2350. // use SplitText().
  2351. //
  2352. // You can use MultiCell if you want to print a text on several lines in a
  2353. // simple way.
  2354. func (f *Fpdf) SplitLines(txt []byte, w float64) [][]byte {
  2355. // Function contributed by Bruno Michel
  2356. lines := [][]byte{}
  2357. cw := f.currentFont.Cw
  2358. wmax := int(math.Ceil((w - 2*f.cMargin) * 1000 / f.fontSize))
  2359. s := bytes.Replace(txt, []byte("\r"), []byte{}, -1)
  2360. nb := len(s)
  2361. for nb > 0 && s[nb-1] == '\n' {
  2362. nb--
  2363. }
  2364. s = s[0:nb]
  2365. sep := -1
  2366. i := 0
  2367. j := 0
  2368. l := 0
  2369. for i < nb {
  2370. c := s[i]
  2371. l += cw[c]
  2372. if c == ' ' || c == '\t' || c == '\n' {
  2373. sep = i
  2374. }
  2375. if c == '\n' || l > wmax {
  2376. if sep == -1 {
  2377. if i == j {
  2378. i++
  2379. }
  2380. sep = i
  2381. } else {
  2382. i = sep + 1
  2383. }
  2384. lines = append(lines, s[j:sep])
  2385. sep = -1
  2386. j = i
  2387. l = 0
  2388. } else {
  2389. i++
  2390. }
  2391. }
  2392. if i != j {
  2393. lines = append(lines, s[j:i])
  2394. }
  2395. return lines
  2396. }
  2397. // MultiCell supports printing text with line breaks. They can be automatic (as
  2398. // soon as the text reaches the right border of the cell) or explicit (via the
  2399. // \n character). As many cells as necessary are output, one below the other.
  2400. //
  2401. // Text can be aligned, centered or justified. The cell block can be framed and
  2402. // the background painted. See CellFormat() for more details.
  2403. //
  2404. // The current position after calling MultiCell() is the beginning of the next
  2405. // line, equivalent to calling CellFormat with ln equal to 1.
  2406. //
  2407. // w is the width of the cells. A value of zero indicates cells that reach to
  2408. // the right margin.
  2409. //
  2410. // h indicates the line height of each cell in the unit of measure specified in New().
  2411. //
  2412. // Note: this method has a known bug that treats UTF-8 fonts differently than
  2413. // non-UTF-8 fonts. With UTF-8 fonts, all trailing newlines in txtStr are
  2414. // removed. With a non-UTF-8 font, if txtStr has one or more trailing newlines,
  2415. // only the last is removed. In the next major module version, the UTF-8 logic
  2416. // will be changed to match the non-UTF-8 logic. To prepare for that change,
  2417. // applications that use UTF-8 fonts and depend on having all trailing newlines
  2418. // removed should call strings.TrimRight(txtStr, "\r\n") before calling this
  2419. // method.
  2420. func (f *Fpdf) MultiCell(w, h float64, txtStr, borderStr, alignStr string, fill bool) {
  2421. if f.err != nil {
  2422. return
  2423. }
  2424. // dbg("MultiCell")
  2425. if alignStr == "" {
  2426. alignStr = "J"
  2427. }
  2428. cw := f.currentFont.Cw
  2429. if w == 0 {
  2430. w = f.w - f.rMargin - f.x
  2431. }
  2432. wmax := int(math.Ceil((w - 2*f.cMargin) * 1000 / f.fontSize))
  2433. s := strings.Replace(txtStr, "\r", "", -1)
  2434. srune := []rune(s)
  2435. // remove extra line breaks
  2436. var nb int
  2437. if f.isCurrentUTF8 {
  2438. nb = len(srune)
  2439. for nb > 0 && srune[nb-1] == '\n' {
  2440. nb--
  2441. }
  2442. srune = srune[0:nb]
  2443. } else {
  2444. nb = len(s)
  2445. bytes2 := []byte(s)
  2446. // for nb > 0 && bytes2[nb-1] == '\n' {
  2447. // Prior to August 2019, if s ended with a newline, this code stripped it.
  2448. // After that date, to be compatible with the UTF-8 code above, *all*
  2449. // trailing newlines were removed. Because this regression caused at least
  2450. // one application to break (see issue #333), the original behavior has been
  2451. // reinstated with a caveat included in the documentation.
  2452. if nb > 0 && bytes2[nb-1] == '\n' {
  2453. nb--
  2454. }
  2455. s = s[0:nb]
  2456. }
  2457. // dbg("[%s]\n", s)
  2458. var b, b2 string
  2459. b = "0"
  2460. if len(borderStr) > 0 {
  2461. if borderStr == "1" {
  2462. borderStr = "LTRB"
  2463. b = "LRT"
  2464. b2 = "LR"
  2465. } else {
  2466. b2 = ""
  2467. if strings.Contains(borderStr, "L") {
  2468. b2 += "L"
  2469. }
  2470. if strings.Contains(borderStr, "R") {
  2471. b2 += "R"
  2472. }
  2473. if strings.Contains(borderStr, "T") {
  2474. b = b2 + "T"
  2475. } else {
  2476. b = b2
  2477. }
  2478. }
  2479. }
  2480. sep := -1
  2481. i := 0
  2482. j := 0
  2483. l := 0
  2484. ls := 0
  2485. ns := 0
  2486. nl := 1
  2487. for i < nb {
  2488. // Get next character
  2489. var c rune
  2490. if f.isCurrentUTF8 {
  2491. c = srune[i]
  2492. } else {
  2493. c = rune(s[i])
  2494. }
  2495. if c == '\n' {
  2496. // Explicit line break
  2497. if f.ws > 0 {
  2498. f.ws = 0
  2499. f.out("0 Tw")
  2500. }
  2501. if f.isCurrentUTF8 {
  2502. newAlignStr := alignStr
  2503. if newAlignStr == "J" {
  2504. if f.isRTL {
  2505. newAlignStr = "R"
  2506. } else {
  2507. newAlignStr = "L"
  2508. }
  2509. }
  2510. f.CellFormat(w, h, string(srune[j:i]), b, 2, newAlignStr, fill, 0, "")
  2511. } else {
  2512. f.CellFormat(w, h, s[j:i], b, 2, alignStr, fill, 0, "")
  2513. }
  2514. i++
  2515. sep = -1
  2516. j = i
  2517. l = 0
  2518. ns = 0
  2519. nl++
  2520. if len(borderStr) > 0 && nl == 2 {
  2521. b = b2
  2522. }
  2523. continue
  2524. }
  2525. if c == ' ' || isChinese(c) {
  2526. sep = i
  2527. ls = l
  2528. ns++
  2529. }
  2530. if int(c) >= len(cw) {
  2531. f.err = fmt.Errorf("character outside the supported range: %s", string(c))
  2532. return
  2533. }
  2534. if cw[int(c)] == 0 { //Marker width 0 used for missing symbols
  2535. l += f.currentFont.Desc.MissingWidth
  2536. } else if cw[int(c)] != 65535 { //Marker width 65535 used for zero width symbols
  2537. l += cw[int(c)]
  2538. }
  2539. if l > wmax {
  2540. // Automatic line break
  2541. if sep == -1 {
  2542. if i == j {
  2543. i++
  2544. }
  2545. if f.ws > 0 {
  2546. f.ws = 0
  2547. f.out("0 Tw")
  2548. }
  2549. if f.isCurrentUTF8 {
  2550. f.CellFormat(w, h, string(srune[j:i]), b, 2, alignStr, fill, 0, "")
  2551. } else {
  2552. f.CellFormat(w, h, s[j:i], b, 2, alignStr, fill, 0, "")
  2553. }
  2554. } else {
  2555. ///////////////
  2556. // 如果第一个字就超宽了,别循环了,会死循环
  2557. if i==0{
  2558. break
  2559. }
  2560. if alignStr == "J" {
  2561. if ns > 1 {
  2562. f.ws = float64((wmax-ls)/1000) * f.fontSize / float64(ns-1)
  2563. } else {
  2564. f.ws = 0
  2565. }
  2566. f.outf("%.3f Tw", f.ws*f.k)
  2567. }
  2568. if f.isCurrentUTF8 {
  2569. f.CellFormat(w, h, string(srune[j:sep]), b, 2, alignStr, fill, 0, "")
  2570. } else {
  2571. f.CellFormat(w, h, s[j:sep], b, 2, alignStr, fill, 0, "")
  2572. }
  2573. //////////
  2574. // i = sep + 1
  2575. /////////
  2576. i=sep
  2577. }
  2578. sep = -1
  2579. j = i
  2580. l = 0
  2581. ns = 0
  2582. nl++
  2583. if len(borderStr) > 0 && nl == 2 {
  2584. b = b2
  2585. }
  2586. } else {
  2587. i++
  2588. }
  2589. }
  2590. // Last chunk
  2591. if f.ws > 0 {
  2592. f.ws = 0
  2593. f.out("0 Tw")
  2594. }
  2595. if len(borderStr) > 0 && strings.Contains(borderStr, "B") {
  2596. b += "B"
  2597. }
  2598. if f.isCurrentUTF8 {
  2599. if alignStr == "J" {
  2600. if f.isRTL {
  2601. alignStr = "R"
  2602. } else {
  2603. alignStr = ""
  2604. }
  2605. }
  2606. f.CellFormat(w, h, string(srune[j:i]), b, 2, alignStr, fill, 0, "")
  2607. } else {
  2608. f.CellFormat(w, h, s[j:i], b, 2, alignStr, fill, 0, "")
  2609. }
  2610. f.x = f.lMargin
  2611. }
  2612. // write outputs text in flowing mode
  2613. func (f *Fpdf) write(h float64, txtStr string, link int, linkStr string) {
  2614. // dbg("Write")
  2615. cw := f.currentFont.Cw
  2616. w := f.w - f.rMargin - f.x
  2617. wmax := (w - 2*f.cMargin) * 1000 / f.fontSize
  2618. s := strings.Replace(txtStr, "\r", "", -1)
  2619. var nb int
  2620. if f.isCurrentUTF8 {
  2621. nb = len([]rune(s))
  2622. if nb == 1 && s == " " {
  2623. f.x += f.GetStringWidth(s)
  2624. return
  2625. }
  2626. } else {
  2627. nb = len(s)
  2628. }
  2629. sep := -1
  2630. i := 0
  2631. j := 0
  2632. l := 0.0
  2633. nl := 1
  2634. for i < nb {
  2635. // Get next character
  2636. var c rune
  2637. if f.isCurrentUTF8 {
  2638. c = []rune(s)[i]
  2639. } else {
  2640. c = rune(byte(s[i]))
  2641. }
  2642. if c == '\n' {
  2643. // Explicit line break
  2644. if f.isCurrentUTF8 {
  2645. f.CellFormat(w, h, string([]rune(s)[j:i]), "", 2, "", false, link, linkStr)
  2646. } else {
  2647. f.CellFormat(w, h, s[j:i], "", 2, "", false, link, linkStr)
  2648. }
  2649. i++
  2650. sep = -1
  2651. j = i
  2652. l = 0.0
  2653. if nl == 1 {
  2654. f.x = f.lMargin
  2655. w = f.w - f.rMargin - f.x
  2656. wmax = (w - 2*f.cMargin) * 1000 / f.fontSize
  2657. }
  2658. nl++
  2659. continue
  2660. }
  2661. if c == ' ' {
  2662. sep = i
  2663. }
  2664. l += float64(cw[int(c)])
  2665. if l > wmax {
  2666. // Automatic line break
  2667. if sep == -1 {
  2668. if f.x > f.lMargin {
  2669. // Move to next line
  2670. f.x = f.lMargin
  2671. f.y += h
  2672. w = f.w - f.rMargin - f.x
  2673. wmax = (w - 2*f.cMargin) * 1000 / f.fontSize
  2674. i++
  2675. nl++
  2676. continue
  2677. }
  2678. if i == j {
  2679. i++
  2680. }
  2681. if f.isCurrentUTF8 {
  2682. f.CellFormat(w, h, string([]rune(s)[j:i]), "", 2, "", false, link, linkStr)
  2683. } else {
  2684. f.CellFormat(w, h, s[j:i], "", 2, "", false, link, linkStr)
  2685. }
  2686. } else {
  2687. if f.isCurrentUTF8 {
  2688. f.CellFormat(w, h, string([]rune(s)[j:sep]), "", 2, "", false, link, linkStr)
  2689. } else {
  2690. f.CellFormat(w, h, s[j:sep], "", 2, "", false, link, linkStr)
  2691. }
  2692. i = sep + 1
  2693. }
  2694. sep = -1
  2695. j = i
  2696. l = 0.0
  2697. if nl == 1 {
  2698. f.x = f.lMargin
  2699. w = f.w - f.rMargin - f.x
  2700. wmax = (w - 2*f.cMargin) * 1000 / f.fontSize
  2701. }
  2702. nl++
  2703. } else {
  2704. i++
  2705. }
  2706. }
  2707. // Last chunk
  2708. if i != j {
  2709. if f.isCurrentUTF8 {
  2710. f.CellFormat(l/1000*f.fontSize, h, string([]rune(s)[j:]), "", 0, "", false, link, linkStr)
  2711. } else {
  2712. f.CellFormat(l/1000*f.fontSize, h, s[j:], "", 0, "", false, link, linkStr)
  2713. }
  2714. }
  2715. }
  2716. // Write prints text from the current position. When the right margin is
  2717. // reached (or the \n character is met) a line break occurs and text continues
  2718. // from the left margin. Upon method exit, the current position is left just at
  2719. // the end of the text.
  2720. //
  2721. // It is possible to put a link on the text.
  2722. //
  2723. // h indicates the line height in the unit of measure specified in New().
  2724. func (f *Fpdf) Write(h float64, txtStr string) {
  2725. f.write(h, txtStr, 0, "")
  2726. }
  2727. // Writef is like Write but uses printf-style formatting. See the documentation
  2728. // for package fmt for more details on fmtStr and args.
  2729. func (f *Fpdf) Writef(h float64, fmtStr string, args ...interface{}) {
  2730. f.write(h, sprintf(fmtStr, args...), 0, "")
  2731. }
  2732. // WriteLinkString writes text that when clicked launches an external URL. See
  2733. // Write() for argument details.
  2734. func (f *Fpdf) WriteLinkString(h float64, displayStr, targetStr string) {
  2735. f.write(h, displayStr, 0, targetStr)
  2736. }
  2737. // WriteLinkID writes text that when clicked jumps to another location in the
  2738. // PDF. linkID is an identifier returned by AddLink(). See Write() for argument
  2739. // details.
  2740. func (f *Fpdf) WriteLinkID(h float64, displayStr string, linkID int) {
  2741. f.write(h, displayStr, linkID, "")
  2742. }
  2743. // WriteAligned is an implementation of Write that makes it possible to align
  2744. // text.
  2745. //
  2746. // width indicates the width of the box the text will be drawn in. This is in
  2747. // the unit of measure specified in New(). If it is set to 0, the bounding box
  2748. //of the page will be taken (pageWidth - leftMargin - rightMargin).
  2749. //
  2750. // lineHeight indicates the line height in the unit of measure specified in
  2751. // New().
  2752. //
  2753. // alignStr sees to horizontal alignment of the given textStr. The options are
  2754. // "L", "C" and "R" (Left, Center, Right). The default is "L".
  2755. func (f *Fpdf) WriteAligned(width, lineHeight float64, textStr, alignStr string) {
  2756. lMargin, _, rMargin, _ := f.GetMargins()
  2757. pageWidth, _ := f.GetPageSize()
  2758. if width == 0 {
  2759. width = pageWidth - (lMargin + rMargin)
  2760. }
  2761. var lines []string
  2762. if f.isCurrentUTF8 {
  2763. lines = f.SplitText(textStr, width)
  2764. } else {
  2765. for _, line := range f.SplitLines([]byte(textStr), width) {
  2766. lines = append(lines, string(line))
  2767. }
  2768. }
  2769. for _, lineBt := range lines {
  2770. lineStr := string(lineBt)
  2771. lineWidth := f.GetStringWidth(lineStr)
  2772. switch alignStr {
  2773. case "C":
  2774. f.SetLeftMargin(lMargin + ((width - lineWidth) / 2))
  2775. f.Write(lineHeight, lineStr)
  2776. f.SetLeftMargin(lMargin)
  2777. case "R":
  2778. f.SetLeftMargin(lMargin + (width - lineWidth) - 2.01*f.cMargin)
  2779. f.Write(lineHeight, lineStr)
  2780. f.SetLeftMargin(lMargin)
  2781. default:
  2782. f.SetRightMargin(pageWidth - lMargin - width)
  2783. f.Write(lineHeight, lineStr)
  2784. f.SetRightMargin(rMargin)
  2785. }
  2786. }
  2787. }
  2788. // Ln performs a line break. The current abscissa goes back to the left margin
  2789. // and the ordinate increases by the amount passed in parameter. A negative
  2790. // value of h indicates the height of the last printed cell.
  2791. //
  2792. // This method is demonstrated in the example for MultiCell.
  2793. func (f *Fpdf) Ln(h float64) {
  2794. f.x = f.lMargin
  2795. if h < 0 {
  2796. f.y += f.lasth
  2797. } else {
  2798. f.y += h
  2799. }
  2800. }
  2801. // ImageTypeFromMime returns the image type used in various image-related
  2802. // functions (for example, Image()) that is associated with the specified MIME
  2803. // type. For example, "jpg" is returned if mimeStr is "image/jpeg". An error is
  2804. // set if the specified MIME type is not supported.
  2805. func (f *Fpdf) ImageTypeFromMime(mimeStr string) (tp string) {
  2806. switch mimeStr {
  2807. case "image/png":
  2808. tp = "png"
  2809. case "image/jpg":
  2810. tp = "jpg"
  2811. case "image/jpeg":
  2812. tp = "jpg"
  2813. case "image/gif":
  2814. tp = "gif"
  2815. default:
  2816. f.SetErrorf("unsupported image type: %s", mimeStr)
  2817. }
  2818. return
  2819. }
  2820. func (f *Fpdf) imageOut(info *ImageInfoType, x, y, w, h float64, allowNegativeX, flow bool, link int, linkStr string) {
  2821. // Automatic width and height calculation if needed
  2822. if w == 0 && h == 0 {
  2823. // Put image at 96 dpi
  2824. w = -96
  2825. h = -96
  2826. }
  2827. if w == -1 {
  2828. // Set image width to whatever value for dpi we read
  2829. // from the image or that was set manually
  2830. w = -info.dpi
  2831. }
  2832. if h == -1 {
  2833. // Set image height to whatever value for dpi we read
  2834. // from the image or that was set manually
  2835. h = -info.dpi
  2836. }
  2837. if w < 0 {
  2838. w = -info.w * 72.0 / w / f.k
  2839. }
  2840. if h < 0 {
  2841. h = -info.h * 72.0 / h / f.k
  2842. }
  2843. if w == 0 {
  2844. w = h * info.w / info.h
  2845. }
  2846. if h == 0 {
  2847. h = w * info.h / info.w
  2848. }
  2849. // Flowing mode
  2850. if flow {
  2851. if f.y+h > f.pageBreakTrigger && !f.inHeader && !f.inFooter && f.acceptPageBreak() {
  2852. // Automatic page break
  2853. x2 := f.x
  2854. f.AddPageFormat(f.curOrientation, f.curPageSize)
  2855. if f.err != nil {
  2856. return
  2857. }
  2858. f.x = x2
  2859. }
  2860. y = f.y
  2861. f.y += h
  2862. }
  2863. if !allowNegativeX {
  2864. if x < 0 {
  2865. x = f.x
  2866. }
  2867. }
  2868. // dbg("h %.2f", h)
  2869. // q 85.04 0 0 NaN 28.35 NaN cm /I2 Do Q
  2870. f.outf("q %.5f 0 0 %.5f %.5f %.5f cm /I%s Do Q", w*f.k, h*f.k, x*f.k, (f.h-(y+h))*f.k, info.i)
  2871. if link > 0 || len(linkStr) > 0 {
  2872. f.newLink(x, y, w, h, link, linkStr)
  2873. }
  2874. }
  2875. // Image puts a JPEG, PNG or GIF image in the current page.
  2876. //
  2877. // Deprecated in favor of ImageOptions -- see that function for
  2878. // details on the behavior of arguments
  2879. func (f *Fpdf) Image(imageNameStr string, x, y, w, h float64, flow bool, tp string, link int, linkStr string) {
  2880. options := ImageOptions{
  2881. ReadDpi: false,
  2882. ImageType: tp,
  2883. }
  2884. f.ImageOptions(imageNameStr, x, y, w, h, flow, options, link, linkStr)
  2885. }
  2886. // ImageOptions puts a JPEG, PNG or GIF image in the current page. The size it
  2887. // will take on the page can be specified in different ways. If both w and h
  2888. // are 0, the image is rendered at 96 dpi. If either w or h is zero, it will be
  2889. // calculated from the other dimension so that the aspect ratio is maintained.
  2890. // If w and/or h are -1, the dpi for that dimension will be read from the
  2891. // ImageInfoType object. PNG files can contain dpi information, and if present,
  2892. // this information will be populated in the ImageInfoType object and used in
  2893. // Width, Height, and Extent calculations. Otherwise, the SetDpi function can
  2894. // be used to change the dpi from the default of 72.
  2895. //
  2896. // If w and h are any other negative value, their absolute values
  2897. // indicate their dpi extents.
  2898. //
  2899. // Supported JPEG formats are 24 bit, 32 bit and gray scale. Supported PNG
  2900. // formats are 24 bit, indexed color, and 8 bit indexed gray scale. If a GIF
  2901. // image is animated, only the first frame is rendered. Transparency is
  2902. // supported. It is possible to put a link on the image.
  2903. //
  2904. // imageNameStr may be the name of an image as registered with a call to either
  2905. // RegisterImageReader() or RegisterImage(). In the first case, the image is
  2906. // loaded using an io.Reader. This is generally useful when the image is
  2907. // obtained from some other means than as a disk-based file. In the second
  2908. // case, the image is loaded as a file. Alternatively, imageNameStr may
  2909. // directly specify a sufficiently qualified filename.
  2910. //
  2911. // However the image is loaded, if it is used more than once only one copy is
  2912. // embedded in the file.
  2913. //
  2914. // If x is negative, the current abscissa is used.
  2915. //
  2916. // If flow is true, the current y value is advanced after placing the image and
  2917. // a page break may be made if necessary.
  2918. //
  2919. // If link refers to an internal page anchor (that is, it is non-zero; see
  2920. // AddLink()), the image will be a clickable internal link. Otherwise, if
  2921. // linkStr specifies a URL, the image will be a clickable external link.
  2922. func (f *Fpdf) ImageOptions(imageNameStr string, x, y, w, h float64, flow bool, options ImageOptions, link int, linkStr string) {
  2923. if f.err != nil {
  2924. return
  2925. }
  2926. info := f.RegisterImageOptions(imageNameStr, options)
  2927. if f.err != nil {
  2928. return
  2929. }
  2930. f.imageOut(info, x, y, w, h, options.AllowNegativePosition, flow, link, linkStr)
  2931. return
  2932. }
  2933. // RegisterImageReader registers an image, reading it from Reader r, adding it
  2934. // to the PDF file but not adding it to the page.
  2935. //
  2936. // This function is now deprecated in favor of RegisterImageOptionsReader
  2937. func (f *Fpdf) RegisterImageReader(imgName, tp string, r io.Reader) (info *ImageInfoType) {
  2938. options := ImageOptions{
  2939. ReadDpi: false,
  2940. ImageType: tp,
  2941. }
  2942. return f.RegisterImageOptionsReader(imgName, options, r)
  2943. }
  2944. // ImageOptions provides a place to hang any options we want to use while
  2945. // parsing an image.
  2946. //
  2947. // ImageType's possible values are (case insensitive):
  2948. // "JPG", "JPEG", "PNG" and "GIF". If empty, the type is inferred from
  2949. // the file extension.
  2950. //
  2951. // ReadDpi defines whether to attempt to automatically read the image
  2952. // dpi information from the image file. Normally, this should be set
  2953. // to true (understanding that not all images will have this info
  2954. // available). However, for backwards compatibility with previous
  2955. // versions of the API, it defaults to false.
  2956. //
  2957. // AllowNegativePosition can be set to true in order to prevent the default
  2958. // coercion of negative x values to the current x position.
  2959. type ImageOptions struct {
  2960. ImageType string
  2961. ReadDpi bool
  2962. AllowNegativePosition bool
  2963. }
  2964. // RegisterImageOptionsReader registers an image, reading it from Reader r, adding it
  2965. // to the PDF file but not adding it to the page. Use Image() with the same
  2966. // name to add the image to the page. Note that tp should be specified in this
  2967. // case.
  2968. //
  2969. // See Image() for restrictions on the image and the options parameters.
  2970. func (f *Fpdf) RegisterImageOptionsReader(imgName string, options ImageOptions, r io.Reader) (info *ImageInfoType) {
  2971. // Thanks, Ivan Daniluk, for generalizing this code to use the Reader interface.
  2972. if f.err != nil {
  2973. return
  2974. }
  2975. info, ok := f.images[imgName]
  2976. if ok {
  2977. return
  2978. }
  2979. // First use of this image, get info
  2980. if options.ImageType == "" {
  2981. f.err = fmt.Errorf("image type should be specified if reading from custom reader")
  2982. return
  2983. }
  2984. options.ImageType = strings.ToLower(options.ImageType)
  2985. if options.ImageType == "jpeg" {
  2986. options.ImageType = "jpg"
  2987. }
  2988. switch options.ImageType {
  2989. case "jpg":
  2990. info = f.parsejpg(r)
  2991. case "png":
  2992. info = f.parsepng(r, options.ReadDpi)
  2993. case "gif":
  2994. info = f.parsegif(r)
  2995. default:
  2996. f.err = fmt.Errorf("unsupported image type: %s", options.ImageType)
  2997. }
  2998. if f.err != nil {
  2999. return
  3000. }
  3001. if info.i, f.err = generateImageID(info); f.err != nil {
  3002. return
  3003. }
  3004. f.images[imgName] = info
  3005. return
  3006. }
  3007. // RegisterImage registers an image, adding it to the PDF file but not adding
  3008. // it to the page. Use Image() with the same filename to add the image to the
  3009. // page. Note that Image() calls this function, so this function is only
  3010. // necessary if you need information about the image before placing it.
  3011. //
  3012. // This function is now deprecated in favor of RegisterImageOptions.
  3013. // See Image() for restrictions on the image and the "tp" parameters.
  3014. func (f *Fpdf) RegisterImage(fileStr, tp string) (info *ImageInfoType) {
  3015. options := ImageOptions{
  3016. ReadDpi: false,
  3017. ImageType: tp,
  3018. }
  3019. return f.RegisterImageOptions(fileStr, options)
  3020. }
  3021. // RegisterImageOptions registers an image, adding it to the PDF file but not
  3022. // adding it to the page. Use Image() with the same filename to add the image
  3023. // to the page. Note that Image() calls this function, so this function is only
  3024. // necessary if you need information about the image before placing it. See
  3025. // Image() for restrictions on the image and the "tp" parameters.
  3026. func (f *Fpdf) RegisterImageOptions(fileStr string, options ImageOptions) (info *ImageInfoType) {
  3027. info, ok := f.images[fileStr]
  3028. if ok {
  3029. return
  3030. }
  3031. file, err := os.Open(fileStr)
  3032. if err != nil {
  3033. f.err = err
  3034. return
  3035. }
  3036. defer file.Close()
  3037. // First use of this image, get info
  3038. if options.ImageType == "" {
  3039. pos := strings.LastIndex(fileStr, ".")
  3040. if pos < 0 {
  3041. f.err = fmt.Errorf("image file has no extension and no type was specified: %s", fileStr)
  3042. return
  3043. }
  3044. options.ImageType = fileStr[pos+1:]
  3045. }
  3046. return f.RegisterImageOptionsReader(fileStr, options, file)
  3047. }
  3048. // GetImageInfo returns information about the registered image specified by
  3049. // imageStr. If the image has not been registered, nil is returned. The
  3050. // internal error is not modified by this method.
  3051. func (f *Fpdf) GetImageInfo(imageStr string) (info *ImageInfoType) {
  3052. return f.images[imageStr]
  3053. }
  3054. // ImportObjects imports objects from gofpdi into current document
  3055. func (f *Fpdf) ImportObjects(objs map[string][]byte) {
  3056. for k, v := range objs {
  3057. f.importedObjs[k] = v
  3058. }
  3059. }
  3060. // ImportObjPos imports object hash positions from gofpdi
  3061. func (f *Fpdf) ImportObjPos(objPos map[string]map[int]string) {
  3062. for k, v := range objPos {
  3063. f.importedObjPos[k] = v
  3064. }
  3065. }
  3066. // putImportedTemplates writes the imported template objects to the PDF
  3067. func (f *Fpdf) putImportedTemplates() {
  3068. nOffset := f.n + 1
  3069. // keep track of list of sha1 hashes (to be replaced with integers)
  3070. objsIDHash := make([]string, len(f.importedObjs))
  3071. // actual object data with new id
  3072. objsIDData := make([][]byte, len(f.importedObjs))
  3073. // Populate hash slice and data slice
  3074. i := 0
  3075. for k, v := range f.importedObjs {
  3076. objsIDHash[i] = k
  3077. objsIDData[i] = v
  3078. i++
  3079. }
  3080. // Populate a lookup table to get an object id from a hash
  3081. hashToObjID := make(map[string]int, len(f.importedObjs))
  3082. for i = 0; i < len(objsIDHash); i++ {
  3083. hashToObjID[objsIDHash[i]] = i + nOffset
  3084. }
  3085. // Now, replace hashes inside data with %040d object id
  3086. for i = 0; i < len(objsIDData); i++ {
  3087. // get hash
  3088. hash := objsIDHash[i]
  3089. for pos, h := range f.importedObjPos[hash] {
  3090. // Convert object id into a 40 character string padded with spaces
  3091. objIDPadded := fmt.Sprintf("%40s", fmt.Sprintf("%d", hashToObjID[h]))
  3092. // Convert objIDPadded into []byte
  3093. objIDBytes := []byte(objIDPadded)
  3094. // Replace sha1 hash with object id padded
  3095. for j := pos; j < pos+40; j++ {
  3096. objsIDData[i][j] = objIDBytes[j-pos]
  3097. }
  3098. }
  3099. // Save objsIDHash so that procset dictionary has the correct object ids
  3100. f.importedTplIDs[hash] = i + nOffset
  3101. }
  3102. // Now, put objects
  3103. for i = 0; i < len(objsIDData); i++ {
  3104. f.newobj()
  3105. f.out(string(objsIDData[i]))
  3106. }
  3107. }
  3108. // UseImportedTemplate uses imported template from gofpdi. It draws imported
  3109. // PDF page onto page.
  3110. func (f *Fpdf) UseImportedTemplate(tplName string, scaleX float64, scaleY float64, tX float64, tY float64) {
  3111. f.outf("q 0 J 1 w 0 j 0 G 0 g q %.4F 0 0 %.4F %.4F %.4F cm %s Do Q Q\n", scaleX*f.k, scaleY*f.k, tX*f.k, (tY+f.h)*f.k, tplName)
  3112. }
  3113. // ImportTemplates imports gofpdi template names into importedTplObjs for
  3114. // inclusion in the procset dictionary
  3115. func (f *Fpdf) ImportTemplates(tpls map[string]string) {
  3116. for tplName, tplID := range tpls {
  3117. f.importedTplObjs[tplName] = tplID
  3118. }
  3119. }
  3120. // GetConversionRatio returns the conversion ratio based on the unit given when
  3121. // creating the PDF.
  3122. func (f *Fpdf) GetConversionRatio() float64 {
  3123. return f.k
  3124. }
  3125. // GetXY returns the abscissa and ordinate of the current position.
  3126. //
  3127. // Note: the value returned for the abscissa will be affected by the current
  3128. // cell margin. To account for this, you may need to either add the value
  3129. // returned by GetCellMargin() to it or call SetCellMargin(0) to remove the
  3130. // cell margin.
  3131. func (f *Fpdf) GetXY() (float64, float64) {
  3132. return f.x, f.y
  3133. }
  3134. // GetX returns the abscissa of the current position.
  3135. //
  3136. // Note: the value returned will be affected by the current cell margin. To
  3137. // account for this, you may need to either add the value returned by
  3138. // GetCellMargin() to it or call SetCellMargin(0) to remove the cell margin.
  3139. func (f *Fpdf) GetX() float64 {
  3140. return f.x
  3141. }
  3142. // SetX defines the abscissa of the current position. If the passed value is
  3143. // negative, it is relative to the right of the page.
  3144. func (f *Fpdf) SetX(x float64) {
  3145. if x >= 0 {
  3146. f.x = x
  3147. } else {
  3148. f.x = f.w + x
  3149. }
  3150. }
  3151. // GetY returns the ordinate of the current position.
  3152. func (f *Fpdf) GetY() float64 {
  3153. return f.y
  3154. }
  3155. // SetY moves the current abscissa back to the left margin and sets the
  3156. // ordinate. If the passed value is negative, it is relative to the bottom of
  3157. // the page.
  3158. func (f *Fpdf) SetY(y float64) {
  3159. // dbg("SetY x %.2f, lMargin %.2f", f.x, f.lMargin)
  3160. f.x = f.lMargin
  3161. if y >= 0 {
  3162. f.y = y
  3163. } else {
  3164. f.y = f.h + y
  3165. }
  3166. }
  3167. // SetHomeXY is a convenience method that sets the current position to the left
  3168. // and top margins.
  3169. func (f *Fpdf) SetHomeXY() {
  3170. f.SetY(f.tMargin)
  3171. f.SetX(f.lMargin)
  3172. }
  3173. // SetXY defines the abscissa and ordinate of the current position. If the
  3174. // passed values are negative, they are relative respectively to the right and
  3175. // bottom of the page.
  3176. func (f *Fpdf) SetXY(x, y float64) {
  3177. f.SetY(y)
  3178. f.SetX(x)
  3179. }
  3180. // SetProtection applies certain constraints on the finished PDF document.
  3181. //
  3182. // actionFlag is a bitflag that controls various document operations.
  3183. // CnProtectPrint allows the document to be printed. CnProtectModify allows a
  3184. // document to be modified by a PDF editor. CnProtectCopy allows text and
  3185. // images to be copied into the system clipboard. CnProtectAnnotForms allows
  3186. // annotations and forms to be added by a PDF editor. These values can be
  3187. // combined by or-ing them together, for example,
  3188. // CnProtectCopy|CnProtectModify. This flag is advisory; not all PDF readers
  3189. // implement the constraints that this argument attempts to control.
  3190. //
  3191. // userPassStr specifies the password that will need to be provided to view the
  3192. // contents of the PDF. The permissions specified by actionFlag will apply.
  3193. //
  3194. // ownerPassStr specifies the password that will need to be provided to gain
  3195. // full access to the document regardless of the actionFlag value. An empty
  3196. // string for this argument will be replaced with a random value, effectively
  3197. // prohibiting full access to the document.
  3198. func (f *Fpdf) SetProtection(actionFlag byte, userPassStr, ownerPassStr string) {
  3199. if f.err != nil {
  3200. return
  3201. }
  3202. f.protect.setProtection(actionFlag, userPassStr, ownerPassStr)
  3203. }
  3204. // OutputAndClose sends the PDF document to the writer specified by w. This
  3205. // method will close both f and w, even if an error is detected and no document
  3206. // is produced.
  3207. func (f *Fpdf) OutputAndClose(w io.WriteCloser) error {
  3208. f.Output(w)
  3209. w.Close()
  3210. return f.err
  3211. }
  3212. // OutputFileAndClose creates or truncates the file specified by fileStr and
  3213. // writes the PDF document to it. This method will close f and the newly
  3214. // written file, even if an error is detected and no document is produced.
  3215. //
  3216. // Most examples demonstrate the use of this method.
  3217. func (f *Fpdf) OutputFileAndClose(fileStr string) error {
  3218. if f.err == nil {
  3219. pdfFile, err := os.Create(fileStr)
  3220. if err == nil {
  3221. f.Output(pdfFile)
  3222. pdfFile.Close()
  3223. } else {
  3224. f.err = err
  3225. }
  3226. }
  3227. return f.err
  3228. }
  3229. // Output sends the PDF document to the writer specified by w. No output will
  3230. // take place if an error has occurred in the document generation process. w
  3231. // remains open after this function returns. After returning, f is in a closed
  3232. // state and its methods should not be called.
  3233. func (f *Fpdf) Output(w io.Writer) error {
  3234. if f.err != nil {
  3235. return f.err
  3236. }
  3237. // dbg("Output")
  3238. if f.state < 3 {
  3239. f.Close()
  3240. }
  3241. _, err := f.buffer.WriteTo(w)
  3242. if err != nil {
  3243. f.err = err
  3244. }
  3245. return f.err
  3246. }
  3247. func (f *Fpdf) getpagesizestr(sizeStr string) (size SizeType) {
  3248. if f.err != nil {
  3249. return
  3250. }
  3251. sizeStr = strings.ToLower(sizeStr)
  3252. // dbg("Size [%s]", sizeStr)
  3253. var ok bool
  3254. size, ok = f.stdPageSizes[sizeStr]
  3255. if ok {
  3256. // dbg("found %s", sizeStr)
  3257. size.Wd /= f.k
  3258. size.Ht /= f.k
  3259. } else {
  3260. f.err = fmt.Errorf("unknown page size %s", sizeStr)
  3261. }
  3262. return
  3263. }
  3264. // GetPageSizeStr returns the SizeType for the given sizeStr (that is A4, A3, etc..)
  3265. func (f *Fpdf) GetPageSizeStr(sizeStr string) (size SizeType) {
  3266. return f.getpagesizestr(sizeStr)
  3267. }
  3268. func (f *Fpdf) _getpagesize(size SizeType) SizeType {
  3269. if size.Wd > size.Ht {
  3270. size.Wd, size.Ht = size.Ht, size.Wd
  3271. }
  3272. return size
  3273. }
  3274. func (f *Fpdf) beginpage(orientationStr string, size SizeType) {
  3275. if f.err != nil {
  3276. return
  3277. }
  3278. f.page++
  3279. // add the default page boxes, if any exist, to the page
  3280. f.pageBoxes[f.page] = make(map[string]PageBox)
  3281. for box, pb := range f.defPageBoxes {
  3282. f.pageBoxes[f.page][box] = pb
  3283. }
  3284. f.pages = append(f.pages, bytes.NewBufferString(""))
  3285. f.pageLinks = append(f.pageLinks, make([]linkType, 0, 0))
  3286. f.pageAttachments = append(f.pageAttachments, []annotationAttach{})
  3287. f.state = 2
  3288. f.x = f.lMargin
  3289. f.y = f.tMargin
  3290. f.fontFamily = ""
  3291. // Check page size and orientation
  3292. if orientationStr == "" {
  3293. orientationStr = f.defOrientation
  3294. } else {
  3295. orientationStr = strings.ToUpper(orientationStr[0:1])
  3296. }
  3297. if orientationStr != f.curOrientation || size.Wd != f.curPageSize.Wd || size.Ht != f.curPageSize.Ht {
  3298. // New size or orientation
  3299. if orientationStr == "P" {
  3300. f.w = size.Wd
  3301. f.h = size.Ht
  3302. } else {
  3303. f.w = size.Ht
  3304. f.h = size.Wd
  3305. }
  3306. f.wPt = f.w * f.k
  3307. f.hPt = f.h * f.k
  3308. f.pageBreakTrigger = f.h - f.bMargin
  3309. f.curOrientation = orientationStr
  3310. f.curPageSize = size
  3311. }
  3312. if orientationStr != f.defOrientation || size.Wd != f.defPageSize.Wd || size.Ht != f.defPageSize.Ht {
  3313. f.pageSizes[f.page] = SizeType{f.wPt, f.hPt}
  3314. }
  3315. return
  3316. }
  3317. func (f *Fpdf) endpage() {
  3318. f.EndLayer()
  3319. f.state = 1
  3320. }
  3321. // Load a font definition file from the given Reader
  3322. func (f *Fpdf) loadfont(r io.Reader) (def fontDefType) {
  3323. if f.err != nil {
  3324. return
  3325. }
  3326. // dbg("Loading font [%s]", fontStr)
  3327. var buf bytes.Buffer
  3328. _, err := buf.ReadFrom(r)
  3329. if err != nil {
  3330. f.err = err
  3331. return
  3332. }
  3333. err = json.Unmarshal(buf.Bytes(), &def)
  3334. if err != nil {
  3335. f.err = err
  3336. return
  3337. }
  3338. if def.i, err = generateFontID(def); err != nil {
  3339. f.err = err
  3340. }
  3341. // dump(def)
  3342. return
  3343. }
  3344. // Escape special characters in strings
  3345. func (f *Fpdf) escape(s string) string {
  3346. s = strings.Replace(s, "\\", "\\\\", -1)
  3347. s = strings.Replace(s, "(", "\\(", -1)
  3348. s = strings.Replace(s, ")", "\\)", -1)
  3349. s = strings.Replace(s, "\r", "\\r", -1)
  3350. return s
  3351. }
  3352. // textstring formats a text string
  3353. func (f *Fpdf) textstring(s string) string {
  3354. if f.protect.encrypted {
  3355. b := []byte(s)
  3356. f.protect.rc4(uint32(f.n), &b)
  3357. s = string(b)
  3358. }
  3359. return "(" + f.escape(s) + ")"
  3360. }
  3361. func blankCount(str string) (count int) {
  3362. l := len(str)
  3363. for j := 0; j < l; j++ {
  3364. if byte(' ') == str[j] {
  3365. count++
  3366. }
  3367. }
  3368. return
  3369. }
  3370. // SetUnderlineThickness accepts a multiplier for adjusting the text underline
  3371. // thickness, defaulting to 1. See SetUnderlineThickness example.
  3372. func (f *Fpdf) SetUnderlineThickness(thickness float64) {
  3373. f.userUnderlineThickness = thickness
  3374. }
  3375. // Underline text
  3376. func (f *Fpdf) dounderline(x, y float64, txt string) string {
  3377. up := float64(f.currentFont.Up)
  3378. ut := float64(f.currentFont.Ut) * f.userUnderlineThickness
  3379. w := f.GetStringWidth(txt) + f.ws*float64(blankCount(txt))
  3380. return sprintf("%.2f %.2f %.2f %.2f re f", x*f.k,
  3381. (f.h-(y-up/1000*f.fontSize))*f.k, w*f.k, -ut/1000*f.fontSizePt)
  3382. }
  3383. func (f *Fpdf) dostrikeout(x, y float64, txt string) string {
  3384. up := float64(f.currentFont.Up)
  3385. ut := float64(f.currentFont.Ut)
  3386. w := f.GetStringWidth(txt) + f.ws*float64(blankCount(txt))
  3387. return sprintf("%.2f %.2f %.2f %.2f re f", x*f.k,
  3388. (f.h-(y+4*up/1000*f.fontSize))*f.k, w*f.k, -ut/1000*f.fontSizePt)
  3389. }
  3390. func bufEqual(buf []byte, str string) bool {
  3391. return string(buf[0:len(str)]) == str
  3392. }
  3393. func be16(buf []byte) int {
  3394. return 256*int(buf[0]) + int(buf[1])
  3395. }
  3396. func (f *Fpdf) newImageInfo() *ImageInfoType {
  3397. // default dpi to 72 unless told otherwise
  3398. return &ImageInfoType{scale: f.k, dpi: 72}
  3399. }
  3400. // parsejpg extracts info from io.Reader with JPEG data
  3401. // Thank you, Bruno Michel, for providing this code.
  3402. func (f *Fpdf) parsejpg(r io.Reader) (info *ImageInfoType) {
  3403. info = f.newImageInfo()
  3404. var (
  3405. data bytes.Buffer
  3406. err error
  3407. )
  3408. _, err = data.ReadFrom(r)
  3409. if err != nil {
  3410. f.err = err
  3411. return
  3412. }
  3413. info.data = data.Bytes()
  3414. config, err := jpeg.DecodeConfig(bytes.NewReader(info.data))
  3415. if err != nil {
  3416. f.err = err
  3417. return
  3418. }
  3419. info.w = float64(config.Width)
  3420. info.h = float64(config.Height)
  3421. info.f = "DCTDecode"
  3422. info.bpc = 8
  3423. switch config.ColorModel {
  3424. case color.GrayModel:
  3425. info.cs = "DeviceGray"
  3426. case color.YCbCrModel:
  3427. info.cs = "DeviceRGB"
  3428. case color.CMYKModel:
  3429. info.cs = "DeviceCMYK"
  3430. default:
  3431. f.err = fmt.Errorf("image JPEG buffer has unsupported color space (%v)", config.ColorModel)
  3432. return
  3433. }
  3434. return
  3435. }
  3436. // parsepng extracts info from a PNG data
  3437. func (f *Fpdf) parsepng(r io.Reader, readdpi bool) (info *ImageInfoType) {
  3438. buf, err := bufferFromReader(r)
  3439. if err != nil {
  3440. f.err = err
  3441. return
  3442. }
  3443. return f.parsepngstream(buf, readdpi)
  3444. }
  3445. func (f *Fpdf) readBeInt32(r io.Reader) (val int32) {
  3446. err := binary.Read(r, binary.BigEndian, &val)
  3447. if err != nil && err != io.EOF {
  3448. f.err = err
  3449. }
  3450. return
  3451. }
  3452. func (f *Fpdf) readByte(r io.Reader) (val byte) {
  3453. err := binary.Read(r, binary.BigEndian, &val)
  3454. if err != nil {
  3455. f.err = err
  3456. }
  3457. return
  3458. }
  3459. // parsegif extracts info from a GIF data (via PNG conversion)
  3460. func (f *Fpdf) parsegif(r io.Reader) (info *ImageInfoType) {
  3461. data, err := bufferFromReader(r)
  3462. if err != nil {
  3463. f.err = err
  3464. return
  3465. }
  3466. var img image.Image
  3467. img, err = gif.Decode(data)
  3468. if err != nil {
  3469. f.err = err
  3470. return
  3471. }
  3472. pngBuf := new(bytes.Buffer)
  3473. err = png.Encode(pngBuf, img)
  3474. if err != nil {
  3475. f.err = err
  3476. return
  3477. }
  3478. return f.parsepngstream(pngBuf, false)
  3479. }
  3480. // newobj begins a new object
  3481. func (f *Fpdf) newobj() {
  3482. // dbg("newobj")
  3483. f.n++
  3484. for j := len(f.offsets); j <= f.n; j++ {
  3485. f.offsets = append(f.offsets, 0)
  3486. }
  3487. f.offsets[f.n] = f.buffer.Len()
  3488. f.outf("%d 0 obj", f.n)
  3489. }
  3490. func (f *Fpdf) putstream(b []byte) {
  3491. // dbg("putstream")
  3492. if f.protect.encrypted {
  3493. f.protect.rc4(uint32(f.n), &b)
  3494. }
  3495. f.out("stream")
  3496. f.out(string(b))
  3497. f.out("endstream")
  3498. }
  3499. // out; Add a line to the document
  3500. func (f *Fpdf) out(s string) {
  3501. if f.state == 2 {
  3502. f.pages[f.page].WriteString(s)
  3503. f.pages[f.page].WriteString("\n")
  3504. } else {
  3505. f.buffer.WriteString(s)
  3506. f.buffer.WriteString("\n")
  3507. }
  3508. }
  3509. // outbuf adds a buffered line to the document
  3510. func (f *Fpdf) outbuf(r io.Reader) {
  3511. if f.state == 2 {
  3512. f.pages[f.page].ReadFrom(r)
  3513. f.pages[f.page].WriteString("\n")
  3514. } else {
  3515. f.buffer.ReadFrom(r)
  3516. f.buffer.WriteString("\n")
  3517. }
  3518. }
  3519. // RawWriteStr writes a string directly to the PDF generation buffer. This is a
  3520. // low-level function that is not required for normal PDF construction. An
  3521. // understanding of the PDF specification is needed to use this method
  3522. // correctly.
  3523. func (f *Fpdf) RawWriteStr(str string) {
  3524. f.out(str)
  3525. }
  3526. // RawWriteBuf writes the contents of the specified buffer directly to the PDF
  3527. // generation buffer. This is a low-level function that is not required for
  3528. // normal PDF construction. An understanding of the PDF specification is needed
  3529. // to use this method correctly.
  3530. func (f *Fpdf) RawWriteBuf(r io.Reader) {
  3531. f.outbuf(r)
  3532. }
  3533. // outf adds a formatted line to the document
  3534. func (f *Fpdf) outf(fmtStr string, args ...interface{}) {
  3535. f.out(sprintf(fmtStr, args...))
  3536. }
  3537. // SetDefaultCatalogSort sets the default value of the catalog sort flag that
  3538. // will be used when initializing a new Fpdf instance. See SetCatalogSort() for
  3539. // more details.
  3540. func SetDefaultCatalogSort(flag bool) {
  3541. gl.catalogSort = flag
  3542. }
  3543. // SetCatalogSort sets a flag that will be used, if true, to consistently order
  3544. // the document's internal resource catalogs. This method is typically only
  3545. // used for test purposes to facilitate PDF comparison.
  3546. func (f *Fpdf) SetCatalogSort(flag bool) {
  3547. f.catalogSort = flag
  3548. }
  3549. // SetDefaultCreationDate sets the default value of the document creation date
  3550. // that will be used when initializing a new Fpdf instance. See
  3551. // SetCreationDate() for more details.
  3552. func SetDefaultCreationDate(tm time.Time) {
  3553. gl.creationDate = tm
  3554. }
  3555. // SetDefaultModificationDate sets the default value of the document modification date
  3556. // that will be used when initializing a new Fpdf instance. See
  3557. // SetCreationDate() for more details.
  3558. func SetDefaultModificationDate(tm time.Time) {
  3559. gl.modDate = tm
  3560. }
  3561. // SetCreationDate fixes the document's internal CreationDate value. By
  3562. // default, the time when the document is generated is used for this value.
  3563. // This method is typically only used for testing purposes to facilitate PDF
  3564. // comparison. Specify a zero-value time to revert to the default behavior.
  3565. func (f *Fpdf) SetCreationDate(tm time.Time) {
  3566. f.creationDate = tm
  3567. }
  3568. // SetModificationDate fixes the document's internal ModDate value.
  3569. // See `SetCreationDate` for more details.
  3570. func (f *Fpdf) SetModificationDate(tm time.Time) {
  3571. f.modDate = tm
  3572. }
  3573. // SetJavascript adds Adobe JavaScript to the document.
  3574. func (f *Fpdf) SetJavascript(script string) {
  3575. f.javascript = &script
  3576. }
  3577. // RegisterAlias adds an (alias, replacement) pair to the document so we can
  3578. // replace all occurrences of that alias after writing but before the document
  3579. // is closed. Functions ExampleFpdf_RegisterAlias() and
  3580. // ExampleFpdf_RegisterAlias_utf8() in fpdf_test.go demonstrate this method.
  3581. func (f *Fpdf) RegisterAlias(alias, replacement string) {
  3582. // Note: map[string]string assignments embed literal escape ("\00") sequences
  3583. // into utf16 key and value strings. Consequently, subsequent search/replace
  3584. // operations will fail unexpectedly if utf8toutf16() conversions take place
  3585. // here. Instead, conversions are deferred until the actual search/replace
  3586. // operation takes place when the PDF output is generated.
  3587. f.aliasMap[alias] = replacement
  3588. }
  3589. func (f *Fpdf) replaceAliases() {
  3590. for mode := 0; mode < 2; mode++ {
  3591. for alias, replacement := range f.aliasMap {
  3592. if mode == 1 {
  3593. alias = utf8toutf16(alias, false)
  3594. replacement = utf8toutf16(replacement, false)
  3595. }
  3596. for n := 1; n <= f.page; n++ {
  3597. s := f.pages[n].String()
  3598. if strings.Contains(s, alias) {
  3599. s = strings.Replace(s, alias, replacement, -1)
  3600. f.pages[n].Truncate(0)
  3601. f.pages[n].WriteString(s)
  3602. }
  3603. }
  3604. }
  3605. }
  3606. }
  3607. func (f *Fpdf) putpages() {
  3608. var wPt, hPt float64
  3609. var pageSize SizeType
  3610. var ok bool
  3611. nb := f.page
  3612. if len(f.aliasNbPagesStr) > 0 {
  3613. // Replace number of pages
  3614. f.RegisterAlias(f.aliasNbPagesStr, sprintf("%d", nb))
  3615. }
  3616. f.replaceAliases()
  3617. if f.defOrientation == "P" {
  3618. wPt = f.defPageSize.Wd * f.k
  3619. hPt = f.defPageSize.Ht * f.k
  3620. } else {
  3621. wPt = f.defPageSize.Ht * f.k
  3622. hPt = f.defPageSize.Wd * f.k
  3623. }
  3624. pagesObjectNumbers := make([]int, nb+1) // 1-based
  3625. for n := 1; n <= nb; n++ {
  3626. // Page
  3627. f.newobj()
  3628. pagesObjectNumbers[n] = f.n // save for /Kids
  3629. f.out("<</Type /Page")
  3630. f.out("/Parent 1 0 R")
  3631. pageSize, ok = f.pageSizes[n]
  3632. if ok {
  3633. f.outf("/MediaBox [0 0 %.2f %.2f]", pageSize.Wd, pageSize.Ht)
  3634. }
  3635. for t, pb := range f.pageBoxes[n] {
  3636. f.outf("/%s [%.2f %.2f %.2f %.2f]", t, pb.X, pb.Y, pb.Wd, pb.Ht)
  3637. }
  3638. f.out("/Resources 2 0 R")
  3639. // Links
  3640. if len(f.pageLinks[n])+len(f.pageAttachments[n]) > 0 {
  3641. var annots fmtBuffer
  3642. annots.printf("/Annots [")
  3643. for _, pl := range f.pageLinks[n] {
  3644. annots.printf("<</Type /Annot /Subtype /Link /Rect [%.2f %.2f %.2f %.2f] /Border [0 0 0] ",
  3645. pl.x, pl.y, pl.x+pl.wd, pl.y-pl.ht)
  3646. if pl.link == 0 {
  3647. annots.printf("/A <</S /URI /URI %s>>>>", f.textstring(pl.linkStr))
  3648. } else {
  3649. l := f.links[pl.link]
  3650. var sz SizeType
  3651. var h float64
  3652. sz, ok = f.pageSizes[l.page]
  3653. if ok {
  3654. h = sz.Ht
  3655. } else {
  3656. h = hPt
  3657. }
  3658. // dbg("h [%.2f], l.y [%.2f] f.k [%.2f]\n", h, l.y, f.k)
  3659. annots.printf("/Dest [%d 0 R /XYZ 0 %.2f null]>>", 1+2*l.page, h-l.y*f.k)
  3660. }
  3661. }
  3662. f.putAttachmentAnnotationLinks(&annots, n)
  3663. annots.printf("]")
  3664. f.out(annots.String())
  3665. }
  3666. if f.pdfVersion > "1.3" {
  3667. f.out("/Group <</Type /Group /S /Transparency /CS /DeviceRGB>>")
  3668. }
  3669. f.outf("/Contents %d 0 R>>", f.n+1)
  3670. f.out("endobj")
  3671. // Page content
  3672. f.newobj()
  3673. if f.compress {
  3674. data := sliceCompress(f.pages[n].Bytes())
  3675. f.outf("<</Filter /FlateDecode /Length %d>>", len(data))
  3676. f.putstream(data)
  3677. } else {
  3678. f.outf("<</Length %d>>", f.pages[n].Len())
  3679. f.putstream(f.pages[n].Bytes())
  3680. }
  3681. f.out("endobj")
  3682. }
  3683. // Pages root
  3684. f.offsets[1] = f.buffer.Len()
  3685. f.out("1 0 obj")
  3686. f.out("<</Type /Pages")
  3687. var kids fmtBuffer
  3688. kids.printf("/Kids [")
  3689. for i := 1; i <= nb; i++ {
  3690. kids.printf("%d 0 R ", pagesObjectNumbers[i])
  3691. }
  3692. kids.printf("]")
  3693. f.out(kids.String())
  3694. f.outf("/Count %d", nb)
  3695. f.outf("/MediaBox [0 0 %.2f %.2f]", wPt, hPt)
  3696. f.out(">>")
  3697. f.out("endobj")
  3698. }
  3699. func (f *Fpdf) putfonts() {
  3700. if f.err != nil {
  3701. return
  3702. }
  3703. nf := f.n
  3704. for _, diff := range f.diffs {
  3705. // Encodings
  3706. f.newobj()
  3707. f.outf("<</Type /Encoding /BaseEncoding /WinAnsiEncoding /Differences [%s]>>", diff)
  3708. f.out("endobj")
  3709. }
  3710. {
  3711. var fileList []string
  3712. var info fontFileType
  3713. var file string
  3714. for file = range f.fontFiles {
  3715. fileList = append(fileList, file)
  3716. }
  3717. if f.catalogSort {
  3718. sort.SliceStable(fileList, func(i, j int) bool { return fileList[i] < fileList[j] })
  3719. }
  3720. for _, file = range fileList {
  3721. info = f.fontFiles[file]
  3722. if info.fontType != "UTF8" {
  3723. f.newobj()
  3724. info.n = f.n
  3725. f.fontFiles[file] = info
  3726. var font []byte
  3727. if info.embedded {
  3728. font = info.content
  3729. } else {
  3730. var err error
  3731. font, err = f.loadFontFile(file)
  3732. if err != nil {
  3733. f.err = err
  3734. return
  3735. }
  3736. }
  3737. compressed := file[len(file)-2:] == ".z"
  3738. if !compressed && info.length2 > 0 {
  3739. buf := font[6:info.length1]
  3740. buf = append(buf, font[6+info.length1+6:info.length2]...)
  3741. font = buf
  3742. }
  3743. f.outf("<</Length %d", len(font))
  3744. if compressed {
  3745. f.out("/Filter /FlateDecode")
  3746. }
  3747. f.outf("/Length1 %d", info.length1)
  3748. if info.length2 > 0 {
  3749. f.outf("/Length2 %d /Length3 0", info.length2)
  3750. }
  3751. f.out(">>")
  3752. f.putstream(font)
  3753. f.out("endobj")
  3754. }
  3755. }
  3756. }
  3757. {
  3758. var keyList []string
  3759. var font fontDefType
  3760. var key string
  3761. for key = range f.fonts {
  3762. keyList = append(keyList, key)
  3763. }
  3764. if f.catalogSort {
  3765. sort.SliceStable(keyList, func(i, j int) bool { return keyList[i] < keyList[j] })
  3766. }
  3767. for _, key = range keyList {
  3768. font = f.fonts[key]
  3769. // Font objects
  3770. font.N = f.n + 1
  3771. f.fonts[key] = font
  3772. tp := font.Tp
  3773. name := font.Name
  3774. switch tp {
  3775. case "Core":
  3776. // Core font
  3777. f.newobj()
  3778. f.out("<</Type /Font")
  3779. f.outf("/BaseFont /%s", name)
  3780. f.out("/Subtype /Type1")
  3781. if name != "Symbol" && name != "ZapfDingbats" {
  3782. f.out("/Encoding /WinAnsiEncoding")
  3783. }
  3784. f.out(">>")
  3785. f.out("endobj")
  3786. case "Type1":
  3787. fallthrough
  3788. case "TrueType":
  3789. // Additional Type1 or TrueType/OpenType font
  3790. f.newobj()
  3791. f.out("<</Type /Font")
  3792. f.outf("/BaseFont /%s", name)
  3793. f.outf("/Subtype /%s", tp)
  3794. f.out("/FirstChar 32 /LastChar 255")
  3795. f.outf("/Widths %d 0 R", f.n+1)
  3796. f.outf("/FontDescriptor %d 0 R", f.n+2)
  3797. if font.DiffN > 0 {
  3798. f.outf("/Encoding %d 0 R", nf+font.DiffN)
  3799. } else {
  3800. f.out("/Encoding /WinAnsiEncoding")
  3801. }
  3802. f.out(">>")
  3803. f.out("endobj")
  3804. // Widths
  3805. f.newobj()
  3806. var s fmtBuffer
  3807. s.WriteString("[")
  3808. for j := 32; j < 256; j++ {
  3809. s.printf("%d ", font.Cw[j])
  3810. }
  3811. s.WriteString("]")
  3812. f.out(s.String())
  3813. f.out("endobj")
  3814. // Descriptor
  3815. f.newobj()
  3816. s.Truncate(0)
  3817. s.printf("<</Type /FontDescriptor /FontName /%s ", name)
  3818. s.printf("/Ascent %d ", font.Desc.Ascent)
  3819. s.printf("/Descent %d ", font.Desc.Descent)
  3820. s.printf("/CapHeight %d ", font.Desc.CapHeight)
  3821. s.printf("/Flags %d ", font.Desc.Flags)
  3822. s.printf("/FontBBox [%d %d %d %d] ", font.Desc.FontBBox.Xmin, font.Desc.FontBBox.Ymin,
  3823. font.Desc.FontBBox.Xmax, font.Desc.FontBBox.Ymax)
  3824. s.printf("/ItalicAngle %d ", font.Desc.ItalicAngle)
  3825. s.printf("/StemV %d ", font.Desc.StemV)
  3826. s.printf("/MissingWidth %d ", font.Desc.MissingWidth)
  3827. var suffix string
  3828. if tp != "Type1" {
  3829. suffix = "2"
  3830. }
  3831. s.printf("/FontFile%s %d 0 R>>", suffix, f.fontFiles[font.File].n)
  3832. f.out(s.String())
  3833. f.out("endobj")
  3834. case "UTF8":
  3835. fontName := "utf8" + font.Name
  3836. usedRunes := font.usedRunes
  3837. delete(usedRunes, 0)
  3838. utf8FontStream := font.utf8File.GenerateCutFont(usedRunes)
  3839. utf8FontSize := len(utf8FontStream)
  3840. compressedFontStream := sliceCompress(utf8FontStream)
  3841. CodeSignDictionary := font.utf8File.CodeSymbolDictionary
  3842. delete(CodeSignDictionary, 0)
  3843. f.newobj()
  3844. f.out(fmt.Sprintf("<</Type /Font\n/Subtype /Type0\n/BaseFont /%s\n/Encoding /Identity-H\n/DescendantFonts [%d 0 R]\n/ToUnicode %d 0 R>>\n"+"endobj", fontName, f.n+1, f.n+2))
  3845. f.newobj()
  3846. f.out("<</Type /Font\n/Subtype /CIDFontType2\n/BaseFont /" + fontName + "\n" +
  3847. "/CIDSystemInfo " + strconv.Itoa(f.n+2) + " 0 R\n/FontDescriptor " + strconv.Itoa(f.n+3) + " 0 R")
  3848. if font.Desc.MissingWidth != 0 {
  3849. f.out("/DW " + strconv.Itoa(font.Desc.MissingWidth) + "")
  3850. }
  3851. f.generateCIDFontMap(&font, font.utf8File.LastRune)
  3852. f.out("/CIDToGIDMap " + strconv.Itoa(f.n+4) + " 0 R>>")
  3853. f.out("endobj")
  3854. f.newobj()
  3855. f.out("<</Length " + strconv.Itoa(len(toUnicode)) + ">>")
  3856. f.putstream([]byte(toUnicode))
  3857. f.out("endobj")
  3858. // CIDInfo
  3859. f.newobj()
  3860. f.out("<</Registry (Adobe)\n/Ordering (UCS)\n/Supplement 0>>")
  3861. f.out("endobj")
  3862. // Font descriptor
  3863. f.newobj()
  3864. var s fmtBuffer
  3865. s.printf("<</Type /FontDescriptor /FontName /%s\n /Ascent %d", fontName, font.Desc.Ascent)
  3866. s.printf(" /Descent %d", font.Desc.Descent)
  3867. s.printf(" /CapHeight %d", font.Desc.CapHeight)
  3868. v := font.Desc.Flags
  3869. v = v | 4
  3870. v = v &^ 32
  3871. s.printf(" /Flags %d", v)
  3872. s.printf("/FontBBox [%d %d %d %d] ", font.Desc.FontBBox.Xmin, font.Desc.FontBBox.Ymin,
  3873. font.Desc.FontBBox.Xmax, font.Desc.FontBBox.Ymax)
  3874. s.printf(" /ItalicAngle %d", font.Desc.ItalicAngle)
  3875. s.printf(" /StemV %d", font.Desc.StemV)
  3876. s.printf(" /MissingWidth %d", font.Desc.MissingWidth)
  3877. s.printf("/FontFile2 %d 0 R", f.n+2)
  3878. s.printf(">>")
  3879. f.out(s.String())
  3880. f.out("endobj")
  3881. // Embed CIDToGIDMap
  3882. cidToGidMap := make([]byte, 256*256*2)
  3883. for cc, glyph := range CodeSignDictionary {
  3884. cidToGidMap[cc*2] = byte(glyph >> 8)
  3885. cidToGidMap[cc*2+1] = byte(glyph & 0xFF)
  3886. }
  3887. cidToGidMap = sliceCompress(cidToGidMap)
  3888. f.newobj()
  3889. f.out("<</Length " + strconv.Itoa(len(cidToGidMap)) + "/Filter /FlateDecode>>")
  3890. f.putstream(cidToGidMap)
  3891. f.out("endobj")
  3892. //Font file
  3893. f.newobj()
  3894. f.out("<</Length " + strconv.Itoa(len(compressedFontStream)))
  3895. f.out("/Filter /FlateDecode")
  3896. f.out("/Length1 " + strconv.Itoa(utf8FontSize))
  3897. f.out(">>")
  3898. f.putstream(compressedFontStream)
  3899. f.out("endobj")
  3900. default:
  3901. f.err = fmt.Errorf("unsupported font type: %s", tp)
  3902. return
  3903. }
  3904. }
  3905. }
  3906. return
  3907. }
  3908. func (f *Fpdf) generateCIDFontMap(font *fontDefType, LastRune int) {
  3909. rangeID := 0
  3910. cidArray := make(map[int]*untypedKeyMap)
  3911. cidArrayKeys := make([]int, 0)
  3912. prevCid := -2
  3913. prevWidth := -1
  3914. interval := false
  3915. startCid := 1
  3916. cwLen := LastRune + 1
  3917. // for each character
  3918. for cid := startCid; cid < cwLen; cid++ {
  3919. if font.Cw[cid] == 0x00 {
  3920. continue
  3921. }
  3922. width := font.Cw[cid]
  3923. if width == 65535 {
  3924. width = 0
  3925. }
  3926. if numb, OK := font.usedRunes[cid]; cid > 255 && (!OK || numb == 0) {
  3927. continue
  3928. }
  3929. if cid == prevCid+1 {
  3930. if width == prevWidth {
  3931. if width == cidArray[rangeID].get(0) {
  3932. cidArray[rangeID].put(nil, width)
  3933. } else {
  3934. cidArray[rangeID].pop()
  3935. rangeID = prevCid
  3936. r := untypedKeyMap{
  3937. valueSet: make([]int, 0),
  3938. keySet: make([]interface{}, 0),
  3939. }
  3940. cidArray[rangeID] = &r
  3941. cidArrayKeys = append(cidArrayKeys, rangeID)
  3942. cidArray[rangeID].put(nil, prevWidth)
  3943. cidArray[rangeID].put(nil, width)
  3944. }
  3945. interval = true
  3946. cidArray[rangeID].put("interval", 1)
  3947. } else {
  3948. if interval {
  3949. // new range
  3950. rangeID = cid
  3951. r := untypedKeyMap{
  3952. valueSet: make([]int, 0),
  3953. keySet: make([]interface{}, 0),
  3954. }
  3955. cidArray[rangeID] = &r
  3956. cidArrayKeys = append(cidArrayKeys, rangeID)
  3957. cidArray[rangeID].put(nil, width)
  3958. } else {
  3959. cidArray[rangeID].put(nil, width)
  3960. }
  3961. interval = false
  3962. }
  3963. } else {
  3964. rangeID = cid
  3965. r := untypedKeyMap{
  3966. valueSet: make([]int, 0),
  3967. keySet: make([]interface{}, 0),
  3968. }
  3969. cidArray[rangeID] = &r
  3970. cidArrayKeys = append(cidArrayKeys, rangeID)
  3971. cidArray[rangeID].put(nil, width)
  3972. interval = false
  3973. }
  3974. prevCid = cid
  3975. prevWidth = width
  3976. }
  3977. previousKey := -1
  3978. nextKey := -1
  3979. isInterval := false
  3980. for g := 0; g < len(cidArrayKeys); {
  3981. key := cidArrayKeys[g]
  3982. ws := *cidArray[key]
  3983. cws := len(ws.keySet)
  3984. if (key == nextKey) && (!isInterval) && (ws.getIndex("interval") < 0 || cws < 4) {
  3985. if cidArray[key].getIndex("interval") >= 0 {
  3986. cidArray[key].delete("interval")
  3987. }
  3988. cidArray[previousKey] = arrayMerge(cidArray[previousKey], cidArray[key])
  3989. cidArrayKeys = remove(cidArrayKeys, key)
  3990. } else {
  3991. g++
  3992. previousKey = key
  3993. }
  3994. nextKey = key + cws
  3995. // ui := ws.getIndex("interval")
  3996. // ui = ui + 1
  3997. if ws.getIndex("interval") >= 0 {
  3998. if cws > 3 {
  3999. isInterval = true
  4000. } else {
  4001. isInterval = false
  4002. }
  4003. cidArray[key].delete("interval")
  4004. nextKey--
  4005. } else {
  4006. isInterval = false
  4007. }
  4008. }
  4009. var w fmtBuffer
  4010. for _, k := range cidArrayKeys {
  4011. ws := cidArray[k]
  4012. if len(arrayCountValues(ws.valueSet)) == 1 {
  4013. w.printf(" %d %d %d", k, k+len(ws.valueSet)-1, ws.get(0))
  4014. } else {
  4015. w.printf(" %d [ %s ]\n", k, implode(" ", ws.valueSet))
  4016. }
  4017. }
  4018. f.out("/W [" + w.String() + " ]")
  4019. }
  4020. func implode(sep string, arr []int) string {
  4021. var s fmtBuffer
  4022. for i := 0; i < len(arr)-1; i++ {
  4023. s.printf("%v", arr[i])
  4024. s.printf(sep)
  4025. }
  4026. if len(arr) > 0 {
  4027. s.printf("%v", arr[len(arr)-1])
  4028. }
  4029. return s.String()
  4030. }
  4031. // arrayCountValues counts the occurrences of each item in the $mp array.
  4032. func arrayCountValues(mp []int) map[int]int {
  4033. answer := make(map[int]int)
  4034. for _, v := range mp {
  4035. answer[v] = answer[v] + 1
  4036. }
  4037. return answer
  4038. }
  4039. func (f *Fpdf) loadFontFile(name string) ([]byte, error) {
  4040. if f.fontLoader != nil {
  4041. reader, err := f.fontLoader.Open(name)
  4042. if err == nil {
  4043. data, err := ioutil.ReadAll(reader)
  4044. if closer, ok := reader.(io.Closer); ok {
  4045. closer.Close()
  4046. }
  4047. return data, err
  4048. }
  4049. }
  4050. return ioutil.ReadFile(path.Join(f.fontpath, name))
  4051. }
  4052. func (f *Fpdf) putimages() {
  4053. var keyList []string
  4054. var key string
  4055. for key = range f.images {
  4056. keyList = append(keyList, key)
  4057. }
  4058. // Sort the keyList []string by the corresponding image's width.
  4059. if f.catalogSort {
  4060. sort.SliceStable(keyList, func(i, j int) bool { return f.images[keyList[i]].w < f.images[keyList[j]].w })
  4061. }
  4062. // Maintain a list of inserted image SHA-1 hashes, with their
  4063. // corresponding object ID number.
  4064. insertedImages := map[string]int{}
  4065. for _, key = range keyList {
  4066. image := f.images[key]
  4067. // Check if this image has already been inserted using it's SHA-1 hash.
  4068. insertedImageObjN, isFound := insertedImages[image.i]
  4069. // If found, skip inserting the image as a new object, and
  4070. // use the object ID from the insertedImages map.
  4071. // If not, insert the image into the PDF and store the object ID.
  4072. if isFound {
  4073. image.n = insertedImageObjN
  4074. } else {
  4075. f.putimage(image)
  4076. insertedImages[image.i] = image.n
  4077. }
  4078. }
  4079. }
  4080. func (f *Fpdf) putimage(info *ImageInfoType) {
  4081. f.newobj()
  4082. info.n = f.n
  4083. f.out("<</Type /XObject")
  4084. f.out("/Subtype /Image")
  4085. f.outf("/Width %d", int(info.w))
  4086. f.outf("/Height %d", int(info.h))
  4087. if info.cs == "Indexed" {
  4088. f.outf("/ColorSpace [/Indexed /DeviceRGB %d %d 0 R]", len(info.pal)/3-1, f.n+1)
  4089. } else {
  4090. f.outf("/ColorSpace /%s", info.cs)
  4091. if info.cs == "DeviceCMYK" {
  4092. f.out("/Decode [1 0 1 0 1 0 1 0]")
  4093. }
  4094. }
  4095. f.outf("/BitsPerComponent %d", info.bpc)
  4096. if len(info.f) > 0 {
  4097. f.outf("/Filter /%s", info.f)
  4098. }
  4099. if len(info.dp) > 0 {
  4100. f.outf("/DecodeParms <<%s>>", info.dp)
  4101. }
  4102. if len(info.trns) > 0 {
  4103. var trns fmtBuffer
  4104. for _, v := range info.trns {
  4105. trns.printf("%d %d ", v, v)
  4106. }
  4107. f.outf("/Mask [%s]", trns.String())
  4108. }
  4109. if info.smask != nil {
  4110. f.outf("/SMask %d 0 R", f.n+1)
  4111. }
  4112. f.outf("/Length %d>>", len(info.data))
  4113. f.putstream(info.data)
  4114. f.out("endobj")
  4115. // Soft mask
  4116. if len(info.smask) > 0 {
  4117. smask := &ImageInfoType{
  4118. w: info.w,
  4119. h: info.h,
  4120. cs: "DeviceGray",
  4121. bpc: 8,
  4122. f: info.f,
  4123. dp: sprintf("/Predictor 15 /Colors 1 /BitsPerComponent 8 /Columns %d", int(info.w)),
  4124. data: info.smask,
  4125. scale: f.k,
  4126. }
  4127. f.putimage(smask)
  4128. }
  4129. // Palette
  4130. if info.cs == "Indexed" {
  4131. f.newobj()
  4132. if f.compress {
  4133. pal := sliceCompress(info.pal)
  4134. f.outf("<</Filter /FlateDecode /Length %d>>", len(pal))
  4135. f.putstream(pal)
  4136. } else {
  4137. f.outf("<</Length %d>>", len(info.pal))
  4138. f.putstream(info.pal)
  4139. }
  4140. f.out("endobj")
  4141. }
  4142. }
  4143. func (f *Fpdf) putxobjectdict() {
  4144. {
  4145. var image *ImageInfoType
  4146. var key string
  4147. var keyList []string
  4148. for key = range f.images {
  4149. keyList = append(keyList, key)
  4150. }
  4151. if f.catalogSort {
  4152. sort.SliceStable(keyList, func(i, j int) bool { return f.images[keyList[i]].i < f.images[keyList[j]].i })
  4153. }
  4154. for _, key = range keyList {
  4155. image = f.images[key]
  4156. f.outf("/I%s %d 0 R", image.i, image.n)
  4157. }
  4158. }
  4159. {
  4160. var keyList []string
  4161. var key string
  4162. var tpl Template
  4163. keyList = templateKeyList(f.templates, f.catalogSort)
  4164. for _, key = range keyList {
  4165. tpl = f.templates[key]
  4166. // for _, tpl := range f.templates {
  4167. id := tpl.ID()
  4168. if objID, ok := f.templateObjects[id]; ok {
  4169. f.outf("/TPL%s %d 0 R", id, objID)
  4170. }
  4171. }
  4172. }
  4173. {
  4174. for tplName, objID := range f.importedTplObjs {
  4175. // here replace obj id hash with n
  4176. f.outf("%s %d 0 R", tplName, f.importedTplIDs[objID])
  4177. }
  4178. }
  4179. }
  4180. func (f *Fpdf) putresourcedict() {
  4181. f.out("/ProcSet [/PDF /Text /ImageB /ImageC /ImageI]")
  4182. f.out("/Font <<")
  4183. {
  4184. var keyList []string
  4185. var font fontDefType
  4186. var key string
  4187. for key = range f.fonts {
  4188. keyList = append(keyList, key)
  4189. }
  4190. if f.catalogSort {
  4191. sort.SliceStable(keyList, func(i, j int) bool { return f.fonts[keyList[i]].i < f.fonts[keyList[j]].i })
  4192. }
  4193. for _, key = range keyList {
  4194. font = f.fonts[key]
  4195. f.outf("/F%s %d 0 R", font.i, font.N)
  4196. }
  4197. }
  4198. f.out(">>")
  4199. f.out("/XObject <<")
  4200. f.putxobjectdict()
  4201. f.out(">>")
  4202. count := len(f.blendList)
  4203. if count > 1 {
  4204. f.out("/ExtGState <<")
  4205. for j := 1; j < count; j++ {
  4206. f.outf("/GS%d %d 0 R", j, f.blendList[j].objNum)
  4207. }
  4208. f.out(">>")
  4209. }
  4210. count = len(f.gradientList)
  4211. if count > 1 {
  4212. f.out("/Shading <<")
  4213. for j := 1; j < count; j++ {
  4214. f.outf("/Sh%d %d 0 R", j, f.gradientList[j].objNum)
  4215. }
  4216. f.out(">>")
  4217. }
  4218. // Layers
  4219. f.layerPutResourceDict()
  4220. f.spotColorPutResourceDict()
  4221. }
  4222. func (f *Fpdf) putBlendModes() {
  4223. count := len(f.blendList)
  4224. for j := 1; j < count; j++ {
  4225. bl := f.blendList[j]
  4226. f.newobj()
  4227. f.blendList[j].objNum = f.n
  4228. f.outf("<</Type /ExtGState /ca %s /CA %s /BM /%s>>",
  4229. bl.fillStr, bl.strokeStr, bl.modeStr)
  4230. f.out("endobj")
  4231. }
  4232. }
  4233. func (f *Fpdf) putGradients() {
  4234. count := len(f.gradientList)
  4235. for j := 1; j < count; j++ {
  4236. var f1 int
  4237. gr := f.gradientList[j]
  4238. if gr.tp == 2 || gr.tp == 3 {
  4239. f.newobj()
  4240. f.outf("<</FunctionType 2 /Domain [0.0 1.0] /C0 [%s] /C1 [%s] /N 1>>", gr.clr1Str, gr.clr2Str)
  4241. f.out("endobj")
  4242. f1 = f.n
  4243. }
  4244. f.newobj()
  4245. f.outf("<</ShadingType %d /ColorSpace /DeviceRGB", gr.tp)
  4246. if gr.tp == 2 {
  4247. f.outf("/Coords [%.5f %.5f %.5f %.5f] /Function %d 0 R /Extend [true true]>>",
  4248. gr.x1, gr.y1, gr.x2, gr.y2, f1)
  4249. } else if gr.tp == 3 {
  4250. f.outf("/Coords [%.5f %.5f 0 %.5f %.5f %.5f] /Function %d 0 R /Extend [true true]>>",
  4251. gr.x1, gr.y1, gr.x2, gr.y2, gr.r, f1)
  4252. }
  4253. f.out("endobj")
  4254. f.gradientList[j].objNum = f.n
  4255. }
  4256. }
  4257. func (f *Fpdf) putjavascript() {
  4258. if f.javascript == nil {
  4259. return
  4260. }
  4261. f.newobj()
  4262. f.nJs = f.n
  4263. f.out("<<")
  4264. f.outf("/Names [(EmbeddedJS) %d 0 R]", f.n+1)
  4265. f.out(">>")
  4266. f.out("endobj")
  4267. f.newobj()
  4268. f.out("<<")
  4269. f.out("/S /JavaScript")
  4270. f.outf("/JS %s", f.textstring(*f.javascript))
  4271. f.out(">>")
  4272. f.out("endobj")
  4273. }
  4274. func (f *Fpdf) putresources() {
  4275. if f.err != nil {
  4276. return
  4277. }
  4278. f.layerPutLayers()
  4279. f.putBlendModes()
  4280. f.putGradients()
  4281. f.putSpotColors()
  4282. f.putfonts()
  4283. if f.err != nil {
  4284. return
  4285. }
  4286. f.putimages()
  4287. f.putTemplates()
  4288. f.putImportedTemplates() // gofpdi
  4289. // Resource dictionary
  4290. f.offsets[2] = f.buffer.Len()
  4291. f.out("2 0 obj")
  4292. f.out("<<")
  4293. f.putresourcedict()
  4294. f.out(">>")
  4295. f.out("endobj")
  4296. f.putjavascript()
  4297. if f.protect.encrypted {
  4298. f.newobj()
  4299. f.protect.objNum = f.n
  4300. f.out("<<")
  4301. f.out("/Filter /Standard")
  4302. f.out("/V 1")
  4303. f.out("/R 2")
  4304. f.outf("/O (%s)", f.escape(string(f.protect.oValue)))
  4305. f.outf("/U (%s)", f.escape(string(f.protect.uValue)))
  4306. f.outf("/P %d", f.protect.pValue)
  4307. f.out(">>")
  4308. f.out("endobj")
  4309. }
  4310. return
  4311. }
  4312. // returns Now() if tm is zero
  4313. func timeOrNow(tm time.Time) time.Time {
  4314. if tm.IsZero() {
  4315. return time.Now()
  4316. }
  4317. return tm
  4318. }
  4319. func (f *Fpdf) putinfo() {
  4320. if len(f.producer) > 0 {
  4321. f.outf("/Producer %s", f.textstring(f.producer))
  4322. }
  4323. if len(f.title) > 0 {
  4324. f.outf("/Title %s", f.textstring(f.title))
  4325. }
  4326. if len(f.subject) > 0 {
  4327. f.outf("/Subject %s", f.textstring(f.subject))
  4328. }
  4329. if len(f.author) > 0 {
  4330. f.outf("/Author %s", f.textstring(f.author))
  4331. }
  4332. if len(f.keywords) > 0 {
  4333. f.outf("/Keywords %s", f.textstring(f.keywords))
  4334. }
  4335. if len(f.creator) > 0 {
  4336. f.outf("/Creator %s", f.textstring(f.creator))
  4337. }
  4338. creation := timeOrNow(f.creationDate)
  4339. f.outf("/CreationDate %s", f.textstring("D:"+creation.Format("20060102150405")))
  4340. mod := timeOrNow(f.modDate)
  4341. f.outf("/ModDate %s", f.textstring("D:"+mod.Format("20060102150405")))
  4342. }
  4343. func (f *Fpdf) putcatalog() {
  4344. f.out("/Type /Catalog")
  4345. f.out("/Pages 1 0 R")
  4346. switch f.zoomMode {
  4347. case "fullpage":
  4348. f.out("/OpenAction [3 0 R /Fit]")
  4349. case "fullwidth":
  4350. f.out("/OpenAction [3 0 R /FitH null]")
  4351. case "real":
  4352. f.out("/OpenAction [3 0 R /XYZ null null 1]")
  4353. }
  4354. // } else if !is_string($this->zoomMode))
  4355. // $this->out('/OpenAction [3 0 R /XYZ null null '.sprintf('%.2f',$this->zoomMode/100).']');
  4356. switch f.layoutMode {
  4357. case "single", "SinglePage":
  4358. f.out("/PageLayout /SinglePage")
  4359. case "continuous", "OneColumn":
  4360. f.out("/PageLayout /OneColumn")
  4361. case "two", "TwoColumnLeft":
  4362. f.out("/PageLayout /TwoColumnLeft")
  4363. case "TwoColumnRight":
  4364. f.out("/PageLayout /TwoColumnRight")
  4365. case "TwoPageLeft", "TwoPageRight":
  4366. if f.pdfVersion < "1.5" {
  4367. f.pdfVersion = "1.5"
  4368. }
  4369. f.out("/PageLayout /" + f.layoutMode)
  4370. }
  4371. // Bookmarks
  4372. if len(f.outlines) > 0 {
  4373. f.outf("/Outlines %d 0 R", f.outlineRoot)
  4374. f.out("/PageMode /UseOutlines")
  4375. }
  4376. // Layers
  4377. f.layerPutCatalog()
  4378. // Name dictionary :
  4379. // -> Javascript
  4380. // -> Embedded files
  4381. f.out("/Names <<")
  4382. // JavaScript
  4383. if f.javascript != nil {
  4384. f.outf("/JavaScript %d 0 R", f.nJs)
  4385. }
  4386. // Embedded files
  4387. f.outf("/EmbeddedFiles %s", f.getEmbeddedFiles())
  4388. f.out(">>")
  4389. }
  4390. func (f *Fpdf) putheader() {
  4391. if len(f.blendMap) > 0 && f.pdfVersion < "1.4" {
  4392. f.pdfVersion = "1.4"
  4393. }
  4394. f.outf("%%PDF-%s", f.pdfVersion)
  4395. }
  4396. func (f *Fpdf) puttrailer() {
  4397. f.outf("/Size %d", f.n+1)
  4398. f.outf("/Root %d 0 R", f.n)
  4399. f.outf("/Info %d 0 R", f.n-1)
  4400. if f.protect.encrypted {
  4401. f.outf("/Encrypt %d 0 R", f.protect.objNum)
  4402. f.out("/ID [()()]")
  4403. }
  4404. }
  4405. func (f *Fpdf) putxmp() {
  4406. if len(f.xmp) == 0 {
  4407. return
  4408. }
  4409. f.newobj()
  4410. f.outf("<< /Type /Metadata /Subtype /XML /Length %d >>", len(f.xmp))
  4411. f.putstream(f.xmp)
  4412. f.out("endobj")
  4413. }
  4414. func (f *Fpdf) putbookmarks() {
  4415. nb := len(f.outlines)
  4416. if nb > 0 {
  4417. lru := make(map[int]int)
  4418. level := 0
  4419. for i, o := range f.outlines {
  4420. if o.level > 0 {
  4421. parent := lru[o.level-1]
  4422. f.outlines[i].parent = parent
  4423. f.outlines[parent].last = i
  4424. if o.level > level {
  4425. f.outlines[parent].first = i
  4426. }
  4427. } else {
  4428. f.outlines[i].parent = nb
  4429. }
  4430. if o.level <= level && i > 0 {
  4431. prev := lru[o.level]
  4432. f.outlines[prev].next = i
  4433. f.outlines[i].prev = prev
  4434. }
  4435. lru[o.level] = i
  4436. level = o.level
  4437. }
  4438. n := f.n + 1
  4439. for _, o := range f.outlines {
  4440. f.newobj()
  4441. f.outf("<</Title %s", f.textstring(o.text))
  4442. f.outf("/Parent %d 0 R", n+o.parent)
  4443. if o.prev != -1 {
  4444. f.outf("/Prev %d 0 R", n+o.prev)
  4445. }
  4446. if o.next != -1 {
  4447. f.outf("/Next %d 0 R", n+o.next)
  4448. }
  4449. if o.first != -1 {
  4450. f.outf("/First %d 0 R", n+o.first)
  4451. }
  4452. if o.last != -1 {
  4453. f.outf("/Last %d 0 R", n+o.last)
  4454. }
  4455. f.outf("/Dest [%d 0 R /XYZ 0 %.2f null]", 1+2*o.p, (f.h-o.y)*f.k)
  4456. f.out("/Count 0>>")
  4457. f.out("endobj")
  4458. }
  4459. f.newobj()
  4460. f.outlineRoot = f.n
  4461. f.outf("<</Type /Outlines /First %d 0 R", n)
  4462. f.outf("/Last %d 0 R>>", n+lru[0])
  4463. f.out("endobj")
  4464. }
  4465. }
  4466. func (f *Fpdf) enddoc() {
  4467. if f.err != nil {
  4468. return
  4469. }
  4470. f.layerEndDoc()
  4471. f.putheader()
  4472. // Embedded files
  4473. f.putAttachments()
  4474. f.putAnnotationsAttachments()
  4475. f.putpages()
  4476. f.putresources()
  4477. if f.err != nil {
  4478. return
  4479. }
  4480. // Bookmarks
  4481. f.putbookmarks()
  4482. // Metadata
  4483. f.putxmp()
  4484. // Info
  4485. f.newobj()
  4486. f.out("<<")
  4487. f.putinfo()
  4488. f.out(">>")
  4489. f.out("endobj")
  4490. // Catalog
  4491. f.newobj()
  4492. f.out("<<")
  4493. f.putcatalog()
  4494. f.out(">>")
  4495. f.out("endobj")
  4496. // Cross-ref
  4497. o := f.buffer.Len()
  4498. f.out("xref")
  4499. f.outf("0 %d", f.n+1)
  4500. f.out("0000000000 65535 f ")
  4501. for j := 1; j <= f.n; j++ {
  4502. f.outf("%010d 00000 n ", f.offsets[j])
  4503. }
  4504. // Trailer
  4505. f.out("trailer")
  4506. f.out("<<")
  4507. f.puttrailer()
  4508. f.out(">>")
  4509. f.out("startxref")
  4510. f.outf("%d", o)
  4511. f.out("%%EOF")
  4512. f.state = 3
  4513. return
  4514. }
  4515. // Path Drawing
  4516. // MoveTo moves the stylus to (x, y) without drawing the path from the
  4517. // previous point. Paths must start with a MoveTo to set the original
  4518. // stylus location or the result is undefined.
  4519. //
  4520. // Create a "path" by moving a virtual stylus around the page (with
  4521. // MoveTo, LineTo, CurveTo, CurveBezierCubicTo, ArcTo & ClosePath)
  4522. // then draw it or fill it in (with DrawPath). The main advantage of
  4523. // using the path drawing routines rather than multiple Fpdf.Line is
  4524. // that PDF creates nice line joins at the angles, rather than just
  4525. // overlaying the lines.
  4526. func (f *Fpdf) MoveTo(x, y float64) {
  4527. f.point(x, y)
  4528. f.x, f.y = x, y
  4529. }
  4530. // LineTo creates a line from the current stylus location to (x, y), which
  4531. // becomes the new stylus location. Note that this only creates the line in
  4532. // the path; it does not actually draw the line on the page.
  4533. //
  4534. // The MoveTo() example demonstrates this method.
  4535. func (f *Fpdf) LineTo(x, y float64) {
  4536. f.outf("%.2f %.2f l", x*f.k, (f.h-y)*f.k)
  4537. f.x, f.y = x, y
  4538. }
  4539. // CurveTo creates a single-segment quadratic Bézier curve. The curve starts at
  4540. // the current stylus location and ends at the point (x, y). The control point
  4541. // (cx, cy) specifies the curvature. At the start point, the curve is tangent
  4542. // to the straight line between the current stylus location and the control
  4543. // point. At the end point, the curve is tangent to the straight line between
  4544. // the end point and the control point.
  4545. //
  4546. // The MoveTo() example demonstrates this method.
  4547. func (f *Fpdf) CurveTo(cx, cy, x, y float64) {
  4548. f.outf("%.5f %.5f %.5f %.5f v", cx*f.k, (f.h-cy)*f.k, x*f.k, (f.h-y)*f.k)
  4549. f.x, f.y = x, y
  4550. }
  4551. // CurveBezierCubicTo creates a single-segment cubic Bézier curve. The curve
  4552. // starts at the current stylus location and ends at the point (x, y). The
  4553. // control points (cx0, cy0) and (cx1, cy1) specify the curvature. At the
  4554. // current stylus, the curve is tangent to the straight line between the
  4555. // current stylus location and the control point (cx0, cy0). At the end point,
  4556. // the curve is tangent to the straight line between the end point and the
  4557. // control point (cx1, cy1).
  4558. //
  4559. // The MoveTo() example demonstrates this method.
  4560. func (f *Fpdf) CurveBezierCubicTo(cx0, cy0, cx1, cy1, x, y float64) {
  4561. f.curve(cx0, cy0, cx1, cy1, x, y)
  4562. f.x, f.y = x, y
  4563. }
  4564. // ClosePath creates a line from the current location to the last MoveTo point
  4565. // (if not the same) and mark the path as closed so the first and last lines
  4566. // join nicely.
  4567. //
  4568. // The MoveTo() example demonstrates this method.
  4569. func (f *Fpdf) ClosePath() {
  4570. f.outf("h")
  4571. }
  4572. // DrawPath actually draws the path on the page.
  4573. //
  4574. // styleStr can be "F" for filled, "D" for outlined only, or "DF" or "FD" for
  4575. // outlined and filled. An empty string will be replaced with "D".
  4576. // Path-painting operators as defined in the PDF specification are also
  4577. // allowed: "S" (Stroke the path), "s" (Close and stroke the path),
  4578. // "f" (fill the path, using the nonzero winding number), "f*"
  4579. // (Fill the path, using the even-odd rule), "B" (Fill and then stroke
  4580. // the path, using the nonzero winding number rule), "B*" (Fill and
  4581. // then stroke the path, using the even-odd rule), "b" (Close, fill,
  4582. // and then stroke the path, using the nonzero winding number rule) and
  4583. // "b*" (Close, fill, and then stroke the path, using the even-odd
  4584. // rule).
  4585. // Drawing uses the current draw color, line width, and cap style
  4586. // centered on the
  4587. // path. Filling uses the current fill color.
  4588. //
  4589. // The MoveTo() example demonstrates this method.
  4590. func (f *Fpdf) DrawPath(styleStr string) {
  4591. f.outf(fillDrawOp(styleStr))
  4592. }
  4593. // ArcTo draws an elliptical arc centered at point (x, y). rx and ry specify its
  4594. // horizontal and vertical radii. If the start of the arc is not at
  4595. // the current position, a connecting line will be drawn.
  4596. //
  4597. // degRotate specifies the angle that the arc will be rotated. degStart and
  4598. // degEnd specify the starting and ending angle of the arc. All angles are
  4599. // specified in degrees and measured counter-clockwise from the 3 o'clock
  4600. // position.
  4601. //
  4602. // styleStr can be "F" for filled, "D" for outlined only, or "DF" or "FD" for
  4603. // outlined and filled. An empty string will be replaced with "D". Drawing uses
  4604. // the current draw color, line width, and cap style centered on the arc's
  4605. // path. Filling uses the current fill color.
  4606. //
  4607. // The MoveTo() example demonstrates this method.
  4608. func (f *Fpdf) ArcTo(x, y, rx, ry, degRotate, degStart, degEnd float64) {
  4609. f.arc(x, y, rx, ry, degRotate, degStart, degEnd, "", true)
  4610. }
  4611. func (f *Fpdf) arc(x, y, rx, ry, degRotate, degStart, degEnd float64,
  4612. styleStr string, path bool) {
  4613. x *= f.k
  4614. y = (f.h - y) * f.k
  4615. rx *= f.k
  4616. ry *= f.k
  4617. segments := int(degEnd-degStart) / 60
  4618. if segments < 2 {
  4619. segments = 2
  4620. }
  4621. angleStart := degStart * math.Pi / 180
  4622. angleEnd := degEnd * math.Pi / 180
  4623. angleTotal := angleEnd - angleStart
  4624. dt := angleTotal / float64(segments)
  4625. dtm := dt / 3
  4626. if degRotate != 0 {
  4627. a := -degRotate * math.Pi / 180
  4628. f.outf("q %.5f %.5f %.5f %.5f %.5f %.5f cm",
  4629. math.Cos(a), -1*math.Sin(a),
  4630. math.Sin(a), math.Cos(a), x, y)
  4631. x = 0
  4632. y = 0
  4633. }
  4634. t := angleStart
  4635. a0 := x + rx*math.Cos(t)
  4636. b0 := y + ry*math.Sin(t)
  4637. c0 := -rx * math.Sin(t)
  4638. d0 := ry * math.Cos(t)
  4639. sx := a0 / f.k // start point of arc
  4640. sy := f.h - (b0 / f.k)
  4641. if path {
  4642. if f.x != sx || f.y != sy {
  4643. // Draw connecting line to start point
  4644. f.LineTo(sx, sy)
  4645. }
  4646. } else {
  4647. f.point(sx, sy)
  4648. }
  4649. for j := 1; j <= segments; j++ {
  4650. // Draw this bit of the total curve
  4651. t = (float64(j) * dt) + angleStart
  4652. a1 := x + rx*math.Cos(t)
  4653. b1 := y + ry*math.Sin(t)
  4654. c1 := -rx * math.Sin(t)
  4655. d1 := ry * math.Cos(t)
  4656. f.curve((a0+(c0*dtm))/f.k,
  4657. f.h-((b0+(d0*dtm))/f.k),
  4658. (a1-(c1*dtm))/f.k,
  4659. f.h-((b1-(d1*dtm))/f.k),
  4660. a1/f.k,
  4661. f.h-(b1/f.k))
  4662. a0 = a1
  4663. b0 = b1
  4664. c0 = c1
  4665. d0 = d1
  4666. if path {
  4667. f.x = a1 / f.k
  4668. f.y = f.h - (b1 / f.k)
  4669. }
  4670. }
  4671. if !path {
  4672. f.out(fillDrawOp(styleStr))
  4673. }
  4674. if degRotate != 0 {
  4675. f.out("Q")
  4676. }
  4677. }