fpdf_test.go 86 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924
  1. /*
  2. * Copyright (c) 2013-2015 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_test
  17. import (
  18. "bufio"
  19. "bytes"
  20. "fmt"
  21. "io"
  22. "io/ioutil"
  23. "math"
  24. "math/rand"
  25. "net/http"
  26. "os"
  27. "path/filepath"
  28. "strconv"
  29. "strings"
  30. "testing"
  31. "time"
  32. "github.com/jung-kurt/gofpdf"
  33. "github.com/jung-kurt/gofpdf/internal/example"
  34. "github.com/jung-kurt/gofpdf/internal/files"
  35. )
  36. func init() {
  37. cleanup()
  38. }
  39. func cleanup() {
  40. filepath.Walk(example.PdfDir(),
  41. func(path string, info os.FileInfo, err error) (reterr error) {
  42. if info.Mode().IsRegular() {
  43. dir, _ := filepath.Split(path)
  44. if "reference" != filepath.Base(dir) {
  45. if len(path) > 3 {
  46. if path[len(path)-4:] == ".pdf" {
  47. os.Remove(path)
  48. }
  49. }
  50. }
  51. }
  52. return
  53. })
  54. }
  55. func TestFpdfImplementPdf(t *testing.T) {
  56. // this will not compile if Fpdf and Tpl
  57. // do not implement Pdf
  58. var _ gofpdf.Pdf = (*gofpdf.Fpdf)(nil)
  59. var _ gofpdf.Pdf = (*gofpdf.Tpl)(nil)
  60. }
  61. // TestPagedTemplate ensures new paged templates work
  62. func TestPagedTemplate(t *testing.T) {
  63. pdf := gofpdf.New("P", "mm", "A4", "")
  64. tpl := pdf.CreateTemplate(func(t *gofpdf.Tpl) {
  65. // this will be the second page, as a page is already
  66. // created by default
  67. t.AddPage()
  68. t.AddPage()
  69. t.AddPage()
  70. })
  71. if tpl.NumPages() != 4 {
  72. t.Fatalf("The template does not have the correct number of pages %d", tpl.NumPages())
  73. }
  74. tplPages := tpl.FromPages()
  75. for x := 0; x < len(tplPages); x++ {
  76. pdf.AddPage()
  77. pdf.UseTemplate(tplPages[x])
  78. }
  79. // get the last template
  80. tpl2, err := tpl.FromPage(tpl.NumPages())
  81. if err != nil {
  82. t.Fatal(err)
  83. }
  84. // the objects should be the exact same, as the
  85. // template will represent the last page by default
  86. // therefore no new id should be set, and the object
  87. // should be the same object
  88. if fmt.Sprintf("%p", tpl2) != fmt.Sprintf("%p", tpl) {
  89. t.Fatal("Template no longer respecting initial template object")
  90. }
  91. }
  92. // TestIssue0116 addresses issue 116 in which library silently fails after
  93. // calling CellFormat when no font has been set.
  94. func TestIssue0116(t *testing.T) {
  95. var pdf *gofpdf.Fpdf
  96. pdf = gofpdf.New("P", "mm", "A4", "")
  97. pdf.AddPage()
  98. pdf.SetFont("Arial", "B", 16)
  99. pdf.Cell(40, 10, "OK")
  100. if pdf.Error() != nil {
  101. t.Fatalf("not expecting error when rendering text")
  102. }
  103. pdf = gofpdf.New("P", "mm", "A4", "")
  104. pdf.AddPage()
  105. pdf.Cell(40, 10, "Not OK") // Font not set
  106. if pdf.Error() == nil {
  107. t.Fatalf("expecting error when rendering text without having set font")
  108. }
  109. }
  110. // TestIssue0193 addresses issue 193 in which the error io.EOF is incorrectly
  111. // assigned to the FPDF instance error.
  112. func TestIssue0193(t *testing.T) {
  113. var png []byte
  114. var pdf *gofpdf.Fpdf
  115. var err error
  116. var rdr *bytes.Reader
  117. png, err = ioutil.ReadFile(example.ImageFile("sweden.png"))
  118. if err == nil {
  119. rdr = bytes.NewReader(png)
  120. pdf = gofpdf.New("P", "mm", "A4", "")
  121. pdf.AddPage()
  122. _ = pdf.RegisterImageOptionsReader("sweden", gofpdf.ImageOptions{ImageType: "png", ReadDpi: true}, rdr)
  123. err = pdf.Error()
  124. }
  125. if err != nil {
  126. t.Fatalf("issue 193 error: %s", err)
  127. }
  128. }
  129. // TestIssue0209SplitLinesEqualMultiCell addresses issue 209
  130. // make SplitLines and MultiCell split at the same place
  131. func TestIssue0209SplitLinesEqualMultiCell(t *testing.T) {
  132. var pdf *gofpdf.Fpdf
  133. pdf = gofpdf.New("P", "mm", "A4", "")
  134. pdf.AddPage()
  135. pdf.SetFont("Arial", "", 8)
  136. // this sentence should not be splited
  137. str := "Guochin Amandine"
  138. lines := pdf.SplitLines([]byte(str), 26)
  139. _, FontSize := pdf.GetFontSize()
  140. y_start := pdf.GetY()
  141. pdf.MultiCell(26, FontSize, str, "", "L", false)
  142. y_end := pdf.GetY()
  143. if len(lines) != 1 {
  144. t.Fatalf("expect SplitLines split in one line")
  145. }
  146. if int(y_end-y_start) != int(FontSize) {
  147. t.Fatalf("expect MultiCell split in one line %.2f != %.2f", y_end-y_start, FontSize)
  148. }
  149. // this sentence should be splited in two lines
  150. str = "Guiochini Amandine"
  151. lines = pdf.SplitLines([]byte(str), 26)
  152. y_start = pdf.GetY()
  153. pdf.MultiCell(26, FontSize, str, "", "L", false)
  154. y_end = pdf.GetY()
  155. if len(lines) != 2 {
  156. t.Fatalf("expect SplitLines split in two lines")
  157. }
  158. if int(y_end-y_start) != int(FontSize*2) {
  159. t.Fatalf("expect MultiCell split in two lines %.2f != %.2f", y_end-y_start, FontSize*2)
  160. }
  161. }
  162. // TestFooterFuncLpi tests to make sure the footer is not call twice and SetFooterFuncLpi can work
  163. // without SetFooterFunc.
  164. func TestFooterFuncLpi(t *testing.T) {
  165. pdf := gofpdf.New("P", "mm", "A4", "")
  166. var (
  167. oldFooterFnc = "oldFooterFnc"
  168. bothPages = "bothPages"
  169. firstPageOnly = "firstPageOnly"
  170. lastPageOnly = "lastPageOnly"
  171. )
  172. // This set just for testing, only set SetFooterFuncLpi.
  173. pdf.SetFooterFunc(func() {
  174. pdf.SetY(-15)
  175. pdf.SetFont("Arial", "I", 8)
  176. pdf.CellFormat(0, 10, oldFooterFnc,
  177. "", 0, "C", false, 0, "")
  178. })
  179. pdf.SetFooterFuncLpi(func(lastPage bool) {
  180. pdf.SetY(-15)
  181. pdf.SetFont("Arial", "I", 8)
  182. pdf.CellFormat(0, 10, bothPages, "", 0, "L", false, 0, "")
  183. if !lastPage {
  184. pdf.CellFormat(0, 10, firstPageOnly, "", 0, "C", false, 0, "")
  185. } else {
  186. pdf.CellFormat(0, 10, lastPageOnly, "", 0, "C", false, 0, "")
  187. }
  188. })
  189. pdf.AddPage()
  190. pdf.SetFont("Arial", "B", 16)
  191. for j := 1; j <= 40; j++ {
  192. pdf.CellFormat(0, 10, fmt.Sprintf("Printing line number %d", j),
  193. "", 1, "", false, 0, "")
  194. }
  195. if pdf.Error() != nil {
  196. t.Fatalf("not expecting error when rendering text")
  197. }
  198. w := &bytes.Buffer{}
  199. if err := pdf.Output(w); err != nil {
  200. t.Errorf("unexpected err: %s", err)
  201. }
  202. b := w.Bytes()
  203. if bytes.Contains(b, []byte(oldFooterFnc)) {
  204. t.Errorf("not expecting %s render on pdf when FooterFncLpi is set", oldFooterFnc)
  205. }
  206. got := bytes.Count(b, []byte("bothPages"))
  207. if got != 2 {
  208. t.Errorf("footer %s should render on two page got:%d", bothPages, got)
  209. }
  210. got = bytes.Count(b, []byte(firstPageOnly))
  211. if got != 1 {
  212. t.Errorf("footer %s should render only on first page got: %d", firstPageOnly, got)
  213. }
  214. got = bytes.Count(b, []byte(lastPageOnly))
  215. if got != 1 {
  216. t.Errorf("footer %s should render only on first page got: %d", lastPageOnly, got)
  217. }
  218. f := bytes.Index(b, []byte(firstPageOnly))
  219. l := bytes.Index(b, []byte(lastPageOnly))
  220. if f > l {
  221. t.Errorf("index %d (%s) should less than index %d (%s)", f, firstPageOnly, l, lastPageOnly)
  222. }
  223. }
  224. type fontResourceType struct {
  225. }
  226. func (f fontResourceType) Open(name string) (rdr io.Reader, err error) {
  227. var buf []byte
  228. buf, err = ioutil.ReadFile(example.FontFile(name))
  229. if err == nil {
  230. rdr = bytes.NewReader(buf)
  231. fmt.Printf("Generalized font loader reading %s\n", name)
  232. }
  233. return
  234. }
  235. // strDelimit converts 'ABCDEFG' to, for example, 'A,BCD,EFG'
  236. func strDelimit(str string, sepstr string, sepcount int) string {
  237. pos := len(str) - sepcount
  238. for pos > 0 {
  239. str = str[:pos] + sepstr + str[pos:]
  240. pos = pos - sepcount
  241. }
  242. return str
  243. }
  244. func loremList() []string {
  245. return []string{
  246. "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod " +
  247. "tempor incididunt ut labore et dolore magna aliqua.",
  248. "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut " +
  249. "aliquip ex ea commodo consequat.",
  250. "Duis aute irure dolor in reprehenderit in voluptate velit esse cillum " +
  251. "dolore eu fugiat nulla pariatur.",
  252. "Excepteur sint occaecat cupidatat non proident, sunt in culpa qui " +
  253. "officia deserunt mollit anim id est laborum.",
  254. }
  255. }
  256. func lorem() string {
  257. return strings.Join(loremList(), " ")
  258. }
  259. // Example demonstrates the generation of a simple PDF document. Note that
  260. // since only core fonts are used (in this case Arial, a synonym for
  261. // Helvetica), an empty string can be specified for the font directory in the
  262. // call to New(). Note also that the example.Filename() and example.Summary()
  263. // functions belong to a separate, internal package and are not part of the
  264. // gofpdf library. If an error occurs at some point during the construction of
  265. // the document, subsequent method calls exit immediately and the error is
  266. // finally retrieved with the output call where it can be handled by the
  267. // application.
  268. func Example() {
  269. pdf := gofpdf.New(gofpdf.OrientationPortrait, "mm", "A4", "")
  270. pdf.AddPage()
  271. pdf.SetFont("Arial", "B", 16)
  272. pdf.Cell(40, 10, "Hello World!")
  273. fileStr := example.Filename("basic")
  274. err := pdf.OutputFileAndClose(fileStr)
  275. example.Summary(err, fileStr)
  276. // Output:
  277. // Successfully generated pdf/basic.pdf
  278. }
  279. // ExampleFpdf_AddPage demonsrates the generation of headers, footers and page breaks.
  280. func ExampleFpdf_AddPage() {
  281. pdf := gofpdf.New("P", "mm", "A4", "")
  282. pdf.SetTopMargin(30)
  283. pdf.SetHeaderFuncMode(func() {
  284. pdf.Image(example.ImageFile("logo.png"), 10, 6, 30, 0, false, "", 0, "")
  285. pdf.SetY(5)
  286. pdf.SetFont("Arial", "B", 15)
  287. pdf.Cell(80, 0, "")
  288. pdf.CellFormat(30, 10, "Title", "1", 0, "C", false, 0, "")
  289. pdf.Ln(20)
  290. }, true)
  291. pdf.SetFooterFunc(func() {
  292. pdf.SetY(-15)
  293. pdf.SetFont("Arial", "I", 8)
  294. pdf.CellFormat(0, 10, fmt.Sprintf("Page %d/{nb}", pdf.PageNo()),
  295. "", 0, "C", false, 0, "")
  296. })
  297. pdf.AliasNbPages("")
  298. pdf.AddPage()
  299. pdf.SetFont("Times", "", 12)
  300. for j := 1; j <= 40; j++ {
  301. pdf.CellFormat(0, 10, fmt.Sprintf("Printing line number %d", j),
  302. "", 1, "", false, 0, "")
  303. }
  304. fileStr := example.Filename("Fpdf_AddPage")
  305. err := pdf.OutputFileAndClose(fileStr)
  306. example.Summary(err, fileStr)
  307. // Output:
  308. // Successfully generated pdf/Fpdf_AddPage.pdf
  309. }
  310. // ExampleFpdf_MultiCell demonstrates word-wrapping, line justification and
  311. // page-breaking.
  312. func ExampleFpdf_MultiCell() {
  313. pdf := gofpdf.New("P", "mm", "A4", "")
  314. titleStr := "20000 Leagues Under the Seas"
  315. pdf.SetTitle(titleStr, false)
  316. pdf.SetAuthor("Jules Verne", false)
  317. pdf.SetHeaderFunc(func() {
  318. // Arial bold 15
  319. pdf.SetFont("Arial", "B", 15)
  320. // Calculate width of title and position
  321. wd := pdf.GetStringWidth(titleStr) + 6
  322. pdf.SetX((210 - wd) / 2)
  323. // Colors of frame, background and text
  324. pdf.SetDrawColor(0, 80, 180)
  325. pdf.SetFillColor(230, 230, 0)
  326. pdf.SetTextColor(220, 50, 50)
  327. // Thickness of frame (1 mm)
  328. pdf.SetLineWidth(1)
  329. // Title
  330. pdf.CellFormat(wd, 9, titleStr, "1", 1, "C", true, 0, "")
  331. // Line break
  332. pdf.Ln(10)
  333. })
  334. pdf.SetFooterFunc(func() {
  335. // Position at 1.5 cm from bottom
  336. pdf.SetY(-15)
  337. // Arial italic 8
  338. pdf.SetFont("Arial", "I", 8)
  339. // Text color in gray
  340. pdf.SetTextColor(128, 128, 128)
  341. // Page number
  342. pdf.CellFormat(0, 10, fmt.Sprintf("Page %d", pdf.PageNo()),
  343. "", 0, "C", false, 0, "")
  344. })
  345. chapterTitle := func(chapNum int, titleStr string) {
  346. // // Arial 12
  347. pdf.SetFont("Arial", "", 12)
  348. // Background color
  349. pdf.SetFillColor(200, 220, 255)
  350. // Title
  351. pdf.CellFormat(0, 6, fmt.Sprintf("Chapter %d : %s", chapNum, titleStr),
  352. "", 1, "L", true, 0, "")
  353. // Line break
  354. pdf.Ln(4)
  355. }
  356. chapterBody := func(fileStr string) {
  357. // Read text file
  358. txtStr, err := ioutil.ReadFile(fileStr)
  359. if err != nil {
  360. pdf.SetError(err)
  361. }
  362. // Times 12
  363. pdf.SetFont("Times", "", 12)
  364. // Output justified text
  365. pdf.MultiCell(0, 5, string(txtStr), "", "", false)
  366. // Line break
  367. pdf.Ln(-1)
  368. // Mention in italics
  369. pdf.SetFont("", "I", 0)
  370. pdf.Cell(0, 5, "(end of excerpt)")
  371. }
  372. printChapter := func(chapNum int, titleStr, fileStr string) {
  373. pdf.AddPage()
  374. chapterTitle(chapNum, titleStr)
  375. chapterBody(fileStr)
  376. }
  377. printChapter(1, "A RUNAWAY REEF", example.TextFile("20k_c1.txt"))
  378. printChapter(2, "THE PROS AND CONS", example.TextFile("20k_c2.txt"))
  379. fileStr := example.Filename("Fpdf_MultiCell")
  380. err := pdf.OutputFileAndClose(fileStr)
  381. example.Summary(err, fileStr)
  382. // Output:
  383. // Successfully generated pdf/Fpdf_MultiCell.pdf
  384. }
  385. // ExampleFpdf_SetLeftMargin demonstrates the generation of a PDF document that has multiple
  386. // columns. This is accomplished with the SetLeftMargin() and Cell() methods.
  387. func ExampleFpdf_SetLeftMargin() {
  388. var y0 float64
  389. var crrntCol int
  390. pdf := gofpdf.New("P", "mm", "A4", "")
  391. pdf.SetDisplayMode("fullpage", "TwoColumnLeft")
  392. titleStr := "20000 Leagues Under the Seas"
  393. pdf.SetTitle(titleStr, false)
  394. pdf.SetAuthor("Jules Verne", false)
  395. setCol := func(col int) {
  396. // Set position at a given column
  397. crrntCol = col
  398. x := 10.0 + float64(col)*65.0
  399. pdf.SetLeftMargin(x)
  400. pdf.SetX(x)
  401. }
  402. chapterTitle := func(chapNum int, titleStr string) {
  403. // Arial 12
  404. pdf.SetFont("Arial", "", 12)
  405. // Background color
  406. pdf.SetFillColor(200, 220, 255)
  407. // Title
  408. pdf.CellFormat(0, 6, fmt.Sprintf("Chapter %d : %s", chapNum, titleStr),
  409. "", 1, "L", true, 0, "")
  410. // Line break
  411. pdf.Ln(4)
  412. y0 = pdf.GetY()
  413. }
  414. chapterBody := func(fileStr string) {
  415. // Read text file
  416. txtStr, err := ioutil.ReadFile(fileStr)
  417. if err != nil {
  418. pdf.SetError(err)
  419. }
  420. // Font
  421. pdf.SetFont("Times", "", 12)
  422. // Output text in a 6 cm width column
  423. pdf.MultiCell(60, 5, string(txtStr), "", "", false)
  424. pdf.Ln(-1)
  425. // Mention
  426. pdf.SetFont("", "I", 0)
  427. pdf.Cell(0, 5, "(end of excerpt)")
  428. // Go back to first column
  429. setCol(0)
  430. }
  431. printChapter := func(num int, titleStr, fileStr string) {
  432. // Add chapter
  433. pdf.AddPage()
  434. chapterTitle(num, titleStr)
  435. chapterBody(fileStr)
  436. }
  437. pdf.SetAcceptPageBreakFunc(func() bool {
  438. // Method accepting or not automatic page break
  439. if crrntCol < 2 {
  440. // Go to next column
  441. setCol(crrntCol + 1)
  442. // Set ordinate to top
  443. pdf.SetY(y0)
  444. // Keep on page
  445. return false
  446. }
  447. // Go back to first column
  448. setCol(0)
  449. // Page break
  450. return true
  451. })
  452. pdf.SetHeaderFunc(func() {
  453. // Arial bold 15
  454. pdf.SetFont("Arial", "B", 15)
  455. // Calculate width of title and position
  456. wd := pdf.GetStringWidth(titleStr) + 6
  457. pdf.SetX((210 - wd) / 2)
  458. // Colors of frame, background and text
  459. pdf.SetDrawColor(0, 80, 180)
  460. pdf.SetFillColor(230, 230, 0)
  461. pdf.SetTextColor(220, 50, 50)
  462. // Thickness of frame (1 mm)
  463. pdf.SetLineWidth(1)
  464. // Title
  465. pdf.CellFormat(wd, 9, titleStr, "1", 1, "C", true, 0, "")
  466. // Line break
  467. pdf.Ln(10)
  468. // Save ordinate
  469. y0 = pdf.GetY()
  470. })
  471. pdf.SetFooterFunc(func() {
  472. // Position at 1.5 cm from bottom
  473. pdf.SetY(-15)
  474. // Arial italic 8
  475. pdf.SetFont("Arial", "I", 8)
  476. // Text color in gray
  477. pdf.SetTextColor(128, 128, 128)
  478. // Page number
  479. pdf.CellFormat(0, 10, fmt.Sprintf("Page %d", pdf.PageNo()),
  480. "", 0, "C", false, 0, "")
  481. })
  482. printChapter(1, "A RUNAWAY REEF", example.TextFile("20k_c1.txt"))
  483. printChapter(2, "THE PROS AND CONS", example.TextFile("20k_c2.txt"))
  484. fileStr := example.Filename("Fpdf_SetLeftMargin_multicolumn")
  485. err := pdf.OutputFileAndClose(fileStr)
  486. example.Summary(err, fileStr)
  487. // Output:
  488. // Successfully generated pdf/Fpdf_SetLeftMargin_multicolumn.pdf
  489. }
  490. // ExampleFpdf_SplitLines_tables demonstrates word-wrapped table cells
  491. func ExampleFpdf_SplitLines_tables() {
  492. const (
  493. colCount = 3
  494. colWd = 60.0
  495. marginH = 15.0
  496. lineHt = 5.5
  497. cellGap = 2.0
  498. )
  499. // var colStrList [colCount]string
  500. type cellType struct {
  501. str string
  502. list [][]byte
  503. ht float64
  504. }
  505. var (
  506. cellList [colCount]cellType
  507. cell cellType
  508. )
  509. pdf := gofpdf.New("P", "mm", "A4", "") // 210 x 297
  510. header := [colCount]string{"Column A", "Column B", "Column C"}
  511. alignList := [colCount]string{"L", "C", "R"}
  512. strList := loremList()
  513. pdf.SetMargins(marginH, 15, marginH)
  514. pdf.SetFont("Arial", "", 14)
  515. pdf.AddPage()
  516. // Headers
  517. pdf.SetTextColor(224, 224, 224)
  518. pdf.SetFillColor(64, 64, 64)
  519. for colJ := 0; colJ < colCount; colJ++ {
  520. pdf.CellFormat(colWd, 10, header[colJ], "1", 0, "CM", true, 0, "")
  521. }
  522. pdf.Ln(-1)
  523. pdf.SetTextColor(24, 24, 24)
  524. pdf.SetFillColor(255, 255, 255)
  525. // Rows
  526. y := pdf.GetY()
  527. count := 0
  528. for rowJ := 0; rowJ < 2; rowJ++ {
  529. maxHt := lineHt
  530. // Cell height calculation loop
  531. for colJ := 0; colJ < colCount; colJ++ {
  532. count++
  533. if count > len(strList) {
  534. count = 1
  535. }
  536. cell.str = strings.Join(strList[0:count], " ")
  537. cell.list = pdf.SplitLines([]byte(cell.str), colWd-cellGap-cellGap)
  538. cell.ht = float64(len(cell.list)) * lineHt
  539. if cell.ht > maxHt {
  540. maxHt = cell.ht
  541. }
  542. cellList[colJ] = cell
  543. }
  544. // Cell render loop
  545. x := marginH
  546. for colJ := 0; colJ < colCount; colJ++ {
  547. pdf.Rect(x, y, colWd, maxHt+cellGap+cellGap, "D")
  548. cell = cellList[colJ]
  549. cellY := y + cellGap + (maxHt-cell.ht)/2
  550. for splitJ := 0; splitJ < len(cell.list); splitJ++ {
  551. pdf.SetXY(x+cellGap, cellY)
  552. pdf.CellFormat(colWd-cellGap-cellGap, lineHt, string(cell.list[splitJ]), "", 0,
  553. alignList[colJ], false, 0, "")
  554. cellY += lineHt
  555. }
  556. x += colWd
  557. }
  558. y += maxHt + cellGap + cellGap
  559. }
  560. fileStr := example.Filename("Fpdf_SplitLines_tables")
  561. err := pdf.OutputFileAndClose(fileStr)
  562. example.Summary(err, fileStr)
  563. // Output:
  564. // Successfully generated pdf/Fpdf_SplitLines_tables.pdf
  565. }
  566. // ExampleFpdf_CellFormat_tables demonstrates various table styles.
  567. func ExampleFpdf_CellFormat_tables() {
  568. pdf := gofpdf.New("P", "mm", "A4", "")
  569. type countryType struct {
  570. nameStr, capitalStr, areaStr, popStr string
  571. }
  572. countryList := make([]countryType, 0, 8)
  573. header := []string{"Country", "Capital", "Area (sq km)", "Pop. (thousands)"}
  574. loadData := func(fileStr string) {
  575. fl, err := os.Open(fileStr)
  576. if err == nil {
  577. scanner := bufio.NewScanner(fl)
  578. var c countryType
  579. for scanner.Scan() {
  580. // Austria;Vienna;83859;8075
  581. lineStr := scanner.Text()
  582. list := strings.Split(lineStr, ";")
  583. if len(list) == 4 {
  584. c.nameStr = list[0]
  585. c.capitalStr = list[1]
  586. c.areaStr = list[2]
  587. c.popStr = list[3]
  588. countryList = append(countryList, c)
  589. } else {
  590. err = fmt.Errorf("error tokenizing %s", lineStr)
  591. }
  592. }
  593. fl.Close()
  594. if len(countryList) == 0 {
  595. err = fmt.Errorf("error loading data from %s", fileStr)
  596. }
  597. }
  598. if err != nil {
  599. pdf.SetError(err)
  600. }
  601. }
  602. // Simple table
  603. basicTable := func() {
  604. left := (210.0 - 4*40) / 2
  605. pdf.SetX(left)
  606. for _, str := range header {
  607. pdf.CellFormat(40, 7, str, "1", 0, "", false, 0, "")
  608. }
  609. pdf.Ln(-1)
  610. for _, c := range countryList {
  611. pdf.SetX(left)
  612. pdf.CellFormat(40, 6, c.nameStr, "1", 0, "", false, 0, "")
  613. pdf.CellFormat(40, 6, c.capitalStr, "1", 0, "", false, 0, "")
  614. pdf.CellFormat(40, 6, c.areaStr, "1", 0, "", false, 0, "")
  615. pdf.CellFormat(40, 6, c.popStr, "1", 0, "", false, 0, "")
  616. pdf.Ln(-1)
  617. }
  618. }
  619. // Better table
  620. improvedTable := func() {
  621. // Column widths
  622. w := []float64{40.0, 35.0, 40.0, 45.0}
  623. wSum := 0.0
  624. for _, v := range w {
  625. wSum += v
  626. }
  627. left := (210 - wSum) / 2
  628. // Header
  629. pdf.SetX(left)
  630. for j, str := range header {
  631. pdf.CellFormat(w[j], 7, str, "1", 0, "C", false, 0, "")
  632. }
  633. pdf.Ln(-1)
  634. // Data
  635. for _, c := range countryList {
  636. pdf.SetX(left)
  637. pdf.CellFormat(w[0], 6, c.nameStr, "LR", 0, "", false, 0, "")
  638. pdf.CellFormat(w[1], 6, c.capitalStr, "LR", 0, "", false, 0, "")
  639. pdf.CellFormat(w[2], 6, strDelimit(c.areaStr, ",", 3),
  640. "LR", 0, "R", false, 0, "")
  641. pdf.CellFormat(w[3], 6, strDelimit(c.popStr, ",", 3),
  642. "LR", 0, "R", false, 0, "")
  643. pdf.Ln(-1)
  644. }
  645. pdf.SetX(left)
  646. pdf.CellFormat(wSum, 0, "", "T", 0, "", false, 0, "")
  647. }
  648. // Colored table
  649. fancyTable := func() {
  650. // Colors, line width and bold font
  651. pdf.SetFillColor(255, 0, 0)
  652. pdf.SetTextColor(255, 255, 255)
  653. pdf.SetDrawColor(128, 0, 0)
  654. pdf.SetLineWidth(.3)
  655. pdf.SetFont("", "B", 0)
  656. // Header
  657. w := []float64{40, 35, 40, 45}
  658. wSum := 0.0
  659. for _, v := range w {
  660. wSum += v
  661. }
  662. left := (210 - wSum) / 2
  663. pdf.SetX(left)
  664. for j, str := range header {
  665. pdf.CellFormat(w[j], 7, str, "1", 0, "C", true, 0, "")
  666. }
  667. pdf.Ln(-1)
  668. // Color and font restoration
  669. pdf.SetFillColor(224, 235, 255)
  670. pdf.SetTextColor(0, 0, 0)
  671. pdf.SetFont("", "", 0)
  672. // Data
  673. fill := false
  674. for _, c := range countryList {
  675. pdf.SetX(left)
  676. pdf.CellFormat(w[0], 6, c.nameStr, "LR", 0, "", fill, 0, "")
  677. pdf.CellFormat(w[1], 6, c.capitalStr, "LR", 0, "", fill, 0, "")
  678. pdf.CellFormat(w[2], 6, strDelimit(c.areaStr, ",", 3),
  679. "LR", 0, "R", fill, 0, "")
  680. pdf.CellFormat(w[3], 6, strDelimit(c.popStr, ",", 3),
  681. "LR", 0, "R", fill, 0, "")
  682. pdf.Ln(-1)
  683. fill = !fill
  684. }
  685. pdf.SetX(left)
  686. pdf.CellFormat(wSum, 0, "", "T", 0, "", false, 0, "")
  687. }
  688. loadData(example.TextFile("countries.txt"))
  689. pdf.SetFont("Arial", "", 14)
  690. pdf.AddPage()
  691. basicTable()
  692. pdf.AddPage()
  693. improvedTable()
  694. pdf.AddPage()
  695. fancyTable()
  696. fileStr := example.Filename("Fpdf_CellFormat_tables")
  697. err := pdf.OutputFileAndClose(fileStr)
  698. example.Summary(err, fileStr)
  699. // Output:
  700. // Successfully generated pdf/Fpdf_CellFormat_tables.pdf
  701. }
  702. // ExampleFpdf_HTMLBasicNew demonstrates internal and external links with and without basic
  703. // HTML.
  704. func ExampleFpdf_HTMLBasicNew() {
  705. pdf := gofpdf.New("P", "mm", "A4", "")
  706. // First page: manual local link
  707. pdf.AddPage()
  708. pdf.SetFont("Helvetica", "", 20)
  709. _, lineHt := pdf.GetFontSize()
  710. pdf.Write(lineHt, "To find out what's new in this tutorial, click ")
  711. pdf.SetFont("", "U", 0)
  712. link := pdf.AddLink()
  713. pdf.WriteLinkID(lineHt, "here", link)
  714. pdf.SetFont("", "", 0)
  715. // Second page: image link and basic HTML with link
  716. pdf.AddPage()
  717. pdf.SetLink(link, 0, -1)
  718. pdf.Image(example.ImageFile("logo.png"), 10, 12, 30, 0, false, "", 0, "http://www.fpdf.org")
  719. pdf.SetLeftMargin(45)
  720. pdf.SetFontSize(14)
  721. _, lineHt = pdf.GetFontSize()
  722. htmlStr := `You can now easily print text mixing different styles: <b>bold</b>, ` +
  723. `<i>italic</i>, <u>underlined</u>, or <b><i><u>all at once</u></i></b>!<br><br>` +
  724. `<center>You can also center text.</center>` +
  725. `<right>Or align it to the right.</right>` +
  726. `You can also insert links on text, such as ` +
  727. `<a href="http://www.fpdf.org">www.fpdf.org</a>, or on an image: click on the logo.`
  728. html := pdf.HTMLBasicNew()
  729. html.Write(lineHt, htmlStr)
  730. fileStr := example.Filename("Fpdf_HTMLBasicNew")
  731. err := pdf.OutputFileAndClose(fileStr)
  732. example.Summary(err, fileStr)
  733. // Output:
  734. // Successfully generated pdf/Fpdf_HTMLBasicNew.pdf
  735. }
  736. // ExampleFpdf_AddFont demonstrates the use of a non-standard font.
  737. func ExampleFpdf_AddFont() {
  738. pdf := gofpdf.New("P", "mm", "A4", example.FontDir())
  739. pdf.AddFont("Calligrapher", "", "calligra.json")
  740. pdf.AddPage()
  741. pdf.SetFont("Calligrapher", "", 35)
  742. pdf.Cell(0, 10, "Enjoy new fonts with FPDF!")
  743. fileStr := example.Filename("Fpdf_AddFont")
  744. err := pdf.OutputFileAndClose(fileStr)
  745. example.Summary(err, fileStr)
  746. // Output:
  747. // Successfully generated pdf/Fpdf_AddFont.pdf
  748. }
  749. // ExampleFpdf_WriteAligned demonstrates how to align text with the Write function.
  750. func ExampleFpdf_WriteAligned() {
  751. pdf := gofpdf.New("P", "mm", "A4", example.FontDir())
  752. pdf.SetLeftMargin(50.0)
  753. pdf.SetRightMargin(50.0)
  754. pdf.AddPage()
  755. pdf.SetFont("Helvetica", "", 12)
  756. pdf.WriteAligned(0, 35, "This text is the default alignment, Left", "")
  757. pdf.Ln(35)
  758. pdf.WriteAligned(0, 35, "This text is aligned Left", "L")
  759. pdf.Ln(35)
  760. pdf.WriteAligned(0, 35, "This text is aligned Center", "C")
  761. pdf.Ln(35)
  762. pdf.WriteAligned(0, 35, "This text is aligned Right", "R")
  763. pdf.Ln(35)
  764. line := "This can by used to write justified text"
  765. leftMargin, _, rightMargin, _ := pdf.GetMargins()
  766. pageWidth, _ := pdf.GetPageSize()
  767. pageWidth -= leftMargin + rightMargin
  768. pdf.SetWordSpacing((pageWidth - pdf.GetStringWidth(line)) / float64(strings.Count(line, " ")))
  769. pdf.WriteAligned(pageWidth, 35, line, "L")
  770. fileStr := example.Filename("Fpdf_WriteAligned")
  771. err := pdf.OutputFileAndClose(fileStr)
  772. example.Summary(err, fileStr)
  773. // Output:
  774. // Successfully generated pdf/Fpdf_WriteAligned.pdf
  775. }
  776. // ExampleFpdf_Image demonstrates how images are included in documents.
  777. func ExampleFpdf_Image() {
  778. pdf := gofpdf.New("P", "mm", "A4", "")
  779. pdf.AddPage()
  780. pdf.SetFont("Arial", "", 11)
  781. pdf.Image(example.ImageFile("logo.png"), 10, 10, 30, 0, false, "", 0, "")
  782. pdf.Text(50, 20, "logo.png")
  783. pdf.Image(example.ImageFile("logo.gif"), 10, 40, 30, 0, false, "", 0, "")
  784. pdf.Text(50, 50, "logo.gif")
  785. pdf.Image(example.ImageFile("logo-gray.png"), 10, 70, 30, 0, false, "", 0, "")
  786. pdf.Text(50, 80, "logo-gray.png")
  787. pdf.Image(example.ImageFile("logo-rgb.png"), 10, 100, 30, 0, false, "", 0, "")
  788. pdf.Text(50, 110, "logo-rgb.png")
  789. pdf.Image(example.ImageFile("logo.jpg"), 10, 130, 30, 0, false, "", 0, "")
  790. pdf.Text(50, 140, "logo.jpg")
  791. fileStr := example.Filename("Fpdf_Image")
  792. err := pdf.OutputFileAndClose(fileStr)
  793. example.Summary(err, fileStr)
  794. // Output:
  795. // Successfully generated pdf/Fpdf_Image.pdf
  796. }
  797. // ExampleFpdf_ImageOptions demonstrates how the AllowNegativePosition field of the
  798. // ImageOption struct can be used to affect horizontal image placement.
  799. func ExampleFpdf_ImageOptions() {
  800. var opt gofpdf.ImageOptions
  801. pdf := gofpdf.New("P", "mm", "A4", "")
  802. pdf.AddPage()
  803. pdf.SetFont("Arial", "", 11)
  804. pdf.SetX(60)
  805. opt.ImageType = "png"
  806. pdf.ImageOptions(example.ImageFile("logo.png"), -10, 10, 30, 0, false, opt, 0, "")
  807. opt.AllowNegativePosition = true
  808. pdf.ImageOptions(example.ImageFile("logo.png"), -10, 50, 30, 0, false, opt, 0, "")
  809. fileStr := example.Filename("Fpdf_ImageOptions")
  810. err := pdf.OutputFileAndClose(fileStr)
  811. example.Summary(err, fileStr)
  812. // Output:
  813. // Successfully generated pdf/Fpdf_ImageOptions.pdf
  814. }
  815. // ExampleFpdf_RegisterImageOptionsReader demonstrates how to load an image
  816. // from a io.Reader (in this case, a file) and register it with options.
  817. func ExampleFpdf_RegisterImageOptionsReader() {
  818. var (
  819. opt gofpdf.ImageOptions
  820. pdfStr string
  821. fl *os.File
  822. err error
  823. )
  824. pdfStr = example.Filename("Fpdf_RegisterImageOptionsReader")
  825. pdf := gofpdf.New("P", "mm", "A4", "")
  826. pdf.AddPage()
  827. pdf.SetFont("Arial", "", 11)
  828. fl, err = os.Open(example.ImageFile("logo.png"))
  829. if err == nil {
  830. opt.ImageType = "png"
  831. opt.AllowNegativePosition = true
  832. _ = pdf.RegisterImageOptionsReader("logo", opt, fl)
  833. fl.Close()
  834. for x := -20.0; x <= 40.0; x += 5 {
  835. pdf.ImageOptions("logo", x, x+30, 0, 0, false, opt, 0, "")
  836. }
  837. err = pdf.OutputFileAndClose(pdfStr)
  838. }
  839. example.Summary(err, pdfStr)
  840. // Output:
  841. // Successfully generated pdf/Fpdf_RegisterImageOptionsReader.pdf
  842. }
  843. // This example demonstrates Landscape mode with images.
  844. func ExampleFpdf_SetAcceptPageBreakFunc() {
  845. var y0 float64
  846. var crrntCol int
  847. loremStr := lorem()
  848. pdf := gofpdf.New("L", "mm", "A4", "")
  849. const (
  850. pageWd = 297.0 // A4 210.0 x 297.0
  851. margin = 10.0
  852. gutter = 4
  853. colNum = 3
  854. colWd = (pageWd - 2*margin - (colNum-1)*gutter) / colNum
  855. )
  856. setCol := func(col int) {
  857. crrntCol = col
  858. x := margin + float64(col)*(colWd+gutter)
  859. pdf.SetLeftMargin(x)
  860. pdf.SetX(x)
  861. }
  862. pdf.SetHeaderFunc(func() {
  863. titleStr := "gofpdf"
  864. pdf.SetFont("Helvetica", "B", 48)
  865. wd := pdf.GetStringWidth(titleStr) + 6
  866. pdf.SetX((pageWd - wd) / 2)
  867. pdf.SetTextColor(128, 128, 160)
  868. pdf.Write(12, titleStr[:2])
  869. pdf.SetTextColor(128, 128, 128)
  870. pdf.Write(12, titleStr[2:])
  871. pdf.Ln(20)
  872. y0 = pdf.GetY()
  873. })
  874. pdf.SetAcceptPageBreakFunc(func() bool {
  875. if crrntCol < colNum-1 {
  876. setCol(crrntCol + 1)
  877. pdf.SetY(y0)
  878. // Start new column, not new page
  879. return false
  880. }
  881. setCol(0)
  882. return true
  883. })
  884. pdf.AddPage()
  885. pdf.SetFont("Times", "", 12)
  886. for j := 0; j < 20; j++ {
  887. if j == 1 {
  888. pdf.Image(example.ImageFile("fpdf.png"), -1, 0, colWd, 0, true, "", 0, "")
  889. } else if j == 5 {
  890. pdf.Image(example.ImageFile("golang-gopher.png"),
  891. -1, 0, colWd, 0, true, "", 0, "")
  892. }
  893. pdf.MultiCell(colWd, 5, loremStr, "", "", false)
  894. pdf.Ln(-1)
  895. }
  896. fileStr := example.Filename("Fpdf_SetAcceptPageBreakFunc_landscape")
  897. err := pdf.OutputFileAndClose(fileStr)
  898. example.Summary(err, fileStr)
  899. // Output:
  900. // Successfully generated pdf/Fpdf_SetAcceptPageBreakFunc_landscape.pdf
  901. }
  902. // This example tests corner cases as reported by the gocov tool.
  903. func ExampleFpdf_SetKeywords() {
  904. var err error
  905. fileStr := example.Filename("Fpdf_SetKeywords")
  906. err = gofpdf.MakeFont(example.FontFile("CalligrapherRegular.pfb"),
  907. example.FontFile("cp1252.map"), example.FontDir(), nil, true)
  908. if err == nil {
  909. pdf := gofpdf.New("", "", "", "")
  910. pdf.SetFontLocation(example.FontDir())
  911. pdf.SetTitle("世界", true)
  912. pdf.SetAuthor("世界", true)
  913. pdf.SetSubject("世界", true)
  914. pdf.SetCreator("世界", true)
  915. pdf.SetKeywords("世界", true)
  916. pdf.AddFont("Calligrapher", "", "CalligrapherRegular.json")
  917. pdf.AddPage()
  918. pdf.SetFont("Calligrapher", "", 16)
  919. pdf.Writef(5, "\x95 %s \x95", pdf)
  920. err = pdf.OutputFileAndClose(fileStr)
  921. }
  922. example.Summary(err, fileStr)
  923. // Output:
  924. // Successfully generated pdf/Fpdf_SetKeywords.pdf
  925. }
  926. // ExampleFpdf_Circle demonstrates the construction of various geometric figures,
  927. func ExampleFpdf_Circle() {
  928. const (
  929. thin = 0.2
  930. thick = 3.0
  931. )
  932. pdf := gofpdf.New("", "", "", "")
  933. pdf.SetFont("Helvetica", "", 12)
  934. pdf.SetFillColor(200, 200, 220)
  935. pdf.AddPage()
  936. y := 15.0
  937. pdf.Text(10, y, "Circles")
  938. pdf.SetFillColor(200, 200, 220)
  939. pdf.SetLineWidth(thin)
  940. pdf.Circle(20, y+15, 10, "D")
  941. pdf.Circle(45, y+15, 10, "F")
  942. pdf.Circle(70, y+15, 10, "FD")
  943. pdf.SetLineWidth(thick)
  944. pdf.Circle(95, y+15, 10, "FD")
  945. pdf.SetLineWidth(thin)
  946. y += 40.0
  947. pdf.Text(10, y, "Ellipses")
  948. pdf.SetFillColor(220, 200, 200)
  949. pdf.Ellipse(30, y+15, 20, 10, 0, "D")
  950. pdf.Ellipse(75, y+15, 20, 10, 0, "F")
  951. pdf.Ellipse(120, y+15, 20, 10, 0, "FD")
  952. pdf.SetLineWidth(thick)
  953. pdf.Ellipse(165, y+15, 20, 10, 0, "FD")
  954. pdf.SetLineWidth(thin)
  955. y += 40.0
  956. pdf.Text(10, y, "Curves (quadratic)")
  957. pdf.SetFillColor(220, 220, 200)
  958. pdf.Curve(10, y+30, 15, y-20, 40, y+30, "D")
  959. pdf.Curve(45, y+30, 50, y-20, 75, y+30, "F")
  960. pdf.Curve(80, y+30, 85, y-20, 110, y+30, "FD")
  961. pdf.SetLineWidth(thick)
  962. pdf.Curve(115, y+30, 120, y-20, 145, y+30, "FD")
  963. pdf.SetLineCapStyle("round")
  964. pdf.Curve(150, y+30, 155, y-20, 180, y+30, "FD")
  965. pdf.SetLineWidth(thin)
  966. pdf.SetLineCapStyle("butt")
  967. y += 40.0
  968. pdf.Text(10, y, "Curves (cubic)")
  969. pdf.SetFillColor(220, 200, 220)
  970. pdf.CurveBezierCubic(10, y+30, 15, y-20, 10, y+30, 40, y+30, "D")
  971. pdf.CurveBezierCubic(45, y+30, 50, y-20, 45, y+30, 75, y+30, "F")
  972. pdf.CurveBezierCubic(80, y+30, 85, y-20, 80, y+30, 110, y+30, "FD")
  973. pdf.SetLineWidth(thick)
  974. pdf.CurveBezierCubic(115, y+30, 120, y-20, 115, y+30, 145, y+30, "FD")
  975. pdf.SetLineCapStyle("round")
  976. pdf.CurveBezierCubic(150, y+30, 155, y-20, 150, y+30, 180, y+30, "FD")
  977. pdf.SetLineWidth(thin)
  978. pdf.SetLineCapStyle("butt")
  979. y += 40.0
  980. pdf.Text(10, y, "Arcs")
  981. pdf.SetFillColor(200, 220, 220)
  982. pdf.SetLineWidth(thick)
  983. pdf.Arc(45, y+35, 20, 10, 0, 0, 180, "FD")
  984. pdf.SetLineWidth(thin)
  985. pdf.Arc(45, y+35, 25, 15, 0, 90, 270, "D")
  986. pdf.SetLineWidth(thick)
  987. pdf.Arc(45, y+35, 30, 20, 0, 0, 360, "D")
  988. pdf.SetLineCapStyle("round")
  989. pdf.Arc(135, y+35, 20, 10, 135, 0, 180, "FD")
  990. pdf.SetLineWidth(thin)
  991. pdf.Arc(135, y+35, 25, 15, 135, 90, 270, "D")
  992. pdf.SetLineWidth(thick)
  993. pdf.Arc(135, y+35, 30, 20, 135, 0, 360, "D")
  994. pdf.SetLineWidth(thin)
  995. pdf.SetLineCapStyle("butt")
  996. fileStr := example.Filename("Fpdf_Circle_figures")
  997. err := pdf.OutputFileAndClose(fileStr)
  998. example.Summary(err, fileStr)
  999. // Output:
  1000. // Successfully generated pdf/Fpdf_Circle_figures.pdf
  1001. }
  1002. // ExampleFpdf_SetAlpha demonstrates alpha transparency.
  1003. func ExampleFpdf_SetAlpha() {
  1004. const (
  1005. gapX = 10.0
  1006. gapY = 9.0
  1007. rectW = 40.0
  1008. rectH = 58.0
  1009. pageW = 210
  1010. pageH = 297
  1011. )
  1012. modeList := []string{"Normal", "Multiply", "Screen", "Overlay",
  1013. "Darken", "Lighten", "ColorDodge", "ColorBurn", "HardLight", "SoftLight",
  1014. "Difference", "Exclusion", "Hue", "Saturation", "Color", "Luminosity"}
  1015. pdf := gofpdf.New("", "", "", "")
  1016. pdf.SetLineWidth(2)
  1017. pdf.SetAutoPageBreak(false, 0)
  1018. pdf.AddPage()
  1019. pdf.SetFont("Helvetica", "", 18)
  1020. pdf.SetXY(0, gapY)
  1021. pdf.SetTextColor(0, 0, 0)
  1022. pdf.CellFormat(pageW, gapY, "Alpha Blending Modes", "", 0, "C", false, 0, "")
  1023. j := 0
  1024. y := 3 * gapY
  1025. for col := 0; col < 4; col++ {
  1026. x := gapX
  1027. for row := 0; row < 4; row++ {
  1028. pdf.Rect(x, y, rectW, rectH, "D")
  1029. pdf.SetFont("Helvetica", "B", 12)
  1030. pdf.SetFillColor(0, 0, 0)
  1031. pdf.SetTextColor(250, 250, 230)
  1032. pdf.SetXY(x, y+rectH-4)
  1033. pdf.CellFormat(rectW, 5, modeList[j], "", 0, "C", true, 0, "")
  1034. pdf.SetFont("Helvetica", "I", 150)
  1035. pdf.SetTextColor(80, 80, 120)
  1036. pdf.SetXY(x, y+2)
  1037. pdf.CellFormat(rectW, rectH, "A", "", 0, "C", false, 0, "")
  1038. pdf.SetAlpha(0.5, modeList[j])
  1039. pdf.Image(example.ImageFile("golang-gopher.png"),
  1040. x-gapX, y, rectW+2*gapX, 0, false, "", 0, "")
  1041. pdf.SetAlpha(1.0, "Normal")
  1042. x += rectW + gapX
  1043. j++
  1044. }
  1045. y += rectH + gapY
  1046. }
  1047. fileStr := example.Filename("Fpdf_SetAlpha_transparency")
  1048. err := pdf.OutputFileAndClose(fileStr)
  1049. example.Summary(err, fileStr)
  1050. // Output:
  1051. // Successfully generated pdf/Fpdf_SetAlpha_transparency.pdf
  1052. }
  1053. // ExampleFpdf_LinearGradient deomstrates various gradients.
  1054. func ExampleFpdf_LinearGradient() {
  1055. pdf := gofpdf.New("", "", "", "")
  1056. pdf.SetFont("Helvetica", "", 12)
  1057. pdf.AddPage()
  1058. pdf.LinearGradient(0, 0, 210, 100, 250, 250, 255, 220, 220, 225, 0, 0, 0, .5)
  1059. pdf.LinearGradient(20, 25, 75, 75, 220, 220, 250, 80, 80, 220, 0, .2, 0, .8)
  1060. pdf.Rect(20, 25, 75, 75, "D")
  1061. pdf.LinearGradient(115, 25, 75, 75, 220, 220, 250, 80, 80, 220, 0, 0, 1, 1)
  1062. pdf.Rect(115, 25, 75, 75, "D")
  1063. pdf.RadialGradient(20, 120, 75, 75, 220, 220, 250, 80, 80, 220,
  1064. 0.25, 0.75, 0.25, 0.75, 1)
  1065. pdf.Rect(20, 120, 75, 75, "D")
  1066. pdf.RadialGradient(115, 120, 75, 75, 220, 220, 250, 80, 80, 220,
  1067. 0.25, 0.75, 0.75, 0.75, 0.75)
  1068. pdf.Rect(115, 120, 75, 75, "D")
  1069. fileStr := example.Filename("Fpdf_LinearGradient_gradient")
  1070. err := pdf.OutputFileAndClose(fileStr)
  1071. example.Summary(err, fileStr)
  1072. // Output:
  1073. // Successfully generated pdf/Fpdf_LinearGradient_gradient.pdf
  1074. }
  1075. // ExampleFpdf_ClipText demonstrates clipping.
  1076. func ExampleFpdf_ClipText() {
  1077. pdf := gofpdf.New("", "", "", "")
  1078. y := 10.0
  1079. pdf.AddPage()
  1080. pdf.SetFont("Helvetica", "", 24)
  1081. pdf.SetXY(0, y)
  1082. pdf.ClipText(10, y+12, "Clipping examples", false)
  1083. pdf.RadialGradient(10, y, 100, 20, 128, 128, 160, 32, 32, 48,
  1084. 0.25, 0.5, 0.25, 0.5, 0.2)
  1085. pdf.ClipEnd()
  1086. y += 12
  1087. pdf.SetFont("Helvetica", "B", 120)
  1088. pdf.SetDrawColor(64, 80, 80)
  1089. pdf.SetLineWidth(.5)
  1090. pdf.ClipText(10, y+40, pdf.String(), true)
  1091. pdf.RadialGradient(10, y, 200, 50, 220, 220, 250, 80, 80, 220,
  1092. 0.25, 0.5, 0.25, 0.5, 1)
  1093. pdf.ClipEnd()
  1094. y += 55
  1095. pdf.ClipRect(10, y, 105, 20, true)
  1096. pdf.SetFillColor(255, 255, 255)
  1097. pdf.Rect(10, y, 105, 20, "F")
  1098. pdf.ClipCircle(40, y+10, 15, false)
  1099. pdf.RadialGradient(25, y, 30, 30, 220, 250, 220, 40, 60, 40, 0.3,
  1100. 0.85, 0.3, 0.85, 0.5)
  1101. pdf.ClipEnd()
  1102. pdf.ClipEllipse(80, y+10, 20, 15, false)
  1103. pdf.RadialGradient(60, y, 40, 30, 250, 220, 220, 60, 40, 40, 0.3,
  1104. 0.85, 0.3, 0.85, 0.5)
  1105. pdf.ClipEnd()
  1106. pdf.ClipEnd()
  1107. y += 28
  1108. pdf.ClipEllipse(26, y+10, 16, 10, true)
  1109. pdf.Image(example.ImageFile("logo.jpg"), 10, y, 32, 0, false, "JPG", 0, "")
  1110. pdf.ClipEnd()
  1111. pdf.ClipCircle(60, y+10, 10, true)
  1112. pdf.RadialGradient(50, y, 20, 20, 220, 220, 250, 40, 40, 60, 0.3,
  1113. 0.7, 0.3, 0.7, 0.5)
  1114. pdf.ClipEnd()
  1115. pdf.ClipPolygon([]gofpdf.PointType{{X: 80, Y: y + 20}, {X: 90, Y: y},
  1116. {X: 100, Y: y + 20}}, true)
  1117. pdf.LinearGradient(80, y, 20, 20, 250, 220, 250, 60, 40, 60, 0.5,
  1118. 1, 0.5, 0.5)
  1119. pdf.ClipEnd()
  1120. y += 30
  1121. pdf.SetLineWidth(.1)
  1122. pdf.SetDrawColor(180, 180, 180)
  1123. pdf.ClipRoundedRect(10, y, 120, 20, 5, true)
  1124. pdf.RadialGradient(10, y, 120, 20, 255, 255, 255, 240, 240, 220,
  1125. 0.25, 0.75, 0.25, 0.75, 0.5)
  1126. pdf.SetXY(5, y-5)
  1127. pdf.SetFont("Times", "", 12)
  1128. pdf.MultiCell(130, 5, lorem(), "", "", false)
  1129. pdf.ClipEnd()
  1130. y += 30
  1131. pdf.SetDrawColor(180, 100, 180)
  1132. pdf.ClipRoundedRectExt(10, y, 120, 20, 5, 10, 5, 10, true)
  1133. pdf.RadialGradient(10, y, 120, 20, 255, 255, 255, 240, 240, 220,
  1134. 0.25, 0.75, 0.25, 0.75, 0.5)
  1135. pdf.SetXY(5, y-5)
  1136. pdf.SetFont("Times", "", 12)
  1137. pdf.MultiCell(130, 5, lorem(), "", "", false)
  1138. pdf.ClipEnd()
  1139. fileStr := example.Filename("Fpdf_ClipText")
  1140. err := pdf.OutputFileAndClose(fileStr)
  1141. example.Summary(err, fileStr)
  1142. // Output:
  1143. // Successfully generated pdf/Fpdf_ClipText.pdf
  1144. }
  1145. // ExampleFpdf_PageSize generates a PDF document with various page sizes.
  1146. func ExampleFpdf_PageSize() {
  1147. pdf := gofpdf.NewCustom(&gofpdf.InitType{
  1148. UnitStr: "in",
  1149. Size: gofpdf.SizeType{Wd: 6, Ht: 6},
  1150. FontDirStr: example.FontDir(),
  1151. })
  1152. pdf.SetMargins(0.5, 1, 0.5)
  1153. pdf.SetFont("Times", "", 14)
  1154. pdf.AddPageFormat("L", gofpdf.SizeType{Wd: 3, Ht: 12})
  1155. pdf.SetXY(0.5, 1.5)
  1156. pdf.CellFormat(11, 0.2, "12 in x 3 in", "", 0, "C", false, 0, "")
  1157. pdf.AddPage() // Default size established in NewCustom()
  1158. pdf.SetXY(0.5, 3)
  1159. pdf.CellFormat(5, 0.2, "6 in x 6 in", "", 0, "C", false, 0, "")
  1160. pdf.AddPageFormat("P", gofpdf.SizeType{Wd: 3, Ht: 12})
  1161. pdf.SetXY(0.5, 6)
  1162. pdf.CellFormat(2, 0.2, "3 in x 12 in", "", 0, "C", false, 0, "")
  1163. for j := 0; j <= 3; j++ {
  1164. wd, ht, u := pdf.PageSize(j)
  1165. fmt.Printf("%d: %6.2f %s, %6.2f %s\n", j, wd, u, ht, u)
  1166. }
  1167. fileStr := example.Filename("Fpdf_PageSize")
  1168. err := pdf.OutputFileAndClose(fileStr)
  1169. example.Summary(err, fileStr)
  1170. // Output:
  1171. // 0: 6.00 in, 6.00 in
  1172. // 1: 12.00 in, 3.00 in
  1173. // 2: 6.00 in, 6.00 in
  1174. // 3: 3.00 in, 12.00 in
  1175. // Successfully generated pdf/Fpdf_PageSize.pdf
  1176. }
  1177. // ExampleFpdf_Bookmark demonstrates the Bookmark method.
  1178. func ExampleFpdf_Bookmark() {
  1179. pdf := gofpdf.New("P", "mm", "A4", "")
  1180. pdf.AddPage()
  1181. pdf.SetFont("Arial", "", 15)
  1182. pdf.Bookmark("Page 1", 0, 0)
  1183. pdf.Bookmark("Paragraph 1", 1, -1)
  1184. pdf.Cell(0, 6, "Paragraph 1")
  1185. pdf.Ln(50)
  1186. pdf.Bookmark("Paragraph 2", 1, -1)
  1187. pdf.Cell(0, 6, "Paragraph 2")
  1188. pdf.AddPage()
  1189. pdf.Bookmark("Page 2", 0, 0)
  1190. pdf.Bookmark("Paragraph 3", 1, -1)
  1191. pdf.Cell(0, 6, "Paragraph 3")
  1192. fileStr := example.Filename("Fpdf_Bookmark")
  1193. err := pdf.OutputFileAndClose(fileStr)
  1194. example.Summary(err, fileStr)
  1195. // Output:
  1196. // Successfully generated pdf/Fpdf_Bookmark.pdf
  1197. }
  1198. // ExampleFpdf_TransformBegin demonstrates various transformations. It is adapted from an
  1199. // example script by Moritz Wagner and Andreas Würmser.
  1200. func ExampleFpdf_TransformBegin() {
  1201. const (
  1202. light = 200
  1203. dark = 0
  1204. )
  1205. var refX, refY float64
  1206. var refStr string
  1207. pdf := gofpdf.New("P", "mm", "A4", "")
  1208. pdf.AddPage()
  1209. color := func(val int) {
  1210. pdf.SetDrawColor(val, val, val)
  1211. pdf.SetTextColor(val, val, val)
  1212. }
  1213. reference := func(str string, x, y float64, val int) {
  1214. color(val)
  1215. pdf.Rect(x, y, 40, 10, "D")
  1216. pdf.Text(x, y-1, str)
  1217. }
  1218. refDraw := func(str string, x, y float64) {
  1219. refStr = str
  1220. refX = x
  1221. refY = y
  1222. reference(str, x, y, light)
  1223. }
  1224. refDupe := func() {
  1225. reference(refStr, refX, refY, dark)
  1226. }
  1227. titleStr := "Transformations"
  1228. titlePt := 36.0
  1229. titleHt := pdf.PointConvert(titlePt)
  1230. pdf.SetFont("Helvetica", "", titlePt)
  1231. titleWd := pdf.GetStringWidth(titleStr)
  1232. titleX := (210 - titleWd) / 2
  1233. pdf.Text(titleX, 10+titleHt, titleStr)
  1234. pdf.TransformBegin()
  1235. pdf.TransformMirrorVertical(10 + titleHt + 0.5)
  1236. pdf.ClipText(titleX, 10+titleHt, titleStr, false)
  1237. // Remember that the transform will mirror the gradient box too
  1238. pdf.LinearGradient(titleX, 10, titleWd, titleHt+4, 120, 120, 120,
  1239. 255, 255, 255, 0, 0, 0, 0.6)
  1240. pdf.ClipEnd()
  1241. pdf.TransformEnd()
  1242. pdf.SetFont("Helvetica", "", 12)
  1243. // Scale by 150% centered by lower left corner of the rectangle
  1244. refDraw("Scale", 50, 60)
  1245. pdf.TransformBegin()
  1246. pdf.TransformScaleXY(150, 50, 70)
  1247. refDupe()
  1248. pdf.TransformEnd()
  1249. // Translate 7 to the right, 5 to the bottom
  1250. refDraw("Translate", 125, 60)
  1251. pdf.TransformBegin()
  1252. pdf.TransformTranslate(7, 5)
  1253. refDupe()
  1254. pdf.TransformEnd()
  1255. // Rotate 20 degrees counter-clockwise centered by the lower left corner of
  1256. // the rectangle
  1257. refDraw("Rotate", 50, 110)
  1258. pdf.TransformBegin()
  1259. pdf.TransformRotate(20, 50, 120)
  1260. refDupe()
  1261. pdf.TransformEnd()
  1262. // Skew 30 degrees along the x-axis centered by the lower left corner of the
  1263. // rectangle
  1264. refDraw("Skew", 125, 110)
  1265. pdf.TransformBegin()
  1266. pdf.TransformSkewX(30, 125, 110)
  1267. refDupe()
  1268. pdf.TransformEnd()
  1269. // Mirror horizontally with axis of reflection at left side of the rectangle
  1270. refDraw("Mirror horizontal", 50, 160)
  1271. pdf.TransformBegin()
  1272. pdf.TransformMirrorHorizontal(50)
  1273. refDupe()
  1274. pdf.TransformEnd()
  1275. // Mirror vertically with axis of reflection at bottom side of the rectangle
  1276. refDraw("Mirror vertical", 125, 160)
  1277. pdf.TransformBegin()
  1278. pdf.TransformMirrorVertical(170)
  1279. refDupe()
  1280. pdf.TransformEnd()
  1281. // Reflect against a point at the lower left point of rectangle
  1282. refDraw("Mirror point", 50, 210)
  1283. pdf.TransformBegin()
  1284. pdf.TransformMirrorPoint(50, 220)
  1285. refDupe()
  1286. pdf.TransformEnd()
  1287. // Mirror against a straight line described by a point and an angle
  1288. angle := -20.0
  1289. px := 120.0
  1290. py := 220.0
  1291. refDraw("Mirror line", 125, 210)
  1292. pdf.TransformBegin()
  1293. pdf.TransformRotate(angle, px, py)
  1294. pdf.Line(px-1, py-1, px+1, py+1)
  1295. pdf.Line(px-1, py+1, px+1, py-1)
  1296. pdf.Line(px-5, py, px+60, py)
  1297. pdf.TransformEnd()
  1298. pdf.TransformBegin()
  1299. pdf.TransformMirrorLine(angle, px, py)
  1300. refDupe()
  1301. pdf.TransformEnd()
  1302. fileStr := example.Filename("Fpdf_TransformBegin")
  1303. err := pdf.OutputFileAndClose(fileStr)
  1304. example.Summary(err, fileStr)
  1305. // Output:
  1306. // Successfully generated pdf/Fpdf_TransformBegin.pdf
  1307. }
  1308. // ExampleFpdf_RegisterImage demonstrates Lawrence Kesteloot's image registration code.
  1309. func ExampleFpdf_RegisterImage() {
  1310. const (
  1311. margin = 10
  1312. wd = 210
  1313. ht = 297
  1314. )
  1315. fileList := []string{
  1316. "logo-gray.png",
  1317. "logo.jpg",
  1318. "logo.png",
  1319. "logo-rgb.png",
  1320. "logo-progressive.jpg",
  1321. }
  1322. var infoPtr *gofpdf.ImageInfoType
  1323. var imageFileStr string
  1324. var imgWd, imgHt, lf, tp float64
  1325. pdf := gofpdf.New("P", "mm", "A4", "")
  1326. pdf.AddPage()
  1327. pdf.SetMargins(10, 10, 10)
  1328. pdf.SetFont("Helvetica", "", 15)
  1329. for j, str := range fileList {
  1330. imageFileStr = example.ImageFile(str)
  1331. infoPtr = pdf.RegisterImage(imageFileStr, "")
  1332. imgWd, imgHt = infoPtr.Extent()
  1333. switch j {
  1334. case 0:
  1335. lf = margin
  1336. tp = margin
  1337. case 1:
  1338. lf = wd - margin - imgWd
  1339. tp = margin
  1340. case 2:
  1341. lf = (wd - imgWd) / 2.0
  1342. tp = (ht - imgHt) / 2.0
  1343. case 3:
  1344. lf = margin
  1345. tp = ht - imgHt - margin
  1346. case 4:
  1347. lf = wd - imgWd - margin
  1348. tp = ht - imgHt - margin
  1349. }
  1350. pdf.Image(imageFileStr, lf, tp, imgWd, imgHt, false, "", 0, "")
  1351. }
  1352. fileStr := example.Filename("Fpdf_RegisterImage")
  1353. // Test the image information retrieval method
  1354. infoShow := func(imageStr string) {
  1355. imageStr = example.ImageFile(imageStr)
  1356. info := pdf.GetImageInfo(imageStr)
  1357. if info != nil {
  1358. if info.Width() > 0.0 {
  1359. fmt.Printf("Image %s is registered\n", filepath.ToSlash(imageStr))
  1360. } else {
  1361. fmt.Printf("Incorrect information for image %s\n", filepath.ToSlash(imageStr))
  1362. }
  1363. } else {
  1364. fmt.Printf("Image %s is not registered\n", filepath.ToSlash(imageStr))
  1365. }
  1366. }
  1367. infoShow(fileList[0])
  1368. infoShow("foo.png")
  1369. err := pdf.OutputFileAndClose(fileStr)
  1370. example.Summary(err, fileStr)
  1371. // Output:
  1372. // Image image/logo-gray.png is registered
  1373. // Image image/foo.png is not registered
  1374. // Successfully generated pdf/Fpdf_RegisterImage.pdf
  1375. }
  1376. // ExampleFpdf_SplitLines demonstrates Bruno Michel's line splitting function.
  1377. func ExampleFpdf_SplitLines() {
  1378. const (
  1379. fontPtSize = 18.0
  1380. wd = 100.0
  1381. )
  1382. pdf := gofpdf.New("P", "mm", "A4", "") // A4 210.0 x 297.0
  1383. pdf.SetFont("Times", "", fontPtSize)
  1384. _, lineHt := pdf.GetFontSize()
  1385. pdf.AddPage()
  1386. pdf.SetMargins(10, 10, 10)
  1387. lines := pdf.SplitLines([]byte(lorem()), wd)
  1388. ht := float64(len(lines)) * lineHt
  1389. y := (297.0 - ht) / 2.0
  1390. pdf.SetDrawColor(128, 128, 128)
  1391. pdf.SetFillColor(255, 255, 210)
  1392. x := (210.0 - (wd + 40.0)) / 2.0
  1393. pdf.Rect(x, y-20.0, wd+40.0, ht+40.0, "FD")
  1394. pdf.SetY(y)
  1395. for _, line := range lines {
  1396. pdf.CellFormat(190.0, lineHt, string(line), "", 1, "C", false, 0, "")
  1397. }
  1398. fileStr := example.Filename("Fpdf_Splitlines")
  1399. err := pdf.OutputFileAndClose(fileStr)
  1400. example.Summary(err, fileStr)
  1401. // Output:
  1402. // Successfully generated pdf/Fpdf_Splitlines.pdf
  1403. }
  1404. // ExampleFpdf_SVGBasicWrite demonstrates how to render a simple path-only SVG image of the
  1405. // type generated by the jSignature web control.
  1406. func ExampleFpdf_SVGBasicWrite() {
  1407. const (
  1408. fontPtSize = 16.0
  1409. wd = 100.0
  1410. sigFileStr = "signature.svg"
  1411. )
  1412. var (
  1413. sig gofpdf.SVGBasicType
  1414. err error
  1415. )
  1416. pdf := gofpdf.New("P", "mm", "A4", "") // A4 210.0 x 297.0
  1417. pdf.SetFont("Times", "", fontPtSize)
  1418. lineHt := pdf.PointConvert(fontPtSize)
  1419. pdf.AddPage()
  1420. pdf.SetMargins(10, 10, 10)
  1421. htmlStr := `This example renders a simple ` +
  1422. `<a href="http://www.w3.org/TR/SVG/">SVG</a> (scalable vector graphics) ` +
  1423. `image that contains only basic path commands without any styling, ` +
  1424. `color fill, reflection or endpoint closures. In particular, the ` +
  1425. `type of vector graphic returned from a ` +
  1426. `<a href="http://willowsystems.github.io/jSignature/#/demo/">jSignature</a> ` +
  1427. `web control is supported and is used in this example.`
  1428. html := pdf.HTMLBasicNew()
  1429. html.Write(lineHt, htmlStr)
  1430. sig, err = gofpdf.SVGBasicFileParse(example.ImageFile(sigFileStr))
  1431. if err == nil {
  1432. scale := 100 / sig.Wd
  1433. scaleY := 30 / sig.Ht
  1434. if scale > scaleY {
  1435. scale = scaleY
  1436. }
  1437. pdf.SetLineCapStyle("round")
  1438. pdf.SetLineWidth(0.25)
  1439. pdf.SetDrawColor(0, 0, 128)
  1440. pdf.SetXY((210.0-scale*sig.Wd)/2.0, pdf.GetY()+10)
  1441. pdf.SVGBasicWrite(&sig, scale)
  1442. } else {
  1443. pdf.SetError(err)
  1444. }
  1445. fileStr := example.Filename("Fpdf_SVGBasicWrite")
  1446. err = pdf.OutputFileAndClose(fileStr)
  1447. example.Summary(err, fileStr)
  1448. // Output:
  1449. // Successfully generated pdf/Fpdf_SVGBasicWrite.pdf
  1450. }
  1451. // ExampleFpdf_CellFormat_align demonstrates Stefan Schroeder's code to control vertical
  1452. // alignment.
  1453. func ExampleFpdf_CellFormat_align() {
  1454. type recType struct {
  1455. align, txt string
  1456. }
  1457. recList := []recType{
  1458. {"TL", "top left"},
  1459. {"TC", "top center"},
  1460. {"TR", "top right"},
  1461. {"LM", "middle left"},
  1462. {"CM", "middle center"},
  1463. {"RM", "middle right"},
  1464. {"BL", "bottom left"},
  1465. {"BC", "bottom center"},
  1466. {"BR", "bottom right"},
  1467. }
  1468. recListBaseline := []recType{
  1469. {"AL", "baseline left"},
  1470. {"AC", "baseline center"},
  1471. {"AR", "baseline right"},
  1472. }
  1473. var formatRect = func(pdf *gofpdf.Fpdf, recList []recType) {
  1474. linkStr := ""
  1475. for pageJ := 0; pageJ < 2; pageJ++ {
  1476. pdf.AddPage()
  1477. pdf.SetMargins(10, 10, 10)
  1478. pdf.SetAutoPageBreak(false, 0)
  1479. borderStr := "1"
  1480. for _, rec := range recList {
  1481. pdf.SetXY(20, 20)
  1482. pdf.CellFormat(170, 257, rec.txt, borderStr, 0, rec.align, false, 0, linkStr)
  1483. borderStr = ""
  1484. }
  1485. linkStr = "https://github.com/jung-kurt/gofpdf"
  1486. }
  1487. }
  1488. pdf := gofpdf.New("P", "mm", "A4", "") // A4 210.0 x 297.0
  1489. pdf.SetFont("Helvetica", "", 16)
  1490. formatRect(pdf, recList)
  1491. formatRect(pdf, recListBaseline)
  1492. var fr fontResourceType
  1493. pdf.SetFontLoader(fr)
  1494. pdf.AddFont("Calligrapher", "", "calligra.json")
  1495. pdf.SetFont("Calligrapher", "", 16)
  1496. formatRect(pdf, recListBaseline)
  1497. fileStr := example.Filename("Fpdf_CellFormat_align")
  1498. err := pdf.OutputFileAndClose(fileStr)
  1499. example.Summary(err, fileStr)
  1500. // Output:
  1501. // Generalized font loader reading calligra.json
  1502. // Generalized font loader reading calligra.z
  1503. // Successfully generated pdf/Fpdf_CellFormat_align.pdf
  1504. }
  1505. // ExampleFpdf_CellFormat_codepageescape demonstrates the use of characters in the high range of the
  1506. // Windows-1252 code page (gofdpf default). See the example for CellFormat (4)
  1507. // for a way to do this automatically.
  1508. func ExampleFpdf_CellFormat_codepageescape() {
  1509. pdf := gofpdf.New("P", "mm", "A4", "") // A4 210.0 x 297.0
  1510. fontSize := 16.0
  1511. pdf.SetFont("Helvetica", "", fontSize)
  1512. ht := pdf.PointConvert(fontSize)
  1513. write := func(str string) {
  1514. pdf.CellFormat(190, ht, str, "", 1, "C", false, 0, "")
  1515. pdf.Ln(ht)
  1516. }
  1517. pdf.AddPage()
  1518. htmlStr := `Until gofpdf supports UTF-8 encoded source text, source text needs ` +
  1519. `to be specified with all special characters escaped to match the code page ` +
  1520. `layout of the currently selected font. By default, gofdpf uses code page 1252.` +
  1521. ` See <a href="http://en.wikipedia.org/wiki/Windows-1252">Wikipedia</a> for ` +
  1522. `a table of this layout.`
  1523. html := pdf.HTMLBasicNew()
  1524. html.Write(ht, htmlStr)
  1525. pdf.Ln(2 * ht)
  1526. write("Voix ambigu\xeb d'un c\x9cur qui au z\xe9phyr pr\xe9f\xe8re les jattes de kiwi.")
  1527. write("Falsches \xdcben von Xylophonmusik qu\xe4lt jeden gr\xf6\xdferen Zwerg.")
  1528. write("Heiz\xf6lr\xfccksto\xdfabd\xe4mpfung")
  1529. write("For\xe5rsj\xe6vnd\xf8gn / Efter\xe5rsj\xe6vnd\xf8gn")
  1530. fileStr := example.Filename("Fpdf_CellFormat_codepageescape")
  1531. err := pdf.OutputFileAndClose(fileStr)
  1532. example.Summary(err, fileStr)
  1533. // Output:
  1534. // Successfully generated pdf/Fpdf_CellFormat_codepageescape.pdf
  1535. }
  1536. // ExampleFpdf_CellFormat_codepage demonstrates the automatic conversion of UTF-8 strings to an
  1537. // 8-bit font encoding.
  1538. func ExampleFpdf_CellFormat_codepage() {
  1539. pdf := gofpdf.New("P", "mm", "A4", example.FontDir()) // A4 210.0 x 297.0
  1540. // See documentation for details on how to generate fonts
  1541. pdf.AddFont("Helvetica-1251", "", "helvetica_1251.json")
  1542. pdf.AddFont("Helvetica-1253", "", "helvetica_1253.json")
  1543. fontSize := 16.0
  1544. pdf.SetFont("Helvetica", "", fontSize)
  1545. ht := pdf.PointConvert(fontSize)
  1546. tr := pdf.UnicodeTranslatorFromDescriptor("") // "" defaults to "cp1252"
  1547. write := func(str string) {
  1548. // pdf.CellFormat(190, ht, tr(str), "", 1, "C", false, 0, "")
  1549. pdf.MultiCell(190, ht, tr(str), "", "C", false)
  1550. pdf.Ln(ht)
  1551. }
  1552. pdf.AddPage()
  1553. str := `Gofpdf provides a translator that will convert any UTF-8 code point ` +
  1554. `that is present in the specified code page.`
  1555. pdf.MultiCell(190, ht, str, "", "L", false)
  1556. pdf.Ln(2 * ht)
  1557. write("Voix ambiguë d'un cœur qui au zéphyr préfère les jattes de kiwi.")
  1558. write("Falsches Üben von Xylophonmusik quält jeden größeren Zwerg.")
  1559. write("Heizölrückstoßabdämpfung")
  1560. write("Forårsjævndøgn / Efterårsjævndøgn")
  1561. write("À noite, vovô Kowalsky vê o ímã cair no pé do pingüim queixoso e vovó" +
  1562. "põe açúcar no chá de tâmaras do jabuti feliz.")
  1563. pdf.SetFont("Helvetica-1251", "", fontSize) // Name matches one specified in AddFont()
  1564. tr = pdf.UnicodeTranslatorFromDescriptor("cp1251")
  1565. write("Съешь же ещё этих мягких французских булок, да выпей чаю.")
  1566. pdf.SetFont("Helvetica-1253", "", fontSize)
  1567. tr = pdf.UnicodeTranslatorFromDescriptor("cp1253")
  1568. write("Θέλει αρετή και τόλμη η ελευθερία. (Ανδρέας Κάλβος)")
  1569. fileStr := example.Filename("Fpdf_CellFormat_codepage")
  1570. err := pdf.OutputFileAndClose(fileStr)
  1571. example.Summary(err, fileStr)
  1572. // Output:
  1573. // Successfully generated pdf/Fpdf_CellFormat_codepage.pdf
  1574. }
  1575. // ExampleFpdf_SetProtection demonstrates password protection for documents.
  1576. func ExampleFpdf_SetProtection() {
  1577. pdf := gofpdf.New("P", "mm", "A4", "")
  1578. pdf.SetProtection(gofpdf.CnProtectPrint, "123", "abc")
  1579. pdf.AddPage()
  1580. pdf.SetFont("Arial", "", 12)
  1581. pdf.Write(10, "Password-protected.")
  1582. fileStr := example.Filename("Fpdf_SetProtection")
  1583. err := pdf.OutputFileAndClose(fileStr)
  1584. example.Summary(err, fileStr)
  1585. // Output:
  1586. // Successfully generated pdf/Fpdf_SetProtection.pdf
  1587. }
  1588. // ExampleFpdf_Polygon displays equilateral polygons in a demonstration of the Polygon
  1589. // function.
  1590. func ExampleFpdf_Polygon() {
  1591. const rowCount = 5
  1592. const colCount = 4
  1593. const ptSize = 36
  1594. var x, y, radius, gap, advance float64
  1595. var rgVal int
  1596. var pts []gofpdf.PointType
  1597. vertices := func(count int) (res []gofpdf.PointType) {
  1598. var pt gofpdf.PointType
  1599. res = make([]gofpdf.PointType, 0, count)
  1600. mlt := 2.0 * math.Pi / float64(count)
  1601. for j := 0; j < count; j++ {
  1602. pt.Y, pt.X = math.Sincos(float64(j) * mlt)
  1603. res = append(res, gofpdf.PointType{
  1604. X: x + radius*pt.X,
  1605. Y: y + radius*pt.Y})
  1606. }
  1607. return
  1608. }
  1609. pdf := gofpdf.New("P", "mm", "A4", "") // A4 210.0 x 297.0
  1610. pdf.AddPage()
  1611. pdf.SetFont("Helvetica", "", ptSize)
  1612. pdf.SetDrawColor(0, 80, 180)
  1613. gap = 12.0
  1614. pdf.SetY(gap)
  1615. pdf.CellFormat(190.0, gap, "Equilateral polygons", "", 1, "C", false, 0, "")
  1616. radius = (210.0 - float64(colCount+1)*gap) / (2.0 * float64(colCount))
  1617. advance = gap + 2.0*radius
  1618. y = 2*gap + pdf.PointConvert(ptSize) + radius
  1619. rgVal = 230
  1620. for row := 0; row < rowCount; row++ {
  1621. pdf.SetFillColor(rgVal, rgVal, 0)
  1622. rgVal -= 12
  1623. x = gap + radius
  1624. for col := 0; col < colCount; col++ {
  1625. pts = vertices(row*colCount + col + 3)
  1626. pdf.Polygon(pts, "FD")
  1627. x += advance
  1628. }
  1629. y += advance
  1630. }
  1631. fileStr := example.Filename("Fpdf_Polygon")
  1632. err := pdf.OutputFileAndClose(fileStr)
  1633. example.Summary(err, fileStr)
  1634. // Output:
  1635. // Successfully generated pdf/Fpdf_Polygon.pdf
  1636. }
  1637. // ExampleFpdf_AddLayer demonstrates document layers. The initial visibility of a layer
  1638. // is specified with the second parameter to AddLayer(). The layer list
  1639. // displayed by the document reader allows layer visibility to be controlled
  1640. // interactively.
  1641. func ExampleFpdf_AddLayer() {
  1642. pdf := gofpdf.New("P", "mm", "A4", "")
  1643. pdf.AddPage()
  1644. pdf.SetFont("Arial", "", 15)
  1645. pdf.Write(8, "This line doesn't belong to any layer.\n")
  1646. // Define layers
  1647. l1 := pdf.AddLayer("Layer 1", true)
  1648. l2 := pdf.AddLayer("Layer 2", true)
  1649. // Open layer pane in PDF viewer
  1650. pdf.OpenLayerPane()
  1651. // First layer
  1652. pdf.BeginLayer(l1)
  1653. pdf.Write(8, "This line belongs to layer 1.\n")
  1654. pdf.EndLayer()
  1655. // Second layer
  1656. pdf.BeginLayer(l2)
  1657. pdf.Write(8, "This line belongs to layer 2.\n")
  1658. pdf.EndLayer()
  1659. // First layer again
  1660. pdf.BeginLayer(l1)
  1661. pdf.Write(8, "This line belongs to layer 1 again.\n")
  1662. pdf.EndLayer()
  1663. fileStr := example.Filename("Fpdf_AddLayer")
  1664. err := pdf.OutputFileAndClose(fileStr)
  1665. example.Summary(err, fileStr)
  1666. // Output:
  1667. // Successfully generated pdf/Fpdf_AddLayer.pdf
  1668. }
  1669. // ExampleFpdf_RegisterImageReader demonstrates the use of an image that is retrieved from a web
  1670. // server.
  1671. func ExampleFpdf_RegisterImageReader() {
  1672. const (
  1673. margin = 10
  1674. wd = 210
  1675. ht = 297
  1676. fontSize = 15
  1677. urlStr = "https://github.com/jung-kurt/gofpdf/blob/master/image/gofpdf.png?raw=true"
  1678. msgStr = `Images from the web can be easily embedded when a PDF document is generated.`
  1679. )
  1680. var (
  1681. rsp *http.Response
  1682. err error
  1683. tp string
  1684. )
  1685. pdf := gofpdf.New("P", "mm", "A4", "")
  1686. pdf.AddPage()
  1687. pdf.SetFont("Helvetica", "", fontSize)
  1688. ln := pdf.PointConvert(fontSize)
  1689. pdf.MultiCell(wd-margin-margin, ln, msgStr, "", "L", false)
  1690. rsp, err = http.Get(urlStr)
  1691. if err == nil {
  1692. tp = pdf.ImageTypeFromMime(rsp.Header["Content-Type"][0])
  1693. infoPtr := pdf.RegisterImageReader(urlStr, tp, rsp.Body)
  1694. if pdf.Ok() {
  1695. imgWd, imgHt := infoPtr.Extent()
  1696. pdf.Image(urlStr, (wd-imgWd)/2.0, pdf.GetY()+ln,
  1697. imgWd, imgHt, false, tp, 0, "")
  1698. }
  1699. } else {
  1700. pdf.SetError(err)
  1701. }
  1702. fileStr := example.Filename("Fpdf_RegisterImageReader_url")
  1703. err = pdf.OutputFileAndClose(fileStr)
  1704. example.Summary(err, fileStr)
  1705. // Output:
  1706. // Successfully generated pdf/Fpdf_RegisterImageReader_url.pdf
  1707. }
  1708. // ExampleFpdf_Beziergon demonstrates the Beziergon function.
  1709. func ExampleFpdf_Beziergon() {
  1710. const (
  1711. margin = 10
  1712. wd = 210
  1713. unit = (wd - 2*margin) / 6
  1714. ht = 297
  1715. fontSize = 15
  1716. msgStr = `Demonstration of Beziergon function`
  1717. coefficient = 0.6
  1718. delta = coefficient * unit
  1719. ln = fontSize * 25.4 / 72
  1720. offsetX = (wd - 4*unit) / 2.0
  1721. offsetY = offsetX + 2*ln
  1722. )
  1723. srcList := []gofpdf.PointType{
  1724. {X: 0, Y: 0},
  1725. {X: 1, Y: 0},
  1726. {X: 1, Y: 1},
  1727. {X: 2, Y: 1},
  1728. {X: 2, Y: 2},
  1729. {X: 3, Y: 2},
  1730. {X: 3, Y: 3},
  1731. {X: 4, Y: 3},
  1732. {X: 4, Y: 4},
  1733. {X: 1, Y: 4},
  1734. {X: 1, Y: 3},
  1735. {X: 0, Y: 3},
  1736. }
  1737. ctrlList := []gofpdf.PointType{
  1738. {X: 1, Y: -1},
  1739. {X: 1, Y: 1},
  1740. {X: 1, Y: 1},
  1741. {X: 1, Y: 1},
  1742. {X: 1, Y: 1},
  1743. {X: 1, Y: 1},
  1744. {X: 1, Y: 1},
  1745. {X: 1, Y: 1},
  1746. {X: -1, Y: 1},
  1747. {X: -1, Y: -1},
  1748. {X: -1, Y: -1},
  1749. {X: -1, Y: -1},
  1750. }
  1751. pdf := gofpdf.New("P", "mm", "A4", "")
  1752. pdf.AddPage()
  1753. pdf.SetFont("Helvetica", "", fontSize)
  1754. for j, src := range srcList {
  1755. srcList[j].X = offsetX + src.X*unit
  1756. srcList[j].Y = offsetY + src.Y*unit
  1757. }
  1758. for j, ctrl := range ctrlList {
  1759. ctrlList[j].X = ctrl.X * delta
  1760. ctrlList[j].Y = ctrl.Y * delta
  1761. }
  1762. jPrev := len(srcList) - 1
  1763. srcPrev := srcList[jPrev]
  1764. curveList := []gofpdf.PointType{srcPrev} // point [, control 0, control 1, point]*
  1765. control := func(x, y float64) {
  1766. curveList = append(curveList, gofpdf.PointType{X: x, Y: y})
  1767. }
  1768. for j, src := range srcList {
  1769. ctrl := ctrlList[jPrev]
  1770. control(srcPrev.X+ctrl.X, srcPrev.Y+ctrl.Y) // Control 0
  1771. ctrl = ctrlList[j]
  1772. control(src.X-ctrl.X, src.Y-ctrl.Y) // Control 1
  1773. curveList = append(curveList, src) // Destination
  1774. jPrev = j
  1775. srcPrev = src
  1776. }
  1777. pdf.MultiCell(wd-margin-margin, ln, msgStr, "", "C", false)
  1778. pdf.SetDashPattern([]float64{0.8, 0.8}, 0)
  1779. pdf.SetDrawColor(160, 160, 160)
  1780. pdf.Polygon(srcList, "D")
  1781. pdf.SetDashPattern([]float64{}, 0)
  1782. pdf.SetDrawColor(64, 64, 128)
  1783. pdf.SetLineWidth(pdf.GetLineWidth() * 3)
  1784. pdf.Beziergon(curveList, "D")
  1785. fileStr := example.Filename("Fpdf_Beziergon")
  1786. err := pdf.OutputFileAndClose(fileStr)
  1787. example.Summary(err, fileStr)
  1788. // Output:
  1789. // Successfully generated pdf/Fpdf_Beziergon.pdf
  1790. }
  1791. // ExampleFpdf_SetFontLoader demonstrates loading a non-standard font using a generalized
  1792. // font loader. fontResourceType implements the FontLoader interface and is
  1793. // defined locally in the test source code.
  1794. func ExampleFpdf_SetFontLoader() {
  1795. var fr fontResourceType
  1796. pdf := gofpdf.New("P", "mm", "A4", "")
  1797. pdf.SetFontLoader(fr)
  1798. pdf.AddFont("Calligrapher", "", "calligra.json")
  1799. pdf.AddPage()
  1800. pdf.SetFont("Calligrapher", "", 35)
  1801. pdf.Cell(0, 10, "Load fonts from any source")
  1802. fileStr := example.Filename("Fpdf_SetFontLoader")
  1803. err := pdf.OutputFileAndClose(fileStr)
  1804. example.Summary(err, fileStr)
  1805. // Output:
  1806. // Generalized font loader reading calligra.json
  1807. // Generalized font loader reading calligra.z
  1808. // Successfully generated pdf/Fpdf_SetFontLoader.pdf
  1809. }
  1810. // ExampleFpdf_MoveTo demonstrates the Path Drawing functions, such as: MoveTo,
  1811. // LineTo, CurveTo, ..., ClosePath and DrawPath.
  1812. func ExampleFpdf_MoveTo() {
  1813. pdf := gofpdf.New("P", "mm", "A4", "")
  1814. pdf.AddPage()
  1815. pdf.MoveTo(20, 20)
  1816. pdf.LineTo(170, 20)
  1817. pdf.ArcTo(170, 40, 20, 20, 0, 90, 0)
  1818. pdf.CurveTo(190, 100, 105, 100)
  1819. pdf.CurveBezierCubicTo(20, 100, 105, 200, 20, 200)
  1820. pdf.ClosePath()
  1821. pdf.SetFillColor(200, 200, 200)
  1822. pdf.SetLineWidth(3)
  1823. pdf.DrawPath("DF")
  1824. fileStr := example.Filename("Fpdf_MoveTo_path")
  1825. err := pdf.OutputFileAndClose(fileStr)
  1826. example.Summary(err, fileStr)
  1827. // Output:
  1828. // Successfully generated pdf/Fpdf_MoveTo_path.pdf
  1829. }
  1830. // ExampleFpdf_SetLineJoinStyle demonstrates various line cap and line join styles.
  1831. func ExampleFpdf_SetLineJoinStyle() {
  1832. const offset = 75.0
  1833. pdf := gofpdf.New("L", "mm", "A4", "")
  1834. pdf.AddPage()
  1835. var draw = func(cap, join string, x0, y0, x1, y1 float64) {
  1836. // transform begin & end needed to isolate caps and joins
  1837. pdf.SetLineCapStyle(cap)
  1838. pdf.SetLineJoinStyle(join)
  1839. // Draw thick line
  1840. pdf.SetDrawColor(0x33, 0x33, 0x33)
  1841. pdf.SetLineWidth(30.0)
  1842. pdf.MoveTo(x0, y0)
  1843. pdf.LineTo((x0+x1)/2+offset, (y0+y1)/2)
  1844. pdf.LineTo(x1, y1)
  1845. pdf.DrawPath("D")
  1846. // Draw thin helping line
  1847. pdf.SetDrawColor(0xFF, 0x33, 0x33)
  1848. pdf.SetLineWidth(2.56)
  1849. pdf.MoveTo(x0, y0)
  1850. pdf.LineTo((x0+x1)/2+offset, (y0+y1)/2)
  1851. pdf.LineTo(x1, y1)
  1852. pdf.DrawPath("D")
  1853. }
  1854. x := 35.0
  1855. caps := []string{"butt", "square", "round"}
  1856. joins := []string{"bevel", "miter", "round"}
  1857. for i := range caps {
  1858. draw(caps[i], joins[i], x, 50, x, 160)
  1859. x += offset
  1860. }
  1861. fileStr := example.Filename("Fpdf_SetLineJoinStyle_caps")
  1862. err := pdf.OutputFileAndClose(fileStr)
  1863. example.Summary(err, fileStr)
  1864. // Output:
  1865. // Successfully generated pdf/Fpdf_SetLineJoinStyle_caps.pdf
  1866. }
  1867. // ExampleFpdf_DrawPath demonstrates various fill modes.
  1868. func ExampleFpdf_DrawPath() {
  1869. pdf := gofpdf.New("P", "mm", "A4", "")
  1870. pdf.SetDrawColor(0xff, 0x00, 0x00)
  1871. pdf.SetFillColor(0x99, 0x99, 0x99)
  1872. pdf.SetFont("Helvetica", "", 15)
  1873. pdf.AddPage()
  1874. pdf.SetAlpha(1, "Multiply")
  1875. var (
  1876. polygon = func(cx, cy, r, n, dir float64) {
  1877. da := 2 * math.Pi / n
  1878. pdf.MoveTo(cx+r, cy)
  1879. pdf.Text(cx+r, cy, "0")
  1880. i := 1
  1881. for a := da; a < 2*math.Pi; a += da {
  1882. x, y := cx+r*math.Cos(dir*a), cy+r*math.Sin(dir*a)
  1883. pdf.LineTo(x, y)
  1884. pdf.Text(x, y, strconv.Itoa(i))
  1885. i++
  1886. }
  1887. pdf.ClosePath()
  1888. }
  1889. polygons = func(cx, cy, r, n, dir float64) {
  1890. d := 1.0
  1891. for rf := r; rf > 0; rf -= 10 {
  1892. polygon(cx, cy, rf, n, d)
  1893. d *= dir
  1894. }
  1895. }
  1896. star = func(cx, cy, r, n float64) {
  1897. da := 4 * math.Pi / n
  1898. pdf.MoveTo(cx+r, cy)
  1899. for a := da; a < 4*math.Pi+da; a += da {
  1900. x, y := cx+r*math.Cos(a), cy+r*math.Sin(a)
  1901. pdf.LineTo(x, y)
  1902. }
  1903. pdf.ClosePath()
  1904. }
  1905. )
  1906. // triangle
  1907. polygons(55, 45, 40, 3, 1)
  1908. pdf.DrawPath("B")
  1909. pdf.Text(15, 95, "B (same direction, non zero winding)")
  1910. // square
  1911. polygons(155, 45, 40, 4, 1)
  1912. pdf.DrawPath("B*")
  1913. pdf.Text(115, 95, "B* (same direction, even odd)")
  1914. // pentagon
  1915. polygons(55, 145, 40, 5, -1)
  1916. pdf.DrawPath("B")
  1917. pdf.Text(15, 195, "B (different direction, non zero winding)")
  1918. // hexagon
  1919. polygons(155, 145, 40, 6, -1)
  1920. pdf.DrawPath("B*")
  1921. pdf.Text(115, 195, "B* (different direction, even odd)")
  1922. // star
  1923. star(55, 245, 40, 5)
  1924. pdf.DrawPath("B")
  1925. pdf.Text(15, 290, "B (non zero winding)")
  1926. // star
  1927. star(155, 245, 40, 5)
  1928. pdf.DrawPath("B*")
  1929. pdf.Text(115, 290, "B* (even odd)")
  1930. fileStr := example.Filename("Fpdf_DrawPath_fill")
  1931. err := pdf.OutputFileAndClose(fileStr)
  1932. example.Summary(err, fileStr)
  1933. // Output:
  1934. // Successfully generated pdf/Fpdf_DrawPath_fill.pdf
  1935. }
  1936. // ExampleFpdf_CreateTemplate demonstrates creating and using templates
  1937. func ExampleFpdf_CreateTemplate() {
  1938. pdf := gofpdf.New("P", "mm", "A4", "")
  1939. pdf.SetCompression(false)
  1940. // pdf.SetFont("Times", "", 12)
  1941. template := pdf.CreateTemplate(func(tpl *gofpdf.Tpl) {
  1942. tpl.Image(example.ImageFile("logo.png"), 6, 6, 30, 0, false, "", 0, "")
  1943. tpl.SetFont("Arial", "B", 16)
  1944. tpl.Text(40, 20, "Template says hello")
  1945. tpl.SetDrawColor(0, 100, 200)
  1946. tpl.SetLineWidth(2.5)
  1947. tpl.Line(95, 12, 105, 22)
  1948. })
  1949. _, tplSize := template.Size()
  1950. // fmt.Println("Size:", tplSize)
  1951. // fmt.Println("Scaled:", tplSize.ScaleBy(1.5))
  1952. template2 := pdf.CreateTemplate(func(tpl *gofpdf.Tpl) {
  1953. tpl.UseTemplate(template)
  1954. subtemplate := tpl.CreateTemplate(func(tpl2 *gofpdf.Tpl) {
  1955. tpl2.Image(example.ImageFile("logo.png"), 6, 86, 30, 0, false, "", 0, "")
  1956. tpl2.SetFont("Arial", "B", 16)
  1957. tpl2.Text(40, 100, "Subtemplate says hello")
  1958. tpl2.SetDrawColor(0, 200, 100)
  1959. tpl2.SetLineWidth(2.5)
  1960. tpl2.Line(102, 92, 112, 102)
  1961. })
  1962. tpl.UseTemplate(subtemplate)
  1963. })
  1964. pdf.SetDrawColor(200, 100, 0)
  1965. pdf.SetLineWidth(2.5)
  1966. pdf.SetFont("Arial", "B", 16)
  1967. // serialize and deserialize template
  1968. b, _ := template2.Serialize()
  1969. template3, _ := gofpdf.DeserializeTemplate(b)
  1970. pdf.AddPage()
  1971. pdf.UseTemplate(template3)
  1972. pdf.UseTemplateScaled(template3, gofpdf.PointType{X: 0, Y: 30}, tplSize)
  1973. pdf.Line(40, 210, 60, 210)
  1974. pdf.Text(40, 200, "Template example page 1")
  1975. pdf.AddPage()
  1976. pdf.UseTemplate(template2)
  1977. pdf.UseTemplateScaled(template3, gofpdf.PointType{X: 0, Y: 30}, tplSize.ScaleBy(1.4))
  1978. pdf.Line(60, 210, 80, 210)
  1979. pdf.Text(40, 200, "Template example page 2")
  1980. fileStr := example.Filename("Fpdf_CreateTemplate")
  1981. err := pdf.OutputFileAndClose(fileStr)
  1982. example.Summary(err, fileStr)
  1983. // Output:
  1984. // Successfully generated pdf/Fpdf_CreateTemplate.pdf
  1985. }
  1986. // ExampleFpdf_AddFontFromBytes demonstrate how to use embedded fonts from byte array
  1987. func ExampleFpdf_AddFontFromBytes() {
  1988. pdf := gofpdf.New("P", "mm", "A4", "")
  1989. pdf.AddPage()
  1990. pdf.AddFontFromBytes("calligra", "", files.CalligraJson, files.CalligraZ)
  1991. pdf.SetFont("calligra", "", 16)
  1992. pdf.Cell(40, 10, "Hello World With Embedded Font!")
  1993. fileStr := example.Filename("Fpdf_EmbeddedFont")
  1994. err := pdf.OutputFileAndClose(fileStr)
  1995. example.Summary(err, fileStr)
  1996. // Output:
  1997. // Successfully generated pdf/Fpdf_EmbeddedFont.pdf
  1998. }
  1999. // This example demonstrate Clipped table cells
  2000. func ExampleFpdf_ClipRect() {
  2001. marginCell := 2. // margin of top/bottom of cell
  2002. pdf := gofpdf.New("P", "mm", "A4", "")
  2003. pdf.SetFont("Arial", "", 12)
  2004. pdf.AddPage()
  2005. pagew, pageh := pdf.GetPageSize()
  2006. mleft, mright, _, mbottom := pdf.GetMargins()
  2007. cols := []float64{60, 100, pagew - mleft - mright - 100 - 60}
  2008. rows := [][]string{}
  2009. for i := 1; i <= 50; i++ {
  2010. word := fmt.Sprintf("%d:%s", i, strings.Repeat("A", i%100))
  2011. rows = append(rows, []string{word, word, word})
  2012. }
  2013. for _, row := range rows {
  2014. _, lineHt := pdf.GetFontSize()
  2015. height := lineHt + marginCell
  2016. x, y := pdf.GetXY()
  2017. // add a new page if the height of the row doesn't fit on the page
  2018. if y+height >= pageh-mbottom {
  2019. pdf.AddPage()
  2020. x, y = pdf.GetXY()
  2021. }
  2022. for i, txt := range row {
  2023. width := cols[i]
  2024. pdf.Rect(x, y, width, height, "")
  2025. pdf.ClipRect(x, y, width, height, false)
  2026. pdf.Cell(width, height, txt)
  2027. pdf.ClipEnd()
  2028. x += width
  2029. }
  2030. pdf.Ln(-1)
  2031. }
  2032. fileStr := example.Filename("Fpdf_ClippedTableCells")
  2033. err := pdf.OutputFileAndClose(fileStr)
  2034. example.Summary(err, fileStr)
  2035. // Output:
  2036. // Successfully generated pdf/Fpdf_ClippedTableCells.pdf
  2037. }
  2038. // This example demonstrate wrapped table cells
  2039. func ExampleFpdf_Rect() {
  2040. marginCell := 2. // margin of top/bottom of cell
  2041. pdf := gofpdf.New("P", "mm", "A4", "")
  2042. pdf.SetFont("Arial", "", 12)
  2043. pdf.AddPage()
  2044. pagew, pageh := pdf.GetPageSize()
  2045. mleft, mright, _, mbottom := pdf.GetMargins()
  2046. cols := []float64{60, 100, pagew - mleft - mright - 100 - 60}
  2047. rows := [][]string{}
  2048. for i := 1; i <= 30; i++ {
  2049. word := fmt.Sprintf("%d:%s", i, strings.Repeat("A", i%100))
  2050. rows = append(rows, []string{word, word, word})
  2051. }
  2052. for _, row := range rows {
  2053. curx, y := pdf.GetXY()
  2054. x := curx
  2055. height := 0.
  2056. _, lineHt := pdf.GetFontSize()
  2057. for i, txt := range row {
  2058. lines := pdf.SplitLines([]byte(txt), cols[i])
  2059. h := float64(len(lines))*lineHt + marginCell*float64(len(lines))
  2060. if h > height {
  2061. height = h
  2062. }
  2063. }
  2064. // add a new page if the height of the row doesn't fit on the page
  2065. if pdf.GetY()+height > pageh-mbottom {
  2066. pdf.AddPage()
  2067. y = pdf.GetY()
  2068. }
  2069. for i, txt := range row {
  2070. width := cols[i]
  2071. pdf.Rect(x, y, width, height, "")
  2072. pdf.MultiCell(width, lineHt+marginCell, txt, "", "", false)
  2073. x += width
  2074. pdf.SetXY(x, y)
  2075. }
  2076. pdf.SetXY(curx, y+height)
  2077. }
  2078. fileStr := example.Filename("Fpdf_WrappedTableCells")
  2079. err := pdf.OutputFileAndClose(fileStr)
  2080. example.Summary(err, fileStr)
  2081. // Output:
  2082. // Successfully generated pdf/Fpdf_WrappedTableCells.pdf
  2083. }
  2084. // ExampleFpdf_SetJavascript demonstrates including JavaScript in the document.
  2085. func ExampleFpdf_SetJavascript() {
  2086. pdf := gofpdf.New("P", "mm", "A4", "")
  2087. pdf.SetJavascript("print(true);")
  2088. pdf.AddPage()
  2089. pdf.SetFont("Arial", "", 12)
  2090. pdf.Write(10, "Auto-print.")
  2091. fileStr := example.Filename("Fpdf_SetJavascript")
  2092. err := pdf.OutputFileAndClose(fileStr)
  2093. example.Summary(err, fileStr)
  2094. // Output:
  2095. // Successfully generated pdf/Fpdf_SetJavascript.pdf
  2096. }
  2097. // ExampleFpdf_AddSpotColor demonstrates spot color use
  2098. func ExampleFpdf_AddSpotColor() {
  2099. pdf := gofpdf.New("P", "mm", "A4", "")
  2100. pdf.AddSpotColor("PANTONE 145 CVC", 0, 42, 100, 25)
  2101. pdf.AddPage()
  2102. pdf.SetFillSpotColor("PANTONE 145 CVC", 90)
  2103. pdf.Rect(80, 40, 50, 50, "F")
  2104. fileStr := example.Filename("Fpdf_AddSpotColor")
  2105. err := pdf.OutputFileAndClose(fileStr)
  2106. example.Summary(err, fileStr)
  2107. // Output:
  2108. // Successfully generated pdf/Fpdf_AddSpotColor.pdf
  2109. }
  2110. // ExampleFpdf_RegisterAlias demonstrates how to use `RegisterAlias` to create a table of
  2111. // contents.
  2112. func ExampleFpdf_RegisterAlias() {
  2113. pdf := gofpdf.New("P", "mm", "A4", "")
  2114. pdf.SetFont("Arial", "", 12)
  2115. pdf.AliasNbPages("")
  2116. pdf.AddPage()
  2117. // Write the table of contents. We use aliases instead of the page number
  2118. // because we don't know which page the section will begin on.
  2119. numSections := 3
  2120. for i := 1; i <= numSections; i++ {
  2121. pdf.Cell(0, 10, fmt.Sprintf("Section %d begins on page {mark %d}", i, i))
  2122. pdf.Ln(10)
  2123. }
  2124. // Write the sections. Before we start writing, we use `RegisterAlias` to
  2125. // ensure that the alias written in the table of contents will be replaced
  2126. // by the current page number.
  2127. for i := 1; i <= numSections; i++ {
  2128. pdf.AddPage()
  2129. pdf.RegisterAlias(fmt.Sprintf("{mark %d}", i), fmt.Sprintf("%d", pdf.PageNo()))
  2130. pdf.Write(10, fmt.Sprintf("Section %d, page %d of {nb}", i, pdf.PageNo()))
  2131. }
  2132. fileStr := example.Filename("Fpdf_RegisterAlias")
  2133. err := pdf.OutputFileAndClose(fileStr)
  2134. example.Summary(err, fileStr)
  2135. // Output:
  2136. // Successfully generated pdf/Fpdf_RegisterAlias.pdf
  2137. }
  2138. // ExampleFpdf_RegisterAlias_utf8 demonstrates how to use `RegisterAlias` to
  2139. // create a table of contents. This particular example demonstrates the use of
  2140. // UTF-8 aliases.
  2141. func ExampleFpdf_RegisterAlias_utf8() {
  2142. pdf := gofpdf.New("P", "mm", "A4", "")
  2143. pdf.AddUTF8Font("dejavu", "", example.FontFile("DejaVuSansCondensed.ttf"))
  2144. pdf.SetFont("dejavu", "", 12)
  2145. pdf.AliasNbPages("{entute}")
  2146. pdf.AddPage()
  2147. // Write the table of contents. We use aliases instead of the page number
  2148. // because we don't know which page the section will begin on.
  2149. numSections := 3
  2150. for i := 1; i <= numSections; i++ {
  2151. pdf.Cell(0, 10, fmt.Sprintf("Sekcio %d komenciĝas ĉe paĝo {ĉi tiu marko %d}", i, i))
  2152. pdf.Ln(10)
  2153. }
  2154. // Write the sections. Before we start writing, we use `RegisterAlias` to
  2155. // ensure that the alias written in the table of contents will be replaced
  2156. // by the current page number.
  2157. for i := 1; i <= numSections; i++ {
  2158. pdf.AddPage()
  2159. pdf.RegisterAlias(fmt.Sprintf("{ĉi tiu marko %d}", i), fmt.Sprintf("%d", pdf.PageNo()))
  2160. pdf.Write(10, fmt.Sprintf("Sekcio %d, paĝo %d de {entute}", i, pdf.PageNo()))
  2161. }
  2162. fileStr := example.Filename("Fpdf_RegisterAliasUTF8")
  2163. err := pdf.OutputFileAndClose(fileStr)
  2164. example.Summary(err, fileStr)
  2165. // Output:
  2166. // Successfully generated pdf/Fpdf_RegisterAliasUTF8.pdf
  2167. }
  2168. // ExampleNewGrid demonstrates the generation of graph grids.
  2169. func ExampleNewGrid() {
  2170. pdf := gofpdf.New("P", "mm", "A4", "")
  2171. pdf.SetFont("Arial", "", 12)
  2172. pdf.AddPage()
  2173. gr := gofpdf.NewGrid(13, 10, 187, 130)
  2174. gr.TickmarksExtentX(0, 10, 4)
  2175. gr.TickmarksExtentY(0, 10, 3)
  2176. gr.Grid(pdf)
  2177. gr = gofpdf.NewGrid(13, 154, 187, 128)
  2178. gr.XLabelRotate = true
  2179. gr.TickmarksExtentX(0, 1, 12)
  2180. gr.XDiv = 5
  2181. gr.TickmarksContainY(0, 1.1)
  2182. gr.YDiv = 20
  2183. // Replace X label formatter with month abbreviation
  2184. gr.XTickStr = func(val float64, precision int) string {
  2185. return time.Month(math.Mod(val, 12) + 1).String()[0:3]
  2186. }
  2187. gr.Grid(pdf)
  2188. dot := func(x, y float64) {
  2189. pdf.Circle(gr.X(x), gr.Y(y), 0.5, "F")
  2190. }
  2191. pts := []float64{0.39, 0.457, 0.612, 0.84, 0.998, 1.037, 1.015, 0.918, 0.772, 0.659, 0.593, 0.164}
  2192. for month, val := range pts {
  2193. dot(float64(month)+0.5, val)
  2194. }
  2195. pdf.SetDrawColor(255, 64, 64)
  2196. pdf.SetAlpha(0.5, "Normal")
  2197. pdf.SetLineWidth(1.2)
  2198. gr.Plot(pdf, 0.5, 11.5, 50, func(x float64) float64 {
  2199. // http://www.xuru.org/rt/PR.asp
  2200. return 0.227 * math.Exp(-0.0373*x*x+0.471*x)
  2201. })
  2202. pdf.SetAlpha(1.0, "Normal")
  2203. pdf.SetXY(gr.X(0.5), gr.Y(1.35))
  2204. pdf.SetFontSize(14)
  2205. pdf.Write(0, "Solar energy (MWh) per month, 2016")
  2206. pdf.AddPage()
  2207. gr = gofpdf.NewGrid(13, 10, 187, 274)
  2208. gr.TickmarksContainX(2.3, 3.4)
  2209. gr.TickmarksContainY(10.4, 56.8)
  2210. gr.Grid(pdf)
  2211. fileStr := example.Filename("Fpdf_Grid")
  2212. err := pdf.OutputFileAndClose(fileStr)
  2213. example.Summary(err, fileStr)
  2214. // Output:
  2215. // Successfully generated pdf/Fpdf_Grid.pdf
  2216. }
  2217. // ExampleFpdf_SetPageBox demonstrates the use of a page box
  2218. func ExampleFpdf_SetPageBox() {
  2219. // pdfinfo (from http://www.xpdfreader.com) reports the following for this example:
  2220. // ~ pdfinfo -box pdf/Fpdf_PageBox.pdf
  2221. // Producer: FPDF 1.7
  2222. // CreationDate: Sat Jan 1 00:00:00 2000
  2223. // ModDate: Sat Jan 1 00:00:00 2000
  2224. // Tagged: no
  2225. // Form: none
  2226. // Pages: 1
  2227. // Encrypted: no
  2228. // Page size: 493.23 x 739.85 pts (rotated 0 degrees)
  2229. // MediaBox: 0.00 0.00 595.28 841.89
  2230. // CropBox: 51.02 51.02 544.25 790.87
  2231. // BleedBox: 51.02 51.02 544.25 790.87
  2232. // TrimBox: 51.02 51.02 544.25 790.87
  2233. // ArtBox: 51.02 51.02 544.25 790.87
  2234. // File size: 1053 bytes
  2235. // Optimized: no
  2236. // PDF version: 1.3
  2237. const (
  2238. wd = 210
  2239. ht = 297
  2240. fontsize = 6
  2241. boxmargin = 3 * fontsize
  2242. )
  2243. pdf := gofpdf.New("P", "mm", "A4", "") // 210mm x 297mm
  2244. pdf.SetPageBox("crop", boxmargin, boxmargin, wd-2*boxmargin, ht-2*boxmargin)
  2245. pdf.SetFont("Arial", "", pdf.UnitToPointConvert(fontsize))
  2246. pdf.AddPage()
  2247. pdf.MoveTo(fontsize, fontsize)
  2248. pdf.Write(fontsize, "This will be cropped from printed output")
  2249. pdf.MoveTo(boxmargin+fontsize, boxmargin+fontsize)
  2250. pdf.Write(fontsize, "This will be displayed in cropped output")
  2251. fileStr := example.Filename("Fpdf_PageBox")
  2252. err := pdf.OutputFileAndClose(fileStr)
  2253. example.Summary(err, fileStr)
  2254. // Output:
  2255. // Successfully generated pdf/Fpdf_PageBox.pdf
  2256. }
  2257. // ExampleFpdf_SubWrite demonstrates subscripted and superscripted text
  2258. // Adapted from http://www.fpdf.org/en/script/script61.php
  2259. func ExampleFpdf_SubWrite() {
  2260. const (
  2261. fontSize = 12
  2262. halfX = 105
  2263. )
  2264. pdf := gofpdf.New("P", "mm", "A4", "") // 210mm x 297mm
  2265. pdf.AddPage()
  2266. pdf.SetFont("Arial", "", fontSize)
  2267. _, lineHt := pdf.GetFontSize()
  2268. pdf.Write(lineHt, "Hello World!")
  2269. pdf.SetX(halfX)
  2270. pdf.Write(lineHt, "This is standard text.\n")
  2271. pdf.Ln(lineHt * 2)
  2272. pdf.SubWrite(10, "H", 33, 0, 0, "")
  2273. pdf.Write(10, "ello World!")
  2274. pdf.SetX(halfX)
  2275. pdf.Write(10, "This is text with a capital first letter.\n")
  2276. pdf.Ln(lineHt * 2)
  2277. pdf.SubWrite(lineHt, "Y", 6, 0, 0, "")
  2278. pdf.Write(lineHt, "ou can also begin the sentence with a small letter. And word wrap also works if the line is too long, like this one is.")
  2279. pdf.SetX(halfX)
  2280. pdf.Write(lineHt, "This is text with a small first letter.\n")
  2281. pdf.Ln(lineHt * 2)
  2282. pdf.Write(lineHt, "The world has a lot of km")
  2283. pdf.SubWrite(lineHt, "2", 6, 4, 0, "")
  2284. pdf.SetX(halfX)
  2285. pdf.Write(lineHt, "This is text with a superscripted letter.\n")
  2286. pdf.Ln(lineHt * 2)
  2287. pdf.Write(lineHt, "The world has a lot of H")
  2288. pdf.SubWrite(lineHt, "2", 6, -3, 0, "")
  2289. pdf.Write(lineHt, "O")
  2290. pdf.SetX(halfX)
  2291. pdf.Write(lineHt, "This is text with a subscripted letter.\n")
  2292. fileStr := example.Filename("Fpdf_SubWrite")
  2293. err := pdf.OutputFileAndClose(fileStr)
  2294. example.Summary(err, fileStr)
  2295. // Output:
  2296. // Successfully generated pdf/Fpdf_SubWrite.pdf
  2297. }
  2298. // ExampleFpdf_SetPage demomstrates the SetPage() method, allowing content
  2299. // generation to be deferred until all pages have been added.
  2300. func ExampleFpdf_SetPage() {
  2301. rnd := rand.New(rand.NewSource(0)) // Make reproducible documents
  2302. pdf := gofpdf.New("L", "cm", "A4", "")
  2303. pdf.SetFont("Times", "", 12)
  2304. var time []float64
  2305. temperaturesFromSensors := make([][]float64, 5)
  2306. maxs := []float64{25, 41, 89, 62, 11}
  2307. for i := range temperaturesFromSensors {
  2308. temperaturesFromSensors[i] = make([]float64, 0)
  2309. }
  2310. for i := 0.0; i < 100; i += 0.5 {
  2311. time = append(time, i)
  2312. for j, sensor := range temperaturesFromSensors {
  2313. dataValue := rnd.Float64() * maxs[j]
  2314. sensor = append(sensor, dataValue)
  2315. temperaturesFromSensors[j] = sensor
  2316. }
  2317. }
  2318. var graphs []gofpdf.GridType
  2319. var pageNums []int
  2320. xMax := time[len(time)-1]
  2321. for i := range temperaturesFromSensors {
  2322. //Create a new page and graph for each sensor we want to graph.
  2323. pdf.AddPage()
  2324. pdf.Ln(1)
  2325. //Custom label per sensor
  2326. pdf.WriteAligned(0, 0, "Temperature Sensor "+strconv.Itoa(i+1)+" (C) vs Time (min)", "C")
  2327. pdf.Ln(0.5)
  2328. graph := gofpdf.NewGrid(pdf.GetX(), pdf.GetY(), 20, 10)
  2329. graph.TickmarksContainX(0, xMax)
  2330. //Custom Y axis
  2331. graph.TickmarksContainY(0, maxs[i])
  2332. graph.Grid(pdf)
  2333. //Save references and locations.
  2334. graphs = append(graphs, graph)
  2335. pageNums = append(pageNums, pdf.PageNo())
  2336. }
  2337. // For each X, graph the Y in each sensor.
  2338. for i, currTime := range time {
  2339. for j, sensor := range temperaturesFromSensors {
  2340. pdf.SetPage(pageNums[j])
  2341. graph := graphs[j]
  2342. temperature := sensor[i]
  2343. pdf.Circle(graph.X(currTime), graph.Y(temperature), 0.04, "D")
  2344. }
  2345. }
  2346. fileStr := example.Filename("Fpdf_SetPage")
  2347. err := pdf.OutputFileAndClose(fileStr)
  2348. example.Summary(err, fileStr)
  2349. // Output:
  2350. // Successfully generated pdf/Fpdf_SetPage.pdf
  2351. }
  2352. // ExampleFpdf_SetFillColor demonstrates how graphic attributes are properly
  2353. // assigned within multiple transformations. See issue #234.
  2354. func ExampleFpdf_SetFillColor() {
  2355. pdf := gofpdf.New("P", "mm", "A4", "")
  2356. pdf.AddPage()
  2357. pdf.SetFont("Arial", "", 8)
  2358. draw := func(trX, trY float64) {
  2359. pdf.TransformBegin()
  2360. pdf.TransformTranslateX(trX)
  2361. pdf.TransformTranslateY(trY)
  2362. pdf.SetLineJoinStyle("round")
  2363. pdf.SetLineWidth(0.5)
  2364. pdf.SetDrawColor(128, 64, 0)
  2365. pdf.SetFillColor(255, 127, 0)
  2366. pdf.SetAlpha(0.5, "Normal")
  2367. pdf.SetDashPattern([]float64{5, 10}, 0)
  2368. pdf.Rect(0, 0, 40, 40, "FD")
  2369. pdf.SetFontSize(12)
  2370. pdf.SetXY(5, 5)
  2371. pdf.Write(0, "Test")
  2372. pdf.TransformEnd()
  2373. }
  2374. draw(5, 5)
  2375. draw(50, 50)
  2376. fileStr := example.Filename("Fpdf_SetFillColor")
  2377. err := pdf.OutputFileAndClose(fileStr)
  2378. example.Summary(err, fileStr)
  2379. // Output:
  2380. // Successfully generated pdf/Fpdf_SetFillColor.pdf
  2381. }
  2382. // ExampleFpdf_TransformRotate demonstrates how to rotate text within a header
  2383. // to make a watermark that appears on each page.
  2384. func ExampleFpdf_TransformRotate() {
  2385. loremStr := lorem() + "\n\n"
  2386. pdf := gofpdf.New("P", "mm", "A4", "")
  2387. margin := 25.0
  2388. pdf.SetMargins(margin, margin, margin)
  2389. fontHt := 13.0
  2390. lineHt := pdf.PointToUnitConvert(fontHt)
  2391. markFontHt := 50.0
  2392. markLineHt := pdf.PointToUnitConvert(markFontHt)
  2393. markY := (297.0 - markLineHt) / 2.0
  2394. ctrX := 210.0 / 2.0
  2395. ctrY := 297.0 / 2.0
  2396. pdf.SetHeaderFunc(func() {
  2397. pdf.SetFont("Arial", "B", markFontHt)
  2398. pdf.SetTextColor(206, 216, 232)
  2399. pdf.SetXY(margin, markY)
  2400. pdf.TransformBegin()
  2401. pdf.TransformRotate(45, ctrX, ctrY)
  2402. pdf.CellFormat(0, markLineHt, "W A T E R M A R K D E M O", "", 0, "C", false, 0, "")
  2403. pdf.TransformEnd()
  2404. pdf.SetXY(margin, margin)
  2405. })
  2406. pdf.AddPage()
  2407. pdf.SetFont("Arial", "", 8)
  2408. for j := 0; j < 25; j++ {
  2409. pdf.MultiCell(0, lineHt, loremStr, "", "L", false)
  2410. }
  2411. fileStr := example.Filename("Fpdf_RotateText")
  2412. err := pdf.OutputFileAndClose(fileStr)
  2413. example.Summary(err, fileStr)
  2414. // Output:
  2415. // Successfully generated pdf/Fpdf_RotateText.pdf
  2416. }
  2417. // ExampleFpdf_AddUTF8Font demonstrates how use the font
  2418. // with utf-8 mode
  2419. func ExampleFpdf_AddUTF8Font() {
  2420. var fileStr string
  2421. var txtStr []byte
  2422. var err error
  2423. pdf := gofpdf.New("P", "mm", "A4", "")
  2424. pdf.AddPage()
  2425. pdf.AddUTF8Font("dejavu", "", example.FontFile("DejaVuSansCondensed.ttf"))
  2426. pdf.AddUTF8Font("dejavu", "B", example.FontFile("DejaVuSansCondensed-Bold.ttf"))
  2427. pdf.AddUTF8Font("dejavu", "I", example.FontFile("DejaVuSansCondensed-Oblique.ttf"))
  2428. pdf.AddUTF8Font("dejavu", "BI", example.FontFile("DejaVuSansCondensed-BoldOblique.ttf"))
  2429. fileStr = example.Filename("Fpdf_AddUTF8Font")
  2430. txtStr, err = ioutil.ReadFile(example.TextFile("utf-8test.txt"))
  2431. if err == nil {
  2432. pdf.SetFont("dejavu", "B", 17)
  2433. pdf.MultiCell(100, 8, "Text in different languages :", "", "C", false)
  2434. pdf.SetFont("dejavu", "", 14)
  2435. pdf.MultiCell(100, 5, string(txtStr), "", "C", false)
  2436. pdf.Ln(15)
  2437. txtStr, err = ioutil.ReadFile(example.TextFile("utf-8test2.txt"))
  2438. if err == nil {
  2439. pdf.SetFont("dejavu", "BI", 17)
  2440. pdf.MultiCell(100, 8, "Greek text with alignStr = \"J\":", "", "C", false)
  2441. pdf.SetFont("dejavu", "I", 14)
  2442. pdf.MultiCell(100, 5, string(txtStr), "", "J", false)
  2443. err = pdf.OutputFileAndClose(fileStr)
  2444. }
  2445. }
  2446. example.Summary(err, fileStr)
  2447. // Output:
  2448. // Successfully generated pdf/Fpdf_AddUTF8Font.pdf
  2449. }
  2450. // ExampleUTF8CutFont demonstrates how generate a TrueType font subset.
  2451. func ExampleUTF8CutFont() {
  2452. var pdfFileStr, fullFontFileStr, subFontFileStr string
  2453. var subFont, fullFont []byte
  2454. var err error
  2455. pdfFileStr = example.Filename("Fpdf_UTF8CutFont")
  2456. fullFontFileStr = example.FontFile("calligra.ttf")
  2457. fullFont, err = ioutil.ReadFile(fullFontFileStr)
  2458. if err == nil {
  2459. subFontFileStr = "calligra_abcde.ttf"
  2460. subFont = gofpdf.UTF8CutFont(fullFont, "abcde")
  2461. err = ioutil.WriteFile(subFontFileStr, subFont, 0600)
  2462. if err == nil {
  2463. y := 24.0
  2464. pdf := gofpdf.New("P", "mm", "A4", "")
  2465. fontHt := 17.0
  2466. lineHt := pdf.PointConvert(fontHt)
  2467. write := func(format string, args ...interface{}) {
  2468. pdf.SetXY(24.0, y)
  2469. pdf.Cell(200.0, lineHt, fmt.Sprintf(format, args...))
  2470. y += lineHt
  2471. }
  2472. writeSize := func(fileStr string) {
  2473. var info os.FileInfo
  2474. var err error
  2475. info, err = os.Stat(fileStr)
  2476. if err == nil {
  2477. write("%6d: size of %s", info.Size(), fileStr)
  2478. }
  2479. }
  2480. pdf.AddPage()
  2481. pdf.AddUTF8Font("calligra", "", subFontFileStr)
  2482. pdf.SetFont("calligra", "", fontHt)
  2483. write("cabbed")
  2484. write("vwxyz")
  2485. pdf.SetFont("courier", "", fontHt)
  2486. writeSize(fullFontFileStr)
  2487. writeSize(subFontFileStr)
  2488. err = pdf.OutputFileAndClose(pdfFileStr)
  2489. os.Remove(subFontFileStr)
  2490. }
  2491. }
  2492. example.Summary(err, pdfFileStr)
  2493. // Output:
  2494. // Successfully generated pdf/Fpdf_UTF8CutFont.pdf
  2495. }
  2496. func ExampleFpdf_RoundedRect() {
  2497. const (
  2498. wd = 40.0
  2499. hgap = 10.0
  2500. radius = 10.0
  2501. ht = 60.0
  2502. vgap = 10.0
  2503. )
  2504. corner := func(b1, b2, b3, b4 bool) (cstr string) {
  2505. if b1 {
  2506. cstr = "1"
  2507. }
  2508. if b2 {
  2509. cstr += "2"
  2510. }
  2511. if b3 {
  2512. cstr += "3"
  2513. }
  2514. if b4 {
  2515. cstr += "4"
  2516. }
  2517. return
  2518. }
  2519. pdf := gofpdf.New("P", "mm", "A4", "") // 210 x 297
  2520. pdf.AddPage()
  2521. pdf.SetLineWidth(0.5)
  2522. y := vgap
  2523. r := 40
  2524. g := 30
  2525. b := 20
  2526. for row := 0; row < 4; row++ {
  2527. x := hgap
  2528. for col := 0; col < 4; col++ {
  2529. pdf.SetFillColor(r, g, b)
  2530. pdf.RoundedRect(x, y, wd, ht, radius, corner(row&1 == 1, row&2 == 2, col&1 == 1, col&2 == 2), "FD")
  2531. r += 8
  2532. g += 10
  2533. b += 12
  2534. x += wd + hgap
  2535. }
  2536. y += ht + vgap
  2537. }
  2538. pdf.AddPage()
  2539. pdf.RoundedRectExt(10, 20, 40, 80, 4., 0., 20, 0., "FD")
  2540. fileStr := example.Filename("Fpdf_RoundedRect")
  2541. err := pdf.OutputFileAndClose(fileStr)
  2542. example.Summary(err, fileStr)
  2543. // Output:
  2544. // Successfully generated pdf/Fpdf_RoundedRect.pdf
  2545. }
  2546. // ExampleFpdf_SetUnderlineThickness demonstrates how to adjust the text
  2547. // underline thickness.
  2548. func ExampleFpdf_SetUnderlineThickness() {
  2549. pdf := gofpdf.New("P", "mm", "A4", "") // 210mm x 297mm
  2550. pdf.AddPage()
  2551. pdf.SetFont("Arial", "U", 12)
  2552. pdf.SetUnderlineThickness(0.5)
  2553. pdf.CellFormat(0, 10, "Thin underline", "", 1, "", false, 0, "")
  2554. pdf.SetUnderlineThickness(1)
  2555. pdf.CellFormat(0, 10, "Normal underline", "", 1, "", false, 0, "")
  2556. pdf.SetUnderlineThickness(2)
  2557. pdf.CellFormat(0, 10, "Thicker underline", "", 1, "", false, 0, "")
  2558. fileStr := example.Filename("Fpdf_UnderlineThickness")
  2559. err := pdf.OutputFileAndClose(fileStr)
  2560. example.Summary(err, fileStr)
  2561. // Output:
  2562. // Successfully generated pdf/Fpdf_UnderlineThickness.pdf
  2563. }
  2564. // ExampleFpdf_Cell_strikeout demonstrates striked-out text
  2565. func ExampleFpdf_Cell_strikeout() {
  2566. pdf := gofpdf.New("P", "mm", "A4", "") // 210mm x 297mm
  2567. pdf.AddPage()
  2568. for fontSize := 4; fontSize < 40; fontSize += 10 {
  2569. pdf.SetFont("Arial", "S", float64(fontSize))
  2570. pdf.SetXY(0, float64(fontSize))
  2571. pdf.Cell(40, 10, "Hello World")
  2572. }
  2573. fileStr := example.Filename("Fpdf_Cell_strikeout")
  2574. err := pdf.OutputFileAndClose(fileStr)
  2575. example.Summary(err, fileStr)
  2576. // Output:
  2577. // Successfully generated pdf/Fpdf_Cell_strikeout.pdf
  2578. }
  2579. // ExampleFpdf_SetTextRenderingMode demonstrates rendering modes in PDFs.
  2580. func ExampleFpdf_SetTextRenderingMode() {
  2581. pdf := gofpdf.New("P", "mm", "A4", "") // 210mm x 297mm
  2582. pdf.AddPage()
  2583. fontSz := float64(16)
  2584. lineSz := pdf.PointToUnitConvert(fontSz)
  2585. pdf.SetFont("Times", "", fontSz)
  2586. pdf.Write(lineSz, "This document demonstrates various modes of text rendering. Search for \"Mode 3\" "+
  2587. "to locate text that has been rendered invisibly. This selection can be copied "+
  2588. "into the clipboard as usual and is useful for overlaying onto non-textual elements such "+
  2589. "as images to make them searchable.\n\n")
  2590. fontSz = float64(125)
  2591. lineSz = pdf.PointToUnitConvert(fontSz)
  2592. pdf.SetFontSize(fontSz)
  2593. pdf.SetTextColor(170, 170, 190)
  2594. pdf.SetDrawColor(50, 60, 90)
  2595. write := func(mode int) {
  2596. pdf.SetTextRenderingMode(mode)
  2597. pdf.CellFormat(210, lineSz, fmt.Sprintf("Mode %d", mode), "", 1, "", false, 0, "")
  2598. }
  2599. for mode := 0; mode < 4; mode++ {
  2600. write(mode)
  2601. }
  2602. write(0)
  2603. fileStr := example.Filename("Fpdf_TextRenderingMode")
  2604. err := pdf.OutputFileAndClose(fileStr)
  2605. example.Summary(err, fileStr)
  2606. // Output:
  2607. // Successfully generated pdf/Fpdf_TextRenderingMode.pdf
  2608. }
  2609. // TestIssue0316 addresses issue 316 in which AddUTF8FromBytes modifies its argument
  2610. // utf8bytes resulting in a panic if you generate two PDFs with the "same" font bytes.
  2611. func TestIssue0316(t *testing.T) {
  2612. pdf := gofpdf.New(gofpdf.OrientationPortrait, "mm", "A4", "")
  2613. pdf.AddPage()
  2614. fontBytes, _ := ioutil.ReadFile(example.FontFile("DejaVuSansCondensed.ttf"))
  2615. ofontBytes := append([]byte{}, fontBytes...)
  2616. pdf.AddUTF8FontFromBytes("dejavu", "", fontBytes)
  2617. pdf.SetFont("dejavu", "", 16)
  2618. pdf.Cell(40, 10, "Hello World!")
  2619. fileStr := example.Filename("TestIssue0316")
  2620. err := pdf.OutputFileAndClose(fileStr)
  2621. example.Summary(err, fileStr)
  2622. pdf.AddPage()
  2623. if !bytes.Equal(fontBytes, ofontBytes) {
  2624. t.Fatal("Font data changed during pdf generation")
  2625. }
  2626. }
  2627. func TestMultiCellUnsupportedChar(t *testing.T) {
  2628. pdf := gofpdf.New("P", "mm", "A4", "")
  2629. pdf.AddPage()
  2630. fontBytes, _ := ioutil.ReadFile(example.FontFile("DejaVuSansCondensed.ttf"))
  2631. pdf.AddUTF8FontFromBytes("dejavu", "", fontBytes)
  2632. pdf.SetFont("dejavu", "", 16)
  2633. defer func() {
  2634. if r := recover(); r != nil {
  2635. t.Errorf("unexpected panic: %v", r)
  2636. }
  2637. }()
  2638. pdf.MultiCell(0, 5, "😀", "", "", false)
  2639. fileStr := example.Filename("TestMultiCellUnsupportedChar")
  2640. pdf.OutputFileAndClose(fileStr)
  2641. }
  2642. // ExampleFpdf_SetTextRenderingMode demonstrates embedding files in PDFs,
  2643. // at the top-level.
  2644. func ExampleFpdf_SetAttachments() {
  2645. pdf := gofpdf.New("P", "mm", "A4", "")
  2646. // Global attachments
  2647. file, err := ioutil.ReadFile("grid.go")
  2648. if err != nil {
  2649. pdf.SetError(err)
  2650. }
  2651. a1 := gofpdf.Attachment{Content: file, Filename: "grid.go"}
  2652. file, err = ioutil.ReadFile("LICENSE")
  2653. if err != nil {
  2654. pdf.SetError(err)
  2655. }
  2656. a2 := gofpdf.Attachment{Content: file, Filename: "License"}
  2657. pdf.SetAttachments([]gofpdf.Attachment{a1, a2})
  2658. fileStr := example.Filename("Fpdf_EmbeddedFiles")
  2659. err = pdf.OutputFileAndClose(fileStr)
  2660. example.Summary(err, fileStr)
  2661. // Output:
  2662. // Successfully generated pdf/Fpdf_EmbeddedFiles.pdf
  2663. }
  2664. func ExampleFpdf_AddAttachmentAnnotation() {
  2665. pdf := gofpdf.New("P", "mm", "A4", "")
  2666. pdf.SetFont("Arial", "", 12)
  2667. pdf.AddPage()
  2668. // Per page attachment
  2669. file, err := ioutil.ReadFile("grid.go")
  2670. if err != nil {
  2671. pdf.SetError(err)
  2672. }
  2673. a := gofpdf.Attachment{Content: file, Filename: "grid.go", Description: "Some amazing code !"}
  2674. pdf.SetXY(5, 10)
  2675. pdf.Rect(2, 10, 50, 15, "D")
  2676. pdf.AddAttachmentAnnotation(&a, 2, 10, 50, 15)
  2677. pdf.Cell(50, 15, "A first link")
  2678. pdf.SetXY(5, 80)
  2679. pdf.Rect(2, 80, 50, 15, "D")
  2680. pdf.AddAttachmentAnnotation(&a, 2, 80, 50, 15)
  2681. pdf.Cell(50, 15, "A second link (no copy)")
  2682. fileStr := example.Filename("Fpdf_FileAnnotations")
  2683. err = pdf.OutputFileAndClose(fileStr)
  2684. example.Summary(err, fileStr)
  2685. // Output:
  2686. // Successfully generated pdf/Fpdf_FileAnnotations.pdf
  2687. }
  2688. func ExampleFpdf_SetModificationDate() {
  2689. // pdfinfo (from http://www.xpdfreader.com) reports the following for this example :
  2690. // ~ pdfinfo -box pdf/Fpdf_PageBox.pdf
  2691. // Producer: FPDF 1.7
  2692. // CreationDate: Sat Jan 1 00:00:00 2000
  2693. // ModDate: Sun Jan 2 10:22:30 2000
  2694. pdf := gofpdf.New("", "", "", "")
  2695. pdf.AddPage()
  2696. pdf.SetModificationDate(time.Date(2000, 1, 2, 10, 22, 30, 0, time.UTC))
  2697. fileStr := example.Filename("Fpdf_SetModificationDate")
  2698. err := pdf.OutputFileAndClose(fileStr)
  2699. example.Summary(err, fileStr)
  2700. // Output:
  2701. // Successfully generated pdf/Fpdf_SetModificationDate.pdf
  2702. }