summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore8
-rw-r--r--Makefile29
-rw-r--r--contrib/gofpdi/gofpdi.go143
-rw-r--r--contrib/gofpdi/gofpdi_test.go76
-rw-r--r--doc/document.md264
-rw-r--r--doc/go.awk13
-rw-r--r--doc/html.txt68
-rw-r--r--go.sum18
-rw-r--r--pdf/reference/Fpdf_SplitLines_tables.pdf159
-rw-r--r--pdf/reference/Fpdf_UnderlineThickness.pdfbin0 -> 1156 bytes
-rw-r--r--splittext.go53
11 files changed, 831 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
index b28eb22..1fae316 100644
--- a/.gitignore
+++ b/.gitignore
@@ -15,3 +15,11 @@ private
*.swp
**/*.test
.idea/
+doc/body.html
+doc/body.md
+doc/index.html
+doc/index.html.ok
+coverage.html
+
+# macOS
+.DS_Store \ No newline at end of file
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..90624c5
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,29 @@
+all : documentation
+
+documentation : doc/index.html doc.go README.md
+
+cov : all
+ go test -v -coverprofile=coverage && go tool cover -html=coverage -o=coverage.html
+
+check :
+ golint .
+ go vet -all .
+ gofmt -s -l .
+ goreportcard-cli -v | grep -v cyclomatic
+
+README.md : doc/document.md
+ pandoc --read=markdown --write=gfm < $< > $@
+
+doc/index.html : doc/document.md doc/html.txt
+ pandoc --read=markdown --write=html --template=doc/html.txt \
+ --metadata pagetitle="GoFPDF Document Generator" < $< > $@
+
+doc.go : doc/document.md doc/go.awk
+ pandoc --read=markdown --write=plain $< | awk --assign=package_name=gofpdf --file=doc/go.awk > $@
+ gofmt -s -w $@
+
+build :
+ go build -v
+
+clean :
+ rm -f coverage.html coverage doc/index.html doc.go README.md
diff --git a/contrib/gofpdi/gofpdi.go b/contrib/gofpdi/gofpdi.go
new file mode 100644
index 0000000..7b9c822
--- /dev/null
+++ b/contrib/gofpdi/gofpdi.go
@@ -0,0 +1,143 @@
+/*
+Package gofpdi wraps the gofpdi PDF library to import existing PDFs as templates. See github.com/phpdave11/gofpdi
+for further information and examples.
+
+Users should call NewImporter() to obtain their own Importer instance to work with.
+To retain backwards compatibility, the package offers a default Importer that may be used via global functions. Note
+however that use of the default Importer is not thread safe.
+*/
+package gofpdi
+
+import (
+ realgofpdi "github.com/phpdave11/gofpdi"
+ "io"
+)
+
+// gofpdiPdf is a partial interface that only implements the functions we need
+// from the PDF generator to put the imported PDF templates on the PDF.
+type gofpdiPdf interface {
+ ImportObjects(objs map[string][]byte)
+ ImportObjPos(objs map[string]map[int]string)
+ ImportTemplates(tpls map[string]string)
+ UseImportedTemplate(tplName string, x float64, y float64, w float64, h float64)
+ SetError(err error)
+}
+
+// Importer wraps an Importer from the gofpdi library.
+type Importer struct {
+ fpdi *realgofpdi.Importer
+}
+
+// NewImporter creates a new Importer wrapping functionality from the gofpdi library.
+func NewImporter() *Importer {
+ return &Importer{
+ fpdi: realgofpdi.NewImporter(),
+ }
+}
+
+// ImportPage imports a page of a PDF file with the specified box (/MediaBox,
+// /TrimBox, /ArtBox, /CropBox, or /BleedBox). Returns a template id that can
+// be used with UseImportedTemplate to draw the template onto the page.
+func (i *Importer) ImportPage(f gofpdiPdf, sourceFile string, pageno int, box string) int {
+ // Set source file for fpdi
+ i.fpdi.SetSourceFile(sourceFile)
+ // return template id
+ return i.getTemplateID(f, pageno, box)
+}
+
+// ImportPageFromStream imports a page of a PDF with the specified box
+// (/MediaBox, TrimBox, /ArtBox, /CropBox, or /BleedBox). Returns a template id
+// that can be used with UseImportedTemplate to draw the template onto the
+// page.
+func (i *Importer) ImportPageFromStream(f gofpdiPdf, rs *io.ReadSeeker, pageno int, box string) int {
+ // Set source stream for fpdi
+ i.fpdi.SetSourceStream(rs)
+ // return template id
+ return i.getTemplateID(f, pageno, box)
+}
+
+func (i *Importer) getTemplateID(f gofpdiPdf, pageno int, box string) int {
+ // Import page
+ tpl := i.fpdi.ImportPage(pageno, box)
+
+ // Import objects into current pdf document
+ // Unordered means that the objects will be returned with a sha1 hash instead of an integer
+ // The objects themselves may have references to other hashes which will be replaced in ImportObjects()
+ tplObjIDs := i.fpdi.PutFormXobjectsUnordered()
+
+ // Set template names and ids (hashes) in gofpdf
+ f.ImportTemplates(tplObjIDs)
+
+ // Get a map[string]string of the imported objects.
+ // The map keys will be the ID of each object.
+ imported := i.fpdi.GetImportedObjectsUnordered()
+
+ // Import gofpdi objects into gofpdf
+ f.ImportObjects(imported)
+
+ // Get a map[string]map[int]string of the object hashes and their positions within each object,
+ // to be replaced with object ids (integers).
+ importedObjPos := i.fpdi.GetImportedObjHashPos()
+
+ // Import gofpdi object hashes and their positions into gopdf
+ f.ImportObjPos(importedObjPos)
+
+ return tpl
+}
+
+// UseImportedTemplate draws the template onto the page at x,y. If w is 0, the
+// template will be scaled to fit based on h. If h is 0, the template will be
+// scaled to fit based on w.
+func (i *Importer) UseImportedTemplate(f gofpdiPdf, tplid int, x float64, y float64, w float64, h float64) {
+ // Get values from fpdi
+ tplName, scaleX, scaleY, tX, tY := i.fpdi.UseTemplate(tplid, x, y, w, h)
+
+ f.UseImportedTemplate(tplName, scaleX, scaleY, tX, tY)
+}
+
+// GetPageSizes returns page dimensions for all pages of the imported pdf.
+// Result consists of map[<page number>]map[<box>]map[<dimension>]<value>.
+// <page number>: page number, note that page numbers start at 1
+// <box>: box identifier, e.g. "/MediaBox"
+// <dimension>: dimension string, either "w" or "h"
+func (i *Importer) GetPageSizes() map[int]map[string]map[string]float64 {
+ return i.fpdi.GetPageSizes()
+}
+
+// Default Importer used by global functions
+var fpdi = NewImporter()
+
+// ImportPage imports a page of a PDF file with the specified box (/MediaBox,
+// /TrimBox, /ArtBox, /CropBox, or /BleedBox). Returns a template id that can
+// be used with UseImportedTemplate to draw the template onto the page.
+// Note: This uses the default Importer. Call NewImporter() to obtain a custom Importer.
+func ImportPage(f gofpdiPdf, sourceFile string, pageno int, box string) int {
+ return fpdi.ImportPage(f, sourceFile, pageno, box)
+}
+
+// ImportPageFromStream imports a page of a PDF with the specified box
+// (/MediaBox, TrimBox, /ArtBox, /CropBox, or /BleedBox). Returns a template id
+// that can be used with UseImportedTemplate to draw the template onto the
+// page.
+// Note: This uses the default Importer. Call NewImporter() to obtain a custom Importer.
+func ImportPageFromStream(f gofpdiPdf, rs *io.ReadSeeker, pageno int, box string) int {
+ return fpdi.ImportPageFromStream(f, rs, pageno, box)
+}
+
+// UseImportedTemplate draws the template onto the page at x,y. If w is 0, the
+// template will be scaled to fit based on h. If h is 0, the template will be
+// scaled to fit based on w.
+// Note: This uses the default Importer. Call NewImporter() to obtain a custom Importer.
+func UseImportedTemplate(f gofpdiPdf, tplid int, x float64, y float64, w float64, h float64) {
+ fpdi.UseImportedTemplate(f, tplid, x, y, w, h)
+}
+
+// GetPageSizes returns page dimensions for all pages of the imported pdf.
+// Result consists of map[<page number>]map[<box>]map[<dimension>]<value>.
+// <page number>: page number, note that page numbers start at 1
+// <box>: box identifier, e.g. "/MediaBox"
+// <dimension>: dimension string, either "w" or "h"
+// Note: This uses the default Importer. Call NewImporter() to obtain a custom Importer.
+func GetPageSizes() map[int]map[string]map[string]float64 {
+ return fpdi.GetPageSizes()
+}
diff --git a/contrib/gofpdi/gofpdi_test.go b/contrib/gofpdi/gofpdi_test.go
new file mode 100644
index 0000000..70ef6cc
--- /dev/null
+++ b/contrib/gofpdi/gofpdi_test.go
@@ -0,0 +1,76 @@
+package gofpdi
+
+import (
+ "bytes"
+ "github.com/jung-kurt/gofpdf"
+ "github.com/jung-kurt/gofpdf/internal/example"
+ "io"
+ "sync"
+ "testing"
+)
+
+func ExampleNewImporter() {
+ // create new pdf
+ pdf := gofpdf.New("P", "pt", "A4", "")
+
+ // for testing purposes, get an arbitrary template pdf as stream
+ rs, _ := getTemplatePdf()
+
+ // create a new Importer instance
+ imp := NewImporter()
+
+ // import first page and determine page sizes
+ tpl := imp.ImportPageFromStream(pdf, &rs, 1, "/MediaBox")
+ pageSizes := imp.GetPageSizes()
+ nrPages := len(imp.GetPageSizes())
+
+ // add all pages from template pdf
+ for i := 1; i <= nrPages; i++ {
+ pdf.AddPage()
+ if i > 1 {
+ tpl = imp.ImportPageFromStream(pdf, &rs, i, "/MediaBox")
+ }
+ imp.UseImportedTemplate(pdf, tpl, 0, 0, pageSizes[i]["/MediaBox"]["w"], pageSizes[i]["/MediaBox"]["h"])
+ }
+
+ // output
+ fileStr := example.Filename("contrib_gofpdi_Importer")
+ err := pdf.OutputFileAndClose(fileStr)
+ example.Summary(err, fileStr)
+ // Output:
+ // Successfully generated ../../pdf/contrib_gofpdi_Importer.pdf
+}
+
+func TestGofpdiConcurrent(t *testing.T) {
+ wg := sync.WaitGroup{}
+ for i := 0; i < 100; i++ {
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ pdf := gofpdf.New("P", "mm", "A4", "")
+ pdf.AddPage()
+ rs, _ := getTemplatePdf()
+ imp := NewImporter()
+ tpl := imp.ImportPageFromStream(pdf, &rs, 1, "/MediaBox")
+ imp.UseImportedTemplate(pdf, tpl, 0, 0, 210.0, 297.0)
+ // write to bytes buffer
+ buf := bytes.Buffer{}
+ if err := pdf.Output(&buf); err != nil {
+ t.Fail()
+ }
+ }()
+ }
+ wg.Wait()
+}
+
+func getTemplatePdf() (io.ReadSeeker, error) {
+ tpdf := gofpdf.New("P", "pt", "A4", "")
+ tpdf.AddPage()
+ tpdf.SetFont("Arial", "", 12)
+ tpdf.Text(20, 20, "Example Page 1")
+ tpdf.AddPage()
+ tpdf.Text(20, 20, "Example Page 2")
+ tbuf := bytes.Buffer{}
+ err := tpdf.Output(&tbuf)
+ return bytes.NewReader(tbuf.Bytes()), err
+}
diff --git a/doc/document.md b/doc/document.md
new file mode 100644
index 0000000..b2289ce
--- /dev/null
+++ b/doc/document.md
@@ -0,0 +1,264 @@
+# GoFPDF document generator
+
+[![MIT licensed][badge-mit]][license]
+[![Report][badge-report]][report]
+[![GoDoc][badge-doc]][godoc]
+
+![][logo]
+
+Package gofpdf implements a PDF document generator with high level support for
+text, drawing and images.
+
+## Features
+
+* UTF-8 support
+* Choice of measurement unit, page format and margins
+* Page header and footer management
+* Automatic page breaks, line breaks, and text justification
+* Inclusion of JPEG, PNG, GIF, TIFF and basic path-only SVG images
+* Colors, gradients and alpha channel transparency
+* Outline bookmarks
+* Internal and external links
+* TrueType, Type1 and encoding support
+* Page compression
+* Lines, Bézier curves, arcs, and ellipses
+* Rotation, scaling, skewing, translation, and mirroring
+* Clipping
+* Document protection
+* Layers
+* Templates
+* Barcodes
+* Charting facility
+* Import PDFs as templates
+
+gofpdf has no dependencies other than the Go standard library. All tests pass
+on Linux, Mac and Windows platforms.
+
+gofpdf supports UTF-8 TrueType fonts and "right-to-left" languages. Note that
+Chinese, Japanese, and Korean characters may not be included in many general
+purpose fonts. For these languages, a specialized font (for example,
+[NotoSansSC][noto] for simplified Chinese) can be used.
+
+Also, support is provided to automatically translate UTF-8 runes to code page
+encodings for languages that have fewer than 256 glyphs.
+
+## Installation
+
+To install the package on your system, run
+
+```shell
+go get github.com/jung-kurt/gofpdf
+```
+
+Later, to receive updates, run
+
+```shell
+go get -u -v github.com/jung-kurt/gofpdf/...
+```
+
+## Quick Start
+
+The following Go code generates a simple PDF file.
+
+```go
+pdf := gofpdf.New("P", "mm", "A4", "")
+pdf.AddPage()
+pdf.SetFont("Arial", "B", 16)
+pdf.Cell(40, 10, "Hello, world")
+err := pdf.OutputFileAndClose("hello.pdf")
+```
+
+See the functions in the [fpdf_test.go][fpdf-test] file (shown as examples in
+this documentation) for more advanced PDF examples.
+
+## Errors
+
+If an error occurs in an Fpdf method, an internal error field is set. After
+this occurs, Fpdf method calls typically return without performing any
+operations and the error state is retained. This error management scheme
+facilitates PDF generation since individual method calls do not need to be
+examined for failure; it is generally sufficient to wait until after `Output()`
+is called. For the same reason, if an error occurs in the calling application
+during PDF generation, it may be desirable for the application to transfer the
+error to the Fpdf instance by calling the `SetError()` method or the
+`SetErrorf()` method. At any time during the life cycle of the Fpdf instance,
+the error state can be determined with a call to `Ok()` or `Err()`. The error
+itself can be retrieved with a call to `Error()`.
+
+## Conversion Notes
+
+This package is a relatively straightforward translation from the original
+[FPDF][fpdf-site] library written in PHP (despite the caveat in the
+introduction to [Effective Go][effective-go]). The
+API names have been retained even though the Go idiom would suggest otherwise
+(for example, `pdf.GetX()` is used rather than simply `pdf.X()`). The
+similarity of the two libraries makes the original FPDF website a good source
+of information. It includes a forum and FAQ.
+
+However, some internal changes have been made. Page content is built up using
+buffers (of type bytes.Buffer) rather than repeated string concatenation.
+Errors are handled as explained above rather than panicking. Output is
+generated through an interface of type io.Writer or io.WriteCloser. A number of
+the original PHP methods behave differently based on the type of the arguments
+that are passed to them; in these cases additional methods have been exported
+to provide similar functionality. Font definition files are produced in JSON
+rather than PHP.
+
+## Example PDFs
+
+A side effect of running `go test ./...` is the production of a number of
+example PDFs. These can be found in the gofpdf/pdf directory after the tests
+complete.
+
+Please note that these examples run in the context of a test. In order run an
+example as a standalone application, you'll need to examine
+[fpdf_test.go][fpdf-test] for some helper routines, for example
+`exampleFilename()` and `summary()`.
+
+Example PDFs can be compared with reference copies in order to verify that they
+have been generated as expected. This comparison will be performed if a PDF
+with the same name as the example PDF is placed in the gofpdf/pdf/reference
+directory and if the third argument to `ComparePDFFiles()` in
+internal/example/example.go is true. (By default it is false.) The routine that
+summarizes an example will look for this file and, if found, will call
+`ComparePDFFiles()` to check the example PDF for equality with its reference PDF.
+If differences exist between the two files they will be printed to standard
+output and the test will fail. If the reference file is missing, the comparison
+is considered to succeed. In order to successfully compare two PDFs, the
+placement of internal resources must be consistent and the internal creation
+timestamps must be the same. To do this, the methods `SetCatalogSort()` and
+`SetCreationDate()` need to be called for both files. This is done automatically
+for all examples.
+
+## Nonstandard Fonts
+
+Nothing special is required to use the standard PDF fonts (courier, helvetica,
+times, zapfdingbats) in your documents other than calling `SetFont()`.
+
+You should use `AddUTF8Font()` or `AddUTF8FontFromBytes()` to add a TrueType
+UTF-8 encoded font. Use `RTL()` and `LTR()` methods switch between
+"right-to-left" and "left-to-right" mode.
+
+In order to use a different non-UTF-8 TrueType or Type1 font, you will need to
+generate a font definition file and, if the font will be embedded into PDFs, a
+compressed version of the font file. This is done by calling the MakeFont
+function or using the included makefont command line utility. To create the
+utility, cd into the makefont subdirectory and run "go build". This will
+produce a standalone executable named makefont. Select the appropriate encoding
+file from the font subdirectory and run the command as in the following
+example.
+
+```shell
+./makefont --embed --enc=../font/cp1252.map --dst=../font ../font/calligra.ttf
+```
+
+In your PDF generation code, call `AddFont()` to load the font and, as with the
+standard fonts, SetFont() to begin using it. Most examples, including the
+package example, demonstrate this method. Good sources of free, open-source
+fonts include [Google Fonts][gfont] and [DejaVu Fonts][dfont].
+
+## Related Packages
+
+The [draw2d][draw2d-site] package is a two dimensional vector graphics library that
+can generate output in different forms. It uses gofpdf for its document
+production mode.
+
+## Contributing Changes
+
+gofpdf is a global community effort and you are invited to make it even better.
+If you have implemented a new feature or corrected a problem, please consider
+contributing your change to the project. A contribution that does not directly
+pertain to the core functionality of gofpdf should be placed in its own
+directory directly beneath the `contrib` directory.
+
+Here are guidelines for making submissions. Your change should
+
+* be compatible with the MIT License
+* be properly documented
+* be formatted with `go fmt`
+* include an example in [fpdf_test.go][test] if appropriate
+* conform to the standards of [golint][lint] and
+[go vet][vet], that is, `golint .` and
+`go vet .` should not generate any warnings
+* not diminish [test coverage][coverage]
+
+[Pull requests][pr] are the preferred means of accepting your changes.
+
+## License
+
+gofpdf is released under the MIT License. It is copyrighted by Kurt Jung and
+the contributors acknowledged below.
+
+## Acknowledgments
+
+This package's code and documentation are closely derived from the [FPDF][fpdf-site]
+library created by Olivier Plathey, and a number of font and image resources
+are copied directly from it. Bruno Michel has provided valuable assistance with
+the code. Drawing support is adapted from the FPDF geometric figures script by
+David Hernández Sanz. Transparency support is adapted from the FPDF
+transparency script by Martin Hall-May. Support for gradients and clipping is
+adapted from FPDF scripts by Andreas Würmser. Support for outline bookmarks is
+adapted from Olivier Plathey by Manuel Cornes. Layer support is adapted from
+Olivier Plathey. Support for transformations is adapted from the FPDF
+transformation script by Moritz Wagner and Andreas Würmser. PDF protection is
+adapted from the work of Klemen Vodopivec for the FPDF product. Lawrence
+Kesteloot provided code to allow an image's extent to be determined prior to
+placement. Support for vertical alignment within a cell was provided by Stefan
+Schroeder. Ivan Daniluk generalized the font and image loading code to use the
+Reader interface while maintaining backward compatibility. Anthony Starks
+provided code for the Polygon function. Robert Lillack provided the Beziergon
+function and corrected some naming issues with the internal curve function.
+Claudio Felber provided implementations for dashed line drawing and generalized
+font loading. Stani Michiels provided support for multi-segment path drawing
+with smooth line joins, line join styles, enhanced fill modes, and has helped
+greatly with package presentation and tests. Templating is adapted by Marcus
+Downing from the FPDF_Tpl library created by Jan Slabon and Setasign. Jelmer
+Snoeck contributed packages that generate a variety of barcodes and help with
+registering images on the web. Jelmer Snoek and Guillermo Pascual augmented the
+basic HTML functionality with aligned text. Kent Quirk implemented
+backwards-compatible support for reading DPI from images that support it, and
+for setting DPI manually and then having it properly taken into account when
+calculating image size. Paulo Coutinho provided support for static embedded
+fonts. Dan Meyers added support for embedded JavaScript. David Fish added a
+generic alias-replacement function to enable, among other things, table of
+contents functionality. Andy Bakun identified and corrected a problem in which
+the internal catalogs were not sorted stably. Paul Montag added encoding and
+decoding functionality for templates, including images that are embedded in
+templates; this allows templates to be stored independently of gofpdf. Paul
+also added support for page boxes used in printing PDF documents. Wojciech
+Matusiak added supported for word spacing. Artem Korotkiy added support of
+UTF-8 fonts. Dave Barnes added support for imported objects and templates.
+Brigham Thompson added support for rounded rectangles. Joe Westcott added
+underline functionality and optimized image storage.
+
+## Roadmap
+
+* Improve test coverage as reported by the coverage tool.
+
+
+[badge-author]: https://img.shields.io/badge/author-Kurt_Jung-blue.svg
+[badge-doc]: https://img.shields.io/badge/godoc-GoFPDF-blue.svg
+[badge-github]: https://img.shields.io/badge/project-Git_Hub-blue.svg
+[badge-mit]: https://img.shields.io/badge/license-MIT-blue.svg
+[badge-report]: https://goreportcard.com/badge/github.com/jung-kurt/gofpdf
+[badge-status]: https://travis-ci.org/jung-kurt/gofpdf.svg?branch=master
+[coverage]: https://blog.golang.org/cover
+[dfont]: http://dejavu-fonts.org/
+[draw2d-site]: https://github.com/llgcode/draw2d
+[effective-go]: https://golang.org/doc/effective_go.html
+[fpdf-site]: http://www.fpdf.org/
+[fpdf-test]: https://github.com/jung-kurt/gofpdf/blob/master/fpdf_test.go
+[gfont]: https://fonts.google.com/
+[github]: https://github.com/jung-kurt/gofpdf
+[godoc]: https://godoc.org/github.com/jung-kurt/gofpdf
+[issue109]: https://github.com/jung-kurt/gofpdf/issues/109
+[jung]: https://github.com/jung-kurt/
+[license]: https://raw.githubusercontent.com/jung-kurt/gofpdf/master/LICENSE
+[lint]: https://github.com/golang/lint
+[logo]: https://github.com/jung-kurt/gofpdf/raw/master/image/logo_gofpdf.jpg?raw=true
+[noto]: https://github.com/jsntn/webfonts/blob/master/NotoSansSC-Regular.ttf
+[pr]: https://help.github.com/articles/using-pull-requests/
+[report]: https://goreportcard.com/report/github.com/jung-kurt/gofpdf
+[status]: https://travis-ci.org/jung-kurt/gofpdf
+[test]: https://github.com/jung-kurt/gofpdf/blob/master/fpdf_test.go
+[vet]: https://golang.org/cmd/vet/
diff --git a/doc/go.awk b/doc/go.awk
new file mode 100644
index 0000000..bcd4a7c
--- /dev/null
+++ b/doc/go.awk
@@ -0,0 +1,13 @@
+BEGIN { show = 0 ; print "/*" }
+
+/^\-/ { trim = 1 ; print "" }
+
+/^Package/ { show = 1 }
+
+!NF { trim = 0 }
+
+trim { sub("^ +", "", $0) }
+
+show { print $0 }
+
+END { print "*/\npackage " package_name }
diff --git a/doc/html.txt b/doc/html.txt
new file mode 100644
index 0000000..7a89bb1
--- /dev/null
+++ b/doc/html.txt
@@ -0,0 +1,68 @@
+<!doctype html>
+
+<html lang="en">
+
+<head>
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width initial-scale=1 maximum-scale=1 minimum-scale=1 user-scalable=0" />
+ <title>GoFPDF Document Generator</title>
+ <style>
+ body {
+ max-width: 800px;
+ font-family: sans-serif;
+ padding: 1em;
+ }
+
+ img {
+ max-width: 800px;
+ }
+
+ h1,
+ h2,
+ h3 {
+ color: #345;
+ }
+
+ .syntax {
+ display: block;
+ white-space: pre;
+ font-family: monospace;
+ background-color: #efe;
+ border: 1px solid #474;
+ margin: 1em 0;
+ padding: 0.25em 1.5em;
+ }
+
+ .warning {
+ background-color: #ffd;
+ border: 1px solid #665;
+ margin: 1em 0;
+ padding: 0 1em;
+ }
+
+ .key {
+ color: #131;
+ font-weight: bold;
+ }
+
+ .subkey {
+ font-style: italic;
+ }
+
+ pre {
+ margin: 1.5em 0;
+ background-color: #eee;
+ padding: 1em;
+ overflow-x: scroll;
+ }
+$if(highlighting-css)$
+$highlighting-css$
+$endif$
+ </style>
+</head>
+
+<body>
+$body$
+</body>
+
+</html>
diff --git a/go.sum b/go.sum
new file mode 100644
index 0000000..a6b40f3
--- /dev/null
+++ b/go.sum
@@ -0,0 +1,18 @@
+github.com/boombuler/barcode v1.0.0 h1:s1TvRnXwL2xJRaccrdcBQMZxq6X7DvsMogtmJeHDdrc=
+github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
+github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/jung-kurt/gofpdf v1.0.0/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes=
+github.com/phpdave11/gofpdi v1.0.7 h1:k2oy4yhkQopCK+qW8KjCla0iU2RpDow+QUDmH9DDt44=
+github.com/phpdave11/gofpdi v1.0.7/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI=
+github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
+github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58 h1:nlG4Wa5+minh3S9LVFtNoY+GVRiudA2e3EVfcCi3RCA=
+github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w=
+github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
+github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
+golang.org/x/image v0.0.0-20190902063713-cb417be4ba39 h1:4dQcAORh9oYBwVSBVIkP489LUPC+f1HBkTYXgmqfR+o=
+golang.org/x/image v0.0.0-20190902063713-cb417be4ba39/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
diff --git a/pdf/reference/Fpdf_SplitLines_tables.pdf b/pdf/reference/Fpdf_SplitLines_tables.pdf
new file mode 100644
index 0000000..f0d3635
--- /dev/null
+++ b/pdf/reference/Fpdf_SplitLines_tables.pdf
@@ -0,0 +1,159 @@
+%PDF-1.3
+3 0 obj
+<</Type /Page
+/Parent 1 0 R
+/Resources 2 0 R
+/Contents 4 0 R>>
+endobj
+4 0 obj
+<</Length 4847>>
+stream
+0 J
+0 j
+0.57 w
+BT /F0a76705d18e0494dd24cb573e53aa0a8c710ec99 14.00 Tf ET
+0.000 G
+0.000 g
+BT /F0a76705d18e0494dd24cb573e53aa0a8c710ec99 14.00 Tf ET
+0.251 g
+42.52 799.37 170.08 -28.35 re B q 0.878 g BT 96.83 781.00 Td (Column A)Tj ET Q
+212.60 799.37 170.08 -28.35 re B q 0.878 g BT 266.91 781.00 Td (Column B)Tj ET Q
+382.68 799.37 170.08 -28.35 re B q 0.878 g BT 436.60 781.00 Td (Column C)Tj ET Q
+1.000 g
+42.52 771.02 170.08 -260.79 re S
+q 0.094 g BT 51.02 675.41 Td (Lorem ipsum dolor sit)Tj ET Q
+q 0.094 g BT 51.02 659.82 Td (amet, consectetur)Tj ET Q
+q 0.094 g BT 51.02 644.23 Td (adipisicing elit, sed do)Tj ET Q
+q 0.094 g BT 51.02 628.63 Td (eiusmod tempor)Tj ET Q
+q 0.094 g BT 51.02 613.04 Td (incididunt ut labore et)Tj ET Q
+q 0.094 g BT 51.02 597.45 Td (dolore magna aliqua.)Tj ET Q
+212.60 771.02 170.08 -260.79 re S
+q 0.094 g BT 230.73 714.38 Td (Lorem ipsum dolor sit)Tj ET Q
+q 0.094 g BT 242.00 698.79 Td (amet, consectetur)Tj ET Q
+q 0.094 g BT 229.16 683.20 Td (adipisicing elit, sed do)Tj ET Q
+q 0.094 g BT 247.45 667.61 Td (eiusmod tempor)Tj ET Q
+q 0.094 g BT 231.10 652.02 Td (incididunt ut labore et)Tj ET Q
+q 0.094 g BT 223.33 636.43 Td (dolore magna aliqua. Ut)Tj ET Q
+q 0.094 g BT 225.68 620.84 Td (enim ad minim veniam,)Tj ET Q
+q 0.094 g BT 221.77 605.25 Td (quis nostrud exercitation)Tj ET Q
+q 0.094 g BT 230.73 589.66 Td (ullamco laboris nisi ut)Tj ET Q
+q 0.094 g BT 225.66 574.07 Td (aliquip ex ea commodo)Tj ET Q
+q 0.094 g BT 263.39 558.48 Td (consequat.)Tj ET Q
+382.68 771.02 170.08 -260.79 re S
+q 0.094 g BT 410.44 753.36 Td (Lorem ipsum dolor sit)Tj ET Q
+q 0.094 g BT 432.98 737.77 Td (amet, consectetur)Tj ET Q
+q 0.094 g BT 407.30 722.18 Td (adipisicing elit, sed do)Tj ET Q
+q 0.094 g BT 443.89 706.59 Td (eiusmod tempor)Tj ET Q
+q 0.094 g BT 411.18 691.00 Td (incididunt ut labore et)Tj ET Q
+q 0.094 g BT 395.63 675.41 Td (dolore magna aliqua. Ut)Tj ET Q
+q 0.094 g BT 400.33 659.82 Td (enim ad minim veniam,)Tj ET Q
+q 0.094 g BT 392.52 644.23 Td (quis nostrud exercitation)Tj ET Q
+q 0.094 g BT 410.44 628.63 Td (ullamco laboris nisi ut)Tj ET Q
+q 0.094 g BT 400.30 613.04 Td (aliquip ex ea commodo)Tj ET Q
+q 0.094 g BT 412.74 597.45 Td (consequat. Duis aute)Tj ET Q
+q 0.094 g BT 466.45 581.86 Td (irure dolor in)Tj ET Q
+q 0.094 g BT 446.21 566.27 Td (reprehenderit in)Tj ET Q
+q 0.094 g BT 425.20 550.68 Td (voluptate velit esse)Tj ET Q
+q 0.094 g BT 408.09 535.09 Td (cillum dolore eu fugiat)Tj ET Q
+q 0.094 g BT 459.44 519.50 Td (nulla pariatur.)Tj ET Q
+42.52 510.24 170.08 -338.74 re S
+q 0.094 g BT 51.02 492.57 Td (Lorem ipsum dolor sit)Tj ET Q
+q 0.094 g BT 51.02 476.98 Td (amet, consectetur)Tj ET Q
+q 0.094 g BT 51.02 461.39 Td (adipisicing elit, sed do)Tj ET Q
+q 0.094 g BT 51.02 445.80 Td (eiusmod tempor)Tj ET Q
+q 0.094 g BT 51.02 430.21 Td (incididunt ut labore et)Tj ET Q
+q 0.094 g BT 51.02 414.62 Td (dolore magna aliqua. Ut)Tj ET Q
+q 0.094 g BT 51.02 399.03 Td (enim ad minim veniam,)Tj ET Q
+q 0.094 g BT 51.02 383.44 Td (quis nostrud exercitation)Tj ET Q
+q 0.094 g BT 51.02 367.85 Td (ullamco laboris nisi ut)Tj ET Q
+q 0.094 g BT 51.02 352.26 Td (aliquip ex ea commodo)Tj ET Q
+q 0.094 g BT 51.02 336.67 Td (consequat. Duis aute)Tj ET Q
+q 0.094 g BT 51.02 321.08 Td (irure dolor in)Tj ET Q
+q 0.094 g BT 51.02 305.49 Td (reprehenderit in)Tj ET Q
+q 0.094 g BT 51.02 289.89 Td (voluptate velit esse)Tj ET Q
+q 0.094 g BT 51.02 274.30 Td (cillum dolore eu fugiat)Tj ET Q
+q 0.094 g BT 51.02 258.71 Td (nulla pariatur. Excepteur)Tj ET Q
+q 0.094 g BT 51.02 243.12 Td (sint occaecat cupidatat)Tj ET Q
+q 0.094 g BT 51.02 227.53 Td (non proident, sunt in)Tj ET Q
+q 0.094 g BT 51.02 211.94 Td (culpa qui officia)Tj ET Q
+q 0.094 g BT 51.02 196.35 Td (deserunt mollit anim id)Tj ET Q
+q 0.094 g BT 51.02 180.76 Td (est laborum.)Tj ET Q
+212.60 510.24 170.08 -338.74 re S
+q 0.094 g BT 230.73 375.64 Td (Lorem ipsum dolor sit)Tj ET Q
+q 0.094 g BT 242.00 360.05 Td (amet, consectetur)Tj ET Q
+q 0.094 g BT 229.16 344.46 Td (adipisicing elit, sed do)Tj ET Q
+q 0.094 g BT 247.45 328.87 Td (eiusmod tempor)Tj ET Q
+q 0.094 g BT 231.10 313.28 Td (incididunt ut labore et)Tj ET Q
+q 0.094 g BT 232.27 297.69 Td (dolore magna aliqua.)Tj ET Q
+382.68 510.24 170.08 -338.74 re S
+q 0.094 g BT 410.44 414.62 Td (Lorem ipsum dolor sit)Tj ET Q
+q 0.094 g BT 432.98 399.03 Td (amet, consectetur)Tj ET Q
+q 0.094 g BT 407.30 383.44 Td (adipisicing elit, sed do)Tj ET Q
+q 0.094 g BT 443.89 367.85 Td (eiusmod tempor)Tj ET Q
+q 0.094 g BT 411.18 352.26 Td (incididunt ut labore et)Tj ET Q
+q 0.094 g BT 395.63 336.67 Td (dolore magna aliqua. Ut)Tj ET Q
+q 0.094 g BT 400.33 321.08 Td (enim ad minim veniam,)Tj ET Q
+q 0.094 g BT 392.52 305.49 Td (quis nostrud exercitation)Tj ET Q
+q 0.094 g BT 410.44 289.89 Td (ullamco laboris nisi ut)Tj ET Q
+q 0.094 g BT 400.30 274.30 Td (aliquip ex ea commodo)Tj ET Q
+q 0.094 g BT 475.76 258.71 Td (consequat.)Tj ET Q
+
+endstream
+endobj
+1 0 obj
+<</Type /Pages
+/Kids [3 0 R ]
+/Count 1
+/MediaBox [0 0 595.28 841.89]
+>>
+endobj
+5 0 obj
+<</Type /Font
+/BaseFont /Helvetica
+/Subtype /Type1
+/Encoding /WinAnsiEncoding
+>>
+endobj
+2 0 obj
+<<
+/ProcSet [/PDF /Text /ImageB /ImageC /ImageI]
+/Font <<
+/F0a76705d18e0494dd24cb573e53aa0a8c710ec99 5 0 R
+>>
+/XObject <<
+>>
+/ColorSpace <<
+>>
+>>
+endobj
+6 0 obj
+<<
+/Producer (FPDF 1.7)
+/CreationDate (D:20000101000000)
+>>
+endobj
+7 0 obj
+<<
+/Type /Catalog
+/Pages 1 0 R
+>>
+endobj
+xref
+0 8
+0000000000 65535 f
+0000004984 00000 n
+0000005167 00000 n
+0000000009 00000 n
+0000000087 00000 n
+0000005071 00000 n
+0000005328 00000 n
+0000005403 00000 n
+trailer
+<<
+/Size 8
+/Root 7 0 R
+/Info 6 0 R
+>>
+startxref
+5452
+%%EOF
diff --git a/pdf/reference/Fpdf_UnderlineThickness.pdf b/pdf/reference/Fpdf_UnderlineThickness.pdf
new file mode 100644
index 0000000..49ad9b1
--- /dev/null
+++ b/pdf/reference/Fpdf_UnderlineThickness.pdf
Binary files differ
diff --git a/splittext.go b/splittext.go
new file mode 100644
index 0000000..525f93b
--- /dev/null
+++ b/splittext.go
@@ -0,0 +1,53 @@
+package gofpdf
+
+import (
+ "math"
+ // "strings"
+ "unicode"
+)
+
+// SplitText splits UTF-8 encoded text into several lines using the current
+// font. Each line has its length limited to a maximum width given by w. This
+// function can be used to determine the total height of wrapped text for
+// vertical placement purposes.
+func (f *Fpdf) SplitText(txt string, w float64) (lines []string) {
+ cw := f.currentFont.Cw
+ wmax := int(math.Ceil((w - 2*f.cMargin) * 1000 / f.fontSize))
+ s := []rune(txt) // Return slice of UTF-8 runes
+ nb := len(s)
+ for nb > 0 && s[nb-1] == '\n' {
+ nb--
+ }
+ s = s[0:nb]
+ sep := -1
+ i := 0
+ j := 0
+ l := 0
+ for i < nb {
+ c := s[i]
+ l += cw[c]
+ if unicode.IsSpace(c) || isChinese(c) {
+ sep = i
+ }
+ if c == '\n' || l > wmax {
+ if sep == -1 {
+ if i == j {
+ i++
+ }
+ sep = i
+ } else {
+ i = sep + 1
+ }
+ lines = append(lines, string(s[j:sep]))
+ sep = -1
+ j = i
+ l = 0
+ } else {
+ i++
+ }
+ }
+ if i != j {
+ lines = append(lines, string(s[j:i]))
+ }
+ return lines
+}