summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--def.go96
-rw-r--r--fpdf_test.go10
-rw-r--r--template.go4
-rw-r--r--template_impl.go151
4 files changed, 258 insertions, 3 deletions
diff --git a/def.go b/def.go
index b4140a9..3c5fa9d 100644
--- a/def.go
+++ b/def.go
@@ -18,6 +18,7 @@ package gofpdf
import (
"bytes"
+ "encoding/gob"
"io"
"time"
)
@@ -175,6 +176,101 @@ type ImageInfoType struct {
dpi float64
}
+func (info *ImageInfoType) GobEncode() ([]byte, error) {
+ w := new(bytes.Buffer)
+ encoder := gob.NewEncoder(w)
+
+ err := encoder.Encode(info.data)
+ if err == nil {
+ err = encoder.Encode(info.smask)
+ }
+ if err == nil {
+ err = encoder.Encode(info.i)
+ }
+ if err == nil {
+ err = encoder.Encode(info.n)
+ }
+ if err == nil {
+ err = encoder.Encode(info.w)
+ }
+ if err == nil {
+ err = encoder.Encode(info.h)
+ }
+ if err == nil {
+ err = encoder.Encode(info.cs)
+ }
+ if err == nil {
+ err = encoder.Encode(info.pal)
+ }
+ if err == nil {
+ err = encoder.Encode(info.bpc)
+ }
+ if err == nil {
+ err = encoder.Encode(info.f)
+ }
+ if err == nil {
+ err = encoder.Encode(info.dp)
+ }
+ if err == nil {
+ err = encoder.Encode(info.trns)
+ }
+ if err == nil {
+ err = encoder.Encode(info.scale)
+ }
+ if err == nil {
+ err = encoder.Encode(info.dpi)
+ }
+
+ return w.Bytes(), err
+}
+
+func (info *ImageInfoType) GobDecode(buf []byte) error {
+ r := bytes.NewBuffer(buf)
+ decoder := gob.NewDecoder(r)
+
+ err := decoder.Decode(&info.data)
+ if err == nil {
+ err = decoder.Decode(&info.smask)
+ }
+ if err == nil {
+ err = decoder.Decode(&info.i)
+ }
+ if err == nil {
+ err = decoder.Decode(&info.n)
+ }
+ if err == nil {
+ err = decoder.Decode(&info.w)
+ }
+ if err == nil {
+ err = decoder.Decode(&info.h)
+ }
+ if err == nil {
+ err = decoder.Decode(&info.cs)
+ }
+ if err == nil {
+ err = decoder.Decode(&info.pal)
+ }
+ if err == nil {
+ err = decoder.Decode(&info.bpc)
+ }
+ if err == nil {
+ err = decoder.Decode(&info.f)
+ }
+ if err == nil {
+ err = decoder.Decode(&info.dp)
+ }
+ if err == nil {
+ err = decoder.Decode(&info.trns)
+ }
+ if err == nil {
+ err = decoder.Decode(&info.scale)
+ }
+ if err == nil {
+ err = decoder.Decode(&info.dpi)
+ }
+ return err
+}
+
// PointConvert returns the value of pt, expressed in points (1/72 inch), as a
// value expressed in the unit of measure specified in New(). Since font
// management in Fpdf uses points, this method can help with line height
diff --git a/fpdf_test.go b/fpdf_test.go
index 4774ec6..19bc533 100644
--- a/fpdf_test.go
+++ b/fpdf_test.go
@@ -1950,10 +1950,14 @@ func ExampleFpdf_CreateTemplate() {
pdf.SetLineWidth(2.5)
pdf.SetFont("Arial", "B", 16)
+ // serialize and deserialize template
+ b, _ := template2.Serialize()
+ template3, _ := gofpdf.DeserializeTemplate(b)
+
pdf.AddPage()
- pdf.UseTemplate(template)
- pdf.UseTemplateScaled(template, gofpdf.PointType{X: 0, Y: 30}, tplSize)
- pdf.UseTemplateScaled(template, gofpdf.PointType{X: 0, Y: 60}, tplSize.ScaleBy(1.4))
+ pdf.UseTemplate(template3)
+ pdf.UseTemplateScaled(template3, gofpdf.PointType{X: 0, Y: 30}, tplSize)
+ pdf.UseTemplateScaled(template3, gofpdf.PointType{X: 0, Y: 60}, tplSize.ScaleBy(1.4))
pdf.Line(40, 210, 60, 210)
pdf.Text(40, 200, "Template example page 1")
diff --git a/template.go b/template.go
index 0bb7f75..d27bc40 100644
--- a/template.go
+++ b/template.go
@@ -18,6 +18,7 @@ package gofpdf
*/
import (
+ "encoding/gob"
"sort"
)
@@ -123,6 +124,9 @@ type Template interface {
Bytes() []byte
Images() map[string]*ImageInfoType
Templates() []Template
+ Serialize() ([]byte, error)
+ gob.GobDecoder
+ gob.GobEncoder
}
func (f *Fpdf) templateFontCatalog() {
diff --git a/template_impl.go b/template_impl.go
index 76c5019..1a91112 100644
--- a/template_impl.go
+++ b/template_impl.go
@@ -1,5 +1,11 @@
package gofpdf
+import (
+ "bytes"
+ "encoding/gob"
+ "fmt"
+)
+
/*
* Copyright (c) 2015 Kurt Jung (Gmail: kurt.w.jung),
* Marcus Downing, Jan Slabon (Setasign)
@@ -76,6 +82,151 @@ func (t *FpdfTpl) Templates() []Template {
return t.templates
}
+// Turn a template into a byte string for later deserialization
+func (t *FpdfTpl) Serialize() ([]byte, error) {
+ b := new(bytes.Buffer)
+ enc := gob.NewEncoder(b)
+ err := enc.Encode(t)
+
+ return b.Bytes(), err
+}
+
+// Create a template from a previously serialized template
+func DeserializeTemplate(b []byte) (Template, error) {
+ tpl := new(FpdfTpl)
+ dec := gob.NewDecoder(bytes.NewBuffer(b))
+ err := dec.Decode(tpl)
+ return tpl, err
+}
+
+// returns the next layer of children images, it doesn't dig into
+// children of children. Applies template namespace to keys to ensure
+// no collisions. See UseTemplateScaled
+func (t *FpdfTpl) childrenImages() map[string]*ImageInfoType {
+ childrenImgs := make(map[string]*ImageInfoType)
+
+ for x := 0; x < len(t.templates); x++ {
+ imgs := t.templates[x].Images()
+ for key, val := range imgs {
+ name := sprintf("t%d-%s", t.templates[x].ID(), key)
+ childrenImgs[name] = val
+ }
+ }
+
+ return childrenImgs
+}
+
+func (t *FpdfTpl) GobEncode() ([]byte, error) {
+ w := new(bytes.Buffer)
+ encoder := gob.NewEncoder(w)
+
+ err := encoder.Encode(t.templates)
+ childrenImgs := t.childrenImages()
+
+ if err == nil {
+ encoder.Encode(len(t.images))
+ }
+
+ for key, img := range t.images {
+ // if the image has already been saved as a child, then
+ // save nil so we don't duplicate data
+ err = encoder.Encode(key)
+
+ if err != nil {
+ break
+ }
+
+ if _, ok := childrenImgs[key]; ok {
+ err = encoder.Encode("p")
+ } else {
+ err = encoder.Encode("o")
+ if err == nil {
+ err = encoder.Encode(img)
+ }
+ }
+ }
+ if err == nil {
+ err = encoder.Encode(t.id)
+ }
+ if err == nil {
+ err = encoder.Encode(t.corner)
+ }
+ if err == nil {
+ err = encoder.Encode(t.size)
+ }
+ if err == nil {
+ err = encoder.Encode(t.bytes)
+ }
+
+ return w.Bytes(), err
+}
+
+func (t *FpdfTpl) GobDecode(buf []byte) error {
+ r := bytes.NewBuffer(buf)
+ decoder := gob.NewDecoder(r)
+
+ templates := make([]*FpdfTpl, 0)
+ err := decoder.Decode(&templates)
+ t.templates = make([]Template, len(templates))
+
+ for x := 0; x < len(templates); x++ {
+ t.templates[x] = templates[x]
+ }
+
+ var numImgs int
+ if err == nil {
+ err = decoder.Decode(&numImgs)
+ }
+
+ t.images = make(map[string]*ImageInfoType)
+ childrenImgs := t.childrenImages()
+
+ for x := 0; x < numImgs; x++ {
+ var key string
+ var tpe string
+
+ if err == nil {
+ err = decoder.Decode(&key)
+ }
+
+ if err == nil {
+ err = decoder.Decode(&tpe)
+ }
+
+ if err == nil {
+ switch tpe {
+ case "p":
+ if _, ok := childrenImgs[key]; !ok {
+ err = fmt.Errorf("Encoded template is corrupt, could not find image %s", key)
+ } else {
+ t.images[key] = childrenImgs[key]
+ }
+ case "o":
+ var img *ImageInfoType
+ err = decoder.Decode(&img)
+
+ if err == nil {
+ t.images[key] = img
+ }
+ }
+ }
+ }
+ if err == nil {
+ err = decoder.Decode(&t.id)
+ }
+ if err == nil {
+ err = decoder.Decode(&t.corner)
+ }
+ if err == nil {
+ err = decoder.Decode(&t.size)
+ }
+ if err == nil {
+ err = decoder.Decode(&t.bytes)
+ }
+
+ return err
+}
+
// Tpl is an Fpdf used for writing a template. It has most of the facilities of
// an Fpdf, but cannot add more pages. Tpl is used directly only during the
// limited time a template is writable.