PageRenderTime 85ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 1ms

/include/html2pdf_v4.03/html2pdf.class.php

https://bitbucket.org/sleininger/stock_online
PHP | 6488 lines | 3863 code | 964 blank | 1661 comment | 732 complexity | cb436125a2986a184266a5b4e82cd42e MD5 | raw file
Possible License(s): LGPL-3.0, LGPL-2.1, GPL-3.0

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. /**
  3. * HTML2PDF Librairy - main class
  4. *
  5. * HTML => PDF convertor
  6. * distributed under the LGPL License
  7. *
  8. * @author Laurent MINGUET <webmaster@html2pdf.fr>
  9. * @version 4.03
  10. */
  11. if (!defined('__CLASS_HTML2PDF__')) {
  12. define('__CLASS_HTML2PDF__', '4.03');
  13. define('HTML2PDF_USED_TCPDF_VERSION', '5.0.002');
  14. require_once(dirname(__FILE__).'/_class/exception.class.php');
  15. require_once(dirname(__FILE__).'/_class/locale.class.php');
  16. require_once(dirname(__FILE__).'/_class/myPdf.class.php');
  17. require_once(dirname(__FILE__).'/_class/parsingHtml.class.php');
  18. require_once(dirname(__FILE__).'/_class/parsingCss.class.php');
  19. class HTML2PDF
  20. {
  21. /**
  22. * HTML2PDF_myPdf object, extends from TCPDF
  23. * @var HTML2PDF_myPdf
  24. */
  25. public $pdf = null;
  26. /**
  27. * CSS parsing
  28. * @var HTML2PDF_parsingCss
  29. */
  30. public $parsingCss = null;
  31. /**
  32. * HTML parsing
  33. * @var HTML2PDF_parsingHtml
  34. */
  35. public $parsingHtml = null;
  36. protected $_langue = 'fr'; // locale of the messages
  37. protected $_orientation = 'P'; // page orientation : Portrait ou Landscape
  38. protected $_format = 'A4'; // page format : A4, A3, ...
  39. protected $_encoding = ''; // charset encoding
  40. protected $_unicode = true; // means that the input text is unicode (default = true)
  41. protected $_testTdInOnepage = true; // test of TD that can not take more than one page
  42. protected $_testIsImage = true; // test if the images exist or not
  43. protected $_testIsDeprecated = false; // test the deprecated functions
  44. protected $_parsePos = 0; // position in the parsing
  45. protected $_tempPos = 0; // temporary position for complex table
  46. protected $_page = 0; // current page number
  47. protected $_subHtml = null; // sub html
  48. protected $_subPart = false; // sub HTML2PDF
  49. protected $_subHEADER = array(); // sub action to make the header
  50. protected $_subFOOTER = array(); // sub action to make the footer
  51. protected $_subSTATES = array(); // array to save some parameters
  52. protected $_isSubPart = false; // flag : in a sub html2pdf
  53. protected $_isInThead = false; // flag : in a thead
  54. protected $_isInTfoot = false; // flag : in a tfoot
  55. protected $_isInOverflow = false; // flag : in a overflow
  56. protected $_isInFooter = false; // flag : in a footer
  57. protected $_isInDraw = null; // flag : in a draw (svg)
  58. protected $_isAfterFloat = false; // flag : is just after a float
  59. protected $_isInForm = false; // flag : is in a float. false / action of the form
  60. protected $_isInLink = ''; // flag : is in a link. empty / href of the link
  61. protected $_isInParagraph = false; // flag : is in a paragraph
  62. protected $_isForOneLine = false; // flag : in a specific sub html2pdf to have the height of the next line
  63. protected $_maxX = 0; // maximum X of the current zone
  64. protected $_maxY = 0; // maximum Y of the current zone
  65. protected $_maxE = 0; // number of elements in the current zone
  66. protected $_maxH = 0; // maximum height of the line in the current zone
  67. protected $_maxSave = array(); // save the maximums of the current zone
  68. protected $_currentH = 0; // height of the current line
  69. protected $_defaultLeft = 0; // default marges of the page
  70. protected $_defaultTop = 0;
  71. protected $_defaultRight = 0;
  72. protected $_defaultBottom = 0;
  73. protected $_defaultFont = null; // default font to use, is the asked font does not exist
  74. protected $_margeLeft = 0; // current marges of the page
  75. protected $_margeTop = 0;
  76. protected $_margeRight = 0;
  77. protected $_margeBottom = 0;
  78. protected $_marges = array(); // save the different marges of the current page
  79. protected $_pageMarges = array(); // float marges of the current page
  80. protected $_background = array(); // background informations
  81. protected $_firstPage = true; // flag : first page
  82. protected $_defList = array(); // table to save the stats of the tags UL and OL
  83. protected $_lstAnchor = array(); // list of the anchors
  84. protected $_lstField = array(); // list of the fields
  85. protected $_lstSelect = array(); // list of the options of the current select
  86. protected $_previousCall = null; // last action called
  87. protected $_debugActif = false; // flag : mode debug is active
  88. protected $_debugOkUsage = false; // flag : the function memory_get_usage exist
  89. protected $_debugOkPeak = false; // flag : the function memory_get_peak_usage exist
  90. protected $_debugLevel = 0; // level in the debug
  91. protected $_debugStartTime = 0; // debug start time
  92. protected $_debugLastTime = 0; // debug stop time
  93. static protected $_subobj = null; // object html2pdf prepared in order to accelerate the creation of sub html2pdf
  94. static protected $_tables = array(); // static table to prepare the nested html tables
  95. /**
  96. * class constructor
  97. *
  98. * @access public
  99. * @param string $orientation page orientation, same as TCPDF
  100. * @param mixed $format The format used for pages, same as TCPDF
  101. * @param $tring $langue Langue : fr, en, it...
  102. * @param boolean $unicode TRUE means that the input text is unicode (default = true)
  103. * @param String $encoding charset encoding; default is UTF-8
  104. * @param array $marges Default marges (left, top, right, bottom)
  105. * @return HTML2PDF $this
  106. */
  107. public function __construct($orientation = 'P', $format = 'A4', $langue='fr', $unicode=true, $encoding='UTF-8', $marges = array(5, 5, 5, 8))
  108. {
  109. // init the page number
  110. $this->_page = 0;
  111. $this->_firstPage = true;
  112. // save the parameters
  113. $this->_orientation = $orientation;
  114. $this->_format = $format;
  115. $this->_langue = strtolower($langue);
  116. $this->_unicode = $unicode;
  117. $this->_encoding = $encoding;
  118. // load the Local
  119. HTML2PDF_locale::load($this->_langue);
  120. // create the HTML2PDF_myPdf object
  121. $this->pdf = new HTML2PDF_myPdf($orientation, 'mm', $format, $unicode, $encoding);
  122. // init the CSS parsing object
  123. $this->parsingCss = new HTML2PDF_parsingCss($this->pdf);
  124. $this->parsingCss->fontSet();
  125. $this->_defList = array();
  126. // init some tests
  127. $this->setTestTdInOnePage(true);
  128. $this->setTestIsImage(true);
  129. $this->setTestIsDeprecated(true);
  130. // init the default font
  131. $this->setDefaultFont(null);
  132. // init the HTML parsing object
  133. $this->parsingHtml = new HTML2PDF_parsingHtml($this->_encoding);
  134. $this->_subHtml = null;
  135. $this->_subPart = false;
  136. // init the marges of the page
  137. if (!is_array($marges)) $marges = array($marges, $marges, $marges, $marges);
  138. $this->_setDefaultMargins($marges[0], $marges[1], $marges[2], $marges[3]);
  139. $this->_setMargins();
  140. $this->_marges = array();
  141. // init the form's fields
  142. $this->_lstField = array();
  143. return $this;
  144. }
  145. /**
  146. * Destructor
  147. *
  148. * @access public
  149. * @return null
  150. */
  151. public function __destruct()
  152. {
  153. }
  154. /**
  155. * Clone to create a sub HTML2PDF from HTML2PDF::$_subobj
  156. *
  157. * @access public
  158. */
  159. public function __clone()
  160. {
  161. $this->pdf = clone $this->pdf;
  162. $this->parsingHtml = clone $this->parsingHtml;
  163. $this->parsingCss = clone $this->parsingCss;
  164. $this->parsingCss->setPdfParent($this->pdf);
  165. }
  166. /**
  167. * set the debug mode to On
  168. *
  169. * @access public
  170. * @return HTML2PDF $this
  171. */
  172. public function setModeDebug()
  173. {
  174. $time = microtime(true);
  175. $this->_debugActif = true;
  176. $this->_debugOkUsage = function_exists('memory_get_usage');
  177. $this->_debugOkPeak = function_exists('memory_get_peak_usage');
  178. $this->_debugStartTime = $time;
  179. $this->_debugLastTime = $time;
  180. $this->_DEBUG_stepline('step', 'time', 'delta', 'memory', 'peak');
  181. $this->_DEBUG_add('Init debug');
  182. return $this;
  183. }
  184. /**
  185. * Set the test of TD thdat can not take more than one page
  186. *
  187. * @access public
  188. * @param boolean $mode
  189. * @return HTML2PDF $this
  190. */
  191. public function setTestTdInOnePage($mode = true)
  192. {
  193. $this->_testTdInOnepage = $mode ? true : false;
  194. return $this;
  195. }
  196. /**
  197. * Set the test if the images exist or not
  198. *
  199. * @access public
  200. * @param boolean $mode
  201. * @return HTML2PDF $this
  202. */
  203. public function setTestIsImage($mode = true)
  204. {
  205. $this->_testIsImage = $mode ? true : false;
  206. return $this;
  207. }
  208. /**
  209. * Set the test on deprecated functions
  210. *
  211. * @access public
  212. * @param boolean $mode
  213. * @return HTML2PDF $this
  214. */
  215. public function setTestIsDeprecated($mode = true)
  216. {
  217. $this->_testIsDeprecated = $mode ? true : false;
  218. return $this;
  219. }
  220. /**
  221. * Set the default font to use, if no font is specify, or if the asked font does not exist
  222. *
  223. * @access public
  224. * @param string $default name of the default font to use. If null : Arial is no font is specify, and error if the asked font does not exist
  225. * @return HTML2PDF $this
  226. */
  227. public function setDefaultFont($default = null)
  228. {
  229. $this->_defaultFont = $default;
  230. $this->parsingCss->setDefaultFont($default);
  231. return $this;
  232. }
  233. /**
  234. * add a font, see TCPDF function addFont
  235. *
  236. * @access public
  237. * @param string $family Font family. The name can be chosen arbitrarily. If it is a standard family name, it will override the corresponding font.
  238. * @param string $style Font style. Possible values are (case insensitive):<ul><li>empty string: regular (default)</li><li>B: bold</li><li>I: italic</li><li>BI or IB: bold italic</li></ul>
  239. * @param string $fontfile The font definition file. By default, the name is built from the family and style, in lower case with no spaces.
  240. * @return HTML2PDF $this
  241. * @see TCPDF::addFont
  242. */
  243. public function addFont($family, $style='', $file='')
  244. {
  245. $this->pdf->AddFont($family, $style, $file);
  246. return $this;
  247. }
  248. /**
  249. * display a automatic index, from the bookmarks
  250. *
  251. * @access public
  252. * @param string $titre index title
  253. * @param int $sizeTitle font size of the index title, in mm
  254. * @param int $sizeBookmark font size of the index, in mm
  255. * @param boolean $bookmarkTitle add a bookmark for the index, at his beginning
  256. * @param boolean $displayPage display the page numbers
  257. * @param int $onPage if null : at the end of the document on a new page, else on the $onPage page
  258. * @param string $fontName font name to use
  259. * @return null
  260. */
  261. public function createIndex($titre = 'Index', $sizeTitle = 20, $sizeBookmark = 15, $bookmarkTitle = true, $displayPage = true, $onPage = null, $fontName = 'helvetica')
  262. {
  263. $oldPage = $this->_INDEX_NewPage($onPage);
  264. $this->pdf->createIndex($this, $titre, $sizeTitle, $sizeBookmark, $bookmarkTitle, $displayPage, $onPage, $fontName);
  265. if ($oldPage) $this->pdf->setPage($oldPage);
  266. }
  267. /**
  268. * clean up the objects
  269. *
  270. * @access protected
  271. */
  272. protected function _cleanUp()
  273. {
  274. HTML2PDF::$_subobj = null;
  275. HTML2PDF::$_tables = array();
  276. }
  277. /**
  278. * Send the document to a given destination: string, local file or browser.
  279. * Dest can be :
  280. * I : send the file inline to the browser (default). The plug-in is used if available. The name given by name is used when one selects the "Save as" option on the link generating the PDF.
  281. * D : send to the browser and force a file download with the name given by name.
  282. * F : save to a local server file with the name given by name.
  283. * S : return the document as a string. name is ignored.
  284. * FI: equivalent to F + I option
  285. * FD: equivalent to F + D option
  286. * true => I
  287. * false => S
  288. *
  289. * @param string $name The name of the file when saved.
  290. * @param string $dest Destination where to send the document.
  291. * @return string content of the PDF, if $dest=S
  292. * @see TCPDF::close
  293. * @access public
  294. */
  295. public function Output($name = '', $dest = false)
  296. {
  297. // close the pdf and clean up
  298. $this->_cleanUp();
  299. // if on debug mode
  300. if ($this->_debugActif) {
  301. $this->_DEBUG_add('Before output');
  302. $this->pdf->Close();
  303. exit;
  304. }
  305. // complete parameters
  306. if ($dest===false) $dest = 'I';
  307. if ($dest===true) $dest = 'S';
  308. if ($dest==='') $dest = 'I';
  309. if ($name=='') $name='document.pdf';
  310. // clean up the destination
  311. $dest = strtoupper($dest);
  312. if (!in_array($dest, array('I', 'D', 'F', 'S', 'FI','FD'))) $dest = 'I';
  313. // the name must be a PDF name
  314. if (strtolower(substr($name, -4))!='.pdf') {
  315. throw new HTML2PDF_exception(0, 'The output document name "'.$name.'" is not a PDF name');
  316. }
  317. // call the output of TCPDF
  318. return $this->pdf->Output($name, $dest);
  319. }
  320. /**
  321. * convert HTML to PDF
  322. *
  323. * @access public
  324. * @param string $html
  325. * @param boolean $debugVue enable the HTML debug vue
  326. * @return null
  327. */
  328. public function writeHTML($html, $debugVue = false)
  329. {
  330. // if it is a real html page, we have to convert it
  331. if (preg_match('/<body/isU', $html))
  332. $html = $this->getHtmlFromPage($html);
  333. $html = str_replace('[[date_y]]', date('Y'), $html);
  334. $html = str_replace('[[date_m]]', date('m'), $html);
  335. $html = str_replace('[[date_d]]', date('d'), $html);
  336. $html = str_replace('[[date_h]]', date('H'), $html);
  337. $html = str_replace('[[date_i]]', date('i'), $html);
  338. $html = str_replace('[[date_s]]', date('s'), $html);
  339. // If we are in HTML debug vue : display the HTML
  340. if ($debugVue) {
  341. return $this->_vueHTML($html);
  342. }
  343. // convert HTMl to PDF
  344. $this->parsingCss->readStyle($html);
  345. $this->parsingHtml->setHTML($html);
  346. $this->parsingHtml->parse();
  347. $this->_makeHTMLcode();
  348. }
  349. /**
  350. * convert the HTML of a real page, to a code adapted to HTML2PDF
  351. *
  352. * @access public
  353. * @param string HTML of a real page
  354. * @return string HTML adapted to HTML2PDF
  355. */
  356. public function getHtmlFromPage($html)
  357. {
  358. $html = str_replace('<BODY', '<body', $html);
  359. $html = str_replace('</BODY', '</body', $html);
  360. // extract the content
  361. $res = explode('<body', $html);
  362. if (count($res)<2) return $html;
  363. $content = '<page'.$res[1];
  364. $content = explode('</body', $content);
  365. $content = $content[0].'</page>';
  366. // extract the link tags
  367. preg_match_all('/<link([^>]*)>/isU', $html, $match);
  368. foreach ($match[0] as $src)
  369. $content = $src.'</link>'.$content;
  370. // extract the css style tags
  371. preg_match_all('/<style[^>]*>(.*)<\/style[^>]*>/isU', $html, $match);
  372. foreach ($match[0] as $src)
  373. $content = $src.$content;
  374. return $content;
  375. }
  376. /**
  377. * init a sub HTML2PDF. does not use it directly. Only the method createSubHTML must use it
  378. *
  379. * @access public
  380. * @param string $format
  381. * @param string $orientation
  382. * @param array $marge
  383. * @param integer $page
  384. * @param array $defLIST
  385. * @param integer $myLastPageGroup
  386. * @param integer $myLastPageGroupNb
  387. */
  388. public function initSubHtml($format, $orientation, $marge, $page, $defLIST, $myLastPageGroup, $myLastPageGroupNb)
  389. {
  390. $this->_isSubPart = true;
  391. $this->parsingCss->setOnlyLeft();
  392. $this->_setNewPage($format, $orientation, null, null, ($myLastPageGroup!==null));
  393. $this->_saveMargin(0, 0, $marge);
  394. $this->_defList = $defLIST;
  395. $this->_page = $page;
  396. $this->pdf->setMyLastPageGroup($myLastPageGroup);
  397. $this->pdf->setMyLastPageGroupNb($myLastPageGroupNb);
  398. $this->pdf->setXY(0, 0);
  399. $this->parsingCss->fontSet();
  400. }
  401. /**
  402. * display the content in HTML moden for debug
  403. *
  404. * @access protected
  405. * @param string $contenu
  406. */
  407. protected function _vueHTML($content)
  408. {
  409. $content = preg_replace('/<page_header([^>]*)>/isU', '<hr>'.HTML2PDF_locale::get('vue01').' : $1<hr><div$1>', $content);
  410. $content = preg_replace('/<page_footer([^>]*)>/isU', '<hr>'.HTML2PDF_locale::get('vue02').' : $1<hr><div$1>', $content);
  411. $content = preg_replace('/<page([^>]*)>/isU', '<hr>'.HTML2PDF_locale::get('vue03').' : $1<hr><div$1>', $content);
  412. $content = preg_replace('/<\/page([^>]*)>/isU', '</div><hr>', $content);
  413. $content = preg_replace('/<bookmark([^>]*)>/isU', '<hr>bookmark : $1<hr>', $content);
  414. $content = preg_replace('/<\/bookmark([^>]*)>/isU', '', $content);
  415. $content = preg_replace('/<barcode([^>]*)>/isU', '<hr>barcode : $1<hr>', $content);
  416. $content = preg_replace('/<\/barcode([^>]*)>/isU', '', $content);
  417. $content = preg_replace('/<qrcode([^>]*)>/isU', '<hr>qrcode : $1<hr>', $content);
  418. $content = preg_replace('/<\/qrcode([^>]*)>/isU', '', $content);
  419. echo '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
  420. <html>
  421. <head>
  422. <title>'.HTML2PDF_locale::get('vue04').' HTML</title>
  423. <meta http-equiv="Content-Type" content="text/html; charset='.$this->_encoding.'" >
  424. </head>
  425. <body style="padding: 10px; font-size: 10pt;font-family: Verdana;">
  426. '.$content.'
  427. </body>
  428. </html>';
  429. exit;
  430. }
  431. /**
  432. * set the default margins of the page
  433. *
  434. * @access protected
  435. * @param int $left (mm, left margin)
  436. * @param int $top (mm, top margin)
  437. * @param int $right (mm, right margin, if null => left=right)
  438. * @param int $bottom (mm, bottom margin, if null => bottom=8mm)
  439. */
  440. protected function _setDefaultMargins($left, $top, $right = null, $bottom = null)
  441. {
  442. if ($right===null) $right = $left;
  443. if ($bottom===null) $bottom = 8;
  444. $this->_defaultLeft = $this->parsingCss->ConvertToMM($left.'mm');
  445. $this->_defaultTop = $this->parsingCss->ConvertToMM($top.'mm');
  446. $this->_defaultRight = $this->parsingCss->ConvertToMM($right.'mm');
  447. $this->_defaultBottom = $this->parsingCss->ConvertToMM($bottom.'mm');
  448. }
  449. /**
  450. * create a new page
  451. *
  452. * @access protected
  453. * @param mixed $format
  454. * @param string $orientation
  455. * @param array $background background information
  456. * @param integer $curr real position in the html parseur (if break line in the write of a text)
  457. * @param boolean $resetPageNumber
  458. */
  459. protected function _setNewPage($format = null, $orientation = '', $background = null, $curr = null, $resetPageNumber=false)
  460. {
  461. $this->_firstPage = false;
  462. $this->_format = $format ? $format : $this->_format;
  463. $this->_orientation = $orientation ? $orientation : $this->_orientation;
  464. $this->_background = $background!==null ? $background : $this->_background;
  465. $this->_maxY = 0;
  466. $this->_maxX = 0;
  467. $this->_maxH = 0;
  468. $this->_maxE = 0;
  469. $this->pdf->SetMargins($this->_defaultLeft, $this->_defaultTop, $this->_defaultRight);
  470. if ($resetPageNumber) {
  471. $this->pdf->startPageGroup();
  472. }
  473. $this->pdf->AddPage($this->_orientation, $this->_format);
  474. if ($resetPageNumber) {
  475. $this->pdf->myStartPageGroup();
  476. }
  477. $this->_page++;
  478. if (!$this->_subPart && !$this->_isSubPart) {
  479. if (is_array($this->_background)) {
  480. if (isset($this->_background['color']) && $this->_background['color']) {
  481. $this->pdf->setFillColorArray($this->_background['color']);
  482. $this->pdf->Rect(0, 0, $this->pdf->getW(), $this->pdf->getH(), 'F');
  483. }
  484. if (isset($this->_background['img']) && $this->_background['img'])
  485. $this->pdf->Image($this->_background['img'], $this->_background['posX'], $this->_background['posY'], $this->_background['width']);
  486. }
  487. $this->_setPageHeader();
  488. $this->_setPageFooter();
  489. }
  490. $this->_setMargins();
  491. $this->pdf->setY($this->_margeTop);
  492. $this->_setNewPositionForNewLine($curr);
  493. $this->_maxH = 0;
  494. }
  495. /**
  496. * set the real margin, using the default margins and the page margins
  497. *
  498. * @access protected
  499. */
  500. protected function _setMargins()
  501. {
  502. // prepare the margins
  503. $this->_margeLeft = $this->_defaultLeft + (isset($this->_background['left']) ? $this->_background['left'] : 0);
  504. $this->_margeRight = $this->_defaultRight + (isset($this->_background['right']) ? $this->_background['right'] : 0);
  505. $this->_margeTop = $this->_defaultTop + (isset($this->_background['top']) ? $this->_background['top'] : 0);
  506. $this->_margeBottom = $this->_defaultBottom + (isset($this->_background['bottom']) ? $this->_background['bottom'] : 0);
  507. // set the PDF margins
  508. $this->pdf->SetMargins($this->_margeLeft, $this->_margeTop, $this->_margeRight);
  509. $this->pdf->SetAutoPageBreak(false, $this->_margeBottom);
  510. // set the float Margins
  511. $this->_pageMarges = array();
  512. if ($this->_isInParagraph!==false) {
  513. $this->_pageMarges[floor($this->_margeTop*100)] = array($this->_isInParagraph[0], $this->pdf->getW()-$this->_isInParagraph[1]);
  514. } else {
  515. $this->_pageMarges[floor($this->_margeTop*100)] = array($this->_margeLeft, $this->pdf->getW()-$this->_margeRight);
  516. }
  517. }
  518. /**
  519. * add a debug step
  520. *
  521. * @access protected
  522. * @param string $name step name
  523. * @param boolean $level (true=up, false=down, null=nothing to do)
  524. * @return $this
  525. */
  526. protected function _DEBUG_add($name, $level=null)
  527. {
  528. // if true : UP
  529. if ($level===true) $this->_debugLevel++;
  530. $name = str_repeat(' ', $this->_debugLevel). $name.($level===true ? ' Begin' : ($level===false ? ' End' : ''));
  531. $time = microtime(true);
  532. $usage = ($this->_debugOkUsage ? memory_get_usage() : 0);
  533. $peak = ($this->_debugOkPeak ? memory_get_peak_usage() : 0);
  534. $this->_DEBUG_stepline(
  535. $name,
  536. number_format(($time - $this->_debugStartTime)*1000, 1, '.', ' ').' ms',
  537. number_format(($time - $this->_debugLastTime)*1000, 1, '.', ' ').' ms',
  538. number_format($usage/1024, 1, '.', ' ').' Ko',
  539. number_format($peak/1024, 1, '.', ' ').' Ko'
  540. );
  541. $this->_debugLastTime = $time;
  542. // it false : DOWN
  543. if ($level===false) $this->_debugLevel--;
  544. return $this;
  545. }
  546. /**
  547. * display a debug line
  548. *
  549. *
  550. * @access protected
  551. * @param string $name
  552. * @param string $timeTotal
  553. * @param string $timeStep
  554. * @param string $memoryUsage
  555. * @param string $memoryPeak
  556. */
  557. protected function _DEBUG_stepline($name, $timeTotal, $timeStep, $memoryUsage, $memoryPeak)
  558. {
  559. $txt = str_pad($name, 30, ' ', STR_PAD_RIGHT).
  560. str_pad($timeTotal, 12, ' ', STR_PAD_LEFT).
  561. str_pad($timeStep, 12, ' ', STR_PAD_LEFT).
  562. str_pad($memoryUsage, 15, ' ', STR_PAD_LEFT).
  563. str_pad($memoryPeak, 15, ' ', STR_PAD_LEFT);
  564. echo '<pre style="padding:0; margin:0">'.$txt.'</pre>';
  565. }
  566. /**
  567. * get the Min and Max X, for Y (use the float margins)
  568. *
  569. * @access protected
  570. * @param float $y
  571. * @return array(float, float)
  572. */
  573. protected function _getMargins($y)
  574. {
  575. $y = floor($y*100);
  576. $x = array($this->pdf->getlMargin(), $this->pdf->getW()-$this->pdf->getrMargin());
  577. foreach ($this->_pageMarges as $mY => $mX)
  578. if ($mY<=$y) $x = $mX;
  579. return $x;
  580. }
  581. /**
  582. * Add margins, for a float
  583. *
  584. * @access protected
  585. * @param string $float (left / right)
  586. * @param float $xLeft
  587. * @param float $yTop
  588. * @param float $xRight
  589. * @param float $yBottom
  590. */
  591. protected function _addMargins($float, $xLeft, $yTop, $xRight, $yBottom)
  592. {
  593. // get the current float margins, for top and bottom
  594. $oldTop = $this->_getMargins($yTop);
  595. $oldBottom = $this->_getMargins($yBottom);
  596. // update the top float margin
  597. if ($float=='left' && $oldTop[0]<$xRight) $oldTop[0] = $xRight;
  598. if ($float=='right' && $oldTop[1]>$xLeft) $oldTop[1] = $xLeft;
  599. $yTop = floor($yTop*100);
  600. $yBottom = floor($yBottom*100);
  601. // erase all the float margins that are smaller than the new one
  602. foreach ($this->_pageMarges as $mY => $mX) {
  603. if ($mY<$yTop) continue;
  604. if ($mY>$yBottom) break;
  605. if ($float=='left' && $this->_pageMarges[$mY][0]<$xRight) unset($this->_pageMarges[$mY]);
  606. if ($float=='right' && $this->_pageMarges[$mY][1]>$xLeft) unset($this->_pageMarges[$mY]);
  607. }
  608. // save the new Top and Bottom margins
  609. $this->_pageMarges[$yTop] = $oldTop;
  610. $this->_pageMarges[$yBottom] = $oldBottom;
  611. // sort the margins
  612. ksort($this->_pageMarges);
  613. // we are just after float
  614. $this->_isAfterFloat = true;
  615. }
  616. /**
  617. * Save old margins (push), and set new ones
  618. *
  619. * @access protected
  620. * @param float $ml left margin
  621. * @param float $mt top margin
  622. * @param float $mr right margin
  623. */
  624. protected function _saveMargin($ml, $mt, $mr)
  625. {
  626. // save old margins
  627. $this->_marges[] = array('l' => $this->pdf->getlMargin(), 't' => $this->pdf->gettMargin(), 'r' => $this->pdf->getrMargin(), 'page' => $this->_pageMarges);
  628. // set new ones
  629. $this->pdf->SetMargins($ml, $mt, $mr);
  630. // prepare for float margins
  631. $this->_pageMarges = array();
  632. $this->_pageMarges[floor($mt*100)] = array($ml, $this->pdf->getW()-$mr);
  633. }
  634. /**
  635. * load the last saved margins (pop)
  636. *
  637. * @access protected
  638. */
  639. protected function _loadMargin()
  640. {
  641. $old = array_pop($this->_marges);
  642. if ($old) {
  643. $ml = $old['l'];
  644. $mt = $old['t'];
  645. $mr = $old['r'];
  646. $mP = $old['page'];
  647. } else {
  648. $ml = $this->_margeLeft;
  649. $mt = 0;
  650. $mr = $this->_margeRight;
  651. $mP = array($mt => array($ml, $this->pdf->getW()-$mr));
  652. }
  653. $this->pdf->SetMargins($ml, $mt, $mr);
  654. $this->_pageMarges = $mP;
  655. }
  656. /**
  657. * save the current maxs (push)
  658. *
  659. * @access protected
  660. */
  661. protected function _saveMax()
  662. {
  663. $this->_maxSave[] = array($this->_maxX, $this->_maxY, $this->_maxH, $this->_maxE);
  664. }
  665. /**
  666. * load the last saved current maxs (pop)
  667. *
  668. * @access protected
  669. */
  670. protected function _loadMax()
  671. {
  672. $old = array_pop($this->_maxSave);
  673. if ($old) {
  674. $this->_maxX = $old[0];
  675. $this->_maxY = $old[1];
  676. $this->_maxH = $old[2];
  677. $this->_maxE = $old[3];
  678. } else {
  679. $this->_maxX = 0;
  680. $this->_maxY = 0;
  681. $this->_maxH = 0;
  682. $this->_maxE = 0;
  683. }
  684. }
  685. /**
  686. * draw the PDF header with the HTML in page_header
  687. *
  688. * @access protected
  689. */
  690. protected function _setPageHeader()
  691. {
  692. if (!count($this->_subHEADER)) return false;
  693. $oldParsePos = $this->_parsePos;
  694. $oldParseCode = $this->parsingHtml->code;
  695. $this->_parsePos = 0;
  696. $this->parsingHtml->code = $this->_subHEADER;
  697. $this->_makeHTMLcode();
  698. $this->_parsePos = $oldParsePos;
  699. $this->parsingHtml->code = $oldParseCode;
  700. }
  701. /**
  702. * draw the PDF footer with the HTML in page_footer
  703. *
  704. * @access protected
  705. */
  706. protected function _setPageFooter()
  707. {
  708. if (!count($this->_subFOOTER)) return false;
  709. $oldParsePos = $this->_parsePos;
  710. $oldParseCode = $this->parsingHtml->code;
  711. $this->_parsePos = 0;
  712. $this->parsingHtml->code = $this->_subFOOTER;
  713. $this->_isInFooter = true;
  714. $this->_makeHTMLcode();
  715. $this->_isInFooter = false;
  716. $this->_parsePos = $oldParsePos;
  717. $this->parsingHtml->code = $oldParseCode;
  718. }
  719. /**
  720. * new line, with a specific height
  721. *
  722. * @access protected
  723. * @param float $h
  724. * @param integer $curr real current position in the text, if new line in the write of a text
  725. */
  726. protected function _setNewLine($h, $curr = null)
  727. {
  728. $this->pdf->Ln($h);
  729. $this->_setNewPositionForNewLine($curr);
  730. }
  731. /**
  732. * calculate the start position of the next line, depending on the text-align
  733. *
  734. * @access protected
  735. * @param integer $curr real current position in the text, if new line in the write of a text
  736. */
  737. protected function _setNewPositionForNewLine($curr = null)
  738. {
  739. // get the margins for the current line
  740. list($lx, $rx) = $this->_getMargins($this->pdf->getY());
  741. $this->pdf->setX($lx);
  742. $wMax = $rx-$lx;
  743. $this->_currentH = 0;
  744. // if subPart => return because align left
  745. if ($this->_subPart || $this->_isSubPart || $this->_isForOneLine) {
  746. $this->pdf->setWordSpacing(0);
  747. return null;
  748. }
  749. // create the sub object
  750. $sub = null;
  751. $this->_createSubHTML($sub);
  752. $sub->_saveMargin(0, 0, $sub->pdf->getW()-$wMax);
  753. $sub->_isForOneLine = true;
  754. $sub->_parsePos = $this->_parsePos;
  755. $sub->parsingHtml->code = $this->parsingHtml->code;
  756. // if $curr => adapt the current position of the parsing
  757. if ($curr!==null && $sub->parsingHtml->code[$this->_parsePos]['name']=='write') {
  758. $txt = $sub->parsingHtml->code[$this->_parsePos]['param']['txt'];
  759. $txt = str_replace('[[page_cu]]', $sub->pdf->getMyNumPage($this->_page), $txt);
  760. $sub->parsingHtml->code[$this->_parsePos]['param']['txt'] = substr($txt, $curr+1);
  761. } else
  762. $sub->_parsePos++;
  763. // for each element of the parsing => load the action
  764. $res = null;
  765. for ($sub->_parsePos; $sub->_parsePos<count($sub->parsingHtml->code); $sub->_parsePos++) {
  766. $action = $sub->parsingHtml->code[$sub->_parsePos];
  767. $res = $sub->_executeAction($action);
  768. if (!$res) break;
  769. }
  770. $w = $sub->_maxX; // max width
  771. $h = $sub->_maxH; // max height
  772. $e = ($res===null ? $sub->_maxE : 0); // maxnumber of elemets on the line
  773. // destroy the sub HTML
  774. $this->_destroySubHTML($sub);
  775. // adapt the start of the line, depending on the text-align
  776. if ($this->parsingCss->value['text-align']=='center')
  777. $this->pdf->setX(($rx+$this->pdf->getX()-$w)*0.5-0.01);
  778. else if ($this->parsingCss->value['text-align']=='right')
  779. $this->pdf->setX($rx-$w-0.01);
  780. else
  781. $this->pdf->setX($lx);
  782. // set the height of the line
  783. $this->_currentH = $h;
  784. // if justify => set the word spacing
  785. if ($this->parsingCss->value['text-align']=='justify' && $e>1) {
  786. $this->pdf->setWordSpacing(($wMax-$w)/($e-1));
  787. } else {
  788. $this->pdf->setWordSpacing(0);
  789. }
  790. }
  791. /**
  792. * prepare HTML2PDF::$_subobj (used for create the sub HTML2PDF objects
  793. *
  794. * @access protected
  795. */
  796. protected function _prepareSubObj()
  797. {
  798. $pdf = null;
  799. // create the sub object
  800. HTML2PDF::$_subobj = new HTML2PDF(
  801. $this->_orientation,
  802. $this->_format,
  803. $this->_langue,
  804. $this->_unicode,
  805. $this->_encoding,
  806. array($this->_defaultLeft,$this->_defaultTop,$this->_defaultRight,$this->_defaultBottom)
  807. );
  808. // init
  809. HTML2PDF::$_subobj->setTestTdInOnePage($this->_testTdInOnepage);
  810. HTML2PDF::$_subobj->setTestIsImage($this->_testIsImage);
  811. HTML2PDF::$_subobj->setTestIsDeprecated($this->_testIsDeprecated);
  812. HTML2PDF::$_subobj->setDefaultFont($this->_defaultFont);
  813. HTML2PDF::$_subobj->parsingCss->css = &$this->parsingCss->css;
  814. HTML2PDF::$_subobj->parsingCss->cssKeys = &$this->parsingCss->cssKeys;
  815. // clone font from the original PDF
  816. HTML2PDF::$_subobj->pdf->cloneFontFrom($this->pdf);
  817. // remove the link to the parent
  818. HTML2PDF::$_subobj->parsingCss->setPdfParent($pdf);
  819. }
  820. /**
  821. * create a sub HTML2PDF, to calculate the multi-tables
  822. *
  823. * @access protected
  824. * @param &HTML2PDF $subHtml sub HTML2PDF to create
  825. * @param integer $cellmargin if in a TD : cellmargin of this td
  826. */
  827. protected function _createSubHTML(&$subHtml, $cellmargin=0)
  828. {
  829. // prepare the subObject, if never prepare before
  830. if (HTML2PDF::$_subobj===null) {
  831. $this->_prepareSubObj();
  832. }
  833. // calculate the width to use
  834. if ($this->parsingCss->value['width']) {
  835. $marge = $cellmargin*2;
  836. $marge+= $this->parsingCss->value['padding']['l'] + $this->parsingCss->value['padding']['r'];
  837. $marge+= $this->parsingCss->value['border']['l']['width'] + $this->parsingCss->value['border']['r']['width'];
  838. $marge = $this->pdf->getW() - $this->parsingCss->value['width'] + $marge;
  839. } else {
  840. $marge = $this->_margeLeft+$this->_margeRight;
  841. }
  842. // BUGFIX : we have to call the method, because of a bug in php 5.1.6
  843. HTML2PDF::$_subobj->pdf->getPage();
  844. // clone the sub oject
  845. $subHtml = clone HTML2PDF::$_subobj;
  846. $subHtml->parsingCss->table = $this->parsingCss->table;
  847. $subHtml->parsingCss->value = $this->parsingCss->value;
  848. $subHtml->initSubHtml(
  849. $this->_format,
  850. $this->_orientation,
  851. $marge,
  852. $this->_page,
  853. $this->_defList,
  854. $this->pdf->getMyLastPageGroup(),
  855. $this->pdf->getMyLastPageGroupNb()
  856. );
  857. }
  858. /**
  859. * destroy a subHTML2PDF
  860. *
  861. * @access protected
  862. */
  863. protected function _destroySubHTML(&$subHtml)
  864. {
  865. unset($subHtml);
  866. $subHtml = null;
  867. }
  868. /**
  869. * Convert a arabic number in roman number
  870. *
  871. * @access protected
  872. * @param integer $nbArabic
  873. * @return string $nbRoman
  874. */
  875. protected function _listeArab2Rom($nbArabic)
  876. {
  877. $nbBaseTen = array('I','X','C','M');
  878. $nbBaseFive = array('V','L','D');
  879. $nbRoman = '';
  880. if ($nbArabic<1) return $nbArabic;
  881. if ($nbArabic>3999) return $nbArabic;
  882. for ($i=3; $i>=0 ; $i--) {
  883. $chiffre=floor($nbArabic/pow(10, $i));
  884. if ($chiffre>=1) {
  885. $nbArabic=$nbArabic-$chiffre*pow(10, $i);
  886. if ($chiffre<=3) {
  887. for ($j=$chiffre; $j>=1; $j--) {
  888. $nbRoman=$nbRoman.$nbBaseTen[$i];
  889. }
  890. } else if ($chiffre==9) {
  891. $nbRoman=$nbRoman.$nbBaseTen[$i].$nbBaseTen[$i+1];
  892. } else if ($chiffre==4) {
  893. $nbRoman=$nbRoman.$nbBaseTen[$i].$nbBaseFive[$i];
  894. } else {
  895. $nbRoman=$nbRoman.$nbBaseFive[$i];
  896. for ($j=$chiffre-5; $j>=1; $j--) {
  897. $nbRoman=$nbRoman.$nbBaseTen[$i];
  898. }
  899. }
  900. }
  901. }
  902. return $nbRoman;
  903. }
  904. /**
  905. * add a LI to the current level
  906. *
  907. * @access protected
  908. */
  909. protected function _listeAddLi()
  910. {
  911. $this->_defList[count($this->_defList)-1]['nb']++;
  912. }
  913. /**
  914. * get the width to use for the column of the list
  915. *
  916. * @access protected
  917. * @return string $width
  918. */
  919. protected function _listeGetWidth()
  920. {
  921. return '7mm';
  922. }
  923. /**
  924. * get the padding to use for the column of the list
  925. *
  926. * @access protected
  927. * @return string $padding
  928. */
  929. protected function _listeGetPadding()
  930. {
  931. return '1mm';
  932. }
  933. /**
  934. * get the information of the li on the current level
  935. *
  936. * @access protected
  937. * @return array(fontName, small size, string)
  938. */
  939. protected function _listeGetLi()
  940. {
  941. $im = $this->_defList[count($this->_defList)-1]['img'];
  942. $st = $this->_defList[count($this->_defList)-1]['style'];
  943. $nb = $this->_defList[count($this->_defList)-1]['nb'];
  944. $up = (substr($st, 0, 6)=='upper-');
  945. if ($im) return array(false, false, $im);
  946. switch($st)
  947. {
  948. case 'none':
  949. return array('helvetica', true, ' ');
  950. case 'upper-alpha':
  951. case 'lower-alpha':
  952. $str = '';
  953. while ($nb>26) {
  954. $str = chr(96+$nb%26).$str;
  955. $nb = floor($nb/26);
  956. }
  957. $str = chr(96+$nb).$str;
  958. return array('helvetica', false, ($up ? strtoupper($str) : $str).'.');
  959. case 'upper-roman':
  960. case 'lower-roman':
  961. $str = $this->_listeArab2Rom($nb);
  962. return array('helvetica', false, ($up ? strtoupper($str) : $str).'.');
  963. case 'decimal':
  964. return array('helvetica', false, $nb.'.');
  965. case 'square':
  966. return array('zapfdingbats', true, chr(110));
  967. case 'circle':
  968. return array('zapfdingbats', true, chr(109));
  969. case 'disc':
  970. default:
  971. return array('zapfdingbats', true, chr(108));
  972. }
  973. }
  974. /**
  975. * add a level to the list
  976. *
  977. * @access protected
  978. * @param string $type : ul, ol
  979. * @param string $style : lower-alpha, ...
  980. * @param string $img
  981. */
  982. protected function _listeAddLevel($type = 'ul', $style = '', $img = null)
  983. {
  984. // get the url of the image, if we want to use a image
  985. if ($img) {
  986. if (preg_match('/^url\(([^)]+)\)$/isU', trim($img), $match)) {
  987. $img = $match[1];
  988. } else {
  989. $img = null;
  990. }
  991. } else {
  992. $img = null;
  993. }
  994. // prepare the datas
  995. if (!in_array($type, array('ul', 'ol'))) $type = 'ul';
  996. if (!in_array($style, array('lower-alpha', 'upper-alpha', 'upper-roman', 'lower-roman', 'decimal', 'square', 'circle', 'disc', 'none'))) $style = '';
  997. if (!$style) {
  998. if ($type=='ul') $style = 'disc';
  999. else $style = 'decimal';
  1000. }
  1001. // add the new level
  1002. $this->_defList[count($this->_defList)] = array('style' => $style, 'nb' => 0, 'img' => $img);
  1003. }
  1004. /**
  1005. * remove a level to the list
  1006. *
  1007. * @access protected
  1008. */
  1009. protected function _listeDelLevel()
  1010. {
  1011. if (count($this->_defList)) {
  1012. unset($this->_defList[count($this->_defList)-1]);
  1013. $this->_defList = array_values($this->_defList);
  1014. }
  1015. }
  1016. /**
  1017. * execute the actions to convert the html
  1018. *
  1019. * @access protected
  1020. */
  1021. protected function _makeHTMLcode()
  1022. {
  1023. // foreach elements of the parsing
  1024. for ($this->_parsePos=0; $this->_parsePos<count($this->parsingHtml->code); $this->_parsePos++) {
  1025. // get the action to do
  1026. $action = $this->parsingHtml->code[$this->_parsePos];
  1027. // if it is a opening of table / ul / ol
  1028. if (in_array($action['name'], array('table', 'ul', 'ol')) && !$action['close']) {
  1029. // we will work as a sub HTML to calculate the size of the element
  1030. $this->_subPart = true;
  1031. // get the name of the opening tag
  1032. $tagOpen = $action['name'];
  1033. // save the actual pos on the parsing
  1034. $this->_tempPos = $this->_parsePos;
  1035. // foreach elements, while we are in the opened tag
  1036. while (isset($this->parsingHtml->code[$this->_tempPos]) && !($this->parsingHtml->code[$this->_tempPos]['name']==$tagOpen && $this->parsingHtml->code[$this->_tempPos]['close'])) {
  1037. // make the action
  1038. $this->_executeAction($this->parsingHtml->code[$this->_tempPos]);
  1039. $this->_tempPos++;
  1040. }
  1041. // execute the closure of the tag
  1042. if (isset($this->parsingHtml->code[$this->_tempPos])) {
  1043. $this->_executeAction($this->parsingHtml->code[$this->_tempPos]);
  1044. }
  1045. // end of the sub part
  1046. $this->_subPart = false;
  1047. }
  1048. // execute the action
  1049. $this->_executeAction($action);
  1050. }
  1051. }
  1052. /**
  1053. * execute the action from the parsing
  1054. *
  1055. * @access protected
  1056. * @param array $action
  1057. */
  1058. protected function _executeAction($action)
  1059. {
  1060. // name of the action
  1061. $fnc = ($action['close'] ? '_tag_close_' : '_tag_open_').strtoupper($action['name']);
  1062. // parameters of the action
  1063. $param = $action['param'];
  1064. // if it the first action of the first page, and if it is not a open tag of PAGE => create the new page
  1065. if ($fnc!='_tag_open_PAGE' && $this->_firstPage) {
  1066. $this->_setNewPage();
  1067. }
  1068. // the action must exist
  1069. if (!is_callable(array(&$this, $fnc))) {
  1070. throw new HTML2PDF_exception(1, strtoupper($action['name']), $this->parsingHtml->getHtmlErrorCode($action['html_pos']));
  1071. }
  1072. // lauch the action
  1073. $res = $this->{$fnc}($param);
  1074. // save the name of the action
  1075. $this->_previousCall = $fnc;
  1076. // return the result
  1077. return $res;
  1078. }
  1079. /**
  1080. * get the position of the element on the current line, depending on his height
  1081. *
  1082. * @access protected
  1083. * @param float $h
  1084. * @return float
  1085. */
  1086. protected function _getElementY($h)
  1087. {
  1088. if ($this->_subPart || $this->_isSubPart || !$this->_currentH || $this->_currentH<$h)
  1089. return 0;
  1090. return ($this->_currentH-$h)*0.8;
  1091. }
  1092. /**
  1093. * make a break line
  1094. *
  1095. * @access protected
  1096. * @param float $h current line height
  1097. * @param integer $curr real current position in the text, if new line in the write of a text
  1098. */
  1099. protected function _makeBreakLine($h, $curr = null)
  1100. {
  1101. if ($h) {
  1102. if (($this->pdf->getY()+$h<$this->pdf->getH() - $this->pdf->getbMargin()) || $this->_isInOverflow || $this->_isInFooter)
  1103. $this->_setNewLine($h, $curr);
  1104. else
  1105. $this->_setNewPage(null, '', null, $curr);
  1106. } else {
  1107. $this->_setNewPositionForNewLine($curr);
  1108. }
  1109. $this->_maxH = 0;
  1110. $this->_maxE = 0;
  1111. }
  1112. /**
  1113. * display a image
  1114. *
  1115. * @access protected
  1116. * @param string $src
  1117. * @param boolean $subLi if true=image of a list
  1118. * @return boolean depending on "isForOneLine"
  1119. */
  1120. protected function _drawImage($src, $subLi=false)
  1121. {
  1122. // get the size of the image
  1123. // WARNING : if URL, "allow_url_fopen" must turned to "on" in php.ini
  1124. $infos=@getimagesize($src);
  1125. // if the image does not exist, or can not be loaded
  1126. if (count($infos)<2) {
  1127. // if the test is activ => exception
  1128. if ($this->_testIsImage) {
  1129. throw new HTML2PDF_exception(6, $src);
  1130. }
  1131. // else, display a gray rectangle
  1132. $src = null;
  1133. $infos = array(16, 16);
  1134. }
  1135. // convert the …

Large files files are truncated, but you can click here to view the full file