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 }