Commit | Line | Data |
---|---|---|
858d457d AG |
1 | <?php |
2 | // | |
3 | // FPDI - Version 1.5.4 | |
4 | // | |
5 | // Copyright 2004-2015 Setasign - Jan Slabon | |
6 | // | |
7 | // Licensed under the Apache License, Version 2.0 (the "License"); | |
8 | // you may not use this file except in compliance with the License. | |
9 | // You may obtain a copy of the License at | |
10 | // | |
11 | // http://www.apache.org/licenses/LICENSE-2.0 | |
12 | // | |
13 | // Unless required by applicable law or agreed to in writing, software | |
14 | // distributed under the License is distributed on an "AS IS" BASIS, | |
15 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
16 | // See the License for the specific language governing permissions and | |
17 | // limitations under the License. | |
18 | // | |
19 | ||
20 | if (!class_exists('fpdi_bridge')) { | |
21 | require_once('fpdi_bridge.php'); | |
22 | } | |
23 | ||
24 | /** | |
25 | * Class FPDF_TPL | |
26 | */ | |
27 | class FPDF_TPL extends fpdi_bridge | |
28 | { | |
29 | /** | |
30 | * Array of template data | |
31 | * | |
32 | * @var array | |
33 | */ | |
34 | protected $_tpls = array(); | |
35 | ||
36 | /** | |
37 | * Current Template-Id | |
38 | * | |
39 | * @var int | |
40 | */ | |
41 | public $tpl = 0; | |
42 | ||
43 | /** | |
44 | * "In Template"-Flag | |
45 | * | |
46 | * @var boolean | |
47 | */ | |
48 | protected $_inTpl = false; | |
49 | ||
50 | /** | |
51 | * Name prefix of templates used in Resources dictionary | |
52 | * | |
53 | * @var string A String defining the Prefix used as Template-Object-Names. Have to begin with an / | |
54 | */ | |
55 | public $tplPrefix = "/TPL"; | |
56 | ||
57 | /** | |
58 | * Resources used by templates and pages | |
59 | * | |
60 | * @var array | |
61 | */ | |
62 | protected $_res = array(); | |
63 | ||
64 | /** | |
65 | * Last used template data | |
66 | * | |
67 | * @var array | |
68 | */ | |
69 | public $lastUsedTemplateData = array(); | |
70 | ||
71 | /** | |
72 | * Start a template. | |
73 | * | |
74 | * This method starts a template. You can give own coordinates to build an own sized | |
75 | * template. Pay attention, that the margins are adapted to the new template size. | |
76 | * If you want to write outside the template, for example to build a clipped template, | |
77 | * you have to set the margins and "cursor"-position manual after beginTemplate()-call. | |
78 | * | |
79 | * If no parameter is given, the template uses the current page-size. | |
80 | * The method returns an id of the current template. This id is used later for using this template. | |
81 | * Warning: A created template is saved in the resulting PDF at all events. Also if you don't use it after creation! | |
82 | * | |
83 | * @param int $x The x-coordinate given in user-unit | |
84 | * @param int $y The y-coordinate given in user-unit | |
85 | * @param int $w The width given in user-unit | |
86 | * @param int $h The height given in user-unit | |
87 | * @return int The id of new created template | |
88 | * @throws LogicException | |
89 | */ | |
90 | public function beginTemplate($x = null, $y = null, $w = null, $h = null) | |
91 | { | |
92 | if (is_subclass_of($this, 'TCPDF')) { | |
93 | throw new LogicException('This method is only usable with FPDF. Use TCPDF methods startTemplate() instead.'); | |
94 | } | |
95 | ||
96 | if ($this->page <= 0) { | |
97 | throw new LogicException("You have to add at least a page first!"); | |
98 | } | |
99 | ||
100 | if ($x == null) | |
101 | $x = 0; | |
102 | if ($y == null) | |
103 | $y = 0; | |
104 | if ($w == null) | |
105 | $w = $this->w; | |
106 | if ($h == null) | |
107 | $h = $this->h; | |
108 | ||
109 | // Save settings | |
110 | $this->tpl++; | |
111 | $tpl =& $this->_tpls[$this->tpl]; | |
112 | $tpl = array( | |
113 | 'o_x' => $this->x, | |
114 | 'o_y' => $this->y, | |
115 | 'o_AutoPageBreak' => $this->AutoPageBreak, | |
116 | 'o_bMargin' => $this->bMargin, | |
117 | 'o_tMargin' => $this->tMargin, | |
118 | 'o_lMargin' => $this->lMargin, | |
119 | 'o_rMargin' => $this->rMargin, | |
120 | 'o_h' => $this->h, | |
121 | 'o_w' => $this->w, | |
122 | 'o_FontFamily' => $this->FontFamily, | |
123 | 'o_FontStyle' => $this->FontStyle, | |
124 | 'o_FontSizePt' => $this->FontSizePt, | |
125 | 'o_FontSize' => $this->FontSize, | |
126 | 'buffer' => '', | |
127 | 'x' => $x, | |
128 | 'y' => $y, | |
129 | 'w' => $w, | |
130 | 'h' => $h | |
131 | ); | |
132 | ||
133 | $this->SetAutoPageBreak(false); | |
134 | ||
135 | // Define own high and width to calculate correct positions | |
136 | $this->h = $h; | |
137 | $this->w = $w; | |
138 | ||
139 | $this->_inTpl = true; | |
140 | $this->SetXY($x + $this->lMargin, $y + $this->tMargin); | |
141 | $this->SetRightMargin($this->w - $w + $this->rMargin); | |
142 | ||
143 | if ($this->CurrentFont) { | |
144 | $fontKey = $this->FontFamily . $this->FontStyle; | |
145 | if ($fontKey) { | |
146 | $this->_res['tpl'][$this->tpl]['fonts'][$fontKey] =& $this->fonts[$fontKey]; | |
147 | $this->_out(sprintf('BT /F%d %.2F Tf ET', $this->CurrentFont['i'], $this->FontSizePt)); | |
148 | } | |
149 | } | |
150 | ||
151 | return $this->tpl; | |
152 | } | |
153 | ||
154 | /** | |
155 | * End template. | |
156 | * | |
157 | * This method ends a template and reset initiated variables collected in {@link beginTemplate()}. | |
158 | * | |
159 | * @return int|boolean If a template is opened, the id is returned. If not a false is returned. | |
160 | */ | |
161 | public function endTemplate() | |
162 | { | |
163 | if (is_subclass_of($this, 'TCPDF')) { | |
164 | $args = func_get_args(); | |
165 | return call_user_func_array(array($this, 'TCPDF::endTemplate'), $args); | |
166 | } | |
167 | ||
168 | if ($this->_inTpl) { | |
169 | $this->_inTpl = false; | |
170 | $tpl = $this->_tpls[$this->tpl]; | |
171 | $this->SetXY($tpl['o_x'], $tpl['o_y']); | |
172 | $this->tMargin = $tpl['o_tMargin']; | |
173 | $this->lMargin = $tpl['o_lMargin']; | |
174 | $this->rMargin = $tpl['o_rMargin']; | |
175 | $this->h = $tpl['o_h']; | |
176 | $this->w = $tpl['o_w']; | |
177 | $this->SetAutoPageBreak($tpl['o_AutoPageBreak'], $tpl['o_bMargin']); | |
178 | ||
179 | $this->FontFamily = $tpl['o_FontFamily']; | |
180 | $this->FontStyle = $tpl['o_FontStyle']; | |
181 | $this->FontSizePt = $tpl['o_FontSizePt']; | |
182 | $this->FontSize = $tpl['o_FontSize']; | |
183 | ||
184 | $fontKey = $this->FontFamily . $this->FontStyle; | |
185 | if ($fontKey) | |
186 | $this->CurrentFont =& $this->fonts[$fontKey]; | |
187 | ||
188 | return $this->tpl; | |
189 | } else { | |
190 | return false; | |
191 | } | |
192 | } | |
193 | ||
194 | /** | |
195 | * Use a template in current page or other template. | |
196 | * | |
197 | * You can use a template in a page or in another template. | |
198 | * You can give the used template a new size. | |
199 | * All parameters are optional. The width or height is calculated automatically | |
200 | * if one is given. If no parameter is given the origin size as defined in | |
201 | * {@link beginTemplate()} method is used. | |
202 | * | |
203 | * The calculated or used width and height are returned as an array. | |
204 | * | |
205 | * @param int $tplIdx A valid template-id | |
206 | * @param int $x The x-position | |
207 | * @param int $y The y-position | |
208 | * @param int $w The new width of the template | |
209 | * @param int $h The new height of the template | |
210 | * @return array The height and width of the template (array('w' => ..., 'h' => ...)) | |
211 | * @throws LogicException|InvalidArgumentException | |
212 | */ | |
213 | public function useTemplate($tplIdx, $x = null, $y = null, $w = 0, $h = 0) | |
214 | { | |
215 | if ($this->page <= 0) { | |
216 | throw new LogicException('You have to add at least a page first!'); | |
217 | } | |
218 | ||
219 | if (!isset($this->_tpls[$tplIdx])) { | |
220 | throw new InvalidArgumentException('Template does not exist!'); | |
221 | } | |
222 | ||
223 | if ($this->_inTpl) { | |
224 | $this->_res['tpl'][$this->tpl]['tpls'][$tplIdx] =& $this->_tpls[$tplIdx]; | |
225 | } | |
226 | ||
227 | $tpl = $this->_tpls[$tplIdx]; | |
228 | $_w = $tpl['w']; | |
229 | $_h = $tpl['h']; | |
230 | ||
231 | if ($x == null) { | |
232 | $x = 0; | |
233 | } | |
234 | ||
235 | if ($y == null) { | |
236 | $y = 0; | |
237 | } | |
238 | ||
239 | $x += $tpl['x']; | |
240 | $y += $tpl['y']; | |
241 | ||
242 | $wh = $this->getTemplateSize($tplIdx, $w, $h); | |
243 | $w = $wh['w']; | |
244 | $h = $wh['h']; | |
245 | ||
246 | $tplData = array( | |
247 | 'x' => $this->x, | |
248 | 'y' => $this->y, | |
249 | 'w' => $w, | |
250 | 'h' => $h, | |
251 | 'scaleX' => ($w / $_w), | |
252 | 'scaleY' => ($h / $_h), | |
253 | 'tx' => $x, | |
254 | 'ty' => ($this->h - $y - $h), | |
255 | 'lty' => ($this->h - $y - $h) - ($this->h - $_h) * ($h / $_h) | |
256 | ); | |
257 | ||
258 | $this->_out(sprintf('q %.4F 0 0 %.4F %.4F %.4F cm', | |
259 | $tplData['scaleX'], $tplData['scaleY'], $tplData['tx'] * $this->k, $tplData['ty'] * $this->k) | |
260 | ); // Translate | |
261 | $this->_out(sprintf('%s%d Do Q', $this->tplPrefix, $tplIdx)); | |
262 | ||
263 | $this->lastUsedTemplateData = $tplData; | |
264 | ||
265 | return array('w' => $w, 'h' => $h); | |
266 | } | |
267 | ||
268 | /** | |
269 | * Get the calculated size of a template. | |
270 | * | |
271 | * If one size is given, this method calculates the other one. | |
272 | * | |
273 | * @param int $tplIdx A valid template-id | |
274 | * @param int $w The width of the template | |
275 | * @param int $h The height of the template | |
276 | * @return array The height and width of the template (array('w' => ..., 'h' => ...)) | |
277 | */ | |
278 | public function getTemplateSize($tplIdx, $w = 0, $h = 0) | |
279 | { | |
280 | if (!isset($this->_tpls[$tplIdx])) | |
281 | return false; | |
282 | ||
283 | $tpl = $this->_tpls[$tplIdx]; | |
284 | $_w = $tpl['w']; | |
285 | $_h = $tpl['h']; | |
286 | ||
287 | if ($w == 0 && $h == 0) { | |
288 | $w = $_w; | |
289 | $h = $_h; | |
290 | } | |
291 | ||
292 | if ($w == 0) | |
293 | $w = $h * $_w / $_h; | |
294 | if($h == 0) | |
295 | $h = $w * $_h / $_w; | |
296 | ||
297 | return array("w" => $w, "h" => $h); | |
298 | } | |
299 | ||
300 | /** | |
301 | * Sets the font used to print character strings. | |
302 | * | |
303 | * See FPDF/TCPDF documentation. | |
304 | * | |
305 | * @see http://fpdf.org/en/doc/setfont.htm | |
306 | * @see http://www.tcpdf.org/doc/code/classTCPDF.html#afd56e360c43553830d543323e81bc045 | |
307 | */ | |
308 | public function SetFont($family, $style = '', $size = null, $fontfile = '', $subset = 'default', $out = true) | |
309 | { | |
310 | if (is_subclass_of($this, 'TCPDF')) { | |
311 | $args = func_get_args(); | |
312 | return call_user_func_array(array($this, 'TCPDF::SetFont'), $args); | |
313 | } | |
314 | ||
315 | parent::SetFont($family, $style, $size); | |
316 | ||
317 | $fontkey = $this->FontFamily . $this->FontStyle; | |
318 | ||
319 | if ($this->_inTpl) { | |
320 | $this->_res['tpl'][$this->tpl]['fonts'][$fontkey] =& $this->fonts[$fontkey]; | |
321 | } else { | |
322 | $this->_res['page'][$this->page]['fonts'][$fontkey] =& $this->fonts[$fontkey]; | |
323 | } | |
324 | } | |
325 | ||
326 | /** | |
327 | * Puts an image. | |
328 | * | |
329 | * See FPDF/TCPDF documentation. | |
330 | * | |
331 | * @see http://fpdf.org/en/doc/image.htm | |
332 | * @see http://www.tcpdf.org/doc/code/classTCPDF.html#a714c2bee7d6b39d4d6d304540c761352 | |
333 | */ | |
334 | public function Image( | |
335 | $file, $x = '', $y = '', $w = 0, $h = 0, $type = '', $link = '', $align = '', $resize = false, | |
336 | $dpi = 300, $palign = '', $ismask = false, $imgmask = false, $border = 0, $fitbox = false, | |
337 | $hidden = false, $fitonpage = false, $alt = false, $altimgs = array() | |
338 | ) | |
339 | { | |
340 | if (is_subclass_of($this, 'TCPDF')) { | |
341 | $args = func_get_args(); | |
342 | return call_user_func_array(array($this, 'TCPDF::Image'), $args); | |
343 | } | |
344 | ||
345 | $ret = parent::Image($file, $x, $y, $w, $h, $type, $link); | |
346 | if ($this->_inTpl) { | |
347 | $this->_res['tpl'][$this->tpl]['images'][$file] =& $this->images[$file]; | |
348 | } else { | |
349 | $this->_res['page'][$this->page]['images'][$file] =& $this->images[$file]; | |
350 | } | |
351 | ||
352 | return $ret; | |
353 | } | |
354 | ||
355 | /** | |
356 | * Adds a new page to the document. | |
357 | * | |
358 | * See FPDF/TCPDF documentation. | |
359 | * | |
360 | * This method cannot be used if you'd started a template. | |
361 | * | |
362 | * @see http://fpdf.org/en/doc/addpage.htm | |
363 | * @see http://www.tcpdf.org/doc/code/classTCPDF.html#a5171e20b366b74523709d84c349c1ced | |
364 | */ | |
365 | public function AddPage($orientation = '', $format = '', $keepmargins = false, $tocpage = false) | |
366 | { | |
367 | if (is_subclass_of($this, 'TCPDF')) { | |
368 | $args = func_get_args(); | |
369 | return call_user_func_array(array($this, 'TCPDF::AddPage'), $args); | |
370 | } | |
371 | ||
372 | if ($this->_inTpl) { | |
373 | throw new LogicException('Adding pages in templates is not possible!'); | |
374 | } | |
375 | ||
376 | parent::AddPage($orientation, $format); | |
377 | } | |
378 | ||
379 | /** | |
380 | * Puts a link on a rectangular area of the page. | |
381 | * | |
382 | * Overwritten because adding links in a template will not work. | |
383 | * | |
384 | * @see http://fpdf.org/en/doc/link.htm | |
385 | * @see http://www.tcpdf.org/doc/code/classTCPDF.html#ab87bf1826384fbfe30eb499d42f1d994 | |
386 | */ | |
387 | public function Link($x, $y, $w, $h, $link, $spaces = 0) | |
388 | { | |
389 | if (is_subclass_of($this, 'TCPDF')) { | |
390 | $args = func_get_args(); | |
391 | return call_user_func_array(array($this, 'TCPDF::Link'), $args); | |
392 | } | |
393 | ||
394 | if ($this->_inTpl) { | |
395 | throw new LogicException('Using links in templates is not posible!'); | |
396 | } | |
397 | ||
398 | parent::Link($x, $y, $w, $h, $link); | |
399 | } | |
400 | ||
401 | /** | |
402 | * Creates a new internal link and returns its identifier. | |
403 | * | |
404 | * Overwritten because adding links in a template will not work. | |
405 | * | |
406 | * @see http://fpdf.org/en/doc/addlink.htm | |
407 | * @see http://www.tcpdf.org/doc/code/classTCPDF.html#a749522038ed7786c3e1701435dcb891e | |
408 | */ | |
409 | public function AddLink() | |
410 | { | |
411 | if (is_subclass_of($this, 'TCPDF')) { | |
412 | $args = func_get_args(); | |
413 | return call_user_func_array(array($this, 'TCPDF::AddLink'), $args); | |
414 | } | |
415 | ||
416 | if ($this->_inTpl) { | |
417 | throw new LogicException('Adding links in templates is not possible!'); | |
418 | } | |
419 | ||
420 | return parent::AddLink(); | |
421 | } | |
422 | ||
423 | /** | |
424 | * Defines the page and position a link points to. | |
425 | * | |
426 | * Overwritten because adding links in a template will not work. | |
427 | * | |
428 | * @see http://fpdf.org/en/doc/setlink.htm | |
429 | * @see http://www.tcpdf.org/doc/code/classTCPDF.html#ace5be60e7857953ea5e2b89cb90df0ae | |
430 | */ | |
431 | public function SetLink($link, $y = 0, $page = -1) | |
432 | { | |
433 | if (is_subclass_of($this, 'TCPDF')) { | |
434 | $args = func_get_args(); | |
435 | return call_user_func_array(array($this, 'TCPDF::SetLink'), $args); | |
436 | } | |
437 | ||
438 | if ($this->_inTpl) { | |
439 | throw new LogicException('Setting links in templates is not possible!'); | |
440 | } | |
441 | ||
442 | parent::SetLink($link, $y, $page); | |
443 | } | |
444 | ||
445 | /** | |
446 | * Writes the form XObjects to the PDF document. | |
447 | */ | |
448 | protected function _putformxobjects() | |
449 | { | |
450 | $filter=($this->compress) ? '/Filter /FlateDecode ' : ''; | |
451 | reset($this->_tpls); | |
452 | ||
453 | foreach($this->_tpls AS $tplIdx => $tpl) { | |
454 | $this->_newobj(); | |
455 | $this->_tpls[$tplIdx]['n'] = $this->n; | |
456 | $this->_out('<<'.$filter.'/Type /XObject'); | |
457 | $this->_out('/Subtype /Form'); | |
458 | $this->_out('/FormType 1'); | |
459 | $this->_out(sprintf('/BBox [%.2F %.2F %.2F %.2F]', | |
460 | // llx | |
461 | $tpl['x'] * $this->k, | |
462 | // lly | |
463 | -$tpl['y'] * $this->k, | |
464 | // urx | |
465 | ($tpl['w'] + $tpl['x']) * $this->k, | |
466 | // ury | |
467 | ($tpl['h'] - $tpl['y']) * $this->k | |
468 | )); | |
469 | ||
470 | if ($tpl['x'] != 0 || $tpl['y'] != 0) { | |
471 | $this->_out(sprintf('/Matrix [1 0 0 1 %.5F %.5F]', | |
472 | -$tpl['x'] * $this->k * 2, $tpl['y'] * $this->k * 2 | |
473 | )); | |
474 | } | |
475 | ||
476 | $this->_out('/Resources '); | |
477 | $this->_out('<</ProcSet [/PDF /Text /ImageB /ImageC /ImageI]'); | |
478 | ||
479 | if (isset($this->_res['tpl'][$tplIdx])) { | |
480 | $res = $this->_res['tpl'][$tplIdx]; | |
481 | if (isset($res['fonts']) && count($res['fonts'])) { | |
482 | $this->_out('/Font <<'); | |
483 | ||
484 | foreach($res['fonts'] as $font) { | |
485 | $this->_out('/F' . $font['i'] . ' ' . $font['n'] . ' 0 R'); | |
486 | } | |
487 | ||
488 | $this->_out('>>'); | |
489 | } | |
490 | ||
491 | if(isset($res['images']) || isset($res['tpls'])) { | |
492 | $this->_out('/XObject <<'); | |
493 | ||
494 | if (isset($res['images'])) { | |
495 | foreach($res['images'] as $image) | |
496 | $this->_out('/I' . $image['i'] . ' ' . $image['n'] . ' 0 R'); | |
497 | } | |
498 | ||
499 | if (isset($res['tpls'])) { | |
500 | foreach($res['tpls'] as $i => $_tpl) | |
501 | $this->_out($this->tplPrefix . $i . ' ' . $_tpl['n'] . ' 0 R'); | |
502 | } | |
503 | ||
504 | $this->_out('>>'); | |
505 | } | |
506 | } | |
507 | ||
508 | $this->_out('>>'); | |
509 | ||
510 | $buffer = ($this->compress) ? gzcompress($tpl['buffer']) : $tpl['buffer']; | |
511 | $this->_out('/Length ' . strlen($buffer) . ' >>'); | |
512 | $this->_putstream($buffer); | |
513 | $this->_out('endobj'); | |
514 | } | |
515 | } | |
516 | ||
517 | /** | |
518 | * Output images. | |
519 | * | |
520 | * Overwritten to add {@link _putformxobjects()} after _putimages(). | |
521 | */ | |
522 | public function _putimages() | |
523 | { | |
524 | parent::_putimages(); | |
525 | $this->_putformxobjects(); | |
526 | } | |
527 | ||
528 | /** | |
529 | * Writes the references of XObject resources to the document. | |
530 | * | |
531 | * Overwritten to add the the templates to the XObject resource dictionary. | |
532 | */ | |
533 | public function _putxobjectdict() | |
534 | { | |
535 | parent::_putxobjectdict(); | |
536 | ||
537 | foreach($this->_tpls as $tplIdx => $tpl) { | |
538 | $this->_out(sprintf('%s%d %d 0 R', $this->tplPrefix, $tplIdx, $tpl['n'])); | |
539 | } | |
540 | } | |
541 | ||
542 | /** | |
543 | * Writes bytes to the resulting document. | |
544 | * | |
545 | * Overwritten to delegate the data to the template buffer. | |
546 | * | |
547 | * @param string $s | |
548 | */ | |
549 | public function _out($s) | |
550 | { | |
551 | if ($this->state == 2 && $this->_inTpl) { | |
552 | $this->_tpls[$this->tpl]['buffer'] .= $s . "\n"; | |
553 | } else { | |
554 | parent::_out($s); | |
555 | } | |
556 | } | |
557 | } |