summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authord1ngd0 <paul.david.montag@gmail.com>2018-12-12 14:04:24 -0600
committerKurt Jung <kurt.w.jung@gmail.com>2018-12-12 15:04:24 -0500
commita8d8f9e6a80f014f8f5a2388fbf7f409fe9cf263 (patch)
tree5d362727bfa65589c7a6fe0cbf8ed5e5505874fd
parent95702eead4d148c6111f5a3ef7ef7cbc0c906b49 (diff)
Added the ability to have multiple pages in a template (#216)
* Added the ability to have multiple pages in a template Templates are now aware of the number of pages they have. The main additions are the FromPage and FromPages methods which allow you to extract a Template from a template if you pass in the page number. It follows the same page mechanism as FPDF where pages start in the index 1. * Update fpdf_test.go
-rw-r--r--fpdf_test.go36
-rw-r--r--template.go3
-rw-r--r--template_impl.go77
3 files changed, 99 insertions, 17 deletions
diff --git a/fpdf_test.go b/fpdf_test.go
index 3e731fd..2fbca9c 100644
--- a/fpdf_test.go
+++ b/fpdf_test.go
@@ -64,6 +64,42 @@ func TestFpdfImplementPdf(t *testing.T) {
var _ gofpdf.Pdf = (*gofpdf.Tpl)(nil)
}
+// TestPagedTemplate ensures new paged templates work
+func TestPagedTemplate(t *testing.T) {
+ pdf := gofpdf.New("P", "mm", "A4", "")
+ tpl := pdf.CreateTemplate(func(t *gofpdf.Tpl) {
+ // this will be the second page, as a page is already
+ // created by default
+ t.AddPage()
+ t.AddPage()
+ t.AddPage()
+ })
+
+ if tpl.NumPages() != 4 {
+ t.Fatalf("The template does not have the correct number of pages %d", tpl.NumPages())
+ }
+
+ tplPages := tpl.FromPages()
+ for x := 0; x < len(tplPages); x++ {
+ pdf.AddPage()
+ pdf.UseTemplate(tplPages[x])
+ }
+
+ // get the last template
+ tpl2, err := tpl.FromPage(tpl.NumPages())
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // the objects should be the exact same, as the
+ // template will represent the last page by default
+ // therefore no new id should be set, and the object
+ // should be the same object
+ if fmt.Sprintf("%p", tpl2) != fmt.Sprintf("%p", tpl) {
+ t.Fatal("Template no longer respecting initial template object")
+ }
+}
+
// TestIssue0116 addresses issue 116 in which library silently fails after
// calling CellFormat when no font has been set.
func TestIssue0116(t *testing.T) {
diff --git a/template.go b/template.go
index d27bc40..1bcd25d 100644
--- a/template.go
+++ b/template.go
@@ -124,6 +124,9 @@ type Template interface {
Bytes() []byte
Images() map[string]*ImageInfoType
Templates() []Template
+ NumPages() int
+ FromPage(int) (Template, error)
+ FromPages() []Template
Serialize() ([]byte, error)
gob.GobDecoder
gob.GobEncoder
diff --git a/template_impl.go b/template_impl.go
index 6a98e58..f7eeee1 100644
--- a/template_impl.go
+++ b/template_impl.go
@@ -3,6 +3,7 @@ package gofpdf
import (
"bytes"
"encoding/gob"
+ "errors"
"fmt"
)
@@ -32,10 +33,15 @@ func newTpl(corner PointType, size SizeType, orientationStr, unitStr, fontDirStr
if copyFrom != nil {
tpl.loadParamsFromFpdf(copyFrom)
}
- tpl.Fpdf.SetAutoPageBreak(false, 0)
tpl.Fpdf.AddPage()
fn(&tpl)
- bytes := tpl.Fpdf.pages[tpl.Fpdf.page].Bytes()
+
+ bytes := make([][]byte, len(tpl.Fpdf.pages))
+ // skip the first page as it will always be empty
+ for x := 1; x < len(bytes); x++ {
+ bytes[x] = tpl.Fpdf.pages[x].Bytes()
+ }
+
templates := make([]Template, 0, len(tpl.Fpdf.templates))
for _, key := range templateKeyList(tpl.Fpdf.templates, true) {
templates = append(templates, tpl.Fpdf.templates[key])
@@ -43,7 +49,7 @@ func newTpl(corner PointType, size SizeType, orientationStr, unitStr, fontDirStr
images := tpl.Fpdf.images
id := GenerateTemplateID()
- template := FpdfTpl{id, corner, size, bytes, images, templates}
+ template := FpdfTpl{id, corner, size, bytes, images, templates, tpl.Fpdf.page}
return &template
}
@@ -52,9 +58,10 @@ type FpdfTpl struct {
id int64
corner PointType
size SizeType
- bytes []byte
+ bytes [][]byte
images map[string]*ImageInfoType
templates []Template
+ page int
}
// ID returns the global template identifier
@@ -69,7 +76,42 @@ func (t *FpdfTpl) Size() (corner PointType, size SizeType) {
// Bytes returns the actual template data, not including resources
func (t *FpdfTpl) Bytes() []byte {
- return t.bytes
+ return t.bytes[t.page]
+}
+
+// FromPage creates a new template from a specific Page
+func (t *FpdfTpl) FromPage(page int) (Template, error) {
+ // pages start at 1
+ if page == 0 {
+ return nil, errors.New("Pages start at 1 No template will have a page 0")
+ }
+
+ if page > t.NumPages() {
+ return nil, fmt.Errorf("The template does not have a page %d", page)
+ }
+ // if it is already pointing to the correct page
+ // there is no need to create a new template
+ if t.page == page {
+ return t, nil
+ }
+
+ t2 := *t
+ t2.id = GenerateTemplateID()
+ t2.page = page
+ return &t2, nil
+}
+
+// FromPages creates a template slice with all the pages within a template.
+func (t *FpdfTpl) FromPages() []Template {
+ p := make([]Template, t.NumPages())
+ for x := 1; x <= t.NumPages(); x++ {
+ // the only error is when accessing a
+ // non existing template... that can't happen
+ // here
+ p[x-1], _ = t.FromPage(x)
+ }
+
+ return p
}
// Images returns a list of the images used in this template
@@ -82,6 +124,13 @@ func (t *FpdfTpl) Templates() []Template {
return t.templates
}
+// NumPages returns the number of available pages within the template. Look at FromPage and FromPages on access to that content.
+func (t *FpdfTpl) NumPages() int {
+ // the first page is empty to
+ // make the pages begin at one
+ return len(t.bytes) - 1
+}
+
// Serialize turns a template into a byte string for later deserialization
func (t *FpdfTpl) Serialize() ([]byte, error) {
b := new(bytes.Buffer)
@@ -160,6 +209,9 @@ func (t *FpdfTpl) GobEncode() ([]byte, error) {
if err == nil {
err = encoder.Encode(t.bytes)
}
+ if err == nil {
+ err = encoder.Encode(t.page)
+ }
return w.Bytes(), err
}
@@ -227,6 +279,9 @@ func (t *FpdfTpl) GobDecode(buf []byte) error {
if err == nil {
err = decoder.Decode(&t.bytes)
}
+ if err == nil {
+ err = decoder.Decode(&t.page)
+ }
return err
}
@@ -260,15 +315,3 @@ func (t *Tpl) loadParamsFromFpdf(f *Fpdf) {
t.Fpdf.fontStyle = f.fontStyle
t.Fpdf.ws = f.ws
}
-
-// AddPage does nothing because you cannot add pages to a template
-func (t *Tpl) AddPage() {
-}
-
-// AddPageFormat does nothign because you cannot add pages to a template
-func (t *Tpl) AddPageFormat(orientationStr string, size SizeType) {
-}
-
-// SetAutoPageBreak does nothing because you cannot add pages to a template
-func (t *Tpl) SetAutoPageBreak(auto bool, margin float64) {
-}