fpdf.go 147 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023
  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. lines := []string{}
  2488. for i < nb {
  2489. // 这里是为了防止内存溢出,曾出现过前面是汉字后面是非汉字,lines为["汉字汉字汉字","","","".....]无限个""导致内存溢出
  2490. if len(lines) > len(srune) {
  2491. break
  2492. }
  2493. // Get next character
  2494. var c rune
  2495. if f.isCurrentUTF8 {
  2496. c = srune[i]
  2497. } else {
  2498. c = rune(s[i])
  2499. }
  2500. if c == '\n' {
  2501. // Explicit line break
  2502. if f.ws > 0 {
  2503. f.ws = 0
  2504. f.out("0 Tw")
  2505. }
  2506. if f.isCurrentUTF8 {
  2507. newAlignStr := alignStr
  2508. if newAlignStr == "J" {
  2509. if f.isRTL {
  2510. newAlignStr = "R"
  2511. } else {
  2512. newAlignStr = "L"
  2513. }
  2514. }
  2515. f.CellFormat(w, h, string(srune[j:i]), b, 2, newAlignStr, fill, 0, "")
  2516. } else {
  2517. f.CellFormat(w, h, s[j:i], b, 2, alignStr, fill, 0, "")
  2518. }
  2519. i++
  2520. lines = append(lines, s[j:i])
  2521. //sep = -1
  2522. j = i
  2523. l = 0
  2524. //ns = 0
  2525. nl++
  2526. if len(borderStr) > 0 && nl == 2 {
  2527. b = b2
  2528. }
  2529. continue
  2530. }
  2531. //if c == ' ' || isChinese(c) {
  2532. // sep = i
  2533. // ls = l
  2534. // ns++
  2535. //}
  2536. if int(c) >= len(cw) {
  2537. f.err = fmt.Errorf("character outside the supported range: %s", string(c))
  2538. return
  2539. }
  2540. if cw[int(c)] == 0 { //Marker width 0 used for missing symbols
  2541. l += f.currentFont.Desc.MissingWidth
  2542. } else if cw[int(c)] != 65535 { //Marker width 65535 used for zero width symbols
  2543. l += cw[int(c)]
  2544. }
  2545. if l > wmax {
  2546. ///////////////
  2547. // 如果第一个字就超宽了,别循环了,会死循环
  2548. if i == 0 {
  2549. break
  2550. }
  2551. // Automatic line break
  2552. //if sep == -1 {
  2553. // if i == j {
  2554. // i++
  2555. // }
  2556. // if f.ws > 0 {
  2557. // f.ws = 0
  2558. // f.out("0 Tw")
  2559. // }
  2560. // if f.isCurrentUTF8 {
  2561. // f.CellFormat(w, h, string(srune[j:i]), b, 2, alignStr, fill, 0, "")
  2562. // } else {
  2563. // f.CellFormat(w, h, s[j:i], b, 2, alignStr, fill, 0, "")
  2564. // }
  2565. //} else {
  2566. // if alignStr == "J" {
  2567. // if ns > 1 {
  2568. // f.ws = float64((wmax-ls)/1000) * f.fontSize / float64(ns-1)
  2569. // } else {
  2570. // f.ws = 0
  2571. // }
  2572. // f.outf("%.3f Tw", f.ws*f.k)
  2573. // }
  2574. // if f.isCurrentUTF8 {
  2575. // f.CellFormat(w, h, string(srune[j:sep]), b, 2, alignStr, fill, 0, "")
  2576. // } else {
  2577. // f.CellFormat(w, h, s[j:sep], b, 2, alignStr, fill, 0, "")
  2578. // }
  2579. // //////////
  2580. // // i = sep + 1
  2581. // /////////
  2582. // i = sep
  2583. //}
  2584. i++
  2585. lines = append(lines, s[j:i])
  2586. if f.ws > 0 {
  2587. f.ws = 0
  2588. f.out("0 Tw")
  2589. }
  2590. if f.isCurrentUTF8 {
  2591. f.CellFormat(w, h, string(srune[j:i]), b, 2, alignStr, fill, 0, "")
  2592. } else {
  2593. f.CellFormat(w, h, s[j:i], b, 2, alignStr, fill, 0, "")
  2594. }
  2595. //sep = -1
  2596. j = i
  2597. l = 0
  2598. //ns = 0
  2599. nl++
  2600. if len(borderStr) > 0 && nl == 2 {
  2601. b = b2
  2602. }
  2603. } else {
  2604. i++
  2605. }
  2606. }
  2607. // Last chunk
  2608. if f.ws > 0 {
  2609. f.ws = 0
  2610. f.out("0 Tw")
  2611. }
  2612. if len(borderStr) > 0 && strings.Contains(borderStr, "B") {
  2613. b += "B"
  2614. }
  2615. if f.isCurrentUTF8 {
  2616. if alignStr == "J" {
  2617. if f.isRTL {
  2618. alignStr = "R"
  2619. } else {
  2620. alignStr = ""
  2621. }
  2622. }
  2623. f.CellFormat(w, h, string(srune[j:i]), b, 2, alignStr, fill, 0, "")
  2624. } else {
  2625. f.CellFormat(w, h, s[j:i], b, 2, alignStr, fill, 0, "")
  2626. }
  2627. f.x = f.lMargin
  2628. }
  2629. // write outputs text in flowing mode
  2630. func (f *Fpdf) write(h float64, txtStr string, link int, linkStr string) {
  2631. // dbg("Write")
  2632. cw := f.currentFont.Cw
  2633. w := f.w - f.rMargin - f.x
  2634. wmax := (w - 2*f.cMargin) * 1000 / f.fontSize
  2635. s := strings.Replace(txtStr, "\r", "", -1)
  2636. var nb int
  2637. if f.isCurrentUTF8 {
  2638. nb = len([]rune(s))
  2639. if nb == 1 && s == " " {
  2640. f.x += f.GetStringWidth(s)
  2641. return
  2642. }
  2643. } else {
  2644. nb = len(s)
  2645. }
  2646. sep := -1
  2647. i := 0
  2648. j := 0
  2649. l := 0.0
  2650. nl := 1
  2651. for i < nb {
  2652. // Get next character
  2653. var c rune
  2654. if f.isCurrentUTF8 {
  2655. c = []rune(s)[i]
  2656. } else {
  2657. c = rune(byte(s[i]))
  2658. }
  2659. if c == '\n' {
  2660. // Explicit line break
  2661. if f.isCurrentUTF8 {
  2662. f.CellFormat(w, h, string([]rune(s)[j:i]), "", 2, "", false, link, linkStr)
  2663. } else {
  2664. f.CellFormat(w, h, s[j:i], "", 2, "", false, link, linkStr)
  2665. }
  2666. i++
  2667. sep = -1
  2668. j = i
  2669. l = 0.0
  2670. if nl == 1 {
  2671. f.x = f.lMargin
  2672. w = f.w - f.rMargin - f.x
  2673. wmax = (w - 2*f.cMargin) * 1000 / f.fontSize
  2674. }
  2675. nl++
  2676. continue
  2677. }
  2678. if c == ' ' {
  2679. sep = i
  2680. }
  2681. l += float64(cw[int(c)])
  2682. if l > wmax {
  2683. // Automatic line break
  2684. if sep == -1 {
  2685. if f.x > f.lMargin {
  2686. // Move to next line
  2687. f.x = f.lMargin
  2688. f.y += h
  2689. w = f.w - f.rMargin - f.x
  2690. wmax = (w - 2*f.cMargin) * 1000 / f.fontSize
  2691. i++
  2692. nl++
  2693. continue
  2694. }
  2695. if i == j {
  2696. i++
  2697. }
  2698. if f.isCurrentUTF8 {
  2699. f.CellFormat(w, h, string([]rune(s)[j:i]), "", 2, "", false, link, linkStr)
  2700. } else {
  2701. f.CellFormat(w, h, s[j:i], "", 2, "", false, link, linkStr)
  2702. }
  2703. } else {
  2704. if f.isCurrentUTF8 {
  2705. f.CellFormat(w, h, string([]rune(s)[j:sep]), "", 2, "", false, link, linkStr)
  2706. } else {
  2707. f.CellFormat(w, h, s[j:sep], "", 2, "", false, link, linkStr)
  2708. }
  2709. i = sep + 1
  2710. }
  2711. sep = -1
  2712. j = i
  2713. l = 0.0
  2714. if nl == 1 {
  2715. f.x = f.lMargin
  2716. w = f.w - f.rMargin - f.x
  2717. wmax = (w - 2*f.cMargin) * 1000 / f.fontSize
  2718. }
  2719. nl++
  2720. } else {
  2721. i++
  2722. }
  2723. }
  2724. // Last chunk
  2725. if i != j {
  2726. if f.isCurrentUTF8 {
  2727. f.CellFormat(l/1000*f.fontSize, h, string([]rune(s)[j:]), "", 0, "", false, link, linkStr)
  2728. } else {
  2729. f.CellFormat(l/1000*f.fontSize, h, s[j:], "", 0, "", false, link, linkStr)
  2730. }
  2731. }
  2732. }
  2733. // Write prints text from the current position. When the right margin is
  2734. // reached (or the \n character is met) a line break occurs and text continues
  2735. // from the left margin. Upon method exit, the current position is left just at
  2736. // the end of the text.
  2737. //
  2738. // It is possible to put a link on the text.
  2739. //
  2740. // h indicates the line height in the unit of measure specified in New().
  2741. func (f *Fpdf) Write(h float64, txtStr string) {
  2742. f.write(h, txtStr, 0, "")
  2743. }
  2744. // Writef is like Write but uses printf-style formatting. See the documentation
  2745. // for package fmt for more details on fmtStr and args.
  2746. func (f *Fpdf) Writef(h float64, fmtStr string, args ...interface{}) {
  2747. f.write(h, sprintf(fmtStr, args...), 0, "")
  2748. }
  2749. // WriteLinkString writes text that when clicked launches an external URL. See
  2750. // Write() for argument details.
  2751. func (f *Fpdf) WriteLinkString(h float64, displayStr, targetStr string) {
  2752. f.write(h, displayStr, 0, targetStr)
  2753. }
  2754. // WriteLinkID writes text that when clicked jumps to another location in the
  2755. // PDF. linkID is an identifier returned by AddLink(). See Write() for argument
  2756. // details.
  2757. func (f *Fpdf) WriteLinkID(h float64, displayStr string, linkID int) {
  2758. f.write(h, displayStr, linkID, "")
  2759. }
  2760. // WriteAligned is an implementation of Write that makes it possible to align
  2761. // text.
  2762. //
  2763. // width indicates the width of the box the text will be drawn in. This is in
  2764. // the unit of measure specified in New(). If it is set to 0, the bounding box
  2765. // of the page will be taken (pageWidth - leftMargin - rightMargin).
  2766. //
  2767. // lineHeight indicates the line height in the unit of measure specified in
  2768. // New().
  2769. //
  2770. // alignStr sees to horizontal alignment of the given textStr. The options are
  2771. // "L", "C" and "R" (Left, Center, Right). The default is "L".
  2772. func (f *Fpdf) WriteAligned(width, lineHeight float64, textStr, alignStr string) {
  2773. lMargin, _, rMargin, _ := f.GetMargins()
  2774. pageWidth, _ := f.GetPageSize()
  2775. if width == 0 {
  2776. width = pageWidth - (lMargin + rMargin)
  2777. }
  2778. var lines []string
  2779. if f.isCurrentUTF8 {
  2780. lines = f.SplitText(textStr, width)
  2781. } else {
  2782. for _, line := range f.SplitLines([]byte(textStr), width) {
  2783. lines = append(lines, string(line))
  2784. }
  2785. }
  2786. for _, lineBt := range lines {
  2787. lineStr := string(lineBt)
  2788. lineWidth := f.GetStringWidth(lineStr)
  2789. switch alignStr {
  2790. case "C":
  2791. f.SetLeftMargin(lMargin + ((width - lineWidth) / 2))
  2792. f.Write(lineHeight, lineStr)
  2793. f.SetLeftMargin(lMargin)
  2794. case "R":
  2795. f.SetLeftMargin(lMargin + (width - lineWidth) - 2.01*f.cMargin)
  2796. f.Write(lineHeight, lineStr)
  2797. f.SetLeftMargin(lMargin)
  2798. default:
  2799. f.SetRightMargin(pageWidth - lMargin - width)
  2800. f.Write(lineHeight, lineStr)
  2801. f.SetRightMargin(rMargin)
  2802. }
  2803. }
  2804. }
  2805. // Ln performs a line break. The current abscissa goes back to the left margin
  2806. // and the ordinate increases by the amount passed in parameter. A negative
  2807. // value of h indicates the height of the last printed cell.
  2808. //
  2809. // This method is demonstrated in the example for MultiCell.
  2810. func (f *Fpdf) Ln(h float64) {
  2811. f.x = f.lMargin
  2812. if h < 0 {
  2813. f.y += f.lasth
  2814. } else {
  2815. f.y += h
  2816. }
  2817. }
  2818. // ImageTypeFromMime returns the image type used in various image-related
  2819. // functions (for example, Image()) that is associated with the specified MIME
  2820. // type. For example, "jpg" is returned if mimeStr is "image/jpeg". An error is
  2821. // set if the specified MIME type is not supported.
  2822. func (f *Fpdf) ImageTypeFromMime(mimeStr string) (tp string) {
  2823. switch mimeStr {
  2824. case "image/png":
  2825. tp = "png"
  2826. case "image/jpg":
  2827. tp = "jpg"
  2828. case "image/jpeg":
  2829. tp = "jpg"
  2830. case "image/gif":
  2831. tp = "gif"
  2832. default:
  2833. f.SetErrorf("unsupported image type: %s", mimeStr)
  2834. }
  2835. return
  2836. }
  2837. func (f *Fpdf) imageOut(info *ImageInfoType, x, y, w, h float64, allowNegativeX, flow bool, link int, linkStr string) {
  2838. // Automatic width and height calculation if needed
  2839. if w == 0 && h == 0 {
  2840. // Put image at 96 dpi
  2841. w = -96
  2842. h = -96
  2843. }
  2844. if w == -1 {
  2845. // Set image width to whatever value for dpi we read
  2846. // from the image or that was set manually
  2847. w = -info.dpi
  2848. }
  2849. if h == -1 {
  2850. // Set image height to whatever value for dpi we read
  2851. // from the image or that was set manually
  2852. h = -info.dpi
  2853. }
  2854. if w < 0 {
  2855. w = -info.w * 72.0 / w / f.k
  2856. }
  2857. if h < 0 {
  2858. h = -info.h * 72.0 / h / f.k
  2859. }
  2860. if w == 0 {
  2861. w = h * info.w / info.h
  2862. }
  2863. if h == 0 {
  2864. h = w * info.h / info.w
  2865. }
  2866. // Flowing mode
  2867. if flow {
  2868. if f.y+h > f.pageBreakTrigger && !f.inHeader && !f.inFooter && f.acceptPageBreak() {
  2869. // Automatic page break
  2870. x2 := f.x
  2871. f.AddPageFormat(f.curOrientation, f.curPageSize)
  2872. if f.err != nil {
  2873. return
  2874. }
  2875. f.x = x2
  2876. }
  2877. y = f.y
  2878. f.y += h
  2879. }
  2880. if !allowNegativeX {
  2881. if x < 0 {
  2882. x = f.x
  2883. }
  2884. }
  2885. // dbg("h %.2f", h)
  2886. // q 85.04 0 0 NaN 28.35 NaN cm /I2 Do Q
  2887. 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)
  2888. if link > 0 || len(linkStr) > 0 {
  2889. f.newLink(x, y, w, h, link, linkStr)
  2890. }
  2891. }
  2892. // Image puts a JPEG, PNG or GIF image in the current page.
  2893. //
  2894. // Deprecated in favor of ImageOptions -- see that function for
  2895. // details on the behavior of arguments
  2896. func (f *Fpdf) Image(imageNameStr string, x, y, w, h float64, flow bool, tp string, link int, linkStr string) {
  2897. options := ImageOptions{
  2898. ReadDpi: false,
  2899. ImageType: tp,
  2900. }
  2901. f.ImageOptions(imageNameStr, x, y, w, h, flow, options, link, linkStr)
  2902. }
  2903. // ImageOptions puts a JPEG, PNG or GIF image in the current page. The size it
  2904. // will take on the page can be specified in different ways. If both w and h
  2905. // are 0, the image is rendered at 96 dpi. If either w or h is zero, it will be
  2906. // calculated from the other dimension so that the aspect ratio is maintained.
  2907. // If w and/or h are -1, the dpi for that dimension will be read from the
  2908. // ImageInfoType object. PNG files can contain dpi information, and if present,
  2909. // this information will be populated in the ImageInfoType object and used in
  2910. // Width, Height, and Extent calculations. Otherwise, the SetDpi function can
  2911. // be used to change the dpi from the default of 72.
  2912. //
  2913. // If w and h are any other negative value, their absolute values
  2914. // indicate their dpi extents.
  2915. //
  2916. // Supported JPEG formats are 24 bit, 32 bit and gray scale. Supported PNG
  2917. // formats are 24 bit, indexed color, and 8 bit indexed gray scale. If a GIF
  2918. // image is animated, only the first frame is rendered. Transparency is
  2919. // supported. It is possible to put a link on the image.
  2920. //
  2921. // imageNameStr may be the name of an image as registered with a call to either
  2922. // RegisterImageReader() or RegisterImage(). In the first case, the image is
  2923. // loaded using an io.Reader. This is generally useful when the image is
  2924. // obtained from some other means than as a disk-based file. In the second
  2925. // case, the image is loaded as a file. Alternatively, imageNameStr may
  2926. // directly specify a sufficiently qualified filename.
  2927. //
  2928. // However the image is loaded, if it is used more than once only one copy is
  2929. // embedded in the file.
  2930. //
  2931. // If x is negative, the current abscissa is used.
  2932. //
  2933. // If flow is true, the current y value is advanced after placing the image and
  2934. // a page break may be made if necessary.
  2935. //
  2936. // If link refers to an internal page anchor (that is, it is non-zero; see
  2937. // AddLink()), the image will be a clickable internal link. Otherwise, if
  2938. // linkStr specifies a URL, the image will be a clickable external link.
  2939. func (f *Fpdf) ImageOptions(imageNameStr string, x, y, w, h float64, flow bool, options ImageOptions, link int, linkStr string) {
  2940. if f.err != nil {
  2941. return
  2942. }
  2943. info := f.RegisterImageOptions(imageNameStr, options)
  2944. if f.err != nil {
  2945. return
  2946. }
  2947. f.imageOut(info, x, y, w, h, options.AllowNegativePosition, flow, link, linkStr)
  2948. return
  2949. }
  2950. // RegisterImageReader registers an image, reading it from Reader r, adding it
  2951. // to the PDF file but not adding it to the page.
  2952. //
  2953. // This function is now deprecated in favor of RegisterImageOptionsReader
  2954. func (f *Fpdf) RegisterImageReader(imgName, tp string, r io.Reader) (info *ImageInfoType) {
  2955. options := ImageOptions{
  2956. ReadDpi: false,
  2957. ImageType: tp,
  2958. }
  2959. return f.RegisterImageOptionsReader(imgName, options, r)
  2960. }
  2961. // ImageOptions provides a place to hang any options we want to use while
  2962. // parsing an image.
  2963. //
  2964. // ImageType's possible values are (case insensitive):
  2965. // "JPG", "JPEG", "PNG" and "GIF". If empty, the type is inferred from
  2966. // the file extension.
  2967. //
  2968. // ReadDpi defines whether to attempt to automatically read the image
  2969. // dpi information from the image file. Normally, this should be set
  2970. // to true (understanding that not all images will have this info
  2971. // available). However, for backwards compatibility with previous
  2972. // versions of the API, it defaults to false.
  2973. //
  2974. // AllowNegativePosition can be set to true in order to prevent the default
  2975. // coercion of negative x values to the current x position.
  2976. type ImageOptions struct {
  2977. ImageType string
  2978. ReadDpi bool
  2979. AllowNegativePosition bool
  2980. }
  2981. // RegisterImageOptionsReader registers an image, reading it from Reader r, adding it
  2982. // to the PDF file but not adding it to the page. Use Image() with the same
  2983. // name to add the image to the page. Note that tp should be specified in this
  2984. // case.
  2985. //
  2986. // See Image() for restrictions on the image and the options parameters.
  2987. func (f *Fpdf) RegisterImageOptionsReader(imgName string, options ImageOptions, r io.Reader) (info *ImageInfoType) {
  2988. // Thanks, Ivan Daniluk, for generalizing this code to use the Reader interface.
  2989. if f.err != nil {
  2990. return
  2991. }
  2992. info, ok := f.images[imgName]
  2993. if ok {
  2994. return
  2995. }
  2996. // First use of this image, get info
  2997. if options.ImageType == "" {
  2998. f.err = fmt.Errorf("image type should be specified if reading from custom reader")
  2999. return
  3000. }
  3001. options.ImageType = strings.ToLower(options.ImageType)
  3002. if options.ImageType == "jpeg" {
  3003. options.ImageType = "jpg"
  3004. }
  3005. switch options.ImageType {
  3006. case "jpg":
  3007. info = f.parsejpg(r)
  3008. case "png":
  3009. info = f.parsepng(r, options.ReadDpi)
  3010. case "gif":
  3011. info = f.parsegif(r)
  3012. default:
  3013. f.err = fmt.Errorf("unsupported image type: %s", options.ImageType)
  3014. }
  3015. if f.err != nil {
  3016. return
  3017. }
  3018. if info.i, f.err = generateImageID(info); f.err != nil {
  3019. return
  3020. }
  3021. f.images[imgName] = info
  3022. return
  3023. }
  3024. // RegisterImage registers an image, adding it to the PDF file but not adding
  3025. // it to the page. Use Image() with the same filename to add the image to the
  3026. // page. Note that Image() calls this function, so this function is only
  3027. // necessary if you need information about the image before placing it.
  3028. //
  3029. // This function is now deprecated in favor of RegisterImageOptions.
  3030. // See Image() for restrictions on the image and the "tp" parameters.
  3031. func (f *Fpdf) RegisterImage(fileStr, tp string) (info *ImageInfoType) {
  3032. options := ImageOptions{
  3033. ReadDpi: false,
  3034. ImageType: tp,
  3035. }
  3036. return f.RegisterImageOptions(fileStr, options)
  3037. }
  3038. // RegisterImageOptions registers an image, adding it to the PDF file but not
  3039. // adding it to the page. Use Image() with the same filename to add the image
  3040. // to the page. Note that Image() calls this function, so this function is only
  3041. // necessary if you need information about the image before placing it. See
  3042. // Image() for restrictions on the image and the "tp" parameters.
  3043. func (f *Fpdf) RegisterImageOptions(fileStr string, options ImageOptions) (info *ImageInfoType) {
  3044. info, ok := f.images[fileStr]
  3045. if ok {
  3046. return
  3047. }
  3048. file, err := os.Open(fileStr)
  3049. if err != nil {
  3050. f.err = err
  3051. return
  3052. }
  3053. defer file.Close()
  3054. // First use of this image, get info
  3055. if options.ImageType == "" {
  3056. pos := strings.LastIndex(fileStr, ".")
  3057. if pos < 0 {
  3058. f.err = fmt.Errorf("image file has no extension and no type was specified: %s", fileStr)
  3059. return
  3060. }
  3061. options.ImageType = fileStr[pos+1:]
  3062. }
  3063. return f.RegisterImageOptionsReader(fileStr, options, file)
  3064. }
  3065. // GetImageInfo returns information about the registered image specified by
  3066. // imageStr. If the image has not been registered, nil is returned. The
  3067. // internal error is not modified by this method.
  3068. func (f *Fpdf) GetImageInfo(imageStr string) (info *ImageInfoType) {
  3069. return f.images[imageStr]
  3070. }
  3071. // ImportObjects imports objects from gofpdi into current document
  3072. func (f *Fpdf) ImportObjects(objs map[string][]byte) {
  3073. for k, v := range objs {
  3074. f.importedObjs[k] = v
  3075. }
  3076. }
  3077. // ImportObjPos imports object hash positions from gofpdi
  3078. func (f *Fpdf) ImportObjPos(objPos map[string]map[int]string) {
  3079. for k, v := range objPos {
  3080. f.importedObjPos[k] = v
  3081. }
  3082. }
  3083. // putImportedTemplates writes the imported template objects to the PDF
  3084. func (f *Fpdf) putImportedTemplates() {
  3085. nOffset := f.n + 1
  3086. // keep track of list of sha1 hashes (to be replaced with integers)
  3087. objsIDHash := make([]string, len(f.importedObjs))
  3088. // actual object data with new id
  3089. objsIDData := make([][]byte, len(f.importedObjs))
  3090. // Populate hash slice and data slice
  3091. i := 0
  3092. for k, v := range f.importedObjs {
  3093. objsIDHash[i] = k
  3094. objsIDData[i] = v
  3095. i++
  3096. }
  3097. // Populate a lookup table to get an object id from a hash
  3098. hashToObjID := make(map[string]int, len(f.importedObjs))
  3099. for i = 0; i < len(objsIDHash); i++ {
  3100. hashToObjID[objsIDHash[i]] = i + nOffset
  3101. }
  3102. // Now, replace hashes inside data with %040d object id
  3103. for i = 0; i < len(objsIDData); i++ {
  3104. // get hash
  3105. hash := objsIDHash[i]
  3106. for pos, h := range f.importedObjPos[hash] {
  3107. // Convert object id into a 40 character string padded with spaces
  3108. objIDPadded := fmt.Sprintf("%40s", fmt.Sprintf("%d", hashToObjID[h]))
  3109. // Convert objIDPadded into []byte
  3110. objIDBytes := []byte(objIDPadded)
  3111. // Replace sha1 hash with object id padded
  3112. for j := pos; j < pos+40; j++ {
  3113. objsIDData[i][j] = objIDBytes[j-pos]
  3114. }
  3115. }
  3116. // Save objsIDHash so that procset dictionary has the correct object ids
  3117. f.importedTplIDs[hash] = i + nOffset
  3118. }
  3119. // Now, put objects
  3120. for i = 0; i < len(objsIDData); i++ {
  3121. f.newobj()
  3122. f.out(string(objsIDData[i]))
  3123. }
  3124. }
  3125. // UseImportedTemplate uses imported template from gofpdi. It draws imported
  3126. // PDF page onto page.
  3127. func (f *Fpdf) UseImportedTemplate(tplName string, scaleX float64, scaleY float64, tX float64, tY float64) {
  3128. 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)
  3129. }
  3130. // ImportTemplates imports gofpdi template names into importedTplObjs for
  3131. // inclusion in the procset dictionary
  3132. func (f *Fpdf) ImportTemplates(tpls map[string]string) {
  3133. for tplName, tplID := range tpls {
  3134. f.importedTplObjs[tplName] = tplID
  3135. }
  3136. }
  3137. // GetConversionRatio returns the conversion ratio based on the unit given when
  3138. // creating the PDF.
  3139. func (f *Fpdf) GetConversionRatio() float64 {
  3140. return f.k
  3141. }
  3142. // GetXY returns the abscissa and ordinate of the current position.
  3143. //
  3144. // Note: the value returned for the abscissa will be affected by the current
  3145. // cell margin. To account for this, you may need to either add the value
  3146. // returned by GetCellMargin() to it or call SetCellMargin(0) to remove the
  3147. // cell margin.
  3148. func (f *Fpdf) GetXY() (float64, float64) {
  3149. return f.x, f.y
  3150. }
  3151. // GetX returns the abscissa of the current position.
  3152. //
  3153. // Note: the value returned will be affected by the current cell margin. To
  3154. // account for this, you may need to either add the value returned by
  3155. // GetCellMargin() to it or call SetCellMargin(0) to remove the cell margin.
  3156. func (f *Fpdf) GetX() float64 {
  3157. return f.x
  3158. }
  3159. // SetX defines the abscissa of the current position. If the passed value is
  3160. // negative, it is relative to the right of the page.
  3161. func (f *Fpdf) SetX(x float64) {
  3162. if x >= 0 {
  3163. f.x = x
  3164. } else {
  3165. f.x = f.w + x
  3166. }
  3167. }
  3168. // GetY returns the ordinate of the current position.
  3169. func (f *Fpdf) GetY() float64 {
  3170. return f.y
  3171. }
  3172. // SetY moves the current abscissa back to the left margin and sets the
  3173. // ordinate. If the passed value is negative, it is relative to the bottom of
  3174. // the page.
  3175. func (f *Fpdf) SetY(y float64) {
  3176. // dbg("SetY x %.2f, lMargin %.2f", f.x, f.lMargin)
  3177. f.x = f.lMargin
  3178. if y >= 0 {
  3179. f.y = y
  3180. } else {
  3181. f.y = f.h + y
  3182. }
  3183. }
  3184. // SetHomeXY is a convenience method that sets the current position to the left
  3185. // and top margins.
  3186. func (f *Fpdf) SetHomeXY() {
  3187. f.SetY(f.tMargin)
  3188. f.SetX(f.lMargin)
  3189. }
  3190. // SetXY defines the abscissa and ordinate of the current position. If the
  3191. // passed values are negative, they are relative respectively to the right and
  3192. // bottom of the page.
  3193. func (f *Fpdf) SetXY(x, y float64) {
  3194. f.SetY(y)
  3195. f.SetX(x)
  3196. }
  3197. // SetProtection applies certain constraints on the finished PDF document.
  3198. //
  3199. // actionFlag is a bitflag that controls various document operations.
  3200. // CnProtectPrint allows the document to be printed. CnProtectModify allows a
  3201. // document to be modified by a PDF editor. CnProtectCopy allows text and
  3202. // images to be copied into the system clipboard. CnProtectAnnotForms allows
  3203. // annotations and forms to be added by a PDF editor. These values can be
  3204. // combined by or-ing them together, for example,
  3205. // CnProtectCopy|CnProtectModify. This flag is advisory; not all PDF readers
  3206. // implement the constraints that this argument attempts to control.
  3207. //
  3208. // userPassStr specifies the password that will need to be provided to view the
  3209. // contents of the PDF. The permissions specified by actionFlag will apply.
  3210. //
  3211. // ownerPassStr specifies the password that will need to be provided to gain
  3212. // full access to the document regardless of the actionFlag value. An empty
  3213. // string for this argument will be replaced with a random value, effectively
  3214. // prohibiting full access to the document.
  3215. func (f *Fpdf) SetProtection(actionFlag byte, userPassStr, ownerPassStr string) {
  3216. if f.err != nil {
  3217. return
  3218. }
  3219. f.protect.setProtection(actionFlag, userPassStr, ownerPassStr)
  3220. }
  3221. // OutputAndClose sends the PDF document to the writer specified by w. This
  3222. // method will close both f and w, even if an error is detected and no document
  3223. // is produced.
  3224. func (f *Fpdf) OutputAndClose(w io.WriteCloser) error {
  3225. f.Output(w)
  3226. w.Close()
  3227. return f.err
  3228. }
  3229. // OutputFileAndClose creates or truncates the file specified by fileStr and
  3230. // writes the PDF document to it. This method will close f and the newly
  3231. // written file, even if an error is detected and no document is produced.
  3232. //
  3233. // Most examples demonstrate the use of this method.
  3234. func (f *Fpdf) OutputFileAndClose(fileStr string) error {
  3235. if f.err == nil {
  3236. pdfFile, err := os.Create(fileStr)
  3237. if err == nil {
  3238. f.Output(pdfFile)
  3239. pdfFile.Close()
  3240. } else {
  3241. f.err = err
  3242. }
  3243. }
  3244. return f.err
  3245. }
  3246. // Output sends the PDF document to the writer specified by w. No output will
  3247. // take place if an error has occurred in the document generation process. w
  3248. // remains open after this function returns. After returning, f is in a closed
  3249. // state and its methods should not be called.
  3250. func (f *Fpdf) Output(w io.Writer) error {
  3251. if f.err != nil {
  3252. return f.err
  3253. }
  3254. // dbg("Output")
  3255. if f.state < 3 {
  3256. f.Close()
  3257. }
  3258. _, err := f.buffer.WriteTo(w)
  3259. if err != nil {
  3260. f.err = err
  3261. }
  3262. return f.err
  3263. }
  3264. func (f *Fpdf) getpagesizestr(sizeStr string) (size SizeType) {
  3265. if f.err != nil {
  3266. return
  3267. }
  3268. sizeStr = strings.ToLower(sizeStr)
  3269. // dbg("Size [%s]", sizeStr)
  3270. var ok bool
  3271. size, ok = f.stdPageSizes[sizeStr]
  3272. if ok {
  3273. // dbg("found %s", sizeStr)
  3274. size.Wd /= f.k
  3275. size.Ht /= f.k
  3276. } else {
  3277. f.err = fmt.Errorf("unknown page size %s", sizeStr)
  3278. }
  3279. return
  3280. }
  3281. // GetPageSizeStr returns the SizeType for the given sizeStr (that is A4, A3, etc..)
  3282. func (f *Fpdf) GetPageSizeStr(sizeStr string) (size SizeType) {
  3283. return f.getpagesizestr(sizeStr)
  3284. }
  3285. func (f *Fpdf) _getpagesize(size SizeType) SizeType {
  3286. if size.Wd > size.Ht {
  3287. size.Wd, size.Ht = size.Ht, size.Wd
  3288. }
  3289. return size
  3290. }
  3291. func (f *Fpdf) beginpage(orientationStr string, size SizeType) {
  3292. if f.err != nil {
  3293. return
  3294. }
  3295. f.page++
  3296. // add the default page boxes, if any exist, to the page
  3297. f.pageBoxes[f.page] = make(map[string]PageBox)
  3298. for box, pb := range f.defPageBoxes {
  3299. f.pageBoxes[f.page][box] = pb
  3300. }
  3301. f.pages = append(f.pages, bytes.NewBufferString(""))
  3302. f.pageLinks = append(f.pageLinks, make([]linkType, 0, 0))
  3303. f.pageAttachments = append(f.pageAttachments, []annotationAttach{})
  3304. f.state = 2
  3305. f.x = f.lMargin
  3306. f.y = f.tMargin
  3307. f.fontFamily = ""
  3308. // Check page size and orientation
  3309. if orientationStr == "" {
  3310. orientationStr = f.defOrientation
  3311. } else {
  3312. orientationStr = strings.ToUpper(orientationStr[0:1])
  3313. }
  3314. if orientationStr != f.curOrientation || size.Wd != f.curPageSize.Wd || size.Ht != f.curPageSize.Ht {
  3315. // New size or orientation
  3316. if orientationStr == "P" {
  3317. f.w = size.Wd
  3318. f.h = size.Ht
  3319. } else {
  3320. f.w = size.Ht
  3321. f.h = size.Wd
  3322. }
  3323. f.wPt = f.w * f.k
  3324. f.hPt = f.h * f.k
  3325. f.pageBreakTrigger = f.h - f.bMargin
  3326. f.curOrientation = orientationStr
  3327. f.curPageSize = size
  3328. }
  3329. if orientationStr != f.defOrientation || size.Wd != f.defPageSize.Wd || size.Ht != f.defPageSize.Ht {
  3330. f.pageSizes[f.page] = SizeType{f.wPt, f.hPt}
  3331. }
  3332. return
  3333. }
  3334. func (f *Fpdf) endpage() {
  3335. f.EndLayer()
  3336. f.state = 1
  3337. }
  3338. // Load a font definition file from the given Reader
  3339. func (f *Fpdf) loadfont(r io.Reader) (def fontDefType) {
  3340. if f.err != nil {
  3341. return
  3342. }
  3343. // dbg("Loading font [%s]", fontStr)
  3344. var buf bytes.Buffer
  3345. _, err := buf.ReadFrom(r)
  3346. if err != nil {
  3347. f.err = err
  3348. return
  3349. }
  3350. err = json.Unmarshal(buf.Bytes(), &def)
  3351. if err != nil {
  3352. f.err = err
  3353. return
  3354. }
  3355. if def.i, err = generateFontID(def); err != nil {
  3356. f.err = err
  3357. }
  3358. // dump(def)
  3359. return
  3360. }
  3361. // Escape special characters in strings
  3362. func (f *Fpdf) escape(s string) string {
  3363. s = strings.Replace(s, "\\", "\\\\", -1)
  3364. s = strings.Replace(s, "(", "\\(", -1)
  3365. s = strings.Replace(s, ")", "\\)", -1)
  3366. s = strings.Replace(s, "\r", "\\r", -1)
  3367. return s
  3368. }
  3369. // textstring formats a text string
  3370. func (f *Fpdf) textstring(s string) string {
  3371. if f.protect.encrypted {
  3372. b := []byte(s)
  3373. f.protect.rc4(uint32(f.n), &b)
  3374. s = string(b)
  3375. }
  3376. return "(" + f.escape(s) + ")"
  3377. }
  3378. func blankCount(str string) (count int) {
  3379. l := len(str)
  3380. for j := 0; j < l; j++ {
  3381. if byte(' ') == str[j] {
  3382. count++
  3383. }
  3384. }
  3385. return
  3386. }
  3387. // SetUnderlineThickness accepts a multiplier for adjusting the text underline
  3388. // thickness, defaulting to 1. See SetUnderlineThickness example.
  3389. func (f *Fpdf) SetUnderlineThickness(thickness float64) {
  3390. f.userUnderlineThickness = thickness
  3391. }
  3392. // Underline text
  3393. func (f *Fpdf) dounderline(x, y float64, txt string) string {
  3394. up := float64(f.currentFont.Up)
  3395. ut := float64(f.currentFont.Ut) * f.userUnderlineThickness
  3396. w := f.GetStringWidth(txt) + f.ws*float64(blankCount(txt))
  3397. return sprintf("%.2f %.2f %.2f %.2f re f", x*f.k,
  3398. (f.h-(y-up/1000*f.fontSize))*f.k, w*f.k, -ut/1000*f.fontSizePt)
  3399. }
  3400. func (f *Fpdf) dostrikeout(x, y float64, txt string) string {
  3401. up := float64(f.currentFont.Up)
  3402. ut := float64(f.currentFont.Ut)
  3403. w := f.GetStringWidth(txt) + f.ws*float64(blankCount(txt))
  3404. return sprintf("%.2f %.2f %.2f %.2f re f", x*f.k,
  3405. (f.h-(y+4*up/1000*f.fontSize))*f.k, w*f.k, -ut/1000*f.fontSizePt)
  3406. }
  3407. func bufEqual(buf []byte, str string) bool {
  3408. return string(buf[0:len(str)]) == str
  3409. }
  3410. func be16(buf []byte) int {
  3411. return 256*int(buf[0]) + int(buf[1])
  3412. }
  3413. func (f *Fpdf) newImageInfo() *ImageInfoType {
  3414. // default dpi to 72 unless told otherwise
  3415. return &ImageInfoType{scale: f.k, dpi: 72}
  3416. }
  3417. // parsejpg extracts info from io.Reader with JPEG data
  3418. // Thank you, Bruno Michel, for providing this code.
  3419. func (f *Fpdf) parsejpg(r io.Reader) (info *ImageInfoType) {
  3420. info = f.newImageInfo()
  3421. var (
  3422. data bytes.Buffer
  3423. err error
  3424. )
  3425. _, err = data.ReadFrom(r)
  3426. if err != nil {
  3427. f.err = err
  3428. return
  3429. }
  3430. info.data = data.Bytes()
  3431. config, err := jpeg.DecodeConfig(bytes.NewReader(info.data))
  3432. if err != nil {
  3433. f.err = err
  3434. return
  3435. }
  3436. info.w = float64(config.Width)
  3437. info.h = float64(config.Height)
  3438. info.f = "DCTDecode"
  3439. info.bpc = 8
  3440. switch config.ColorModel {
  3441. case color.GrayModel:
  3442. info.cs = "DeviceGray"
  3443. case color.YCbCrModel:
  3444. info.cs = "DeviceRGB"
  3445. case color.CMYKModel:
  3446. info.cs = "DeviceCMYK"
  3447. default:
  3448. f.err = fmt.Errorf("image JPEG buffer has unsupported color space (%v)", config.ColorModel)
  3449. return
  3450. }
  3451. return
  3452. }
  3453. // parsepng extracts info from a PNG data
  3454. func (f *Fpdf) parsepng(r io.Reader, readdpi bool) (info *ImageInfoType) {
  3455. buf, err := bufferFromReader(r)
  3456. if err != nil {
  3457. f.err = err
  3458. return
  3459. }
  3460. return f.parsepngstream(buf, readdpi)
  3461. }
  3462. func (f *Fpdf) readBeInt32(r io.Reader) (val int32) {
  3463. err := binary.Read(r, binary.BigEndian, &val)
  3464. if err != nil && err != io.EOF {
  3465. f.err = err
  3466. }
  3467. return
  3468. }
  3469. func (f *Fpdf) readByte(r io.Reader) (val byte) {
  3470. err := binary.Read(r, binary.BigEndian, &val)
  3471. if err != nil {
  3472. f.err = err
  3473. }
  3474. return
  3475. }
  3476. // parsegif extracts info from a GIF data (via PNG conversion)
  3477. func (f *Fpdf) parsegif(r io.Reader) (info *ImageInfoType) {
  3478. data, err := bufferFromReader(r)
  3479. if err != nil {
  3480. f.err = err
  3481. return
  3482. }
  3483. var img image.Image
  3484. img, err = gif.Decode(data)
  3485. if err != nil {
  3486. f.err = err
  3487. return
  3488. }
  3489. pngBuf := new(bytes.Buffer)
  3490. err = png.Encode(pngBuf, img)
  3491. if err != nil {
  3492. f.err = err
  3493. return
  3494. }
  3495. return f.parsepngstream(pngBuf, false)
  3496. }
  3497. // newobj begins a new object
  3498. func (f *Fpdf) newobj() {
  3499. // dbg("newobj")
  3500. f.n++
  3501. for j := len(f.offsets); j <= f.n; j++ {
  3502. f.offsets = append(f.offsets, 0)
  3503. }
  3504. f.offsets[f.n] = f.buffer.Len()
  3505. f.outf("%d 0 obj", f.n)
  3506. }
  3507. func (f *Fpdf) putstream(b []byte) {
  3508. // dbg("putstream")
  3509. if f.protect.encrypted {
  3510. f.protect.rc4(uint32(f.n), &b)
  3511. }
  3512. f.out("stream")
  3513. f.out(string(b))
  3514. f.out("endstream")
  3515. }
  3516. // out; Add a line to the document
  3517. func (f *Fpdf) out(s string) {
  3518. if f.state == 2 {
  3519. f.pages[f.page].WriteString(s)
  3520. f.pages[f.page].WriteString("\n")
  3521. } else {
  3522. f.buffer.WriteString(s)
  3523. f.buffer.WriteString("\n")
  3524. }
  3525. }
  3526. // outbuf adds a buffered line to the document
  3527. func (f *Fpdf) outbuf(r io.Reader) {
  3528. if f.state == 2 {
  3529. f.pages[f.page].ReadFrom(r)
  3530. f.pages[f.page].WriteString("\n")
  3531. } else {
  3532. f.buffer.ReadFrom(r)
  3533. f.buffer.WriteString("\n")
  3534. }
  3535. }
  3536. // RawWriteStr writes a string directly to the PDF generation buffer. This is a
  3537. // low-level function that is not required for normal PDF construction. An
  3538. // understanding of the PDF specification is needed to use this method
  3539. // correctly.
  3540. func (f *Fpdf) RawWriteStr(str string) {
  3541. f.out(str)
  3542. }
  3543. // RawWriteBuf writes the contents of the specified buffer directly to the PDF
  3544. // generation buffer. This is a low-level function that is not required for
  3545. // normal PDF construction. An understanding of the PDF specification is needed
  3546. // to use this method correctly.
  3547. func (f *Fpdf) RawWriteBuf(r io.Reader) {
  3548. f.outbuf(r)
  3549. }
  3550. // outf adds a formatted line to the document
  3551. func (f *Fpdf) outf(fmtStr string, args ...interface{}) {
  3552. f.out(sprintf(fmtStr, args...))
  3553. }
  3554. // SetDefaultCatalogSort sets the default value of the catalog sort flag that
  3555. // will be used when initializing a new Fpdf instance. See SetCatalogSort() for
  3556. // more details.
  3557. func SetDefaultCatalogSort(flag bool) {
  3558. gl.catalogSort = flag
  3559. }
  3560. // SetCatalogSort sets a flag that will be used, if true, to consistently order
  3561. // the document's internal resource catalogs. This method is typically only
  3562. // used for test purposes to facilitate PDF comparison.
  3563. func (f *Fpdf) SetCatalogSort(flag bool) {
  3564. f.catalogSort = flag
  3565. }
  3566. // SetDefaultCreationDate sets the default value of the document creation date
  3567. // that will be used when initializing a new Fpdf instance. See
  3568. // SetCreationDate() for more details.
  3569. func SetDefaultCreationDate(tm time.Time) {
  3570. gl.creationDate = tm
  3571. }
  3572. // SetDefaultModificationDate sets the default value of the document modification date
  3573. // that will be used when initializing a new Fpdf instance. See
  3574. // SetCreationDate() for more details.
  3575. func SetDefaultModificationDate(tm time.Time) {
  3576. gl.modDate = tm
  3577. }
  3578. // SetCreationDate fixes the document's internal CreationDate value. By
  3579. // default, the time when the document is generated is used for this value.
  3580. // This method is typically only used for testing purposes to facilitate PDF
  3581. // comparison. Specify a zero-value time to revert to the default behavior.
  3582. func (f *Fpdf) SetCreationDate(tm time.Time) {
  3583. f.creationDate = tm
  3584. }
  3585. // SetModificationDate fixes the document's internal ModDate value.
  3586. // See `SetCreationDate` for more details.
  3587. func (f *Fpdf) SetModificationDate(tm time.Time) {
  3588. f.modDate = tm
  3589. }
  3590. // SetJavascript adds Adobe JavaScript to the document.
  3591. func (f *Fpdf) SetJavascript(script string) {
  3592. f.javascript = &script
  3593. }
  3594. // RegisterAlias adds an (alias, replacement) pair to the document so we can
  3595. // replace all occurrences of that alias after writing but before the document
  3596. // is closed. Functions ExampleFpdf_RegisterAlias() and
  3597. // ExampleFpdf_RegisterAlias_utf8() in fpdf_test.go demonstrate this method.
  3598. func (f *Fpdf) RegisterAlias(alias, replacement string) {
  3599. // Note: map[string]string assignments embed literal escape ("\00") sequences
  3600. // into utf16 key and value strings. Consequently, subsequent search/replace
  3601. // operations will fail unexpectedly if utf8toutf16() conversions take place
  3602. // here. Instead, conversions are deferred until the actual search/replace
  3603. // operation takes place when the PDF output is generated.
  3604. f.aliasMap[alias] = replacement
  3605. }
  3606. func (f *Fpdf) replaceAliases() {
  3607. for mode := 0; mode < 2; mode++ {
  3608. for alias, replacement := range f.aliasMap {
  3609. if mode == 1 {
  3610. alias = utf8toutf16(alias, false)
  3611. replacement = utf8toutf16(replacement, false)
  3612. }
  3613. for n := 1; n <= f.page; n++ {
  3614. s := f.pages[n].String()
  3615. if strings.Contains(s, alias) {
  3616. s = strings.Replace(s, alias, replacement, -1)
  3617. f.pages[n].Truncate(0)
  3618. f.pages[n].WriteString(s)
  3619. }
  3620. }
  3621. }
  3622. }
  3623. }
  3624. func (f *Fpdf) putpages() {
  3625. var wPt, hPt float64
  3626. var pageSize SizeType
  3627. var ok bool
  3628. nb := f.page
  3629. if len(f.aliasNbPagesStr) > 0 {
  3630. // Replace number of pages
  3631. f.RegisterAlias(f.aliasNbPagesStr, sprintf("%d", nb))
  3632. }
  3633. f.replaceAliases()
  3634. if f.defOrientation == "P" {
  3635. wPt = f.defPageSize.Wd * f.k
  3636. hPt = f.defPageSize.Ht * f.k
  3637. } else {
  3638. wPt = f.defPageSize.Ht * f.k
  3639. hPt = f.defPageSize.Wd * f.k
  3640. }
  3641. pagesObjectNumbers := make([]int, nb+1) // 1-based
  3642. for n := 1; n <= nb; n++ {
  3643. // Page
  3644. f.newobj()
  3645. pagesObjectNumbers[n] = f.n // save for /Kids
  3646. f.out("<</Type /Page")
  3647. f.out("/Parent 1 0 R")
  3648. pageSize, ok = f.pageSizes[n]
  3649. if ok {
  3650. f.outf("/MediaBox [0 0 %.2f %.2f]", pageSize.Wd, pageSize.Ht)
  3651. }
  3652. for t, pb := range f.pageBoxes[n] {
  3653. f.outf("/%s [%.2f %.2f %.2f %.2f]", t, pb.X, pb.Y, pb.Wd, pb.Ht)
  3654. }
  3655. f.out("/Resources 2 0 R")
  3656. // Links
  3657. if len(f.pageLinks[n])+len(f.pageAttachments[n]) > 0 {
  3658. var annots fmtBuffer
  3659. annots.printf("/Annots [")
  3660. for _, pl := range f.pageLinks[n] {
  3661. annots.printf("<</Type /Annot /Subtype /Link /Rect [%.2f %.2f %.2f %.2f] /Border [0 0 0] ",
  3662. pl.x, pl.y, pl.x+pl.wd, pl.y-pl.ht)
  3663. if pl.link == 0 {
  3664. annots.printf("/A <</S /URI /URI %s>>>>", f.textstring(pl.linkStr))
  3665. } else {
  3666. l := f.links[pl.link]
  3667. var sz SizeType
  3668. var h float64
  3669. sz, ok = f.pageSizes[l.page]
  3670. if ok {
  3671. h = sz.Ht
  3672. } else {
  3673. h = hPt
  3674. }
  3675. // dbg("h [%.2f], l.y [%.2f] f.k [%.2f]\n", h, l.y, f.k)
  3676. annots.printf("/Dest [%d 0 R /XYZ 0 %.2f null]>>", 1+2*l.page, h-l.y*f.k)
  3677. }
  3678. }
  3679. f.putAttachmentAnnotationLinks(&annots, n)
  3680. annots.printf("]")
  3681. f.out(annots.String())
  3682. }
  3683. if f.pdfVersion > "1.3" {
  3684. f.out("/Group <</Type /Group /S /Transparency /CS /DeviceRGB>>")
  3685. }
  3686. f.outf("/Contents %d 0 R>>", f.n+1)
  3687. f.out("endobj")
  3688. // Page content
  3689. f.newobj()
  3690. if f.compress {
  3691. data := sliceCompress(f.pages[n].Bytes())
  3692. f.outf("<</Filter /FlateDecode /Length %d>>", len(data))
  3693. f.putstream(data)
  3694. } else {
  3695. f.outf("<</Length %d>>", f.pages[n].Len())
  3696. f.putstream(f.pages[n].Bytes())
  3697. }
  3698. f.out("endobj")
  3699. }
  3700. // Pages root
  3701. f.offsets[1] = f.buffer.Len()
  3702. f.out("1 0 obj")
  3703. f.out("<</Type /Pages")
  3704. var kids fmtBuffer
  3705. kids.printf("/Kids [")
  3706. for i := 1; i <= nb; i++ {
  3707. kids.printf("%d 0 R ", pagesObjectNumbers[i])
  3708. }
  3709. kids.printf("]")
  3710. f.out(kids.String())
  3711. f.outf("/Count %d", nb)
  3712. f.outf("/MediaBox [0 0 %.2f %.2f]", wPt, hPt)
  3713. f.out(">>")
  3714. f.out("endobj")
  3715. }
  3716. func (f *Fpdf) putfonts() {
  3717. if f.err != nil {
  3718. return
  3719. }
  3720. nf := f.n
  3721. for _, diff := range f.diffs {
  3722. // Encodings
  3723. f.newobj()
  3724. f.outf("<</Type /Encoding /BaseEncoding /WinAnsiEncoding /Differences [%s]>>", diff)
  3725. f.out("endobj")
  3726. }
  3727. {
  3728. var fileList []string
  3729. var info fontFileType
  3730. var file string
  3731. for file = range f.fontFiles {
  3732. fileList = append(fileList, file)
  3733. }
  3734. if f.catalogSort {
  3735. sort.SliceStable(fileList, func(i, j int) bool { return fileList[i] < fileList[j] })
  3736. }
  3737. for _, file = range fileList {
  3738. info = f.fontFiles[file]
  3739. if info.fontType != "UTF8" {
  3740. f.newobj()
  3741. info.n = f.n
  3742. f.fontFiles[file] = info
  3743. var font []byte
  3744. if info.embedded {
  3745. font = info.content
  3746. } else {
  3747. var err error
  3748. font, err = f.loadFontFile(file)
  3749. if err != nil {
  3750. f.err = err
  3751. return
  3752. }
  3753. }
  3754. compressed := file[len(file)-2:] == ".z"
  3755. if !compressed && info.length2 > 0 {
  3756. buf := font[6:info.length1]
  3757. buf = append(buf, font[6+info.length1+6:info.length2]...)
  3758. font = buf
  3759. }
  3760. f.outf("<</Length %d", len(font))
  3761. if compressed {
  3762. f.out("/Filter /FlateDecode")
  3763. }
  3764. f.outf("/Length1 %d", info.length1)
  3765. if info.length2 > 0 {
  3766. f.outf("/Length2 %d /Length3 0", info.length2)
  3767. }
  3768. f.out(">>")
  3769. f.putstream(font)
  3770. f.out("endobj")
  3771. }
  3772. }
  3773. }
  3774. {
  3775. var keyList []string
  3776. var font fontDefType
  3777. var key string
  3778. for key = range f.fonts {
  3779. keyList = append(keyList, key)
  3780. }
  3781. if f.catalogSort {
  3782. sort.SliceStable(keyList, func(i, j int) bool { return keyList[i] < keyList[j] })
  3783. }
  3784. for _, key = range keyList {
  3785. font = f.fonts[key]
  3786. // Font objects
  3787. font.N = f.n + 1
  3788. f.fonts[key] = font
  3789. tp := font.Tp
  3790. name := font.Name
  3791. switch tp {
  3792. case "Core":
  3793. // Core font
  3794. f.newobj()
  3795. f.out("<</Type /Font")
  3796. f.outf("/BaseFont /%s", name)
  3797. f.out("/Subtype /Type1")
  3798. if name != "Symbol" && name != "ZapfDingbats" {
  3799. f.out("/Encoding /WinAnsiEncoding")
  3800. }
  3801. f.out(">>")
  3802. f.out("endobj")
  3803. case "Type1":
  3804. fallthrough
  3805. case "TrueType":
  3806. // Additional Type1 or TrueType/OpenType font
  3807. f.newobj()
  3808. f.out("<</Type /Font")
  3809. f.outf("/BaseFont /%s", name)
  3810. f.outf("/Subtype /%s", tp)
  3811. f.out("/FirstChar 32 /LastChar 255")
  3812. f.outf("/Widths %d 0 R", f.n+1)
  3813. f.outf("/FontDescriptor %d 0 R", f.n+2)
  3814. if font.DiffN > 0 {
  3815. f.outf("/Encoding %d 0 R", nf+font.DiffN)
  3816. } else {
  3817. f.out("/Encoding /WinAnsiEncoding")
  3818. }
  3819. f.out(">>")
  3820. f.out("endobj")
  3821. // Widths
  3822. f.newobj()
  3823. var s fmtBuffer
  3824. s.WriteString("[")
  3825. for j := 32; j < 256; j++ {
  3826. s.printf("%d ", font.Cw[j])
  3827. }
  3828. s.WriteString("]")
  3829. f.out(s.String())
  3830. f.out("endobj")
  3831. // Descriptor
  3832. f.newobj()
  3833. s.Truncate(0)
  3834. s.printf("<</Type /FontDescriptor /FontName /%s ", name)
  3835. s.printf("/Ascent %d ", font.Desc.Ascent)
  3836. s.printf("/Descent %d ", font.Desc.Descent)
  3837. s.printf("/CapHeight %d ", font.Desc.CapHeight)
  3838. s.printf("/Flags %d ", font.Desc.Flags)
  3839. s.printf("/FontBBox [%d %d %d %d] ", font.Desc.FontBBox.Xmin, font.Desc.FontBBox.Ymin,
  3840. font.Desc.FontBBox.Xmax, font.Desc.FontBBox.Ymax)
  3841. s.printf("/ItalicAngle %d ", font.Desc.ItalicAngle)
  3842. s.printf("/StemV %d ", font.Desc.StemV)
  3843. s.printf("/MissingWidth %d ", font.Desc.MissingWidth)
  3844. var suffix string
  3845. if tp != "Type1" {
  3846. suffix = "2"
  3847. }
  3848. s.printf("/FontFile%s %d 0 R>>", suffix, f.fontFiles[font.File].n)
  3849. f.out(s.String())
  3850. f.out("endobj")
  3851. case "UTF8":
  3852. fontName := "utf8" + font.Name
  3853. usedRunes := font.usedRunes
  3854. delete(usedRunes, 0)
  3855. utf8FontStream := font.utf8File.GenerateCutFont(usedRunes)
  3856. utf8FontSize := len(utf8FontStream)
  3857. compressedFontStream := sliceCompress(utf8FontStream)
  3858. CodeSignDictionary := font.utf8File.CodeSymbolDictionary
  3859. delete(CodeSignDictionary, 0)
  3860. f.newobj()
  3861. 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))
  3862. f.newobj()
  3863. f.out("<</Type /Font\n/Subtype /CIDFontType2\n/BaseFont /" + fontName + "\n" +
  3864. "/CIDSystemInfo " + strconv.Itoa(f.n+2) + " 0 R\n/FontDescriptor " + strconv.Itoa(f.n+3) + " 0 R")
  3865. if font.Desc.MissingWidth != 0 {
  3866. f.out("/DW " + strconv.Itoa(font.Desc.MissingWidth) + "")
  3867. }
  3868. f.generateCIDFontMap(&font, font.utf8File.LastRune)
  3869. f.out("/CIDToGIDMap " + strconv.Itoa(f.n+4) + " 0 R>>")
  3870. f.out("endobj")
  3871. f.newobj()
  3872. f.out("<</Length " + strconv.Itoa(len(toUnicode)) + ">>")
  3873. f.putstream([]byte(toUnicode))
  3874. f.out("endobj")
  3875. // CIDInfo
  3876. f.newobj()
  3877. f.out("<</Registry (Adobe)\n/Ordering (UCS)\n/Supplement 0>>")
  3878. f.out("endobj")
  3879. // Font descriptor
  3880. f.newobj()
  3881. var s fmtBuffer
  3882. s.printf("<</Type /FontDescriptor /FontName /%s\n /Ascent %d", fontName, font.Desc.Ascent)
  3883. s.printf(" /Descent %d", font.Desc.Descent)
  3884. s.printf(" /CapHeight %d", font.Desc.CapHeight)
  3885. v := font.Desc.Flags
  3886. v = v | 4
  3887. v = v &^ 32
  3888. s.printf(" /Flags %d", v)
  3889. s.printf("/FontBBox [%d %d %d %d] ", font.Desc.FontBBox.Xmin, font.Desc.FontBBox.Ymin,
  3890. font.Desc.FontBBox.Xmax, font.Desc.FontBBox.Ymax)
  3891. s.printf(" /ItalicAngle %d", font.Desc.ItalicAngle)
  3892. s.printf(" /StemV %d", font.Desc.StemV)
  3893. s.printf(" /MissingWidth %d", font.Desc.MissingWidth)
  3894. s.printf("/FontFile2 %d 0 R", f.n+2)
  3895. s.printf(">>")
  3896. f.out(s.String())
  3897. f.out("endobj")
  3898. // Embed CIDToGIDMap
  3899. cidToGidMap := make([]byte, 256*256*2)
  3900. for cc, glyph := range CodeSignDictionary {
  3901. cidToGidMap[cc*2] = byte(glyph >> 8)
  3902. cidToGidMap[cc*2+1] = byte(glyph & 0xFF)
  3903. }
  3904. cidToGidMap = sliceCompress(cidToGidMap)
  3905. f.newobj()
  3906. f.out("<</Length " + strconv.Itoa(len(cidToGidMap)) + "/Filter /FlateDecode>>")
  3907. f.putstream(cidToGidMap)
  3908. f.out("endobj")
  3909. //Font file
  3910. f.newobj()
  3911. f.out("<</Length " + strconv.Itoa(len(compressedFontStream)))
  3912. f.out("/Filter /FlateDecode")
  3913. f.out("/Length1 " + strconv.Itoa(utf8FontSize))
  3914. f.out(">>")
  3915. f.putstream(compressedFontStream)
  3916. f.out("endobj")
  3917. default:
  3918. f.err = fmt.Errorf("unsupported font type: %s", tp)
  3919. return
  3920. }
  3921. }
  3922. }
  3923. return
  3924. }
  3925. func (f *Fpdf) generateCIDFontMap(font *fontDefType, LastRune int) {
  3926. rangeID := 0
  3927. cidArray := make(map[int]*untypedKeyMap)
  3928. cidArrayKeys := make([]int, 0)
  3929. prevCid := -2
  3930. prevWidth := -1
  3931. interval := false
  3932. startCid := 1
  3933. cwLen := LastRune + 1
  3934. // for each character
  3935. for cid := startCid; cid < cwLen; cid++ {
  3936. if font.Cw[cid] == 0x00 {
  3937. continue
  3938. }
  3939. width := font.Cw[cid]
  3940. if width == 65535 {
  3941. width = 0
  3942. }
  3943. if numb, OK := font.usedRunes[cid]; cid > 255 && (!OK || numb == 0) {
  3944. continue
  3945. }
  3946. if cid == prevCid+1 {
  3947. if width == prevWidth {
  3948. if width == cidArray[rangeID].get(0) {
  3949. cidArray[rangeID].put(nil, width)
  3950. } else {
  3951. cidArray[rangeID].pop()
  3952. rangeID = prevCid
  3953. r := untypedKeyMap{
  3954. valueSet: make([]int, 0),
  3955. keySet: make([]interface{}, 0),
  3956. }
  3957. cidArray[rangeID] = &r
  3958. cidArrayKeys = append(cidArrayKeys, rangeID)
  3959. cidArray[rangeID].put(nil, prevWidth)
  3960. cidArray[rangeID].put(nil, width)
  3961. }
  3962. interval = true
  3963. cidArray[rangeID].put("interval", 1)
  3964. } else {
  3965. if interval {
  3966. // new range
  3967. rangeID = cid
  3968. r := untypedKeyMap{
  3969. valueSet: make([]int, 0),
  3970. keySet: make([]interface{}, 0),
  3971. }
  3972. cidArray[rangeID] = &r
  3973. cidArrayKeys = append(cidArrayKeys, rangeID)
  3974. cidArray[rangeID].put(nil, width)
  3975. } else {
  3976. cidArray[rangeID].put(nil, width)
  3977. }
  3978. interval = false
  3979. }
  3980. } else {
  3981. rangeID = cid
  3982. r := untypedKeyMap{
  3983. valueSet: make([]int, 0),
  3984. keySet: make([]interface{}, 0),
  3985. }
  3986. cidArray[rangeID] = &r
  3987. cidArrayKeys = append(cidArrayKeys, rangeID)
  3988. cidArray[rangeID].put(nil, width)
  3989. interval = false
  3990. }
  3991. prevCid = cid
  3992. prevWidth = width
  3993. }
  3994. previousKey := -1
  3995. nextKey := -1
  3996. isInterval := false
  3997. for g := 0; g < len(cidArrayKeys); {
  3998. key := cidArrayKeys[g]
  3999. ws := *cidArray[key]
  4000. cws := len(ws.keySet)
  4001. if (key == nextKey) && (!isInterval) && (ws.getIndex("interval") < 0 || cws < 4) {
  4002. if cidArray[key].getIndex("interval") >= 0 {
  4003. cidArray[key].delete("interval")
  4004. }
  4005. cidArray[previousKey] = arrayMerge(cidArray[previousKey], cidArray[key])
  4006. cidArrayKeys = remove(cidArrayKeys, key)
  4007. } else {
  4008. g++
  4009. previousKey = key
  4010. }
  4011. nextKey = key + cws
  4012. // ui := ws.getIndex("interval")
  4013. // ui = ui + 1
  4014. if ws.getIndex("interval") >= 0 {
  4015. if cws > 3 {
  4016. isInterval = true
  4017. } else {
  4018. isInterval = false
  4019. }
  4020. cidArray[key].delete("interval")
  4021. nextKey--
  4022. } else {
  4023. isInterval = false
  4024. }
  4025. }
  4026. var w fmtBuffer
  4027. for _, k := range cidArrayKeys {
  4028. ws := cidArray[k]
  4029. if len(arrayCountValues(ws.valueSet)) == 1 {
  4030. w.printf(" %d %d %d", k, k+len(ws.valueSet)-1, ws.get(0))
  4031. } else {
  4032. w.printf(" %d [ %s ]\n", k, implode(" ", ws.valueSet))
  4033. }
  4034. }
  4035. f.out("/W [" + w.String() + " ]")
  4036. }
  4037. func implode(sep string, arr []int) string {
  4038. var s fmtBuffer
  4039. for i := 0; i < len(arr)-1; i++ {
  4040. s.printf("%v", arr[i])
  4041. s.printf(sep)
  4042. }
  4043. if len(arr) > 0 {
  4044. s.printf("%v", arr[len(arr)-1])
  4045. }
  4046. return s.String()
  4047. }
  4048. // arrayCountValues counts the occurrences of each item in the $mp array.
  4049. func arrayCountValues(mp []int) map[int]int {
  4050. answer := make(map[int]int)
  4051. for _, v := range mp {
  4052. answer[v] = answer[v] + 1
  4053. }
  4054. return answer
  4055. }
  4056. func (f *Fpdf) loadFontFile(name string) ([]byte, error) {
  4057. if f.fontLoader != nil {
  4058. reader, err := f.fontLoader.Open(name)
  4059. if err == nil {
  4060. data, err := ioutil.ReadAll(reader)
  4061. if closer, ok := reader.(io.Closer); ok {
  4062. closer.Close()
  4063. }
  4064. return data, err
  4065. }
  4066. }
  4067. return ioutil.ReadFile(path.Join(f.fontpath, name))
  4068. }
  4069. func (f *Fpdf) putimages() {
  4070. var keyList []string
  4071. var key string
  4072. for key = range f.images {
  4073. keyList = append(keyList, key)
  4074. }
  4075. // Sort the keyList []string by the corresponding image's width.
  4076. if f.catalogSort {
  4077. sort.SliceStable(keyList, func(i, j int) bool { return f.images[keyList[i]].w < f.images[keyList[j]].w })
  4078. }
  4079. // Maintain a list of inserted image SHA-1 hashes, with their
  4080. // corresponding object ID number.
  4081. insertedImages := map[string]int{}
  4082. for _, key = range keyList {
  4083. image := f.images[key]
  4084. // Check if this image has already been inserted using it's SHA-1 hash.
  4085. insertedImageObjN, isFound := insertedImages[image.i]
  4086. // If found, skip inserting the image as a new object, and
  4087. // use the object ID from the insertedImages map.
  4088. // If not, insert the image into the PDF and store the object ID.
  4089. if isFound {
  4090. image.n = insertedImageObjN
  4091. } else {
  4092. f.putimage(image)
  4093. insertedImages[image.i] = image.n
  4094. }
  4095. }
  4096. }
  4097. func (f *Fpdf) putimage(info *ImageInfoType) {
  4098. f.newobj()
  4099. info.n = f.n
  4100. f.out("<</Type /XObject")
  4101. f.out("/Subtype /Image")
  4102. f.outf("/Width %d", int(info.w))
  4103. f.outf("/Height %d", int(info.h))
  4104. if info.cs == "Indexed" {
  4105. f.outf("/ColorSpace [/Indexed /DeviceRGB %d %d 0 R]", len(info.pal)/3-1, f.n+1)
  4106. } else {
  4107. f.outf("/ColorSpace /%s", info.cs)
  4108. if info.cs == "DeviceCMYK" {
  4109. f.out("/Decode [1 0 1 0 1 0 1 0]")
  4110. }
  4111. }
  4112. f.outf("/BitsPerComponent %d", info.bpc)
  4113. if len(info.f) > 0 {
  4114. f.outf("/Filter /%s", info.f)
  4115. }
  4116. if len(info.dp) > 0 {
  4117. f.outf("/DecodeParms <<%s>>", info.dp)
  4118. }
  4119. if len(info.trns) > 0 {
  4120. var trns fmtBuffer
  4121. for _, v := range info.trns {
  4122. trns.printf("%d %d ", v, v)
  4123. }
  4124. f.outf("/Mask [%s]", trns.String())
  4125. }
  4126. if info.smask != nil {
  4127. f.outf("/SMask %d 0 R", f.n+1)
  4128. }
  4129. f.outf("/Length %d>>", len(info.data))
  4130. f.putstream(info.data)
  4131. f.out("endobj")
  4132. // Soft mask
  4133. if len(info.smask) > 0 {
  4134. smask := &ImageInfoType{
  4135. w: info.w,
  4136. h: info.h,
  4137. cs: "DeviceGray",
  4138. bpc: 8,
  4139. f: info.f,
  4140. dp: sprintf("/Predictor 15 /Colors 1 /BitsPerComponent 8 /Columns %d", int(info.w)),
  4141. data: info.smask,
  4142. scale: f.k,
  4143. }
  4144. f.putimage(smask)
  4145. }
  4146. // Palette
  4147. if info.cs == "Indexed" {
  4148. f.newobj()
  4149. if f.compress {
  4150. pal := sliceCompress(info.pal)
  4151. f.outf("<</Filter /FlateDecode /Length %d>>", len(pal))
  4152. f.putstream(pal)
  4153. } else {
  4154. f.outf("<</Length %d>>", len(info.pal))
  4155. f.putstream(info.pal)
  4156. }
  4157. f.out("endobj")
  4158. }
  4159. }
  4160. func (f *Fpdf) putxobjectdict() {
  4161. {
  4162. var image *ImageInfoType
  4163. var key string
  4164. var keyList []string
  4165. for key = range f.images {
  4166. keyList = append(keyList, key)
  4167. }
  4168. if f.catalogSort {
  4169. sort.SliceStable(keyList, func(i, j int) bool { return f.images[keyList[i]].i < f.images[keyList[j]].i })
  4170. }
  4171. for _, key = range keyList {
  4172. image = f.images[key]
  4173. f.outf("/I%s %d 0 R", image.i, image.n)
  4174. }
  4175. }
  4176. {
  4177. var keyList []string
  4178. var key string
  4179. var tpl Template
  4180. keyList = templateKeyList(f.templates, f.catalogSort)
  4181. for _, key = range keyList {
  4182. tpl = f.templates[key]
  4183. // for _, tpl := range f.templates {
  4184. id := tpl.ID()
  4185. if objID, ok := f.templateObjects[id]; ok {
  4186. f.outf("/TPL%s %d 0 R", id, objID)
  4187. }
  4188. }
  4189. }
  4190. {
  4191. for tplName, objID := range f.importedTplObjs {
  4192. // here replace obj id hash with n
  4193. f.outf("%s %d 0 R", tplName, f.importedTplIDs[objID])
  4194. }
  4195. }
  4196. }
  4197. func (f *Fpdf) putresourcedict() {
  4198. f.out("/ProcSet [/PDF /Text /ImageB /ImageC /ImageI]")
  4199. f.out("/Font <<")
  4200. {
  4201. var keyList []string
  4202. var font fontDefType
  4203. var key string
  4204. for key = range f.fonts {
  4205. keyList = append(keyList, key)
  4206. }
  4207. if f.catalogSort {
  4208. sort.SliceStable(keyList, func(i, j int) bool { return f.fonts[keyList[i]].i < f.fonts[keyList[j]].i })
  4209. }
  4210. for _, key = range keyList {
  4211. font = f.fonts[key]
  4212. f.outf("/F%s %d 0 R", font.i, font.N)
  4213. }
  4214. }
  4215. f.out(">>")
  4216. f.out("/XObject <<")
  4217. f.putxobjectdict()
  4218. f.out(">>")
  4219. count := len(f.blendList)
  4220. if count > 1 {
  4221. f.out("/ExtGState <<")
  4222. for j := 1; j < count; j++ {
  4223. f.outf("/GS%d %d 0 R", j, f.blendList[j].objNum)
  4224. }
  4225. f.out(">>")
  4226. }
  4227. count = len(f.gradientList)
  4228. if count > 1 {
  4229. f.out("/Shading <<")
  4230. for j := 1; j < count; j++ {
  4231. f.outf("/Sh%d %d 0 R", j, f.gradientList[j].objNum)
  4232. }
  4233. f.out(">>")
  4234. }
  4235. // Layers
  4236. f.layerPutResourceDict()
  4237. f.spotColorPutResourceDict()
  4238. }
  4239. func (f *Fpdf) putBlendModes() {
  4240. count := len(f.blendList)
  4241. for j := 1; j < count; j++ {
  4242. bl := f.blendList[j]
  4243. f.newobj()
  4244. f.blendList[j].objNum = f.n
  4245. f.outf("<</Type /ExtGState /ca %s /CA %s /BM /%s>>",
  4246. bl.fillStr, bl.strokeStr, bl.modeStr)
  4247. f.out("endobj")
  4248. }
  4249. }
  4250. func (f *Fpdf) putGradients() {
  4251. count := len(f.gradientList)
  4252. for j := 1; j < count; j++ {
  4253. var f1 int
  4254. gr := f.gradientList[j]
  4255. if gr.tp == 2 || gr.tp == 3 {
  4256. f.newobj()
  4257. f.outf("<</FunctionType 2 /Domain [0.0 1.0] /C0 [%s] /C1 [%s] /N 1>>", gr.clr1Str, gr.clr2Str)
  4258. f.out("endobj")
  4259. f1 = f.n
  4260. }
  4261. f.newobj()
  4262. f.outf("<</ShadingType %d /ColorSpace /DeviceRGB", gr.tp)
  4263. if gr.tp == 2 {
  4264. f.outf("/Coords [%.5f %.5f %.5f %.5f] /Function %d 0 R /Extend [true true]>>",
  4265. gr.x1, gr.y1, gr.x2, gr.y2, f1)
  4266. } else if gr.tp == 3 {
  4267. f.outf("/Coords [%.5f %.5f 0 %.5f %.5f %.5f] /Function %d 0 R /Extend [true true]>>",
  4268. gr.x1, gr.y1, gr.x2, gr.y2, gr.r, f1)
  4269. }
  4270. f.out("endobj")
  4271. f.gradientList[j].objNum = f.n
  4272. }
  4273. }
  4274. func (f *Fpdf) putjavascript() {
  4275. if f.javascript == nil {
  4276. return
  4277. }
  4278. f.newobj()
  4279. f.nJs = f.n
  4280. f.out("<<")
  4281. f.outf("/Names [(EmbeddedJS) %d 0 R]", f.n+1)
  4282. f.out(">>")
  4283. f.out("endobj")
  4284. f.newobj()
  4285. f.out("<<")
  4286. f.out("/S /JavaScript")
  4287. f.outf("/JS %s", f.textstring(*f.javascript))
  4288. f.out(">>")
  4289. f.out("endobj")
  4290. }
  4291. func (f *Fpdf) putresources() {
  4292. if f.err != nil {
  4293. return
  4294. }
  4295. f.layerPutLayers()
  4296. f.putBlendModes()
  4297. f.putGradients()
  4298. f.putSpotColors()
  4299. f.putfonts()
  4300. if f.err != nil {
  4301. return
  4302. }
  4303. f.putimages()
  4304. f.putTemplates()
  4305. f.putImportedTemplates() // gofpdi
  4306. // Resource dictionary
  4307. f.offsets[2] = f.buffer.Len()
  4308. f.out("2 0 obj")
  4309. f.out("<<")
  4310. f.putresourcedict()
  4311. f.out(">>")
  4312. f.out("endobj")
  4313. f.putjavascript()
  4314. if f.protect.encrypted {
  4315. f.newobj()
  4316. f.protect.objNum = f.n
  4317. f.out("<<")
  4318. f.out("/Filter /Standard")
  4319. f.out("/V 1")
  4320. f.out("/R 2")
  4321. f.outf("/O (%s)", f.escape(string(f.protect.oValue)))
  4322. f.outf("/U (%s)", f.escape(string(f.protect.uValue)))
  4323. f.outf("/P %d", f.protect.pValue)
  4324. f.out(">>")
  4325. f.out("endobj")
  4326. }
  4327. return
  4328. }
  4329. // returns Now() if tm is zero
  4330. func timeOrNow(tm time.Time) time.Time {
  4331. if tm.IsZero() {
  4332. return time.Now()
  4333. }
  4334. return tm
  4335. }
  4336. func (f *Fpdf) putinfo() {
  4337. if len(f.producer) > 0 {
  4338. f.outf("/Producer %s", f.textstring(f.producer))
  4339. }
  4340. if len(f.title) > 0 {
  4341. f.outf("/Title %s", f.textstring(f.title))
  4342. }
  4343. if len(f.subject) > 0 {
  4344. f.outf("/Subject %s", f.textstring(f.subject))
  4345. }
  4346. if len(f.author) > 0 {
  4347. f.outf("/Author %s", f.textstring(f.author))
  4348. }
  4349. if len(f.keywords) > 0 {
  4350. f.outf("/Keywords %s", f.textstring(f.keywords))
  4351. }
  4352. if len(f.creator) > 0 {
  4353. f.outf("/Creator %s", f.textstring(f.creator))
  4354. }
  4355. creation := timeOrNow(f.creationDate)
  4356. f.outf("/CreationDate %s", f.textstring("D:"+creation.Format("20060102150405")))
  4357. mod := timeOrNow(f.modDate)
  4358. f.outf("/ModDate %s", f.textstring("D:"+mod.Format("20060102150405")))
  4359. }
  4360. func (f *Fpdf) putcatalog() {
  4361. f.out("/Type /Catalog")
  4362. f.out("/Pages 1 0 R")
  4363. switch f.zoomMode {
  4364. case "fullpage":
  4365. f.out("/OpenAction [3 0 R /Fit]")
  4366. case "fullwidth":
  4367. f.out("/OpenAction [3 0 R /FitH null]")
  4368. case "real":
  4369. f.out("/OpenAction [3 0 R /XYZ null null 1]")
  4370. }
  4371. // } else if !is_string($this->zoomMode))
  4372. // $this->out('/OpenAction [3 0 R /XYZ null null '.sprintf('%.2f',$this->zoomMode/100).']');
  4373. switch f.layoutMode {
  4374. case "single", "SinglePage":
  4375. f.out("/PageLayout /SinglePage")
  4376. case "continuous", "OneColumn":
  4377. f.out("/PageLayout /OneColumn")
  4378. case "two", "TwoColumnLeft":
  4379. f.out("/PageLayout /TwoColumnLeft")
  4380. case "TwoColumnRight":
  4381. f.out("/PageLayout /TwoColumnRight")
  4382. case "TwoPageLeft", "TwoPageRight":
  4383. if f.pdfVersion < "1.5" {
  4384. f.pdfVersion = "1.5"
  4385. }
  4386. f.out("/PageLayout /" + f.layoutMode)
  4387. }
  4388. // Bookmarks
  4389. if len(f.outlines) > 0 {
  4390. f.outf("/Outlines %d 0 R", f.outlineRoot)
  4391. f.out("/PageMode /UseOutlines")
  4392. }
  4393. // Layers
  4394. f.layerPutCatalog()
  4395. // Name dictionary :
  4396. // -> Javascript
  4397. // -> Embedded files
  4398. f.out("/Names <<")
  4399. // JavaScript
  4400. if f.javascript != nil {
  4401. f.outf("/JavaScript %d 0 R", f.nJs)
  4402. }
  4403. // Embedded files
  4404. f.outf("/EmbeddedFiles %s", f.getEmbeddedFiles())
  4405. f.out(">>")
  4406. }
  4407. func (f *Fpdf) putheader() {
  4408. if len(f.blendMap) > 0 && f.pdfVersion < "1.4" {
  4409. f.pdfVersion = "1.4"
  4410. }
  4411. f.outf("%%PDF-%s", f.pdfVersion)
  4412. }
  4413. func (f *Fpdf) puttrailer() {
  4414. f.outf("/Size %d", f.n+1)
  4415. f.outf("/Root %d 0 R", f.n)
  4416. f.outf("/Info %d 0 R", f.n-1)
  4417. if f.protect.encrypted {
  4418. f.outf("/Encrypt %d 0 R", f.protect.objNum)
  4419. f.out("/ID [()()]")
  4420. }
  4421. }
  4422. func (f *Fpdf) putxmp() {
  4423. if len(f.xmp) == 0 {
  4424. return
  4425. }
  4426. f.newobj()
  4427. f.outf("<< /Type /Metadata /Subtype /XML /Length %d >>", len(f.xmp))
  4428. f.putstream(f.xmp)
  4429. f.out("endobj")
  4430. }
  4431. func (f *Fpdf) putbookmarks() {
  4432. nb := len(f.outlines)
  4433. if nb > 0 {
  4434. lru := make(map[int]int)
  4435. level := 0
  4436. for i, o := range f.outlines {
  4437. if o.level > 0 {
  4438. parent := lru[o.level-1]
  4439. f.outlines[i].parent = parent
  4440. f.outlines[parent].last = i
  4441. if o.level > level {
  4442. f.outlines[parent].first = i
  4443. }
  4444. } else {
  4445. f.outlines[i].parent = nb
  4446. }
  4447. if o.level <= level && i > 0 {
  4448. prev := lru[o.level]
  4449. f.outlines[prev].next = i
  4450. f.outlines[i].prev = prev
  4451. }
  4452. lru[o.level] = i
  4453. level = o.level
  4454. }
  4455. n := f.n + 1
  4456. for _, o := range f.outlines {
  4457. f.newobj()
  4458. f.outf("<</Title %s", f.textstring(o.text))
  4459. f.outf("/Parent %d 0 R", n+o.parent)
  4460. if o.prev != -1 {
  4461. f.outf("/Prev %d 0 R", n+o.prev)
  4462. }
  4463. if o.next != -1 {
  4464. f.outf("/Next %d 0 R", n+o.next)
  4465. }
  4466. if o.first != -1 {
  4467. f.outf("/First %d 0 R", n+o.first)
  4468. }
  4469. if o.last != -1 {
  4470. f.outf("/Last %d 0 R", n+o.last)
  4471. }
  4472. f.outf("/Dest [%d 0 R /XYZ 0 %.2f null]", 1+2*o.p, (f.h-o.y)*f.k)
  4473. f.out("/Count 0>>")
  4474. f.out("endobj")
  4475. }
  4476. f.newobj()
  4477. f.outlineRoot = f.n
  4478. f.outf("<</Type /Outlines /First %d 0 R", n)
  4479. f.outf("/Last %d 0 R>>", n+lru[0])
  4480. f.out("endobj")
  4481. }
  4482. }
  4483. func (f *Fpdf) enddoc() {
  4484. if f.err != nil {
  4485. return
  4486. }
  4487. f.layerEndDoc()
  4488. f.putheader()
  4489. // Embedded files
  4490. f.putAttachments()
  4491. f.putAnnotationsAttachments()
  4492. f.putpages()
  4493. f.putresources()
  4494. if f.err != nil {
  4495. return
  4496. }
  4497. // Bookmarks
  4498. f.putbookmarks()
  4499. // Metadata
  4500. f.putxmp()
  4501. // Info
  4502. f.newobj()
  4503. f.out("<<")
  4504. f.putinfo()
  4505. f.out(">>")
  4506. f.out("endobj")
  4507. // Catalog
  4508. f.newobj()
  4509. f.out("<<")
  4510. f.putcatalog()
  4511. f.out(">>")
  4512. f.out("endobj")
  4513. // Cross-ref
  4514. o := f.buffer.Len()
  4515. f.out("xref")
  4516. f.outf("0 %d", f.n+1)
  4517. f.out("0000000000 65535 f ")
  4518. for j := 1; j <= f.n; j++ {
  4519. f.outf("%010d 00000 n ", f.offsets[j])
  4520. }
  4521. // Trailer
  4522. f.out("trailer")
  4523. f.out("<<")
  4524. f.puttrailer()
  4525. f.out(">>")
  4526. f.out("startxref")
  4527. f.outf("%d", o)
  4528. f.out("%%EOF")
  4529. f.state = 3
  4530. return
  4531. }
  4532. // Path Drawing
  4533. // MoveTo moves the stylus to (x, y) without drawing the path from the
  4534. // previous point. Paths must start with a MoveTo to set the original
  4535. // stylus location or the result is undefined.
  4536. //
  4537. // Create a "path" by moving a virtual stylus around the page (with
  4538. // MoveTo, LineTo, CurveTo, CurveBezierCubicTo, ArcTo & ClosePath)
  4539. // then draw it or fill it in (with DrawPath). The main advantage of
  4540. // using the path drawing routines rather than multiple Fpdf.Line is
  4541. // that PDF creates nice line joins at the angles, rather than just
  4542. // overlaying the lines.
  4543. func (f *Fpdf) MoveTo(x, y float64) {
  4544. f.point(x, y)
  4545. f.x, f.y = x, y
  4546. }
  4547. // LineTo creates a line from the current stylus location to (x, y), which
  4548. // becomes the new stylus location. Note that this only creates the line in
  4549. // the path; it does not actually draw the line on the page.
  4550. //
  4551. // The MoveTo() example demonstrates this method.
  4552. func (f *Fpdf) LineTo(x, y float64) {
  4553. f.outf("%.2f %.2f l", x*f.k, (f.h-y)*f.k)
  4554. f.x, f.y = x, y
  4555. }
  4556. // CurveTo creates a single-segment quadratic Bézier curve. The curve starts at
  4557. // the current stylus location and ends at the point (x, y). The control point
  4558. // (cx, cy) specifies the curvature. At the start point, the curve is tangent
  4559. // to the straight line between the current stylus location and the control
  4560. // point. At the end point, the curve is tangent to the straight line between
  4561. // the end point and the control point.
  4562. //
  4563. // The MoveTo() example demonstrates this method.
  4564. func (f *Fpdf) CurveTo(cx, cy, x, y float64) {
  4565. f.outf("%.5f %.5f %.5f %.5f v", cx*f.k, (f.h-cy)*f.k, x*f.k, (f.h-y)*f.k)
  4566. f.x, f.y = x, y
  4567. }
  4568. // CurveBezierCubicTo creates a single-segment cubic Bézier curve. The curve
  4569. // starts at the current stylus location and ends at the point (x, y). The
  4570. // control points (cx0, cy0) and (cx1, cy1) specify the curvature. At the
  4571. // current stylus, the curve is tangent to the straight line between the
  4572. // current stylus location and the control point (cx0, cy0). At the end point,
  4573. // the curve is tangent to the straight line between the end point and the
  4574. // control point (cx1, cy1).
  4575. //
  4576. // The MoveTo() example demonstrates this method.
  4577. func (f *Fpdf) CurveBezierCubicTo(cx0, cy0, cx1, cy1, x, y float64) {
  4578. f.curve(cx0, cy0, cx1, cy1, x, y)
  4579. f.x, f.y = x, y
  4580. }
  4581. // ClosePath creates a line from the current location to the last MoveTo point
  4582. // (if not the same) and mark the path as closed so the first and last lines
  4583. // join nicely.
  4584. //
  4585. // The MoveTo() example demonstrates this method.
  4586. func (f *Fpdf) ClosePath() {
  4587. f.outf("h")
  4588. }
  4589. // DrawPath actually draws the path on the page.
  4590. //
  4591. // styleStr can be "F" for filled, "D" for outlined only, or "DF" or "FD" for
  4592. // outlined and filled. An empty string will be replaced with "D".
  4593. // Path-painting operators as defined in the PDF specification are also
  4594. // allowed: "S" (Stroke the path), "s" (Close and stroke the path),
  4595. // "f" (fill the path, using the nonzero winding number), "f*"
  4596. // (Fill the path, using the even-odd rule), "B" (Fill and then stroke
  4597. // the path, using the nonzero winding number rule), "B*" (Fill and
  4598. // then stroke the path, using the even-odd rule), "b" (Close, fill,
  4599. // and then stroke the path, using the nonzero winding number rule) and
  4600. // "b*" (Close, fill, and then stroke the path, using the even-odd
  4601. // rule).
  4602. // Drawing uses the current draw color, line width, and cap style
  4603. // centered on the
  4604. // path. Filling uses the current fill color.
  4605. //
  4606. // The MoveTo() example demonstrates this method.
  4607. func (f *Fpdf) DrawPath(styleStr string) {
  4608. f.outf(fillDrawOp(styleStr))
  4609. }
  4610. // ArcTo draws an elliptical arc centered at point (x, y). rx and ry specify its
  4611. // horizontal and vertical radii. If the start of the arc is not at
  4612. // the current position, a connecting line will be drawn.
  4613. //
  4614. // degRotate specifies the angle that the arc will be rotated. degStart and
  4615. // degEnd specify the starting and ending angle of the arc. All angles are
  4616. // specified in degrees and measured counter-clockwise from the 3 o'clock
  4617. // position.
  4618. //
  4619. // styleStr can be "F" for filled, "D" for outlined only, or "DF" or "FD" for
  4620. // outlined and filled. An empty string will be replaced with "D". Drawing uses
  4621. // the current draw color, line width, and cap style centered on the arc's
  4622. // path. Filling uses the current fill color.
  4623. //
  4624. // The MoveTo() example demonstrates this method.
  4625. func (f *Fpdf) ArcTo(x, y, rx, ry, degRotate, degStart, degEnd float64) {
  4626. f.arc(x, y, rx, ry, degRotate, degStart, degEnd, "", true)
  4627. }
  4628. func (f *Fpdf) arc(x, y, rx, ry, degRotate, degStart, degEnd float64,
  4629. styleStr string, path bool) {
  4630. x *= f.k
  4631. y = (f.h - y) * f.k
  4632. rx *= f.k
  4633. ry *= f.k
  4634. segments := int(degEnd-degStart) / 60
  4635. if segments < 2 {
  4636. segments = 2
  4637. }
  4638. angleStart := degStart * math.Pi / 180
  4639. angleEnd := degEnd * math.Pi / 180
  4640. angleTotal := angleEnd - angleStart
  4641. dt := angleTotal / float64(segments)
  4642. dtm := dt / 3
  4643. if degRotate != 0 {
  4644. a := -degRotate * math.Pi / 180
  4645. f.outf("q %.5f %.5f %.5f %.5f %.5f %.5f cm",
  4646. math.Cos(a), -1*math.Sin(a),
  4647. math.Sin(a), math.Cos(a), x, y)
  4648. x = 0
  4649. y = 0
  4650. }
  4651. t := angleStart
  4652. a0 := x + rx*math.Cos(t)
  4653. b0 := y + ry*math.Sin(t)
  4654. c0 := -rx * math.Sin(t)
  4655. d0 := ry * math.Cos(t)
  4656. sx := a0 / f.k // start point of arc
  4657. sy := f.h - (b0 / f.k)
  4658. if path {
  4659. if f.x != sx || f.y != sy {
  4660. // Draw connecting line to start point
  4661. f.LineTo(sx, sy)
  4662. }
  4663. } else {
  4664. f.point(sx, sy)
  4665. }
  4666. for j := 1; j <= segments; j++ {
  4667. // Draw this bit of the total curve
  4668. t = (float64(j) * dt) + angleStart
  4669. a1 := x + rx*math.Cos(t)
  4670. b1 := y + ry*math.Sin(t)
  4671. c1 := -rx * math.Sin(t)
  4672. d1 := ry * math.Cos(t)
  4673. f.curve((a0+(c0*dtm))/f.k,
  4674. f.h-((b0+(d0*dtm))/f.k),
  4675. (a1-(c1*dtm))/f.k,
  4676. f.h-((b1-(d1*dtm))/f.k),
  4677. a1/f.k,
  4678. f.h-(b1/f.k))
  4679. a0 = a1
  4680. b0 = b1
  4681. c0 = c1
  4682. d0 = d1
  4683. if path {
  4684. f.x = a1 / f.k
  4685. f.y = f.h - (b1 / f.k)
  4686. }
  4687. }
  4688. if !path {
  4689. f.out(fillDrawOp(styleStr))
  4690. }
  4691. if degRotate != 0 {
  4692. f.out("Q")
  4693. }
  4694. }