From c27eea9fd19b65f75c4326c12446e829b39ab66d Mon Sep 17 00:00:00 2001 From: Paul Montag Date: Fri, 14 Dec 2018 11:34:00 -0600 Subject: Refactored Encode and Decode functions, Fixed Template ID Conflicts - Updated Encode and Decode to ensure templates and images are pointers to the original objects - Refactored so encoding no longer has to create p and o labels for images - removed id from template and generate it using Bytes instead. --- def.go | 4 +- fpdf.go | 10 ++--- template.go | 35 +++++----------- template_impl.go | 120 +++++++++++++++++++++++-------------------------------- 4 files changed, 67 insertions(+), 102 deletions(-) diff --git a/def.go b/def.go index b1dbc8c..3c4d902 100644 --- a/def.go +++ b/def.go @@ -486,8 +486,8 @@ type Fpdf struct { page int // current page number 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 + templates map[string]Template // templates used in this document + templateObjects map[string]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 diff --git a/fpdf.go b/fpdf.go index 99c087e..46fe007 100644 --- a/fpdf.go +++ b/fpdf.go @@ -83,8 +83,8 @@ func fpdfNew(orientationStr, unitStr, sizeStr, fontDirStr string, size SizeType) f.fonts = make(map[string]fontDefType) f.fontFiles = make(map[string]fontFileType) f.diffs = make([]string, 0, 8) - f.templates = make(map[int64]Template) - f.templateObjects = make(map[int64]int) + f.templates = make(map[string]Template) + f.templateObjects = make(map[string]int) f.images = make(map[string]*ImageInfoType) f.pageLinks = make([][]linkType, 0, 8) f.pageLinks = append(f.pageLinks, make([]linkType, 0, 0)) // pageLinks[0] is unused (1-based) @@ -3559,8 +3559,8 @@ func (f *Fpdf) putxobjectdict() { } } { - var keyList []int64 - var key int64 + var keyList []string + var key string var tpl Template keyList = templateKeyList(f.templates, f.catalogSort) for _, key = range keyList { @@ -3568,7 +3568,7 @@ func (f *Fpdf) putxobjectdict() { // for _, tpl := range f.templates { id := tpl.ID() if objID, ok := f.templateObjects[id]; ok { - f.outf("/TPL%d %d 0 R", id, objID) + f.outf("/TPL%s %d 0 R", id, objID) } } } diff --git a/template.go b/template.go index 1bcd25d..fc6e29c 100644 --- a/template.go +++ b/template.go @@ -85,7 +85,7 @@ func (f *Fpdf) UseTemplateScaled(t Template, corner PointType, size SizeType) { f.templates[tt.ID()] = tt } for name, ti := range t.Images() { - name = sprintf("t%d-%s", t.ID(), name) + name = sprintf("t%s-%s", t.ID(), name) f.images[name] = ti } @@ -97,29 +97,12 @@ func (f *Fpdf) UseTemplateScaled(t Template, corner PointType, size SizeType) { ty := (f.curPageSize.Ht - corner.Y - size.Ht) * f.k f.outf("q %.4f 0 0 %.4f %.4f %.4f cm", scaleX, scaleY, tx, ty) // Translate - f.outf("/TPL%d Do Q", t.ID()) -} - -var nextTemplateIDChannel = func() chan int64 { - ch := make(chan int64) - go func() { - var nextID int64 = 1 - for { - ch <- nextID - nextID++ - } - }() - return ch -}() - -// GenerateTemplateID gives the next template ID. These numbers are global so that they can never clash. -func GenerateTemplateID() int64 { - return <-nextTemplateIDChannel + f.outf("/TPL%s Do Q", t.ID()) } // Template is an object that can be written to, then used and re-used any number of times within a document. type Template interface { - ID() int64 + ID() string Size() (PointType, SizeType) Bytes() []byte Images() map[string]*ImageInfoType @@ -201,7 +184,7 @@ func (f *Fpdf) putTemplates() { for _, tt := range tTemplates { id := tt.ID() if objID, ok := f.templateObjects[id]; ok { - f.outf("/TPL%d %d 0 R", id, objID) + f.outf("/TPL%s %d 0 R", id, objID) } } f.out(">>") @@ -221,8 +204,8 @@ func (f *Fpdf) putTemplates() { } } -func templateKeyList(mp map[int64]Template, sort bool) (keyList []int64) { - var key int64 +func templateKeyList(mp map[string]Template, sort bool) (keyList []string) { + var key string for key = range mp { keyList = append(keyList, key) } @@ -239,12 +222,12 @@ func templateKeyList(mp map[int64]Template, sort bool) (keyList []int64) { } // sortTemplates puts templates in a suitable order based on dependices -func sortTemplates(templates map[int64]Template, catalogSort bool) []Template { +func sortTemplates(templates map[string]Template, catalogSort bool) []Template { chain := make([]Template, 0, len(templates)*2) // build a full set of dependency chains - var keyList []int64 - var key int64 + var keyList []string + var key string var t Template keyList = templateKeyList(templates, catalogSort) for _, key = range keyList { diff --git a/template_impl.go b/template_impl.go index f7eeee1..c5d7be8 100644 --- a/template_impl.go +++ b/template_impl.go @@ -2,6 +2,7 @@ package gofpdf import ( "bytes" + "crypto/sha1" "encoding/gob" "errors" "fmt" @@ -48,14 +49,12 @@ func newTpl(corner PointType, size SizeType, orientationStr, unitStr, fontDirStr } images := tpl.Fpdf.images - id := GenerateTemplateID() - template := FpdfTpl{id, corner, size, bytes, images, templates, tpl.Fpdf.page} + template := FpdfTpl{corner, size, bytes, images, templates, tpl.Fpdf.page} return &template } // FpdfTpl is a concrete implementation of the Template interface. type FpdfTpl struct { - id int64 corner PointType size SizeType bytes [][]byte @@ -65,8 +64,8 @@ type FpdfTpl struct { } // ID returns the global template identifier -func (t *FpdfTpl) ID() int64 { - return t.id +func (t *FpdfTpl) ID() string { + return fmt.Sprintf("%x", sha1.Sum(t.Bytes())) } // Size gives the bounding dimensions of this template @@ -96,7 +95,6 @@ func (t *FpdfTpl) FromPage(page int) (Template, error) { } t2 := *t - t2.id = GenerateTemplateID() t2.page = page return &t2, nil } @@ -158,7 +156,7 @@ func (t *FpdfTpl) childrenImages() 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) + name := sprintf("t%s-%s", t.templates[x].ID(), key) childrenImgs[name] = val } } @@ -166,39 +164,51 @@ func (t *FpdfTpl) childrenImages() map[string]*ImageInfoType { return childrenImgs } +// childrensTemplates returns the next layer of children templates, it doesn't dig into +// children of children. +func (t *FpdfTpl) childrensTemplates() []Template { + childrenTmpls := make([]Template, 0) + + for x := 0; x < len(t.templates); x++ { + tmpls := t.templates[x].Templates() + childrenTmpls = append(childrenTmpls, tmpls...) + } + + return childrenTmpls +} + // 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() + childrensTemplates := t.childrensTemplates() + firstClassTemplates := make([]Template, 0) - if err == nil { - encoder.Encode(len(t.images)) - } +found_continue: + for x := 0; x < len(t.templates); x++ { + for y := 0; y < len(childrensTemplates); y++ { + if childrensTemplates[y].ID() == t.templates[x].ID() { + continue found_continue + } + } - 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) + firstClassTemplates = append(firstClassTemplates, t.templates[x]) + } + err := encoder.Encode(firstClassTemplates) - if err != nil { - break - } + childrenImgs := t.childrenImages() + firstClassImgs := make(map[string]*ImageInfoType) - if _, ok := childrenImgs[key]; ok { - err = encoder.Encode("p") - } else { - err = encoder.Encode("o") - if err == nil { - err = encoder.Encode(img) - } + for key, img := range t.images { + if _, ok := childrenImgs[key]; !ok { + firstClassImgs[key] = img } } + if err == nil { - err = encoder.Encode(t.id) + err = encoder.Encode(firstClassImgs) } if err == nil { err = encoder.Encode(t.corner) @@ -221,55 +231,27 @@ 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] - } + firstClassTemplates := make([]*FpdfTpl, 0) + err := decoder.Decode(&firstClassTemplates) + t.templates = make([]Template, len(firstClassTemplates)) - var numImgs int - if err == nil { - err = decoder.Decode(&numImgs) + for x := 0; x < len(t.templates); x++ { + t.templates[x] = Template(firstClassTemplates[x]) } - 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) - } + firstClassImages := t.childrenImages() - if err == nil { - err = decoder.Decode(&tpe) - } + t.templates = append(t.childrensTemplates(), t.templates...) - 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 - } - } - } - } + t.images = make(map[string]*ImageInfoType) if err == nil { - err = decoder.Decode(&t.id) + err = decoder.Decode(&t.images) + } + + for k, v := range firstClassImages { + t.images[k] = v } + if err == nil { err = decoder.Decode(&t.corner) } -- cgit v1.2.1-24-ge1ad