fpdf_tpl.php 17 KB

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