github.com/phpdave11/gofpdf@v1.4.2/template_impl.go (about)

     1  package gofpdf
     2  
     3  import (
     4  	"bytes"
     5  	"crypto/sha1"
     6  	"encoding/gob"
     7  	"errors"
     8  	"fmt"
     9  )
    10  
    11  /*
    12   * Copyright (c) 2015 Kurt Jung (Gmail: kurt.w.jung),
    13   *   Marcus Downing, Jan Slabon (Setasign)
    14   *
    15   * Permission to use, copy, modify, and distribute this software for any
    16   * purpose with or without fee is hereby granted, provided that the above
    17   * copyright notice and this permission notice appear in all copies.
    18   *
    19   * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
    20   * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    21   * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    22   * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    23   * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    24   * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    25   * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    26   */
    27  
    28  // newTpl creates a template, copying graphics settings from a template if one is given
    29  func newTpl(corner PointType, size SizeType, orientationStr, unitStr, fontDirStr string, fn func(*Tpl), copyFrom *Fpdf) Template {
    30  	sizeStr := ""
    31  
    32  	fpdf := fpdfNew(orientationStr, unitStr, sizeStr, fontDirStr, size)
    33  	tpl := Tpl{*fpdf}
    34  	if copyFrom != nil {
    35  		tpl.loadParamsFromFpdf(copyFrom)
    36  	}
    37  	tpl.Fpdf.AddPage()
    38  	fn(&tpl)
    39  
    40  	bytes := make([][]byte, len(tpl.Fpdf.pages))
    41  	// skip the first page as it will always be empty
    42  	for x := 1; x < len(bytes); x++ {
    43  		bytes[x] = tpl.Fpdf.pages[x].Bytes()
    44  	}
    45  
    46  	templates := make([]Template, 0, len(tpl.Fpdf.templates))
    47  	for _, key := range templateKeyList(tpl.Fpdf.templates, true) {
    48  		templates = append(templates, tpl.Fpdf.templates[key])
    49  	}
    50  	images := tpl.Fpdf.images
    51  
    52  	template := FpdfTpl{corner, size, bytes, images, templates, tpl.Fpdf.page}
    53  	return &template
    54  }
    55  
    56  // FpdfTpl is a concrete implementation of the Template interface.
    57  type FpdfTpl struct {
    58  	corner    PointType
    59  	size      SizeType
    60  	bytes     [][]byte
    61  	images    map[string]*ImageInfoType
    62  	templates []Template
    63  	page      int
    64  }
    65  
    66  // ID returns the global template identifier
    67  func (t *FpdfTpl) ID() string {
    68  	return fmt.Sprintf("%x", sha1.Sum(t.Bytes()))
    69  }
    70  
    71  // Size gives the bounding dimensions of this template
    72  func (t *FpdfTpl) Size() (corner PointType, size SizeType) {
    73  	return t.corner, t.size
    74  }
    75  
    76  // Bytes returns the actual template data, not including resources
    77  func (t *FpdfTpl) Bytes() []byte {
    78  	return t.bytes[t.page]
    79  }
    80  
    81  // FromPage creates a new template from a specific Page
    82  func (t *FpdfTpl) FromPage(page int) (Template, error) {
    83  	// pages start at 1
    84  	if page == 0 {
    85  		return nil, errors.New("Pages start at 1 No template will have a page 0")
    86  	}
    87  
    88  	if page > t.NumPages() {
    89  		return nil, fmt.Errorf("The template does not have a page %d", page)
    90  	}
    91  	// if it is already pointing to the correct page
    92  	// there is no need to create a new template
    93  	if t.page == page {
    94  		return t, nil
    95  	}
    96  
    97  	t2 := *t
    98  	t2.page = page
    99  	return &t2, nil
   100  }
   101  
   102  // FromPages creates a template slice with all the pages within a template.
   103  func (t *FpdfTpl) FromPages() []Template {
   104  	p := make([]Template, t.NumPages())
   105  	for x := 1; x <= t.NumPages(); x++ {
   106  		// the only error is when accessing a
   107  		// non existing template... that can't happen
   108  		// here
   109  		p[x-1], _ = t.FromPage(x)
   110  	}
   111  
   112  	return p
   113  }
   114  
   115  // Images returns a list of the images used in this template
   116  func (t *FpdfTpl) Images() map[string]*ImageInfoType {
   117  	return t.images
   118  }
   119  
   120  // Templates returns a list of templates used in this template
   121  func (t *FpdfTpl) Templates() []Template {
   122  	return t.templates
   123  }
   124  
   125  // NumPages returns the number of available pages within the template. Look at FromPage and FromPages on access to that content.
   126  func (t *FpdfTpl) NumPages() int {
   127  	// the first page is empty to
   128  	// make the pages begin at one
   129  	return len(t.bytes) - 1
   130  }
   131  
   132  // Serialize turns a template into a byte string for later deserialization
   133  func (t *FpdfTpl) Serialize() ([]byte, error) {
   134  	b := new(bytes.Buffer)
   135  	enc := gob.NewEncoder(b)
   136  	err := enc.Encode(t)
   137  
   138  	return b.Bytes(), err
   139  }
   140  
   141  // DeserializeTemplate creaties a template from a previously serialized
   142  // template
   143  func DeserializeTemplate(b []byte) (Template, error) {
   144  	tpl := new(FpdfTpl)
   145  	dec := gob.NewDecoder(bytes.NewBuffer(b))
   146  	err := dec.Decode(tpl)
   147  	return tpl, err
   148  }
   149  
   150  // childrenImages returns the next layer of children images, it doesn't dig into
   151  // children of children. Applies template namespace to keys to ensure
   152  // no collisions. See UseTemplateScaled
   153  func (t *FpdfTpl) childrenImages() map[string]*ImageInfoType {
   154  	childrenImgs := make(map[string]*ImageInfoType)
   155  
   156  	for x := 0; x < len(t.templates); x++ {
   157  		imgs := t.templates[x].Images()
   158  		for key, val := range imgs {
   159  			name := sprintf("t%s-%s", t.templates[x].ID(), key)
   160  			childrenImgs[name] = val
   161  		}
   162  	}
   163  
   164  	return childrenImgs
   165  }
   166  
   167  // childrensTemplates returns the next layer of children templates, it doesn't dig into
   168  // children of children.
   169  func (t *FpdfTpl) childrensTemplates() []Template {
   170  	childrenTmpls := make([]Template, 0)
   171  
   172  	for x := 0; x < len(t.templates); x++ {
   173  		tmpls := t.templates[x].Templates()
   174  		childrenTmpls = append(childrenTmpls, tmpls...)
   175  	}
   176  
   177  	return childrenTmpls
   178  }
   179  
   180  // GobEncode encodes the receiving template into a byte buffer. Use GobDecode
   181  // to decode the byte buffer back to a template.
   182  func (t *FpdfTpl) GobEncode() ([]byte, error) {
   183  	w := new(bytes.Buffer)
   184  	encoder := gob.NewEncoder(w)
   185  
   186  	childrensTemplates := t.childrensTemplates()
   187  	firstClassTemplates := make([]Template, 0)
   188  
   189  found_continue:
   190  	for x := 0; x < len(t.templates); x++ {
   191  		for y := 0; y < len(childrensTemplates); y++ {
   192  			if childrensTemplates[y].ID() == t.templates[x].ID() {
   193  				continue found_continue
   194  			}
   195  		}
   196  
   197  		firstClassTemplates = append(firstClassTemplates, t.templates[x])
   198  	}
   199  	err := encoder.Encode(firstClassTemplates)
   200  
   201  	childrenImgs := t.childrenImages()
   202  	firstClassImgs := make(map[string]*ImageInfoType)
   203  
   204  	for key, img := range t.images {
   205  		if _, ok := childrenImgs[key]; !ok {
   206  			firstClassImgs[key] = img
   207  		}
   208  	}
   209  
   210  	if err == nil {
   211  		err = encoder.Encode(firstClassImgs)
   212  	}
   213  	if err == nil {
   214  		err = encoder.Encode(t.corner)
   215  	}
   216  	if err == nil {
   217  		err = encoder.Encode(t.size)
   218  	}
   219  	if err == nil {
   220  		err = encoder.Encode(t.bytes)
   221  	}
   222  	if err == nil {
   223  		err = encoder.Encode(t.page)
   224  	}
   225  
   226  	return w.Bytes(), err
   227  }
   228  
   229  // GobDecode decodes the specified byte buffer into the receiving template.
   230  func (t *FpdfTpl) GobDecode(buf []byte) error {
   231  	r := bytes.NewBuffer(buf)
   232  	decoder := gob.NewDecoder(r)
   233  
   234  	firstClassTemplates := make([]*FpdfTpl, 0)
   235  	err := decoder.Decode(&firstClassTemplates)
   236  	t.templates = make([]Template, len(firstClassTemplates))
   237  
   238  	for x := 0; x < len(t.templates); x++ {
   239  		t.templates[x] = Template(firstClassTemplates[x])
   240  	}
   241  
   242  	firstClassImages := t.childrenImages()
   243  
   244  	t.templates = append(t.childrensTemplates(), t.templates...)
   245  
   246  	t.images = make(map[string]*ImageInfoType)
   247  	if err == nil {
   248  		err = decoder.Decode(&t.images)
   249  	}
   250  
   251  	for k, v := range firstClassImages {
   252  		t.images[k] = v
   253  	}
   254  
   255  	if err == nil {
   256  		err = decoder.Decode(&t.corner)
   257  	}
   258  	if err == nil {
   259  		err = decoder.Decode(&t.size)
   260  	}
   261  	if err == nil {
   262  		err = decoder.Decode(&t.bytes)
   263  	}
   264  	if err == nil {
   265  		err = decoder.Decode(&t.page)
   266  	}
   267  
   268  	return err
   269  }
   270  
   271  // Tpl is an Fpdf used for writing a template. It has most of the facilities of
   272  // an Fpdf, but cannot add more pages. Tpl is used directly only during the
   273  // limited time a template is writable.
   274  type Tpl struct {
   275  	Fpdf
   276  }
   277  
   278  func (t *Tpl) loadParamsFromFpdf(f *Fpdf) {
   279  	t.Fpdf.compress = false
   280  
   281  	t.Fpdf.k = f.k
   282  	t.Fpdf.x = f.x
   283  	t.Fpdf.y = f.y
   284  	t.Fpdf.lineWidth = f.lineWidth
   285  	t.Fpdf.capStyle = f.capStyle
   286  	t.Fpdf.joinStyle = f.joinStyle
   287  
   288  	t.Fpdf.color.draw = f.color.draw
   289  	t.Fpdf.color.fill = f.color.fill
   290  	t.Fpdf.color.text = f.color.text
   291  
   292  	t.Fpdf.fonts = f.fonts
   293  	t.Fpdf.currentFont = f.currentFont
   294  	t.Fpdf.fontFamily = f.fontFamily
   295  	t.Fpdf.fontSize = f.fontSize
   296  	t.Fpdf.fontSizePt = f.fontSizePt
   297  	t.Fpdf.fontStyle = f.fontStyle
   298  	t.Fpdf.ws = f.ws
   299  
   300  	for key, value := range f.images {
   301  		t.Fpdf.images[key] = value
   302  	}
   303  }