PageRenderTime 40ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

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

https://bitbucket.org/chamilo/chamilo/
PHP | 2115 lines | 1344 code | 309 blank | 462 comment | 188 complexity | ca913e667e1afd5ef9c8573b8103cda4 MD5 | raw file
Possible License(s): GPL-2.0, BSD-3-Clause, LGPL-2.1, LGPL-3.0, GPL-3.0, MIT
  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. static protected $SUBOBJ = null; // sous objet HTML2PDF pr?par? en cas de besoin
  78. static protected $TABLES = array(); // tableau global necessaire ? la gestion des tables imbriqu?es
  79. static protected $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)) $marges = array($marges, $marges, $marges, $marges);
  119. $this->setDefaultMargins($marges[0], $marges[1], $marges[2], $marges[3]);
  120. $this->setMargins();
  121. $this->marges = array();
  122. // initialisation des champs de formulaire
  123. $this->lstChamps = array();
  124. }
  125. /**
  126. * Destructeur
  127. *
  128. * @return null
  129. */
  130. public function __destruct()
  131. {
  132. }
  133. /**
  134. * activer le debug mode
  135. *
  136. * @return null
  137. */
  138. public function setModeDebug()
  139. {
  140. list($usec, $sec) = explode(' ', microtime());
  141. $this->DEBUG_actif = true;
  142. $this->DEBUG_ok_usage = function_exists('memory_get_usage');
  143. $this->DEBUG_ok_peak = function_exists('memory_get_peak_usage');
  144. $this->DEBUG_start_time = (float)$sec + (float)$usec;
  145. $this->DEBUG_last_time = (float)$sec + (float)$usec;
  146. $this->DEBUG_stepline('step', 'time', 'delta', 'memory', 'peak');
  147. $this->DEBUG_add('Init debug');
  148. }
  149. /**
  150. * rajouter une ligne de debug
  151. *
  152. * @param string nom de l'etape
  153. * @param boolean true=monter d'un niveau, false=descendre d'un niveau, null : ne rien faire
  154. * @return null
  155. */
  156. protected function DEBUG_add($nom, $level=null)
  157. {
  158. list($usec, $sec) = explode(' ', microtime());
  159. if ($level===true) $this->DEBUG_level++;
  160. $nom = str_repeat(' ',$this->DEBUG_level). $nom.($level===true ? ' Begin' : ($level===false ? ' End' : ''));
  161. $time = (float)$sec + (float)$usec;
  162. $usage = ($this->DEBUG_ok_usage ? memory_get_usage() : 0);
  163. $peak = ($this->DEBUG_ok_peak ? memory_get_peak_usage() : 0);
  164. $this->DEBUG_stepline(
  165. $nom,
  166. number_format(($time - $this->DEBUG_start_time)*1000, 1, '.', ' ').' ms',
  167. number_format(($time - $this->DEBUG_last_time)*1000, 1, '.', ' ').' ms',
  168. number_format($usage/1024, 1, '.', ' ').' Ko',
  169. number_format($peak/1024, 1, '.', ' ').' Ko');
  170. $this->DEBUG_last_time = $time;
  171. if ($level===false) $this->DEBUG_level--;
  172. return true;
  173. }
  174. /**
  175. * affiche une ligne de debug
  176. *
  177. * @param string nom de l'etape
  178. * @param string valeur 1
  179. * @param string valeur 2
  180. * @param string valeur 3
  181. * @param string valeur 4
  182. * @return null
  183. */
  184. protected function DEBUG_stepline($nom, $val1, $val2, $val3, $val4)
  185. {
  186. $txt = str_pad($nom, 30, ' ', STR_PAD_RIGHT).
  187. str_pad($val1, 12, ' ', STR_PAD_LEFT).
  188. str_pad($val2, 12, ' ', STR_PAD_LEFT).
  189. str_pad($val3, 15, ' ', STR_PAD_LEFT).
  190. str_pad($val4, 15, ' ', STR_PAD_LEFT);
  191. echo '<pre style="padding:0; margin:0">'.$txt.'</pre>';
  192. }
  193. /**
  194. * activer ou desactiver le test de TD ne devant pas depasser une page
  195. *
  196. * @param boolean nouvel etat
  197. * @return boolean ancien etat
  198. */
  199. public function setTestTdInOnePage($mode = true)
  200. {
  201. $old = $this->testTDin1page;
  202. $this->testTDin1page = $mode ? true : false;
  203. return $old;
  204. }
  205. /**
  206. * activer ou desactiver le test sur la pr?sence des images
  207. *
  208. * @param boolean nouvel etat
  209. * @return boolean ancien etat
  210. */
  211. public function setTestIsImage($mode = true)
  212. {
  213. $old = $this->testIsImage;
  214. $this->testIsImage = $mode ? true : false;
  215. return $old;
  216. }
  217. /**
  218. * d?finit la fonte par d?faut si aucun fonte n'est sp?cifi?e, ou si la fonte demand?e n'existe pas
  219. *
  220. * @param string nom de la fonte par defaut. si null : Arial pour fonte non sp?cifi?e, et erreur pour fonte non existante
  221. * @return string nom de l'ancienne fonte par defaut
  222. */
  223. public function setDefaultFont($default = null)
  224. {
  225. $old = $this->defaultFont;
  226. $this->defaultFont = $default;
  227. $this->style->setDefaultFont($default);
  228. return $old;
  229. }
  230. /**
  231. * d?finir les marges par d?fault
  232. *
  233. * @param int en mm, marge left
  234. * @param int en mm, marge top
  235. * @param int en mm, marge right. si null, left=right
  236. * @param int en mm, marge bottom. si null, bottom=8
  237. * @return null
  238. */
  239. protected function setDefaultMargins($left, $top, $right = null, $bottom = null)
  240. {
  241. if ($right===null) $right = $left;
  242. if ($bottom===null) $bottom = 8;
  243. $this->defaultLeft = $this->style->ConvertToMM($left.'mm');
  244. $this->defaultTop = $this->style->ConvertToMM($top.'mm');
  245. $this->defaultRight = $this->style->ConvertToMM($right.'mm');
  246. $this->defaultBottom = $this->style->ConvertToMM($bottom.'mm');
  247. }
  248. /**
  249. * d?finir les marges r?elles, fonctions de la balise page
  250. *
  251. * @return null
  252. */
  253. protected function setMargins()
  254. {
  255. $this->margeLeft = $this->defaultLeft + (isset($this->background['left']) ? $this->background['left'] : 0);
  256. $this->margeRight = $this->defaultRight + (isset($this->background['right']) ? $this->background['right'] : 0);
  257. $this->margeTop = $this->defaultTop + (isset($this->background['top']) ? $this->background['top'] : 0);
  258. $this->margeBottom = $this->defaultBottom + (isset($this->background['bottom']) ? $this->background['bottom'] : 0);
  259. $this->pdf->SetMargins($this->margeLeft, $this->margeTop, $this->margeRight);
  260. $this->pdf->setcMargin(0);
  261. $this->pdf->SetAutoPageBreak(false, $this->margeBottom);
  262. $this->pageMarges = array();
  263. $this->pageMarges[floor($this->margeTop*100)] = array($this->margeLeft, $this->pdf->getW()-$this->margeRight);
  264. }
  265. /**
  266. * recuperer les positions x minimales et maximales en fonction d'une hauteur
  267. *
  268. * @param float y
  269. * @return array(float, float)
  270. */
  271. protected function getMargins($y)
  272. {
  273. $y = floor($y*100);
  274. $x = array($this->pdf->getlMargin(), $this->pdf->getW()-$this->pdf->getrMargin());
  275. foreach($this->pageMarges as $m_y => $m_x)
  276. if ($m_y<=$y) $x = $m_x;
  277. return $x;
  278. }
  279. /**
  280. * ajouter une marge suite a un float
  281. *
  282. * @param string left ou right
  283. * @param float x1
  284. * @param float y1
  285. * @param float x2
  286. * @param float y2
  287. * @return null
  288. */
  289. protected function addMargins($float, $x1, $y1, $x2, $y2)
  290. {
  291. $old1 = $this->getMargins($y1);
  292. $old2 = $this->getMargins($y2);
  293. if ($float=='left') $old1[0] = $x2;
  294. if ($float=='right') $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) continue;
  300. if ($m_y>$y2) break;
  301. if ($float=='left' && $this->pageMarges[$m_y][0]<$x2) unset($this->pageMarges[$m_y]);
  302. if ($float=='right' && $this->pageMarges[$m_y][1]>$x1) unset($this->pageMarges[$m_y]);
  303. }
  304. $this->pageMarges[$y1] = $old1;
  305. $this->pageMarges[$y2] = $old2;
  306. ksort($this->pageMarges);
  307. $this->isAfterFloat = true;
  308. }
  309. /**
  310. * d?finir des nouvelles marges et sauvegarder les anciennes
  311. *
  312. * @param float marge left
  313. * @param float marge top
  314. * @param float marge right
  315. * @return null
  316. */
  317. protected function saveMargin($ml, $mt, $mr)
  318. {
  319. $this->marges[] = array('l' => $this->pdf->getlMargin(), 't' => $this->pdf->gettMargin(), 'r' => $this->pdf->getrMargin(), 'page' => $this->pageMarges);
  320. $this->pdf->SetMargins($ml, $mt, $mr);
  321. $this->pageMarges = array();
  322. $this->pageMarges[floor($mt*100)] = array($ml, $this->pdf->getW()-$mr);
  323. }
  324. /**
  325. * r?cuperer les derni?res marches sauv?es
  326. *
  327. * @return null
  328. */
  329. protected function loadMargin()
  330. {
  331. $old = array_pop($this->marges);
  332. if ($old)
  333. {
  334. $ml = $old['l'];
  335. $mt = $old['t'];
  336. $mr = $old['r'];
  337. $mP = $old['page'];
  338. }
  339. else
  340. {
  341. $ml = $this->margeLeft;
  342. $mt = 0;
  343. $mr = $this->margeRight;
  344. $mP = array($mt => array($ml, $this->pdf->getW()-$mr));
  345. }
  346. $this->pdf->SetMargins($ml, $mt, $mr);
  347. $this->pageMarges = $mP;
  348. }
  349. /**
  350. * permet d'ajouter une fonte.
  351. *
  352. * @param string nom de la fonte
  353. * @param string style de la fonte
  354. * @param string fichier de la fonte
  355. * @return null
  356. */
  357. public function addFont($family, $style='', $file='')
  358. {
  359. $this->pdf->AddFont($family, $style, $file);
  360. }
  361. /**
  362. * sauvegarder l'?tat actuelle des maximums
  363. *
  364. * @return null
  365. */
  366. protected function saveMax()
  367. {
  368. $this->maxSave[] = array($this->maxX, $this->maxY, $this->maxH, $this->maxE);
  369. }
  370. /**
  371. * charger le dernier ?tat sauv? des maximums
  372. *
  373. * @return null
  374. */
  375. protected function loadMax()
  376. {
  377. $old = array_pop($this->maxSave);
  378. if ($old)
  379. {
  380. $this->maxX = $old[0];
  381. $this->maxY = $old[1];
  382. $this->maxH = $old[2];
  383. $this->maxE = $old[3];
  384. }
  385. else
  386. {
  387. $this->maxX = 0;
  388. $this->maxY = 0;
  389. $this->maxH = 0;
  390. $this->maxE = 0;
  391. }
  392. }
  393. /**
  394. * afficher l'header contenu dans page_header
  395. *
  396. * @return null
  397. */
  398. protected function setPageHeader()
  399. {
  400. if (!count($this->subHEADER)) return false;
  401. $OLD_parse_pos = $this->parse_pos;
  402. $OLD_parse_code = $this->parsing->code;
  403. $this->parse_pos = 0;
  404. $this->parsing->code = $this->subHEADER;
  405. $this->makeHTMLcode();
  406. $this->parse_pos = $OLD_parse_pos;
  407. $this->parsing->code = $OLD_parse_code;
  408. }
  409. /**
  410. * afficher le footer contenu dans page_footer
  411. *
  412. * @return null
  413. */
  414. protected function setPageFooter()
  415. {
  416. if (!count($this->subFOOTER)) return false;
  417. $OLD_parse_pos = $this->parse_pos;
  418. $OLD_parse_code = $this->parsing->code;
  419. $this->parse_pos = 0;
  420. $this->parsing->code = $this->subFOOTER;
  421. $this->isInFooter = true;
  422. $this->makeHTMLcode();
  423. $this->isInFooter = false;
  424. $this->parse_pos = $OLD_parse_pos;
  425. $this->parsing->code = $OLD_parse_code;
  426. }
  427. /**
  428. * saut de ligne avec une hauteur sp?cifique
  429. *
  430. * @param float hauteur de la ligne
  431. * @param integer position reelle courante si saut de ligne pendant l'ecriture d'un texte
  432. * @return null
  433. */
  434. protected function setNewLine($h, $curr = null)
  435. {
  436. $this->pdf->Ln($h);
  437. $this->setNewPositionForNewLine($curr);
  438. }
  439. /**
  440. * cr?ation d'une nouvelle page avec le format et l'orientation sp?cifies
  441. *
  442. * @param mixed format de la page : A5, A4, array(width, height)
  443. * @param string sens P=portrait ou L=landscape
  444. * @param array tableau des propri?t?s du fond de la page
  445. * @param integer position reelle courante si saut de ligne pendant l'ecriture d'un texte
  446. * @return null
  447. */
  448. public function setNewPage($format = null, $orientation = '', $background = null, $curr = null)
  449. {
  450. $this->firstPage = false;
  451. $this->format = $format ? $format : $this->format;
  452. $this->sens = $orientation ? $orientation : $this->sens;
  453. $this->background = $background!==null ? $background : $this->background;
  454. $this->maxY = 0;
  455. $this->maxX = 0;
  456. $this->maxH = 0;
  457. $this->pdf->SetMargins($this->defaultLeft, $this->defaultTop, $this->defaultRight);
  458. $this->pdf->AddPage($this->sens, $this->format);
  459. $this->page++;
  460. if (!$this->sub_part && !$this->isSubPart)
  461. {
  462. if (is_array($this->background))
  463. {
  464. if (isset($this->background['color']) && $this->background['color'])
  465. {
  466. $this->pdf->setFillColorArray($this->background['color']);
  467. $this->pdf->Rect(0, 0, $this->pdf->getW(), $this->pdf->getH(), 'F');
  468. }
  469. if (isset($this->background['img']) && $this->background['img'])
  470. $this->pdf->Image($this->background['img'], $this->background['posX'], $this->background['posY'], $this->background['width']);
  471. }
  472. $this->setPageHeader();
  473. $this->setPageFooter();
  474. }
  475. $this->setMargins();
  476. $this->pdf->setY($this->margeTop);
  477. $this->setNewPositionForNewLine($curr);
  478. $this->maxH = 0;
  479. }
  480. /**
  481. * calcul de la position de debut de la prochaine ligne en fonction de l'alignement voulu
  482. *
  483. * @param integer position reelle courante si saut de ligne pendant l'ecriture d'un texte
  484. * @return null
  485. */
  486. protected function setNewPositionForNewLine($curr = null)
  487. {
  488. list($lx, $rx) = $this->getMargins($this->pdf->getY());
  489. $this->pdf->setX($lx);
  490. $wMax = $rx-$lx;
  491. $this->currentH = 0;
  492. if ($this->sub_part || $this->isSubPart || $this->forOneLine)
  493. {
  494. // $this->pdf->setWordSpacing(0);
  495. return null;
  496. }
  497. /*
  498. if (
  499. $this->style->value['text-align']!='right' &&
  500. $this->style->value['text-align']!='center' &&
  501. $this->style->value['text-align']!='justify'
  502. )
  503. {
  504. // $this->pdf->setWordSpacing(0);
  505. return null;
  506. }
  507. */
  508. $sub = null;
  509. $this->createSubHTML($sub);
  510. $sub->saveMargin(0, 0, $sub->pdf->getW()-$wMax);
  511. $sub->forOneLine = true;
  512. $sub->parse_pos = $this->parse_pos;
  513. $sub->parsing->code = $this->parsing->code;
  514. if ($curr!==null && $sub->parsing->code[$this->parse_pos]['name']=='write')
  515. {
  516. $txt = $sub->parsing->code[$this->parse_pos]['param']['txt'];
  517. $txt = str_replace('[[page_cu]]', $sub->page, $txt);
  518. $sub->parsing->code[$this->parse_pos]['param']['txt'] = substr($txt, $curr);
  519. }
  520. else
  521. $sub->parse_pos++;
  522. // pour chaque element identifi? par le parsing
  523. $res = null;
  524. for($sub->parse_pos; $sub->parse_pos<count($sub->parsing->code); $sub->parse_pos++)
  525. {
  526. $todo = $sub->parsing->code[$sub->parse_pos];
  527. $res = $sub->loadAction($todo);
  528. if (!$res) break;
  529. }
  530. $w = $sub->maxX; // largeur maximale
  531. $h = $sub->maxH; // hauteur maximale
  532. $e = ($res===null ? $sub->maxE : 0); // nombre d'?l?ments maximal
  533. $this->destroySubHTML($sub);
  534. if ($this->style->value['text-align']=='center')
  535. $this->pdf->setX(($rx+$this->pdf->getX()-$w)*0.5-0.01);
  536. elseif ($this->style->value['text-align']=='right')
  537. $this->pdf->setX($rx-$w-0.01);
  538. else
  539. $this->pdf->setX($lx);
  540. $this->currentH = $h;
  541. /*
  542. if ($this->style->value['text-align']=='justify' && $e>1)
  543. $this->pdf->setWordSpacing(($wMax-$w)/($e-1));
  544. else
  545. $this->pdf->setWordSpacing(0);
  546. */
  547. }
  548. /**
  549. * r?cup?ration du PDF
  550. *
  551. * @param string nom du fichier PDF
  552. * @param boolean destination
  553. * @return string contenu ?ventuel du pdf
  554. *
  555. *
  556. * Destination o? envoyer le document. Le param?tre peut prendre les valeurs suivantes :
  557. * true : equivalent ? I
  558. * false : equivalent ? S
  559. * 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.
  560. * D : envoyer au navigateur en for?ant le t?l?chargement, avec le nom indiqu? dans name.
  561. * F : sauver dans un fichier local, avec le nom indiqu? dans name (peut inclure un r?pertoire).
  562. * S : renvoyer le document sous forme de cha?ne. name est ignor?.
  563. */
  564. public function Output($name = '', $dest = false)
  565. {
  566. // nettoyage
  567. HTML2PDF::$TABLES = array();
  568. if ($this->DEBUG_actif)
  569. {
  570. $this->DEBUG_add('Before output');
  571. $this->pdf->Close();
  572. exit;
  573. }
  574. // interpretation des param?tres
  575. if ($dest===false) $dest = 'I';
  576. if ($dest===true) $dest = 'S';
  577. if ($dest==='') $dest = 'I';
  578. if ($name=='') $name='document.pdf';
  579. // verification de la destination
  580. $dest = strtoupper($dest);
  581. if (!in_array($dest, array('I', 'D', 'F', 'S'))) $dest = 'I';
  582. // verification du nom
  583. if (strtolower(substr($name, -4))!='.pdf')
  584. {
  585. echo 'ERROR : The output document name "'.$name.'" is not a PDF name';
  586. exit;
  587. }
  588. return $this->pdf->Output($name, $dest);
  589. }
  590. /**
  591. * preparation de HTML2PDF::$SUBOBJ utilis? pour la cr?ation des sous HTML2PDF
  592. *
  593. * @return null
  594. */
  595. protected function prepareSubObj()
  596. {
  597. $pdf = null;
  598. HTML2PDF::$SUBOBJ = new HTML2PDF(
  599. $this->sens,
  600. $this->format,
  601. $this->langue,
  602. $this->unicode,
  603. $this->encoding,
  604. array($this->defaultLeft,$this->defaultTop,$this->defaultRight,$this->defaultBottom)
  605. );
  606. // initialisation
  607. HTML2PDF::$SUBOBJ->setIsSubPart();
  608. HTML2PDF::$SUBOBJ->setTestTdInOnePage($this->testTDin1page);
  609. HTML2PDF::$SUBOBJ->setTestIsImage($this->testIsImage);
  610. HTML2PDF::$SUBOBJ->setDefaultFont($this->defaultFont);
  611. HTML2PDF::$SUBOBJ->style->css = &$this->style->css;
  612. HTML2PDF::$SUBOBJ->style->css_keys = &$this->style->css_keys;
  613. HTML2PDF::$SUBOBJ->pdf->cloneFontFrom($this->pdf);
  614. HTML2PDF::$SUBOBJ->style->setPdfParent($pdf);
  615. }
  616. /**
  617. * fonction de clonage pour la creation d'un sous HTML2PDF ? partir de HTML2PDF::$SUBOBJ
  618. *
  619. * @return null
  620. */
  621. public function __clone()
  622. {
  623. $this->pdf = clone $this->pdf;
  624. $this->parsing = clone $this->parsing;
  625. $this->style = clone $this->style;
  626. $this->style->setPdfParent($this->pdf);
  627. }
  628. /**
  629. * cr?ation d'un sous HTML2PDF pour la gestion des tableaux imbriqu?s
  630. *
  631. * @param HTML2PDF futur sous HTML2PDF pass? en r?f?rence pour cr?ation
  632. * @param integer marge eventuelle de l'objet si simulation d'un TD
  633. * @return null
  634. */
  635. protected function createSubHTML(&$sub_html, $cellmargin=0)
  636. {
  637. if (!HTML2PDF::$SUBOBJ) $this->prepareSubObj();
  638. // calcul de la largueur
  639. if ($this->style->value['width'])
  640. {
  641. $marge = $cellmargin*2;
  642. $marge+= $this->style->value['padding']['l'] + $this->style->value['padding']['r'];
  643. $marge+= $this->style->value['border']['l']['width'] + $this->style->value['border']['r']['width'];
  644. $marge = $this->pdf->getW() - $this->style->value['width'] + $marge;
  645. }
  646. else
  647. $marge = $this->margeLeft+$this->margeRight;
  648. //clonage
  649. $sub_html = clone HTML2PDF::$SUBOBJ;
  650. $sub_html->style->table = $this->style->table;
  651. $sub_html->style->value = $this->style->value;
  652. $sub_html->style->setOnlyLeft();
  653. $sub_html->setNewPage($this->format, $this->sens);
  654. $sub_html->initSubHtml($marge, $this->page, $this->defLIST);
  655. }
  656. /**
  657. * initialise le sous HTML2PDF. Ne pas utiliser directement. seul la fonction createSubHTML doit l'utiliser
  658. *
  659. * @return null
  660. */
  661. public function initSubHtml($marge, $page, $defLIST)
  662. {
  663. $this->saveMargin(0, 0, $marge);
  664. $this->defLIST = $defLIST;
  665. $this->page = $page;
  666. $this->pdf->setXY(0, 0);
  667. $this->style->FontSet();
  668. }
  669. public function setIsSubPart()
  670. {
  671. $this->isSubPart = true;
  672. }
  673. /**
  674. * destruction d'un sous HTML2PDF pour la gestion des tableaux imbriqu?s
  675. *
  676. * @return null
  677. */
  678. protected function destroySubHTML(&$sub_html)
  679. {
  680. unset($sub_html);
  681. $sub_html = null;
  682. }
  683. /**
  684. * Convertir un nombre arabe en nombre romain
  685. *
  686. * @param integer nombre ? convertir
  687. * @return string nombre converti
  688. */
  689. protected function listeArab2Rom($nb_ar)
  690. {
  691. $nb_b10 = array('I','X','C','M');
  692. $nb_b5 = array('V','L','D');
  693. $nb_ro = '';
  694. if ($nb_ar<1) return $nb_ar;
  695. if ($nb_ar>3999) return $nb_ar;
  696. for($i=3; $i>=0 ; $i--)
  697. {
  698. $chiffre=floor($nb_ar/pow(10,$i));
  699. if($chiffre>=1)
  700. {
  701. $nb_ar=$nb_ar-$chiffre*pow(10,$i);
  702. if($chiffre<=3)
  703. {
  704. for($j=$chiffre; $j>=1; $j--)
  705. {
  706. $nb_ro=$nb_ro.$nb_b10[$i];
  707. }
  708. }
  709. else if($chiffre==9)
  710. {
  711. $nb_ro=$nb_ro.$nb_b10[$i].$nb_b10[$i+1];
  712. }
  713. elseif($chiffre==4)
  714. {
  715. $nb_ro=$nb_ro.$nb_b10[$i].$nb_b5[$i];
  716. }
  717. else
  718. {
  719. $nb_ro=$nb_ro.$nb_b5[$i];
  720. for($j=$chiffre-5; $j>=1; $j--)
  721. {
  722. $nb_ro=$nb_ro.$nb_b10[$i];
  723. }
  724. }
  725. }
  726. }
  727. return $nb_ro;
  728. }
  729. /**
  730. * Ajouter un LI au niveau actuel
  731. *
  732. * @return null
  733. */
  734. protected function listeAddLi()
  735. {
  736. $this->defLIST[count($this->defLIST)-1]['nb']++;
  737. }
  738. protected function listeGetWidth() { return '7mm'; }
  739. protected function listeGetPadding() { return '1mm'; }
  740. /**
  741. * Recuperer le LI du niveau actuel
  742. *
  743. * @return string chaine ? afficher
  744. */
  745. protected function listeGetLi()
  746. {
  747. $im = $this->defLIST[count($this->defLIST)-1]['img'];
  748. $st = $this->defLIST[count($this->defLIST)-1]['style'];
  749. $nb = $this->defLIST[count($this->defLIST)-1]['nb'];
  750. $up = (substr($st, 0, 6)=='upper-');
  751. if ($im) return array(false, false, $im);
  752. switch($st)
  753. {
  754. case 'none':
  755. return array('helvetica', true, ' ');
  756. case 'upper-alpha':
  757. case 'lower-alpha':
  758. $str = '';
  759. while($nb>26)
  760. {
  761. $str = chr(96+$nb%26).$str;
  762. $nb = floor($nb/26);
  763. }
  764. $str = chr(96+$nb).$str;
  765. return array('helvetica', false, ($up ? strtoupper($str) : $str).'.');
  766. case 'upper-roman':
  767. case 'lower-roman':
  768. $str = $this->listeArab2Rom($nb);
  769. return array('helvetica', false, ($up ? strtoupper($str) : $str).'.');
  770. case 'decimal':
  771. return array('helvetica', false, $nb.'.');
  772. case 'square':
  773. return array('zapfdingbats', true, chr(110));
  774. case 'circle':
  775. return array('zapfdingbats', true, chr(109));
  776. case 'disc':
  777. default:
  778. return array('zapfdingbats', true, chr(108));
  779. }
  780. }
  781. /**
  782. * Ajouter un niveau de liste
  783. *
  784. * @param string type de liste : ul, ol
  785. * @param string style de la liste
  786. * @return null
  787. */
  788. protected function listeAddLevel($type = 'ul', $style = '', $img = null)
  789. {
  790. if ($img)
  791. {
  792. if (preg_match('/^url\(([^)]+)\)$/isU', trim($img), $match))
  793. $img = $match[1];
  794. else
  795. $img = null;
  796. }
  797. else
  798. $img = null;
  799. if (!in_array($type, array('ul', 'ol'))) $type = 'ul';
  800. if (!in_array($style, array('lower-alpha', 'upper-alpha', 'upper-roman', 'lower-roman', 'decimal', 'square', 'circle', 'disc', 'none'))) $style = '';
  801. if (!$style)
  802. {
  803. if ($type=='ul') $style = 'disc';
  804. else $style = 'decimal';
  805. }
  806. $this->defLIST[count($this->defLIST)] = array('style' => $style, 'nb' => 0, 'img' => $img);
  807. }
  808. /**
  809. * Supprimer un niveau de liste
  810. *
  811. * @return null
  812. */
  813. protected function listeDelLevel()
  814. {
  815. if (count($this->defLIST))
  816. {
  817. unset($this->defLIST[count($this->defLIST)-1]);
  818. $this->defLIST = array_values($this->defLIST);
  819. }
  820. }
  821. /**
  822. * traitement d'un code HTML fait pour HTML2PDF
  823. *
  824. * @param string code HTML ? convertir
  825. * @param boolean afficher en pdf (false) ou en html adapt? (true)
  826. * @return null
  827. */
  828. public function writeHTML($html, $vue = false)
  829. {
  830. // si c'est une vrai page HTML, une conversion s'impose
  831. if (preg_match('/<body/isU', $html))
  832. $html = $this->getHtmlFromPage($html);
  833. $html = str_replace('[[page_nb]]', '{nb}', $html);
  834. $html = str_replace('[[date_y]]', date('Y'), $html);
  835. $html = str_replace('[[date_m]]', date('m'), $html);
  836. $html = str_replace('[[date_d]]', date('d'), $html);
  837. $html = str_replace('[[date_h]]', date('H'), $html);
  838. $html = str_replace('[[date_i]]', date('i'), $html);
  839. $html = str_replace('[[date_s]]', date('s'), $html);
  840. // si on veut voir le r?sultat en HTML => on appelle la fonction
  841. if ($vue) $this->vueHTML($html);
  842. // sinon, traitement pour conversion en PDF :
  843. // parsing
  844. $this->sub_pdf = false;
  845. $this->style->readStyle($html);
  846. $this->parsing->setHTML($html);
  847. $this->parsing->parse();
  848. $this->makeHTMLcode();
  849. }
  850. /**
  851. * traitement du code d'une vrai page HTML pour l'adapter ? HTML2PDF
  852. *
  853. * @param string code HTML ? adapter
  854. * @return string code HTML adapt?
  855. */
  856. public function getHtmlFromPage($html)
  857. {
  858. $html = str_replace('<BODY', '<body', $html);
  859. $html = str_replace('</BODY', '</body', $html);
  860. // extraction du contenu
  861. $res = explode('<body', $html);
  862. if (count($res)<2) return $html;
  863. $content = '<page'.$res[1];
  864. $content = explode('</body', $content);
  865. $content = $content[0].'</page>';
  866. // extraction des balises link
  867. preg_match_all('/<link([^>]*)>/isU', $html, $match);
  868. foreach($match[0] as $src)
  869. $content = $src.'</link>'.$content;
  870. // extraction des balises style
  871. preg_match_all('/<style[^>]*>(.*)<\/style[^>]*>/isU', $html, $match);
  872. foreach($match[0] as $src)
  873. $content = $src.$content;
  874. return $content;
  875. }
  876. /**
  877. * execute les diff?rentes actions du code HTML
  878. *
  879. * @return null
  880. */
  881. protected function makeHTMLcode()
  882. {
  883. // pour chaque element identifi? par le parsing
  884. for($this->parse_pos=0; $this->parse_pos<count($this->parsing->code); $this->parse_pos++)
  885. {
  886. // r?cup?ration de l'?l?ment
  887. $todo = $this->parsing->code[$this->parse_pos];
  888. // si c'est une ouverture de tableau
  889. if (in_array($todo['name'], array('table', 'ul', 'ol')) && !$todo['close'])
  890. {
  891. // on va cr?er un sous HTML, et on va travailler sur une position temporaire
  892. $tag_open = $todo['name'];
  893. $this->sub_part = true;
  894. $this->temp_pos = $this->parse_pos;
  895. // pour tous les ?l?ments jusqu'? la fermeture de la table afin de pr?parer les dimensions
  896. while(isset($this->parsing->code[$this->temp_pos]) && !($this->parsing->code[$this->temp_pos]['name']==$tag_open && $this->parsing->code[$this->temp_pos]['close']))
  897. {
  898. $this->loadAction($this->parsing->code[$this->temp_pos]);
  899. $this->temp_pos++;
  900. }
  901. if (isset($this->parsing->code[$this->temp_pos])) $this->loadAction($this->parsing->code[$this->temp_pos]);
  902. $this->sub_part = false;
  903. }
  904. // chargement de l'action correspondant ? l'?l?ment
  905. $this->loadAction($todo);
  906. }
  907. }
  908. /**
  909. * affichage en mode HTML du contenu
  910. *
  911. * @param string contenu
  912. * @return null
  913. */
  914. protected function vueHTML($content)
  915. {
  916. $content = preg_replace('/<page_header([^>]*)>/isU', '<hr>'.HTML2PDF::textGET('vue01').' : $1<hr><div$1>', $content);
  917. $content = preg_replace('/<page_footer([^>]*)>/isU', '<hr>'.HTML2PDF::textGET('vue02').' : $1<hr><div$1>', $content);
  918. $content = preg_replace('/<page([^>]*)>/isU', '<hr>'.HTML2PDF::textGET('vue03').' : $1<hr><div$1>', $content);
  919. $content = preg_replace('/<\/page([^>]*)>/isU', '</div><hr>', $content);
  920. $content = preg_replace('/<bookmark([^>]*)>/isU', '<hr>bookmark : $1<hr>', $content);
  921. $content = preg_replace('/<\/bookmark([^>]*)>/isU', '', $content);
  922. $content = preg_replace('/<barcode([^>]*)>/isU', '<hr>barcode : $1<hr>', $content);
  923. $content = preg_replace('/<\/barcode([^>]*)>/isU', '', $content);
  924. $content = preg_replace('/<qrcode([^>]*)>/isU', '<hr>qrcode : $1<hr>', $content);
  925. $content = preg_replace('/<\/qrcode([^>]*)>/isU', '', $content);
  926. echo '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
  927. <html>
  928. <head>
  929. <title>'.HTML2PDF::textGET('vue04').' HTML</title>
  930. <meta http-equiv="Content-Type" content="text/html; charset='.$this->encoding.'" >
  931. </head>
  932. <body style="padding: 10px; font-size: 10pt;font-family: Verdana;">
  933. '.$content.'
  934. </body>
  935. </html>';
  936. exit;
  937. }
  938. /**
  939. * chargement de l'action correspondante ? un element de parsing
  940. *
  941. * @param array ?l?ment de parsing
  942. * @return null
  943. */
  944. protected function loadAction($row)
  945. {
  946. // nom de l'action
  947. $fnc = ($row['close'] ? 'c_' : 'o_').strtoupper($row['name']);
  948. // parametres de l'action
  949. $param = $row['param'];
  950. // si aucune page n'est cr??, on la cr??
  951. if ($fnc!='o_PAGE' && $this->firstPage)
  952. {
  953. $this->setNewPage();
  954. }
  955. // lancement de l'action
  956. if (is_callable(array(&$this, $fnc)))
  957. {
  958. $res = $this->{$fnc}($param);
  959. $this->previousCall = $fnc;
  960. return $res;
  961. }
  962. else
  963. {
  964. HTML2PDF::makeError(1, __FILE__, __LINE__, strtoupper($row['name']), $this->parsing->getHtmlErrorCode($row['html_pos']));
  965. return false;
  966. }
  967. }
  968. /**
  969. * balise : PAGE
  970. * mode : OUVERTURE
  971. *
  972. * @param array param?tres de l'?l?ment de parsing
  973. * @return null
  974. */
  975. protected function o_PAGE($param)
  976. {
  977. if ($this->forOneLine) return false;
  978. if ($this->DEBUG_actif) $this->DEBUG_add('PAGE n?'.($this->page+1), true);
  979. $newPageSet= (!isset($param['pageset']) || $param['pageset']!='old');
  980. $this->maxH = 0;
  981. if ($newPageSet)
  982. {
  983. $this->subHEADER = array();
  984. $this->subFOOTER = array();
  985. // identification de l'orientation demand?e
  986. $orientation = '';
  987. if (isset($param['orientation']))
  988. {
  989. $param['orientation'] = strtolower($param['orientation']);
  990. if ($param['orientation']=='p') $orientation = 'P';
  991. if ($param['orientation']=='portrait') $orientation = 'P';
  992. if ($param['orientation']=='l') $orientation = 'L';
  993. if ($param['orientation']=='paysage') $orientation = 'L';
  994. if ($param['orientation']=='landscape') $orientation = 'L';
  995. }
  996. // identification de l'orientation demand?e
  997. $format = null;
  998. if (isset($param['format']))
  999. {
  1000. $format = strtolower($param['format']);
  1001. if (preg_match('/^([0-9]+)x([0-9]+)$/isU', $format, $match))
  1002. {
  1003. $format = array(intval($match[1]), intval($match[2]));
  1004. }
  1005. }
  1006. // identification des propri?t?s du background
  1007. $background = array();
  1008. if (isset($param['backimg']))
  1009. {
  1010. $background['img'] = isset($param['backimg']) ? $param['backimg'] : ''; // nom de l'image
  1011. $background['posX'] = isset($param['backimgx']) ? $param['backimgx'] : 'center'; // position horizontale de l'image
  1012. $background['posY'] = isset($param['backimgy']) ? $param['backimgy'] : 'middle'; // position verticale de l'image
  1013. $background['width'] = isset($param['backimgw']) ? $param['backimgw'] : '100%'; // taille de l'image (100% = largueur de la feuille)
  1014. // conversion du nom de l'image, en cas de param?tres en _GET
  1015. $background['img'] = str_replace('&amp;', '&', $background['img']);
  1016. // conversion des positions
  1017. if ($background['posX']=='left') $background['posX'] = '0%';
  1018. if ($background['posX']=='center') $background['posX'] = '50%';
  1019. if ($background['posX']=='right') $background['posX'] = '100%';
  1020. if ($background['posY']=='top') $background['posY'] = '0%';
  1021. if ($background['posY']=='middle') $background['posY'] = '50%';
  1022. if ($background['posY']=='bottom') $background['posY'] = '100%';
  1023. // si il y a une image de pr?cis?
  1024. if ($background['img'])
  1025. {
  1026. // est-ce que c'est une image ?
  1027. $infos=@GetImageSize($background['img']);
  1028. if (count($infos)>1)
  1029. {
  1030. // taille de l'image, en fonction de la taille sp?cifi?e.
  1031. $Wi = $this->style->ConvertToMM($background['width'], $this->pdf->getW());
  1032. $Hi = $Wi*$infos[1]/$infos[0];
  1033. // r?cup?ration des dimensions et positions de l'image
  1034. $background['width'] = $Wi;
  1035. $background['posX'] = $this->style->ConvertToMM($background['posX'], $this->pdf->getW() - $Wi);
  1036. $background['posY'] = $this->style->ConvertToMM($background['posY'], $this->pdf->getH() - $Hi);
  1037. }
  1038. else
  1039. $background = array();
  1040. }
  1041. else
  1042. $background = array();
  1043. }
  1044. // marges TOP et BOTTOM pour le texte.
  1045. $background['top'] = isset($param['backtop']) ? $param['backtop'] : '0';
  1046. $background['bottom'] = isset($param['backbottom']) ? $param['backbottom'] : '0';
  1047. $background['left'] = isset($param['backleft']) ? $param['backleft'] : '0';
  1048. $background['right'] = isset($param['backright']) ? $param['backright'] : '0';
  1049. if (preg_match('/^([0-9]*)$/isU', $background['top'])) $background['top'] .= 'mm';
  1050. if (preg_match('/^([0-9]*)$/isU', $background['bottom'])) $background['bottom'] .= 'mm';
  1051. if (preg_match('/^([0-9]*)$/isU', $background['left'])) $background['left'] .= 'mm';
  1052. if (preg_match('/^([0-9]*)$/isU', $background['right'])) $background['right'] .= 'mm';
  1053. $background['top'] = $this->style->ConvertToMM($background['top'], $this->pdf->getH());
  1054. $background['bottom'] = $this->style->ConvertToMM($background['bottom'], $this->pdf->getH());
  1055. $background['left'] = $this->style->ConvertToMM($background['left'], $this->pdf->getW());
  1056. $background['right'] = $this->style->ConvertToMM($background['right'], $this->pdf->getW());
  1057. $res = false;
  1058. $background['color'] = isset($param['backcolor']) ? $this->style->ConvertToColor($param['backcolor'], $res) : null;
  1059. if (!$res) $background['color'] = null;
  1060. $this->style->save();
  1061. $this->style->analyse('PAGE', $param);
  1062. $this->style->setPosition();
  1063. $this->style->FontSet();
  1064. // nouvelle page
  1065. $this->setNewPage($format, $orientation, $background);
  1066. // footer automatique
  1067. if (isset($param['footer']))
  1068. {
  1069. $lst = explode(';', $param['footer']);
  1070. foreach($lst as $key => $val) $lst[$key] = trim(strtolower($val));
  1071. $page = in_array('page', $lst);
  1072. $date = in_array('date', $lst);
  1073. $heure = in_array('heure', $lst);
  1074. $form = in_array('form', $lst);
  1075. }
  1076. else
  1077. {
  1078. $page = null;
  1079. $date = null;
  1080. $heure = null;
  1081. $form = null;
  1082. }
  1083. $this->pdf->SetMyFooter($page, $date, $heure, $form);
  1084. }
  1085. else
  1086. {
  1087. $this->style->save();
  1088. $this->style->analyse('PAGE', $param);
  1089. $this->style->setPosition();
  1090. $this->style->FontSet();
  1091. $this->setNewPage();
  1092. }
  1093. return true;
  1094. }
  1095. /**
  1096. * balise : PAGE
  1097. * mode : FERMETURE
  1098. *
  1099. * @param array param?tres de l'?l?ment de parsing
  1100. * @return null
  1101. */
  1102. protected function c_PAGE($param)
  1103. {
  1104. if ($this->forOneLine) return false;
  1105. $this->maxH = 0;
  1106. $this->style->load();
  1107. $this->style->FontSet();
  1108. if ($this->DEBUG_actif) $this->DEBUG_add('PAGE n?'.$this->page, false);
  1109. return true;
  1110. }
  1111. protected function o_PAGE_HEADER($param)
  1112. {
  1113. if ($this->forOneLine) return false;
  1114. $this->subHEADER = array();
  1115. for($this->parse_pos; $this->parse_pos<count($this->parsing->code); $this->parse_pos++)
  1116. {
  1117. $todo = $this->parsing->code[$this->parse_pos];
  1118. if ($todo['name']=='page_header') $todo['name']='page_header_sub';
  1119. $this->subHEADER[] = $todo;
  1120. if (strtolower($todo['name'])=='page_header_sub' && $todo['close']) break;
  1121. }
  1122. $this->setPageHeader();
  1123. return true;
  1124. }
  1125. protected function o_PAGE_FOOTER($param)
  1126. {
  1127. if ($this->forOneLine) return false;
  1128. $this->subFOOTER = array();
  1129. for($this->parse_pos; $this->parse_pos<count($this->parsing->code); $this->parse_pos++)
  1130. {
  1131. $todo = $this->parsing->code[$this->parse_pos];
  1132. if ($todo['name']=='page_footer') $todo['name']='page_footer_sub';
  1133. $this->subFOOTER[] = $todo;
  1134. if (strtolower($todo['name'])=='page_footer_sub' && $todo['close']) break;
  1135. }
  1136. $this->setPageFooter();
  1137. return true;
  1138. }
  1139. protected function o_PAGE_HEADER_SUB($param)
  1140. {
  1141. if ($this->forOneLine) return false;
  1142. // sauvegarde de l'?tat
  1143. $this->subSTATES = array();
  1144. $this->subSTATES['x'] = $this->pdf->getX();
  1145. $this->subSTATES['y'] = $this->pdf->getY();
  1146. $this->subSTATES['s'] = $this->style->value;
  1147. $this->subSTATES['t'] = $this->style->table;
  1148. $this->subSTATES['ml'] = $this->margeLeft;
  1149. $this->subSTATES['mr'] = $this->margeRight;
  1150. $this->subSTATES['mt'] = $this->margeTop;
  1151. $this->subSTATES['mb'] = $this->margeBottom;
  1152. $this->subSTATES['mp'] = $this->pageMarges;
  1153. // nouvel etat pour le footer
  1154. $this->pageMarges = array();
  1155. $this->margeLeft = $this->defaultLeft;
  1156. $this->margeRight = $this->defaultRight;
  1157. $this->margeTop = $this->defaultTop;
  1158. $this->margeBottom = $this->defaultBottom;
  1159. $this->pdf->SetMargins($this->margeLeft, $this->margeTop, $this->margeRight);
  1160. $this->pdf->SetAutoPageBreak(false, $this->margeBottom);
  1161. $this->pdf->setXY($this->defaultLeft, $this->defaultTop);
  1162. $this->style->initStyle();
  1163. $this->style->resetStyle();
  1164. $this->style->value['width'] = $this->pdf->getW() - $this->defaultLeft - $this->defaultRight;
  1165. $this->style->table = array();
  1166. $this->style->save();
  1167. $this->style->analyse('page_header_sub', $param);
  1168. $this->style->setPosition();
  1169. $this->style->FontSet();
  1170. $this->setNewPositionForNewLine();
  1171. return true;
  1172. }
  1173. protected function c_PAGE_HEADER_SUB($param)
  1174. {
  1175. if ($this->forOneLine) return false;
  1176. $this->style->load();
  1177. // retablissement de l'etat
  1178. $this->style->value = $this->subSTATES['s'];
  1179. $this->style->table = $this->subSTATES['t'];
  1180. $this->pageMarges = $this->subSTATES['mp'];
  1181. $this->margeLeft = $this->subSTATES['ml'];
  1182. $this->margeRight = $this->subSTATES['mr'];
  1183. $this->margeTop = $this->subSTATES['mt'];
  1184. $this->margeBottom = $this->subSTATES['mb'];
  1185. $this->pdf->SetMargins($this->margeLeft, $this->margeTop, $this->margeRight);
  1186. $this->pdf->setbMargin($this->margeBottom);
  1187. $this->pdf->SetAutoPageBreak(false, $this->margeBottom);
  1188. $this->pdf->setXY($this->subSTATES['x'], $this->subSTATES['y']);
  1189. $this->style->FontSet();
  1190. $this->maxH = 0;
  1191. return true;
  1192. }
  1193. protected function o_PAGE_FOOTER_SUB($param)
  1194. {
  1195. if ($this->forOneLine) return false;
  1196. $this->subSTATES = array();
  1197. $this->subSTATES['x'] = $this->pdf->getX();
  1198. $this->subSTATES['y'] = $this->pdf->getY();
  1199. $this->subSTATES['s'] = $this->style->value;
  1200. $this->subSTATES['t'] = $this->style->table;
  1201. $this->subSTATES['ml'] = $this->margeLeft;
  1202. $this->subSTATES['mr'] = $this->margeRight;
  1203. $this->subSTATES['mt'] = $this->margeTop;
  1204. $this->subSTATES['mb'] = $this->margeBottom;
  1205. $this->subSTATES['mp'] = $this->pageMarges;
  1206. // nouvel etat pour le footer
  1207. $this->pageMarges = array();
  1208. $this->margeLeft = $this->defaultLeft;
  1209. $this->margeRight = $this->defaultRight;
  1210. $this->margeTop = $this->defaultTop;
  1211. $this->margeBottom = $this->defaultBottom;
  1212. $this->pdf->SetMargins($this->margeLeft, $this->margeTop, $this->margeRight);
  1213. $this->pdf->SetAutoPageBreak(false, $this->margeBottom);
  1214. $this->pdf->setXY($this->defaultLeft, $this->defaultTop);
  1215. $this->style->initStyle();
  1216. $this->style->resetStyle();
  1217. $this->style->value['width'] = $this->pdf->getW() - $this->defaultLeft - $this->defaultRight;
  1218. $this->style->table = array();
  1219. // on en cr?? un sous HTML que l'on transforme en PDF
  1220. // pour r?cup?rer la hauteur
  1221. // on extrait tout ce qui est contenu dans le FOOTER
  1222. $sub = null;
  1223. $this->CreateSubHTML($sub);
  1224. $sub->parsing->code = $this->parsing->getLevel($this->parse_pos);
  1225. $sub->MakeHTMLcode();
  1226. $this->pdf->setY($this->pdf->getH() - $sub->maxY - $this->defaultBottom - 0.01);
  1227. $this->destroySubHTML($sub);
  1228. $this->style->save();
  1229. $this->style->analyse('page_footer_sub', $param);
  1230. $this->style->setPosition();
  1231. $this->style->FontSet();
  1232. $this->setNewPositionForNewLine();
  1233. return true;
  1234. }
  1235. protected function c_PAGE_FOOTER_SUB($param)
  1236. {
  1237. if ($this->forOneLine) return false;
  1238. $this->style->load();
  1239. $this->style->value = $this->subSTATES['s'];
  1240. $this->style->table = $this->subSTATES['t'];
  1241. $this->pageMarges = $this->subSTATES['mp'];
  1242. $this->margeLeft = $this->subSTATES['ml'];
  1243. $this->margeRight = $this->subSTATES['mr'];
  1244. $this->margeTop = $this->subSTATES['mt'];
  1245. $this->margeBottom = $this->subSTATES['mb'];
  1246. $this->pdf->SetMargins($this->margeLeft, $this->margeTop, $this->margeRight);
  1247. $this->pdf->SetAutoPageBreak(false, $this->margeBottom);
  1248. $this->pdf->setXY($this->subSTATES['x'], $this->subSTATES['y']);
  1249. $this->style->FontSet();
  1250. $this->maxH = 0;
  1251. return true;
  1252. }
  1253. /**
  1254. * balise : NOBREAK
  1255. * mode : OUVERTURE
  1256. *
  1257. * @param array param?tres de l'?l?ment de parsing
  1258. * @return null
  1259. */
  1260. protected function o_NOBREAK($param)
  1261. {
  1262. if ($this->forOneLine) return false;
  1263. $this->maxH = 0;
  1264. // on en cr?? un sous HTML que l'on transforme en PDF
  1265. // pour analyse les dimensions
  1266. // et voir si ca rentre
  1267. $sub = null;
  1268. $this->CreateSubHTML($sub);
  1269. $sub->parsing->code = $this->parsing->getLevel($this->parse_pos);
  1270. $sub->MakeHTMLcode();
  1271. $y = $this->pdf->getY();
  1272. if (
  1273. $sub->maxY < ($this->pdf->getH() - $this->pdf->gettMargin()-$this->pdf->getbMargin()) &&
  1274. $y + $sub->maxY>=($this->pdf->getH() - $this->pdf->getbMargin())
  1275. )
  1276. $this->setNewPage();
  1277. $this->destroySubHTML($sub);
  1278. return true;
  1279. }
  1280. /**
  1281. * balise : NOBREAK
  1282. * mode : FERMETURE
  1283. *
  1284. * @param array param?tres de l'?l?ment de parsing
  1285. * @return null
  1286. */
  1287. protected function c_NOBREAK($param)
  1288. {
  1289. if ($this->forOneLine) return false;
  1290. $this->maxH = 0;
  1291. return true;
  1292. }
  1293. /**
  1294. * balise : DIV
  1295. * mode : OUVERTURE
  1296. *
  1297. * @param array param?tres de l'?l?ment de parsing
  1298. * @return null
  1299. */
  1300. protected function o_DIV($param, $other = 'div')
  1301. {
  1302. if ($this->forOneLine) return false;
  1303. if ($this->DEBUG_actif) $this->DEBUG_add('DIV', true);
  1304. $this->style->save();
  1305. $this->style->analyse($other, $param);
  1306. $this->style->FontSet();
  1307. $align_object = null;
  1308. if ($this->style->value['margin-auto']) $align_object = 'center';
  1309. $marge = array();
  1310. $marge['l'] = $this->style->value['border']['l']['width'] + $this->style->value['padding']['l']+0.03;
  1311. $marge['r'] = $this->style->value['border']['r']['width'] + $this->style->value['padding']['r']+0.03;
  1312. $marge['t'] = $this->style->value['border']['t']['width'] + $this->style->value['padding']['t']+0.03;
  1313. $marge['b'] = $this->style->value['border']['b']['width'] + $this->style->value['padding']['b']+0.03;
  1314. // on extrait tout ce qui est contenu dans la DIV
  1315. $level = $this->parsing->getLevel($this->parse_pos);
  1316. // on en cr?? un sous HTML que l'on transforme en PDF
  1317. // pour analyse les dimensions
  1318. $w = 0; $h = 0;
  1319. if (count($level))
  1320. {
  1321. $sub = null;
  1322. $this->CreateSubHTML($sub);
  1323. $sub->parsing->code = $level;
  1324. $sub->MakeHTMLcode();
  1325. $w = $sub->maxX;
  1326. $h = $sub->maxY;
  1327. $this->destroySubHTML($sub);
  1328. }
  1329. $w_reel = $w;
  1330. $h_reel = $h;
  1331. // if (($w==0 && $this->style->value['width']==0) || ($w>$this->style->value['width']) || $this->style->value['position']=='absolute')
  1332. $w+= $marge['l']+$marge['r']+0.001;
  1333. $h+= $marge['t']+$marge['b']+0.001;
  1334. if ($this->style->value['overflow']=='hidden')
  1335. {
  1336. $over_w = max($w, $this->style->value['width']);
  1337. $over_h = max($h, $this->style->value['height']);
  1338. $overflow = true;
  1339. $this->style->value['old_maxX'] = $this->maxX;
  1340. $this->style->value['old_maxY'] = $this->maxY;
  1341. $this->style->value['old_maxH'] = $this->maxH;
  1342. $this->style->value['old_overflow'] = $this->isInOverflow;
  1343. $this->isInOverflow = true;
  1344. }
  1345. else
  1346. {
  1347. $over_w = null;
  1348. $over_h = null;
  1349. $overflow = false;
  1350. $this->style->value['width'] = max($w, $this->style->value['width']);
  1351. $this->style->value['height'] = max($h, $this->style->value['height']);
  1352. }
  1353. switch($this->style->value['rotate'])
  1354. {
  1355. case 90:
  1356. $tmp = $over_h; $over_h = $over_w; $over_w = $tmp;
  1357. $tmp = $h_reel; $h_reel = $w_reel; $w_reel = $tmp;
  1358. unset($tmp);
  1359. $w = $this->style->value['height'];
  1360. $h = $this->style->value['width'];
  1361. $t_x =-$h;
  1362. $t_y = 0;
  1363. break;
  1364. case 180:
  1365. $w = $this->style->value['width'];
  1366. $h = $this->style->value['height'];
  1367. $t_x = -$w;
  1368. $t_y = -$h;
  1369. break;
  1370. case 270:
  1371. $tmp = $over_h; $over_h = $over_w; $over_w = $tmp;
  1372. $tmp = $h_reel; $h_reel = $w_reel; $w_reel = $tmp;
  1373. unset($tmp);
  1374. $w = $this->style->value['height'];
  1375. $h = $this->style->value['width'];
  1376. $t_x = 0;
  1377. $t_y =-$w;
  1378. break;
  1379. default:
  1380. $w = $this->style->value['width'];
  1381. $h = $this->style->value['height'];
  1382. $t_x = 0;
  1383. $t_y = 0;
  1384. break;
  1385. }
  1386. if (!$this->style->value['position'])
  1387. {
  1388. if (
  1389. $w < ($this->pdf->getW() - $this->pdf->getlMargin()-$this->pdf->getrMargin()) &&
  1390. $this->pdf->getX() + $w>=($this->pdf->getW() - $this->pdf->getrMargin())
  1391. )
  1392. $this->o_BR(array());
  1393. if (
  1394. ($h < ($this->pdf->getH() - $this->pdf->gettMargin()-$this->pdf->getbMargin())) &&
  1395. ($this->pdf->getY() + $h>=($this->pdf->getH() - $this->pdf->getbMargin())) &&
  1396. !$this->isInOverflow
  1397. )
  1398. $this->setNewPage();
  1399. // en cas d'alignement => correction
  1400. $old = $this->style->getOldValues();
  1401. $parent_w = $old['width'] ? $old['width'] : $this->pdf->getW() - $this->pdf->getlMargin() - $this->pdf->getrMargin();
  1402. if ($parent_w>$w)
  1403. {
  1404. if ($align_object=='center') $this->pdf->setX($this->pdf->getX() + ($parent_w-$w)*0.5);
  1405. else if ($align_object=='right') $this->pdf->setX($this->pdf->getX() + $parent_w-$w);
  1406. }
  1407. $this->style->setPosition();
  1408. }
  1409. else
  1410. {
  1411. // en cas d'alignement => correction
  1412. $old = $this->style->getOldValues();
  1413. $parent_w = $old['width'] ? $old['width'] : $this->pdf->getW() - $this->pdf->getlMargin() - $this->pdf->getrMargin();
  1414. if ($parent_w>$w)
  1415. {
  1416. if ($align_object=='center') $this->pdf->setX($this->pdf->getX() + ($parent_w-$w)*0.5);
  1417. else if ($align_object=='right') $this->pdf->setX($this->pdf->getX() + $parent_w-$w);
  1418. }
  1419. $this->style->setPosition();
  1420. $this->saveMax();
  1421. $this->saveX = 0;
  1422. $this->saveY = 0;
  1423. $this->saveH = 0;
  1424. }
  1425. if ($this->style->value['rotate'])
  1426. {
  1427. $this->pdf->startTransform();
  1428. $this->pdf->setRotation($this->style->value['rotate']);
  1429. $this->pdf->setTranslate($t_x, $t_y);
  1430. }
  1431. // initialisation du style des bordures de la div
  1432. $this->drawRectangle(
  1433. $this->style->value['x'],
  1434. $this->style->value['y'],
  1435. $this->style->value['width'],
  1436. $this->style->value['height'],
  1437. $this->style->value['border'],
  1438. $this->style->value['padding'],
  1439. 0,
  1440. $this->style->value['background']
  1441. );
  1442. $marge = array();
  1443. $marge['l'] = $this->style->value['border']['l']['width'] + $this->style->value['padding']['l']+0.03;
  1444. $marge['r'] = $this->style->value['border']['r']['width'] + $this->style->value['padding']['r']+0.03;
  1445. $marge['t'] = $this->style->value['border']['t']['width'] + $this->style->value['padding']['t']+0.03;
  1446. $marge['b'] = $this->style->value['border']['b']['width'] + $this->style->value['padding']['b']+0.03;
  1447. $this->style->value['width'] -= $marge['l']+$marge['r'];
  1448. $this->style->value['height']-= $marge['t']+$marge['b'];
  1449. // positionnement en fonction des alignements
  1450. $x_corr = 0;
  1451. $y_corr = 0;
  1452. if (!$this->sub_part && !$this->isSubPart)
  1453. {
  1454. switch($this->style->value['text-align'])
  1455. {
  1456. case 'right': $x_corr = ($this->style->value['width']-$w_reel); break;
  1457. case 'center': $x_corr = ($this->style->value['width']-$w_reel)*0.5; break;
  1458. }
  1459. if ($x_corr>0) $x_corr=0;
  1460. switch($this->style->value['vertical-align'])
  1461. {
  1462. case 'bottom': $y_corr = ($this->style->value['height']-$h_reel); break;
  1463. case 'middle': $y_corr = ($this->style->value['height']-$h_reel)*0.5; break;
  1464. }
  1465. }
  1466. if ($overflow)
  1467. {
  1468. $over_w-= $marge['l']+$marge['r'];
  1469. $over_h-= $marge['t']+$marge['b'];
  1470. $this->pdf->clippingPathOpen(
  1471. $this->style->value['x']+$marge['l'],
  1472. $this->style->value['y']+$marge['t'],
  1473. $this->style->value['width'],
  1474. $this->style->value['height']
  1475. );
  1476. $this->style->value['x']+= $x_corr;
  1477. // limitation des marges aux dimensions du contenu
  1478. $mL = $this->style->value['x']+$marge['l'];
  1479. $mR = $this->pdf->getW() - $mL - $over_w;
  1480. }
  1481. else
  1482. {
  1483. // limitation des marges aux dimensions de la div
  1484. $mL = $this->style->value['x']+$marge['l'];
  1485. $mR = $this->pdf->getW() - $mL - $this->style->value['width'];
  1486. }
  1487. $x = $this->style->value['x']+$marge['l'];
  1488. $y = $this->style->value['y']+$marge['t']+$y_corr;
  1489. $this->saveMargin($mL, 0, $mR);
  1490. $this->pdf->setXY($x, $y);
  1491. $this->setNewPositionForNewLine();
  1492. return true;
  1493. }
  1494. protected function o_BLOCKQUOTE($param) { return $this->o_DIV($param, 'blockquote'); }
  1495. /**
  1496. * balise : DIV
  1497. * mode : FERMETURE
  1498. *
  1499. * @param array param?tres de l'?l?ment de parsing
  1500. * @return null
  1501. */
  1502. protected function c_DIV($param)
  1503. {
  1504. if ($this->forOneLine) return false;
  1505. if ($this->style->value['overflow']=='hidden')
  1506. {
  1507. $this->maxX = $this->style->value['old_maxX'];
  1508. $this->maxY = $this->style->value['old_maxY'];
  1509. $this->maxH = $this->style->value['old_maxH'];
  1510. $this->isInOverflow = $this->style->value['old_overflow'];
  1511. $this->pdf->clippingPathClose();
  1512. }
  1513. if ($this->style->value['rotate'])
  1514. $this->pdf->stopTransform();
  1515. $marge = array();
  1516. $marge['l'] = $this->style->value['border']['l']['width'] + $this->style->value['padding']['l']+0.03;
  1517. $marge['r'] = $this->style->value['border']['r']['width'] + $this->style->value['padding']['r']+0.03;
  1518. $marge['t'] = $this->style->value['border']['t']['width'] + $this->style->value['padding']['t']+0.03;
  1519. $marge['b'] = $this->style->value['border']['b']['width'] + $this->style->value['padding']['b']+0.03;
  1520. $x = $this->style->value['x'];
  1521. $y = $this->style->value['y'];
  1522. $w = $this->style->value['width']+$marge['l']+$marge['r']+$this->style->value['margin']['r'];
  1523. $h = $this->style->value['height']+$marge['t']+$marge['b']+$this->style->value['margin']['b'];
  1524. switch($this->style->value['rotate'])
  1525. {
  1526. case 90:
  1527. $t = $w; $w = $h; $h = $t;
  1528. break;
  1529. case 270:
  1530. $t = $w; $w = $h; $h = $t;
  1531. break;
  1532. default:
  1533. break;
  1534. }
  1535. if ($this->style->value['position']!='absolute')
  1536. {
  1537. // position
  1538. $this->pdf->setXY($x+$w, $y);
  1539. // position MAX
  1540. $this->maxX = max($this->maxX, $x+$w);
  1541. $this->maxY = max($this->maxY, $y+$h);
  1542. $this->maxH = max($this->maxH, $h);
  1543. }
  1544. else
  1545. {
  1546. // position
  1547. $this->pdf->setXY($this->style->value['xc'], $this->style->value['yc']);
  1548. $this->loadMax();
  1549. }
  1550. $block = ($this->style->value['display']!='inline' && $this->style->value['position']!='absolute');
  1551. $this->style->load();
  1552. $this->style->FontSet();
  1553. $this->loadMargin();
  1554. if ($block) $this->o_BR(array());
  1555. if ($this->DEBUG_actif) $this->DEBUG_add('DIV', false);
  1556. return true;
  1557. }
  1558. protected function c_BLOCKQUOTE($param) { return $this->c_DIV($param); }
  1559. /**
  1560. * balise : BARCODE
  1561. * mode : OUVERTURE
  1562. *
  1563. * @param array param?tres de l'?l?ment de parsing
  1564. * @return null
  1565. */
  1566. protected function o_BARCODE($param)
  1567. {
  1568. // pour compatibilit? < 3.29
  1569. $lst_barcode = array();
  1570. $lst_barcode['UPC_A'] = 'UPCA';
  1571. $lst_barcode['CODE39'] = 'C39';
  1572. if (!isset($param['type'])) $param['type'] = 'C39';
  1573. if (!isset($param['value'])) $param['value'] = 0;
  1574. if (!isset($param['label'])) $param['label'] = 'label';
  1575. if (!isset($param['style']['color'])) $param['style']['color'] = '#000000';
  1576. $param['type'] = strtoupper($param['type']);
  1577. if (isset($lst_barcode[$param['type']])) $param['type'] = $lst_barcode[$param['type']];
  1578. $this->style->save();
  1579. $this->style->analyse('barcode', $param);
  1580. $this->style->setPosition();
  1581. $this->style->FontSet();
  1582. $x = $this->pdf->getX();
  1583. $y = $this->pdf->getY();
  1584. $w = $this->style->value['width']; if (!$w) $w = $this->style->ConvertToMM('30mm');
  1585. $h = $this->style->value['height']; if (!$h) $h = $this->style->ConvertToMM('10mm');
  1586. $txt = ($param['label']!=='none' ? $this->style->value['font-size'] : false);
  1587. $c = $this->style->value['color'];
  1588. $infos = $this->pdf->myBarcode($param['value'], $param['type'], $x, $y, $w, $h, $txt, $c);
  1589. // position maximale globale
  1590. $this->maxX = max($this->maxX, $x+$infos[0]);
  1591. $this->maxY = max($this->maxY, $y+$infos[1]);
  1592. $this->maxH = max($this->maxH, $infos[1]);
  1593. $this->maxE++;
  1594. $this->pdf->setXY($x+$infos[0], $y);
  1595. $this->style->load();
  1596. $this->style->FontSet();
  1597. return true;
  1598. }
  1599. /**
  1600. * balise : BARCODE
  1601. * mode : FERMETURE
  1602. *
  1603. * @param array param?tres de l'?l?ment de parsing
  1604. * @return null
  1605. */
  1606. protected function c_BARCODE($param)
  1607. {
  1608. // completement inutile
  1609. return true;
  1610. }
  1611. /**
  1612. * balise : QRCODE
  1613. * mode : OUVERTURE
  1614. *
  1615. * @param array param?tres de l'?l?ment de parsing
  1616. * @return null
  1617. */
  1618. protected function o_QRCODE($param)
  1619. {
  1620. if ($this->DEBUG_actif) $this->DEBUG_add('QRCODE', true);
  1621. if (!isset($param['value'])) $param['value'] = '';
  1622. if (!isset($param['ec'])) $param['ec'] = 'H';
  1623. if (!isset($param['size'])) $param['size'] = '0.6mm';
  1624. if (!isset($param['style']['color'])) $param['style']['color'] = '#000000';
  1625. if (!isset($param['style']['background-color'])) $param['style']['background-color'] = '#FFFFFF';
  1626. if ($param['value']==='') return true;
  1627. $noborder = isset($param['noborder']);
  1628. $this->style->save();
  1629. $this->style->analyse('qrcode', $param);
  1630. $this->style->setPosition();
  1631. $this->style->FontSet();
  1632. $x = $this->pdf->getX();
  1633. $y = $this->pdf->getY();
  1634. $s = $this->style->ConvertToMM($param['size']);
  1635. $ec = $param['ec']; if (!in_array($ec, array('L', 'M', 'Q', 'H'))) $ec = 'H';
  1636. require_once(dirname(__FILE__).'/qrcode/qrcode.class.php');
  1637. $qrcode = new QRcode($param['value'], $ec);
  1638. if ($noborder) $qrcode->disableBorder();
  1639. if (!$this->sub_part && !$this->isSubPart)
  1640. $qrcode->displayTCPDF($this->pdf, $x, $y, $s, $this->style->value['background']['color'], $this->style->value['color']);
  1641. $size = $s*$qrcode->getQrSize();
  1642. unset($qrcode);
  1643. // position maximale globale
  1644. $this->maxX = max($this->maxX, $x+$size);
  1645. $this->maxY = max($this->maxY, $y+$size);
  1646. $this->maxH = max($this->maxH, $size);
  1647. $this->pdf->setX($x+$size);
  1648. $this->style->load();
  1649. $this->style->FontSet();
  1650. return true;
  1651. }
  1652. /**
  1653. * balise : QRCODE
  1654. * mode : FERMETURE
  1655. *
  1656. * @param array param?tres de l'?l?ment de parsing
  1657. * @return null
  1658. */
  1659. protected function c_QRCODE($param)
  1660. {
  1661. if ($this->DEBUG_actif) $this->DEBUG_add('QRCODE', false);
  1662. // completement inutile
  1663. return true;
  1664. }
  1665. /**
  1666. * balise : BOOKMARK
  1667. * mode : OUVERTURE
  1668. *
  1669. * @param array param?tres de l'?l?ment de parsing
  1670. * @return null
  1671. */
  1672. protected function o_BOOKMARK($param)
  1673. {
  1674. $titre = isset($param['title']) ? trim($param['title']) : '';
  1675. $level = isset($param['level']) ? floor($param['level']) : 0;
  1676. if ($level<0) $level = 0;
  1677. if ($titre) $this->pdf->Bookmark($titre, $level, -1);
  1678. return true;
  1679. }
  1680. /**
  1681. * balise : BOOKMARK
  1682. * mode : FERMETURE
  1683. *
  1684. * @param array param?tres de l'?l?ment de parsing
  1685. * @return null
  1686. */
  1687. protected function c_BOOKMARK($param)
  1688. {
  1689. // completement inutile
  1690. return true;
  1691. }
  1692. function getElementY($h)
  1693. {
  1694. if ($this->sub_part || $this->isSubPart || !$this->currentH || $this->currentH<$h)
  1695. return 0;
  1696. return ($this->currentH-$h)*0.8;
  1697. }
  1698. /**
  1699. * balise : WRITE
  1700. * mode : OUVERTURE
  1701. *
  1702. * @param array param?tres de l'?l?ment de parsing
  1703. * @return null
  1704. */
  1705. protected function o_WRITE($param)
  1706. {
  1707. $fill = ($this->style->value['background']['color']!==null && $this->style->value['background']['image']===null);
  1708. if (in_array($this->style->value['id_balise'], array('div', 'table', 'tr', 'td', 'th')))
  1709. $fill = false;
  1710. // r?cup?ration du texte ? ?crire, et conversion
  1711. $txt = $param['txt'];
  1712. if ($this->isAfterFloat)
  1713. {
  1714. $txt = ltrim($txt);
  1715. $this->isAfterFloat = false;
  1716. }
  1717. $txt = str_replace('[[page_cu]]', $this->page, $txt);
  1718. if ($this->style->value['text-transform']!='none')
  1719. {
  1720. if ($this->style->value['text-transform']=='capitalize')
  1721. $txt = ucwords($txt);
  1722. else if ($this->style->value['text-transform']=='uppercase')
  1723. $txt = strtoupper($txt);
  1724. else if ($this->style->value['text-transform']=='lowercase')
  1725. $txt = strtolower($txt);
  1726. }
  1727. // tailles du texte
  1728. $h = 1.08*$this->style->value['font-size'];
  1729. $dh = $h*$this->style->value['mini-decal'];
  1730. $lh = $this->style->getLineHeight();
  1731. // identification de l'alignement
  1732. $align = 'L';
  1733. if ($this->style->value['text-align']=='li_right')
  1734. {
  1735. $w = $this->style->value['width'];
  1736. $align = 'R';
  1737. }
  1738. // pr? calcul de la taille de chaque mot et de la phrase complete
  1739. $w = 0;
  1740. $words = explode(' ', $txt);
  1741. foreach($words as $k => $word)
  1742. {
  1743. $words[$k] = array($word, $this->pdf->GetStringWidth($word));
  1744. $w+= $words[$k][1];
  1745. }
  1746. $space = $this->pdf->GetStringWidth(' ');
  1747. $w+= $space*(count($words)-1);
  1748. $curr_pos = 0; // position dans le texte
  1749. $curr_max = strlen($txt); // taille maxi du texte
  1750. $maxX = 0; // plus grande largeur du texte apres retour ? la ligne
  1751. $x = $this->pdf->getX(); // position du texte
  1752. $y = $this->pdf->getY();
  1753. $dy = $this->getElementY($lh);
  1754. list($left, $right) = $this->getMargins($y); // marges autorisees
  1755. $nb = 0; // nbr de lignes d?coup?es
  1756. // tant que ca ne rentre pas sur la ligne et qu'on a du texte => on d?coupe
  1757. while($x+$w>$right && $x<$right && count($words))
  1758. {
  1759. // trouver une phrase qui rentre dans la largeur, en ajoutant les mots 1 ? 1
  1760. $i=0;
  1761. $old = array('', 0);
  1762. $str = $words[0];
  1763. while(($x+$str[1])<$right)
  1764. {
  1765. $i++;
  1766. array_shift($words);
  1767. $old = $str;
  1768. if (!count($words)) break;
  1769. $str[0].= ' '.$words[0][0];
  1770. $str[1]+= $space+$words[0][1];
  1771. }
  1772. $str = $old;
  1773. // si rien de rentre, et que le premier mot ne rentre de toute facon pas dans une ligne, on le force...
  1774. if ($i==0 && (($left+$str[1])>=$right))
  1775. {
  1776. $str = $words[0];
  1777. array_shift($words);
  1778. }
  1779. $curr_pos+= ($curr_pos ? 1 : 0)+strlen($str[0]);
  1780. // ecriture du bout de phrase extrait et qui rentre
  1781. $wc = ($align=='L' ? $str[1] : $this->style->value['width']);
  1782. if ($right - $left<$wc) $wc = $right - $left;
  1783. /*
  1784. if ($this->pdf->ws)
  1785. {
  1786. $oldSpace = $this->pdf->CurrentFont['cw'][' '];
  1787. $this->pdf->CurrentFont['cw'][' ']*=(1.+$this->pdf->ws);
  1788. $wc = $str[1];
  1789. $this->pdf->CurrentFont['cw'][' '] = $oldSpace;
  1790. }
  1791. */
  1792. if (strlen($str[0]))
  1793. {
  1794. $this->pdf->setXY($this->pdf->getX(), $y+$dh+$dy);
  1795. $this->pdf->Cell($wc, $h, $str[0], 0, 0, $align, $fill, $this->inLink);
  1796. $this->pdf->setXY($this->pdf->getX(), $y);
  1797. }
  1798. $this->maxH = max($this->maxH, $lh);
  1799. // d?termination de la largeur max
  1800. $maxX = max($maxX, $this->pdf->getX());
  1801. // nouvelle position et nouvelle largeur pour la boucle
  1802. $w-= $str[1];
  1803. $y = $this->pdf->getY();
  1804. $x = $this->pdf->getX();
  1805. $dy = $this->getElementY($lh);
  1806. // si il r