diff options
author | Kurt <kurt.w.jung@gmail.com> | 2018-11-10 12:07:08 -0500 |
---|---|---|
committer | Kurt <kurt.w.jung@gmail.com> | 2018-11-10 12:07:08 -0500 |
commit | 13c78403a35a19e3943791af9435411c401ab446 (patch) | |
tree | 0ce3865cbd2051a4a6d74e4273ccc3eb2dd7cd24 | |
parent | e200d3e7c7ef20b29a47b67e58b7561f4099e7ae (diff) | |
parent | 193187d077554b92944a4757e202d1300e1ed1fb (diff) |
Merge branch 'd1ngd0-ftr/gob'
-rw-r--r-- | README.md | 4 | ||||
-rw-r--r-- | def.go | 33 | ||||
-rw-r--r-- | doc.go | 5 | ||||
-rw-r--r-- | fpdf_test.go | 10 | ||||
-rw-r--r-- | template.go | 4 | ||||
-rw-r--r-- | template_impl.go | 155 |
6 files changed, 205 insertions, 6 deletions
@@ -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 @@ -18,6 +18,7 @@ package gofpdf import ( "bytes" + "encoding/gob" "io" "time" ) @@ -157,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 @@ -175,6 +178,34 @@ type ImageInfoType struct { dpi float64 } +// 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) + for j := 0; j < len(fields) && err == nil; j++ { + err = encoder.Encode(fields[j]) + } + if err == nil { + buf = w.Bytes() + } + return +} + +// 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) + for j := 0; j < len(fields) && err == nil; j++ { + err = decoder.Decode(fields[j]) + } + return +} + // 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 @@ -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 4774ec6..68a26ad 100644 --- a/fpdf_test.go +++ b/fpdf_test.go @@ -1950,15 +1950,19 @@ 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.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.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..c34e688 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,155 @@ func (t *FpdfTpl) Templates() []Template { return t.templates } +// 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) + err := enc.Encode(t) + + return b.Bytes(), err +} + +// DeserializeTemplate creaties 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 +} + +// 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) + + 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 +} + +// 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) + + 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. |