diff options
| -rw-r--r-- | compare.go | 149 | ||||
| -rw-r--r-- | contrib/barcode/barcode_test.go | 7 | ||||
| -rw-r--r-- | contrib/httpimg/httpimg_test.go | 7 | ||||
| -rw-r--r-- | def.go | 7 | ||||
| -rw-r--r-- | fpdf.go | 300 | ||||
| -rw-r--r-- | fpdf_test.go | 14 | ||||
| -rw-r--r-- | internal/example/example.go | 25 | ||||
| -rw-r--r-- | template.go | 6 | 
8 files changed, 403 insertions, 112 deletions
| diff --git a/compare.go b/compare.go new file mode 100644 index 0000000..64cad1f --- /dev/null +++ b/compare.go @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2015 Kurt Jung (Gmail: kurt.w.jung) + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +package gofpdf + +import ( +	"bytes" +	"fmt" +	"io" +	"io/ioutil" +	"sort" +) + +type sortType struct { +	length int +	less   func(int, int) bool +	swap   func(int, int) +} + +func (s *sortType) Len() int { +	return s.length +} + +func (s *sortType) Less(i, j int) bool { +	return s.less(i, j) +} + +func (s *sortType) Swap(i, j int) { +	s.swap(i, j) +} + +func gensort(Len int, Less func(int, int) bool, Swap func(int, int)) { +	sort.Sort(&sortType{length: Len, less: Less, swap: Swap}) +} + +func writeBytes(leadStr string, startPos int, sl []byte) { +	var pos, max int +	var b byte +	fmt.Printf("%s %07x", leadStr, startPos) +	max = len(sl) +	for pos < max { +		fmt.Printf(" ") +		for k := 0; k < 8; k++ { +			if pos < max { +				fmt.Printf(" %02x", sl[pos]) +			} else { +				fmt.Printf("   ") +			} +			pos++ +		} +	} +	fmt.Printf("  |") +	pos = 0 +	for pos < max { +		b = sl[pos] +		if b < 32 || b >= 128 { +			b = '.' +		} +		fmt.Printf("%c", b) +		pos++ +	} +	fmt.Printf("|\n") +} + +func checkBytes(pos int, sl1, sl2 []byte) (eq bool) { +	eq = bytes.Equal(sl1, sl2) +	if !eq { +		writeBytes("<", pos, sl1) +		writeBytes(">", pos, sl2) +	} +	return +} + +// compareBytes compares the bytes referred to by sl1 with those referred to by +// sl2. Nil is returned if the buffers are equal, otherwise an error. +func compareBytes(sl1, sl2 []byte) (err error) { +	var posStart, posEnd, len1, len2, length int +	var diffs bool + +	len1 = len(sl1) +	len2 = len(sl2) +	length = len1 +	if length > len2 { +		length = len2 +	} +	for posStart < length-1 { +		posEnd = posStart + 16 +		if posEnd > length { +			posEnd = length +		} +		if !checkBytes(posStart, sl1[posStart:posEnd], sl2[posStart:posEnd]) { +			diffs = true +		} +		posStart = posEnd +	} +	if diffs { +		err = fmt.Errorf("documents are different") +	} +	return +} + +// ComparePDFs reads and compares the full contents of the two specified +// readers. The comparison is done byte-for-byte with the exception of the +// CreationDate fields which are effectively ignored. Nil is returned if the +// buffers are equal, otherwise an error. +func ComparePDFs(rdr1, rdr2 io.Reader) (err error) { +	var b1, b2 *bytes.Buffer +	_, err = b1.ReadFrom(rdr1) +	if err == nil { +		_, err = b2.ReadFrom(rdr2) +		if err == nil { +			err = compareBytes(b1.Bytes(), b2.Bytes()) +		} +	} +	return +} + +// ComparePDFFiles reads and compares the full contents of the two specified +// files. The comparison is done byte-for-byte with the exception of the +// CreationDate fields which are effectively ignored. Nil is returned if the +// file contents are equal, or if the second file is missing, otherwise an +// error. +func ComparePDFFiles(file1Str, file2Str string) (err error) { +	var sl1, sl2 []byte +	sl1, err = ioutil.ReadFile(file1Str) +	if err == nil { +		sl2, err = ioutil.ReadFile(file2Str) +		if err == nil { +			err = compareBytes(sl1, sl2) +		} else { +			// Second file is missing; treat this as success +			err = nil +		} +	} +	return +} diff --git a/contrib/barcode/barcode_test.go b/contrib/barcode/barcode_test.go index c12ff12..86aafcc 100644 --- a/contrib/barcode/barcode_test.go +++ b/contrib/barcode/barcode_test.go @@ -1,6 +1,8 @@  package barcode_test  import ( +	"time" +  	"github.com/boombuler/barcode/code128"  	"github.com/boombuler/barcode/qr"  	"github.com/jung-kurt/gofpdf" @@ -8,6 +10,11 @@ import (  	"github.com/jung-kurt/gofpdf/internal/example"  ) +func init() { +	gofpdf.SetDefaultCatalogSort(true) +	gofpdf.SetDefaultCreationDate(time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC)) +} +  func createPdf() (pdf *gofpdf.Fpdf) {  	pdf = gofpdf.New("L", "mm", "A4", "")  	pdf.SetFont("Helvetica", "", 12) diff --git a/contrib/httpimg/httpimg_test.go b/contrib/httpimg/httpimg_test.go index bf13492..6390f09 100644 --- a/contrib/httpimg/httpimg_test.go +++ b/contrib/httpimg/httpimg_test.go @@ -1,11 +1,18 @@  package httpimg_test  import ( +	"time" +  	"github.com/jung-kurt/gofpdf"  	"github.com/jung-kurt/gofpdf/contrib/httpimg"  	"github.com/jung-kurt/gofpdf/internal/example"  ) +func init() { +	gofpdf.SetDefaultCatalogSort(true) +	gofpdf.SetDefaultCreationDate(time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC)) +} +  func ExampleRegister() {  	pdf := gofpdf.New("L", "mm", "A4", "")  	pdf.SetFont("Helvetica", "", 12) @@ -19,6 +19,7 @@ package gofpdf  import (  	"bytes"  	"io" +	"time"  )  // Version of FPDF from which this package is derived @@ -150,7 +151,7 @@ type InitType struct {  // from arbitrary locations (e.g. files, zip files, embedded font resources).  //  // Open provides an io.Reader for the specified font file (.json or .z). The file name -// does never include a path. Open returns an error if the specified file cannot be opened. +// never includes a path. Open returns an error if the specified file cannot be opened.  type FontLoader interface {  	Open(name string) (io.Reader, error)  } @@ -161,7 +162,7 @@ type Fpdf struct {  	n                int                       // current object number  	offsets          []int                     // array of object offsets  	templates        map[int64]Template        // templates used in this document -	templateObjects  map[int64]int             //template object IDs within this document +	templateObjects  map[int64]int             // template object IDs within this document  	buffer           fmtBuffer                 // buffer holding in-memory PDF  	pages            []*bytes.Buffer           // slice[page] of page content; 1-based  	state            int                       // current document state @@ -216,6 +217,7 @@ type Fpdf struct {  	author           string                    // author  	keywords         string                    // keywords  	creator          string                    // creator +	creationDate     time.Time                 // override for dcoument CreationDate value  	aliasNbPagesStr  string                    // alias for total number of pages  	pdfVersion       string                    // PDF version number  	fontDirStr       string                    // location of font definition files @@ -233,6 +235,7 @@ type Fpdf struct {  	err              error                     // Set if error occurs during life cycle of instance  	protect          protectType               // document protection structure  	layer            layerRecType              // manages optional layers in document +	catalogSort      bool                      // sort resource catalogs in document  	colorFlag        bool                      // indicates whether fill and text colors are different  	color            struct {                  // Composite values of colors  		draw, fill, text clrType @@ -36,11 +36,17 @@ import (  	"math"  	"os"  	"path" +	"sort"  	"strconv"  	"strings"  	"time"  ) +var gl struct { +	catalogSort  bool +	creationDate time.Time +} +  type fmtBuffer struct {  	bytes.Buffer  } @@ -179,6 +185,8 @@ func fpdfNew(orientationStr, unitStr, sizeStr, fontDirStr string, size SizeType)  	// Set default PDF version number  	f.pdfVersion = "1.3"  	f.layerInit() +	f.catalogSort = gl.catalogSort +	f.creationDate = gl.creationDate  	return  } @@ -2986,6 +2994,35 @@ func (f *Fpdf) outf(fmtStr string, args ...interface{}) {  	f.out(sprintf(fmtStr, args...))  } +// SetDefaultCatalogSort sets the default value of the catalog sort flag that +// will be used when initializing a new Fpdf instance. See SetCatalogSort() for +// more details. +func SetDefaultCatalogSort(flag bool) { +	gl.catalogSort = flag +} + +// SetCatalogSort sets a flag that will be used, if true, to consistently order +// the document's internal resource catalogs. This method is typically only +// used for test purposes. +func (f *Fpdf) SetCatalogSort(flag bool) { +	f.catalogSort = flag +} + +// SetDefaultCreationDate sets the default value of the document creation date +// that will be used when initializing a new Fpdf instance. See +// SetCreationDate() for more details. +func SetDefaultCreationDate(tm time.Time) { +	gl.creationDate = tm +} + +// SetCreationDate fixes the document's internal CreationDate value. By +// default, the time when the document is generated is used for this value. +// This method is typically only used for testing purposes. Specify a +// zero-value time to revert to the default behavior. +func (f *Fpdf) SetCreationDate(tm time.Time) { +	f.creationDate = tm +} +  func (f *Fpdf) putpages() {  	var wPt, hPt float64  	var pageSize SizeType @@ -3092,107 +3129,130 @@ func (f *Fpdf) putfonts() {  		f.outf("<</Type /Encoding /BaseEncoding /WinAnsiEncoding /Differences [%s]>>", diff)  		f.out("endobj")  	} -	for file, info := range f.fontFiles { -		// 	foreach($this->fontFiles as $file=>$info) -		// Font file embedding -		f.newobj() -		info.n = f.n -		f.fontFiles[file] = info -		font, err := f.loadFontFile(file) -		if err != nil { -			f.err = err -			return -		} -		// dbg("font file [%s], ext [%s]", file, file[len(file)-2:]) -		compressed := file[len(file)-2:] == ".z" -		if !compressed && info.length2 > 0 { -			buf := font[6:info.length1] -			buf = append(buf, font[6+info.length1+6:info.length2]...) -			font = buf +	{ +		var fileList []string +		var info fontFileType +		var file string +		for file = range f.fontFiles { +			fileList = append(fileList, file)  		} -		f.outf("<</Length %d", len(font)) -		if compressed { -			f.out("/Filter /FlateDecode") +		if f.catalogSort { +			sort.Strings(fileList)  		} -		f.outf("/Length1 %d", info.length1) -		if info.length2 > 0 { -			f.outf("/Length2 %d /Length3 0", info.length2) -		} -		f.out(">>") -		f.putstream(font) -		f.out("endobj") -	} -	for k, font := range f.fonts { -		// Font objects -		font.N = f.n + 1 -		f.fonts[k] = font -		tp := font.Tp -		name := font.Name -		if tp == "Core" { -			// Core font +		for _, file = range fileList { +			info = f.fontFiles[file] +			// Font file embedding  			f.newobj() -			f.out("<</Type /Font") -			f.outf("/BaseFont /%s", name) -			f.out("/Subtype /Type1") -			if name != "Symbol" && name != "ZapfDingbats" { -				f.out("/Encoding /WinAnsiEncoding") +			info.n = f.n +			f.fontFiles[file] = info +			font, err := f.loadFontFile(file) +			if err != nil { +				f.err = err +				return  			} -			f.out(">>") -			f.out("endobj") -		} else if tp == "Type1" || tp == "TrueType" { -			// Additional Type1 or TrueType/OpenType font -			f.newobj() -			f.out("<</Type /Font") -			f.outf("/BaseFont /%s", name) -			f.outf("/Subtype /%s", tp) -			f.out("/FirstChar 32 /LastChar 255") -			f.outf("/Widths %d 0 R", f.n+1) -			f.outf("/FontDescriptor %d 0 R", f.n+2) -			if font.DiffN > 0 { -				f.outf("/Encoding %d 0 R", nf+font.DiffN) -			} else { -				f.out("/Encoding /WinAnsiEncoding") +			// dbg("font file [%s], ext [%s]", file, file[len(file)-2:]) +			compressed := file[len(file)-2:] == ".z" +			if !compressed && info.length2 > 0 { +				buf := font[6:info.length1] +				buf = append(buf, font[6+info.length1+6:info.length2]...) +				font = buf  			} -			f.out(">>") -			f.out("endobj") -			// Widths -			f.newobj() -			var s fmtBuffer -			s.WriteString("[") -			for j := 32; j < 256; j++ { -				s.printf("%d ", font.Cw[j]) +			f.outf("<</Length %d", len(font)) +			if compressed { +				f.out("/Filter /FlateDecode")  			} -			s.WriteString("]") -			f.out(s.String()) -			f.out("endobj") -			// Descriptor -			f.newobj() -			s.Truncate(0) -			s.printf("<</Type /FontDescriptor /FontName /%s ", name) -			s.printf("/Ascent %d ", font.Desc.Ascent) -			s.printf("/Descent %d ", font.Desc.Descent) -			s.printf("/CapHeight %d ", font.Desc.CapHeight) -			s.printf("/Flags %d ", font.Desc.Flags) -			s.printf("/FontBBox [%d %d %d %d] ", font.Desc.FontBBox.Xmin, font.Desc.FontBBox.Ymin, -				font.Desc.FontBBox.Xmax, font.Desc.FontBBox.Ymax) -			s.printf("/ItalicAngle %d ", font.Desc.ItalicAngle) -			s.printf("/StemV %d ", font.Desc.StemV) -			s.printf("/MissingWidth %d ", font.Desc.MissingWidth) -			var suffix string -			if tp != "Type1" { -				suffix = "2" +			f.outf("/Length1 %d", info.length1) +			if info.length2 > 0 { +				f.outf("/Length2 %d /Length3 0", info.length2)  			} -			s.printf("/FontFile%s %d 0 R>>", suffix, f.fontFiles[font.File].n) -			f.out(s.String()) +			f.out(">>") +			f.putstream(font)  			f.out("endobj") -		} else { -			f.err = fmt.Errorf("unsupported font type: %s", tp) -			return -			// Allow for additional types -			// 			$mtd = 'put'.strtolower($type); -			// 			if(!method_exists($this,$mtd)) -			// 				$this->Error('Unsupported font type: '.$type); -			// 			$this->$mtd($font); +		} +	} +	{ +		var keyList []string +		var font fontDefType +		var key string +		for key = range f.fonts { +			keyList = append(keyList, key) +		} +		if f.catalogSort { +			sort.Strings(keyList) +		} +		for _, key = range keyList { +			font = f.fonts[key] +			// Font objects +			font.N = f.n + 1 +			f.fonts[key] = font +			tp := font.Tp +			name := font.Name +			if tp == "Core" { +				// Core font +				f.newobj() +				f.out("<</Type /Font") +				f.outf("/BaseFont /%s", name) +				f.out("/Subtype /Type1") +				if name != "Symbol" && name != "ZapfDingbats" { +					f.out("/Encoding /WinAnsiEncoding") +				} +				f.out(">>") +				f.out("endobj") +			} else if tp == "Type1" || tp == "TrueType" { +				// Additional Type1 or TrueType/OpenType font +				f.newobj() +				f.out("<</Type /Font") +				f.outf("/BaseFont /%s", name) +				f.outf("/Subtype /%s", tp) +				f.out("/FirstChar 32 /LastChar 255") +				f.outf("/Widths %d 0 R", f.n+1) +				f.outf("/FontDescriptor %d 0 R", f.n+2) +				if font.DiffN > 0 { +					f.outf("/Encoding %d 0 R", nf+font.DiffN) +				} else { +					f.out("/Encoding /WinAnsiEncoding") +				} +				f.out(">>") +				f.out("endobj") +				// Widths +				f.newobj() +				var s fmtBuffer +				s.WriteString("[") +				for j := 32; j < 256; j++ { +					s.printf("%d ", font.Cw[j]) +				} +				s.WriteString("]") +				f.out(s.String()) +				f.out("endobj") +				// Descriptor +				f.newobj() +				s.Truncate(0) +				s.printf("<</Type /FontDescriptor /FontName /%s ", name) +				s.printf("/Ascent %d ", font.Desc.Ascent) +				s.printf("/Descent %d ", font.Desc.Descent) +				s.printf("/CapHeight %d ", font.Desc.CapHeight) +				s.printf("/Flags %d ", font.Desc.Flags) +				s.printf("/FontBBox [%d %d %d %d] ", font.Desc.FontBBox.Xmin, font.Desc.FontBBox.Ymin, +					font.Desc.FontBBox.Xmax, font.Desc.FontBBox.Ymax) +				s.printf("/ItalicAngle %d ", font.Desc.ItalicAngle) +				s.printf("/StemV %d ", font.Desc.StemV) +				s.printf("/MissingWidth %d ", font.Desc.MissingWidth) +				var suffix string +				if tp != "Type1" { +					suffix = "2" +				} +				s.printf("/FontFile%s %d 0 R>>", suffix, f.fontFiles[font.File].n) +				f.out(s.String()) +				f.out("endobj") +			} else { +				f.err = fmt.Errorf("unsupported font type: %s", tp) +				return +				// Allow for additional types +				// 			$mtd = 'put'.strtolower($type); +				// 			if(!method_exists($this,$mtd)) +				// 				$this->Error('Unsupported font type: '.$type); +				// 			$this->$mtd($font); +			}  		}  	}  	return @@ -3213,8 +3273,16 @@ func (f *Fpdf) loadFontFile(name string) ([]byte, error) {  }  func (f *Fpdf) putimages() { -	for _, img := range f.images { -		f.putimage(img) +	var keyList []string +	var key string +	for key = range f.images { +		keyList = append(keyList, key) +	} +	if f.catalogSort { +		sort.Strings(keyList) +	} +	for _, key = range keyList { +		f.putimage(f.images[key])  	}  } @@ -3283,9 +3351,20 @@ func (f *Fpdf) putimage(info *ImageInfoType) {  }  func (f *Fpdf) putxobjectdict() { -	for _, image := range f.images { -		// 	foreach($this->images as $image) -		f.outf("/I%d %d 0 R", image.i, image.n) +	{ +		var image *ImageInfoType +		var key string +		var keyList []string +		for key = range f.images { +			keyList = append(keyList, key) +		} +		if f.catalogSort { +			sort.Strings(keyList) +		} +		for _, key = range keyList { +			image = f.images[key] +			f.outf("/I%d %d 0 R", image.i, image.n) +		}  	}  	for _, tpl := range f.templates {  		id := tpl.ID() @@ -3298,9 +3377,20 @@ func (f *Fpdf) putxobjectdict() {  func (f *Fpdf) putresourcedict() {  	f.out("/ProcSet [/PDF /Text /ImageB /ImageC /ImageI]")  	f.out("/Font <<") -	for _, font := range f.fonts { -		// 	foreach($this->fonts as $font) -		f.outf("/F%d %d 0 R", font.I, font.N) +	{ +		var keyList []string +		var font fontDefType +		var key string +		for key = range f.fonts { +			keyList = append(keyList, key) +		} +		if f.catalogSort { +			sort.Strings(keyList) +		} +		for _, key = range keyList { +			font = f.fonts[key] +			f.outf("/F%d %d 0 R", font.I, font.N) +		}  	}  	f.out(">>")  	f.out("/XObject <<") @@ -3400,6 +3490,7 @@ func (f *Fpdf) putresources() {  }  func (f *Fpdf) putinfo() { +	var tm time.Time  	f.outf("/Producer %s", f.textstring("FPDF "+cnFpdfVersion))  	if len(f.title) > 0 {  		f.outf("/Title %s", f.textstring(f.title)) @@ -3416,7 +3507,12 @@ func (f *Fpdf) putinfo() {  	if len(f.creator) > 0 {  		f.outf("/Creator %s", f.textstring(f.creator))  	} -	f.outf("/CreationDate %s", f.textstring("D:"+time.Now().Format("20060102150405"))) +	if f.creationDate.IsZero() { +		tm = time.Now() +	} else { +		tm = f.creationDate +	} +	f.outf("/CreationDate %s", f.textstring("D:"+tm.Format("20060102150405")))  }  func (f *Fpdf) putcatalog() { diff --git a/fpdf_test.go b/fpdf_test.go index 966767f..2238ccd 100644 --- a/fpdf_test.go +++ b/fpdf_test.go @@ -28,6 +28,7 @@ import (  	"path/filepath"  	"strconv"  	"strings" +	"time"  	"github.com/jung-kurt/gofpdf"  	"github.com/jung-kurt/gofpdf/internal/example" @@ -35,14 +36,21 @@ import (  func init() {  	cleanup() +	gofpdf.SetDefaultCatalogSort(true) +	gofpdf.SetDefaultCreationDate(time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC))  }  func cleanup() {  	filepath.Walk(example.PdfDir(),  		func(path string, info os.FileInfo, err error) (reterr error) { -			if len(path) > 3 { -				if path[len(path)-4:] == ".pdf" { -					os.Remove(path) +			if info.Mode().IsRegular() { +				dir, _ := filepath.Split(path) +				if "reference" != filepath.Base(dir) { +					if len(path) > 3 { +						if path[len(path)-4:] == ".pdf" { +							os.Remove(path) +						} +					}  				}  			}  			return diff --git a/internal/example/example.go b/internal/example/example.go index d6a114c..b29561c 100644 --- a/internal/example/example.go +++ b/internal/example/example.go @@ -22,6 +22,8 @@ import (  	"os"  	"path/filepath"  	"strings" + +	"github.com/jung-kurt/gofpdf"  )  var gofpdfDir string @@ -36,8 +38,7 @@ func setRoot() {  	wdStr, err := os.Getwd()  	if err == nil {  		gofpdfDir = "" -		sepStr := string(os.PathSeparator) -		list := strings.Split(wdStr, sepStr) +		list := strings.Split(filepath.ToSlash(wdStr), "/")  		for j := len(list) - 1; j >= 0 && list[j] != "gofpdf"; j-- {  			gofpdfDir = filepath.Join(gofpdfDir, "..")  		} @@ -87,12 +88,32 @@ func Filename(baseStr string) string {  	return PdfFile(baseStr + ".pdf")  } +// referenceCompare compares the specified file with the file's reference copy +// located in the 'reference' subdirectory. All bytes of the two files are +// compared except for the value of the /CreationDate field in the PDF. This +// function succeeds if both files are equivalent except for their +// /CreationDate values or if the reference file does not exist. +func referenceCompare(fileStr string) (err error) { +	var refFileStr, refDirStr, dirStr, baseFileStr string +	dirStr, baseFileStr = filepath.Split(fileStr) +	refDirStr = filepath.Join(dirStr, "reference") +	err = os.MkdirAll(refDirStr, 0755) +	if err == nil { +		refFileStr = filepath.Join(refDirStr, baseFileStr) +		err = gofpdf.ComparePDFFiles(fileStr, refFileStr) +	} +	return +} +  // Summary generates a predictable report for use by test examples. If the  // specified error is nil, the filename delimiters are normalized and the  // filename printed to standard output with a success message. If the specified  // error is not nil, its String() value is printed to standard output.  func Summary(err error, fileStr string) {  	if err == nil { +		err = referenceCompare(fileStr) +	} +	if err == nil {  		fileStr = filepath.ToSlash(fileStr)  		fmt.Printf("Successfully generated %s\n", fileStr)  	} else { diff --git a/template.go b/template.go index 7561ae1..342032e 100644 --- a/template.go +++ b/template.go @@ -36,7 +36,7 @@ func CreateTemplate(corner PointType, size SizeType, unitStr, fontDirStr string,  // using the size and position at which it was originally written.  func (f *Fpdf) UseTemplate(t Template) {  	if t == nil { -		f.SetErrorf("Template is nil") +		f.SetErrorf("template is nil")  		return  	}  	corner, size := t.Size() @@ -47,13 +47,13 @@ func (f *Fpdf) UseTemplate(t Template) {  // using the given page coordinates.  func (f *Fpdf) UseTemplateScaled(t Template, corner PointType, size SizeType) {  	if t == nil { -		f.SetErrorf("Template is nil") +		f.SetErrorf("template is nil")  		return  	}  	// You have to add at least a page first  	if f.page <= 0 { -		f.SetErrorf("Cannot use a template without first adding a page") +		f.SetErrorf("cannot use a template without first adding a page")  		return  	} | 
