Kurt Jungs Auslieferungszustand
This commit is contained in:
303
template_impl.go
Normal file
303
template_impl.go
Normal file
@@ -0,0 +1,303 @@
|
||||
package gofpdf
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/sha1"
|
||||
"encoding/gob"
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
/*
|
||||
* Copyright (c) 2015 Kurt Jung (Gmail: kurt.w.jung),
|
||||
* Marcus Downing, Jan Slabon (Setasign)
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
// newTpl creates a template, copying graphics settings from a template if one is given
|
||||
func newTpl(corner PointType, size SizeType, orientationStr, unitStr, fontDirStr string, fn func(*Tpl), copyFrom *Fpdf) Template {
|
||||
sizeStr := ""
|
||||
|
||||
fpdf := fpdfNew(orientationStr, unitStr, sizeStr, fontDirStr, size)
|
||||
tpl := Tpl{*fpdf}
|
||||
if copyFrom != nil {
|
||||
tpl.loadParamsFromFpdf(copyFrom)
|
||||
}
|
||||
tpl.Fpdf.AddPage()
|
||||
fn(&tpl)
|
||||
|
||||
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])
|
||||
}
|
||||
images := tpl.Fpdf.images
|
||||
|
||||
template := FpdfTpl{corner, size, bytes, images, templates, tpl.Fpdf.page}
|
||||
return &template
|
||||
}
|
||||
|
||||
// FpdfTpl is a concrete implementation of the Template interface.
|
||||
type FpdfTpl struct {
|
||||
corner PointType
|
||||
size SizeType
|
||||
bytes [][]byte
|
||||
images map[string]*ImageInfoType
|
||||
templates []Template
|
||||
page int
|
||||
}
|
||||
|
||||
// ID returns the global template identifier
|
||||
func (t *FpdfTpl) ID() string {
|
||||
return fmt.Sprintf("%x", sha1.Sum(t.Bytes()))
|
||||
}
|
||||
|
||||
// Size gives the bounding dimensions of this template
|
||||
func (t *FpdfTpl) Size() (corner PointType, size SizeType) {
|
||||
return t.corner, t.size
|
||||
}
|
||||
|
||||
// Bytes returns the actual template data, not including resources
|
||||
func (t *FpdfTpl) Bytes() []byte {
|
||||
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.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
|
||||
func (t *FpdfTpl) Images() map[string]*ImageInfoType {
|
||||
return t.images
|
||||
}
|
||||
|
||||
// Templates returns a list of templates used in this template
|
||||
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)
|
||||
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
|
||||
}
|
||||
|
||||
// childrenImages 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%s-%s", t.templates[x].ID(), key)
|
||||
childrenImgs[name] = val
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
childrensTemplates := t.childrensTemplates()
|
||||
firstClassTemplates := make([]Template, 0)
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
firstClassTemplates = append(firstClassTemplates, t.templates[x])
|
||||
}
|
||||
err := encoder.Encode(firstClassTemplates)
|
||||
|
||||
childrenImgs := t.childrenImages()
|
||||
firstClassImgs := make(map[string]*ImageInfoType)
|
||||
|
||||
for key, img := range t.images {
|
||||
if _, ok := childrenImgs[key]; !ok {
|
||||
firstClassImgs[key] = img
|
||||
}
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
err = encoder.Encode(firstClassImgs)
|
||||
}
|
||||
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.page)
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
firstClassTemplates := make([]*FpdfTpl, 0)
|
||||
err := decoder.Decode(&firstClassTemplates)
|
||||
t.templates = make([]Template, len(firstClassTemplates))
|
||||
|
||||
for x := 0; x < len(t.templates); x++ {
|
||||
t.templates[x] = Template(firstClassTemplates[x])
|
||||
}
|
||||
|
||||
firstClassImages := t.childrenImages()
|
||||
|
||||
t.templates = append(t.childrensTemplates(), t.templates...)
|
||||
|
||||
t.images = make(map[string]*ImageInfoType)
|
||||
if err == nil {
|
||||
err = decoder.Decode(&t.images)
|
||||
}
|
||||
|
||||
for k, v := range firstClassImages {
|
||||
t.images[k] = v
|
||||
}
|
||||
|
||||
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.page)
|
||||
}
|
||||
|
||||
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.
|
||||
type Tpl struct {
|
||||
Fpdf
|
||||
}
|
||||
|
||||
func (t *Tpl) loadParamsFromFpdf(f *Fpdf) {
|
||||
t.Fpdf.compress = false
|
||||
|
||||
t.Fpdf.k = f.k
|
||||
t.Fpdf.x = f.x
|
||||
t.Fpdf.y = f.y
|
||||
t.Fpdf.lineWidth = f.lineWidth
|
||||
t.Fpdf.capStyle = f.capStyle
|
||||
t.Fpdf.joinStyle = f.joinStyle
|
||||
|
||||
t.Fpdf.color.draw = f.color.draw
|
||||
t.Fpdf.color.fill = f.color.fill
|
||||
t.Fpdf.color.text = f.color.text
|
||||
|
||||
t.Fpdf.fonts = f.fonts
|
||||
t.Fpdf.currentFont = f.currentFont
|
||||
t.Fpdf.fontFamily = f.fontFamily
|
||||
t.Fpdf.fontSize = f.fontSize
|
||||
t.Fpdf.fontSizePt = f.fontSizePt
|
||||
t.Fpdf.fontStyle = f.fontStyle
|
||||
t.Fpdf.ws = f.ws
|
||||
|
||||
for key, value := range f.images {
|
||||
t.Fpdf.images[key] = value
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user