1 package gofpdf
2
3
19
20 import (
21 "encoding/gob"
22 "sort"
23 )
24
25
26 func (f *Fpdf) CreateTemplate(fn func(*Tpl)) Template {
27 return newTpl(PointType{0, 0}, f.curPageSize, f.defOrientation, f.unitStr, f.fontDirStr, fn, f)
28 }
29
30
31 func (f *Fpdf) CreateTemplateCustom(corner PointType, size SizeType, fn func(*Tpl)) Template {
32 return newTpl(corner, size, f.defOrientation, f.unitStr, f.fontDirStr, fn, f)
33 }
34
35
36
37
38
39
40
41
42 func CreateTemplate(corner PointType, size SizeType, unitStr, fontDirStr string, fn func(*Tpl)) Template {
43 orientationStr := "p"
44 if size.Wd > size.Ht {
45 orientationStr = "l"
46 }
47
48 return CreateTpl(corner, size, orientationStr, unitStr, fontDirStr, fn)
49 }
50
51
52 func CreateTpl(corner PointType, size SizeType, orientationStr, unitStr, fontDirStr string, fn func(*Tpl)) Template {
53 return newTpl(corner, size, orientationStr, unitStr, fontDirStr, fn, nil)
54 }
55
56
57
58 func (f *Fpdf) UseTemplate(t Template) {
59 if t == nil {
60 f.SetErrorf("template is nil")
61 return
62 }
63 corner, size := t.Size()
64 f.UseTemplateScaled(t, corner, size)
65 }
66
67
68
69 func (f *Fpdf) UseTemplateScaled(t Template, corner PointType, size SizeType) {
70 if t == nil {
71 f.SetErrorf("template is nil")
72 return
73 }
74
75
76 if f.page <= 0 {
77 f.SetErrorf("cannot use a template without first adding a page")
78 return
79 }
80
81
82
83 f.templates[t.ID()] = t
84 for _, tt := range t.Templates() {
85 f.templates[tt.ID()] = tt
86 }
87
88
89 existingImages := map[string]bool{}
90 for _, image := range f.images {
91 existingImages[image.i] = true
92 }
93
94
95 for name, ti := range t.Images() {
96 if _, found := existingImages[ti.i]; found {
97 continue
98 }
99 name = sprintf("t%s-%s", t.ID(), name)
100 f.images[name] = ti
101 }
102
103
104 _, templateSize := t.Size()
105 scaleX := size.Wd / templateSize.Wd
106 scaleY := size.Ht / templateSize.Ht
107 tx := corner.X * f.k
108 ty := (f.curPageSize.Ht - corner.Y - size.Ht) * f.k
109
110 f.outf("q %.4f 0 0 %.4f %.4f %.4f cm", scaleX, scaleY, tx, ty)
111 f.outf("/TPL%s Do Q", t.ID())
112 }
113
114
115 type Template interface {
116 ID() string
117 Size() (PointType, SizeType)
118 Bytes() []byte
119 Images() map[string]*ImageInfoType
120 Templates() []Template
121 NumPages() int
122 FromPage(int) (Template, error)
123 FromPages() []Template
124 Serialize() ([]byte, error)
125 gob.GobDecoder
126 gob.GobEncoder
127 }
128
129 func (f *Fpdf) templateFontCatalog() {
130 var keyList []string
131 var font fontDefType
132 var key string
133 f.out("/Font <<")
134 for key = range f.fonts {
135 keyList = append(keyList, key)
136 }
137 if f.catalogSort {
138 sort.Strings(keyList)
139 }
140 for _, key = range keyList {
141 font = f.fonts[key]
142 f.outf("/F%s %d 0 R", font.i, font.N)
143 }
144 f.out(">>")
145 }
146
147
148 func (f *Fpdf) putTemplates() {
149 filter := ""
150 if f.compress {
151 filter = "/Filter /FlateDecode "
152 }
153
154 templates := sortTemplates(f.templates, f.catalogSort)
155 var t Template
156 for _, t = range templates {
157 corner, size := t.Size()
158
159 f.newobj()
160 f.templateObjects[t.ID()] = f.n
161 f.outf("<<%s/Type /XObject", filter)
162 f.out("/Subtype /Form")
163 f.out("/Formtype 1")
164 f.outf("/BBox [%.2f %.2f %.2f %.2f]", corner.X*f.k, corner.Y*f.k, (corner.X+size.Wd)*f.k, (corner.Y+size.Ht)*f.k)
165 if corner.X != 0 || corner.Y != 0 {
166 f.outf("/Matrix [1 0 0 1 %.5f %.5f]", -corner.X*f.k*2, corner.Y*f.k*2)
167 }
168
169
170 f.out("/Resources ")
171 f.out("<</ProcSet [/PDF /Text /ImageB /ImageC /ImageI]")
172
173 f.templateFontCatalog()
174
175 tImages := t.Images()
176 tTemplates := t.Templates()
177 if len(tImages) > 0 || len(tTemplates) > 0 {
178 f.out("/XObject <<")
179 {
180 var key string
181 var keyList []string
182 var ti *ImageInfoType
183 for key = range tImages {
184 keyList = append(keyList, key)
185 }
186 if gl.catalogSort {
187 sort.Strings(keyList)
188 }
189 for _, key = range keyList {
190
191 ti = tImages[key]
192 f.outf("/I%s %d 0 R", ti.i, ti.n)
193 }
194 }
195 for _, tt := range tTemplates {
196 id := tt.ID()
197 if objID, ok := f.templateObjects[id]; ok {
198 f.outf("/TPL%s %d 0 R", id, objID)
199 }
200 }
201 f.out(">>")
202 }
203
204 f.out(">>")
205
206
207 buffer := t.Bytes()
208
209 if f.compress {
210 buffer = sliceCompress(buffer)
211 }
212 f.outf("/Length %d >>", len(buffer))
213 f.putstream(buffer)
214 f.out("endobj")
215 }
216 }
217
218 func templateKeyList(mp map[string]Template, sort bool) (keyList []string) {
219 var key string
220 for key = range mp {
221 keyList = append(keyList, key)
222 }
223 if sort {
224 gensort(len(keyList),
225 func(a, b int) bool {
226 return keyList[a] < keyList[b]
227 },
228 func(a, b int) {
229 keyList[a], keyList[b] = keyList[b], keyList[a]
230 })
231 }
232 return
233 }
234
235
236 func sortTemplates(templates map[string]Template, catalogSort bool) []Template {
237 chain := make([]Template, 0, len(templates)*2)
238
239
240 var keyList []string
241 var key string
242 var t Template
243 keyList = templateKeyList(templates, catalogSort)
244 for _, key = range keyList {
245 t = templates[key]
246 tlist := templateChainDependencies(t)
247 for _, tt := range tlist {
248 if tt != nil {
249 chain = append(chain, tt)
250 }
251 }
252 }
253
254
255 sorted := make([]Template, 0, len(templates))
256 chain:
257 for _, t := range chain {
258 for _, already := range sorted {
259 if t == already {
260 continue chain
261 }
262 }
263 sorted = append(sorted, t)
264 }
265
266 return sorted
267 }
268
269
270 func templateChainDependencies(template Template) []Template {
271 requires := template.Templates()
272 chain := make([]Template, len(requires)*2)
273 for _, req := range requires {
274 chain = append(chain, templateChainDependencies(req)...)
275 }
276 chain = append(chain, template)
277 return chain
278 }
279
280
281
282
283
284
285
View as plain text