Fixed scrolling report headers, take 1.
[openemr.git] / library / html2pdf / html2pdf.class.php
blobd6a068412ca009dd0e4815c53e601d4da919a1c0
1 <?php
2 /**
3 * HTML2PDF Library - main class
5 * HTML => PDF convertor
6 * distributed under the LGPL License
8 * @package Html2pdf
9 * @author Laurent MINGUET <webmaster@html2pdf.fr>
10 * @copyright 2016 Laurent MINGUET
12 require_once(dirname(__FILE__).'/_class/tcpdfConfig.php');
14 class HTML2PDF
16 /**
17 * HTML2PDF_myPdf object, extends from TCPDF
18 * @var HTML2PDF_myPdf
20 public $pdf = null;
22 /**
23 * CSS parsing
24 * @var HTML2PDF_parsingCss
26 public $parsingCss = null;
28 /**
29 * HTML parsing
30 * @var HTML2PDF_parsingHtml
32 public $parsingHtml = null;
34 protected $_langue = 'fr'; // locale of the messages
35 protected $_orientation = 'P'; // page orientation : Portrait ou Landscape
36 protected $_format = 'A4'; // page format : A4, A3, ...
37 protected $_encoding = ''; // charset encoding
38 protected $_unicode = true; // means that the input text is unicode (default = true)
40 protected $_testTdInOnepage = true; // test of TD that can not take more than one page
41 protected $_testIsImage = true; // test if the images exist or not
42 protected $_testIsDeprecated = false; // test the deprecated functions
44 protected $_parsePos = 0; // position in the parsing
45 protected $_tempPos = 0; // temporary position for complex table
46 protected $_page = 0; // current page number
48 protected $_subHtml = null; // sub html
49 protected $_subPart = false; // sub HTML2PDF
50 protected $_subHEADER = array(); // sub action to make the header
51 protected $_subFOOTER = array(); // sub action to make the footer
52 protected $_subSTATES = array(); // array to save some parameters
54 protected $_isSubPart = false; // flag : in a sub html2pdf
55 protected $_isInThead = false; // flag : in a thead
56 protected $_isInTfoot = false; // flag : in a tfoot
57 protected $_isInOverflow = false; // flag : in a overflow
58 protected $_isInFooter = false; // flag : in a footer
59 protected $_isInDraw = null; // flag : in a draw (svg)
60 protected $_isAfterFloat = false; // flag : is just after a float
61 protected $_isInForm = false; // flag : is in a float. false / action of the form
62 protected $_isInLink = ''; // flag : is in a link. empty / href of the link
63 protected $_isInParagraph = false; // flag : is in a paragraph
64 protected $_isForOneLine = false; // flag : in a specific sub html2pdf to have the height of the next line
66 protected $_maxX = 0; // maximum X of the current zone
67 protected $_maxY = 0; // maximum Y of the current zone
68 protected $_maxE = 0; // number of elements in the current zone
69 protected $_maxH = 0; // maximum height of the line in the current zone
70 protected $_maxSave = array(); // save the maximums of the current zone
71 protected $_currentH = 0; // height of the current line
73 protected $_defaultLeft = 0; // default marges of the page
74 protected $_defaultTop = 0;
75 protected $_defaultRight = 0;
76 protected $_defaultBottom = 0;
77 protected $_defaultFont = null; // default font to use, is the asked font does not exist
79 protected $_margeLeft = 0; // current marges of the page
80 protected $_margeTop = 0;
81 protected $_margeRight = 0;
82 protected $_margeBottom = 0;
83 protected $_marges = array(); // save the different marges of the current page
84 protected $_pageMarges = array(); // float marges of the current page
85 protected $_background = array(); // background informations
87 protected $_hideHeader = array(); // array : list of pages which the header gonna be hidden
88 protected $_firstPage = true; // flag : first page
89 protected $_defList = array(); // table to save the stats of the tags UL and OL
91 protected $_lstAnchor = array(); // list of the anchors
92 protected $_lstField = array(); // list of the fields
93 protected $_lstSelect = array(); // list of the options of the current select
94 protected $_previousCall = null; // last action called
96 protected $_debugActif = false; // flag : mode debug is active
97 protected $_debugOkUsage = false; // flag : the function memory_get_usage exist
98 protected $_debugOkPeak = false; // flag : the function memory_get_peak_usage exist
99 protected $_debugLevel = 0; // level in the debug
100 protected $_debugStartTime = 0; // debug start time
101 protected $_debugLastTime = 0; // debug stop time
103 static protected $_subobj = null; // object html2pdf prepared in order to accelerate the creation of sub html2pdf
104 static protected $_tables = array(); // static table to prepare the nested html tables
107 * class constructor
109 * @access public
110 * @param string $orientation page orientation, same as TCPDF
111 * @param mixed $format The format used for pages, same as TCPDF
112 * @param $tring $langue Lang : fr, en, it...
113 * @param boolean $unicode TRUE means that the input text is unicode (default = true)
114 * @param String $encoding charset encoding; default is UTF-8
115 * @param array $marges Default margins (left, top, right, bottom)
116 * @param boolean $is_rtl True will set to use RTL(right to left) language.
117 * @return HTML2PDF $this
119 public function __construct($orientation = 'P', $format = 'A4', $langue='fr', $unicode=true, $encoding='UTF-8', $marges = array(5, 5, 5, 8), $is_rtl = false)
121 // init the page number
122 $this->_page = 0;
123 $this->_firstPage = true;
125 // save the parameters
126 $this->_orientation = $orientation;
127 $this->_format = $format;
128 $this->_langue = strtolower($langue);
129 $this->_unicode = $unicode;
130 $this->_encoding = $encoding;
132 // load the Local
133 HTML2PDF_locale::load($this->_langue);
135 // create the HTML2PDF_myPdf object
136 $this->pdf = new HTML2PDF_myPdf($orientation, 'mm', $format, $unicode, $encoding);
138 // init the CSS parsing object
139 $this->parsingCss = new HTML2PDF_parsingCss($this->pdf);
140 $this->parsingCss->fontSet();
141 $this->_defList = array();
143 // init some tests
144 $this->setTestTdInOnePage(true);
145 $this->setTestIsImage(true);
146 $this->setTestIsDeprecated(true);
148 // init the default font
149 $this->setDefaultFont(null);
151 // init language direction setting
152 if($is_rtl)
153 $this->pdf->setRTL(true);
155 // init the HTML parsing object
156 $this->parsingHtml = new HTML2PDF_parsingHtml($this->_encoding);
157 $this->_subHtml = null;
158 $this->_subPart = false;
160 // init the marges of the page
161 if (!is_array($marges)) $marges = array($marges, $marges, $marges, $marges);
162 $this->_setDefaultMargins($marges[0], $marges[1], $marges[2], $marges[3]);
163 $this->_setMargins();
164 $this->_marges = array();
166 // init the form's fields
167 $this->_lstField = array();
169 return $this;
173 * Destructor
175 * @access public
176 * @return null
178 public function __destruct()
184 * Gets the detailed version as array
186 * @return array
188 public function getVersionAsArray()
190 return array(
191 'major' => 4,
192 'minor' => 5,
193 'revision' => 0,
198 * Gets the current version as string
200 * @return string
202 public function getVersion()
204 $v = $this->getVersionAsArray();
205 return $v['major'].'.'.$v['minor'].'.'.$v['revision'];
209 * Clone to create a sub HTML2PDF from HTML2PDF::$_subobj
211 * @access public
213 public function __clone()
215 $this->pdf = clone $this->pdf;
216 $this->parsingHtml = clone $this->parsingHtml;
217 $this->parsingCss = clone $this->parsingCss;
218 $this->parsingCss->setPdfParent($this->pdf);
222 * set the debug mode to On
224 * @access public
225 * @return HTML2PDF $this
227 public function setModeDebug()
229 $time = microtime(true);
231 $this->_debugActif = true;
232 $this->_debugOkUsage = function_exists('memory_get_usage');
233 $this->_debugOkPeak = function_exists('memory_get_peak_usage');
234 $this->_debugStartTime = $time;
235 $this->_debugLastTime = $time;
237 $this->_DEBUG_stepline('step', 'time', 'delta', 'memory', 'peak');
238 $this->_DEBUG_add('Init debug');
240 return $this;
244 * Set the test of TD that can not take more than one page
246 * @access public
247 * @param boolean $mode
248 * @return HTML2PDF $this
250 public function setTestTdInOnePage($mode = true)
252 $this->_testTdInOnepage = $mode ? true : false;
254 return $this;
258 * Set the test if the images exist or not
260 * @access public
261 * @param boolean $mode
262 * @return HTML2PDF $this
264 public function setTestIsImage($mode = true)
266 $this->_testIsImage = $mode ? true : false;
268 return $this;
272 * Set the test on deprecated functions
274 * @access public
275 * @param boolean $mode
276 * @return HTML2PDF $this
278 public function setTestIsDeprecated($mode = true)
280 $this->_testIsDeprecated = $mode ? true : false;
282 return $this;
286 * Set the default font to use, if no font is specified, or if the asked font does not exist
288 * @access public
289 * @param string $default name of the default font to use. If null : Arial if no font is specified, and error if the asked font does not exist
290 * @return HTML2PDF $this
292 public function setDefaultFont($default = null)
294 $this->_defaultFont = $default;
295 $this->parsingCss->setDefaultFont($default);
297 return $this;
301 * add a font, see TCPDF function addFont
303 * @access public
304 * @param string $family Font family. The name can be chosen arbitrarily. If it is a standard family name, it will override the corresponding font.
305 * @param string $style Font style. Possible values are (case insensitive):<ul><li>empty string: regular (default)</li><li>B: bold</li><li>I: italic</li><li>BI or IB: bold italic</li></ul>
306 * @param string $file The font definition file. By default, the name is built from the family and style, in lower case with no spaces.
307 * @return HTML2PDF $this
308 * @see TCPDF::addFont
310 public function addFont($family, $style='', $file='')
312 $this->pdf->AddFont($family, $style, $file);
314 return $this;
318 * display a automatic index, from the bookmarks
320 * @access public
321 * @param string $titre index title
322 * @param int $sizeTitle font size of the index title, in mm
323 * @param int $sizeBookmark font size of the index, in mm
324 * @param boolean $bookmarkTitle add a bookmark for the index, at his beginning
325 * @param boolean $displayPage display the page numbers
326 * @param int $onPage if null : at the end of the document on a new page, else on the $onPage page
327 * @param string $fontName font name to use
328 * @return null
330 public function createIndex($titre = 'Index', $sizeTitle = 20, $sizeBookmark = 15, $bookmarkTitle = true, $displayPage = true, $onPage = null, $fontName = 'helvetica')
332 $oldPage = $this->_INDEX_NewPage($onPage);
333 $this->pdf->createIndex($this, $titre, $sizeTitle, $sizeBookmark, $bookmarkTitle, $displayPage, $onPage, $fontName);
334 if ($oldPage) $this->pdf->setPage($oldPage);
338 * clean up the objects
340 * @access protected
342 protected function _cleanUp()
344 HTML2PDF::$_subobj = null;
345 HTML2PDF::$_tables = array();
349 * Send the document to a given destination: string, local file or browser.
350 * Dest can be :
351 * I : send the file inline to the browser (default). The plug-in is used if available. The name given by name is used when one selects the "Save as" option on the link generating the PDF.
352 * D : send to the browser and force a file download with the name given by name.
353 * F : save to a local server file with the name given by name.
354 * S : return the document as a string. name is ignored.
355 * FI: equivalent to F + I option
356 * FD: equivalent to F + D option
357 * true => I
358 * false => S
360 * @param string $name The name of the file when saved.
361 * @param string $dest Destination where to send the document.
362 * @return string content of the PDF, if $dest=S
363 * @throws HTML2PDF_exception
364 * @see TCPDF::close
365 * @access public
367 public function Output($name = '', $dest = false)
369 // close the pdf and clean up
370 $this->_cleanUp();
372 // if on debug mode
373 if ($this->_debugActif) {
374 $this->_DEBUG_add('Before output');
375 $this->pdf->Close();
376 exit;
379 // complete parameters
380 if ($dest===false) $dest = 'I';
381 if ($dest===true) $dest = 'S';
382 if ($dest==='') $dest = 'I';
383 if ($name=='') $name='document.pdf';
385 // clean up the destination
386 $dest = strtoupper($dest);
387 if (!in_array($dest, array('I', 'D', 'F', 'S', 'FI','FD'))) $dest = 'I';
389 // the name must be a PDF name
390 if (strtolower(substr($name, -4))!='.pdf') {
391 throw new HTML2PDF_exception(0, 'The output document name "'.$name.'" is not a PDF name');
394 // call the output of TCPDF
395 return $this->pdf->Output($name, $dest);
399 * convert HTML to PDF
401 * @access public
402 * @param string $html
403 * @param boolean $debugVue enable the HTML debug vue
404 * @return null
406 public function writeHTML($html, $debugVue = false)
408 // if it is a real html page, we have to convert it
409 if (preg_match('/<body/isU', $html))
410 $html = $this->getHtmlFromPage($html);
412 $html = str_replace('[[date_y]]', date('Y'), $html);
413 $html = str_replace('[[date_m]]', date('m'), $html);
414 $html = str_replace('[[date_d]]', date('d'), $html);
416 $html = str_replace('[[date_h]]', date('H'), $html);
417 $html = str_replace('[[date_i]]', date('i'), $html);
418 $html = str_replace('[[date_s]]', date('s'), $html);
420 // If we are in HTML debug vue : display the HTML
421 if ($debugVue) {
422 return $this->_vueHTML($html);
425 // convert HTMl to PDF
426 $this->parsingCss->readStyle($html);
427 $this->parsingHtml->setHTML($html);
428 $this->parsingHtml->parse();
429 $this->_makeHTMLcode();
433 * convert the HTML of a real page, to a code adapted to HTML2PDF
435 * @access public
436 * @param string $html HTML code of a real page
437 * @return string HTML adapted to HTML2PDF
439 public function getHtmlFromPage($html)
441 $html = str_replace('<BODY', '<body', $html);
442 $html = str_replace('</BODY', '</body', $html);
444 // extract the content
445 $res = explode('<body', $html);
446 if (count($res)<2) return $html;
447 $content = '<page'.$res[1];
448 $content = explode('</body', $content);
449 $content = $content[0].'</page>';
451 // extract the link tags
452 preg_match_all('/<link([^>]*)>/isU', $html, $match);
453 foreach ($match[0] as $src)
454 $content = $src.'</link>'.$content;
456 // extract the css style tags
457 preg_match_all('/<style[^>]*>(.*)<\/style[^>]*>/isU', $html, $match);
458 foreach ($match[0] as $src)
459 $content = $src.$content;
461 return $content;
465 * init a sub HTML2PDF. do not use it directly. Only the method createSubHTML must use it
467 * @access public
468 * @param string $format
469 * @param string $orientation
470 * @param array $marge
471 * @param integer $page
472 * @param array $defLIST
473 * @param integer $myLastPageGroup
474 * @param integer $myLastPageGroupNb
476 public function initSubHtml($format, $orientation, $marge, $page, $defLIST, $myLastPageGroup, $myLastPageGroupNb)
478 $this->_isSubPart = true;
480 $this->parsingCss->setOnlyLeft();
482 $this->_setNewPage($format, $orientation, null, null, ($myLastPageGroup!==null));
484 $this->_saveMargin(0, 0, $marge);
485 $this->_defList = $defLIST;
487 $this->_page = $page;
488 $this->pdf->setMyLastPageGroup($myLastPageGroup);
489 $this->pdf->setMyLastPageGroupNb($myLastPageGroupNb);
490 $this->pdf->setXY(0, 0);
491 $this->parsingCss->fontSet();
495 * display the content in HTML moden for debug
497 * @access protected
498 * @param string $content
500 protected function _vueHTML($content)
502 $content = preg_replace('/<page_header([^>]*)>/isU', '<hr>'.HTML2PDF_locale::get('vue01').' : $1<hr><div$1>', $content);
503 $content = preg_replace('/<page_footer([^>]*)>/isU', '<hr>'.HTML2PDF_locale::get('vue02').' : $1<hr><div$1>', $content);
504 $content = preg_replace('/<page([^>]*)>/isU', '<hr>'.HTML2PDF_locale::get('vue03').' : $1<hr><div$1>', $content);
505 $content = preg_replace('/<\/page([^>]*)>/isU', '</div><hr>', $content);
506 $content = preg_replace('/<bookmark([^>]*)>/isU', '<hr>bookmark : $1<hr>', $content);
507 $content = preg_replace('/<\/bookmark([^>]*)>/isU', '', $content);
508 $content = preg_replace('/<barcode([^>]*)>/isU', '<hr>barcode : $1<hr>', $content);
509 $content = preg_replace('/<\/barcode([^>]*)>/isU', '', $content);
510 $content = preg_replace('/<qrcode([^>]*)>/isU', '<hr>qrcode : $1<hr>', $content);
511 $content = preg_replace('/<\/qrcode([^>]*)>/isU', '', $content);
513 echo '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
514 <html>
515 <head>
516 <title>'.HTML2PDF_locale::get('vue04').' HTML</title>
517 <meta http-equiv="Content-Type" content="text/html; charset='.$this->_encoding.'" >
518 </head>
519 <body style="padding: 10px; font-size: 10pt;font-family: Verdana;">
520 '.$content.'
521 </body>
522 </html>';
523 exit;
527 * set the default margins of the page
529 * @access protected
530 * @param int $left (mm, left margin)
531 * @param int $top (mm, top margin)
532 * @param int $right (mm, right margin, if null => left=right)
533 * @param int $bottom (mm, bottom margin, if null => bottom=8mm)
535 protected function _setDefaultMargins($left, $top, $right = null, $bottom = null)
537 if ($right===null) $right = $left;
538 if ($bottom===null) $bottom = 8;
540 $this->_defaultLeft = $this->parsingCss->ConvertToMM($left.'mm');
541 $this->_defaultTop = $this->parsingCss->ConvertToMM($top.'mm');
542 $this->_defaultRight = $this->parsingCss->ConvertToMM($right.'mm');
543 $this->_defaultBottom = $this->parsingCss->ConvertToMM($bottom.'mm');
547 * create a new page
549 * @access protected
550 * @param mixed $format
551 * @param string $orientation
552 * @param array $background background information
553 * @param integer $curr real position in the html parser (if break line in the write of a text)
554 * @param boolean $resetPageNumber
556 protected function _setNewPage($format = null, $orientation = '', $background = null, $curr = null, $resetPageNumber=false)
558 $this->_firstPage = false;
560 $this->_format = $format ? $format : $this->_format;
561 $this->_orientation = $orientation ? $orientation : $this->_orientation;
562 $this->_background = $background!==null ? $background : $this->_background;
563 $this->_maxY = 0;
564 $this->_maxX = 0;
565 $this->_maxH = 0;
566 $this->_maxE = 0;
568 $this->pdf->SetMargins($this->_defaultLeft, $this->_defaultTop, $this->_defaultRight);
570 if ($resetPageNumber) {
571 $this->pdf->startPageGroup();
574 $this->pdf->AddPage($this->_orientation, $this->_format);
576 if ($resetPageNumber) {
577 $this->pdf->myStartPageGroup();
580 $this->_page++;
582 if (!$this->_subPart && !$this->_isSubPart) {
583 if (is_array($this->_background)) {
584 if (isset($this->_background['color']) && $this->_background['color']) {
585 $this->pdf->setFillColorArray($this->_background['color']);
586 $this->pdf->Rect(0, 0, $this->pdf->getW(), $this->pdf->getH(), 'F');
589 if (isset($this->_background['img']) && $this->_background['img'])
590 $this->pdf->Image($this->_background['img'], $this->_background['posX'], $this->_background['posY'], $this->_background['width']);
593 $this->_setPageHeader();
594 $this->_setPageFooter();
597 $this->_setMargins();
598 $this->pdf->setY($this->_margeTop);
600 $this->_setNewPositionForNewLine($curr);
601 $this->_maxH = 0;
605 * set the real margin, using the default margins and the page margins
607 * @access protected
609 protected function _setMargins()
611 // prepare the margins
612 $this->_margeLeft = $this->_defaultLeft + (isset($this->_background['left']) ? $this->_background['left'] : 0);
613 $this->_margeRight = $this->_defaultRight + (isset($this->_background['right']) ? $this->_background['right'] : 0);
614 $this->_margeTop = $this->_defaultTop + (isset($this->_background['top']) ? $this->_background['top'] : 0);
615 $this->_margeBottom = $this->_defaultBottom + (isset($this->_background['bottom']) ? $this->_background['bottom'] : 0);
617 // set the PDF margins
618 $this->pdf->SetMargins($this->_margeLeft, $this->_margeTop, $this->_margeRight);
619 $this->pdf->SetAutoPageBreak(false, $this->_margeBottom);
621 // set the float Margins
622 $this->_pageMarges = array();
623 if ($this->_isInParagraph!==false) {
624 $this->_pageMarges[floor($this->_margeTop*100)] = array($this->_isInParagraph[0], $this->pdf->getW()-$this->_isInParagraph[1]);
625 } else {
626 $this->_pageMarges[floor($this->_margeTop*100)] = array($this->_margeLeft, $this->pdf->getW()-$this->_margeRight);
631 * add a debug step
633 * @access protected
634 * @param string $name step name
635 * @param boolean $level (true=up, false=down, null=nothing to do)
636 * @return $this
638 protected function _DEBUG_add($name, $level=null)
640 // if true : UP
641 if ($level===true) $this->_debugLevel++;
643 $name = str_repeat(' ', $this->_debugLevel). $name.($level===true ? ' Begin' : ($level===false ? ' End' : ''));
644 $time = microtime(true);
645 $usage = ($this->_debugOkUsage ? memory_get_usage() : 0);
646 $peak = ($this->_debugOkPeak ? memory_get_peak_usage() : 0);
648 $this->_DEBUG_stepline(
649 $name,
650 number_format(($time - $this->_debugStartTime)*1000, 1, '.', ' ').' ms',
651 number_format(($time - $this->_debugLastTime)*1000, 1, '.', ' ').' ms',
652 number_format($usage/1024, 1, '.', ' ').' Ko',
653 number_format($peak/1024, 1, '.', ' ').' Ko'
656 $this->_debugLastTime = $time;
658 // it false : DOWN
659 if ($level===false) $this->_debugLevel--;
661 return $this;
665 * display a debug line
668 * @access protected
669 * @param string $name
670 * @param string $timeTotal
671 * @param string $timeStep
672 * @param string $memoryUsage
673 * @param string $memoryPeak
675 protected function _DEBUG_stepline($name, $timeTotal, $timeStep, $memoryUsage, $memoryPeak)
677 $txt = str_pad($name, 30, ' ', STR_PAD_RIGHT).
678 str_pad($timeTotal, 12, ' ', STR_PAD_LEFT).
679 str_pad($timeStep, 12, ' ', STR_PAD_LEFT).
680 str_pad($memoryUsage, 15, ' ', STR_PAD_LEFT).
681 str_pad($memoryPeak, 15, ' ', STR_PAD_LEFT);
683 echo '<pre style="padding:0; margin:0">'.$txt.'</pre>';
687 * get the Min and Max X, for Y (use the float margins)
689 * @access protected
690 * @param float $y
691 * @return array(float, float)
693 protected function _getMargins($y)
695 $y = floor($y*100);
696 $x = array($this->pdf->getlMargin(), $this->pdf->getW()-$this->pdf->getrMargin());
698 foreach ($this->_pageMarges as $mY => $mX)
699 if ($mY<=$y) $x = $mX;
701 return $x;
705 * Add margins, for a float
707 * @access protected
708 * @param string $float (left / right)
709 * @param float $xLeft
710 * @param float $yTop
711 * @param float $xRight
712 * @param float $yBottom
714 protected function _addMargins($float, $xLeft, $yTop, $xRight, $yBottom)
716 // get the current float margins, for top and bottom
717 $oldTop = $this->_getMargins($yTop);
718 $oldBottom = $this->_getMargins($yBottom);
720 // update the top float margin
721 if ($float=='left' && $oldTop[0]<$xRight) $oldTop[0] = $xRight;
722 if ($float=='right' && $oldTop[1]>$xLeft) $oldTop[1] = $xLeft;
724 $yTop = floor($yTop*100);
725 $yBottom = floor($yBottom*100);
727 // erase all the float margins that are smaller than the new one
728 foreach ($this->_pageMarges as $mY => $mX) {
729 if ($mY<$yTop) continue;
730 if ($mY>$yBottom) break;
731 if ($float=='left' && $this->_pageMarges[$mY][0]<$xRight) unset($this->_pageMarges[$mY]);
732 if ($float=='right' && $this->_pageMarges[$mY][1]>$xLeft) unset($this->_pageMarges[$mY]);
735 // save the new Top and Bottom margins
736 $this->_pageMarges[$yTop] = $oldTop;
737 $this->_pageMarges[$yBottom] = $oldBottom;
739 // sort the margins
740 ksort($this->_pageMarges);
742 // we are just after float
743 $this->_isAfterFloat = true;
747 * Save old margins (push), and set new ones
749 * @access protected
750 * @param float $ml left margin
751 * @param float $mt top margin
752 * @param float $mr right margin
754 protected function _saveMargin($ml, $mt, $mr)
756 // save old margins
757 $this->_marges[] = array('l' => $this->pdf->getlMargin(), 't' => $this->pdf->gettMargin(), 'r' => $this->pdf->getrMargin(), 'page' => $this->_pageMarges);
759 // set new ones
760 $this->pdf->SetMargins($ml, $mt, $mr);
762 // prepare for float margins
763 $this->_pageMarges = array();
764 $this->_pageMarges[floor($mt*100)] = array($ml, $this->pdf->getW()-$mr);
768 * load the last saved margins (pop)
770 * @access protected
772 protected function _loadMargin()
774 $old = array_pop($this->_marges);
775 if ($old) {
776 $ml = $old['l'];
777 $mt = $old['t'];
778 $mr = $old['r'];
779 $mP = $old['page'];
780 } else {
781 $ml = $this->_margeLeft;
782 $mt = 0;
783 $mr = $this->_margeRight;
784 $mP = array($mt => array($ml, $this->pdf->getW()-$mr));
787 $this->pdf->SetMargins($ml, $mt, $mr);
788 $this->_pageMarges = $mP;
792 * save the current maxs (push)
794 * @access protected
796 protected function _saveMax()
798 $this->_maxSave[] = array($this->_maxX, $this->_maxY, $this->_maxH, $this->_maxE);
802 * load the last saved current maxs (pop)
804 * @access protected
806 protected function _loadMax()
808 $old = array_pop($this->_maxSave);
810 if ($old) {
811 $this->_maxX = $old[0];
812 $this->_maxY = $old[1];
813 $this->_maxH = $old[2];
814 $this->_maxE = $old[3];
815 } else {
816 $this->_maxX = 0;
817 $this->_maxY = 0;
818 $this->_maxH = 0;
819 $this->_maxE = 0;
824 * draw the PDF header with the HTML in page_header
826 * @access protected
828 protected function _setPageHeader()
830 if (!count($this->_subHEADER)) return false;
832 if (in_array($this->pdf->getPage(), $this->_hideHeader)) return false;
834 $oldParsePos = $this->_parsePos;
835 $oldParseCode = $this->parsingHtml->code;
837 $this->_parsePos = 0;
838 $this->parsingHtml->code = $this->_subHEADER;
839 $this->_makeHTMLcode();
841 $this->_parsePos = $oldParsePos;
842 $this->parsingHtml->code = $oldParseCode;
846 * draw the PDF footer with the HTML in page_footer
848 * @access protected
850 protected function _setPageFooter()
852 if (!count($this->_subFOOTER)) return false;
854 $oldParsePos = $this->_parsePos;
855 $oldParseCode = $this->parsingHtml->code;
857 $this->_parsePos = 0;
858 $this->parsingHtml->code = $this->_subFOOTER;
859 $this->_isInFooter = true;
860 $this->_makeHTMLcode();
861 $this->_isInFooter = false;
863 $this->_parsePos = $oldParsePos;
864 $this->parsingHtml->code = $oldParseCode;
868 * new line, with a specific height
870 * @access protected
871 * @param float $h
872 * @param integer $curr real current position in the text, if new line in the write of a text
874 protected function _setNewLine($h, $curr = null)
876 $this->pdf->Ln($h);
877 $this->_setNewPositionForNewLine($curr);
881 * calculate the start position of the next line, depending on the text-align
883 * @access protected
884 * @param integer $curr real current position in the text, if new line in the write of a text
886 protected function _setNewPositionForNewLine($curr = null)
888 // get the margins for the current line
889 list($lx, $rx) = $this->_getMargins($this->pdf->getY());
890 $this->pdf->setX($lx);
891 $wMax = $rx-$lx;
892 $this->_currentH = 0;
894 // if subPart => return because align left
895 if ($this->_subPart || $this->_isSubPart || $this->_isForOneLine) {
896 $this->pdf->setWordSpacing(0);
897 return null;
900 // create the sub object
901 $sub = null;
902 $this->_createSubHTML($sub);
903 $sub->_saveMargin(0, 0, $sub->pdf->getW()-$wMax);
904 $sub->_isForOneLine = true;
905 $sub->_parsePos = $this->_parsePos;
906 $sub->parsingHtml->code = $this->parsingHtml->code;
908 // if $curr => adapt the current position of the parsing
909 if ($curr!==null && $sub->parsingHtml->code[$this->_parsePos]['name']=='write') {
910 $txt = $sub->parsingHtml->code[$this->_parsePos]['param']['txt'];
911 $txt = str_replace('[[page_cu]]', $sub->pdf->getMyNumPage($this->_page), $txt);
912 $sub->parsingHtml->code[$this->_parsePos]['param']['txt'] = substr($txt, $curr+1);
913 } else
914 $sub->_parsePos++;
916 // for each element of the parsing => load the action
917 $res = null;
918 for ($sub->_parsePos; $sub->_parsePos<count($sub->parsingHtml->code); $sub->_parsePos++) {
919 $action = $sub->parsingHtml->code[$sub->_parsePos];
920 $res = $sub->_executeAction($action);
921 if (!$res) break;
924 $w = $sub->_maxX; // max width
925 $h = $sub->_maxH; // max height
926 $e = ($res===null ? $sub->_maxE : 0); // maxnumber of elemets on the line
928 // destroy the sub HTML
929 $this->_destroySubHTML($sub);
931 // adapt the start of the line, depending on the text-align
932 if ($this->parsingCss->value['text-align']=='center')
933 $this->pdf->setX(($rx+$this->pdf->getX()-$w)*0.5-0.01);
934 else if ($this->parsingCss->value['text-align']=='right')
935 $this->pdf->setX($rx-$w-0.01);
936 else
937 $this->pdf->setX($lx);
939 // set the height of the line
940 $this->_currentH = $h;
942 // if justify => set the word spacing
943 if ($this->parsingCss->value['text-align']=='justify' && $e>1) {
944 $this->pdf->setWordSpacing(($wMax-$w)/($e-1));
945 } else {
946 $this->pdf->setWordSpacing(0);
951 * prepare HTML2PDF::$_subobj (used for create the sub HTML2PDF objects
953 * @access protected
955 protected function _prepareSubObj()
957 $pdf = null;
959 // create the sub object
960 HTML2PDF::$_subobj = new HTML2PDF(
961 $this->_orientation,
962 $this->_format,
963 $this->_langue,
964 $this->_unicode,
965 $this->_encoding,
966 array($this->_defaultLeft,$this->_defaultTop,$this->_defaultRight,$this->_defaultBottom)
969 // init
970 HTML2PDF::$_subobj->setTestTdInOnePage($this->_testTdInOnepage);
971 HTML2PDF::$_subobj->setTestIsImage($this->_testIsImage);
972 HTML2PDF::$_subobj->setTestIsDeprecated($this->_testIsDeprecated);
973 HTML2PDF::$_subobj->setDefaultFont($this->_defaultFont);
974 HTML2PDF::$_subobj->parsingCss->css = &$this->parsingCss->css;
975 HTML2PDF::$_subobj->parsingCss->cssKeys = &$this->parsingCss->cssKeys;
977 // clone font from the original PDF
978 HTML2PDF::$_subobj->pdf->cloneFontFrom($this->pdf);
980 // remove the link to the parent
981 HTML2PDF::$_subobj->parsingCss->setPdfParent($pdf);
985 * create a sub HTML2PDF, to calculate the multi-tables
987 * @access protected
988 * @param &HTML2PDF $subHtml sub HTML2PDF to create
989 * @param integer $cellmargin if in a TD : cellmargin of this td
991 protected function _createSubHTML(&$subHtml, $cellmargin=0)
993 // prepare the subObject, if never prepare before
994 if (HTML2PDF::$_subobj===null) {
995 $this->_prepareSubObj();
998 // calculate the width to use
999 if ($this->parsingCss->value['width']) {
1000 $marge = $cellmargin*2;
1001 $marge+= $this->parsingCss->value['padding']['l'] + $this->parsingCss->value['padding']['r'];
1002 $marge+= $this->parsingCss->value['border']['l']['width'] + $this->parsingCss->value['border']['r']['width'];
1003 $marge = $this->pdf->getW() - $this->parsingCss->value['width'] + $marge;
1004 } else {
1005 $marge = $this->_margeLeft+$this->_margeRight;
1008 // BUGFIX : we have to call the method, because of a bug in php 5.1.6
1009 HTML2PDF::$_subobj->pdf->getPage();
1011 // clone the sub oject
1012 $subHtml = clone HTML2PDF::$_subobj;
1013 $subHtml->parsingCss->table = $this->parsingCss->table;
1014 $subHtml->parsingCss->value = $this->parsingCss->value;
1015 $subHtml->initSubHtml(
1016 $this->_format,
1017 $this->_orientation,
1018 $marge,
1019 $this->_page,
1020 $this->_defList,
1021 $this->pdf->getMyLastPageGroup(),
1022 $this->pdf->getMyLastPageGroupNb()
1027 * destroy a subHTML2PDF
1029 * @access protected
1031 protected function _destroySubHTML(&$subHtml)
1033 unset($subHtml);
1034 $subHtml = null;
1038 * Convert an arabic number into a roman number
1040 * @access protected
1041 * @param integer $nbArabic
1042 * @return string $nbRoman
1044 protected function _listeArab2Rom($nbArabic)
1046 $nbBaseTen = array('I','X','C','M');
1047 $nbBaseFive = array('V','L','D');
1048 $nbRoman = '';
1050 if ($nbArabic<1) return $nbArabic;
1051 if ($nbArabic>3999) return $nbArabic;
1053 for ($i=3; $i>=0 ; $i--) {
1054 $digit=floor($nbArabic/pow(10, $i));
1055 if ($digit>=1) {
1056 $nbArabic=$nbArabic-$digit*pow(10, $i);
1057 if ($digit<=3) {
1058 for ($j=$digit; $j>=1; $j--) {
1059 $nbRoman=$nbRoman.$nbBaseTen[$i];
1061 } else if ($digit==9) {
1062 $nbRoman=$nbRoman.$nbBaseTen[$i].$nbBaseTen[$i+1];
1063 } else if ($digit==4) {
1064 $nbRoman=$nbRoman.$nbBaseTen[$i].$nbBaseFive[$i];
1065 } else {
1066 $nbRoman=$nbRoman.$nbBaseFive[$i];
1067 for ($j=$digit-5; $j>=1; $j--) {
1068 $nbRoman=$nbRoman.$nbBaseTen[$i];
1073 return $nbRoman;
1077 * add a LI to the current level
1079 * @access protected
1081 protected function _listeAddLi()
1083 $this->_defList[count($this->_defList)-1]['nb']++;
1087 * get the width to use for the column of the list
1089 * @access protected
1090 * @return string $width
1092 protected function _listeGetWidth()
1094 return '7mm';
1098 * get the padding to use for the column of the list
1100 * @access protected
1101 * @return string $padding
1103 protected function _listeGetPadding()
1105 return '1mm';
1109 * get the information of the li on the current level
1111 * @access protected
1112 * @return array(fontName, small size, string)
1114 protected function _listeGetLi()
1116 $im = $this->_defList[count($this->_defList)-1]['img'];
1117 $st = $this->_defList[count($this->_defList)-1]['style'];
1118 $nb = $this->_defList[count($this->_defList)-1]['nb'];
1119 $up = (substr($st, 0, 6)=='upper-');
1121 if ($im) return array(false, false, $im);
1123 switch($st)
1125 case 'none':
1126 return array('helvetica', true, ' ');
1128 case 'upper-alpha':
1129 case 'lower-alpha':
1130 $str = '';
1131 while ($nb>26) {
1132 $str = chr(96+$nb%26).$str;
1133 $nb = floor($nb/26);
1135 $str = chr(96+$nb).$str;
1137 return array('helvetica', false, ($up ? strtoupper($str) : $str).'.');
1139 case 'upper-roman':
1140 case 'lower-roman':
1141 $str = $this->_listeArab2Rom($nb);
1143 return array('helvetica', false, ($up ? strtoupper($str) : $str).'.');
1145 case 'decimal':
1146 return array('helvetica', false, $nb.'.');
1148 case 'square':
1149 return array('zapfdingbats', true, chr(110));
1151 case 'circle':
1152 return array('zapfdingbats', true, chr(109));
1154 case 'disc':
1155 default:
1156 return array('zapfdingbats', true, chr(108));
1161 * add a level to the list
1163 * @access protected
1164 * @param string $type : ul, ol
1165 * @param string $style : lower-alpha, ...
1166 * @param string $img
1168 protected function _listeAddLevel($type = 'ul', $style = '', $img = null)
1170 // get the url of the image, if we want to use a image
1171 if ($img) {
1172 if (preg_match('/^url\(([^)]+)\)$/isU', trim($img), $match)) {
1173 $img = $match[1];
1174 } else {
1175 $img = null;
1177 } else {
1178 $img = null;
1181 // prepare the datas
1182 if (!in_array($type, array('ul', 'ol'))) $type = 'ul';
1183 if (!in_array($style, array('lower-alpha', 'upper-alpha', 'upper-roman', 'lower-roman', 'decimal', 'square', 'circle', 'disc', 'none'))) $style = '';
1185 if (!$style) {
1186 if ($type=='ul') $style = 'disc';
1187 else $style = 'decimal';
1190 // add the new level
1191 $this->_defList[count($this->_defList)] = array('style' => $style, 'nb' => 0, 'img' => $img);
1195 * remove a level from the list
1197 * @access protected
1199 protected function _listeDelLevel()
1201 if (count($this->_defList)) {
1202 unset($this->_defList[count($this->_defList)-1]);
1203 $this->_defList = array_values($this->_defList);
1208 * execute the actions to convert the html
1210 * @access protected
1212 protected function _makeHTMLcode()
1214 // foreach elements of the parsing
1215 for ($this->_parsePos=0; $this->_parsePos<count($this->parsingHtml->code); $this->_parsePos++) {
1217 // get the action to do
1218 $action = $this->parsingHtml->code[$this->_parsePos];
1220 // if it is a opening of table / ul / ol
1221 if (in_array($action['name'], array('table', 'ul', 'ol')) && !$action['close']) {
1223 // we will work as a sub HTML to calculate the size of the element
1224 $this->_subPart = true;
1226 // get the name of the opening tag
1227 $tagOpen = $action['name'];
1229 // save the actual pos on the parsing
1230 $this->_tempPos = $this->_parsePos;
1232 // foreach elements, while we are in the opened tag
1233 while (isset($this->parsingHtml->code[$this->_tempPos]) && !($this->parsingHtml->code[$this->_tempPos]['name']==$tagOpen && $this->parsingHtml->code[$this->_tempPos]['close'])) {
1234 // make the action
1235 $this->_executeAction($this->parsingHtml->code[$this->_tempPos]);
1236 $this->_tempPos++;
1239 // execute the closure of the tag
1240 if (isset($this->parsingHtml->code[$this->_tempPos])) {
1241 $this->_executeAction($this->parsingHtml->code[$this->_tempPos]);
1244 // end of the sub part
1245 $this->_subPart = false;
1248 // execute the action
1249 $this->_executeAction($action);
1254 * execute the action from the parsing
1256 * @access protected
1257 * @param array $action
1259 * @throws HTML2PDF_exception
1261 protected function _executeAction($action)
1263 // name of the action
1264 $fnc = ($action['close'] ? '_tag_close_' : '_tag_open_').strtoupper($action['name']);
1266 // parameters of the action
1267 $param = $action['param'];
1269 // if it is the first action of the first page, and if it is not an open tag of PAGE => create the new page
1270 if ($fnc!='_tag_open_PAGE' && $this->_firstPage) {
1271 $this->_setNewPage();
1274 // the action must exist
1275 if (!is_callable(array(&$this, $fnc))) {
1276 throw new HTML2PDF_exception(1, strtoupper($action['name']), $this->parsingHtml->getHtmlErrorCode($action['html_pos']));
1279 // run the action
1280 $res = $this->{$fnc}($param);
1282 // save the name of the action
1283 $this->_previousCall = $fnc;
1285 // return the result
1286 return $res;
1290 * get the position of the element on the current line, depending on its height
1292 * @access protected
1293 * @param float $h
1294 * @return float
1296 protected function _getElementY($h)
1298 if ($this->_subPart || $this->_isSubPart || !$this->_currentH || $this->_currentH<$h)
1299 return 0;
1301 return ($this->_currentH-$h)*0.8;
1305 * make a break line
1307 * @access protected
1308 * @param float $h current line height
1309 * @param integer $curr real current position in the text, if new line in the write of a text
1311 protected function _makeBreakLine($h, $curr = null)
1313 if ($h) {
1314 if (($this->pdf->getY()+$h<$this->pdf->getH() - $this->pdf->getbMargin()) || $this->_isInOverflow || $this->_isInFooter)
1315 $this->_setNewLine($h, $curr);
1316 else
1317 $this->_setNewPage(null, '', null, $curr);
1318 } else {
1319 $this->_setNewPositionForNewLine($curr);
1322 $this->_maxH = 0;
1323 $this->_maxE = 0;
1327 * display an image
1329 * @access protected
1330 * @param string $src
1331 * @param boolean $subLi if true=image of a list
1332 * @return boolean depending on "isForOneLine"
1333 * @throws HTML2PDF_exception
1335 protected function _drawImage($src, $subLi=false)
1337 // get the size of the image
1338 // WARNING : if URL, "allow_url_fopen" must turned to "on" in php.ini
1339 $infos=@getimagesize($src);
1341 // if the image does not exist, or can not be loaded
1342 if (count($infos)<2) {
1343 // if the test is activ => exception
1344 if ($this->_testIsImage) {
1345 throw new HTML2PDF_exception(6, $src);
1348 // else, display a gray rectangle
1349 $src = null;
1350 $infos = array(16, 16);
1353 // convert the size of the image in the unit of the PDF
1354 $imageWidth = $infos[0]/$this->pdf->getK();
1355 $imageHeight = $infos[1]/$this->pdf->getK();
1357 // calculate the size from the css style
1358 if ($this->parsingCss->value['width'] && $this->parsingCss->value['height']) {
1359 $w = $this->parsingCss->value['width'];
1360 $h = $this->parsingCss->value['height'];
1361 } else if ($this->parsingCss->value['width']) {
1362 $w = $this->parsingCss->value['width'];
1363 $h = $imageHeight*$w/$imageWidth;
1364 } else if ($this->parsingCss->value['height']) {
1365 $h = $this->parsingCss->value['height'];
1366 $w = $imageWidth*$h/$imageHeight;
1367 } else {
1368 // convert px to pt
1369 $w = 72./96.*$imageWidth;
1370 $h = 72./96.*$imageHeight;
1373 // are we in a float
1374 $float = $this->parsingCss->getFloat();
1376 // if we are in a float, but if something else if on the line => Break Line
1377 if ($float && $this->_maxH) {
1378 // make the break line (false if we are in "_isForOneLine" mode)
1379 if (!$this->_tag_open_BR(array())) {
1380 return false;
1384 // position of the image
1385 $x = $this->pdf->getX();
1386 $y = $this->pdf->getY();
1388 // if the image can not be put on the current line => new line
1389 if (!$float && ($x + $w>$this->pdf->getW() - $this->pdf->getrMargin()) && $this->_maxH) {
1390 if ($this->_isForOneLine) {
1391 return false;
1394 // set the new line
1395 $hnl = max($this->_maxH, $this->parsingCss->getLineHeight());
1396 $this->_setNewLine($hnl);
1398 // get the new position
1399 $x = $this->pdf->getX();
1400 $y = $this->pdf->getY();
1403 // if the image can not be put on the current page
1404 if (($y + $h>$this->pdf->getH() - $this->pdf->getbMargin()) && !$this->_isInOverflow) {
1405 // new page
1406 $this->_setNewPage();
1408 // get the new position
1409 $x = $this->pdf->getX();
1410 $y = $this->pdf->getY();
1413 // correction for display the image of a list
1414 $hT = 0.80*$this->parsingCss->value['font-size'];
1415 if ($subLi && $h<$hT) {
1416 $y+=($hT-$h);
1419 // add the margin top
1420 $yc = $y-$this->parsingCss->value['margin']['t'];
1422 // get the width and the position of the parent
1423 $old = $this->parsingCss->getOldValues();
1424 if ( $old['width']) {
1425 $parentWidth = $old['width'];
1426 $parentX = $x;
1427 } else {
1428 $parentWidth = $this->pdf->getW() - $this->pdf->getlMargin() - $this->pdf->getrMargin();
1429 $parentX = $this->pdf->getlMargin();
1432 // if we are in a gloat => adapt the parent position and width
1433 if ($float) {
1434 list($lx, $rx) = $this->_getMargins($yc);
1435 $parentX = $lx;
1436 $parentWidth = $rx-$lx;
1439 // calculate the position of the image, if align to the right
1440 if ($parentWidth>$w && $float!='left') {
1441 if ($float=='right' || $this->parsingCss->value['text-align']=='li_right') $x = $parentX + $parentWidth - $w-$this->parsingCss->value['margin']['r']-$this->parsingCss->value['margin']['l'];
1444 // display the image
1445 if (!$this->_subPart && !$this->_isSubPart) {
1446 if ($src) {
1447 $this->pdf->Image($src, $x, $y, $w, $h, '', $this->_isInLink);
1448 } else {
1449 // rectangle if the image can not be loaded
1450 $this->pdf->setFillColorArray(array(240, 220, 220));
1451 $this->pdf->Rect($x, $y, $w, $h, 'F');
1455 // apply the margins
1456 $x-= $this->parsingCss->value['margin']['l'];
1457 $y-= $this->parsingCss->value['margin']['t'];
1458 $w+= $this->parsingCss->value['margin']['l'] + $this->parsingCss->value['margin']['r'];
1459 $h+= $this->parsingCss->value['margin']['t'] + $this->parsingCss->value['margin']['b'];
1461 if ($float=='left') {
1462 // save the current max
1463 $this->_maxX = max($this->_maxX, $x+$w);
1464 $this->_maxY = max($this->_maxY, $y+$h);
1466 // add the image to the margins
1467 $this->_addMargins($float, $x, $y, $x+$w, $y+$h);
1469 // get the new position
1470 list($lx, $rx) = $this->_getMargins($yc);
1471 $this->pdf->setXY($lx, $yc);
1472 } else if ($float=='right') {
1473 // save the current max. We don't save the X because it is not the real max of the line
1474 $this->_maxY = max($this->_maxY, $y+$h);
1476 // add the image to the margins
1477 $this->_addMargins($float, $x, $y, $x+$w, $y+$h);
1479 // get the new position
1480 list($lx, $rx) = $this->_getMargins($yc);
1481 $this->pdf->setXY($lx, $yc);
1482 } else {
1483 // set the new position at the end of the image
1484 $this->pdf->setX($x+$w);
1486 // save the current max
1487 $this->_maxX = max($this->_maxX, $x+$w);
1488 $this->_maxY = max($this->_maxY, $y+$h);
1489 $this->_maxH = max($this->_maxH, $h);
1492 return true;
1496 * draw a rectangle
1498 * @access protected
1499 * @param float $x
1500 * @param float $y
1501 * @param float $w
1502 * @param float $h
1503 * @param array $border
1504 * @param float $padding - internal margin of the rectangle => not used, but...
1505 * @param float $margin - external margin of the rectangle
1506 * @param array $background
1507 * @return boolean
1508 * @throws HTML2PDF_exception
1510 protected function _drawRectangle($x, $y, $w, $h, $border, $padding, $margin, $background)
1512 // if we are in a subpart or if height is null => return false
1513 if ($this->_subPart || $this->_isSubPart || $h===null) return false;
1515 // add the margin
1516 $x+= $margin;
1517 $y+= $margin;
1518 $w-= $margin*2;
1519 $h-= $margin*2;
1521 // get the radius of the border
1522 $outTL = $border['radius']['tl'];
1523 $outTR = $border['radius']['tr'];
1524 $outBR = $border['radius']['br'];
1525 $outBL = $border['radius']['bl'];
1527 // prepare the out radius
1528 $outTL = ($outTL[0] && $outTL[1]) ? $outTL : null;
1529 $outTR = ($outTR[0] && $outTR[1]) ? $outTR : null;
1530 $outBR = ($outBR[0] && $outBR[1]) ? $outBR : null;
1531 $outBL = ($outBL[0] && $outBL[1]) ? $outBL : null;
1533 // prepare the in radius
1534 $inTL = $outTL;
1535 $inTR = $outTR;
1536 $inBR = $outBR;
1537 $inBL = $outBL;
1539 if (is_array($inTL)) {
1540 $inTL[0]-= $border['l']['width'];
1541 $inTL[1]-= $border['t']['width'];
1543 if (is_array($inTR)) {
1544 $inTR[0]-= $border['r']['width'];
1545 $inTR[1]-= $border['t']['width'];
1547 if (is_array($inBR)) {
1548 $inBR[0]-= $border['r']['width'];
1549 $inBR[1]-= $border['b']['width'];
1551 if (is_array($inBL)) {
1552 $inBL[0]-= $border['l']['width'];
1553 $inBL[1]-= $border['b']['width'];
1556 if ($inTL[0]<=0 || $inTL[1]<=0) $inTL = null;
1557 if ($inTR[0]<=0 || $inTR[1]<=0) $inTR = null;
1558 if ($inBR[0]<=0 || $inBR[1]<=0) $inBR = null;
1559 if ($inBL[0]<=0 || $inBL[1]<=0) $inBL = null;
1561 // prepare the background color
1562 $pdfStyle = '';
1563 if ($background['color']) {
1564 $this->pdf->setFillColorArray($background['color']);
1565 $pdfStyle.= 'F';
1568 // if we have a background to fill => fill it with a path (because of the radius)
1569 if ($pdfStyle) {
1570 $this->pdf->clippingPathStart($x, $y, $w, $h, $outTL, $outTR, $outBL, $outBR);
1571 $this->pdf->Rect($x, $y, $w, $h, $pdfStyle);
1572 $this->pdf->clippingPathStop();
1575 // prepare the background image
1576 if ($background['image']) {
1577 $iName = $background['image'];
1578 $iPosition = $background['position']!==null ? $background['position'] : array(0, 0);
1579 $iRepeat = $background['repeat']!==null ? $background['repeat'] : array(true, true);
1581 // size of the background without the borders
1582 $bX = $x;
1583 $bY = $y;
1584 $bW = $w;
1585 $bH = $h;
1587 if ($border['b']['width']) {
1588 $bH-= $border['b']['width'];
1590 if ($border['l']['width']) {
1591 $bW-= $border['l']['width'];
1592 $bX+= $border['l']['width'];
1594 if ($border['t']['width']) {
1595 $bH-= $border['t']['width'];
1596 $bY+= $border['t']['width'];
1598 if ($border['r']['width']) {
1599 $bW-= $border['r']['width'];
1602 // get the size of the image
1603 // WARNING : if URL, "allow_url_fopen" must turned to "on" in php.ini
1604 $imageInfos=@getimagesize($iName);
1606 // if the image can not be loaded
1607 if (count($imageInfos)<2) {
1608 if ($this->_testIsImage) {
1609 throw new HTML2PDF_exception(6, $iName);
1611 } else {
1612 // convert the size of the image from pixel to the unit of the PDF
1613 $imageWidth = 72./96.*$imageInfos[0]/$this->pdf->getK();
1614 $imageHeight = 72./96.*$imageInfos[1]/$this->pdf->getK();
1616 // prepare the position of the backgroung
1617 if ($iRepeat[0]) $iPosition[0] = $bX;
1618 else if (preg_match('/^([-]?[0-9\.]+)%/isU', $iPosition[0], $match)) $iPosition[0] = $bX + $match[1]*($bW-$imageWidth)/100;
1619 else $iPosition[0] = $bX+$iPosition[0];
1621 if ($iRepeat[1]) $iPosition[1] = $bY;
1622 else if (preg_match('/^([-]?[0-9\.]+)%/isU', $iPosition[1], $match)) $iPosition[1] = $bY + $match[1]*($bH-$imageHeight)/100;
1623 else $iPosition[1] = $bY+$iPosition[1];
1625 $imageXmin = $bX;
1626 $imageXmax = $bX+$bW;
1627 $imageYmin = $bY;
1628 $imageYmax = $bY+$bH;
1630 if (!$iRepeat[0] && !$iRepeat[1]) {
1631 $imageXmin = $iPosition[0]; $imageXmax = $iPosition[0]+$imageWidth;
1632 $imageYmin = $iPosition[1]; $imageYmax = $iPosition[1]+$imageHeight;
1633 } else if ($iRepeat[0] && !$iRepeat[1]) {
1634 $imageYmin = $iPosition[1]; $imageYmax = $iPosition[1]+$imageHeight;
1635 } else if (!$iRepeat[0] && $iRepeat[1]) {
1636 $imageXmin = $iPosition[0]; $imageXmax = $iPosition[0]+$imageWidth;
1639 // build the path to display the image (because of radius)
1640 $this->pdf->clippingPathStart($bX, $bY, $bW, $bH, $inTL, $inTR, $inBL, $inBR);
1642 // repeat the image
1643 for ($iY=$imageYmin; $iY<$imageYmax; $iY+=$imageHeight) {
1644 for ($iX=$imageXmin; $iX<$imageXmax; $iX+=$imageWidth) {
1645 $cX = null;
1646 $cY = null;
1647 $cW = $imageWidth;
1648 $cH = $imageHeight;
1649 if ($imageYmax-$iY<$imageHeight) {
1650 $cX = $iX;
1651 $cY = $iY;
1652 $cH = $imageYmax-$iY;
1654 if ($imageXmax-$iX<$imageWidth) {
1655 $cX = $iX;
1656 $cY = $iY;
1657 $cW = $imageXmax-$iX;
1660 $this->pdf->Image($iName, $iX, $iY, $imageWidth, $imageHeight, '', '');
1664 // end of the path
1665 $this->pdf->clippingPathStop();
1669 // adding some loose (0.01mm)
1670 $loose = 0.01;
1671 $x-= $loose;
1672 $y-= $loose;
1673 $w+= 2.*$loose;
1674 $h+= 2.*$loose;
1675 if ($border['l']['width']) $border['l']['width']+= 2.*$loose;
1676 if ($border['t']['width']) $border['t']['width']+= 2.*$loose;
1677 if ($border['r']['width']) $border['r']['width']+= 2.*$loose;
1678 if ($border['b']['width']) $border['b']['width']+= 2.*$loose;
1680 // prepare the test on borders
1681 $testBl = ($border['l']['width'] && $border['l']['color'][0]!==null);
1682 $testBt = ($border['t']['width'] && $border['t']['color'][0]!==null);
1683 $testBr = ($border['r']['width'] && $border['r']['color'][0]!==null);
1684 $testBb = ($border['b']['width'] && $border['b']['color'][0]!==null);
1686 // draw the radius bottom-left
1687 if (is_array($outBL) && ($testBb || $testBl)) {
1688 if ($inBL) {
1689 $courbe = array();
1690 $courbe[] = $x+$outBL[0]; $courbe[] = $y+$h;
1691 $courbe[] = $x; $courbe[] = $y+$h-$outBL[1];
1692 $courbe[] = $x+$outBL[0]; $courbe[] = $y+$h-$border['b']['width'];
1693 $courbe[] = $x+$border['l']['width']; $courbe[] = $y+$h-$outBL[1];
1694 $courbe[] = $x+$outBL[0]; $courbe[] = $y+$h-$outBL[1];
1695 } else {
1696 $courbe = array();
1697 $courbe[] = $x+$outBL[0]; $courbe[] = $y+$h;
1698 $courbe[] = $x; $courbe[] = $y+$h-$outBL[1];
1699 $courbe[] = $x+$border['l']['width']; $courbe[] = $y+$h-$border['b']['width'];
1700 $courbe[] = $x+$outBL[0]; $courbe[] = $y+$h-$outBL[1];
1702 $this->_drawCurve($courbe, $border['l']['color']);
1705 // draw the radius left-top
1706 if (is_array($outTL) && ($testBt || $testBl)) {
1707 if ($inTL) {
1708 $courbe = array();
1709 $courbe[] = $x; $courbe[] = $y+$outTL[1];
1710 $courbe[] = $x+$outTL[0]; $courbe[] = $y;
1711 $courbe[] = $x+$border['l']['width']; $courbe[] = $y+$outTL[1];
1712 $courbe[] = $x+$outTL[0]; $courbe[] = $y+$border['t']['width'];
1713 $courbe[] = $x+$outTL[0]; $courbe[] = $y+$outTL[1];
1714 } else {
1715 $courbe = array();
1716 $courbe[] = $x; $courbe[] = $y+$outTL[1];
1717 $courbe[] = $x+$outTL[0]; $courbe[] = $y;
1718 $courbe[] = $x+$border['l']['width']; $courbe[] = $y+$border['t']['width'];
1719 $courbe[] = $x+$outTL[0]; $courbe[] = $y+$outTL[1];
1721 $this->_drawCurve($courbe, $border['t']['color']);
1724 // draw the radius top-right
1725 if (is_array($outTR) && ($testBt || $testBr)) {
1726 if ($inTR) {
1727 $courbe = array();
1728 $courbe[] = $x+$w-$outTR[0]; $courbe[] = $y;
1729 $courbe[] = $x+$w; $courbe[] = $y+$outTR[1];
1730 $courbe[] = $x+$w-$outTR[0]; $courbe[] = $y+$border['t']['width'];
1731 $courbe[] = $x+$w-$border['r']['width']; $courbe[] = $y+$outTR[1];
1732 $courbe[] = $x+$w-$outTR[0]; $courbe[] = $y+$outTR[1];
1733 } else {
1734 $courbe = array();
1735 $courbe[] = $x+$w-$outTR[0]; $courbe[] = $y;
1736 $courbe[] = $x+$w; $courbe[] = $y+$outTR[1];
1737 $courbe[] = $x+$w-$border['r']['width']; $courbe[] = $y+$border['t']['width'];
1738 $courbe[] = $x+$w-$outTR[0]; $courbe[] = $y+$outTR[1];
1740 $this->_drawCurve($courbe, $border['r']['color']);
1743 // draw the radius right-bottom
1744 if (is_array($outBR) && ($testBb || $testBr)) {
1745 if ($inBR) {
1746 $courbe = array();
1747 $courbe[] = $x+$w; $courbe[] = $y+$h-$outBR[1];
1748 $courbe[] = $x+$w-$outBR[0]; $courbe[] = $y+$h;
1749 $courbe[] = $x+$w-$border['r']['width']; $courbe[] = $y+$h-$outBR[1];
1750 $courbe[] = $x+$w-$outBR[0]; $courbe[] = $y+$h-$border['b']['width'];
1751 $courbe[] = $x+$w-$outBR[0]; $courbe[] = $y+$h-$outBR[1];
1752 } else {
1753 $courbe = array();
1754 $courbe[] = $x+$w; $courbe[] = $y+$h-$outBR[1];
1755 $courbe[] = $x+$w-$outBR[0]; $courbe[] = $y+$h;
1756 $courbe[] = $x+$w-$border['r']['width']; $courbe[] = $y+$h-$border['b']['width'];
1757 $courbe[] = $x+$w-$outBR[0]; $courbe[] = $y+$h-$outBR[1];
1759 $this->_drawCurve($courbe, $border['b']['color']);
1762 // draw the left border
1763 if ($testBl) {
1764 $pt = array();
1765 $pt[] = $x; $pt[] = $y+$h;
1766 $pt[] = $x; $pt[] = $y+$h-$border['b']['width'];
1767 $pt[] = $x; $pt[] = $y+$border['t']['width'];
1768 $pt[] = $x; $pt[] = $y;
1769 $pt[] = $x+$border['l']['width']; $pt[] = $y+$border['t']['width'];
1770 $pt[] = $x+$border['l']['width']; $pt[] = $y+$h-$border['b']['width'];
1772 $bord = 3;
1773 if (is_array($outBL)) {
1774 $bord-=1;
1775 $pt[3] -= $outBL[1] - $border['b']['width'];
1776 if ($inBL) $pt[11]-= $inBL[1];
1777 unset($pt[0]);unset($pt[1]);
1779 if (is_array($outTL)) {
1780 $bord-=2;
1781 $pt[5] += $outTL[1]-$border['t']['width'];
1782 if ($inTL) $pt[9] += $inTL[1];
1783 unset($pt[6]);unset($pt[7]);
1786 $pt = array_values($pt);
1787 $this->_drawLine($pt, $border['l']['color'], $border['l']['type'], $border['l']['width'], $bord);
1790 // draw the top border
1791 if ($testBt) {
1792 $pt = array();
1793 $pt[] = $x; $pt[] = $y;
1794 $pt[] = $x+$border['l']['width']; $pt[] = $y;
1795 $pt[] = $x+$w-$border['r']['width']; $pt[] = $y;
1796 $pt[] = $x+$w; $pt[] = $y;
1797 $pt[] = $x+$w-$border['r']['width']; $pt[] = $y+$border['t']['width'];
1798 $pt[] = $x+$border['l']['width']; $pt[] = $y+$border['t']['width'];
1800 $bord = 3;
1801 if (is_array($outTL)) {
1802 $bord-=1;
1803 $pt[2] += $outTL[0] - $border['l']['width'];
1804 if ($inTL) $pt[10]+= $inTL[0];
1805 unset($pt[0]);unset($pt[1]);
1807 if (is_array($outTR)) {
1808 $bord-=2;
1809 $pt[4] -= $outTR[0] - $border['r']['width'];
1810 if ($inTR) $pt[8] -= $inTR[0];
1811 unset($pt[6]);unset($pt[7]);
1814 $pt = array_values($pt);
1815 $this->_drawLine($pt, $border['t']['color'], $border['t']['type'], $border['t']['width'], $bord);
1818 // draw the right border
1819 if ($testBr) {
1820 $pt = array();
1821 $pt[] = $x+$w; $pt[] = $y;
1822 $pt[] = $x+$w; $pt[] = $y+$border['t']['width'];
1823 $pt[] = $x+$w; $pt[] = $y+$h-$border['b']['width'];
1824 $pt[] = $x+$w; $pt[] = $y+$h;
1825 $pt[] = $x+$w-$border['r']['width']; $pt[] = $y+$h-$border['b']['width'];
1826 $pt[] = $x+$w-$border['r']['width']; $pt[] = $y+$border['t']['width'];
1828 $bord = 3;
1829 if (is_array($outTR)) {
1830 $bord-=1;
1831 $pt[3] += $outTR[1] - $border['t']['width'];
1832 if ($inTR) $pt[11]+= $inTR[1];
1833 unset($pt[0]);unset($pt[1]);
1835 if (is_array($outBR)) {
1836 $bord-=2;
1837 $pt[5] -= $outBR[1] - $border['b']['width'];
1838 if ($inBR) $pt[9] -= $inBR[1];
1839 unset($pt[6]);unset($pt[7]);
1842 $pt = array_values($pt);
1843 $this->_drawLine($pt, $border['r']['color'], $border['r']['type'], $border['r']['width'], $bord);
1846 // draw the bottom border
1847 if ($testBb) {
1848 $pt = array();
1849 $pt[] = $x+$w; $pt[] = $y+$h;
1850 $pt[] = $x+$w-$border['r']['width']; $pt[] = $y+$h;
1851 $pt[] = $x+$border['l']['width']; $pt[] = $y+$h;
1852 $pt[] = $x; $pt[] = $y+$h;
1853 $pt[] = $x+$border['l']['width']; $pt[] = $y+$h-$border['b']['width'];
1854 $pt[] = $x+$w-$border['r']['width']; $pt[] = $y+$h-$border['b']['width'];
1856 $bord = 3;
1857 if (is_array($outBL)) {
1858 $bord-=2;
1859 $pt[4] += $outBL[0] - $border['l']['width'];
1860 if ($inBL) $pt[8] += $inBL[0];
1861 unset($pt[6]);unset($pt[7]);
1863 if (is_array($outBR)) {
1864 $bord-=1;
1865 $pt[2] -= $outBR[0] - $border['r']['width'];
1866 if ($inBR) $pt[10]-= $inBR[0];
1867 unset($pt[0]);unset($pt[1]);
1871 $pt = array_values($pt);
1872 $this->_drawLine($pt, $border['b']['color'], $border['b']['type'], $border['b']['width'], $bord);
1875 if ($background['color']) {
1876 $this->pdf->setFillColorArray($background['color']);
1879 return true;
1883 * draw a curve (for border radius)
1885 * @access protected
1886 * @param array $pt
1887 * @param array $color
1889 protected function _drawCurve($pt, $color)
1891 $this->pdf->setFillColorArray($color);
1893 if (count($pt)==10)
1894 $this->pdf->drawCurve($pt[0], $pt[1], $pt[2], $pt[3], $pt[4], $pt[5], $pt[6], $pt[7], $pt[8], $pt[9]);
1895 else
1896 $this->pdf->drawCorner($pt[0], $pt[1], $pt[2], $pt[3], $pt[4], $pt[5], $pt[6], $pt[7]);
1900 * draw a line with a specific type, and specific start and end for radius
1902 * @access protected
1903 * @param array $pt
1904 * @param array $color
1905 * @param string $type (dashed, dotted, double, solid)
1906 * @param float $width
1907 * @param integer $radius (binary from 0 to 3 with 1=>start with a radius, 2=>end with a radius)
1909 protected function _drawLine($pt, $color, $type, $width, $radius=3)
1911 // set the fill color
1912 $this->pdf->setFillColorArray($color);
1914 // if dashed or dotted
1915 if ($type=='dashed' || $type=='dotted') {
1917 // clean the end of the line, if radius
1918 if ($radius==1) {
1919 $tmp = array(); $tmp[]=$pt[0]; $tmp[]=$pt[1]; $tmp[]=$pt[2]; $tmp[]=$pt[3]; $tmp[]=$pt[8]; $tmp[]=$pt[9];
1920 $this->pdf->Polygon($tmp, 'F');
1922 $tmp = array(); $tmp[]=$pt[2]; $tmp[]=$pt[3]; $tmp[]=$pt[4]; $tmp[]=$pt[5]; $tmp[]=$pt[6]; $tmp[]=$pt[7]; $tmp[]=$pt[8]; $tmp[]=$pt[9];
1923 $pt = $tmp;
1924 } else if ($radius==2) {
1925 $tmp = array(); $tmp[]=$pt[2]; $tmp[]=$pt[3]; $tmp[]=$pt[4]; $tmp[]=$pt[5]; $tmp[]=$pt[6]; $tmp[]=$pt[7];
1926 $this->pdf->Polygon($tmp, 'F');
1928 $tmp = array(); $tmp[]=$pt[0]; $tmp[]=$pt[1]; $tmp[]=$pt[2]; $tmp[]=$pt[3]; $tmp[]=$pt[6]; $tmp[]=$pt[7]; $tmp[]=$pt[8]; $tmp[]=$pt[9];
1929 $pt = $tmp;
1930 } else if ($radius==3) {
1931 $tmp = array(); $tmp[]=$pt[0]; $tmp[]=$pt[1]; $tmp[]=$pt[2]; $tmp[]=$pt[3]; $tmp[]=$pt[10]; $tmp[]=$pt[11];
1932 $this->pdf->Polygon($tmp, 'F');
1934 $tmp = array(); $tmp[]=$pt[4]; $tmp[]=$pt[5]; $tmp[]=$pt[6]; $tmp[]=$pt[7]; $tmp[]=$pt[8]; $tmp[]=$pt[9];
1935 $this->pdf->Polygon($tmp, 'F');
1937 $tmp = array(); $tmp[]=$pt[2]; $tmp[]=$pt[3]; $tmp[]=$pt[4]; $tmp[]=$pt[5]; $tmp[]=$pt[8]; $tmp[]=$pt[9]; $tmp[]=$pt[10]; $tmp[]=$pt[11];
1938 $pt = $tmp;
1941 // horisontal or vertical line
1942 if ($pt[2]==$pt[0]) {
1943 $l = abs(($pt[3]-$pt[1])*0.5);
1944 $px = 0;
1945 $py = $width;
1946 $x1 = $pt[0]; $y1 = ($pt[3]+$pt[1])*0.5;
1947 $x2 = $pt[6]; $y2 = ($pt[7]+$pt[5])*0.5;
1948 } else {
1949 $l = abs(($pt[2]-$pt[0])*0.5);
1950 $px = $width;
1951 $py = 0;
1952 $x1 = ($pt[2]+$pt[0])*0.5; $y1 = $pt[1];
1953 $x2 = ($pt[6]+$pt[4])*0.5; $y2 = $pt[7];
1956 // if dashed : 3x bigger than dotted
1957 if ($type=='dashed') {
1958 $px = $px*3.;
1959 $py = $py*3.;
1961 $mode = ($l/($px+$py)<.5);
1963 // display the dotted/dashed line
1964 for ($i=0; $l-($px+$py)*($i-0.5)>0; $i++) {
1965 if (($i%2)==$mode) {
1966 $j = $i-0.5;
1967 $lx1 = $px*($j); if ($lx1<-$l) $lx1 =-$l;
1968 $ly1 = $py*($j); if ($ly1<-$l) $ly1 =-$l;
1969 $lx2 = $px*($j+1); if ($lx2>$l) $lx2 = $l;
1970 $ly2 = $py*($j+1); if ($ly2>$l) $ly2 = $l;
1972 $tmp = array();
1973 $tmp[] = $x1+$lx1; $tmp[] = $y1+$ly1;
1974 $tmp[] = $x1+$lx2; $tmp[] = $y1+$ly2;
1975 $tmp[] = $x2+$lx2; $tmp[] = $y2+$ly2;
1976 $tmp[] = $x2+$lx1; $tmp[] = $y2+$ly1;
1977 $this->pdf->Polygon($tmp, 'F');
1979 if ($j>0) {
1980 $tmp = array();
1981 $tmp[] = $x1-$lx1; $tmp[] = $y1-$ly1;
1982 $tmp[] = $x1-$lx2; $tmp[] = $y1-$ly2;
1983 $tmp[] = $x2-$lx2; $tmp[] = $y2-$ly2;
1984 $tmp[] = $x2-$lx1; $tmp[] = $y2-$ly1;
1985 $this->pdf->Polygon($tmp, 'F');
1989 } else if ($type=='double') {
1991 // if double, 2 lines : 0=>1/3 and 2/3=>1
1992 $pt1 = $pt;
1993 $pt2 = $pt;
1995 if (count($pt)==12) {
1996 // line 1
1997 $pt1[0] = ($pt[0]-$pt[10])*0.33 + $pt[10];
1998 $pt1[1] = ($pt[1]-$pt[11])*0.33 + $pt[11];
1999 $pt1[2] = ($pt[2]-$pt[10])*0.33 + $pt[10];
2000 $pt1[3] = ($pt[3]-$pt[11])*0.33 + $pt[11];
2001 $pt1[4] = ($pt[4]-$pt[8])*0.33 + $pt[8];
2002 $pt1[5] = ($pt[5]-$pt[9])*0.33 + $pt[9];
2003 $pt1[6] = ($pt[6]-$pt[8])*0.33 + $pt[8];
2004 $pt1[7] = ($pt[7]-$pt[9])*0.33 + $pt[9];
2005 $pt2[10]= ($pt[10]-$pt[0])*0.33 + $pt[0];
2006 $pt2[11]= ($pt[11]-$pt[1])*0.33 + $pt[1];
2008 // line 2
2009 $pt2[2] = ($pt[2] -$pt[0])*0.33 + $pt[0];
2010 $pt2[3] = ($pt[3] -$pt[1])*0.33 + $pt[1];
2011 $pt2[4] = ($pt[4] -$pt[6])*0.33 + $pt[6];
2012 $pt2[5] = ($pt[5] -$pt[7])*0.33 + $pt[7];
2013 $pt2[8] = ($pt[8] -$pt[6])*0.33 + $pt[6];
2014 $pt2[9] = ($pt[9] -$pt[7])*0.33 + $pt[7];
2015 } else {
2016 // line 1
2017 $pt1[0] = ($pt[0]-$pt[6])*0.33 + $pt[6];
2018 $pt1[1] = ($pt[1]-$pt[7])*0.33 + $pt[7];
2019 $pt1[2] = ($pt[2]-$pt[4])*0.33 + $pt[4];
2020 $pt1[3] = ($pt[3]-$pt[5])*0.33 + $pt[5];
2022 // line 2
2023 $pt2[6] = ($pt[6]-$pt[0])*0.33 + $pt[0];
2024 $pt2[7] = ($pt[7]-$pt[1])*0.33 + $pt[1];
2025 $pt2[4] = ($pt[4]-$pt[2])*0.33 + $pt[2];
2026 $pt2[5] = ($pt[5]-$pt[3])*0.33 + $pt[3];
2028 $this->pdf->Polygon($pt1, 'F');
2029 $this->pdf->Polygon($pt2, 'F');
2030 } else if ($type=='solid') {
2031 // solid line : draw directly the polygon
2032 $this->pdf->Polygon($pt, 'F');
2037 * prepare a transform matrix, only for drawing a SVG graphic
2039 * @access protected
2040 * @param string $transform
2041 * @return array $matrix
2043 protected function _prepareTransform($transform)
2045 // it can not be empty
2046 if (!$transform) return null;
2048 // sctions must be like scale(...)
2049 if (!preg_match_all('/([a-z]+)\(([^\)]*)\)/isU', $transform, $match)) return null;
2051 // prepare the list of the actions
2052 $actions = array();
2054 // for actions
2055 for ($k=0; $k<count($match[0]); $k++) {
2057 // get the name of the action
2058 $name = strtolower($match[1][$k]);
2060 // get the parameters of the action
2061 $val = explode(',', trim($match[2][$k]));
2062 foreach ($val as $i => $j) {
2063 $val[$i] = trim($j);
2066 // prepare the matrix, depending on the action
2067 switch($name)
2069 case 'scale':
2070 if (!isset($val[0])) $val[0] = 1.; else $val[0] = 1.*$val[0];
2071 if (!isset($val[1])) $val[1] = $val[0]; else $val[1] = 1.*$val[1];
2072 $actions[] = array($val[0],0,0,$val[1],0,0);
2073 break;
2075 case 'translate':
2076 if (!isset($val[0])) $val[0] = 0.; else $val[0] = $this->parsingCss->ConvertToMM($val[0], $this->_isInDraw['w']);
2077 if (!isset($val[1])) $val[1] = 0.; else $val[1] = $this->parsingCss->ConvertToMM($val[1], $this->_isInDraw['h']);
2078 $actions[] = array(1,0,0,1,$val[0],$val[1]);
2079 break;
2081 case 'rotate':
2082 if (!isset($val[0])) $val[0] = 0.; else $val[0] = $val[0]*M_PI/180.;
2083 if (!isset($val[1])) $val[1] = 0.; else $val[1] = $this->parsingCss->ConvertToMM($val[1], $this->_isInDraw['w']);
2084 if (!isset($val[2])) $val[2] = 0.; else $val[2] = $this->parsingCss->ConvertToMM($val[2], $this->_isInDraw['h']);
2085 if ($val[1] || $val[2]) $actions[] = array(1,0,0,1,-$val[1],-$val[2]);
2086 $actions[] = array(cos($val[0]),sin($val[0]),-sin($val[0]),cos($val[0]),0,0);
2087 if ($val[1] || $val[2]) $actions[] = array(1,0,0,1,$val[1],$val[2]);
2088 break;
2090 case 'skewx':
2091 if (!isset($val[0])) $val[0] = 0.; else $val[0] = $val[0]*M_PI/180.;
2092 $actions[] = array(1,0,tan($val[0]),1,0,0);
2093 break;
2095 case 'skewy':
2096 if (!isset($val[0])) $val[0] = 0.; else $val[0] = $val[0]*M_PI/180.;
2097 $actions[] = array(1,tan($val[0]),0,1,0,0);
2098 break;
2099 case 'matrix':
2100 if (!isset($val[0])) $val[0] = 0.; else $val[0] = $val[0]*1.;
2101 if (!isset($val[1])) $val[1] = 0.; else $val[1] = $val[1]*1.;
2102 if (!isset($val[2])) $val[2] = 0.; else $val[2] = $val[2]*1.;
2103 if (!isset($val[3])) $val[3] = 0.; else $val[3] = $val[3]*1.;
2104 if (!isset($val[4])) $val[4] = 0.; else $val[4] = $this->parsingCss->ConvertToMM($val[4], $this->_isInDraw['w']);
2105 if (!isset($val[5])) $val[5] = 0.; else $val[5] = $this->parsingCss->ConvertToMM($val[5], $this->_isInDraw['h']);
2106 $actions[] =$val;
2107 break;
2111 // if there are no actions => return
2112 if (!$actions) return null;
2114 // get the first matrix
2115 $m = $actions[0]; unset($actions[0]);
2117 // foreach matrix => multiply to the last matrix
2118 foreach ($actions as $n) {
2119 $m = array(
2120 $m[0]*$n[0]+$m[2]*$n[1],
2121 $m[1]*$n[0]+$m[3]*$n[1],
2122 $m[0]*$n[2]+$m[2]*$n[3],
2123 $m[1]*$n[2]+$m[3]*$n[3],
2124 $m[0]*$n[4]+$m[2]*$n[5]+$m[4],
2125 $m[1]*$n[4]+$m[3]*$n[5]+$m[5]
2129 // return the matrix
2130 return $m;
2134 * @access protected
2135 * @param &array $cases
2136 * @param &array $corr
2138 protected function _calculateTableCellSize(&$cases, &$corr)
2140 if (!isset($corr[0])) return true;
2142 // for each cell without colspan, we get the max width for each column
2143 $sw = array();
2144 for ($x=0; $x<count($corr[0]); $x++) {
2145 $m=0;
2146 for ($y=0; $y<count($corr); $y++) {
2147 if (isset($corr[$y][$x]) && is_array($corr[$y][$x]) && $corr[$y][$x][2]==1) {
2148 $m = max($m, $cases[$corr[$y][$x][1]][$corr[$y][$x][0]]['w']);
2151 $sw[$x] = $m;
2154 // for each cell with colspan, we adapt the width of each column
2155 for ($x=0; $x<count($corr[0]); $x++) {
2156 for ($y=0; $y<count($corr); $y++) {
2157 if (isset($corr[$y][$x]) && is_array($corr[$y][$x]) && $corr[$y][$x][2]>1) {
2159 // sum the max width of each column in colspan
2160 $s = 0; for ($i=0; $i<$corr[$y][$x][2]; $i++) $s+= $sw[$x+$i];
2162 // if the max width is < the width of the cell with colspan => we adapt the width of each max width
2163 if ($s>0 && $s<$cases[$corr[$y][$x][1]][$corr[$y][$x][0]]['w']) {
2164 for ($i=0; $i<$corr[$y][$x][2]; $i++) {
2165 $sw[$x+$i] = $sw[$x+$i]/$s*$cases[$corr[$y][$x][1]][$corr[$y][$x][0]]['w'];
2172 // set the new width, for each cell
2173 for ($x=0; $x<count($corr[0]); $x++) {
2174 for ($y=0; $y<count($corr); $y++) {
2175 if (isset($corr[$y][$x]) && is_array($corr[$y][$x])) {
2176 // without colspan
2177 if ($corr[$y][$x][2]==1) {
2178 $cases[$corr[$y][$x][1]][$corr[$y][$x][0]]['w'] = $sw[$x];
2179 // with colspan
2180 } else {
2181 $s = 0;
2182 for ($i=0; $i<$corr[$y][$x][2]; $i++) {
2183 $s+= $sw[$x+$i];
2185 $cases[$corr[$y][$x][1]][$corr[$y][$x][0]]['w'] = $s;
2191 // for each cell without rowspan, we get the max height for each line
2192 $sh = array();
2193 for ($y=0; $y<count($corr); $y++) {
2194 $m=0;
2195 for ($x=0; $x<count($corr[0]); $x++) {
2196 if (isset($corr[$y][$x]) && is_array($corr[$y][$x]) && $corr[$y][$x][3]==1) {
2197 $m = max($m, $cases[$corr[$y][$x][1]][$corr[$y][$x][0]]['h']);
2200 $sh[$y] = $m;
2203 // for each cell with rowspan, we adapt the height of each line
2204 for ($y=0; $y<count($corr); $y++) {
2205 for ($x=0; $x<count($corr[0]); $x++) {
2206 if (isset($corr[$y][$x]) && is_array($corr[$y][$x]) && $corr[$y][$x][3]>1) {
2208 // sum the max height of each line in rowspan
2209 $s = 0;
2210 for ($i=0; $i<$corr[$y][$x][3]; $i++) {
2211 $s+= isset($sh[$y+$i]) ? $sh[$y+$i] : 0;
2214 // if the max height is < the height of the cell with rowspan => we adapt the height of each max height
2215 if ($s>0 && $s<$cases[$corr[$y][$x][1]][$corr[$y][$x][0]]['h']) {
2216 for ($i=0; $i<$corr[$y][$x][3]; $i++) {
2217 $sh[$y+$i] = $sh[$y+$i]/$s*$cases[$corr[$y][$x][1]][$corr[$y][$x][0]]['h'];
2224 // set the new height, for each cell
2225 for ($y=0; $y<count($corr); $y++) {
2226 for ($x=0; $x<count($corr[0]); $x++) {
2227 if (isset($corr[$y][$x]) && is_array($corr[$y][$x])) {
2228 // without rowspan
2229 if ($corr[$y][$x][3]==1) {
2230 $cases[$corr[$y][$x][1]][$corr[$y][$x][0]]['h'] = $sh[$y];
2231 // with rowspan
2232 } else {
2233 $s = 0;
2234 for ($i=0; $i<$corr[$y][$x][3]; $i++) {
2235 $s+= $sh[$y+$i];
2237 $cases[$corr[$y][$x][1]][$corr[$y][$x][0]]['h'] = $s;
2239 for ($j=1; $j<$corr[$y][$x][3]; $j++) {
2240 $tx = $x+1;
2241 $ty = $y+$j;
2242 for (true; isset($corr[$ty][$tx]) && !is_array($corr[$ty][$tx]); $tx++);
2243 if (isset($corr[$ty][$tx])) {
2244 $cases[$corr[$ty][$tx][1]][$corr[$ty][$tx][0]]['dw']+= $cases[$corr[$y][$x][1]][$corr[$y][$x][0]]['w'];
2254 * tag : PAGE
2255 * mode : OPEN
2257 * @param array $param
2258 * @return boolean
2260 protected function _tag_open_PAGE($param)
2262 if ($this->_isForOneLine) return false;
2263 if ($this->_debugActif) $this->_DEBUG_add('PAGE '.($this->_page+1), true);
2265 $newPageSet= (!isset($param['pageset']) || $param['pageset']!='old');
2267 $resetPageNumber = (isset($param['pagegroup']) && $param['pagegroup']=='new');
2269 if (array_key_exists('hideheader', $param) && $param['hideheader']!='false' && !empty($param['hideheader'])) {
2270 $this->_hideHeader = (array) array_merge($this->_hideHeader, split(',', $param['hideheader']));
2273 $this->_maxH = 0;
2275 // if new page set asked
2276 if ($newPageSet) {
2277 $this->_subHEADER = array();
2278 $this->_subFOOTER = array();
2280 // orientation
2281 $orientation = '';
2282 if (isset($param['orientation'])) {
2283 $param['orientation'] = strtolower($param['orientation']);
2284 if ($param['orientation']=='p') $orientation = 'P';
2285 if ($param['orientation']=='portrait') $orientation = 'P';
2287 if ($param['orientation']=='l') $orientation = 'L';
2288 if ($param['orientation']=='paysage') $orientation = 'L';
2289 if ($param['orientation']=='landscape') $orientation = 'L';
2292 // format
2293 $format = null;
2294 if (isset($param['format'])) {
2295 $format = strtolower($param['format']);
2296 if (preg_match('/^([0-9]+)x([0-9]+)$/isU', $format, $match)) {
2297 $format = array(intval($match[1]), intval($match[2]));
2301 // background
2302 $background = array();
2303 if (isset($param['backimg'])) {
2304 $background['img'] = isset($param['backimg']) ? $param['backimg'] : ''; // src of the image
2305 $background['posX'] = isset($param['backimgx']) ? $param['backimgx'] : 'center'; // horizontale position of the image
2306 $background['posY'] = isset($param['backimgy']) ? $param['backimgy'] : 'middle'; // vertical position of the image
2307 $background['width'] = isset($param['backimgw']) ? $param['backimgw'] : '100%'; // width of the image (100% = page width)
2309 // convert the src of the image, if parameters
2310 $background['img'] = str_replace('&amp;', '&', $background['img']);
2312 // convert the positions
2313 if ($background['posX']=='left') $background['posX'] = '0%';
2314 if ($background['posX']=='center') $background['posX'] = '50%';
2315 if ($background['posX']=='right') $background['posX'] = '100%';
2316 if ($background['posY']=='top') $background['posY'] = '0%';
2317 if ($background['posY']=='middle') $background['posY'] = '50%';
2318 if ($background['posY']=='bottom') $background['posY'] = '100%';
2320 if ($background['img']) {
2321 // get the size of the image
2322 // WARNING : if URL, "allow_url_fopen" must turned to "on" in php.ini
2323 $infos=@getimagesize($background['img']);
2324 if (count($infos)>1) {
2325 $imageWidth = $this->parsingCss->ConvertToMM($background['width'], $this->pdf->getW());
2326 $imageHeight = $imageWidth*$infos[1]/$infos[0];
2328 $background['width'] = $imageWidth;
2329 $background['posX'] = $this->parsingCss->ConvertToMM($background['posX'], $this->pdf->getW() - $imageWidth);
2330 $background['posY'] = $this->parsingCss->ConvertToMM($background['posY'], $this->pdf->getH() - $imageHeight);
2331 } else {
2332 $background = array();
2334 } else {
2335 $background = array();
2339 // margins of the page
2340 $background['top'] = isset($param['backtop']) ? $param['backtop'] : '0';
2341 $background['bottom'] = isset($param['backbottom']) ? $param['backbottom'] : '0';
2342 $background['left'] = isset($param['backleft']) ? $param['backleft'] : '0';
2343 $background['right'] = isset($param['backright']) ? $param['backright'] : '0';
2345 // if no unit => mm
2346 if (preg_match('/^([0-9]*)$/isU', $background['top'])) $background['top'] .= 'mm';
2347 if (preg_match('/^([0-9]*)$/isU', $background['bottom'])) $background['bottom'] .= 'mm';
2348 if (preg_match('/^([0-9]*)$/isU', $background['left'])) $background['left'] .= 'mm';
2349 if (preg_match('/^([0-9]*)$/isU', $background['right'])) $background['right'] .= 'mm';
2351 // convert to mm
2352 $background['top'] = $this->parsingCss->ConvertToMM($background['top'], $this->pdf->getH());
2353 $background['bottom'] = $this->parsingCss->ConvertToMM($background['bottom'], $this->pdf->getH());
2354 $background['left'] = $this->parsingCss->ConvertToMM($background['left'], $this->pdf->getW());
2355 $background['right'] = $this->parsingCss->ConvertToMM($background['right'], $this->pdf->getW());
2357 // get the background color
2358 $res = false;
2359 $background['color'] = isset($param['backcolor']) ? $this->parsingCss->convertToColor($param['backcolor'], $res) : null;
2360 if (!$res) $background['color'] = null;
2362 $this->parsingCss->save();
2363 $this->parsingCss->analyse('PAGE', $param);
2364 $this->parsingCss->setPosition();
2365 $this->parsingCss->fontSet();
2367 // new page
2368 $this->_setNewPage($format, $orientation, $background, null, $resetPageNumber);
2370 // automatic footer
2371 if (isset($param['footer'])) {
2372 $lst = explode(';', $param['footer']);
2373 foreach ($lst as $key => $val) $lst[$key] = trim(strtolower($val));
2374 $page = in_array('page', $lst);
2375 $date = in_array('date', $lst);
2376 $hour = in_array('heure', $lst);
2377 $form = in_array('form', $lst);
2378 } else {
2379 $page = null;
2380 $date = null;
2381 $hour = null;
2382 $form = null;
2384 $this->pdf->SetMyFooter($page, $date, $hour, $form);
2385 // else => we use the last page set used
2386 } else {
2387 $this->parsingCss->save();
2388 $this->parsingCss->analyse('PAGE', $param);
2389 $this->parsingCss->setPosition();
2390 $this->parsingCss->fontSet();
2392 $this->_setNewPage(null, null, null, null, $resetPageNumber);
2395 return true;
2399 * tag : PAGE
2400 * mode : CLOSE
2402 * @param array $param
2403 * @return boolean
2405 protected function _tag_close_PAGE($param)
2407 if ($this->_isForOneLine) return false;
2409 $this->_maxH = 0;
2411 $this->parsingCss->load();
2412 $this->parsingCss->fontSet();
2414 if ($this->_debugActif) $this->_DEBUG_add('PAGE '.$this->_page, false);
2416 return true;
2420 * tag : PAGE_HEADER
2421 * mode : OPEN
2423 * @param array $param
2424 * @return boolean
2426 protected function _tag_open_PAGE_HEADER($param)
2428 if ($this->_isForOneLine) return false;
2430 $this->_subHEADER = array();
2431 for ($this->_parsePos; $this->_parsePos<count($this->parsingHtml->code); $this->_parsePos++) {
2432 $action = $this->parsingHtml->code[$this->_parsePos];
2433 if ($action['name']=='page_header') $action['name']='page_header_sub';
2434 $this->_subHEADER[] = $action;
2435 if (strtolower($action['name'])=='page_header_sub' && $action['close']) break;
2438 $this->_setPageHeader();
2440 return true;
2444 * tag : PAGE_FOOTER
2445 * mode : OPEN
2447 * @param array $param
2448 * @return boolean
2450 protected function _tag_open_PAGE_FOOTER($param)
2452 if ($this->_isForOneLine) return false;
2454 $this->_subFOOTER = array();
2455 for ($this->_parsePos; $this->_parsePos<count($this->parsingHtml->code); $this->_parsePos++) {
2456 $action = $this->parsingHtml->code[$this->_parsePos];
2457 if ($action['name']=='page_footer') $action['name']='page_footer_sub';
2458 $this->_subFOOTER[] = $action;
2459 if (strtolower($action['name'])=='page_footer_sub' && $action['close']) break;
2462 $this->_setPageFooter();
2464 return true;
2468 * It is not a real tag. Does not use it directly
2470 * @param array $param
2471 * @return boolean
2473 protected function _tag_open_PAGE_HEADER_SUB($param)
2475 if ($this->_isForOneLine) return false;
2477 // save the current stat
2478 $this->_subSTATES = array();
2479 $this->_subSTATES['x'] = $this->pdf->getX();
2480 $this->_subSTATES['y'] = $this->pdf->getY();
2481 $this->_subSTATES['s'] = $this->parsingCss->value;
2482 $this->_subSTATES['t'] = $this->parsingCss->table;
2483 $this->_subSTATES['ml'] = $this->_margeLeft;
2484 $this->_subSTATES['mr'] = $this->_margeRight;
2485 $this->_subSTATES['mt'] = $this->_margeTop;
2486 $this->_subSTATES['mb'] = $this->_margeBottom;
2487 $this->_subSTATES['mp'] = $this->_pageMarges;
2489 // new stat for the header
2490 $this->_pageMarges = array();
2491 $this->_margeLeft = $this->_defaultLeft;
2492 $this->_margeRight = $this->_defaultRight;
2493 $this->_margeTop = $this->_defaultTop;
2494 $this->_margeBottom = $this->_defaultBottom;
2495 $this->pdf->SetMargins($this->_margeLeft, $this->_margeTop, $this->_margeRight);
2496 $this->pdf->SetAutoPageBreak(false, $this->_margeBottom);
2497 $this->pdf->setXY($this->_defaultLeft, $this->_defaultTop);
2499 $this->parsingCss->initStyle();
2500 $this->parsingCss->resetStyle();
2501 $this->parsingCss->value['width'] = $this->pdf->getW() - $this->_defaultLeft - $this->_defaultRight;
2502 $this->parsingCss->table = array();
2504 $this->parsingCss->save();
2505 $this->parsingCss->analyse('page_header_sub', $param);
2506 $this->parsingCss->setPosition();
2507 $this->parsingCss->fontSet();
2508 $this->_setNewPositionForNewLine();
2509 return true;
2513 * It is not a real tag. Does not use it directly
2515 * @param array $param
2516 * @return boolean
2518 protected function _tag_close_PAGE_HEADER_SUB($param)
2520 if ($this->_isForOneLine) return false;
2522 $this->parsingCss->load();
2524 // restore the stat
2525 $this->parsingCss->value = $this->_subSTATES['s'];
2526 $this->parsingCss->table = $this->_subSTATES['t'];
2527 $this->_pageMarges = $this->_subSTATES['mp'];
2528 $this->_margeLeft = $this->_subSTATES['ml'];
2529 $this->_margeRight = $this->_subSTATES['mr'];
2530 $this->_margeTop = $this->_subSTATES['mt'];
2531 $this->_margeBottom = $this->_subSTATES['mb'];
2532 $this->pdf->SetMargins($this->_margeLeft, $this->_margeTop, $this->_margeRight);
2533 $this->pdf->setbMargin($this->_margeBottom);
2534 $this->pdf->SetAutoPageBreak(false, $this->_margeBottom);
2535 $this->pdf->setXY($this->_subSTATES['x'], $this->_subSTATES['y']);
2537 $this->parsingCss->fontSet();
2538 $this->_maxH = 0;
2540 return true;
2544 * It is not a real tag. Does not use it directly
2546 * @param array $param
2547 * @return boolean
2549 protected function _tag_open_PAGE_FOOTER_SUB($param)
2551 if ($this->_isForOneLine) return false;
2553 // save the current stat
2554 $this->_subSTATES = array();
2555 $this->_subSTATES['x'] = $this->pdf->getX();
2556 $this->_subSTATES['y'] = $this->pdf->getY();
2557 $this->_subSTATES['s'] = $this->parsingCss->value;
2558 $this->_subSTATES['t'] = $this->parsingCss->table;
2559 $this->_subSTATES['ml'] = $this->_margeLeft;
2560 $this->_subSTATES['mr'] = $this->_margeRight;
2561 $this->_subSTATES['mt'] = $this->_margeTop;
2562 $this->_subSTATES['mb'] = $this->_margeBottom;
2563 $this->_subSTATES['mp'] = $this->_pageMarges;
2565 // new stat for the footer
2566 $this->_pageMarges = array();
2567 $this->_margeLeft = $this->_defaultLeft;
2568 $this->_margeRight = $this->_defaultRight;
2569 $this->_margeTop = $this->_defaultTop;
2570 $this->_margeBottom = $this->_defaultBottom;
2571 $this->pdf->SetMargins($this->_margeLeft, $this->_margeTop, $this->_margeRight);
2572 $this->pdf->SetAutoPageBreak(false, $this->_margeBottom);
2573 $this->pdf->setXY($this->_defaultLeft, $this->_defaultTop);
2575 $this->parsingCss->initStyle();
2576 $this->parsingCss->resetStyle();
2577 $this->parsingCss->value['width'] = $this->pdf->getW() - $this->_defaultLeft - $this->_defaultRight;
2578 $this->parsingCss->table = array();
2580 // we create a sub HTML2PFDF, and we execute on it the content of the footer, to get the height of it
2581 $sub = null;
2582 $this->_createSubHTML($sub);
2583 $sub->parsingHtml->code = $this->parsingHtml->getLevel($this->_parsePos);
2584 $sub->_makeHTMLcode();
2585 $this->pdf->setY($this->pdf->getH() - $sub->_maxY - $this->_defaultBottom - 0.01);
2586 $this->_destroySubHTML($sub);
2588 $this->parsingCss->save();
2589 $this->parsingCss->analyse('page_footer_sub', $param);
2590 $this->parsingCss->setPosition();
2591 $this->parsingCss->fontSet();
2592 $this->_setNewPositionForNewLine();
2594 return true;
2598 * It is not a real tag. Do not use it directly
2600 * @param array $param
2601 * @return boolean
2603 protected function _tag_close_PAGE_FOOTER_SUB($param)
2605 if ($this->_isForOneLine) return false;
2607 $this->parsingCss->load();
2609 $this->parsingCss->value = $this->_subSTATES['s'];
2610 $this->parsingCss->table = $this->_subSTATES['t'];
2611 $this->_pageMarges = $this->_subSTATES['mp'];
2612 $this->_margeLeft = $this->_subSTATES['ml'];
2613 $this->_margeRight = $this->_subSTATES['mr'];
2614 $this->_margeTop = $this->_subSTATES['mt'];
2615 $this->_margeBottom = $this->_subSTATES['mb'];
2616 $this->pdf->SetMargins($this->_margeLeft, $this->_margeTop, $this->_margeRight);
2617 $this->pdf->SetAutoPageBreak(false, $this->_margeBottom);
2618 $this->pdf->setXY($this->_subSTATES['x'], $this->_subSTATES['y']);
2620 $this->parsingCss->fontSet();
2621 $this->_maxH = 0;
2623 return true;
2627 * tag : NOBREAK
2628 * mode : OPEN
2630 * @param array $param
2631 * @return boolean
2633 protected function _tag_open_NOBREAK($param)
2635 if ($this->_isForOneLine) return false;
2637 $this->_maxH = 0;
2639 // create a sub HTML2PDF to execute the content of the tag, to get the dimensions
2640 $sub = null;
2641 $this->_createSubHTML($sub);
2642 $sub->parsingHtml->code = $this->parsingHtml->getLevel($this->_parsePos);
2643 $sub->_makeHTMLcode();
2644 $y = $this->pdf->getY();
2646 // if the content does not fit on the page => new page
2647 if (
2648 $sub->_maxY < ($this->pdf->getH() - $this->pdf->gettMargin()-$this->pdf->getbMargin()) &&
2649 $y + $sub->_maxY>=($this->pdf->getH() - $this->pdf->getbMargin())
2651 $this->_setNewPage();
2654 // destroy the sub HTML2PDF
2655 $this->_destroySubHTML($sub);
2657 return true;
2662 * tag : NOBREAK
2663 * mode : CLOSE
2665 * @param array $param
2666 * @return boolean
2668 protected function _tag_close_NOBREAK($param)
2670 if ($this->_isForOneLine) return false;
2672 $this->_maxH = 0;
2674 return true;
2678 * tag : DIV
2679 * mode : OPEN
2681 * @param array $param
2682 * @param string $other name of tag that used the div tag
2683 * @return boolean
2685 protected function _tag_open_DIV($param, $other = 'div')
2687 if ($this->_isForOneLine) return false;
2688 if ($this->_debugActif) $this->_DEBUG_add(strtoupper($other), true);
2690 $this->parsingCss->save();
2691 $this->parsingCss->analyse($other, $param);
2692 $this->parsingCss->fontSet();
2694 // for fieldset and legend
2695 if (in_array($other, array('fieldset', 'legend'))) {
2696 if (isset($param['moveTop'])) $this->parsingCss->value['margin']['t'] += $param['moveTop'];
2697 if (isset($param['moveLeft'])) $this->parsingCss->value['margin']['l'] += $param['moveLeft'];
2698 if (isset($param['moveDown'])) $this->parsingCss->value['margin']['b'] += $param['moveDown'];
2701 $alignObject = null;
2702 if ($this->parsingCss->value['margin-auto']) $alignObject = 'center';
2704 $marge = array();
2705 $marge['l'] = $this->parsingCss->value['border']['l']['width'] + $this->parsingCss->value['padding']['l']+0.03;
2706 $marge['r'] = $this->parsingCss->value['border']['r']['width'] + $this->parsingCss->value['padding']['r']+0.03;
2707 $marge['t'] = $this->parsingCss->value['border']['t']['width'] + $this->parsingCss->value['padding']['t']+0.03;
2708 $marge['b'] = $this->parsingCss->value['border']['b']['width'] + $this->parsingCss->value['padding']['b']+0.03;
2710 // extract the content of the div
2711 $level = $this->parsingHtml->getLevel($this->_parsePos);
2713 // create a sub HTML2PDF to get the dimensions of the content of the div
2714 $w = 0; $h = 0;
2715 if (count($level)) {
2716 $sub = null;
2717 $this->_createSubHTML($sub);
2718 $sub->parsingHtml->code = $level;
2719 $sub->_makeHTMLcode();
2720 $w = $sub->_maxX;
2721 $h = $sub->_maxY;
2722 $this->_destroySubHTML($sub);
2724 $wReel = $w;
2725 $hReel = $h;
2727 $w+= $marge['l']+$marge['r']+0.001;
2728 $h+= $marge['t']+$marge['b']+0.001;
2730 if ($this->parsingCss->value['overflow']=='hidden') {
2731 $overW = max($w, $this->parsingCss->value['width']);
2732 $overH = max($h, $this->parsingCss->value['height']);
2733 $overflow = true;
2734 $this->parsingCss->value['old_maxX'] = $this->_maxX;
2735 $this->parsingCss->value['old_maxY'] = $this->_maxY;
2736 $this->parsingCss->value['old_maxH'] = $this->_maxH;
2737 $this->parsingCss->value['old_overflow'] = $this->_isInOverflow;
2738 $this->_isInOverflow = true;
2739 } else {
2740 $overW = null;
2741 $overH = null;
2742 $overflow = false;
2743 $this->parsingCss->value['width'] = max($w, $this->parsingCss->value['width']);
2744 $this->parsingCss->value['height'] = max($h, $this->parsingCss->value['height']);
2747 switch($this->parsingCss->value['rotate'])
2749 case 90:
2750 $tmp = $overH; $overH = $overW; $overW = $tmp;
2751 $tmp = $hReel; $hReel = $wReel; $wReel = $tmp;
2752 unset($tmp);
2753 $w = $this->parsingCss->value['height'];
2754 $h = $this->parsingCss->value['width'];
2755 $tX =-$h;
2756 $tY = 0;
2757 break;
2759 case 180:
2760 $w = $this->parsingCss->value['width'];
2761 $h = $this->parsingCss->value['height'];
2762 $tX = -$w;
2763 $tY = -$h;
2764 break;
2766 case 270:
2767 $tmp = $overH; $overH = $overW; $overW = $tmp;
2768 $tmp = $hReel; $hReel = $wReel; $wReel = $tmp;
2769 unset($tmp);
2770 $w = $this->parsingCss->value['height'];
2771 $h = $this->parsingCss->value['width'];
2772 $tX = 0;
2773 $tY =-$w;
2774 break;
2776 default:
2777 $w = $this->parsingCss->value['width'];
2778 $h = $this->parsingCss->value['height'];
2779 $tX = 0;
2780 $tY = 0;
2781 break;
2784 if (!$this->parsingCss->value['position']) {
2785 if (
2786 $w < ($this->pdf->getW() - $this->pdf->getlMargin()-$this->pdf->getrMargin()) &&
2787 $this->pdf->getX() + $w>=($this->pdf->getW() - $this->pdf->getrMargin())
2789 $this->_tag_open_BR(array());
2791 if (
2792 ($h < ($this->pdf->getH() - $this->pdf->gettMargin()-$this->pdf->getbMargin())) &&
2793 ($this->pdf->getY() + $h>=($this->pdf->getH() - $this->pdf->getbMargin())) &&
2794 !$this->_isInOverflow
2796 $this->_setNewPage();
2798 $old = $this->parsingCss->getOldValues();
2799 $parentWidth = $old['width'] ? $old['width'] : $this->pdf->getW() - $this->pdf->getlMargin() - $this->pdf->getrMargin();
2801 if ($parentWidth>$w) {
2802 if ($alignObject=='center') $this->pdf->setX($this->pdf->getX() + ($parentWidth-$w)*0.5);
2803 else if ($alignObject=='right') $this->pdf->setX($this->pdf->getX() + $parentWidth-$w);
2806 $this->parsingCss->setPosition();
2807 } else {
2808 $old = $this->parsingCss->getOldValues();
2809 $parentWidth = $old['width'] ? $old['width'] : $this->pdf->getW() - $this->pdf->getlMargin() - $this->pdf->getrMargin();
2811 if ($parentWidth>$w) {
2812 if ($alignObject=='center') $this->pdf->setX($this->pdf->getX() + ($parentWidth-$w)*0.5);
2813 else if ($alignObject=='right') $this->pdf->setX($this->pdf->getX() + $parentWidth-$w);
2816 $this->parsingCss->setPosition();
2817 $this->_saveMax();
2818 $this->_maxX = 0;
2819 $this->_maxY = 0;
2820 $this->_maxH = 0;
2821 $this->_maxE = 0;
2824 if ($this->parsingCss->value['rotate']) {
2825 $this->pdf->startTransform();
2826 $this->pdf->setRotation($this->parsingCss->value['rotate']);
2827 $this->pdf->setTranslate($tX, $tY);
2830 $this->_drawRectangle(
2831 $this->parsingCss->value['x'],
2832 $this->parsingCss->value['y'],
2833 $this->parsingCss->value['width'],
2834 $this->parsingCss->value['height'],
2835 $this->parsingCss->value['border'],
2836 $this->parsingCss->value['padding'],
2838 $this->parsingCss->value['background']
2841 $marge = array();
2842 $marge['l'] = $this->parsingCss->value['border']['l']['width'] + $this->parsingCss->value['padding']['l']+0.03;
2843 $marge['r'] = $this->parsingCss->value['border']['r']['width'] + $this->parsingCss->value['padding']['r']+0.03;
2844 $marge['t'] = $this->parsingCss->value['border']['t']['width'] + $this->parsingCss->value['padding']['t']+0.03;
2845 $marge['b'] = $this->parsingCss->value['border']['b']['width'] + $this->parsingCss->value['padding']['b']+0.03;
2847 $this->parsingCss->value['width'] -= $marge['l']+$marge['r'];
2848 $this->parsingCss->value['height']-= $marge['t']+$marge['b'];
2850 $xCorr = 0;
2851 $yCorr = 0;
2852 if (!$this->_subPart && !$this->_isSubPart) {
2853 switch($this->parsingCss->value['text-align'])
2855 case 'right':
2856 $xCorr = ($this->parsingCss->value['width']-$wReel);
2857 break;
2858 case 'center':
2859 $xCorr = ($this->parsingCss->value['width']-$wReel)*0.5;
2860 break;
2862 if ($xCorr>0) $xCorr=0;
2863 switch($this->parsingCss->value['vertical-align'])
2865 case 'bottom':
2866 $yCorr = ($this->parsingCss->value['height']-$hReel);
2867 break;
2868 case 'middle':
2869 $yCorr = ($this->parsingCss->value['height']-$hReel)*0.5;
2870 break;
2874 if ($overflow) {
2875 $overW-= $marge['l']+$marge['r'];
2876 $overH-= $marge['t']+$marge['b'];
2877 $this->pdf->clippingPathStart(
2878 $this->parsingCss->value['x']+$marge['l'],
2879 $this->parsingCss->value['y']+$marge['t'],
2880 $this->parsingCss->value['width'],
2881 $this->parsingCss->value['height']
2884 $this->parsingCss->value['x']+= $xCorr;
2886 // marges from the dimension of the content
2887 $mL = $this->parsingCss->value['x']+$marge['l'];
2888 $mR = $this->pdf->getW() - $mL - $overW;
2889 } else {
2890 // marges from the dimension of the div
2891 $mL = $this->parsingCss->value['x']+$marge['l'];
2892 $mR = $this->pdf->getW() - $mL - $this->parsingCss->value['width'];
2895 $x = $this->parsingCss->value['x']+$marge['l'];
2896 $y = $this->parsingCss->value['y']+$marge['t']+$yCorr;
2897 $this->_saveMargin($mL, 0, $mR);
2898 $this->pdf->setXY($x, $y);
2900 $this->_setNewPositionForNewLine();
2902 return true;
2906 * tag : BLOCKQUOTE
2907 * mode : OPEN
2909 * @param array $param
2910 * @return boolean
2912 protected function _tag_open_BLOCKQUOTE($param)
2914 return $this->_tag_open_DIV($param, 'blockquote');
2918 * tag : LEGEND
2919 * mode : OPEN
2921 * @param array $param
2922 * @return boolean
2924 protected function _tag_open_LEGEND($param)
2926 return $this->_tag_open_DIV($param, 'legend');
2930 * tag : FIELDSET
2931 * mode : OPEN
2933 * @author Pavel Kochman
2934 * @param array $param
2935 * @return boolean
2937 protected function _tag_open_FIELDSET($param)
2940 $this->parsingCss->save();
2941 $this->parsingCss->analyse('fieldset', $param);
2943 // get height of LEGEND element and make fieldset corrections
2944 for ($tempPos = $this->_parsePos + 1; $tempPos<count($this->parsingHtml->code); $tempPos++) {
2945 $action = $this->parsingHtml->code[$tempPos];
2946 if ($action['name'] == 'fieldset') break;
2947 if ($action['name'] == 'legend' && !$action['close']) {
2948 $legendOpenPos = $tempPos;
2950 $sub = null;
2951 $this->_createSubHTML($sub);
2952 $sub->parsingHtml->code = $this->parsingHtml->getLevel($tempPos - 1);
2954 $res = null;
2955 for ($sub->_parsePos = 0; $sub->_parsePos<count($sub->parsingHtml->code); $sub->_parsePos++) {
2956 $action = $sub->parsingHtml->code[$sub->_parsePos];
2957 $sub->_executeAction($action);
2959 if ($action['name'] == 'legend' && $action['close'])
2960 break;
2963 $legendH = $sub->_maxY;
2964 $this->_destroySubHTML($sub);
2966 $move = $this->parsingCss->value['padding']['t'] + $this->parsingCss->value['border']['t']['width'] + 0.03;
2968 $param['moveTop'] = $legendH / 2;
2970 $this->parsingHtml->code[$legendOpenPos]['param']['moveTop'] = - ($legendH / 2 + $move);
2971 $this->parsingHtml->code[$legendOpenPos]['param']['moveLeft'] = 2 - $this->parsingCss->value['border']['l']['width'] - $this->parsingCss->value['padding']['l'];
2972 $this->parsingHtml->code[$legendOpenPos]['param']['moveDown'] = $move;
2973 break;
2976 $this->parsingCss->load();
2978 return $this->_tag_open_DIV($param, 'fieldset');
2982 * tag : DIV
2983 * mode : CLOSE
2985 * @param array $param
2986 * @param string $other name of tag that used the div tag
2987 * @return boolean
2989 protected function _tag_close_DIV($param, $other='div')
2991 if ($this->_isForOneLine) return false;
2993 if ($this->parsingCss->value['overflow']=='hidden') {
2994 $this->_maxX = $this->parsingCss->value['old_maxX'];
2995 $this->_maxY = $this->parsingCss->value['old_maxY'];
2996 $this->_maxH = $this->parsingCss->value['old_maxH'];
2997 $this->_isInOverflow = $this->parsingCss->value['old_overflow'];
2998 $this->pdf->clippingPathStop();
3001 if ($this->parsingCss->value['rotate'])
3002 $this->pdf->stopTransform();
3004 $marge = array();
3005 $marge['l'] = $this->parsingCss->value['border']['l']['width'] + $this->parsingCss->value['padding']['l']+0.03;
3006 $marge['r'] = $this->parsingCss->value['border']['r']['width'] + $this->parsingCss->value['padding']['r']+0.03;
3007 $marge['t'] = $this->parsingCss->value['border']['t']['width'] + $this->parsingCss->value['padding']['t']+0.03;
3008 $marge['b'] = $this->parsingCss->value['border']['b']['width'] + $this->parsingCss->value['padding']['b']+0.03;
3010 $x = $this->parsingCss->value['x'];
3011 $y = $this->parsingCss->value['y'];
3012 $w = $this->parsingCss->value['width']+$marge['l']+$marge['r']+$this->parsingCss->value['margin']['r'];
3013 $h = $this->parsingCss->value['height']+$marge['t']+$marge['b']+$this->parsingCss->value['margin']['b'];
3015 switch($this->parsingCss->value['rotate'])
3017 case 90:
3018 $t = $w; $w = $h; $h = $t;
3019 break;
3021 case 270:
3022 $t = $w; $w = $h; $h = $t;
3023 break;
3025 default:
3026 break;
3030 if ($this->parsingCss->value['position']!='absolute') {
3031 $this->pdf->setXY($x+$w, $y);
3033 $this->_maxX = max($this->_maxX, $x+$w);
3034 $this->_maxY = max($this->_maxY, $y+$h);
3035 $this->_maxH = max($this->_maxH, $h);
3036 } else {
3037 $this->pdf->setXY($this->parsingCss->value['xc'], $this->parsingCss->value['yc']);
3039 $this->_loadMax();
3042 $block = ($this->parsingCss->value['display']!='inline' && $this->parsingCss->value['position']!='absolute');
3044 $this->parsingCss->load();
3045 $this->parsingCss->fontSet();
3046 $this->_loadMargin();
3048 if ($block) $this->_tag_open_BR(array());
3049 if ($this->_debugActif) $this->_DEBUG_add(strtoupper($other), false);
3051 return true;
3055 * tag : BLOCKQUOTE
3056 * mode : CLOSE
3058 * @param array $param
3059 * @return boolean
3061 protected function _tag_close_BLOCKQUOTE($param)
3063 return $this->_tag_close_DIV($param, 'blockquote');
3067 * tag : FIELDSET
3068 * mode : CLOSE
3070 * @param array $param
3071 * @return boolean
3073 protected function _tag_close_FIELDSET($param)
3075 return $this->_tag_close_DIV($param, 'fieldset');
3079 * tag : LEGEND
3080 * mode : CLOSE
3082 * @param array $param
3083 * @return boolean
3085 protected function _tag_close_LEGEND($param)
3087 return $this->_tag_close_DIV($param, 'legend');
3091 * tag : BARCODE
3092 * mode : OPEN
3094 * @param array $param
3095 * @return boolean
3097 protected function _tag_open_BARCODE($param)
3099 // for compatibility with old versions < 3.29
3100 $lstBarcode = array();
3101 $lstBarcode['UPC_A'] = 'UPCA';
3102 $lstBarcode['CODE39'] = 'C39';
3104 if (!isset($param['type'])) $param['type'] = 'C39';
3105 if (!isset($param['value'])) $param['value'] = 0;
3106 if (!isset($param['label'])) $param['label'] = 'label';
3107 if (!isset($param['style']['color'])) $param['style']['color'] = '#000000';
3109 if ($this->_testIsDeprecated && (isset($param['bar_h']) || isset($param['bar_w'])))
3110 throw new HTML2PDF_exception(9, array('BARCODE', 'bar_h, bar_w'));
3112 $param['type'] = strtoupper($param['type']);
3113 if (isset($lstBarcode[$param['type']])) $param['type'] = $lstBarcode[$param['type']];
3115 $this->parsingCss->save();
3116 $this->parsingCss->analyse('barcode', $param);
3117 $this->parsingCss->setPosition();
3118 $this->parsingCss->fontSet();
3120 $x = $this->pdf->getX();
3121 $y = $this->pdf->getY();
3122 $w = $this->parsingCss->value['width']; if (!$w) $w = $this->parsingCss->ConvertToMM('50mm');
3123 $h = $this->parsingCss->value['height']; if (!$h) $h = $this->parsingCss->ConvertToMM('10mm');
3124 $txt = ($param['label']!=='none' ? $this->parsingCss->value['font-size'] : false);
3125 $c = $this->parsingCss->value['color'];
3126 $infos = $this->pdf->myBarcode($param['value'], $param['type'], $x, $y, $w, $h, $txt, $c);
3128 $this->_maxX = max($this->_maxX, $x+$infos[0]);
3129 $this->_maxY = max($this->_maxY, $y+$infos[1]);
3130 $this->_maxH = max($this->_maxH, $infos[1]);
3131 $this->_maxE++;
3133 $this->pdf->setXY($x+$infos[0], $y);
3135 $this->parsingCss->load();
3136 $this->parsingCss->fontSet();
3138 return true;
3142 * tag : BARCODE
3143 * mode : CLOSE
3145 * @param array $param
3146 * @return boolean
3148 protected function _tag_close_BARCODE($param)
3150 // there is nothing to do here
3152 return true;
3156 * tag : QRCODE
3157 * mode : OPEN
3159 * @param array $param
3160 * @return boolean
3162 protected function _tag_open_QRCODE($param)
3164 if ($this->_testIsDeprecated && (isset($param['size']) || isset($param['noborder'])))
3165 throw new HTML2PDF_exception(9, array('QRCODE', 'size, noborder'));
3167 if ($this->_debugActif) $this->_DEBUG_add('QRCODE');
3169 if (!isset($param['value'])) $param['value'] = '';
3170 if (!isset($param['ec'])) $param['ec'] = 'H';
3171 if (!isset($param['style']['color'])) $param['style']['color'] = '#000000';
3172 if (!isset($param['style']['background-color'])) $param['style']['background-color'] = '#FFFFFF';
3173 if (isset($param['style']['border'])) {
3174 $borders = $param['style']['border']!='none';
3175 unset($param['style']['border']);
3176 } else {
3177 $borders = true;
3180 if ($param['value']==='') return true;
3181 if (!in_array($param['ec'], array('L', 'M', 'Q', 'H'))) $param['ec'] = 'H';
3183 $this->parsingCss->save();
3184 $this->parsingCss->analyse('qrcode', $param);
3185 $this->parsingCss->setPosition();
3186 $this->parsingCss->fontSet();
3188 $x = $this->pdf->getX();
3189 $y = $this->pdf->getY();
3190 $w = $this->parsingCss->value['width'];
3191 $h = $this->parsingCss->value['height'];
3192 $size = max($w, $h); if (!$size) $size = $this->parsingCss->ConvertToMM('50mm');
3194 $style = array(
3195 'fgcolor' => $this->parsingCss->value['color'],
3196 'bgcolor' => $this->parsingCss->value['background']['color'],
3199 if ($borders) {
3200 $style['border'] = true;
3201 $style['padding'] = 'auto';
3202 } else {
3203 $style['border'] = false;
3204 $style['padding'] = 0;
3207 if (!$this->_subPart && !$this->_isSubPart) {
3208 $this->pdf->write2DBarcode($param['value'], 'QRCODE,'.$param['ec'], $x, $y, $size, $size, $style);
3211 $this->_maxX = max($this->_maxX, $x+$size);
3212 $this->_maxY = max($this->_maxY, $y+$size);
3213 $this->_maxH = max($this->_maxH, $size);
3214 $this->_maxE++;
3216 $this->pdf->setX($x+$size);
3218 $this->parsingCss->load();
3219 $this->parsingCss->fontSet();
3221 return true;
3225 * tag : QRCODE
3226 * mode : CLOSE
3228 * @param array $param
3229 * @return boolean
3231 protected function _tag_close_QRCODE($param)
3233 // there is nothing to do here
3235 return true;
3239 * tag : BOOKMARK
3240 * mode : OPEN
3242 * @param array $param
3243 * @return boolean
3245 protected function _tag_open_BOOKMARK($param)
3247 $titre = isset($param['title']) ? trim($param['title']) : '';
3248 $level = isset($param['level']) ? floor($param['level']) : 0;
3250 if ($level<0) $level = 0;
3251 if ($titre) $this->pdf->Bookmark($titre, $level, -1);
3253 return true;
3257 * tag : BOOKMARK
3258 * mode : CLOSE
3260 * @param array $param
3261 * @return boolean
3263 protected function _tag_close_BOOKMARK($param)
3265 // there is nothing to do here
3267 return true;
3271 * this is not a real TAG, it is just to write texts
3273 * @param array $param
3274 * @return boolean
3276 protected function _tag_open_WRITE($param)
3278 $fill = ($this->parsingCss->value['background']['color']!==null && $this->parsingCss->value['background']['image']===null);
3279 if (in_array($this->parsingCss->value['id_tag'], array('fieldset', 'legend', 'div', 'table', 'tr', 'td', 'th'))) {
3280 $fill = false;
3283 // get the text to write
3284 $txt = $param['txt'];
3286 if ($this->_isAfterFloat) {
3287 $txt = ltrim($txt);
3288 $this->_isAfterFloat = false;
3291 $txt = str_replace('[[page_nb]]', $this->pdf->getMyAliasNbPages(), $txt);
3292 $txt = str_replace('[[page_cu]]', $this->pdf->getMyNumPage($this->_page), $txt);
3294 if ($this->parsingCss->value['text-transform']!='none') {
3295 if ($this->parsingCss->value['text-transform']=='capitalize')
3296 $txt = mb_convert_case($txt, MB_CASE_TITLE, $this->_encoding);
3297 else if ($this->parsingCss->value['text-transform']=='uppercase')
3298 $txt = mb_convert_case($txt, MB_CASE_UPPER, $this->_encoding);
3299 else if ($this->parsingCss->value['text-transform']=='lowercase')
3300 $txt = mb_convert_case($txt, MB_CASE_LOWER, $this->_encoding);
3303 // size of the text
3304 $h = 1.08*$this->parsingCss->value['font-size'];
3305 $dh = $h*$this->parsingCss->value['mini-decal'];
3306 $lh = $this->parsingCss->getLineHeight();
3308 // identify the align
3309 $align = 'L';
3310 if ($this->parsingCss->value['text-align']=='li_right') {
3311 $w = $this->parsingCss->value['width'];
3312 $align = 'R';
3315 // calculate the width of each words, and of all the sentence
3316 $w = 0;
3317 $words = explode(' ', $txt);
3318 foreach ($words as $k => $word) {
3319 $words[$k] = array($word, $this->pdf->GetStringWidth($word));
3320 $w+= $words[$k][1];
3322 $space = $this->pdf->GetStringWidth(' ');
3323 $w+= $space*(count($words)-1);
3325 // position in the text
3326 $currPos = 0;
3328 // the bigger width of the text, after automatic break line
3329 $maxX = 0;
3331 // position of the text
3332 $x = $this->pdf->getX();
3333 $y = $this->pdf->getY();
3334 $dy = $this->_getElementY($lh);
3336 // margins
3337 list($left, $right) = $this->_getMargins($y);
3339 // number of lines after automatic break line
3340 $nb = 0;
3342 // while we have words, and the text does not fit on the line => we cut the sentence
3343 while ($x+$w>$right && $x<$right+$space && count($words)) {
3344 // adding words 1 by 1 to fit on the line
3345 $i=0;
3346 $old = array('', 0);
3347 $str = $words[0];
3348 $add = false;
3349 while (($x+$str[1])<$right) {
3350 $i++;
3351 $add = true;
3353 array_shift($words);
3354 $old = $str;
3356 if (!count($words)) break;
3357 $str[0].= ' '.$words[0][0];
3358 $str[1]+= $space+$words[0][1];
3360 $str = $old;
3362 // if nothing fits on the line, and if the first word does not fit on the line => the word is too long, we put it
3363 if ($i==0 && (($left+$words[0][1])>=$right)) {
3364 $str = $words[0];
3365 array_shift($words);
3366 $i++;
3367 $add = true;
3369 $currPos+= ($currPos ? 1 : 0)+strlen($str[0]);
3371 // write the extract sentence that fit on the page
3372 $wc = ($align=='L' ? $str[1] : $this->parsingCss->value['width']);
3373 if ($right - $left<$wc) $wc = $right - $left;
3375 if (strlen($str[0])) {
3376 $this->pdf->setXY($this->pdf->getX(), $y+$dh+$dy);
3377 $this->pdf->Cell($wc, $h, $str[0], 0, 0, $align, $fill, $this->_isInLink);
3378 $this->pdf->setXY($this->pdf->getX(), $y);
3380 $this->_maxH = max($this->_maxH, $lh);
3382 // max width
3383 $maxX = max($maxX, $this->pdf->getX());
3385 // new position and new width for the "while"
3386 $w-= $str[1];
3387 $y = $this->pdf->getY();
3388 $x = $this->pdf->getX();
3389 $dy = $this->_getElementY($lh);
3391 // if we have again words to write
3392 if (count($words)) {
3393 // remove the space at the end
3394 if ($add) $w-= $space;
3396 // if we don't add any word, and if the first word is empty => useless space to skip
3397 if (!$add && $words[0][0]==='') {
3398 array_shift($words);
3401 // if it is just to calculate for one line => adding the number of words
3402 if ($this->_isForOneLine) {
3403 $this->_maxE+= $i;
3404 $this->_maxX = max($this->_maxX, $maxX);
3405 return null;
3408 // automatic line break
3409 $this->_tag_open_BR(array('style' => ''), $currPos);
3411 // new position
3412 $y = $this->pdf->getY();
3413 $x = $this->pdf->getX();
3414 $dy = $this->_getElementY($lh);
3416 // if the next line does not fit on the page => new page
3417 if ($y + $h>=$this->pdf->getH() - $this->pdf->getbMargin()) {
3418 if (!$this->_isInOverflow && !$this->_isInFooter) {
3419 $this->_setNewPage(null, '', null, $currPos);
3420 $y = $this->pdf->getY();
3421 $x = $this->pdf->getX();
3422 $dy = $this->_getElementY($lh);
3426 // if more than 10000 line => error
3427 $nb++;
3428 if ($nb>10000) {
3429 $txt = ''; foreach ($words as $k => $word) $txt.= ($k ? ' ' : '').$word[0];
3430 throw new HTML2PDF_exception(2, array($txt, $right-$left, $w));
3433 // new margins for the new line
3434 list($left, $right) = $this->_getMargins($y);
3438 // if we have words after automatic cut, it is because they fit on the line => we write the text
3439 if (count($words)) {
3440 $txt = ''; foreach ($words as $k => $word) $txt.= ($k ? ' ' : '').$word[0];
3441 $w+= $this->pdf->getWordSpacing()*(count($words));
3442 $this->pdf->setXY($this->pdf->getX(), $y+$dh+$dy);
3443 $this->pdf->Cell(($align=='L' ? $w : $this->parsingCss->value['width']), $h, $txt, 0, 0, $align, $fill, $this->_isInLink);
3444 $this->pdf->setXY($this->pdf->getX(), $y);
3445 $this->_maxH = max($this->_maxH, $lh);
3446 $this->_maxE+= count($words);
3449 $maxX = max($maxX, $this->pdf->getX());
3450 $maxY = $this->pdf->getY()+$h;
3452 $this->_maxX = max($this->_maxX, $maxX);
3453 $this->_maxY = max($this->_maxY, $maxY);
3455 return true;
3459 * tag : BR
3460 * mode : OPEN
3462 * @param array $param
3463 * @param integer $curr real position in the html parseur (if break line in the write of a text)
3464 * @return boolean
3466 protected function _tag_open_BR($param, $curr = null)
3468 if ($this->_isForOneLine) return false;
3470 $h = max($this->_maxH, $this->parsingCss->getLineHeight());
3472 if ($this->_maxH==0) $this->_maxY = max($this->_maxY, $this->pdf->getY()+$h);
3474 $this->_makeBreakLine($h, $curr);
3476 $this->_maxH = 0;
3477 $this->_maxE = 0;
3479 return true;
3483 * tag : HR
3484 * mode : OPEN
3486 * @param array $param
3487 * @return boolean
3489 protected function _tag_open_HR($param)
3491 if ($this->_isForOneLine) return false;
3492 $oldAlign = $this->parsingCss->value['text-align'];
3493 $this->parsingCss->value['text-align'] = 'left';
3495 if ($this->_maxH) $this->_tag_open_BR($param);
3497 $fontSize = $this->parsingCss->value['font-size'];
3498 $this->parsingCss->value['font-size']=$fontSize*0.5;
3499 $this->_tag_open_BR($param);
3500 $this->parsingCss->value['font-size']=$fontSize;
3502 $param['style']['width'] = '100%';
3504 $this->parsingCss->save();
3505 $this->parsingCss->value['height']=$this->parsingCss->ConvertToMM('1mm');
3507 $this->parsingCss->analyse('hr', $param);
3508 $this->parsingCss->setPosition();
3509 $this->parsingCss->fontSet();
3511 $h = $this->parsingCss->value['height'];
3512 if ($h) $h-= $this->parsingCss->value['border']['t']['width']+$this->parsingCss->value['border']['b']['width'];
3513 if ($h<=0) $h = $this->parsingCss->value['border']['t']['width']+$this->parsingCss->value['border']['b']['width'];
3515 $this->_drawRectangle($this->pdf->getX(), $this->pdf->getY(), $this->parsingCss->value['width'], $h, $this->parsingCss->value['border'], 0, 0, $this->parsingCss->value['background']);
3516 $this->_maxH = $h;
3518 $this->parsingCss->load();
3519 $this->parsingCss->fontSet();
3521 $this->parsingCss->value['font-size'] = 0;
3522 $this->_tag_open_BR($param);
3524 $this->parsingCss->value['font-size']=$fontSize*0.5; $this->_tag_open_BR($param);
3525 $this->parsingCss->value['font-size']=$fontSize;
3527 $this->parsingCss->value['text-align'] = $oldAlign;
3528 $this->_setNewPositionForNewLine();
3530 return true;
3534 * tag : B
3535 * mode : OPEN
3537 * @param array $param
3538 * @param string $other
3539 * @return boolean
3541 protected function _tag_open_B($param, $other = 'b')
3543 $this->parsingCss->save();
3544 $this->parsingCss->value['font-bold'] = true;
3545 $this->parsingCss->analyse($other, $param);
3546 $this->parsingCss->setPosition();
3547 $this->parsingCss->fontSet();
3549 return true;
3553 * tag : STRONG
3554 * mode : OPEN
3556 * @param array $param
3557 * @return boolean
3559 protected function _tag_open_STRONG($param)
3561 return $this->_tag_open_B($param, 'strong');
3565 * tag : B
3566 * mode : CLOSE
3568 * @param array $param
3569 * @return boolean
3571 protected function _tag_close_B($param)
3573 $this->parsingCss->load();
3574 $this->parsingCss->fontSet();
3576 return true;
3580 * tag : STRONG
3581 * mode : CLOSE
3583 * @param array $param
3584 * @return boolean
3586 protected function _tag_close_STRONG($param)
3588 return $this->_tag_close_B($param);
3592 * tag : I
3593 * mode : OPEN
3595 * @param array $param
3596 * @param string $other
3597 * @return boolean
3599 protected function _tag_open_I($param, $other = 'i')
3601 $this->parsingCss->save();
3602 $this->parsingCss->value['font-italic'] = true;
3603 $this->parsingCss->analyse($other, $param);
3604 $this->parsingCss->setPosition();
3605 $this->parsingCss->fontSet();
3607 return true;
3611 * tag : ADDRESS
3612 * mode : OPEN
3614 * @param array $param
3615 * @return boolean
3617 protected function _tag_open_ADDRESS($param)
3619 return $this->_tag_open_I($param, 'address');
3623 * tag : CITE
3624 * mode : OPEN
3626 * @param array $param
3627 * @return boolean
3629 protected function _tag_open_CITE($param)
3631 return $this->_tag_open_I($param, 'cite');
3635 * tag : EM
3636 * mode : OPEN
3638 * @param array $param
3639 * @return boolean
3641 protected function _tag_open_EM($param)
3643 return $this->_tag_open_I($param, 'em');
3647 * tag : SAMP
3648 * mode : OPEN
3650 * @param array $param
3651 * @return boolean
3653 protected function _tag_open_SAMP($param)
3655 return $this->_tag_open_I($param, 'samp');
3659 * tag : I
3660 * mode : CLOSE
3662 * @param array $param
3663 * @return boolean
3665 protected function _tag_close_I($param)
3667 $this->parsingCss->load();
3668 $this->parsingCss->fontSet();
3670 return true;
3674 * tag : ADDRESS
3675 * mode : CLOSE
3677 * @param array $param
3678 * @return boolean
3680 protected function _tag_close_ADDRESS($param)
3682 return $this->_tag_close_I($param);
3686 * tag : CITE
3687 * mode : CLOSE
3689 * @param array $param
3690 * @return boolean
3692 protected function _tag_close_CITE($param)
3694 return $this->_tag_close_I($param);
3698 * tag : EM
3699 * mode : CLOSE
3701 * @param array $param
3702 * @return boolean
3704 protected function _tag_close_EM($param)
3706 return $this->_tag_close_I($param);
3710 * tag : SAMP
3711 * mode : CLOSE
3713 * @param array $param
3714 * @return boolean
3716 protected function _tag_close_SAMP($param)
3718 return $this->_tag_close_I($param);
3722 * tag : S
3723 * mode : OPEN
3725 * @param array $param
3726 * @param string $other
3727 * @return boolean
3729 protected function _tag_open_S($param, $other = 's')
3731 $this->parsingCss->save();
3732 $this->parsingCss->value['font-linethrough'] = true;
3733 $this->parsingCss->analyse($other, $param);
3734 $this->parsingCss->setPosition();
3735 $this->parsingCss->fontSet();
3737 return true;
3741 * tag : DEL
3742 * mode : OPEN
3744 * @param array $param
3745 * @return boolean
3747 protected function _tag_open_DEL($param)
3749 return $this->_tag_open_S($param, 'del');
3753 * tag : S
3754 * mode : CLOSE
3756 * @param array $param
3757 * @return boolean
3759 protected function _tag_close_S($param)
3761 $this->parsingCss->load();
3762 $this->parsingCss->fontSet();
3764 return true;
3768 * tag : DEL
3769 * mode : CLOSE
3771 * @param array $param
3772 * @return boolean
3774 protected function _tag_close_DEL($param)
3776 return $this->_tag_close_S($param);
3780 * tag : U
3781 * mode : OPEN
3783 * @param array $param
3784 * @param string $other
3785 * @return boolean
3787 protected function _tag_open_U($param, $other='u')
3789 $this->parsingCss->save();
3790 $this->parsingCss->value['font-underline'] = true;
3791 $this->parsingCss->analyse($other, $param);
3792 $this->parsingCss->setPosition();
3793 $this->parsingCss->fontSet();
3795 return true;
3799 * tag : INS
3800 * mode : OPEN
3802 * @param array $param
3803 * @return boolean
3805 protected function _tag_open_INS($param)
3807 return $this->_tag_open_U($param, 'ins');
3811 * tag : U
3812 * mode : CLOSE
3814 * @param array $param
3815 * @return boolean
3817 protected function _tag_close_U($param)
3819 $this->parsingCss->load();
3820 $this->parsingCss->fontSet();
3822 return true;
3826 * tag : INS
3827 * mode : CLOSE
3829 * @param array $param
3830 * @return boolean
3832 protected function _tag_close_INS($param)
3834 return $this->_tag_close_U($param);
3838 * tag : A
3839 * mode : OPEN
3841 * @param array $param
3842 * @return boolean
3844 protected function _tag_open_A($param)
3846 $this->_isInLink = str_replace('&amp;', '&', isset($param['href']) ? $param['href'] : '');
3848 if (isset($param['name'])) {
3849 $name = $param['name'];
3850 if (!isset($this->_lstAnchor[$name])) $this->_lstAnchor[$name] = array($this->pdf->AddLink(), false);
3852 if (!$this->_lstAnchor[$name][1]) {
3853 $this->_lstAnchor[$name][1] = true;
3854 $this->pdf->SetLink($this->_lstAnchor[$name][0], -1, -1);
3858 if (preg_match('/^#([^#]+)$/isU', $this->_isInLink, $match)) {
3859 $name = $match[1];
3860 if (!isset($this->_lstAnchor[$name])) $this->_lstAnchor[$name] = array($this->pdf->AddLink(), false);
3862 $this->_isInLink = $this->_lstAnchor[$name][0];
3865 $this->parsingCss->save();
3866 $this->parsingCss->value['font-underline'] = true;
3867 $this->parsingCss->value['color'] = array(20, 20, 250);
3868 $this->parsingCss->analyse('a', $param);
3869 $this->parsingCss->setPosition();
3870 $this->parsingCss->fontSet();
3872 return true;
3876 * tag : A
3877 * mode : CLOSE
3879 * @param array $param
3880 * @return boolean
3882 protected function _tag_close_A($param)
3884 $this->_isInLink = '';
3885 $this->parsingCss->load();
3886 $this->parsingCss->fontSet();
3888 return true;
3892 * tag : H1
3893 * mode : OPEN
3895 * @param array $param
3896 * @param string $other
3897 * @return boolean
3899 protected function _tag_open_H1($param, $other = 'h1')
3901 if ($this->_isForOneLine) return false;
3903 if ($this->_maxH) $this->_tag_open_BR(array());
3904 $this->parsingCss->save();
3905 $this->parsingCss->value['font-bold'] = true;
3907 $size = array('h1' => '28px', 'h2' => '24px', 'h3' => '20px', 'h4' => '16px', 'h5' => '12px', 'h6' => '9px');
3908 $this->parsingCss->value['margin']['l'] = 0;
3909 $this->parsingCss->value['margin']['r'] = 0;
3910 $this->parsingCss->value['margin']['t'] = $this->parsingCss->ConvertToMM('16px');
3911 $this->parsingCss->value['margin']['b'] = $this->parsingCss->ConvertToMM('16px');
3912 $this->parsingCss->value['font-size'] = $this->parsingCss->ConvertToMM($size[$other]);
3914 $this->parsingCss->analyse($other, $param);
3915 $this->parsingCss->setPosition();
3916 $this->parsingCss->fontSet();
3917 $this->_setNewPositionForNewLine();
3919 return true;
3923 * tag : H2
3924 * mode : OPEN
3926 * @param array $param
3927 * @return boolean
3929 protected function _tag_open_H2($param)
3931 return $this->_tag_open_H1($param, 'h2');
3935 * tag : H3
3936 * mode : OPEN
3938 * @param array $param
3939 * @return boolean
3941 protected function _tag_open_H3($param)
3943 return $this->_tag_open_H1($param, 'h3');
3947 * tag : H4
3948 * mode : OPEN
3950 * @param array $param
3951 * @return boolean
3953 protected function _tag_open_H4($param)
3955 return $this->_tag_open_H1($param, 'h4');
3959 * tag : H5
3960 * mode : OPEN
3962 * @param array $param
3963 * @return boolean
3965 protected function _tag_open_H5($param)
3967 return $this->_tag_open_H1($param, 'h5');
3971 * tag : H6
3972 * mode : OPEN
3974 * @param array $param
3975 * @return boolean
3977 protected function _tag_open_H6($param)
3979 return $this->_tag_open_H1($param, 'h6');
3983 * tag : H1
3984 * mode : CLOSE
3986 * @param array $param
3987 * @return boolean
3989 protected function _tag_close_H1($param)
3991 if ($this->_isForOneLine) return false;
3993 $this->_maxH+= $this->parsingCss->value['margin']['b'];
3994 $h = max($this->_maxH, $this->parsingCss->getLineHeight());
3996 $this->parsingCss->load();
3997 $this->parsingCss->fontSet();
3999 $this->_makeBreakLine($h);
4000 $this->_maxH = 0;
4002 $this->_maxY = max($this->_maxY, $this->pdf->getY());
4004 return true;
4008 * tag : H2
4009 * mode : CLOSE
4011 * @param array $param
4012 * @return boolean
4014 protected function _tag_close_H2($param)
4016 return $this->_tag_close_H1($param);
4020 * tag : H3
4021 * mode : CLOSE
4023 * @param array $param
4024 * @return boolean
4026 protected function _tag_close_H3($param)
4028 return $this->_tag_close_H1($param);
4032 * tag : H4
4033 * mode : CLOSE
4035 * @param array $param
4036 * @return boolean
4038 protected function _tag_close_H4($param)
4040 return $this->_tag_close_H1($param);
4044 * tag : H5
4045 * mode : CLOSE
4047 * @param array $param
4048 * @return boolean
4050 protected function _tag_close_H5($param)
4052 return $this->_tag_close_H1($param);
4056 * tag : H6
4057 * mode : CLOSE
4059 * @param array $param
4060 * @return boolean
4062 protected function _tag_close_H6($param)
4064 return $this->_tag_close_H1($param);
4068 * tag : SPAN
4069 * mode : OPEN
4071 * @param array $param
4072 * @param string $other
4073 * @return boolean
4075 protected function _tag_open_SPAN($param, $other = 'span')
4077 $this->parsingCss->save();
4078 $this->parsingCss->analyse($other, $param);
4079 $this->parsingCss->setPosition();
4080 $this->parsingCss->fontSet();
4082 return true;
4086 * tag : FONT
4087 * mode : OPEN
4089 * @param array $param
4090 * @return boolean
4092 protected function _tag_open_FONT($param)
4094 return $this->_tag_open_SPAN($param, 'font');
4098 * tag : LABEL
4099 * mode : OPEN
4101 * @param array $param
4102 * @return boolean
4104 protected function _tag_open_LABEL($param)
4106 return $this->_tag_open_SPAN($param, 'label');
4110 * tag : SPAN
4111 * mode : CLOSE
4113 * @param array $param
4114 * @return boolean
4116 protected function _tag_close_SPAN($param)
4118 $this->parsingCss->restorePosition();
4119 $this->parsingCss->load();
4120 $this->parsingCss->fontSet();
4122 return true;
4126 * tag : FONT
4127 * mode : CLOSE
4129 * @param array $param
4130 * @return boolean
4132 protected function _tag_close_FONT($param)
4134 return $this->_tag_close_SPAN($param);
4138 * tag : LABEL
4139 * mode : CLOSE
4141 * @param array $param
4142 * @return boolean
4144 protected function _tag_close_LABEL($param)
4146 return $this->_tag_close_SPAN($param);
4150 * tag : P
4151 * mode : OPEN
4153 * @param array $param
4154 * @return boolean
4156 protected function _tag_open_P($param)
4158 if ($this->_isForOneLine) return false;
4160 if (!in_array($this->_previousCall, array('_tag_close_P', '_tag_close_UL'))) {
4161 if ($this->_maxH) $this->_tag_open_BR(array());
4164 $this->parsingCss->save();
4165 $this->parsingCss->analyse('p', $param);
4166 $this->parsingCss->setPosition();
4167 $this->parsingCss->fontSet();
4169 // cancel the effects of the setPosition
4170 $this->pdf->setXY($this->pdf->getX()-$this->parsingCss->value['margin']['l'], $this->pdf->getY()-$this->parsingCss->value['margin']['t']);
4172 list($mL, $mR) = $this->_getMargins($this->pdf->getY());
4173 $mR = $this->pdf->getW()-$mR;
4174 $mL+= $this->parsingCss->value['margin']['l']+$this->parsingCss->value['padding']['l'];
4175 $mR+= $this->parsingCss->value['margin']['r']+$this->parsingCss->value['padding']['r'];
4176 $this->_saveMargin($mL, 0, $mR);
4178 if ($this->parsingCss->value['text-indent']>0) {
4179 $y = $this->pdf->getY()+$this->parsingCss->value['margin']['t']+$this->parsingCss->value['padding']['t'];
4180 $this->_pageMarges[floor($y*100)] = array($mL+$this->parsingCss->value['text-indent'], $this->pdf->getW()-$mR);
4181 $y+= $this->parsingCss->getLineHeight()*0.1;
4182 $this->_pageMarges[floor($y*100)] = array($mL, $this->pdf->getW()-$mR);
4184 $this->_makeBreakLine($this->parsingCss->value['margin']['t']+$this->parsingCss->value['padding']['t']);
4185 $this->_isInParagraph = array($mL, $mR);
4186 return true;
4190 * tag : P
4191 * mode : CLOSE
4193 * @param array $param
4194 * @return boolean
4196 protected function _tag_close_P($param)
4198 if ($this->_isForOneLine) return false;
4200 if ($this->_maxH) $this->_tag_open_BR(array());
4201 $this->_isInParagraph = false;
4202 $this->_loadMargin();
4203 $h = $this->parsingCss->value['margin']['b']+$this->parsingCss->value['padding']['b'];
4205 $this->parsingCss->load();
4206 $this->parsingCss->fontSet();
4207 $this->_makeBreakLine($h);
4209 return true;
4213 * tag : PRE
4214 * mode : OPEN
4216 * @param array $param
4217 * @param string $other
4218 * @return boolean
4220 protected function _tag_open_PRE($param, $other = 'pre')
4222 if ($other=='pre' && $this->_maxH) $this->_tag_open_BR(array());
4224 $this->parsingCss->save();
4225 $this->parsingCss->value['font-family'] = 'courier';
4226 $this->parsingCss->analyse($other, $param);
4227 $this->parsingCss->setPosition();
4228 $this->parsingCss->fontSet();
4230 if ($other=='pre') return $this->_tag_open_DIV($param, $other);
4232 return true;
4236 * tag : CODE
4237 * mode : OPEN
4239 * @param array $param
4240 * @return boolean
4242 protected function _tag_open_CODE($param)
4244 return $this->_tag_open_PRE($param, 'code');
4248 * tag : PRE
4249 * mode : CLOSE
4251 * @param array $param
4252 * @param string $other
4253 * @return boolean
4255 protected function _tag_close_PRE($param, $other = 'pre')
4257 if ($other=='pre') {
4258 if ($this->_isForOneLine) return false;
4260 $this->_tag_close_DIV($param, $other);
4261 $this->_tag_open_BR(array());
4263 $this->parsingCss->load();
4264 $this->parsingCss->fontSet();
4266 return true;
4270 * tag : CODE
4271 * mode : CLOSE
4273 * @param array $param
4274 * @return boolean
4276 protected function _tag_close_CODE($param)
4278 return $this->_tag_close_PRE($param, 'code');
4282 * tag : BIG
4283 * mode : OPEN
4285 * @param array $param
4286 * @return boolean
4288 protected function _tag_open_BIG($param)
4290 $this->parsingCss->save();
4291 $this->parsingCss->value['mini-decal']-= $this->parsingCss->value['mini-size']*0.12;
4292 $this->parsingCss->value['mini-size'] *= 1.2;
4293 $this->parsingCss->analyse('big', $param);
4294 $this->parsingCss->setPosition();
4295 $this->parsingCss->fontSet();
4296 return true;
4300 * tag : BIG
4301 * mode : CLOSE
4303 * @param array $param
4304 * @return boolean
4306 protected function _tag_close_BIG($param)
4308 $this->parsingCss->load();
4309 $this->parsingCss->fontSet();
4311 return true;
4315 * tag : SMALL
4316 * mode : OPEN
4318 * @param array $param
4319 * @return boolean
4321 protected function _tag_open_SMALL($param)
4323 $this->parsingCss->save();
4324 $this->parsingCss->value['mini-decal']+= $this->parsingCss->value['mini-size']*0.05;
4325 $this->parsingCss->value['mini-size'] *= 0.82;
4326 $this->parsingCss->analyse('small', $param);
4327 $this->parsingCss->setPosition();
4328 $this->parsingCss->fontSet();
4329 return true;
4333 * tag : SMALL
4334 * mode : CLOSE
4336 * @param array $param
4337 * @return boolean
4339 protected function _tag_close_SMALL($param)
4341 $this->parsingCss->load();
4342 $this->parsingCss->fontSet();
4344 return true;
4348 * tag : SUP
4349 * mode : OPEN
4351 * @param array $param
4352 * @return boolean
4354 protected function _tag_open_SUP($param)
4356 $this->parsingCss->save();
4357 $this->parsingCss->value['mini-decal']-= $this->parsingCss->value['mini-size']*0.15;
4358 $this->parsingCss->value['mini-size'] *= 0.75;
4359 $this->parsingCss->analyse('sup', $param);
4360 $this->parsingCss->setPosition();
4361 $this->parsingCss->fontSet();
4363 return true;
4367 * tag : SUP
4368 * mode : CLOSE
4370 * @param array $param
4371 * @return boolean
4373 protected function _tag_close_SUP($param)
4375 $this->parsingCss->load();
4376 $this->parsingCss->fontSet();
4378 return true;
4382 * tag : SUB
4383 * mode : OPEN
4385 * @param array $param
4386 * @return boolean
4388 protected function _tag_open_SUB($param)
4390 $this->parsingCss->save();
4391 $this->parsingCss->value['mini-decal']+= $this->parsingCss->value['mini-size']*0.15;
4392 $this->parsingCss->value['mini-size'] *= 0.75;
4393 $this->parsingCss->analyse('sub', $param);
4394 $this->parsingCss->setPosition();
4395 $this->parsingCss->fontSet();
4396 return true;
4400 * tag : SUB
4401 * mode : CLOSE
4403 * @param array $param
4404 * @return boolean
4406 protected function _tag_close_SUB($param)
4408 $this->parsingCss->load();
4409 $this->parsingCss->fontSet();
4411 return true;
4415 * tag : UL
4416 * mode : OPEN
4418 * @param array $param
4419 * @param string $other
4420 * @return boolean
4422 protected function _tag_open_UL($param, $other = 'ul')
4424 if ($this->_isForOneLine) return false;
4426 if (!in_array($this->_previousCall, array('_tag_close_P', '_tag_close_UL'))) {
4427 if ($this->_maxH) $this->_tag_open_BR(array());
4428 if (!count($this->_defList)) $this->_tag_open_BR(array());
4431 if (!isset($param['style']['width'])) $param['allwidth'] = true;
4432 $param['cellspacing'] = 0;
4434 // a list is like a table
4435 $this->_tag_open_TABLE($param, $other);
4437 // add a level of list
4438 $this->_listeAddLevel($other, $this->parsingCss->value['list-style-type'], $this->parsingCss->value['list-style-image']);
4440 return true;
4444 * tag : OL
4445 * mode : OPEN
4447 * @param array $param
4448 * @return boolean
4450 protected function _tag_open_OL($param)
4452 return $this->_tag_open_UL($param, 'ol');
4456 * tag : UL
4457 * mode : CLOSE
4459 * @param array $param
4460 * @return boolean
4462 protected function _tag_close_UL($param)
4464 if ($this->_isForOneLine) return false;
4466 $this->_tag_close_TABLE($param);
4468 $this->_listeDelLevel();
4470 if (!$this->_subPart) {
4471 if (!count($this->_defList)) $this->_tag_open_BR(array());
4474 return true;
4478 * tag : OL
4479 * mode : CLOSE
4481 * @param array $param
4482 * @return boolean
4484 protected function _tag_close_OL($param)
4486 return $this->_tag_close_UL($param);
4490 * tag : LI
4491 * mode : OPEN
4493 * @param array $param
4494 * @return boolean
4496 protected function _tag_open_LI($param)
4498 if ($this->_isForOneLine) return false;
4500 $this->_listeAddLi();
4502 if (!isset($param['style']['width'])) $param['style']['width'] = '100%';
4504 $paramPUCE = $param;
4506 $inf = $this->_listeGetLi();
4507 if ($inf[0]) {
4508 $paramPUCE['style']['font-family'] = $inf[0];
4509 $paramPUCE['style']['text-align'] = 'li_right';
4510 $paramPUCE['style']['vertical-align'] = 'top';
4511 $paramPUCE['style']['width'] = $this->_listeGetWidth();
4512 $paramPUCE['style']['padding-right'] = $this->_listeGetPadding();
4513 $paramPUCE['txt'] = $inf[2];
4514 } else {
4515 $paramPUCE['style']['text-align'] = 'li_right';
4516 $paramPUCE['style']['vertical-align'] = 'top';
4517 $paramPUCE['style']['width'] = $this->_listeGetWidth();
4518 $paramPUCE['style']['padding-right'] = $this->_listeGetPadding();
4519 $paramPUCE['src'] = $inf[2];
4520 $paramPUCE['sub_li'] = true;
4523 $this->_tag_open_TR($param, 'li');
4525 $this->parsingCss->save();
4527 // if small LI
4528 if ($inf[1]) {
4529 $this->parsingCss->value['mini-decal']+= $this->parsingCss->value['mini-size']*0.045;
4530 $this->parsingCss->value['mini-size'] *= 0.75;
4533 // if we are in a sub html => prepare. Else : display
4534 if ($this->_subPart) {
4535 // TD for the puce
4536 $tmpPos = $this->_tempPos;
4537 $tmpLst1 = $this->parsingHtml->code[$tmpPos+1];
4538 $tmpLst2 = $this->parsingHtml->code[$tmpPos+2];
4539 $this->parsingHtml->code[$tmpPos+1] = array();
4540 $this->parsingHtml->code[$tmpPos+1]['name'] = (isset($paramPUCE['src'])) ? 'img' : 'write';
4541 $this->parsingHtml->code[$tmpPos+1]['param'] = $paramPUCE; unset($this->parsingHtml->code[$tmpPos+1]['param']['style']['width']);
4542 $this->parsingHtml->code[$tmpPos+1]['close'] = 0;
4543 $this->parsingHtml->code[$tmpPos+2] = array();
4544 $this->parsingHtml->code[$tmpPos+2]['name'] = 'li';
4545 $this->parsingHtml->code[$tmpPos+2]['param'] = $paramPUCE;
4546 $this->parsingHtml->code[$tmpPos+2]['close'] = 1;
4547 $this->_tag_open_TD($paramPUCE, 'li_sub');
4548 $this->_tag_close_TD($param);
4549 $this->_tempPos = $tmpPos;
4550 $this->parsingHtml->code[$tmpPos+1] = $tmpLst1;
4551 $this->parsingHtml->code[$tmpPos+2] = $tmpLst2;
4552 } else {
4553 // TD for the puce
4554 $this->_tag_open_TD($paramPUCE, 'li_sub');
4555 unset($paramPUCE['style']['width']);
4556 if (isset($paramPUCE['src'])) $this->_tag_open_IMG($paramPUCE);
4557 else $this->_tag_open_WRITE($paramPUCE);
4558 $this->_tag_close_TD($paramPUCE);
4560 $this->parsingCss->load();
4563 // TD for the content
4564 $this->_tag_open_TD($param, 'li');
4566 return true;
4570 * tag : LI
4571 * mode : CLOSE
4573 * @param array $param
4574 * @return boolean
4576 protected function _tag_close_LI($param)
4578 if ($this->_isForOneLine) return false;
4580 $this->_tag_close_TD($param);
4582 $this->_tag_close_TR($param);
4584 return true;
4588 * tag : TBODY
4589 * mode : OPEN
4591 * @param array $param
4592 * @return boolean
4594 protected function _tag_open_TBODY($param)
4596 if ($this->_isForOneLine) return false;
4598 $this->parsingCss->save();
4599 $this->parsingCss->analyse('tbody', $param);
4600 $this->parsingCss->setPosition();
4601 $this->parsingCss->fontSet();
4603 return true;
4607 * tag : TBODY
4608 * mode : CLOSE
4610 * @param array $param
4611 * @return boolean
4613 protected function _tag_close_TBODY($param)
4615 if ($this->_isForOneLine) return false;
4617 $this->parsingCss->load();
4618 $this->parsingCss->fontSet();
4620 return true;
4624 * tag : THEAD
4625 * mode : OPEN
4627 * @param array $param
4628 * @return boolean
4630 protected function _tag_open_THEAD($param)
4632 if ($this->_isForOneLine) return false;
4634 $this->parsingCss->save();
4635 $this->parsingCss->analyse('thead', $param);
4636 $this->parsingCss->setPosition();
4637 $this->parsingCss->fontSet();
4639 // if we are in a sub part, save the number of the first TR in the thead
4640 if ($this->_subPart) {
4641 HTML2PDF::$_tables[$param['num']]['thead']['tr'][0] = HTML2PDF::$_tables[$param['num']]['tr_curr'];
4642 HTML2PDF::$_tables[$param['num']]['thead']['code'] = array();
4643 for ($pos=$this->_tempPos; $pos<count($this->parsingHtml->code); $pos++) {
4644 $action = $this->parsingHtml->code[$pos];
4645 if (strtolower($action['name'])=='thead') $action['name'] = 'thead_sub';
4646 HTML2PDF::$_tables[$param['num']]['thead']['code'][] = $action;
4647 if (strtolower($action['name'])=='thead_sub' && $action['close']) break;
4649 } else {
4650 $level = $this->parsingHtml->getLevel($this->_parsePos);
4651 $this->_parsePos+= count($level);
4652 HTML2PDF::$_tables[$param['num']]['tr_curr']+= count(HTML2PDF::$_tables[$param['num']]['thead']['tr']);
4655 return true;
4659 * tag : THEAD
4660 * mode : CLOSE
4662 * @param array $param
4663 * @return boolean
4665 protected function _tag_close_THEAD($param)
4667 if ($this->_isForOneLine) return false;
4669 $this->parsingCss->load();
4670 $this->parsingCss->fontSet();
4672 // if we are in a sub HTM, construct the list of the TR in the thead
4673 if ($this->_subPart) {
4674 $min = HTML2PDF::$_tables[$param['num']]['thead']['tr'][0];
4675 $max = HTML2PDF::$_tables[$param['num']]['tr_curr']-1;
4676 HTML2PDF::$_tables[$param['num']]['thead']['tr'] = range($min, $max);
4679 return true;
4683 * tag : TFOOT
4684 * mode : OPEN
4686 * @param array $param
4687 * @return boolean
4689 protected function _tag_open_TFOOT($param)
4691 if ($this->_isForOneLine) return false;
4693 $this->parsingCss->save();
4694 $this->parsingCss->analyse('tfoot', $param);
4695 $this->parsingCss->setPosition();
4696 $this->parsingCss->fontSet();
4698 // if we are in a sub part, save the number of the first TR in the tfoot
4699 if ($this->_subPart) {
4700 HTML2PDF::$_tables[$param['num']]['tfoot']['tr'][0] = HTML2PDF::$_tables[$param['num']]['tr_curr'];
4701 HTML2PDF::$_tables[$param['num']]['tfoot']['code'] = array();
4702 for ($pos=$this->_tempPos; $pos<count($this->parsingHtml->code); $pos++) {
4703 $action = $this->parsingHtml->code[$pos];
4704 if (strtolower($action['name'])=='tfoot') $action['name'] = 'tfoot_sub';
4705 HTML2PDF::$_tables[$param['num']]['tfoot']['code'][] = $action;
4706 if (strtolower($action['name'])=='tfoot_sub' && $action['close']) break;
4708 } else {
4709 $level = $this->parsingHtml->getLevel($this->_parsePos);
4710 $this->_parsePos+= count($level);
4711 HTML2PDF::$_tables[$param['num']]['tr_curr']+= count(HTML2PDF::$_tables[$param['num']]['tfoot']['tr']);
4714 return true;
4718 * tag : TFOOT
4719 * mode : CLOSE
4721 * @param array $param
4722 * @return boolean
4724 protected function _tag_close_TFOOT($param)
4726 if ($this->_isForOneLine) return false;
4728 $this->parsingCss->load();
4729 $this->parsingCss->fontSet();
4731 // if we are in a sub HTM, construct the list of the TR in the tfoot
4732 if ($this->_subPart) {
4733 $min = HTML2PDF::$_tables[$param['num']]['tfoot']['tr'][0];
4734 $max = HTML2PDF::$_tables[$param['num']]['tr_curr']-1;
4735 HTML2PDF::$_tables[$param['num']]['tfoot']['tr'] = range($min, $max);
4738 return true;
4742 * It is not a real TAG, do not use it !
4744 * @param array $param
4745 * @return boolean
4747 protected function _tag_open_THEAD_SUB($param)
4749 if ($this->_isForOneLine) return false;
4751 $this->parsingCss->save();
4752 $this->parsingCss->analyse('thead', $param);
4753 $this->parsingCss->setPosition();
4754 $this->parsingCss->fontSet();
4756 return true;
4760 * It is not a real TAG, do not use it !
4762 * @param array $param
4763 * @return boolean
4765 protected function _tag_close_THEAD_SUB($param)
4767 if ($this->_isForOneLine) return false;
4769 $this->parsingCss->load();
4770 $this->parsingCss->fontSet();
4772 return true;
4776 * It is not a real TAG, do not use it !
4778 * @param array $param
4779 * @return boolean
4781 protected function _tag_open_TFOOT_SUB($param)
4783 if ($this->_isForOneLine) return false;
4785 $this->parsingCss->save();
4786 $this->parsingCss->analyse('tfoot', $param);
4787 $this->parsingCss->setPosition();
4788 $this->parsingCss->fontSet();
4790 return true;
4794 * It is not a real TAG, do not use it !
4796 * @param array $param
4797 * @return boolean
4799 protected function _tag_close_TFOOT_SUB($param)
4801 if ($this->_isForOneLine) return false;
4803 $this->parsingCss->load();
4804 $this->parsingCss->fontSet();
4806 return true;
4810 * tag : FORM
4811 * mode : OPEN
4813 * @param array $param
4814 * @return boolean
4816 protected function _tag_open_FORM($param)
4818 $this->parsingCss->save();
4819 $this->parsingCss->analyse('form', $param);
4820 $this->parsingCss->setPosition();
4821 $this->parsingCss->fontSet();
4823 $this->pdf->setFormDefaultProp(
4824 array(
4825 'lineWidth'=>1,
4826 'borderStyle'=>'solid',
4827 'fillColor'=>array(220, 220, 255),
4828 'strokeColor'=>array(128, 128, 200)
4832 $this->_isInForm = isset($param['action']) ? $param['action'] : '';
4834 return true;
4838 * tag : FORM
4839 * mode : CLOSE
4841 * @param array $param
4842 * @return boolean
4844 protected function _tag_close_FORM($param)
4846 $this->_isInForm = false;
4847 $this->parsingCss->load();
4848 $this->parsingCss->fontSet();
4850 return true;
4854 * tag : TABLE
4855 * mode : OPEN
4857 * @param array $param
4858 * @return boolean
4860 protected function _tag_open_TABLE($param, $other = 'table')
4862 if ($this->_maxH) {
4863 if ($this->_isForOneLine) return false;
4864 $this->_tag_open_BR(array());
4867 if ($this->_isForOneLine) {
4868 $this->_maxX = $this->pdf->getW() - $this->pdf->getlMargin() - $this->pdf->getrMargin();
4869 return false;
4872 $this->_maxH = 0;
4874 $alignObject = isset($param['align']) ? strtolower($param['align']) : 'left';
4875 if (isset($param['align'])) unset($param['align']);
4876 if (!in_array($alignObject, array('left', 'center', 'right'))) $alignObject = 'left';
4878 $this->parsingCss->save();
4879 $this->parsingCss->analyse($other, $param);
4880 $this->parsingCss->setPosition();
4881 $this->parsingCss->fontSet();
4883 if ($this->parsingCss->value['margin-auto']) $alignObject = 'center';
4885 // collapse table ?
4886 $collapse = false;
4887 if ($other=='table') {
4888 $collapse = isset($this->parsingCss->value['border']['collapse']) ? $this->parsingCss->value['border']['collapse'] : false;
4891 // if collapse => no borders for the table, only for TD
4892 if ($collapse) {
4893 $param['style']['border'] = 'none';
4894 $param['cellspacing'] = 0;
4895 $none = $this->parsingCss->readBorder('none');
4896 $this->parsingCss->value['border']['t'] = $none;
4897 $this->parsingCss->value['border']['r'] = $none;
4898 $this->parsingCss->value['border']['b'] = $none;
4899 $this->parsingCss->value['border']['l'] = $none;
4902 // if we are in a SUB html => prepare the properties of the table
4903 if ($this->_subPart) {
4904 if ($this->_debugActif) $this->_DEBUG_add('Table n'.$param['num'], true);
4905 HTML2PDF::$_tables[$param['num']] = array();
4906 HTML2PDF::$_tables[$param['num']]['border'] = isset($param['border']) ? $this->parsingCss->readBorder($param['border']) : null;
4907 HTML2PDF::$_tables[$param['num']]['cellpadding'] = $this->parsingCss->ConvertToMM(isset($param['cellpadding']) ? $param['cellpadding'] : '1px');
4908 HTML2PDF::$_tables[$param['num']]['cellspacing'] = $this->parsingCss->ConvertToMM(isset($param['cellspacing']) ? $param['cellspacing'] : '2px');
4909 HTML2PDF::$_tables[$param['num']]['cases'] = array(); // properties of each TR/TD
4910 HTML2PDF::$_tables[$param['num']]['corr'] = array(); // link between TR/TD and colspan/rowspan
4911 HTML2PDF::$_tables[$param['num']]['corr_x'] = 0; // position in 'cases'
4912 HTML2PDF::$_tables[$param['num']]['corr_y'] = 0; // position in 'cases'
4913 HTML2PDF::$_tables[$param['num']]['td_curr'] = 0; // current column
4914 HTML2PDF::$_tables[$param['num']]['tr_curr'] = 0; // current row
4915 HTML2PDF::$_tables[$param['num']]['curr_x'] = $this->pdf->getX();
4916 HTML2PDF::$_tables[$param['num']]['curr_y'] = $this->pdf->getY();
4917 HTML2PDF::$_tables[$param['num']]['width'] = 0; // global width
4918 HTML2PDF::$_tables[$param['num']]['height'] = 0; // global height
4919 HTML2PDF::$_tables[$param['num']]['align'] = $alignObject;
4920 HTML2PDF::$_tables[$param['num']]['marge'] = array();
4921 HTML2PDF::$_tables[$param['num']]['marge']['t'] = $this->parsingCss->value['padding']['t']+$this->parsingCss->value['border']['t']['width']+HTML2PDF::$_tables[$param['num']]['cellspacing']*0.5;
4922 HTML2PDF::$_tables[$param['num']]['marge']['r'] = $this->parsingCss->value['padding']['r']+$this->parsingCss->value['border']['r']['width']+HTML2PDF::$_tables[$param['num']]['cellspacing']*0.5;
4923 HTML2PDF::$_tables[$param['num']]['marge']['b'] = $this->parsingCss->value['padding']['b']+$this->parsingCss->value['border']['b']['width']+HTML2PDF::$_tables[$param['num']]['cellspacing']*0.5;
4924 HTML2PDF::$_tables[$param['num']]['marge']['l'] = $this->parsingCss->value['padding']['l']+$this->parsingCss->value['border']['l']['width']+HTML2PDF::$_tables[$param['num']]['cellspacing']*0.5;
4925 HTML2PDF::$_tables[$param['num']]['page'] = 0; // number of pages
4926 HTML2PDF::$_tables[$param['num']]['new_page'] = true; // flag : new page for the current TR
4927 HTML2PDF::$_tables[$param['num']]['style_value'] = null; // CSS style of the table
4928 HTML2PDF::$_tables[$param['num']]['thead'] = array(); // properties on the thead
4929 HTML2PDF::$_tables[$param['num']]['tfoot'] = array(); // properties on the tfoot
4930 HTML2PDF::$_tables[$param['num']]['thead']['tr'] = array(); // list of the TRs in the thead
4931 HTML2PDF::$_tables[$param['num']]['tfoot']['tr'] = array(); // list of the TRs in the tfoot
4932 HTML2PDF::$_tables[$param['num']]['thead']['height'] = 0; // thead height
4933 HTML2PDF::$_tables[$param['num']]['tfoot']['height'] = 0; // tfoot height
4934 HTML2PDF::$_tables[$param['num']]['thead']['code'] = array(); // HTML content of the thead
4935 HTML2PDF::$_tables[$param['num']]['tfoot']['code'] = array(); // HTML content of the tfoot
4936 HTML2PDF::$_tables[$param['num']]['cols'] = array(); // properties of the COLs
4938 $this->_saveMargin($this->pdf->getlMargin(), $this->pdf->gettMargin(), $this->pdf->getrMargin());
4940 $this->parsingCss->value['width']-= HTML2PDF::$_tables[$param['num']]['marge']['l'] + HTML2PDF::$_tables[$param['num']]['marge']['r'];
4941 } else {
4942 // we start from the first page and the first page of the table
4943 HTML2PDF::$_tables[$param['num']]['page'] = 0;
4944 HTML2PDF::$_tables[$param['num']]['td_curr'] = 0;
4945 HTML2PDF::$_tables[$param['num']]['tr_curr'] = 0;
4946 HTML2PDF::$_tables[$param['num']]['td_x'] = HTML2PDF::$_tables[$param['num']]['marge']['l']+HTML2PDF::$_tables[$param['num']]['curr_x'];
4947 HTML2PDF::$_tables[$param['num']]['td_y'] = HTML2PDF::$_tables[$param['num']]['marge']['t']+HTML2PDF::$_tables[$param['num']]['curr_y'];
4949 // draw the borders/background of the first page/part of the table
4950 $this->_drawRectangle(
4951 HTML2PDF::$_tables[$param['num']]['curr_x'],
4952 HTML2PDF::$_tables[$param['num']]['curr_y'],
4953 HTML2PDF::$_tables[$param['num']]['width'],
4954 isset(HTML2PDF::$_tables[$param['num']]['height'][0]) ? HTML2PDF::$_tables[$param['num']]['height'][0] : null,
4955 $this->parsingCss->value['border'],
4956 $this->parsingCss->value['padding'],
4958 $this->parsingCss->value['background']
4961 HTML2PDF::$_tables[$param['num']]['style_value'] = $this->parsingCss->value;
4964 return true;
4968 * tag : TABLE
4969 * mode : CLOSE
4971 * @param array $param
4972 * @return boolean
4974 protected function _tag_close_TABLE($param)
4976 if ($this->_isForOneLine) return false;
4978 $this->_maxH = 0;
4980 // if we are in a sub HTML
4981 if ($this->_subPart) {
4982 // calculate the size of each case
4983 $this->_calculateTableCellSize(HTML2PDF::$_tables[$param['num']]['cases'], HTML2PDF::$_tables[$param['num']]['corr']);
4985 // calculate the height of the thead and the tfoot
4986 $lst = array('thead', 'tfoot');
4987 foreach ($lst as $mode) {
4988 HTML2PDF::$_tables[$param['num']][$mode]['height'] = 0;
4989 foreach (HTML2PDF::$_tables[$param['num']][$mode]['tr'] as $tr) {
4990 // hauteur de la ligne tr
4991 $h = 0;
4992 for ($i=0; $i<count(HTML2PDF::$_tables[$param['num']]['cases'][$tr]); $i++)
4993 if (HTML2PDF::$_tables[$param['num']]['cases'][$tr][$i]['rowspan']==1)
4994 $h = max($h, HTML2PDF::$_tables[$param['num']]['cases'][$tr][$i]['h']);
4995 HTML2PDF::$_tables[$param['num']][$mode]['height']+= $h;
4999 // calculate the width of the table
5000 HTML2PDF::$_tables[$param['num']]['width'] = HTML2PDF::$_tables[$param['num']]['marge']['l'] + HTML2PDF::$_tables[$param['num']]['marge']['r'];
5001 if (isset(HTML2PDF::$_tables[$param['num']]['cases'][0])) {
5002 foreach (HTML2PDF::$_tables[$param['num']]['cases'][0] as $case) {
5003 HTML2PDF::$_tables[$param['num']]['width']+= $case['w'];
5007 // X position of the table
5008 $old = $this->parsingCss->getOldValues();
5009 $parentWidth = $old['width'] ? $old['width'] : $this->pdf->getW() - $this->pdf->getlMargin() - $this->pdf->getrMargin();
5010 $x = HTML2PDF::$_tables[$param['num']]['curr_x'];
5011 $w = HTML2PDF::$_tables[$param['num']]['width'];
5012 if ($parentWidth>$w) {
5013 if (HTML2PDF::$_tables[$param['num']]['align']=='center')
5014 $x = $x + ($parentWidth-$w)*0.5;
5015 else if (HTML2PDF::$_tables[$param['num']]['align']=='right')
5016 $x = $x + $parentWidth-$w;
5018 HTML2PDF::$_tables[$param['num']]['curr_x'] = $x;
5021 // calculate the height of the table
5022 HTML2PDF::$_tables[$param['num']]['height'] = array();
5024 // minimum of the height because of margins, and of the thead and tfoot height
5025 $h0 = HTML2PDF::$_tables[$param['num']]['marge']['t'] + HTML2PDF::$_tables[$param['num']]['marge']['b'];
5026 $h0+= HTML2PDF::$_tables[$param['num']]['thead']['height'] + HTML2PDF::$_tables[$param['num']]['tfoot']['height'];
5028 // max height of the page
5029 $max = $this->pdf->getH() - $this->pdf->getbMargin();
5031 // current position on the page
5032 $y = HTML2PDF::$_tables[$param['num']]['curr_y'];
5033 $height = $h0;
5035 // we get the height of each line
5036 for ($k=0; $k<count(HTML2PDF::$_tables[$param['num']]['cases']); $k++) {
5038 // if it is a TR of the thead or of the tfoot => skip
5039 if (in_array($k, HTML2PDF::$_tables[$param['num']]['thead']['tr'])) continue;
5040 if (in_array($k, HTML2PDF::$_tables[$param['num']]['tfoot']['tr'])) continue;
5042 // height of the line
5043 $th = 0;
5044 $h = 0;
5045 for ($i=0; $i<count(HTML2PDF::$_tables[$param['num']]['cases'][$k]); $i++) {
5046 $h = max($h, HTML2PDF::$_tables[$param['num']]['cases'][$k][$i]['h']);
5048 if (HTML2PDF::$_tables[$param['num']]['cases'][$k][$i]['rowspan']==1)
5049 $th = max($th, HTML2PDF::$_tables[$param['num']]['cases'][$k][$i]['h']);
5052 // if the row does not fit on the page => new page
5053 if ($y+$h+$height>$max) {
5054 if ($height==$h0) $height = null;
5055 HTML2PDF::$_tables[$param['num']]['height'][] = $height;
5056 $height = $h0;
5057 $y = $this->_margeTop;
5059 $height+= $th;
5062 // if ther is a height at the end, add it
5063 if ($height!=$h0 || $k==0) HTML2PDF::$_tables[$param['num']]['height'][] = $height;
5064 } else {
5065 // if we have tfoor, draw it
5066 if (count(HTML2PDF::$_tables[$param['num']]['tfoot']['code'])) {
5067 $tmpTR = HTML2PDF::$_tables[$param['num']]['tr_curr'];
5068 $tmpTD = HTML2PDF::$_tables[$param['num']]['td_curr'];
5069 $oldParsePos = $this->_parsePos;
5070 $oldParseCode = $this->parsingHtml->code;
5072 HTML2PDF::$_tables[$param['num']]['tr_curr'] = HTML2PDF::$_tables[$param['num']]['tfoot']['tr'][0];
5073 HTML2PDF::$_tables[$param['num']]['td_curr'] = 0;
5074 $this->_parsePos = 0;
5075 $this->parsingHtml->code = HTML2PDF::$_tables[$param['num']]['tfoot']['code'];
5076 $this->_isInTfoot = true;
5077 $this->_makeHTMLcode();
5078 $this->_isInTfoot = false;
5080 $this->_parsePos = $oldParsePos;
5081 $this->parsingHtml->code = $oldParseCode;
5082 HTML2PDF::$_tables[$param['num']]['tr_curr'] = $tmpTR;
5083 HTML2PDF::$_tables[$param['num']]['td_curr'] = $tmpTD;
5086 // get the positions of the end of the table
5087 $x = HTML2PDF::$_tables[$param['num']]['curr_x'] + HTML2PDF::$_tables[$param['num']]['width'];
5088 if (count(HTML2PDF::$_tables[$param['num']]['height'])>1)
5089 $y = $this->_margeTop+HTML2PDF::$_tables[$param['num']]['height'][count(HTML2PDF::$_tables[$param['num']]['height'])-1];
5090 else if (count(HTML2PDF::$_tables[$param['num']]['height'])==1)
5091 $y = HTML2PDF::$_tables[$param['num']]['curr_y']+HTML2PDF::$_tables[$param['num']]['height'][count(HTML2PDF::$_tables[$param['num']]['height'])-1];
5092 else
5093 $y = HTML2PDF::$_tables[$param['num']]['curr_y'];
5095 $this->_maxX = max($this->_maxX, $x);
5096 $this->_maxY = max($this->_maxY, $y);
5098 $this->pdf->setXY($this->pdf->getlMargin(), $y);
5100 $this->_loadMargin();
5102 if ($this->_debugActif) $this->_DEBUG_add('Table '.$param['num'], false);
5105 $this->parsingCss->load();
5106 $this->parsingCss->fontSet();
5109 return true;
5113 * tag : COL
5114 * mode : OPEN
5116 * @param array $param
5117 * @return boolean
5119 protected function _tag_open_COL($param)
5121 $span = isset($param['span']) ? $param['span'] : 1;
5122 for ($k=0; $k<$span; $k++)
5123 HTML2PDF::$_tables[$param['num']]['cols'][] = $param;
5127 * tag : COL
5128 * mode : CLOSE
5130 * @param array $param
5131 * @return boolean
5133 protected function _tag_close_COL($param)
5135 // there is nothing to do here
5137 return true;
5141 * tag : TR
5142 * mode : OPEN
5144 * @param array $param
5145 * @return boolean
5147 protected function _tag_open_TR($param, $other = 'tr')
5149 if ($this->_isForOneLine) return false;
5151 $this->_maxH = 0;
5153 $this->parsingCss->save();
5154 $this->parsingCss->analyse($other, $param);
5155 $this->parsingCss->setPosition();
5156 $this->parsingCss->fontSet();
5158 // position in the table
5159 HTML2PDF::$_tables[$param['num']]['tr_curr']++;
5160 HTML2PDF::$_tables[$param['num']]['td_curr']= 0;
5162 // if we are not in a sub html
5163 if (!$this->_subPart) {
5165 // Y after the row
5166 $ty=null;
5167 for ($ii=0; $ii<count(HTML2PDF::$_tables[$param['num']]['cases'][HTML2PDF::$_tables[$param['num']]['tr_curr']-1]); $ii++) {
5168 $ty = max($ty, HTML2PDF::$_tables[$param['num']]['cases'][HTML2PDF::$_tables[$param['num']]['tr_curr']-1][$ii]['h']);
5171 // height of the tfoot
5172 $hfoot = HTML2PDF::$_tables[$param['num']]['tfoot']['height'];
5174 // if the line does not fit on the page => new page
5175 if (!$this->_isInTfoot && HTML2PDF::$_tables[$param['num']]['td_y'] + HTML2PDF::$_tables[$param['num']]['marge']['b'] + $ty +$hfoot> $this->pdf->getH() - $this->pdf->getbMargin()) {
5177 // fi ther is a tfoot => draw it
5178 if (count(HTML2PDF::$_tables[$param['num']]['tfoot']['code'])) {
5179 $tmpTR = HTML2PDF::$_tables[$param['num']]['tr_curr'];
5180 $tmpTD = HTML2PDF::$_tables[$param['num']]['td_curr'];
5181 $oldParsePos = $this->_parsePos;
5182 $oldParseCode = $this->parsingHtml->code;
5184 HTML2PDF::$_tables[$param['num']]['tr_curr'] = HTML2PDF::$_tables[$param['num']]['tfoot']['tr'][0];
5185 HTML2PDF::$_tables[$param['num']]['td_curr'] = 0;
5186 $this->_parsePos = 0;
5187 $this->parsingHtml->code = HTML2PDF::$_tables[$param['num']]['tfoot']['code'];
5188 $this->_isInTfoot = true;
5189 $this->_makeHTMLcode();
5190 $this->_isInTfoot = false;
5192 $this->_parsePos = $oldParsePos;
5193 $this->parsingHtml->code = $oldParseCode;
5194 HTML2PDF::$_tables[$param['num']]['tr_curr'] = $tmpTR;
5195 HTML2PDF::$_tables[$param['num']]['td_curr'] = $tmpTD;
5198 // new page
5199 HTML2PDF::$_tables[$param['num']]['new_page'] = true;
5200 $this->_setNewPage();
5202 // new position
5203 HTML2PDF::$_tables[$param['num']]['page']++;
5204 HTML2PDF::$_tables[$param['num']]['curr_y'] = $this->pdf->getY();
5205 HTML2PDF::$_tables[$param['num']]['td_y'] = HTML2PDF::$_tables[$param['num']]['curr_y']+HTML2PDF::$_tables[$param['num']]['marge']['t'];
5207 // if we have the height of the tbale on the page => draw borders and background
5208 if (isset(HTML2PDF::$_tables[$param['num']]['height'][HTML2PDF::$_tables[$param['num']]['page']])) {
5209 $old = $this->parsingCss->value;
5210 $this->parsingCss->value = HTML2PDF::$_tables[$param['num']]['style_value'];
5212 $this->_drawRectangle(
5213 HTML2PDF::$_tables[$param['num']]['curr_x'],
5214 HTML2PDF::$_tables[$param['num']]['curr_y'],
5215 HTML2PDF::$_tables[$param['num']]['width'],
5216 HTML2PDF::$_tables[$param['num']]['height'][HTML2PDF::$_tables[$param['num']]['page']],
5217 $this->parsingCss->value['border'],
5218 $this->parsingCss->value['padding'],
5219 HTML2PDF::$_tables[$param['num']]['cellspacing']*0.5,
5220 $this->parsingCss->value['background']
5223 $this->parsingCss->value = $old;
5227 // if we are in a new page, and if we have a thead => draw it
5228 if (HTML2PDF::$_tables[$param['num']]['new_page'] && count(HTML2PDF::$_tables[$param['num']]['thead']['code'])) {
5229 HTML2PDF::$_tables[$param['num']]['new_page'] = false;
5230 $tmpTR = HTML2PDF::$_tables[$param['num']]['tr_curr'];
5231 $tmpTD = HTML2PDF::$_tables[$param['num']]['td_curr'];
5232 $oldParsePos = $this->_parsePos;
5233 $oldParseCode = $this->parsingHtml->code;
5235 HTML2PDF::$_tables[$param['num']]['tr_curr'] = HTML2PDF::$_tables[$param['num']]['thead']['tr'][0];
5236 HTML2PDF::$_tables[$param['num']]['td_curr'] = 0;
5237 $this->_parsePos = 0;
5238 $this->parsingHtml->code = HTML2PDF::$_tables[$param['num']]['thead']['code'];
5239 $this->_isInThead = true;
5240 $this->_makeHTMLcode();
5241 $this->_isInThead = false;
5243 $this->_parsePos = $oldParsePos;
5244 $this->parsingHtml->code = $oldParseCode;
5245 HTML2PDF::$_tables[$param['num']]['tr_curr'] = $tmpTR;
5246 HTML2PDF::$_tables[$param['num']]['td_curr'] = $tmpTD;
5247 HTML2PDF::$_tables[$param['num']]['new_page'] = true;
5249 // else (in a sub HTML)
5250 } else {
5251 // prepare it
5252 HTML2PDF::$_tables[$param['num']]['cases'][HTML2PDF::$_tables[$param['num']]['tr_curr']-1] = array();
5253 if (!isset(HTML2PDF::$_tables[$param['num']]['corr'][HTML2PDF::$_tables[$param['num']]['corr_y']]))
5254 HTML2PDF::$_tables[$param['num']]['corr'][HTML2PDF::$_tables[$param['num']]['corr_y']] = array();
5256 HTML2PDF::$_tables[$param['num']]['corr_x']=0;
5257 while(isset(HTML2PDF::$_tables[$param['num']]['corr'][HTML2PDF::$_tables[$param['num']]['corr_y']][HTML2PDF::$_tables[$param['num']]['corr_x']]))
5258 HTML2PDF::$_tables[$param['num']]['corr_x']++;
5261 return true;
5265 * tag : TR
5266 * mode : CLOSE
5268 * @param array $param
5269 * @return boolean
5271 protected function _tag_close_TR($param)
5273 if ($this->_isForOneLine) return false;
5275 $this->_maxH = 0;
5277 $this->parsingCss->load();
5278 $this->parsingCss->fontSet();
5280 // if we are not in a sub HTML
5281 if (!$this->_subPart) {
5283 // Y of the current line
5284 $ty=null;
5285 for ($ii=0; $ii<count(HTML2PDF::$_tables[$param['num']]['cases'][HTML2PDF::$_tables[$param['num']]['tr_curr']-1]); $ii++) {
5286 if (HTML2PDF::$_tables[$param['num']]['cases'][HTML2PDF::$_tables[$param['num']]['tr_curr']-1][$ii]['rowspan']==1) {
5287 $ty = HTML2PDF::$_tables[$param['num']]['cases'][HTML2PDF::$_tables[$param['num']]['tr_curr']-1][$ii]['h'];
5291 // new position
5292 HTML2PDF::$_tables[$param['num']]['td_x'] = HTML2PDF::$_tables[$param['num']]['curr_x']+HTML2PDF::$_tables[$param['num']]['marge']['l'];
5293 HTML2PDF::$_tables[$param['num']]['td_y']+= $ty;
5294 HTML2PDF::$_tables[$param['num']]['new_page'] = false;
5295 } else {
5296 HTML2PDF::$_tables[$param['num']]['corr_y']++;
5299 return true;
5303 * tag : TD
5304 * mode : OPEN
5306 * @param array $param
5307 * @param string $other
5309 * @return boolean
5310 * @throws HTML2PDF_exception
5312 protected function _tag_open_TD($param, $other = 'td')
5314 if ($this->_isForOneLine) return false;
5316 $this->_maxH = 0;
5318 $param['cellpadding'] = HTML2PDF::$_tables[$param['num']]['cellpadding'].'mm';
5319 $param['cellspacing'] = HTML2PDF::$_tables[$param['num']]['cellspacing'].'mm';
5321 // specific style for LI
5322 if ($other=='li') {
5323 $specialLi = true;
5324 } else {
5325 $specialLi = false;
5326 if ($other=='li_sub') {
5327 $param['style']['border'] = 'none';
5328 $param['style']['background-color'] = 'transparent';
5329 $param['style']['background-image'] = 'none';
5330 $param['style']['background-position'] = '';
5331 $param['style']['background-repeat'] = '';
5332 $other = 'li';
5336 // get the properties of the TD
5337 $x = HTML2PDF::$_tables[$param['num']]['td_curr'];
5338 $y = HTML2PDF::$_tables[$param['num']]['tr_curr']-1;
5339 $colspan = isset($param['colspan']) ? $param['colspan'] : 1;
5340 $rowspan = isset($param['rowspan']) ? $param['rowspan'] : 1;
5342 // flag for collapse table
5343 $collapse = false;
5345 // specific treatment for TD and TH
5346 if (in_array($other, array('td', 'th'))) {
5347 // id of the column
5348 $numCol = isset(HTML2PDF::$_tables[$param['num']]['cases'][$y][$x]['Xr']) ? HTML2PDF::$_tables[$param['num']]['cases'][$y][$x]['Xr'] : HTML2PDF::$_tables[$param['num']]['corr_x'];
5350 // we get the properties of the COL tag, if exist
5351 if (isset(HTML2PDF::$_tables[$param['num']]['cols'][$numCol])) {
5353 $colParam = HTML2PDF::$_tables[$param['num']]['cols'][$numCol];
5355 // for colspans => we get all the needed widths
5356 $colParam['style']['width'] = array();
5357 for ($k=0; $k<$colspan; $k++) {
5358 if (isset(HTML2PDF::$_tables[$param['num']]['cols'][$numCol+$k]['style']['width'])) {
5359 $colParam['style']['width'][] = HTML2PDF::$_tables[$param['num']]['cols'][$numCol+$k]['style']['width'];
5363 // calculate the total width of the column
5364 $total = '';
5365 $last = $this->parsingCss->getLastWidth();
5366 if (count($colParam['style']['width'])) {
5367 $total = $colParam['style']['width'][0]; unset($colParam['style']['width'][0]);
5368 foreach ($colParam['style']['width'] as $width) {
5369 if (substr($total, -1)=='%' && substr($width, -1)=='%')
5370 $total = (str_replace('%', '', $total)+str_replace('%', '', $width)).'%';
5371 else
5372 $total = ($this->parsingCss->ConvertToMM($total, $last) + $this->parsingCss->ConvertToMM($width, $last)).'mm';
5376 // get the final width
5377 if ($total) {
5378 $colParam['style']['width'] = $total;
5379 } else {
5380 unset($colParam['style']['width']);
5384 // merge the styles of the COL and the TD
5385 $param['style'] = array_merge($colParam['style'], $param['style']);
5387 // merge the class of the COL and the TD
5388 if (isset($colParam['class'])) {
5389 $param['class'] = $colParam['class'].(isset($param['class']) ? ' '.$param['class'] : '');
5393 $collapse = isset($this->parsingCss->value['border']['collapse']) ? $this->parsingCss->value['border']['collapse'] : false;
5396 $this->parsingCss->save();
5398 // legacy for TD and TH
5399 $legacy = null;
5400 if (in_array($other, array('td', 'th'))) {
5401 $legacy = array();
5403 $old = $this->parsingCss->getLastValue('background');
5404 if ($old && ($old['color'] || $old['image']))
5405 $legacy['background'] = $old;
5407 if (HTML2PDF::$_tables[$param['num']]['border']) {
5408 $legacy['border'] = array();
5409 $legacy['border']['l'] = HTML2PDF::$_tables[$param['num']]['border'];
5410 $legacy['border']['t'] = HTML2PDF::$_tables[$param['num']]['border'];
5411 $legacy['border']['r'] = HTML2PDF::$_tables[$param['num']]['border'];
5412 $legacy['border']['b'] = HTML2PDF::$_tables[$param['num']]['border'];
5415 $return = $this->parsingCss->analyse($other, $param, $legacy);
5417 if ($specialLi) {
5418 $this->parsingCss->value['width']-= $this->parsingCss->ConvertToMM($this->_listeGetWidth());
5419 $this->parsingCss->value['width']-= $this->parsingCss->ConvertToMM($this->_listeGetPadding());
5421 $this->parsingCss->setPosition();
5422 $this->parsingCss->fontSet();
5424 // if table collapse => modify the borders
5425 if ($collapse) {
5426 if (!$this->_subPart) {
5427 if (
5428 (HTML2PDF::$_tables[$param['num']]['tr_curr']>1 && !HTML2PDF::$_tables[$param['num']]['new_page']) ||
5429 (!$this->_isInThead && count(HTML2PDF::$_tables[$param['num']]['thead']['code']))
5431 $this->parsingCss->value['border']['t'] = $this->parsingCss->readBorder('none');
5435 if (HTML2PDF::$_tables[$param['num']]['td_curr']>0) {
5436 if (!$return) $this->parsingCss->value['width']+= $this->parsingCss->value['border']['l']['width'];
5437 $this->parsingCss->value['border']['l'] = $this->parsingCss->readBorder('none');
5441 // margins of the table
5442 $marge = array();
5443 $marge['t'] = $this->parsingCss->value['padding']['t']+0.5*HTML2PDF::$_tables[$param['num']]['cellspacing']+$this->parsingCss->value['border']['t']['width'];
5444 $marge['r'] = $this->parsingCss->value['padding']['r']+0.5*HTML2PDF::$_tables[$param['num']]['cellspacing']+$this->parsingCss->value['border']['r']['width'];
5445 $marge['b'] = $this->parsingCss->value['padding']['b']+0.5*HTML2PDF::$_tables[$param['num']]['cellspacing']+$this->parsingCss->value['border']['b']['width'];
5446 $marge['l'] = $this->parsingCss->value['padding']['l']+0.5*HTML2PDF::$_tables[$param['num']]['cellspacing']+$this->parsingCss->value['border']['l']['width'];
5448 // if we are in a sub HTML
5449 if ($this->_subPart) {
5450 // new position in the table
5451 HTML2PDF::$_tables[$param['num']]['td_curr']++;
5452 HTML2PDF::$_tables[$param['num']]['cases'][$y][$x] = array();
5453 HTML2PDF::$_tables[$param['num']]['cases'][$y][$x]['w'] = 0;
5454 HTML2PDF::$_tables[$param['num']]['cases'][$y][$x]['h'] = 0;
5455 HTML2PDF::$_tables[$param['num']]['cases'][$y][$x]['dw'] = 0;
5456 HTML2PDF::$_tables[$param['num']]['cases'][$y][$x]['colspan'] = $colspan;
5457 HTML2PDF::$_tables[$param['num']]['cases'][$y][$x]['rowspan'] = $rowspan;
5458 HTML2PDF::$_tables[$param['num']]['cases'][$y][$x]['Xr'] = HTML2PDF::$_tables[$param['num']]['corr_x'];
5459 HTML2PDF::$_tables[$param['num']]['cases'][$y][$x]['Yr'] = HTML2PDF::$_tables[$param['num']]['corr_y'];
5461 // prepare the mapping for rowspan and colspan
5462 for ($j=0; $j<$rowspan; $j++) {
5463 for ($i=0; $i<$colspan; $i++) {
5464 HTML2PDF::$_tables[$param['num']]['corr']
5465 [HTML2PDF::$_tables[$param['num']]['corr_y']+$j]
5466 [HTML2PDF::$_tables[$param['num']]['corr_x']+$i] = ($i+$j>0) ? '' : array($x,$y,$colspan,$rowspan);
5469 HTML2PDF::$_tables[$param['num']]['corr_x']+= $colspan;
5470 while (isset(HTML2PDF::$_tables[$param['num']]['corr'][HTML2PDF::$_tables[$param['num']]['corr_y']][HTML2PDF::$_tables[$param['num']]['corr_x']])) {
5471 HTML2PDF::$_tables[$param['num']]['corr_x']++;
5474 // extract the content of the TD, and calculate his size
5475 $level = $this->parsingHtml->getLevel($this->_tempPos);
5476 $this->_createSubHTML($this->_subHtml);
5477 $this->_subHtml->parsingHtml->code = $level;
5478 $this->_subHtml->_makeHTMLcode();
5479 $this->_tempPos+= count($level);
5480 } else {
5481 // new position in the table
5482 HTML2PDF::$_tables[$param['num']]['td_curr']++;
5483 HTML2PDF::$_tables[$param['num']]['td_x']+= HTML2PDF::$_tables[$param['num']]['cases'][$y][$x]['dw'];
5485 // borders and background of the TD
5486 $this->_drawRectangle(
5487 HTML2PDF::$_tables[$param['num']]['td_x'],
5488 HTML2PDF::$_tables[$param['num']]['td_y'],
5489 HTML2PDF::$_tables[$param['num']]['cases'][$y][$x]['w'],
5490 HTML2PDF::$_tables[$param['num']]['cases'][$y][$x]['h'],
5491 $this->parsingCss->value['border'],
5492 $this->parsingCss->value['padding'],
5493 HTML2PDF::$_tables[$param['num']]['cellspacing']*0.5,
5494 $this->parsingCss->value['background']
5497 $this->parsingCss->value['width'] = HTML2PDF::$_tables[$param['num']]['cases'][$y][$x]['w'] - $marge['l'] - $marge['r'];
5499 // marges = size of the TD
5500 $mL = HTML2PDF::$_tables[$param['num']]['td_x']+$marge['l'];
5501 $mR = $this->pdf->getW() - $mL - $this->parsingCss->value['width'];
5502 $this->_saveMargin($mL, 0, $mR);
5504 // position of the content, from vertical-align
5505 $hCorr = HTML2PDF::$_tables[$param['num']]['cases'][$y][$x]['h'];
5506 $hReel = HTML2PDF::$_tables[$param['num']]['cases'][$y][$x]['real_h'];
5507 switch($this->parsingCss->value['vertical-align'])
5509 case 'bottom':
5510 $yCorr = $hCorr-$hReel;
5511 break;
5513 case 'middle':
5514 $yCorr = ($hCorr-$hReel)*0.5;
5515 break;
5517 case 'top':
5518 default:
5519 $yCorr = 0;
5520 break;
5523 // position of the content
5524 $x = HTML2PDF::$_tables[$param['num']]['td_x']+$marge['l'];
5525 $y = HTML2PDF::$_tables[$param['num']]['td_y']+$marge['t']+$yCorr;
5526 $this->pdf->setXY($x, $y);
5527 $this->_setNewPositionForNewLine();
5530 return true;
5534 * tag : TD
5535 * mode : CLOSE
5537 * @param array $param
5538 * @return boolean
5540 protected function _tag_close_TD($param)
5542 if ($this->_isForOneLine) return false;
5544 $this->_maxH = 0;
5546 // get the margins
5547 $marge = array();
5548 $marge['t'] = $this->parsingCss->value['padding']['t']+0.5*HTML2PDF::$_tables[$param['num']]['cellspacing']+$this->parsingCss->value['border']['t']['width'];
5549 $marge['r'] = $this->parsingCss->value['padding']['r']+0.5*HTML2PDF::$_tables[$param['num']]['cellspacing']+$this->parsingCss->value['border']['r']['width'];
5550 $marge['b'] = $this->parsingCss->value['padding']['b']+0.5*HTML2PDF::$_tables[$param['num']]['cellspacing']+$this->parsingCss->value['border']['b']['width'];
5551 $marge['l'] = $this->parsingCss->value['padding']['l']+0.5*HTML2PDF::$_tables[$param['num']]['cellspacing']+$this->parsingCss->value['border']['l']['width'];
5552 $marge['t']+= 0.001;
5553 $marge['r']+= 0.001;
5554 $marge['b']+= 0.001;
5555 $marge['l']+= 0.001;
5557 // if we are in a sub HTML
5558 if ($this->_subPart) {
5560 // it msut take only one page
5561 if ($this->_testTdInOnepage && $this->_subHtml->pdf->getPage()>1) {
5562 throw new HTML2PDF_exception(7);
5565 // size of the content of the TD
5566 $w0 = $this->_subHtml->_maxX + $marge['l'] + $marge['r'];
5567 $h0 = $this->_subHtml->_maxY + $marge['t'] + $marge['b'];
5569 // size from the CSS style
5570 $w2 = $this->parsingCss->value['width'] + $marge['l'] + $marge['r'];
5571 $h2 = $this->parsingCss->value['height'] + $marge['t'] + $marge['b'];
5573 // final size of the TD
5574 HTML2PDF::$_tables[$param['num']]['cases'][HTML2PDF::$_tables[$param['num']]['tr_curr']-1][HTML2PDF::$_tables[$param['num']]['td_curr']-1]['w'] = max(array($w0, $w2));
5575 HTML2PDF::$_tables[$param['num']]['cases'][HTML2PDF::$_tables[$param['num']]['tr_curr']-1][HTML2PDF::$_tables[$param['num']]['td_curr']-1]['h'] = max(array($h0, $h2));
5577 // real position of the content
5578 HTML2PDF::$_tables[$param['num']]['cases'][HTML2PDF::$_tables[$param['num']]['tr_curr']-1][HTML2PDF::$_tables[$param['num']]['td_curr']-1]['real_w'] = $w0;
5579 HTML2PDF::$_tables[$param['num']]['cases'][HTML2PDF::$_tables[$param['num']]['tr_curr']-1][HTML2PDF::$_tables[$param['num']]['td_curr']-1]['real_h'] = $h0;
5581 // destroy the sub HTML
5582 $this->_destroySubHTML($this->_subHtml);
5583 } else {
5584 $this->_loadMargin();
5586 HTML2PDF::$_tables[$param['num']]['td_x']+= HTML2PDF::$_tables[$param['num']]['cases'][HTML2PDF::$_tables[$param['num']]['tr_curr']-1][HTML2PDF::$_tables[$param['num']]['td_curr']-1]['w'];
5589 $this->parsingCss->load();
5590 $this->parsingCss->fontSet();
5592 return true;
5597 * tag : TH
5598 * mode : OPEN
5600 * @param array $param
5601 * @return boolean
5603 protected function _tag_open_TH($param)
5605 if ($this->_isForOneLine) return false;
5607 $this->parsingCss->save();
5608 $this->parsingCss->value['font-bold'] = true;
5610 $this->_tag_open_TD($param, 'th');
5612 return true;
5616 * tag : TH
5617 * mode : CLOSE
5619 * @param array $param
5620 * @return boolean
5622 protected function _tag_close_TH($param)
5624 if ($this->_isForOneLine) return false;
5626 $this->_tag_close_TD($param);
5628 $this->parsingCss->load();
5630 return true;
5634 * tag : IMG
5635 * mode : OPEN
5637 * @param array $param
5638 * @return boolean
5640 protected function _tag_open_IMG($param)
5642 $src = str_replace('&amp;', '&', $param['src']);
5644 $this->parsingCss->save();
5645 $this->parsingCss->value['width'] = 0;
5646 $this->parsingCss->value['height'] = 0;
5647 $this->parsingCss->value['border'] = array('type' => 'none', 'width' => 0, 'color' => array(0, 0, 0));
5648 $this->parsingCss->value['background'] = array('color' => null, 'image' => null, 'position' => null, 'repeat' => null);
5649 $this->parsingCss->analyse('img', $param);
5650 $this->parsingCss->setPosition();
5651 $this->parsingCss->fontSet();
5653 $res = $this->_drawImage($src, isset($param['sub_li']));
5654 if (!$res) return $res;
5656 $this->parsingCss->load();
5657 $this->parsingCss->fontSet();
5658 $this->_maxE++;
5660 return true;
5664 * tag : SELECT
5665 * mode : OPEN
5667 * @param array $param
5668 * @return boolean
5670 protected function _tag_open_SELECT($param)
5672 if (!isset($param['name'])) {
5673 $param['name'] = 'champs_pdf_'.(count($this->_lstField)+1);
5676 $param['name'] = strtolower($param['name']);
5678 if (isset($this->_lstField[$param['name']])) {
5679 $this->_lstField[$param['name']]++;
5680 } else {
5681 $this->_lstField[$param['name']] = 1;
5684 $this->parsingCss->save();
5685 $this->parsingCss->analyse('select', $param);
5686 $this->parsingCss->setPosition();
5687 $this->parsingCss->fontSet();
5689 $this->_lstSelect = array();
5690 $this->_lstSelect['name'] = $param['name'];
5691 $this->_lstSelect['multi'] = isset($param['multiple']) ? true : false;
5692 $this->_lstSelect['size'] = isset($param['size']) ? $param['size'] : 1;
5693 $this->_lstSelect['options'] = array();
5695 if ($this->_lstSelect['multi'] && $this->_lstSelect['size']<3) $this->_lstSelect['size'] = 3;
5697 return true;
5701 * tag : OPTION
5702 * mode : OPEN
5704 * @param array $param
5705 * @return boolean
5707 protected function _tag_open_OPTION($param)
5709 // get the content of the option : it is the text of the option
5710 $level = $this->parsingHtml->getLevel($this->_parsePos);
5711 $this->_parsePos+= count($level);
5712 $value = isset($param['value']) ? $param['value'] : 'aut_tag_open_opt_'.(count($this->_lstSelect)+1);
5714 $this->_lstSelect['options'][$value] = isset($level[0]['param']['txt']) ? $level[0]['param']['txt'] : '';
5716 return true;
5720 * tag : OPTION
5721 * mode : CLOSE
5723 * @param array $param
5724 * @return boolean
5726 protected function _tag_close_OPTION($param)
5728 // nothing to do here
5730 return true;
5734 * tag : SELECT
5735 * mode : CLOSE
5737 * @param array $param
5738 * @return boolean
5740 protected function _tag_close_SELECT()
5742 // position of the select
5743 $x = $this->pdf->getX();
5744 $y = $this->pdf->getY();
5745 $f = 1.08*$this->parsingCss->value['font-size'];
5747 // width
5748 $w = $this->parsingCss->value['width']; if (!$w) $w = 50;
5750 // height (automatic)
5751 $h = ($f*1.07*$this->_lstSelect['size'] + 1);
5753 $prop = $this->parsingCss->getFormStyle();
5755 // multy select
5756 if ($this->_lstSelect['multi']) {
5757 $prop['multipleSelection'] = 'true';
5761 // single or multi select
5762 if ($this->_lstSelect['size']>1) {
5763 $this->pdf->ListBox($this->_lstSelect['name'], $w, $h, $this->_lstSelect['options'], $prop);
5764 } else {
5765 $this->pdf->ComboBox($this->_lstSelect['name'], $w, $h, $this->_lstSelect['options'], $prop);
5768 $this->_maxX = max($this->_maxX, $x+$w);
5769 $this->_maxY = max($this->_maxY, $y+$h);
5770 $this->_maxH = max($this->_maxH, $h);
5771 $this->_maxE++;
5772 $this->pdf->setX($x+$w);
5774 $this->parsingCss->load();
5775 $this->parsingCss->fontSet();
5777 $this->_lstSelect = array();
5779 return true;
5783 * tag : TEXTAREA
5784 * mode : OPEN
5786 * @param array $param
5787 * @return boolean
5789 protected function _tag_open_TEXTAREA($param)
5791 if (!isset($param['name'])) {
5792 $param['name'] = 'champs_pdf_'.(count($this->_lstField)+1);
5795 $param['name'] = strtolower($param['name']);
5797 if (isset($this->_lstField[$param['name']])) {
5798 $this->_lstField[$param['name']]++;
5799 } else {
5800 $this->_lstField[$param['name']] = 1;
5803 $this->parsingCss->save();
5804 $this->parsingCss->analyse('textarea', $param);
5805 $this->parsingCss->setPosition();
5806 $this->parsingCss->fontSet();
5808 $x = $this->pdf->getX();
5809 $y = $this->pdf->getY();
5810 $fx = 0.65*$this->parsingCss->value['font-size'];
5811 $fy = 1.08*$this->parsingCss->value['font-size'];
5813 // extract the content the textarea : value
5814 $level = $this->parsingHtml->getLevel($this->_parsePos);
5815 $this->_parsePos+= count($level);
5817 // automatic size, from cols and rows properties
5818 $w = $fx*(isset($param['cols']) ? $param['cols'] : 22)+1;
5819 $h = $fy*1.07*(isset($param['rows']) ? $param['rows'] : 3)+3;
5821 $prop = $this->parsingCss->getFormStyle();
5823 $prop['multiline'] = true;
5824 $prop['value'] = isset($level[0]['param']['txt']) ? $level[0]['param']['txt'] : '';
5826 $this->pdf->TextField($param['name'], $w, $h, $prop, array(), $x, $y);
5828 $this->_maxX = max($this->_maxX, $x+$w);
5829 $this->_maxY = max($this->_maxY, $y+$h);
5830 $this->_maxH = max($this->_maxH, $h);
5831 $this->_maxE++;
5832 $this->pdf->setX($x+$w);
5834 return true;
5838 * tag : TEXTAREA
5839 * mode : CLOSE
5841 * @param array $param
5842 * @return boolean
5844 protected function _tag_close_TEXTAREA()
5846 $this->parsingCss->load();
5847 $this->parsingCss->fontSet();
5849 return true;
5853 * tag : INPUT
5854 * mode : OPEN
5856 * @param array $param
5857 * @return boolean
5859 protected function _tag_open_INPUT($param)
5861 if (!isset($param['name'])) $param['name'] = 'champs_pdf_'.(count($this->_lstField)+1);
5862 if (!isset($param['value'])) $param['value'] = '';
5863 if (!isset($param['type'])) $param['type'] = 'text';
5865 $param['name'] = strtolower($param['name']);
5866 $param['type'] = strtolower($param['type']);
5868 // the type must be valid
5869 if (!in_array($param['type'], array('text', 'checkbox', 'radio', 'hidden', 'submit', 'reset', 'button'))) {
5870 $param['type'] = 'text';
5873 if (isset($this->_lstField[$param['name']])) {
5874 $this->_lstField[$param['name']]++;
5875 } else {
5876 $this->_lstField[$param['name']] = 1;
5879 $this->parsingCss->save();
5880 $this->parsingCss->analyse('input', $param);
5881 $this->parsingCss->setPosition();
5882 $this->parsingCss->fontSet();
5884 $name = $param['name'];
5886 $x = $this->pdf->getX();
5887 $y = $this->pdf->getY();
5888 $f = 1.08*$this->parsingCss->value['font-size'];
5890 $prop = $this->parsingCss->getFormStyle();
5892 switch($param['type'])
5894 case 'checkbox':
5895 $w = 3;
5896 $h = $w;
5897 if ($h<$f) $y+= ($f-$h)*0.5;
5898 $checked = (isset($param['checked']) && $param['checked']=='checked');
5899 $this->pdf->CheckBox($name, $w, $checked, $prop, array(), ($param['value'] ? $param['value'] : 'Yes'), $x, $y);
5900 break;
5902 case 'radio':
5903 $w = 3;
5904 $h = $w;
5905 if ($h<$f) $y+= ($f-$h)*0.5;
5906 $checked = (isset($param['checked']) && $param['checked']=='checked');
5907 $this->pdf->RadioButton($name, $w, $prop, array(), ($param['value'] ? $param['value'] : 'On'), $checked, $x, $y);
5908 break;
5910 case 'hidden':
5911 $w = 0;
5912 $h = 0;
5913 $prop['value'] = $param['value'];
5914 $this->pdf->TextField($name, $w, $h, $prop, array(), $x, $y);
5915 break;
5917 case 'text':
5918 $w = $this->parsingCss->value['width']; if (!$w) $w = 40;
5919 $h = $f*1.3;
5920 $prop['value'] = $param['value'];
5921 $this->pdf->TextField($name, $w, $h, $prop, array(), $x, $y);
5922 break;
5924 case 'submit':
5925 $w = $this->parsingCss->value['width']; if (!$w) $w = 40;
5926 $h = $this->parsingCss->value['height']; if (!$h) $h = $f*1.3;
5927 $action = array('S'=>'SubmitForm', 'F'=>$this->_isInForm, 'Flags'=>array('ExportFormat'));
5928 $this->pdf->Button($name, $w, $h, $param['value'], $action, $prop, array(), $x, $y);
5929 break;
5931 case 'reset':
5932 $w = $this->parsingCss->value['width']; if (!$w) $w = 40;
5933 $h = $this->parsingCss->value['height']; if (!$h) $h = $f*1.3;
5934 $action = array('S'=>'ResetForm');
5935 $this->pdf->Button($name, $w, $h, $param['value'], $action, $prop, array(), $x, $y);
5936 break;
5938 case 'button':
5939 $w = $this->parsingCss->value['width']; if (!$w) $w = 40;
5940 $h = $this->parsingCss->value['height']; if (!$h) $h = $f*1.3;
5941 $action = isset($param['onclick']) ? $param['onclick'] : '';
5942 $this->pdf->Button($name, $w, $h, $param['value'], $action, $prop, array(), $x, $y);
5943 break;
5945 default:
5946 $w = 0;
5947 $h = 0;
5948 break;
5951 $this->_maxX = max($this->_maxX, $x+$w);
5952 $this->_maxY = max($this->_maxY, $y+$h);
5953 $this->_maxH = max($this->_maxH, $h);
5954 $this->_maxE++;
5955 $this->pdf->setX($x+$w);
5957 $this->parsingCss->load();
5958 $this->parsingCss->fontSet();
5960 return true;
5964 * tag : DRAW
5965 * mode : OPEN
5967 * @param array $param
5968 * @return boolean
5970 protected function _tag_open_DRAW($param)
5972 if ($this->_isForOneLine) return false;
5973 if ($this->_debugActif) $this->_DEBUG_add('DRAW', true);
5975 $this->parsingCss->save();
5976 $this->parsingCss->analyse('draw', $param);
5977 $this->parsingCss->fontSet();
5979 $alignObject = null;
5980 if ($this->parsingCss->value['margin-auto']) $alignObject = 'center';
5982 $overW = $this->parsingCss->value['width'];
5983 $overH = $this->parsingCss->value['height'];
5984 $this->parsingCss->value['old_maxX'] = $this->_maxX;
5985 $this->parsingCss->value['old_maxY'] = $this->_maxY;
5986 $this->parsingCss->value['old_maxH'] = $this->_maxH;
5988 $w = $this->parsingCss->value['width'];
5989 $h = $this->parsingCss->value['height'];
5991 if (!$this->parsingCss->value['position']) {
5992 if (
5993 $w < ($this->pdf->getW() - $this->pdf->getlMargin()-$this->pdf->getrMargin()) &&
5994 $this->pdf->getX() + $w>=($this->pdf->getW() - $this->pdf->getrMargin())
5996 $this->_tag_open_BR(array());
5998 if (
5999 ($h < ($this->pdf->getH() - $this->pdf->gettMargin()-$this->pdf->getbMargin())) &&
6000 ($this->pdf->getY() + $h>=($this->pdf->getH() - $this->pdf->getbMargin())) &&
6001 !$this->_isInOverflow
6003 $this->_setNewPage();
6005 $old = $this->parsingCss->getOldValues();
6006 $parentWidth = $old['width'] ? $old['width'] : $this->pdf->getW() - $this->pdf->getlMargin() - $this->pdf->getrMargin();
6008 if ($parentWidth>$w) {
6009 if ($alignObject=='center') $this->pdf->setX($this->pdf->getX() + ($parentWidth-$w)*0.5);
6010 else if ($alignObject=='right') $this->pdf->setX($this->pdf->getX() + $parentWidth-$w);
6013 $this->parsingCss->setPosition();
6014 } else {
6015 $old = $this->parsingCss->getOldValues();
6016 $parentWidth = $old['width'] ? $old['width'] : $this->pdf->getW() - $this->pdf->getlMargin() - $this->pdf->getrMargin();
6018 if ($parentWidth>$w) {
6019 if ($alignObject=='center') $this->pdf->setX($this->pdf->getX() + ($parentWidth-$w)*0.5);
6020 else if ($alignObject=='right') $this->pdf->setX($this->pdf->getX() + $parentWidth-$w);
6023 $this->parsingCss->setPosition();
6024 $this->_saveMax();
6025 $this->_maxX = 0;
6026 $this->_maxY = 0;
6027 $this->_maxH = 0;
6028 $this->_maxE = 0;
6031 $this->_drawRectangle(
6032 $this->parsingCss->value['x'],
6033 $this->parsingCss->value['y'],
6034 $this->parsingCss->value['width'],
6035 $this->parsingCss->value['height'],
6036 $this->parsingCss->value['border'],
6037 $this->parsingCss->value['padding'],
6039 $this->parsingCss->value['background']
6042 $marge = array();
6043 $marge['l'] = $this->parsingCss->value['border']['l']['width'];
6044 $marge['r'] = $this->parsingCss->value['border']['r']['width'];
6045 $marge['t'] = $this->parsingCss->value['border']['t']['width'];
6046 $marge['b'] = $this->parsingCss->value['border']['b']['width'];
6048 $this->parsingCss->value['width'] -= $marge['l']+$marge['r'];
6049 $this->parsingCss->value['height']-= $marge['t']+$marge['b'];
6051 $overW-= $marge['l']+$marge['r'];
6052 $overH-= $marge['t']+$marge['b'];
6054 // clipping to draw only in the size opf the DRAW tag
6055 $this->pdf->clippingPathStart(
6056 $this->parsingCss->value['x']+$marge['l'],
6057 $this->parsingCss->value['y']+$marge['t'],
6058 $this->parsingCss->value['width'],
6059 $this->parsingCss->value['height']
6062 // left and right of the DRAW tag
6063 $mL = $this->parsingCss->value['x']+$marge['l'];
6064 $mR = $this->pdf->getW() - $mL - $overW;
6066 // position of the DRAW tag
6067 $x = $this->parsingCss->value['x']+$marge['l'];
6068 $y = $this->parsingCss->value['y']+$marge['t'];
6070 // prepare the drawing area
6071 $this->_saveMargin($mL, 0, $mR);
6072 $this->pdf->setXY($x, $y);
6074 // we are in a draw tag
6075 $this->_isInDraw = array(
6076 'x' => $x,
6077 'y' => $y,
6078 'w' => $overW,
6079 'h' => $overH,
6082 // init the translate matrix : (0,0) => ($x, $y)
6083 $this->pdf->doTransform(array(1,0,0,1,$x,$y));
6084 $this->pdf->SetAlpha(1.);
6085 return true;
6089 * tag : DRAW
6090 * mode : CLOSE
6092 * @param array $param
6093 * @return boolean
6095 protected function _tag_close_DRAW($param)
6097 if ($this->_isForOneLine) return false;
6099 $this->pdf->SetAlpha(1.);
6100 $this->pdf->undoTransform();
6101 $this->pdf->clippingPathStop();
6103 $this->_maxX = $this->parsingCss->value['old_maxX'];
6104 $this->_maxY = $this->parsingCss->value['old_maxY'];
6105 $this->_maxH = $this->parsingCss->value['old_maxH'];
6107 $marge = array();
6108 $marge['l'] = $this->parsingCss->value['border']['l']['width'];
6109 $marge['r'] = $this->parsingCss->value['border']['r']['width'];
6110 $marge['t'] = $this->parsingCss->value['border']['t']['width'];
6111 $marge['b'] = $this->parsingCss->value['border']['b']['width'];
6113 $x = $this->parsingCss->value['x'];
6114 $y = $this->parsingCss->value['y'];
6115 $w = $this->parsingCss->value['width']+$marge['l']+$marge['r'];
6116 $h = $this->parsingCss->value['height']+$marge['t']+$marge['b'];
6118 if ($this->parsingCss->value['position']!='absolute') {
6119 $this->pdf->setXY($x+$w, $y);
6121 $this->_maxX = max($this->_maxX, $x+$w);
6122 $this->_maxY = max($this->_maxY, $y+$h);
6123 $this->_maxH = max($this->_maxH, $h);
6124 $this->_maxE++;
6125 } else {
6126 // position
6127 $this->pdf->setXY($this->parsingCss->value['xc'], $this->parsingCss->value['yc']);
6129 $this->_loadMax();
6132 $block = ($this->parsingCss->value['display']!='inline' && $this->parsingCss->value['position']!='absolute');
6134 $this->parsingCss->load();
6135 $this->parsingCss->fontSet();
6136 $this->_loadMargin();
6138 if ($block) $this->_tag_open_BR(array());
6139 if ($this->_debugActif) $this->_DEBUG_add('DRAW', false);
6141 $this->_isInDraw = null;
6143 return true;
6147 * tag : LINE
6148 * mode : OPEN
6150 * @param array $param
6151 * @return boolean
6153 protected function _tag_open_LINE($param)
6155 if (!$this->_isInDraw) throw new HTML2PDF_exception(8, 'LINE');
6157 $this->pdf->doTransform(isset($param['transform']) ? $this->_prepareTransform($param['transform']) : null);
6158 $this->parsingCss->save();
6159 $styles = $this->parsingCss->getSvgStyle('path', $param);
6160 $styles['fill'] = null;
6161 $style = $this->pdf->svgSetStyle($styles);
6163 $x1 = isset($param['x1']) ? $this->parsingCss->ConvertToMM($param['x1'], $this->_isInDraw['w']) : 0.;
6164 $y1 = isset($param['y1']) ? $this->parsingCss->ConvertToMM($param['y1'], $this->_isInDraw['h']) : 0.;
6165 $x2 = isset($param['x2']) ? $this->parsingCss->ConvertToMM($param['x2'], $this->_isInDraw['w']) : 0.;
6166 $y2 = isset($param['y2']) ? $this->parsingCss->ConvertToMM($param['y2'], $this->_isInDraw['h']) : 0.;
6167 $this->pdf->svgLine($x1, $y1, $x2, $y2);
6169 $this->pdf->undoTransform();
6170 $this->parsingCss->load();
6174 * tag : RECT
6175 * mode : OPEN
6177 * @param array $param
6178 * @return boolean
6180 protected function _tag_open_RECT($param)
6182 if (!$this->_isInDraw) throw new HTML2PDF_exception(8, 'RECT');
6184 $this->pdf->doTransform(isset($param['transform']) ? $this->_prepareTransform($param['transform']) : null);
6185 $this->parsingCss->save();
6186 $styles = $this->parsingCss->getSvgStyle('path', $param);
6187 $style = $this->pdf->svgSetStyle($styles);
6189 $x = isset($param['x']) ? $this->parsingCss->ConvertToMM($param['x'], $this->_isInDraw['w']) : 0.;
6190 $y = isset($param['y']) ? $this->parsingCss->ConvertToMM($param['y'], $this->_isInDraw['h']) : 0.;
6191 $w = isset($param['w']) ? $this->parsingCss->ConvertToMM($param['w'], $this->_isInDraw['w']) : 0.;
6192 $h = isset($param['h']) ? $this->parsingCss->ConvertToMM($param['h'], $this->_isInDraw['h']) : 0.;
6194 $this->pdf->svgRect($x, $y, $w, $h, $style);
6196 $this->pdf->undoTransform();
6197 $this->parsingCss->load();
6201 * tag : CIRCLE
6202 * mode : OPEN
6204 * @param array $param
6205 * @return boolean
6207 protected function _tag_open_CIRCLE($param)
6209 if (!$this->_isInDraw) throw new HTML2PDF_exception(8, 'CIRCLE');
6211 $this->pdf->doTransform(isset($param['transform']) ? $this->_prepareTransform($param['transform']) : null);
6212 $this->parsingCss->save();
6213 $styles = $this->parsingCss->getSvgStyle('path', $param);
6214 $style = $this->pdf->svgSetStyle($styles);
6216 $cx = isset($param['cx']) ? $this->parsingCss->ConvertToMM($param['cx'], $this->_isInDraw['w']) : 0.;
6217 $cy = isset($param['cy']) ? $this->parsingCss->ConvertToMM($param['cy'], $this->_isInDraw['h']) : 0.;
6218 $r = isset($param['r']) ? $this->parsingCss->ConvertToMM($param['r'], $this->_isInDraw['w']) : 0.;
6219 $this->pdf->svgEllipse($cx, $cy, $r, $r, $style);
6221 $this->pdf->undoTransform();
6222 $this->parsingCss->load();
6226 * tag : ELLIPSE
6227 * mode : OPEN
6229 * @param array $param
6230 * @return boolean
6232 protected function _tag_open_ELLIPSE($param)
6234 if (!$this->_isInDraw) throw new HTML2PDF_exception(8, 'ELLIPSE');
6236 $this->pdf->doTransform(isset($param['transform']) ? $this->_prepareTransform($param['transform']) : null);
6237 $this->parsingCss->save();
6238 $styles = $this->parsingCss->getSvgStyle('path', $param);
6239 $style = $this->pdf->svgSetStyle($styles);
6241 $cx = isset($param['cx']) ? $this->parsingCss->ConvertToMM($param['cx'], $this->_isInDraw['w']) : 0.;
6242 $cy = isset($param['cy']) ? $this->parsingCss->ConvertToMM($param['cy'], $this->_isInDraw['h']) : 0.;
6243 $rx = isset($param['ry']) ? $this->parsingCss->ConvertToMM($param['rx'], $this->_isInDraw['w']) : 0.;
6244 $ry = isset($param['rx']) ? $this->parsingCss->ConvertToMM($param['ry'], $this->_isInDraw['h']) : 0.;
6245 $this->pdf->svgEllipse($cx, $cy, $rx, $ry, $style);
6247 $this->pdf->undoTransform();
6248 $this->parsingCss->load();
6253 * tag : POLYLINE
6254 * mode : OPEN
6256 * @param array $param
6257 * @return boolean
6259 protected function _tag_open_POLYLINE($param)
6261 if (!$this->_isInDraw) throw new HTML2PDF_exception(8, 'POLYGON');
6263 $this->pdf->doTransform(isset($param['transform']) ? $this->_prepareTransform($param['transform']) : null);
6264 $this->parsingCss->save();
6265 $styles = $this->parsingCss->getSvgStyle('path', $param);
6266 $style = $this->pdf->svgSetStyle($styles);
6268 $path = isset($param['points']) ? $param['points'] : null;
6269 if ($path) {
6270 $path = str_replace(',', ' ', $path);
6271 $path = preg_replace('/[\s]+/', ' ', trim($path));
6273 // prepare the path
6274 $path = explode(' ', $path);
6275 foreach ($path as $k => $v) {
6276 $path[$k] = trim($v);
6277 if ($path[$k]==='') unset($path[$k]);
6279 $path = array_values($path);
6281 $actions = array();
6282 for ($k=0; $k<count($path); $k+=2) {
6283 $actions[] = array(
6284 ($k ? 'L' : 'M') ,
6285 $this->parsingCss->ConvertToMM($path[$k+0], $this->_isInDraw['w']),
6286 $this->parsingCss->ConvertToMM($path[$k+1], $this->_isInDraw['h'])
6290 // drawing
6291 $this->pdf->svgPolygone($actions, $style);
6294 $this->pdf->undoTransform();
6295 $this->parsingCss->load();
6299 * tag : POLYGON
6300 * mode : OPEN
6302 * @param array $param
6303 * @return boolean
6305 protected function _tag_open_POLYGON($param)
6307 if (!$this->_isInDraw) throw new HTML2PDF_exception(8, 'POLYGON');
6309 $this->pdf->doTransform(isset($param['transform']) ? $this->_prepareTransform($param['transform']) : null);
6310 $this->parsingCss->save();
6311 $styles = $this->parsingCss->getSvgStyle('path', $param);
6312 $style = $this->pdf->svgSetStyle($styles);
6314 $path = (isset($param['points']) ? $param['points'] : null);
6315 if ($path) {
6316 $path = str_replace(',', ' ', $path);
6317 $path = preg_replace('/[\s]+/', ' ', trim($path));
6319 // prepare the path
6320 $path = explode(' ', $path);
6321 foreach ($path as $k => $v) {
6322 $path[$k] = trim($v);
6323 if ($path[$k]==='') unset($path[$k]);
6325 $path = array_values($path);
6327 $actions = array();
6328 for ($k=0; $k<count($path); $k+=2) {
6329 $actions[] = array(
6330 ($k ? 'L' : 'M') ,
6331 $this->parsingCss->ConvertToMM($path[$k+0], $this->_isInDraw['w']),
6332 $this->parsingCss->ConvertToMM($path[$k+1], $this->_isInDraw['h'])
6335 $actions[] = array('z');
6337 // drawing
6338 $this->pdf->svgPolygone($actions, $style);
6341 $this->pdf->undoTransform();
6342 $this->parsingCss->load();
6346 * tag : PATH
6347 * mode : OPEN
6349 * @param array $param
6350 * @return boolean
6352 protected function _tag_open_PATH($param)
6354 if (!$this->_isInDraw) throw new HTML2PDF_exception(8, 'PATH');
6356 $this->pdf->doTransform(isset($param['transform']) ? $this->_prepareTransform($param['transform']) : null);
6357 $this->parsingCss->save();
6358 $styles = $this->parsingCss->getSvgStyle('path', $param);
6359 $style = $this->pdf->svgSetStyle($styles);
6361 $path = isset($param['d']) ? $param['d'] : null;
6363 if ($path) {
6364 // prepare the path
6365 $path = str_replace(',', ' ', $path);
6366 $path = preg_replace('/([a-zA-Z])([0-9\.\-])/', '$1 $2', $path);
6367 $path = preg_replace('/([0-9\.])([a-zA-Z])/', '$1 $2', $path);
6368 $path = preg_replace('/[\s]+/', ' ', trim($path));
6369 $path = preg_replace('/ ([a-z]{2})/', '$1', $path);
6371 $path = explode(' ', $path);
6372 foreach ($path as $k => $v) {
6373 $path[$k] = trim($v);
6374 if ($path[$k]==='') unset($path[$k]);
6376 $path = array_values($path);
6378 // read each actions in the path
6379 $actions = array();
6380 $action = array();
6381 $lastAction = null; // last action found
6382 for ($k=0; $k<count($path);true) {
6384 // for this actions, we can not have multi coordonate
6385 if (in_array($lastAction, array('z', 'Z'))) {
6386 $lastAction = null;
6389 // read the new action (forcing if no action before)
6390 if (preg_match('/^[a-z]+$/i', $path[$k]) || $lastAction===null) {
6391 $lastAction = $path[$k];
6392 $k++;
6395 // current action
6396 $action = array();
6397 $action[] = $lastAction;
6398 switch($lastAction)
6400 case 'C':
6401 case 'c':
6402 $action[] = $this->parsingCss->ConvertToMM($path[$k+0], $this->_isInDraw['w']); // x1
6403 $action[] = $this->parsingCss->ConvertToMM($path[$k+1], $this->_isInDraw['h']); // y1
6404 $action[] = $this->parsingCss->ConvertToMM($path[$k+2], $this->_isInDraw['w']); // x2
6405 $action[] = $this->parsingCss->ConvertToMM($path[$k+3], $this->_isInDraw['h']); // y2
6406 $action[] = $this->parsingCss->ConvertToMM($path[$k+4], $this->_isInDraw['w']); // x
6407 $action[] = $this->parsingCss->ConvertToMM($path[$k+5], $this->_isInDraw['h']); // y
6408 $k+= 6;
6409 break;
6411 case 'Q':
6412 case 'S':
6413 case 'q':
6414 case 's':
6415 $action[] = $this->parsingCss->ConvertToMM($path[$k+0], $this->_isInDraw['w']); // x2
6416 $action[] = $this->parsingCss->ConvertToMM($path[$k+1], $this->_isInDraw['h']); // y2
6417 $action[] = $this->parsingCss->ConvertToMM($path[$k+2], $this->_isInDraw['w']); // x
6418 $action[] = $this->parsingCss->ConvertToMM($path[$k+3], $this->_isInDraw['h']); // y
6419 $k+= 4;
6420 break;
6422 case 'A':
6423 case 'a':
6424 $action[] = $this->parsingCss->ConvertToMM($path[$k+0], $this->_isInDraw['w']); // rx
6425 $action[] = $this->parsingCss->ConvertToMM($path[$k+1], $this->_isInDraw['h']); // ry
6426 $action[] = 1.*$path[$k+2]; // angle de deviation de l'axe X
6427 $action[] = ($path[$k+3]=='1') ? 1 : 0; // large-arc-flag
6428 $action[] = ($path[$k+4]=='1') ? 1 : 0; // sweep-flag
6429 $action[] = $this->parsingCss->ConvertToMM($path[$k+5], $this->_isInDraw['w']); // x
6430 $action[] = $this->parsingCss->ConvertToMM($path[$k+6], $this->_isInDraw['h']); // y
6431 $k+= 7;
6432 break;
6434 case 'M':
6435 case 'L':
6436 case 'T':
6437 case 'm':
6438 case 'l':
6439 case 't':
6440 $action[] = $this->parsingCss->ConvertToMM($path[$k+0], $this->_isInDraw['w']); // x
6441 $action[] = $this->parsingCss->ConvertToMM($path[$k+1], $this->_isInDraw['h']); // y
6442 $k+= 2;
6443 break;
6445 case 'H':
6446 case 'h':
6447 $action[] = $this->parsingCss->ConvertToMM($path[$k+0], $this->_isInDraw['w']); // x
6448 $k+= 1;
6449 break;
6451 case 'V':
6452 case 'v':
6453 $action[] = $this->parsingCss->ConvertToMM($path[$k+0], $this->_isInDraw['h']); // y
6454 $k+= 1;
6455 break;
6457 case 'z':
6458 case 'Z':
6459 default:
6460 break;
6462 // add the action
6463 $actions[] = $action;
6466 // drawing
6467 $this->pdf->svgPolygone($actions, $style);
6470 $this->pdf->undoTransform();
6471 $this->parsingCss->load();
6475 * tag : G
6476 * mode : OPEN
6478 * @param array $param
6479 * @return boolean
6481 protected function _tag_open_G($param)
6483 if (!$this->_isInDraw) throw new HTML2PDF_exception(8, 'G');
6485 $this->pdf->doTransform(isset($param['transform']) ? $this->_prepareTransform($param['transform']) : null);
6486 $this->parsingCss->save();
6487 $styles = $this->parsingCss->getSvgStyle('path', $param);
6488 $style = $this->pdf->svgSetStyle($styles);
6492 * tag : G
6493 * mode : CLOSE
6495 * @param array $param
6496 * @return boolean
6498 protected function _tag_close_G($param)
6500 $this->pdf->undoTransform();
6501 $this->parsingCss->load();
6505 * tag : END_LAST_PAGE
6506 * mode : OPEN
6508 * @param array $param
6509 * @return void
6511 protected function _tag_open_END_LAST_PAGE($param)
6513 $height = $this->parsingCss->ConvertToMM(
6514 $param['end_height'],
6515 $this->pdf->getH() - $this->pdf->gettMargin()-$this->pdf->getbMargin()
6518 if ($height < ($this->pdf->getH() - $this->pdf->gettMargin()-$this->pdf->getbMargin())
6519 && $this->pdf->getY() + $height>=($this->pdf->getH() - $this->pdf->getbMargin())
6521 $this->_setNewPage();
6524 $this->parsingCss->save();
6525 $this->parsingCss->analyse('end_last_page', $param);
6526 $this->parsingCss->setPosition();
6527 $this->parsingCss->fontSet();
6529 $this->pdf->setY($this->pdf->getH() - $this->pdf->getbMargin() - $height);
6533 * tag : END_LAST_PAGE
6534 * mode : CLOSE
6536 * @param array $param
6537 * @return void
6539 protected function _tag_close_END_LAST_PAGE($param)
6541 $this->parsingCss->load();
6542 $this->parsingCss->fontSet();
6546 * new page for the automatic Index, do not use this method. Only HTML2PDF_myPdf could use it !!!!
6548 * @param &int $page
6549 * @return integer $oldPage
6551 public function _INDEX_NewPage(&$page)
6553 if ($page) {
6554 $oldPage = $this->pdf->getPage();
6555 $this->pdf->setPage($page);
6556 $this->pdf->setXY($this->_margeLeft, $this->_margeTop);
6557 $this->_maxH = 0;
6558 $page++;
6559 return $oldPage;
6560 } else {
6561 $this->_setNewPage();
6562 return null;