PageRenderTime 74ms CodeModel.GetById 38ms RepoModel.GetById 0ms app.codeStats 2ms

/common/libraries/plugin/html2pdf/html2pdf.class.php

https://bitbucket.org/renaatdemuynck/chamilo
PHP | 6528 lines | 4448 code | 863 blank | 1217 comment | 748 complexity | 5f659e18d7f4af2877b8f9e0b0c52f61 MD5 | raw file
Possible License(s): BSD-3-Clause, LGPL-2.1, LGPL-3.0, GPL-3.0, MIT, GPL-2.0

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

  1. <?php
  2. /**
  3. * Logiciel : HTML2PDF
  4. *
  5. * Convertisseur HTML => PDF, utilise TCPDF
  6. * Distribu� sous la licence LGPL.
  7. *
  8. * @author Laurent MINGUET <webmaster@html2pdf.fr>
  9. * @version 4.00
  10. */
  11. if (! defined('__CLASS_HTML2PDF__'))
  12. {
  13. define('__CLASS_HTML2PDF__', '4.00');
  14. require_once (dirname(__FILE__) . '/_mypdf/mypdf.class.php'); // classe mypdf
  15. require_once (dirname(__FILE__) . '/parsingHTML.class.php'); // classe de parsing HTML
  16. require_once (dirname(__FILE__) . '/styleHTML.class.php'); // classe de gestion des styles
  17. class HTML2PDF
  18. {
  19. public $pdf = null; // objet PDF
  20. public $style = null; // objet de style
  21. public $parsing = null; // objet de parsing
  22. protected $langue = 'fr'; // langue des messages
  23. protected $sens = 'P'; // sens d'affichage Portrait ou Landscape
  24. protected $format = 'A4'; // format de la page : A4, A3, ...
  25. protected $encoding = ''; // charset encoding
  26. protected $unicode = true; // means that the input text is unicode (default = true)
  27. protected $background = array(); // informations sur le background
  28. protected $testTDin1page = true; // activer le test de TD ne devant pas depasser une page
  29. protected $testIsImage = true; // test si les images existes ou non
  30. protected $isSubPart = false; // indique que le convertisseur courant est un sous html
  31. protected $parse_pos = 0; // position du parsing
  32. protected $temp_pos = 0; // position temporaire pour multi tableau
  33. protected $page = 0; // numero de la page courante
  34. protected $sub_html = null; // sous html
  35. protected $sub_part = false; // indicateur de sous html
  36. protected $maxX = 0; // zone maxi X
  37. protected $maxY = 0; // zone maxi Y
  38. protected $maxE = 0; // nomre d'elements dans la zone
  39. protected $maxH = 0; // plus grande hauteur dans la ligne, pour saut de ligne � corriger
  40. protected $maxSave = array(); // tableau de sauvegarde des maximaux
  41. protected $currentH = 0; // hauteur de la ligne courante
  42. protected $firstPage = true; // premier page
  43. protected $defaultLeft = 0; // marges par default de la page
  44. protected $defaultTop = 0;
  45. protected $defaultRight = 0;
  46. protected $defaultBottom = 0;
  47. protected $margeLeft = 0; //marges r�elles de la page
  48. protected $margeTop = 0;
  49. protected $margeRight = 0;
  50. protected $margeBottom = 0;
  51. protected $marges = array(); // tableau de sauvegarde des differents etats des marges de la page courante
  52. protected $inLink = ''; // indique si on est � l'interieur d'un lien
  53. protected $lstAncre = array(); // liste des ancres d�tect�es ou cr��es
  54. protected $subHEADER = array(); // tableau des sous commandes pour faire l'HEADER
  55. protected $subFOOTER = array(); // tableau des sous commandes pour faire le FOOTER
  56. protected $subSTATES = array(); // tableau de sauvegarde de certains param�tres
  57. protected $defLIST = array(); // tableau de sauvegarde de l'etat des UL et OL
  58. protected $lstChamps = array(); // liste des champs
  59. protected $lstSelect = array(); // options du select en cours
  60. protected $previousCall = null; // dernier appel
  61. protected $pageMarges = array(); // marges sp�cifiques dues aux floats
  62. protected $isInThead = false; // indique si on est dans un thead
  63. protected $isInTfoot = false; // indique si on est dans un tfoot
  64. protected $isInOverflow = false; // indique si on est dans une div overflow
  65. protected $isInFooter = false; // indique si on est dans un footer ou non
  66. protected $isInDraw = null; // indique si on est en mode dessin
  67. protected $isAfterFloat = false; // indique si on est apres un float
  68. protected $forOneLine = false; // indique si on est dans un sous HTML ne servant qu'a calculer la taille de la prochaine ligne
  69. protected $isInForm = false; // indique si on est dans un formulaire. Contient dans ce cas l� l'action de celui-ci
  70. protected $DEBUG_actif = false; // indique si on est en mode debug
  71. protected $DEBUG_ok_usage = false; // indique l'existance de la fonction memory_get_usage
  72. protected $DEBUG_ok_peak = false; // indique l'existance de la fonction memory_get_peak_usage
  73. protected $DEBUG_level = 0; // niveau du debug
  74. protected $DEBUG_start_time = 0; //
  75. protected $DEBUG_last_time = 0; //
  76. protected $defaultFont = null; // fonte par d�faut si la fonte demand�e n'existe pas
  77. protected static $SUBOBJ = null; // sous objet HTML2PDF pr�par� en cas de besoin
  78. protected static $TABLES = array(); // tableau global necessaire � la gestion des tables imbriqu�es
  79. protected static $TEXTES = array(); // tableau comprennant le fichier de langue
  80. /**
  81. * Constructeur
  82. *
  83. * @param string sens portrait ou landscape
  84. * @param string format A4, A5, ...
  85. * @param string langue : fr, en, it...
  86. * @param boolean $unicode TRUE means that the input text is unicode (default = true)
  87. * @param String $encoding charset encoding; default is UTF-8
  88. * @param array marges par defaut, dans l'ordre (left, top, right, bottom)
  89. * @return null
  90. */
  91. public function __construct($sens = 'P', $format = 'A4', $langue = 'fr', $unicode = true, $encoding = 'UTF-8', $marges = array(5, 5, 5, 8))
  92. {
  93. // sauvegarde des param�tres
  94. $this->page = 0;
  95. $this->sens = $sens;
  96. $this->format = $format;
  97. $this->unicode = $unicode;
  98. $this->encoding = $encoding;
  99. $this->firstPage = true;
  100. $this->langue = strtolower($langue);
  101. // chargement du fichier de langue
  102. HTML2PDF :: textLOAD($this->langue);
  103. // cr�ation de l' objet PDF
  104. $this->pdf = new MyPDF($sens, 'mm', $format, $unicode, $encoding);
  105. // initialisation des styles
  106. $this->style = new styleHTML($this->pdf);
  107. $this->style->FontSet();
  108. $this->defLIST = array();
  109. // initialisations diverses
  110. $this->setTestTdInOnePage(true);
  111. $this->setTestIsImage(true);
  112. $this->setDefaultFont(null);
  113. // initialisation du parsing
  114. $this->parsing = new parsingHTML($this->encoding);
  115. $this->sub_html = null;
  116. $this->sub_part = false;
  117. // initialisation des marges
  118. if (! is_array($marges))
  119. $marges = array($marges, $marges, $marges, $marges);
  120. $this->setDefaultMargins($marges[0], $marges[1], $marges[2], $marges[3]);
  121. $this->setMargins();
  122. $this->marges = array();
  123. // initialisation des champs de formulaire
  124. $this->lstChamps = array();
  125. }
  126. /**
  127. * Destructeur
  128. *
  129. * @return null
  130. */
  131. public function __destruct()
  132. {
  133. }
  134. /**
  135. * activer le debug mode
  136. *
  137. * @return null
  138. */
  139. public function setModeDebug()
  140. {
  141. list($usec, $sec) = explode(' ', microtime());
  142. $this->DEBUG_actif = true;
  143. $this->DEBUG_ok_usage = function_exists('memory_get_usage');
  144. $this->DEBUG_ok_peak = function_exists('memory_get_peak_usage');
  145. $this->DEBUG_start_time = (float) $sec + (float) $usec;
  146. $this->DEBUG_last_time = (float) $sec + (float) $usec;
  147. $this->DEBUG_stepline('step', 'time', 'delta', 'memory', 'peak');
  148. $this->DEBUG_add('Init debug');
  149. }
  150. /**
  151. * rajouter une ligne de debug
  152. *
  153. * @param string nom de l'etape
  154. * @param boolean true=monter d'un niveau, false=descendre d'un niveau, null : ne rien faire
  155. * @return null
  156. */
  157. protected function DEBUG_add($nom, $level = null)
  158. {
  159. list($usec, $sec) = explode(' ', microtime());
  160. if ($level === true)
  161. $this->DEBUG_level ++;
  162. $nom = str_repeat(' ', $this->DEBUG_level) . $nom . ($level === true ? ' Begin' : ($level === false ? ' End' : ''));
  163. $time = (float) $sec + (float) $usec;
  164. $usage = ($this->DEBUG_ok_usage ? memory_get_usage() : 0);
  165. $peak = ($this->DEBUG_ok_peak ? memory_get_peak_usage() : 0);
  166. $this->DEBUG_stepline($nom, number_format(($time - $this->DEBUG_start_time) * 1000, 1, '.', ' ') . ' ms', number_format(($time - $this->DEBUG_last_time) * 1000, 1, '.', ' ') . ' ms', number_format($usage / 1024, 1, '.', ' ') . ' Ko', number_format($peak / 1024, 1, '.', ' ') . ' Ko');
  167. $this->DEBUG_last_time = $time;
  168. if ($level === false)
  169. $this->DEBUG_level --;
  170. return true;
  171. }
  172. /**
  173. * affiche une ligne de debug
  174. *
  175. * @param string nom de l'etape
  176. * @param string valeur 1
  177. * @param string valeur 2
  178. * @param string valeur 3
  179. * @param string valeur 4
  180. * @return null
  181. */
  182. protected function DEBUG_stepline($nom, $val1, $val2, $val3, $val4)
  183. {
  184. $txt = str_pad($nom, 30, ' ', STR_PAD_RIGHT) . str_pad($val1, 12, ' ', STR_PAD_LEFT) . str_pad($val2, 12, ' ', STR_PAD_LEFT) . str_pad($val3, 15, ' ', STR_PAD_LEFT) . str_pad($val4, 15, ' ', STR_PAD_LEFT);
  185. echo '<pre style="padding:0; margin:0">' . $txt . '</pre>';
  186. }
  187. /**
  188. * activer ou desactiver le test de TD ne devant pas depasser une page
  189. *
  190. * @param boolean nouvel etat
  191. * @return boolean ancien etat
  192. */
  193. public function setTestTdInOnePage($mode = true)
  194. {
  195. $old = $this->testTDin1page;
  196. $this->testTDin1page = $mode ? true : false;
  197. return $old;
  198. }
  199. /**
  200. * activer ou desactiver le test sur la pr�sence des images
  201. *
  202. * @param boolean nouvel etat
  203. * @return boolean ancien etat
  204. */
  205. public function setTestIsImage($mode = true)
  206. {
  207. $old = $this->testIsImage;
  208. $this->testIsImage = $mode ? true : false;
  209. return $old;
  210. }
  211. /**
  212. * d�finit la fonte par d�faut si aucun fonte n'est sp�cifi�e, ou si la fonte demand�e n'existe pas
  213. *
  214. * @param string nom de la fonte par defaut. si null : Arial pour fonte non sp�cifi�e, et erreur pour fonte non existante
  215. * @return string nom de l'ancienne fonte par defaut
  216. */
  217. public function setDefaultFont($default = null)
  218. {
  219. $old = $this->defaultFont;
  220. $this->defaultFont = $default;
  221. $this->style->setDefaultFont($default);
  222. return $old;
  223. }
  224. /**
  225. * d�finir les marges par d�fault
  226. *
  227. * @param int en mm, marge left
  228. * @param int en mm, marge top
  229. * @param int en mm, marge right. si null, left=right
  230. * @param int en mm, marge bottom. si null, bottom=8
  231. * @return null
  232. */
  233. protected function setDefaultMargins($left, $top, $right = null, $bottom = null)
  234. {
  235. if ($right === null)
  236. $right = $left;
  237. if ($bottom === null)
  238. $bottom = 8;
  239. $this->defaultLeft = $this->style->ConvertToMM($left . 'mm');
  240. $this->defaultTop = $this->style->ConvertToMM($top . 'mm');
  241. $this->defaultRight = $this->style->ConvertToMM($right . 'mm');
  242. $this->defaultBottom = $this->style->ConvertToMM($bottom . 'mm');
  243. }
  244. /**
  245. * d�finir les marges r�elles, fonctions de la balise page
  246. *
  247. * @return null
  248. */
  249. protected function setMargins()
  250. {
  251. $this->margeLeft = $this->defaultLeft + (isset($this->background['left']) ? $this->background['left'] : 0);
  252. $this->margeRight = $this->defaultRight + (isset($this->background['right']) ? $this->background['right'] : 0);
  253. $this->margeTop = $this->defaultTop + (isset($this->background['top']) ? $this->background['top'] : 0);
  254. $this->margeBottom = $this->defaultBottom + (isset($this->background['bottom']) ? $this->background['bottom'] : 0);
  255. $this->pdf->SetMargins($this->margeLeft, $this->margeTop, $this->margeRight);
  256. $this->pdf->setcMargin(0);
  257. $this->pdf->SetAutoPageBreak(false, $this->margeBottom);
  258. $this->pageMarges = array();
  259. $this->pageMarges[floor($this->margeTop * 100)] = array($this->margeLeft,
  260. $this->pdf->getW() - $this->margeRight);
  261. }
  262. /**
  263. * recuperer les positions x minimales et maximales en fonction d'une hauteur
  264. *
  265. * @param float y
  266. * @return array(float, float)
  267. */
  268. protected function getMargins($y)
  269. {
  270. $y = floor($y * 100);
  271. $x = array($this->pdf->getlMargin(), $this->pdf->getW() - $this->pdf->getrMargin());
  272. foreach ($this->pageMarges as $m_y => $m_x)
  273. if ($m_y <= $y)
  274. $x = $m_x;
  275. return $x;
  276. }
  277. /**
  278. * ajouter une marge suite a un float
  279. *
  280. * @param string left ou right
  281. * @param float x1
  282. * @param float y1
  283. * @param float x2
  284. * @param float y2
  285. * @return null
  286. */
  287. protected function addMargins($float, $x1, $y1, $x2, $y2)
  288. {
  289. $old1 = $this->getMargins($y1);
  290. $old2 = $this->getMargins($y2);
  291. if ($float == 'left')
  292. $old1[0] = $x2;
  293. if ($float == 'right')
  294. $old1[1] = $x1;
  295. $y1 = floor($y1 * 100);
  296. $y2 = floor($y2 * 100);
  297. foreach ($this->pageMarges as $m_y => $m_x)
  298. {
  299. if ($m_y < $y1)
  300. continue;
  301. if ($m_y > $y2)
  302. break;
  303. if ($float == 'left' && $this->pageMarges[$m_y][0] < $x2)
  304. unset($this->pageMarges[$m_y]);
  305. if ($float == 'right' && $this->pageMarges[$m_y][1] > $x1)
  306. unset($this->pageMarges[$m_y]);
  307. }
  308. $this->pageMarges[$y1] = $old1;
  309. $this->pageMarges[$y2] = $old2;
  310. ksort($this->pageMarges);
  311. $this->isAfterFloat = true;
  312. }
  313. /**
  314. * d�finir des nouvelles marges et sauvegarder les anciennes
  315. *
  316. * @param float marge left
  317. * @param float marge top
  318. * @param float marge right
  319. * @return null
  320. */
  321. protected function saveMargin($ml, $mt, $mr)
  322. {
  323. $this->marges[] = array('l' => $this->pdf->getlMargin(), 't' => $this->pdf->gettMargin(),
  324. 'r' => $this->pdf->getrMargin(), 'page' => $this->pageMarges);
  325. $this->pdf->SetMargins($ml, $mt, $mr);
  326. $this->pageMarges = array();
  327. $this->pageMarges[floor($mt * 100)] = array($ml, $this->pdf->getW() - $mr);
  328. }
  329. /**
  330. * r�cuperer les derni�res marches sauv�es
  331. *
  332. * @return null
  333. */
  334. protected function loadMargin()
  335. {
  336. $old = array_pop($this->marges);
  337. if ($old)
  338. {
  339. $ml = $old['l'];
  340. $mt = $old['t'];
  341. $mr = $old['r'];
  342. $mP = $old['page'];
  343. }
  344. else
  345. {
  346. $ml = $this->margeLeft;
  347. $mt = 0;
  348. $mr = $this->margeRight;
  349. $mP = array($mt => array($ml, $this->pdf->getW() - $mr));
  350. }
  351. $this->pdf->SetMargins($ml, $mt, $mr);
  352. $this->pageMarges = $mP;
  353. }
  354. /**
  355. * permet d'ajouter une fonte.
  356. *
  357. * @param string nom de la fonte
  358. * @param string style de la fonte
  359. * @param string fichier de la fonte
  360. * @return null
  361. */
  362. public function addFont($family, $style = '', $file = '')
  363. {
  364. $this->pdf->AddFont($family, $style, $file);
  365. }
  366. /**
  367. * sauvegarder l'�tat actuelle des maximums
  368. *
  369. * @return null
  370. */
  371. protected function saveMax()
  372. {
  373. $this->maxSave[] = array($this->maxX, $this->maxY, $this->maxH, $this->maxE);
  374. }
  375. /**
  376. * charger le dernier �tat sauv� des maximums
  377. *
  378. * @return null
  379. */
  380. protected function loadMax()
  381. {
  382. $old = array_pop($this->maxSave);
  383. if ($old)
  384. {
  385. $this->maxX = $old[0];
  386. $this->maxY = $old[1];
  387. $this->maxH = $old[2];
  388. $this->maxE = $old[3];
  389. }
  390. else
  391. {
  392. $this->maxX = 0;
  393. $this->maxY = 0;
  394. $this->maxH = 0;
  395. $this->maxE = 0;
  396. }
  397. }
  398. /**
  399. * afficher l'header contenu dans page_header
  400. *
  401. * @return null
  402. */
  403. protected function setPageHeader()
  404. {
  405. if (! count($this->subHEADER))
  406. return false;
  407. $OLD_parse_pos = $this->parse_pos;
  408. $OLD_parse_code = $this->parsing->code;
  409. $this->parse_pos = 0;
  410. $this->parsing->code = $this->subHEADER;
  411. $this->makeHTMLcode();
  412. $this->parse_pos = $OLD_parse_pos;
  413. $this->parsing->code = $OLD_parse_code;
  414. }
  415. /**
  416. * afficher le footer contenu dans page_footer
  417. *
  418. * @return null
  419. */
  420. protected function setPageFooter()
  421. {
  422. if (! count($this->subFOOTER))
  423. return false;
  424. $OLD_parse_pos = $this->parse_pos;
  425. $OLD_parse_code = $this->parsing->code;
  426. $this->parse_pos = 0;
  427. $this->parsing->code = $this->subFOOTER;
  428. $this->isInFooter = true;
  429. $this->makeHTMLcode();
  430. $this->isInFooter = false;
  431. $this->parse_pos = $OLD_parse_pos;
  432. $this->parsing->code = $OLD_parse_code;
  433. }
  434. /**
  435. * saut de ligne avec une hauteur sp�cifique
  436. *
  437. * @param float hauteur de la ligne
  438. * @param integer position reelle courante si saut de ligne pendant l'ecriture d'un texte
  439. * @return null
  440. */
  441. protected function setNewLine($h, $curr = null)
  442. {
  443. $this->pdf->Ln($h);
  444. $this->setNewPositionForNewLine($curr);
  445. }
  446. /**
  447. * cr�ation d'une nouvelle page avec le format et l'orientation sp�cifies
  448. *
  449. * @param mixed format de la page : A5, A4, array(width, height)
  450. * @param string sens P=portrait ou L=landscape
  451. * @param array tableau des propri�t�s du fond de la page
  452. * @param integer position reelle courante si saut de ligne pendant l'ecriture d'un texte
  453. * @return null
  454. */
  455. public function setNewPage($format = null, $orientation = '', $background = null, $curr = null)
  456. {
  457. $this->firstPage = false;
  458. $this->format = $format ? $format : $this->format;
  459. $this->sens = $orientation ? $orientation : $this->sens;
  460. $this->background = $background !== null ? $background : $this->background;
  461. $this->maxY = 0;
  462. $this->maxX = 0;
  463. $this->maxH = 0;
  464. $this->pdf->SetMargins($this->defaultLeft, $this->defaultTop, $this->defaultRight);
  465. $this->pdf->AddPage($this->sens, $this->format);
  466. $this->page ++;
  467. if (! $this->sub_part && ! $this->isSubPart)
  468. {
  469. if (is_array($this->background))
  470. {
  471. if (isset($this->background['color']) && $this->background['color'])
  472. {
  473. $this->pdf->setFillColorArray($this->background['color']);
  474. $this->pdf->Rect(0, 0, $this->pdf->getW(), $this->pdf->getH(), 'F');
  475. }
  476. if (isset($this->background['img']) && $this->background['img'])
  477. $this->pdf->Image($this->background['img'], $this->background['posX'], $this->background['posY'], $this->background['width']);
  478. }
  479. $this->setPageHeader();
  480. $this->setPageFooter();
  481. }
  482. $this->setMargins();
  483. $this->pdf->setY($this->margeTop);
  484. $this->setNewPositionForNewLine($curr);
  485. $this->maxH = 0;
  486. }
  487. /**
  488. * calcul de la position de debut de la prochaine ligne en fonction de l'alignement voulu
  489. *
  490. * @param integer position reelle courante si saut de ligne pendant l'ecriture d'un texte
  491. * @return null
  492. */
  493. protected function setNewPositionForNewLine($curr = null)
  494. {
  495. list($lx, $rx) = $this->getMargins($this->pdf->getY());
  496. $this->pdf->setX($lx);
  497. $wMax = $rx - $lx;
  498. $this->currentH = 0;
  499. if ($this->sub_part || $this->isSubPart || $this->forOneLine)
  500. {
  501. // $this->pdf->setWordSpacing(0);
  502. return null;
  503. }
  504. /*
  505. if (
  506. $this->style->value['text-align']!='right' &&
  507. $this->style->value['text-align']!='center' &&
  508. $this->style->value['text-align']!='justify'
  509. )
  510. {
  511. // $this->pdf->setWordSpacing(0);
  512. return null;
  513. }
  514. */
  515. $sub = null;
  516. $this->createSubHTML($sub);
  517. $sub->saveMargin(0, 0, $sub->pdf->getW() - $wMax);
  518. $sub->forOneLine = true;
  519. $sub->parse_pos = $this->parse_pos;
  520. $sub->parsing->code = $this->parsing->code;
  521. if ($curr !== null && $sub->parsing->code[$this->parse_pos]['name'] == 'write')
  522. {
  523. $txt = $sub->parsing->code[$this->parse_pos]['param']['txt'];
  524. $txt = str_replace('[[page_cu]]', $sub->page, $txt);
  525. $sub->parsing->code[$this->parse_pos]['param']['txt'] = substr($txt, $curr);
  526. }
  527. else
  528. $sub->parse_pos ++;
  529. // pour chaque element identifi� par le parsing
  530. $res = null;
  531. for($sub->parse_pos; $sub->parse_pos < count($sub->parsing->code); $sub->parse_pos ++)
  532. {
  533. $todo = $sub->parsing->code[$sub->parse_pos];
  534. $res = $sub->loadAction($todo);
  535. if (! $res)
  536. break;
  537. }
  538. $w = $sub->maxX; // largeur maximale
  539. $h = $sub->maxH; // hauteur maximale
  540. $e = ($res === null ? $sub->maxE : 0); // nombre d'�l�ments maximal
  541. $this->destroySubHTML($sub);
  542. if ($this->style->value['text-align'] == 'center')
  543. $this->pdf->setX(($rx + $this->pdf->getX() - $w) * 0.5 - 0.01);
  544. elseif ($this->style->value['text-align'] == 'right')
  545. $this->pdf->setX($rx - $w - 0.01);
  546. else
  547. $this->pdf->setX($lx);
  548. $this->currentH = $h;
  549. /*
  550. if ($this->style->value['text-align']=='justify' && $e>1)
  551. $this->pdf->setWordSpacing(($wMax-$w)/($e-1));
  552. else
  553. $this->pdf->setWordSpacing(0);
  554. */
  555. }
  556. /**
  557. * r�cup�ration du PDF
  558. *
  559. * @param string nom du fichier PDF
  560. * @param boolean destination
  561. * @return string contenu �ventuel du pdf
  562. *
  563. *
  564. * Destination o� envoyer le document. Le param�tre peut prendre les valeurs suivantes :
  565. * true : equivalent � I
  566. * false : equivalent � S
  567. * I : envoyer en inline au navigateur. Le plug-in est utilis� s'il est install�. Le nom indiqu� dans name est utilis� lorsque l'on s�lectionne "Enregistrer sous" sur le lien g�n�rant le PDF.
  568. * D : envoyer au navigateur en for�ant le t�l�chargement, avec le nom indiqu� dans name.
  569. * F : sauver dans un fichier local, avec le nom indiqu� dans name (peut inclure un r�pertoire).
  570. * S : renvoyer le document sous forme de cha�ne. name est ignor�.
  571. */
  572. public function Output($name = '', $dest = false)
  573. {
  574. // nettoyage
  575. HTML2PDF :: $TABLES = array();
  576. if ($this->DEBUG_actif)
  577. {
  578. $this->DEBUG_add('Before output');
  579. $this->pdf->Close();
  580. exit();
  581. }
  582. // interpretation des param�tres
  583. if ($dest === false)
  584. $dest = 'I';
  585. if ($dest === true)
  586. $dest = 'S';
  587. if ($dest === '')
  588. $dest = 'I';
  589. if ($name == '')
  590. $name = 'document.pdf';
  591. // verification de la destination
  592. $dest = strtoupper($dest);
  593. if (! in_array($dest, array('I', 'D', 'F', 'S')))
  594. $dest = 'I';
  595. // verification du nom
  596. if (strtolower(substr($name, - 4)) != '.pdf')
  597. {
  598. echo 'ERROR : The output document name "' . $name . '" is not a PDF name';
  599. exit();
  600. }
  601. return $this->pdf->Output($name, $dest);
  602. }
  603. /**
  604. * preparation de HTML2PDF::$SUBOBJ utilis� pour la cr�ation des sous HTML2PDF
  605. *
  606. * @return null
  607. */
  608. protected function prepareSubObj()
  609. {
  610. $pdf = null;
  611. HTML2PDF :: $SUBOBJ = new HTML2PDF($this->sens, $this->format, $this->langue, $this->unicode, $this->encoding, array(
  612. $this->defaultLeft, $this->defaultTop, $this->defaultRight, $this->defaultBottom));
  613. // initialisation
  614. HTML2PDF :: $SUBOBJ->setIsSubPart();
  615. HTML2PDF :: $SUBOBJ->setTestTdInOnePage($this->testTDin1page);
  616. HTML2PDF :: $SUBOBJ->setTestIsImage($this->testIsImage);
  617. HTML2PDF :: $SUBOBJ->setDefaultFont($this->defaultFont);
  618. HTML2PDF :: $SUBOBJ->style->css = &$this->style->css;
  619. HTML2PDF :: $SUBOBJ->style->css_keys = &$this->style->css_keys;
  620. HTML2PDF :: $SUBOBJ->pdf->cloneFontFrom($this->pdf);
  621. HTML2PDF :: $SUBOBJ->style->setPdfParent($pdf);
  622. }
  623. /**
  624. * fonction de clonage pour la creation d'un sous HTML2PDF � partir de HTML2PDF::$SUBOBJ
  625. *
  626. * @return null
  627. */
  628. public function __clone()
  629. {
  630. $this->pdf = clone $this->pdf;
  631. $this->parsing = clone $this->parsing;
  632. $this->style = clone $this->style;
  633. $this->style->setPdfParent($this->pdf);
  634. }
  635. /**
  636. * cr�ation d'un sous HTML2PDF pour la gestion des tableaux imbriqu�s
  637. *
  638. * @param HTML2PDF futur sous HTML2PDF pass� en r�f�rence pour cr�ation
  639. * @param integer marge eventuelle de l'objet si simulation d'un TD
  640. * @return null
  641. */
  642. protected function createSubHTML(&$sub_html, $cellmargin = 0)
  643. {
  644. if (! HTML2PDF :: $SUBOBJ)
  645. $this->prepareSubObj();
  646. // calcul de la largueur
  647. if ($this->style->value['width'])
  648. {
  649. $marge = $cellmargin * 2;
  650. $marge += $this->style->value['padding']['l'] + $this->style->value['padding']['r'];
  651. $marge += $this->style->value['border']['l']['width'] + $this->style->value['border']['r']['width'];
  652. $marge = $this->pdf->getW() - $this->style->value['width'] + $marge;
  653. }
  654. else
  655. $marge = $this->margeLeft + $this->margeRight;
  656. //clonage
  657. $sub_html = clone HTML2PDF :: $SUBOBJ;
  658. $sub_html->style->table = $this->style->table;
  659. $sub_html->style->value = $this->style->value;
  660. $sub_html->style->setOnlyLeft();
  661. $sub_html->setNewPage($this->format, $this->sens);
  662. $sub_html->initSubHtml($marge, $this->page, $this->defLIST);
  663. }
  664. /**
  665. * initialise le sous HTML2PDF. Ne pas utiliser directement. seul la fonction createSubHTML doit l'utiliser
  666. *
  667. * @return null
  668. */
  669. public function initSubHtml($marge, $page, $defLIST)
  670. {
  671. $this->saveMargin(0, 0, $marge);
  672. $this->defLIST = $defLIST;
  673. $this->page = $page;
  674. $this->pdf->setXY(0, 0);
  675. $this->style->FontSet();
  676. }
  677. public function setIsSubPart()
  678. {
  679. $this->isSubPart = true;
  680. }
  681. /**
  682. * destruction d'un sous HTML2PDF pour la gestion des tableaux imbriqu�s
  683. *
  684. * @return null
  685. */
  686. protected function destroySubHTML(&$sub_html)
  687. {
  688. unset($sub_html);
  689. $sub_html = null;
  690. }
  691. /**
  692. * Convertir un nombre arabe en nombre romain
  693. *
  694. * @param integer nombre � convertir
  695. * @return string nombre converti
  696. */
  697. protected function listeArab2Rom($nb_ar)
  698. {
  699. $nb_b10 = array('I', 'X', 'C', 'M');
  700. $nb_b5 = array('V', 'L', 'D');
  701. $nb_ro = '';
  702. if ($nb_ar < 1)
  703. return $nb_ar;
  704. if ($nb_ar > 3999)
  705. return $nb_ar;
  706. for($i = 3; $i >= 0; $i --)
  707. {
  708. $chiffre = floor($nb_ar / pow(10, $i));
  709. if ($chiffre >= 1)
  710. {
  711. $nb_ar = $nb_ar - $chiffre * pow(10, $i);
  712. if ($chiffre <= 3)
  713. {
  714. for($j = $chiffre; $j >= 1; $j --)
  715. {
  716. $nb_ro = $nb_ro . $nb_b10[$i];
  717. }
  718. }
  719. else
  720. if ($chiffre == 9)
  721. {
  722. $nb_ro = $nb_ro . $nb_b10[$i] . $nb_b10[$i + 1];
  723. }
  724. elseif ($chiffre == 4)
  725. {
  726. $nb_ro = $nb_ro . $nb_b10[$i] . $nb_b5[$i];
  727. }
  728. else
  729. {
  730. $nb_ro = $nb_ro . $nb_b5[$i];
  731. for($j = $chiffre - 5; $j >= 1; $j --)
  732. {
  733. $nb_ro = $nb_ro . $nb_b10[$i];
  734. }
  735. }
  736. }
  737. }
  738. return $nb_ro;
  739. }
  740. /**
  741. * Ajouter un LI au niveau actuel
  742. *
  743. * @return null
  744. */
  745. protected function listeAddLi()
  746. {
  747. $this->defLIST[count($this->defLIST) - 1]['nb'] ++;
  748. }
  749. protected function listeGetWidth()
  750. {
  751. return '7mm';
  752. }
  753. protected function listeGetPadding()
  754. {
  755. return '1mm';
  756. }
  757. /**
  758. * Recuperer le LI du niveau actuel
  759. *
  760. * @return string chaine � afficher
  761. */
  762. protected function listeGetLi()
  763. {
  764. $im = $this->defLIST[count($this->defLIST) - 1]['img'];
  765. $st = $this->defLIST[count($this->defLIST) - 1]['style'];
  766. $nb = $this->defLIST[count($this->defLIST) - 1]['nb'];
  767. $up = (substr($st, 0, 6) == 'upper-');
  768. if ($im)
  769. return array(false, false, $im);
  770. switch ($st)
  771. {
  772. case 'none' :
  773. return array('helvetica', true, ' ');
  774. case 'upper-alpha' :
  775. case 'lower-alpha' :
  776. $str = '';
  777. while ($nb > 26)
  778. {
  779. $str = chr(96 + $nb % 26) . $str;
  780. $nb = floor($nb / 26);
  781. }
  782. $str = chr(96 + $nb) . $str;
  783. return array('helvetica', false, ($up ? strtoupper($str) : $str) . '.');
  784. case 'upper-roman' :
  785. case 'lower-roman' :
  786. $str = $this->listeArab2Rom($nb);
  787. return array('helvetica', false, ($up ? strtoupper($str) : $str) . '.');
  788. case 'decimal' :
  789. return array('helvetica', false, $nb . '.');
  790. case 'square' :
  791. return array('zapfdingbats', true, chr(110));
  792. case 'circle' :
  793. return array('zapfdingbats', true, chr(109));
  794. case 'disc' :
  795. default :
  796. return array('zapfdingbats', true, chr(108));
  797. }
  798. }
  799. /**
  800. * Ajouter un niveau de liste
  801. *
  802. * @param string type de liste : ul, ol
  803. * @param string style de la liste
  804. * @return null
  805. */
  806. protected function listeAddLevel($type = 'ul', $style = '', $img = null)
  807. {
  808. if ($img)
  809. {
  810. if (preg_match('/^url\(([^)]+)\)$/isU', trim($img), $match))
  811. $img = $match[1];
  812. else
  813. $img = null;
  814. }
  815. else
  816. $img = null;
  817. if (! in_array($type, array('ul', 'ol')))
  818. $type = 'ul';
  819. if (! in_array($style, array('lower-alpha', 'upper-alpha', 'upper-roman', 'lower-roman', 'decimal',
  820. 'square', 'circle', 'disc', 'none')))
  821. $style = '';
  822. if (! $style)
  823. {
  824. if ($type == 'ul')
  825. $style = 'disc';
  826. else
  827. $style = 'decimal';
  828. }
  829. $this->defLIST[count($this->defLIST)] = array('style' => $style, 'nb' => 0, 'img' => $img);
  830. }
  831. /**
  832. * Supprimer un niveau de liste
  833. *
  834. * @return null
  835. */
  836. protected function listeDelLevel()
  837. {
  838. if (count($this->defLIST))
  839. {
  840. unset($this->defLIST[count($this->defLIST) - 1]);
  841. $this->defLIST = array_values($this->defLIST);
  842. }
  843. }
  844. /**
  845. * traitement d'un code HTML fait pour HTML2PDF
  846. *
  847. * @param string code HTML � convertir
  848. * @param boolean afficher en pdf (false) ou en html adapt� (true)
  849. * @return null
  850. */
  851. public function writeHTML($html, $vue = false)
  852. {
  853. // si c'est une vrai page HTML, une conversion s'impose
  854. if (preg_match('/<body/isU', $html))
  855. $html = $this->getHtmlFromPage($html);
  856. $html = str_replace('[[page_nb]]', '{nb}', $html);
  857. $html = str_replace('[[date_y]]', date('Y'), $html);
  858. $html = str_replace('[[date_m]]', date('m'), $html);
  859. $html = str_replace('[[date_d]]', date('d'), $html);
  860. $html = str_replace('[[date_h]]', date('H'), $html);
  861. $html = str_replace('[[date_i]]', date('i'), $html);
  862. $html = str_replace('[[date_s]]', date('s'), $html);
  863. // si on veut voir le r�sultat en HTML => on appelle la fonction
  864. if ($vue)
  865. $this->vueHTML($html);
  866. // sinon, traitement pour conversion en PDF :
  867. // parsing
  868. $this->sub_pdf = false;
  869. $this->style->readStyle($html);
  870. $this->parsing->setHTML($html);
  871. $this->parsing->parse();
  872. $this->makeHTMLcode();
  873. }
  874. /**
  875. * traitement du code d'une vrai page HTML pour l'adapter � HTML2PDF
  876. *
  877. * @param string code HTML � adapter
  878. * @return string code HTML adapt�
  879. */
  880. public function getHtmlFromPage($html)
  881. {
  882. $html = str_replace('<BODY', '<body', $html);
  883. $html = str_replace('</BODY', '</body', $html);
  884. // extraction du contenu
  885. $res = explode('<body', $html);
  886. if (count($res) < 2)
  887. return $html;
  888. $content = '<page' . $res[1];
  889. $content = explode('</body', $content);
  890. $content = $content[0] . '</page>';
  891. // extraction des balises link
  892. preg_match_all('/<link([^>]*)>/isU', $html, $match);
  893. foreach ($match[0] as $src)
  894. $content = $src . '</link>' . $content;
  895. // extraction des balises style
  896. preg_match_all('/<style[^>]*>(.*)<\/style[^>]*>/isU', $html, $match);
  897. foreach ($match[0] as $src)
  898. $content = $src . $content;
  899. return $content;
  900. }
  901. /**
  902. * execute les diff�rentes actions du code HTML
  903. *
  904. * @return null
  905. */
  906. protected function makeHTMLcode()
  907. {
  908. // pour chaque element identifi� par le parsing
  909. for($this->parse_pos = 0; $this->parse_pos < count($this->parsing->code); $this->parse_pos ++)
  910. {
  911. // r�cup�ration de l'�l�ment
  912. $todo = $this->parsing->code[$this->parse_pos];
  913. // si c'est une ouverture de tableau
  914. if (in_array($todo['name'], array('table', 'ul', 'ol')) && ! $todo['close'])
  915. {
  916. // on va cr�er un sous HTML, et on va travailler sur une position temporaire
  917. $tag_open = $todo['name'];
  918. $this->sub_part = true;
  919. $this->temp_pos = $this->parse_pos;
  920. // pour tous les �l�ments jusqu'� la fermeture de la table afin de pr�parer les dimensions
  921. while (isset($this->parsing->code[$this->temp_pos]) && ! ($this->parsing->code[$this->temp_pos]['name'] == $tag_open && $this->parsing->code[$this->temp_pos]['close']))
  922. {
  923. $this->loadAction($this->parsing->code[$this->temp_pos]);
  924. $this->temp_pos ++;
  925. }
  926. if (isset($this->parsing->code[$this->temp_pos]))
  927. $this->loadAction($this->parsing->code[$this->temp_pos]);
  928. $this->sub_part = false;
  929. }
  930. // chargement de l'action correspondant � l'�l�ment
  931. $this->loadAction($todo);
  932. }
  933. }
  934. /**
  935. * affichage en mode HTML du contenu
  936. *
  937. * @param string contenu
  938. * @return null
  939. */
  940. protected function vueHTML($content)
  941. {
  942. $content = preg_replace('/<page_header([^>]*)>/isU', '<hr>' . HTML2PDF :: textGET('vue01') . ' : $1<hr><div$1>', $content);
  943. $content = preg_replace('/<page_footer([^>]*)>/isU', '<hr>' . HTML2PDF :: textGET('vue02') . ' : $1<hr><div$1>', $content);
  944. $content = preg_replace('/<page([^>]*)>/isU', '<hr>' . HTML2PDF :: textGET('vue03') . ' : $1<hr><div$1>', $content);
  945. $content = preg_replace('/<\/page([^>]*)>/isU', '</div><hr>', $content);
  946. $content = preg_replace('/<bookmark([^>]*)>/isU', '<hr>bookmark : $1<hr>', $content);
  947. $content = preg_replace('/<\/bookmark([^>]*)>/isU', '', $content);
  948. $content = preg_replace('/<barcode([^>]*)>/isU', '<hr>barcode : $1<hr>', $content);
  949. $content = preg_replace('/<\/barcode([^>]*)>/isU', '', $content);
  950. $content = preg_replace('/<qrcode([^>]*)>/isU', '<hr>qrcode : $1<hr>', $content);
  951. $content = preg_replace('/<\/qrcode([^>]*)>/isU', '', $content);
  952. echo '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
  953. <html>
  954. <head>
  955. <title>' . HTML2PDF :: textGET('vue04') . ' HTML</title>
  956. <meta http-equiv="Content-Type" content="text/html; charset=' . $this->encoding . '" >
  957. </head>
  958. <body style="padding: 10px; font-size: 10pt;font-family: Verdana;">
  959. ' . $content . '
  960. </body>
  961. </html>';
  962. exit();
  963. }
  964. /**
  965. * chargement de l'action correspondante � un element de parsing
  966. *
  967. * @param array �l�ment de parsing
  968. * @return null
  969. */
  970. protected function loadAction($row)
  971. {
  972. // nom de l'action
  973. $fnc = ($row['close'] ? 'c_' : 'o_') . strtoupper($row['name']);
  974. // parametres de l'action
  975. $param = $row['param'];
  976. // si aucune page n'est cr��, on la cr��
  977. if ($fnc != 'o_PAGE' && $this->firstPage)
  978. {
  979. $this->setNewPage();
  980. }
  981. // lancement de l'action
  982. if (is_callable(array(&$this, $fnc)))
  983. {
  984. $res = $this->{$fnc}($param);
  985. $this->previousCall = $fnc;
  986. return $res;
  987. }
  988. else
  989. {
  990. HTML2PDF :: makeError(1, __FILE__, __LINE__, strtoupper($row['name']), $this->parsing->getHtmlErrorCode($row['html_pos']));
  991. return false;
  992. }
  993. }
  994. /**
  995. * balise : PAGE
  996. * mode : OUVERTURE
  997. *
  998. * @param array param�tres de l'�l�ment de parsing
  999. * @return null
  1000. */
  1001. protected function o_PAGE($param)
  1002. {
  1003. if ($this->forOneLine)
  1004. return false;
  1005. if ($this->DEBUG_actif)
  1006. $this->DEBUG_add('PAGE n�' . ($this->page + 1), true);
  1007. $newPageSet = (! isset($param['pageset']) || $param['pageset'] != 'old');
  1008. $this->maxH = 0;
  1009. if ($newPageSet)
  1010. {
  1011. $this->subHEADER = array();
  1012. $this->subFOOTER = array();
  1013. // identification de l'orientation demand�e
  1014. $orientation = '';
  1015. if (isset($param['orientation']))
  1016. {
  1017. $param['orientation'] = strtolower($param['orientation']);
  1018. if ($param['orientation'] == 'p')
  1019. $orientation = 'P';
  1020. if ($param['orientation'] == 'portrait')
  1021. $orientation = 'P';
  1022. if ($param['orientation'] == 'l')
  1023. $orientation = 'L';
  1024. if ($param['orientation'] == 'paysage')
  1025. $orientation = 'L';
  1026. if ($param['orientation'] == 'landscape')
  1027. $orientation = 'L';
  1028. }
  1029. // identification de l'orientation demand�e
  1030. $format = null;
  1031. if (isset($param['format']))
  1032. {
  1033. $format = strtolower($param['format']);
  1034. if (preg_match('/^([0-9]+)x([0-9]+)$/isU', $format, $match))
  1035. {
  1036. $format = array(intval($match[1]), intval($match[2]));
  1037. }
  1038. }
  1039. // identification des propri�t�s du background
  1040. $background = array();
  1041. if (isset($param['backimg']))
  1042. {
  1043. $background['img'] = isset($param['backimg']) ? $param['backimg'] : ''; // nom de l'image
  1044. $background['posX'] = isset($param['backimgx']) ? $param['backimgx'] : 'center'; // position horizontale de l'image
  1045. $background['posY'] = isset($param['backimgy']) ? $param['backimgy'] : 'middle'; // position verticale de l'image
  1046. $background['width'] = isset($param['backimgw']) ? $param['backimgw'] : '100%'; // taille de l'image (100% = largueur de la feuille)
  1047. // conversion du nom de l'image, en cas de param�tres en _GET
  1048. $background['img'] = str_replace('&amp;', '&', $background['img']);
  1049. // conversion des positions
  1050. if ($background['posX'] == 'left')
  1051. $background['posX'] = '0%';
  1052. if ($background['posX'] == 'center')
  1053. $background['posX'] = '50%';
  1054. if ($background['posX'] == 'right')
  1055. $background['posX'] = '100%';
  1056. if ($background['posY'] == 'top')
  1057. $background['posY'] = '0%';
  1058. if ($background['posY'] == 'middle')
  1059. $background['posY'] = '50%';
  1060. if ($background['posY'] == 'bottom')
  1061. $background['posY'] = '100%';
  1062. // si il y a une image de pr�cis�
  1063. if ($background['img'])
  1064. {
  1065. // est-ce que c'est une image ?
  1066. $infos = @GetImageSize($background['img']);
  1067. if (count($infos) > 1)
  1068. {
  1069. // taille de l'image, en fonction de la taille sp�cifi�e.
  1070. $Wi = $this->style->ConvertToMM($background['width'], $this->pdf->getW());
  1071. $Hi = $Wi * $infos[1] / $infos[0];
  1072. // r�cup�ration des dimensions et positions de l'image
  1073. $background['width'] = $Wi;
  1074. $background['posX'] = $this->style->ConvertToMM($background['posX'], $this->pdf->getW() - $Wi);
  1075. $background['posY'] = $this->style->ConvertToMM($background['posY'], $this->pdf->getH() - $Hi);
  1076. }
  1077. else
  1078. $background = array();
  1079. }
  1080. else
  1081. $background = array();
  1082. }
  1083. // marges TOP et BOTTOM pour le texte.
  1084. $background['top'] = isset($param['backtop']) ? $param['backtop'] : '0';
  1085. $background['bottom'] = isset($param['backbottom']) ? $param['backbottom'] : '0';
  1086. $background['left'] = isset($param['backleft']) ? $param['backleft'] : '0';
  1087. $background['right'] = isset($param['backright']) ? $param['backright'] : '0';
  1088. if (preg_match('/^([0-9]*)$/isU', $background['top']))
  1089. $background['top'] .= 'mm';
  1090. if (preg_match('/^([0-9]*)$/isU', $background['bottom']))
  1091. $background['bottom'] .= 'mm';
  1092. if (preg_match('/^([0-9]*)$/isU', $background['left']))
  1093. $background['left'] .= 'mm';
  1094. if (preg_match('/^([0-9]*)$/isU', $background['right']))
  1095. $background['right'] .= 'mm';

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