template_impl.go 7.8 KB

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