From bb287515d3b5c5b4ca7665a64a9224e8b6038804 Mon Sep 17 00:00:00 2001
From: Paul Montag <pmontag@iseeme.com>
Date: Wed, 31 Oct 2018 19:56:01 -0500
Subject: Added Ability to turn template into a byte string

---
 def.go           | 96 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 fpdf_test.go     | 20 ++++++++++--
 template.go      |  3 ++
 template_impl.go | 59 ++++++++++++++++++++++++++++++++++
 4 files changed, 175 insertions(+), 3 deletions(-)

diff --git a/def.go b/def.go
index d53e627..4b19a06 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..e212d95 100644
--- a/fpdf_test.go
+++ b/fpdf_test.go
@@ -19,6 +19,7 @@ package gofpdf_test
 import (
 	"bufio"
 	"bytes"
+	"encoding/gob"
 	"fmt"
 	"io"
 	"io/ioutil"
@@ -1950,10 +1951,23 @@ func ExampleFpdf_CreateTemplate() {
 	pdf.SetLineWidth(2.5)
 	pdf.SetFont("Arial", "B", 16)
 
+	template3 := new(gofpdf.FpdfTpl)
+	b := new(bytes.Buffer)
+	enc := gob.NewEncoder(b)
+
+	if err := enc.Encode(template); err != nil {
+		pdf.SetError(err)
+	}
+
+	dec := gob.NewDecoder(b)
+	if err := dec.Decode(template3); err != nil {
+		pdf.SetError(err)
+	}
+
 	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 60b076b..2b886ed 100644
--- a/template.go
+++ b/template.go
@@ -18,6 +18,7 @@ package gofpdf
  */
 
 import (
+	"encoding/gob"
 	"sort"
 )
 
@@ -107,6 +108,8 @@ type Template interface {
 	Bytes() []byte
 	Images() map[string]*ImageInfoType
 	Templates() []Template
+	gob.GobDecoder
+	gob.GobEncoder
 }
 
 func (f *Fpdf) templateFontCatalog() {
diff --git a/template_impl.go b/template_impl.go
index 01bb040..9e5d496 100644
--- a/template_impl.go
+++ b/template_impl.go
@@ -1,5 +1,10 @@
 package gofpdf
 
+import (
+	"bytes"
+	"encoding/gob"
+)
+
 /*
  * Copyright (c) 2015 Kurt Jung (Gmail: kurt.w.jung),
  *   Marcus Downing, Jan Slabon (Setasign)
@@ -80,6 +85,60 @@ func (t *FpdfTpl) Templates() []Template {
 	return t.templates
 }
 
+func (t *FpdfTpl) GobEncode() ([]byte, error) {
+	w := new(bytes.Buffer)
+	encoder := gob.NewEncoder(w)
+
+	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)
+	}
+	if err == nil {
+		err = encoder.Encode(t.images)
+	}
+	if err == nil {
+		err = encoder.Encode(t.templates)
+	}
+
+	return w.Bytes(), err
+}
+
+func (t *FpdfTpl) GobDecode(buf []byte) error {
+	r := bytes.NewBuffer(buf)
+	decoder := gob.NewDecoder(r)
+
+	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)
+	}
+	if err == nil {
+		err = decoder.Decode(&t.images)
+	}
+	if err == nil {
+		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]
+		}
+	}
+
+	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.
-- 
cgit v1.2.1-24-ge1ad


From 6993fe6ea4223dca30d0cae9fa0bd9a3cdfdb12d Mon Sep 17 00:00:00 2001
From: Paul Montag <pmontag@iseeme.com>
Date: Mon, 5 Nov 2018 15:50:58 -0600
Subject: fixed pointer values when mutltiple templates are used

---
 template_impl.go | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/template_impl.go b/template_impl.go
index 9e5d496..b1b2382 100644
--- a/template_impl.go
+++ b/template_impl.go
@@ -3,6 +3,7 @@ package gofpdf
 import (
 	"bytes"
 	"encoding/gob"
+	"reflect"
 )
 
 /*
@@ -136,9 +137,26 @@ func (t *FpdfTpl) GobDecode(buf []byte) error {
 		}
 	}
 
+	t.relinkPointers(t.images)
+
 	return err
 }
 
+func (t *FpdfTpl) relinkPointers(images map[string]*ImageInfoType) {
+	for gKey, _ := range images {
+		for key, _ := range t.images {
+			if reflect.DeepEqual(t.images[key], images[gKey]) {
+				t.images[key] = images[gKey]
+			}
+		}
+	}
+
+	for x := 0; x < len(t.templates); x++ {
+		innerT := t.templates[x].(*FpdfTpl)
+		innerT.relinkPointers(t.images)
+	}
+}
+
 // 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.
-- 
cgit v1.2.1-24-ge1ad


From a90e8ab8a5ab8b8bb484c51df7c29e721f31e184 Mon Sep 17 00:00:00 2001
From: Paul Montag <pmontag@iseeme.com>
Date: Wed, 7 Nov 2018 08:03:04 -0600
Subject: Changed the byte encoding so we are no longer saving redundant data
 from pointers

---
 template_impl.go | 119 ++++++++++++++++++++++++++++++++++++++-----------------
 1 file changed, 83 insertions(+), 36 deletions(-)

diff --git a/template_impl.go b/template_impl.go
index b1b2382..174e893 100644
--- a/template_impl.go
+++ b/template_impl.go
@@ -3,7 +3,7 @@ package gofpdf
 import (
 	"bytes"
 	"encoding/gob"
-	"reflect"
+	"fmt"
 )
 
 /*
@@ -86,25 +86,60 @@ func (t *FpdfTpl) Templates() []Template {
 	return t.templates
 }
 
+// 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.id)
+	err := encoder.Encode(t.templates)
+	childrenImgs := t.childrenImages()
+
 	if err == nil {
-		err = encoder.Encode(t.corner)
+		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(nil)
+		} else {
+			err = encoder.Encode(img)
+		}
 	}
 	if err == nil {
-		err = encoder.Encode(t.size)
+		err = encoder.Encode(t.id)
 	}
 	if err == nil {
-		err = encoder.Encode(t.bytes)
+		err = encoder.Encode(t.corner)
 	}
 	if err == nil {
-		err = encoder.Encode(t.images)
+		err = encoder.Encode(t.size)
 	}
 	if err == nil {
-		err = encoder.Encode(t.templates)
+		err = encoder.Encode(t.bytes)
 	}
 
 	return w.Bytes(), err
@@ -114,49 +149,61 @@ func (t *FpdfTpl) GobDecode(buf []byte) error {
 	r := bytes.NewBuffer(buf)
 	decoder := gob.NewDecoder(r)
 
-	err := decoder.Decode(&t.id)
+	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(&t.corner)
+		err = decoder.Decode(&numImgs)
+	}
+	t.images = make(map[string]*ImageInfoType)
+	childrenImgs := t.childrenImages()
+
+	for x := 0; x < numImgs; x++ {
+		var key string
+		var img *ImageInfoType
+
+		if err == nil {
+			err = decoder.Decode(&key)
+		}
+
+		if err == nil {
+			err = decoder.Decode(&img)
+		}
+
+		if err == nil {
+			if img != nil {
+				t.images[key] = img
+			} else {
+				if _, ok := childrenImgs[key]; !ok {
+					err = fmt.Errorf("Encoded template is corrupt, could not find image %s", key)
+				} else {
+					t.images[key] = childrenImgs[key]
+				}
+			}
+		}
 	}
 	if err == nil {
-		err = decoder.Decode(&t.size)
+		err = decoder.Decode(&t.id)
 	}
 	if err == nil {
-		err = decoder.Decode(&t.bytes)
+		err = decoder.Decode(&t.corner)
 	}
 	if err == nil {
-		err = decoder.Decode(&t.images)
+		err = decoder.Decode(&t.size)
 	}
 	if err == nil {
-		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]
-		}
+		err = decoder.Decode(&t.bytes)
 	}
 
-	t.relinkPointers(t.images)
-
 	return err
 }
 
-func (t *FpdfTpl) relinkPointers(images map[string]*ImageInfoType) {
-	for gKey, _ := range images {
-		for key, _ := range t.images {
-			if reflect.DeepEqual(t.images[key], images[gKey]) {
-				t.images[key] = images[gKey]
-			}
-		}
-	}
-
-	for x := 0; x < len(t.templates); x++ {
-		innerT := t.templates[x].(*FpdfTpl)
-		innerT.relinkPointers(t.images)
-	}
-}
-
 // 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.
-- 
cgit v1.2.1-24-ge1ad


From bc10d22b451bd5ecfdc2d06dc12c1c7d94adb2d2 Mon Sep 17 00:00:00 2001
From: Paul Montag <pmontag@iseeme.com>
Date: Wed, 7 Nov 2018 08:21:00 -0600
Subject: Fixed nil encoding

---
 template_impl.go | 24 +++++++++++++++++-------
 1 file changed, 17 insertions(+), 7 deletions(-)

diff --git a/template_impl.go b/template_impl.go
index 174e893..001b2d9 100644
--- a/template_impl.go
+++ b/template_impl.go
@@ -124,9 +124,12 @@ func (t *FpdfTpl) GobEncode() ([]byte, error) {
 		}
 
 		if _, ok := childrenImgs[key]; ok {
-			err = encoder.Encode(nil)
+			err = encoder.Encode("p")
 		} else {
-			err = encoder.Encode(img)
+			err = encoder.Encode("o")
+			if err == nil {
+				err = encoder.Encode(img)
+			}
 		}
 	}
 	if err == nil {
@@ -161,30 +164,37 @@ func (t *FpdfTpl) GobDecode(buf []byte) error {
 	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 img *ImageInfoType
+		var tpe string
 
 		if err == nil {
 			err = decoder.Decode(&key)
 		}
 
 		if err == nil {
-			err = decoder.Decode(&img)
+			err = decoder.Decode(&tpe)
 		}
 
 		if err == nil {
-			if img != nil {
-				t.images[key] = img
-			} else {
+			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
+				}
 			}
 		}
 	}
-- 
cgit v1.2.1-24-ge1ad


From 01381ea7603b12304064fcd01a49b1cc4434b4ca Mon Sep 17 00:00:00 2001
From: Paul Montag <pmontag@iseeme.com>
Date: Wed, 7 Nov 2018 08:51:37 -0600
Subject: Created helper functions for serialiation

---
 fpdf_test.go     | 16 +++-------------
 template.go      |  1 +
 template_impl.go | 17 +++++++++++++++++
 3 files changed, 21 insertions(+), 13 deletions(-)

diff --git a/fpdf_test.go b/fpdf_test.go
index e212d95..19bc533 100644
--- a/fpdf_test.go
+++ b/fpdf_test.go
@@ -19,7 +19,6 @@ package gofpdf_test
 import (
 	"bufio"
 	"bytes"
-	"encoding/gob"
 	"fmt"
 	"io"
 	"io/ioutil"
@@ -1951,18 +1950,9 @@ func ExampleFpdf_CreateTemplate() {
 	pdf.SetLineWidth(2.5)
 	pdf.SetFont("Arial", "B", 16)
 
-	template3 := new(gofpdf.FpdfTpl)
-	b := new(bytes.Buffer)
-	enc := gob.NewEncoder(b)
-
-	if err := enc.Encode(template); err != nil {
-		pdf.SetError(err)
-	}
-
-	dec := gob.NewDecoder(b)
-	if err := dec.Decode(template3); err != nil {
-		pdf.SetError(err)
-	}
+	// serialize and deserialize template
+	b, _ := template2.Serialize()
+	template3, _ := gofpdf.DeserializeTemplate(b)
 
 	pdf.AddPage()
 	pdf.UseTemplate(template3)
diff --git a/template.go b/template.go
index 2b886ed..9abdf62 100644
--- a/template.go
+++ b/template.go
@@ -108,6 +108,7 @@ type Template interface {
 	Bytes() []byte
 	Images() map[string]*ImageInfoType
 	Templates() []Template
+	Serialize() ([]byte, error)
 	gob.GobDecoder
 	gob.GobEncoder
 }
diff --git a/template_impl.go b/template_impl.go
index 001b2d9..9c690c1 100644
--- a/template_impl.go
+++ b/template_impl.go
@@ -86,6 +86,23 @@ 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
-- 
cgit v1.2.1-24-ge1ad


From 193187d077554b92944a4757e202d1300e1ed1fb Mon Sep 17 00:00:00 2001
From: Kurt <kurt.w.jung@gmail.com>
Date: Sat, 10 Nov 2018 12:06:51 -0500
Subject: Added some comments to new encoding/decoding methods

---
 README.md        |   4 ++-
 def.go           | 103 ++++++++++---------------------------------------------
 doc.go           |   5 ++-
 fpdf_test.go     |   2 +-
 template_impl.go |   8 +++--
 5 files changed, 33 insertions(+), 89 deletions(-)

diff --git a/README.md b/README.md
index 953857b..2a8d606 100644
--- a/README.md
+++ b/README.md
@@ -221,7 +221,9 @@ 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.
+which the internal catalogs were not sorted stably. d1ngd0 added encoding and
+decoding functionality for templates, including images that are embedded in
+templates; this allows templates to be stored independently of gofpdf.
 
 ## Roadmap
 
diff --git a/def.go b/def.go
index 3c5fa9d..605cdbc 100644
--- a/def.go
+++ b/def.go
@@ -158,7 +158,9 @@ func (p PointType) XY() (float64, float64) {
 	return p.X, p.Y
 }
 
-// ImageInfoType contains size, color and other information about an image
+// ImageInfoType contains size, color and other information about an image.
+// Changes to this structure should be reflected in its GobEncode and GobDecode
+// methods.
 type ImageInfoType struct {
 	data  []byte
 	smask []byte
@@ -176,99 +178,32 @@ type ImageInfoType struct {
 	dpi   float64
 }
 
-func (info *ImageInfoType) GobEncode() ([]byte, error) {
+// GobEncode encodes the receiving image to a byte slice.
+func (info *ImageInfoType) GobEncode() (buf []byte, err error) {
+	fields := []interface{}{info.data, info.smask, info.i, info.n, info.w, info.h, info.cs,
+		info.pal, info.bpc, info.f, info.dp, info.trns, info.scale, info.dpi}
 	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)
+	for j := 0; j < len(fields) && err == nil; j++ {
+		err = encoder.Encode(fields[j])
 	}
 	if err == nil {
-		err = encoder.Encode(info.trns)
+		buf = w.Bytes()
 	}
-	if err == nil {
-		err = encoder.Encode(info.scale)
-	}
-	if err == nil {
-		err = encoder.Encode(info.dpi)
-	}
-
-	return w.Bytes(), err
+	return
 }
 
-func (info *ImageInfoType) GobDecode(buf []byte) error {
+// GobDecode decodes the specified byte buffer (generated by GobEncode) into
+// the receiving image.
+func (info *ImageInfoType) GobDecode(buf []byte) (err error) {
+	fields := []interface{}{&info.data, &info.smask, &info.i, &info.n, &info.w, &info.h,
+		&info.cs, &info.pal, &info.bpc, &info.f, &info.dp, &info.trns, &info.scale, &info.dpi}
 	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)
+	for j := 0; j < len(fields) && err == nil; j++ {
+		err = decoder.Decode(fields[j])
 	}
-	return err
+	return
 }
 
 // PointConvert returns the value of pt, expressed in points (1/72 inch), as a
diff --git a/doc.go b/doc.go
index 02733ba..534b1d7 100644
--- a/doc.go
+++ b/doc.go
@@ -235,7 +235,10 @@ 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.
+which the internal catalogs were not sorted stably. d1ngd0 added encoding and
+decoding functionality for templates, including images that are embedded in
+templates; this allows templates to be stored independently of gofpdf.
+
 
 Roadmap
 
diff --git a/fpdf_test.go b/fpdf_test.go
index 19bc533..68a26ad 100644
--- a/fpdf_test.go
+++ b/fpdf_test.go
@@ -1957,12 +1957,12 @@ func ExampleFpdf_CreateTemplate() {
 	pdf.AddPage()
 	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")
 
 	pdf.AddPage()
 	pdf.UseTemplate(template2)
+	pdf.UseTemplateScaled(template3, gofpdf.PointType{X: 0, Y: 30}, tplSize.ScaleBy(1.4))
 	pdf.Line(60, 210, 80, 210)
 	pdf.Text(40, 200, "Template example page 2")
 
diff --git a/template_impl.go b/template_impl.go
index 1a91112..c34e688 100644
--- a/template_impl.go
+++ b/template_impl.go
@@ -82,7 +82,7 @@ func (t *FpdfTpl) Templates() []Template {
 	return t.templates
 }
 
-// Turn a template into a byte string for later deserialization
+// Serialize turns a template into a byte string for later deserialization
 func (t *FpdfTpl) Serialize() ([]byte, error) {
 	b := new(bytes.Buffer)
 	enc := gob.NewEncoder(b)
@@ -91,7 +91,8 @@ func (t *FpdfTpl) Serialize() ([]byte, error) {
 	return b.Bytes(), err
 }
 
-// Create a template from a previously serialized template
+// DeserializeTemplate creaties a template from a previously serialized
+// template
 func DeserializeTemplate(b []byte) (Template, error) {
 	tpl := new(FpdfTpl)
 	dec := gob.NewDecoder(bytes.NewBuffer(b))
@@ -116,6 +117,8 @@ func (t *FpdfTpl) childrenImages() map[string]*ImageInfoType {
 	return childrenImgs
 }
 
+// GobEncode encodes the receiving template into a byte buffer. Use GobDecode
+// to decode the byte buffer back to a template.
 func (t *FpdfTpl) GobEncode() ([]byte, error) {
 	w := new(bytes.Buffer)
 	encoder := gob.NewEncoder(w)
@@ -161,6 +164,7 @@ func (t *FpdfTpl) GobEncode() ([]byte, error) {
 	return w.Bytes(), err
 }
 
+// GobDecode decodes the specified byte buffer into the receiving template.
 func (t *FpdfTpl) GobDecode(buf []byte) error {
 	r := bytes.NewBuffer(buf)
 	decoder := gob.NewDecoder(r)
-- 
cgit v1.2.1-24-ge1ad