[ Index ] |
PHP Cross Reference of Unnamed Project |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * HTML2PDF Librairy - main class 4 * 5 * HTML => PDF convertor 6 * distributed under the LGPL License 7 * 8 * @author Laurent MINGUET <webmaster@html2pdf.fr> 9 * @version 4.03 10 */ 11 12 if (!defined('__CLASS_HTML2PDF__')) { 13 14 define('__CLASS_HTML2PDF__', '4.03'); 15 define('HTML2PDF_USED_TCPDF_VERSION', '5.0.002'); 16 17 require_once(dirname(__FILE__).'/_class/exception.class.php'); 18 require_once(dirname(__FILE__).'/_class/locale.class.php'); 19 require_once(dirname(__FILE__).'/_class/myPdf.class.php'); 20 require_once(dirname(__FILE__).'/_class/parsingHtml.class.php'); 21 require_once(dirname(__FILE__).'/_class/parsingCss.class.php'); 22 23 class HTML2PDF 24 { 25 /** 26 * HTML2PDF_myPdf object, extends from TCPDF 27 * @var HTML2PDF_myPdf 28 */ 29 public $pdf = null; 30 31 /** 32 * CSS parsing 33 * @var HTML2PDF_parsingCss 34 */ 35 public $parsingCss = null; 36 37 /** 38 * HTML parsing 39 * @var HTML2PDF_parsingHtml 40 */ 41 public $parsingHtml = null; 42 43 protected $_langue = 'fr'; // locale of the messages 44 protected $_orientation = 'P'; // page orientation : Portrait ou Landscape 45 protected $_format = 'A4'; // page format : A4, A3, ... 46 protected $_encoding = ''; // charset encoding 47 protected $_unicode = true; // means that the input text is unicode (default = true) 48 49 protected $_testTdInOnepage = true; // test of TD that can not take more than one page 50 protected $_testIsImage = true; // test if the images exist or not 51 protected $_testIsDeprecated = false; // test the deprecated functions 52 53 protected $_parsePos = 0; // position in the parsing 54 protected $_tempPos = 0; // temporary position for complex table 55 protected $_page = 0; // current page number 56 57 protected $_subHtml = null; // sub html 58 protected $_subPart = false; // sub HTML2PDF 59 protected $_subHEADER = array(); // sub action to make the header 60 protected $_subFOOTER = array(); // sub action to make the footer 61 protected $_subSTATES = array(); // array to save some parameters 62 63 protected $_isSubPart = false; // flag : in a sub html2pdf 64 protected $_isInThead = false; // flag : in a thead 65 protected $_isInTfoot = false; // flag : in a tfoot 66 protected $_isInOverflow = false; // flag : in a overflow 67 protected $_isInFooter = false; // flag : in a footer 68 protected $_isInDraw = null; // flag : in a draw (svg) 69 protected $_isAfterFloat = false; // flag : is just after a float 70 protected $_isInForm = false; // flag : is in a float. false / action of the form 71 protected $_isInLink = ''; // flag : is in a link. empty / href of the link 72 protected $_isInParagraph = false; // flag : is in a paragraph 73 protected $_isForOneLine = false; // flag : in a specific sub html2pdf to have the height of the next line 74 75 protected $_maxX = 0; // maximum X of the current zone 76 protected $_maxY = 0; // maximum Y of the current zone 77 protected $_maxE = 0; // number of elements in the current zone 78 protected $_maxH = 0; // maximum height of the line in the current zone 79 protected $_maxSave = array(); // save the maximums of the current zone 80 protected $_currentH = 0; // height of the current line 81 82 protected $_defaultLeft = 0; // default marges of the page 83 protected $_defaultTop = 0; 84 protected $_defaultRight = 0; 85 protected $_defaultBottom = 0; 86 protected $_defaultFont = null; // default font to use, is the asked font does not exist 87 88 protected $_margeLeft = 0; // current marges of the page 89 protected $_margeTop = 0; 90 protected $_margeRight = 0; 91 protected $_margeBottom = 0; 92 protected $_marges = array(); // save the different marges of the current page 93 protected $_pageMarges = array(); // float marges of the current page 94 protected $_background = array(); // background informations 95 96 97 protected $_firstPage = true; // flag : first page 98 protected $_defList = array(); // table to save the stats of the tags UL and OL 99 100 protected $_lstAnchor = array(); // list of the anchors 101 protected $_lstField = array(); // list of the fields 102 protected $_lstSelect = array(); // list of the options of the current select 103 protected $_previousCall = null; // last action called 104 105 protected $_debugActif = false; // flag : mode debug is active 106 protected $_debugOkUsage = false; // flag : the function memory_get_usage exist 107 protected $_debugOkPeak = false; // flag : the function memory_get_peak_usage exist 108 protected $_debugLevel = 0; // level in the debug 109 protected $_debugStartTime = 0; // debug start time 110 protected $_debugLastTime = 0; // debug stop time 111 112 static protected $_subobj = null; // object html2pdf prepared in order to accelerate the creation of sub html2pdf 113 static protected $_tables = array(); // static table to prepare the nested html tables 114 115 /** 116 * class constructor 117 * 118 * @access public 119 * @param string $orientation page orientation, same as TCPDF 120 * @param mixed $format The format used for pages, same as TCPDF 121 * @param $tring $langue Langue : fr, en, it... 122 * @param boolean $unicode TRUE means that the input text is unicode (default = true) 123 * @param String $encoding charset encoding; default is UTF-8 124 * @param array $marges Default marges (left, top, right, bottom) 125 * @return HTML2PDF $this 126 */ 127 public function __construct($orientation = 'P', $format = 'A4', $langue='fr', $unicode=true, $encoding='UTF-8', $marges = array(5, 5, 5, 8)) 128 { 129 // init the page number 130 $this->_page = 0; 131 $this->_firstPage = true; 132 133 // save the parameters 134 $this->_orientation = $orientation; 135 $this->_format = $format; 136 $this->_langue = strtolower($langue); 137 $this->_unicode = $unicode; 138 $this->_encoding = $encoding; 139 140 // load the Local 141 HTML2PDF_locale::load($this->_langue); 142 143 // create the HTML2PDF_myPdf object 144 $this->pdf = new HTML2PDF_myPdf($orientation, 'mm', $format, $unicode, $encoding); 145 146 // init the CSS parsing object 147 $this->parsingCss = new HTML2PDF_parsingCss($this->pdf); 148 $this->parsingCss->fontSet(); 149 $this->_defList = array(); 150 151 // init some tests 152 $this->setTestTdInOnePage(true); 153 $this->setTestIsImage(true); 154 $this->setTestIsDeprecated(true); 155 156 // init the default font 157 $this->setDefaultFont(null); 158 159 // init the HTML parsing object 160 $this->parsingHtml = new HTML2PDF_parsingHtml($this->_encoding); 161 $this->_subHtml = null; 162 $this->_subPart = false; 163 164 // init the marges of the page 165 if (!is_array($marges)) $marges = array($marges, $marges, $marges, $marges); 166 $this->_setDefaultMargins($marges[0], $marges[1], $marges[2], $marges[3]); 167 $this->_setMargins(); 168 $this->_marges = array(); 169 170 // init the form's fields 171 $this->_lstField = array(); 172 173 return $this; 174 } 175 176 /** 177 * Destructor 178 * 179 * @access public 180 * @return null 181 */ 182 public function __destruct() 183 { 184 185 } 186 187 /** 188 * Clone to create a sub HTML2PDF from HTML2PDF::$_subobj 189 * 190 * @access public 191 */ 192 public function __clone() 193 { 194 $this->pdf = clone $this->pdf; 195 $this->parsingHtml = clone $this->parsingHtml; 196 $this->parsingCss = clone $this->parsingCss; 197 $this->parsingCss->setPdfParent($this->pdf); 198 } 199 200 /** 201 * set the debug mode to On 202 * 203 * @access public 204 * @return HTML2PDF $this 205 */ 206 public function setModeDebug() 207 { 208 $time = microtime(true); 209 210 $this->_debugActif = true; 211 $this->_debugOkUsage = function_exists('memory_get_usage'); 212 $this->_debugOkPeak = function_exists('memory_get_peak_usage'); 213 $this->_debugStartTime = $time; 214 $this->_debugLastTime = $time; 215 216 $this->_DEBUG_stepline('step', 'time', 'delta', 'memory', 'peak'); 217 $this->_DEBUG_add('Init debug'); 218 219 return $this; 220 } 221 222 /** 223 * Set the test of TD thdat can not take more than one page 224 * 225 * @access public 226 * @param boolean $mode 227 * @return HTML2PDF $this 228 */ 229 public function setTestTdInOnePage($mode = true) 230 { 231 $this->_testTdInOnepage = $mode ? true : false; 232 233 return $this; 234 } 235 236 /** 237 * Set the test if the images exist or not 238 * 239 * @access public 240 * @param boolean $mode 241 * @return HTML2PDF $this 242 */ 243 public function setTestIsImage($mode = true) 244 { 245 $this->_testIsImage = $mode ? true : false; 246 247 return $this; 248 } 249 250 /** 251 * Set the test on deprecated functions 252 * 253 * @access public 254 * @param boolean $mode 255 * @return HTML2PDF $this 256 */ 257 public function setTestIsDeprecated($mode = true) 258 { 259 $this->_testIsDeprecated = $mode ? true : false; 260 261 return $this; 262 } 263 264 /** 265 * Set the default font to use, if no font is specify, or if the asked font does not exist 266 * 267 * @access public 268 * @param string $default name of the default font to use. If null : Arial is no font is specify, and error if the asked font does not exist 269 * @return HTML2PDF $this 270 */ 271 public function setDefaultFont($default = null) 272 { 273 $this->_defaultFont = $default; 274 $this->parsingCss->setDefaultFont($default); 275 276 return $this; 277 } 278 279 /** 280 * add a font, see TCPDF function addFont 281 * 282 * @access public 283 * @param string $family Font family. The name can be chosen arbitrarily. If it is a standard family name, it will override the corresponding font. 284 * @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> 285 * @param string $fontfile The font definition file. By default, the name is built from the family and style, in lower case with no spaces. 286 * @return HTML2PDF $this 287 * @see TCPDF::addFont 288 */ 289 public function addFont($family, $style='', $file='') 290 { 291 $this->pdf->AddFont($family, $style, $file); 292 293 return $this; 294 } 295 296 /** 297 * display a automatic index, from the bookmarks 298 * 299 * @access public 300 * @param string $titre index title 301 * @param int $sizeTitle font size of the index title, in mm 302 * @param int $sizeBookmark font size of the index, in mm 303 * @param boolean $bookmarkTitle add a bookmark for the index, at his beginning 304 * @param boolean $displayPage display the page numbers 305 * @param int $onPage if null : at the end of the document on a new page, else on the $onPage page 306 * @param string $fontName font name to use 307 * @return null 308 */ 309 public function createIndex($titre = 'Index', $sizeTitle = 20, $sizeBookmark = 15, $bookmarkTitle = true, $displayPage = true, $onPage = null, $fontName = 'helvetica') 310 { 311 $oldPage = $this->_INDEX_NewPage($onPage); 312 $this->pdf->createIndex($this, $titre, $sizeTitle, $sizeBookmark, $bookmarkTitle, $displayPage, $onPage, $fontName); 313 if ($oldPage) $this->pdf->setPage($oldPage); 314 } 315 316 /** 317 * clean up the objects 318 * 319 * @access protected 320 */ 321 protected function _cleanUp() 322 { 323 HTML2PDF::$_subobj = null; 324 HTML2PDF::$_tables = array(); 325 } 326 327 /** 328 * Send the document to a given destination: string, local file or browser. 329 * Dest can be : 330 * 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. 331 * D : send to the browser and force a file download with the name given by name. 332 * F : save to a local server file with the name given by name. 333 * S : return the document as a string. name is ignored. 334 * FI: equivalent to F + I option 335 * FD: equivalent to F + D option 336 * true => I 337 * false => S 338 * 339 * @param string $name The name of the file when saved. 340 * @param string $dest Destination where to send the document. 341 * @return string content of the PDF, if $dest=S 342 * @see TCPDF::close 343 * @access public 344 345 */ 346 public function Output($name = '', $dest = false) 347 { 348 // close the pdf and clean up 349 $this->_cleanUp(); 350 351 // if on debug mode 352 if ($this->_debugActif) { 353 $this->_DEBUG_add('Before output'); 354 $this->pdf->Close(); 355 exit; 356 } 357 358 // complete parameters 359 if ($dest===false) $dest = 'I'; 360 if ($dest===true) $dest = 'S'; 361 if ($dest==='') $dest = 'I'; 362 if ($name=='') $name='document.pdf'; 363 364 // clean up the destination 365 $dest = strtoupper($dest); 366 if (!in_array($dest, array('I', 'D', 'F', 'S', 'FI','FD'))) $dest = 'I'; 367 368 // the name must be a PDF name 369 if (strtolower(substr($name, -4))!='.pdf') { 370 throw new HTML2PDF_exception(0, 'The output document name "'.$name.'" is not a PDF name'); 371 } 372 373 // call the output of TCPDF 374 return $this->pdf->Output($name, $dest); 375 } 376 377 /** 378 * convert HTML to PDF 379 * 380 * @access public 381 * @param string $html 382 * @param boolean $debugVue enable the HTML debug vue 383 * @return null 384 */ 385 public function writeHTML($html, $debugVue = false) 386 { 387 // if it is a real html page, we have to convert it 388 if (preg_match('/<body/isU', $html)) 389 $html = $this->getHtmlFromPage($html); 390 391 $html = str_replace('[[date_y]]', date('Y'), $html); 392 $html = str_replace('[[date_m]]', date('m'), $html); 393 $html = str_replace('[[date_d]]', date('d'), $html); 394 395 $html = str_replace('[[date_h]]', date('H'), $html); 396 $html = str_replace('[[date_i]]', date('i'), $html); 397 $html = str_replace('[[date_s]]', date('s'), $html); 398 399 // If we are in HTML debug vue : display the HTML 400 if ($debugVue) { 401 return $this->_vueHTML($html); 402 } 403 404 // convert HTMl to PDF 405 $this->parsingCss->readStyle($html); 406 $this->parsingHtml->setHTML($html); 407 $this->parsingHtml->parse(); 408 $this->_makeHTMLcode(); 409 } 410 411 /** 412 * convert the HTML of a real page, to a code adapted to HTML2PDF 413 * 414 * @access public 415 * @param string HTML of a real page 416 * @return string HTML adapted to HTML2PDF 417 */ 418 public function getHtmlFromPage($html) 419 { 420 $html = str_replace('<BODY', '<body', $html); 421 $html = str_replace('</BODY', '</body', $html); 422 423 // extract the content 424 $res = explode('<body', $html); 425 if (count($res)<2) return $html; 426 $content = '<page'.$res[1]; 427 $content = explode('</body', $content); 428 $content = $content[0].'</page>'; 429 430 // extract the link tags 431 preg_match_all('/<link([^>]*)>/isU', $html, $match); 432 foreach ($match[0] as $src) 433 $content = $src.'</link>'.$content; 434 435 // extract the css style tags 436 preg_match_all('/<style[^>]*>(.*)<\/style[^>]*>/isU', $html, $match); 437 foreach ($match[0] as $src) 438 $content = $src.$content; 439 440 return $content; 441 } 442 443 /** 444 * init a sub HTML2PDF. does not use it directly. Only the method createSubHTML must use it 445 * 446 * @access public 447 * @param string $format 448 * @param string $orientation 449 * @param array $marge 450 * @param integer $page 451 * @param array $defLIST 452 * @param integer $myLastPageGroup 453 * @param integer $myLastPageGroupNb 454 */ 455 public function initSubHtml($format, $orientation, $marge, $page, $defLIST, $myLastPageGroup, $myLastPageGroupNb) 456 { 457 $this->_isSubPart = true; 458 459 $this->parsingCss->setOnlyLeft(); 460 461 $this->_setNewPage($format, $orientation, null, null, ($myLastPageGroup!==null)); 462 463 $this->_saveMargin(0, 0, $marge); 464 $this->_defList = $defLIST; 465 466 $this->_page = $page; 467 $this->pdf->setMyLastPageGroup($myLastPageGroup); 468 $this->pdf->setMyLastPageGroupNb($myLastPageGroupNb); 469 $this->pdf->setXY(0, 0); 470 $this->parsingCss->fontSet(); 471 } 472 473 /** 474 * display the content in HTML moden for debug 475 * 476 * @access protected 477 * @param string $contenu 478 */ 479 protected function _vueHTML($content) 480 { 481 $content = preg_replace('/<page_header([^>]*)>/isU', '<hr>'.HTML2PDF_locale::get('vue01').' : $1<hr><div$1>', $content); 482 $content = preg_replace('/<page_footer([^>]*)>/isU', '<hr>'.HTML2PDF_locale::get('vue02').' : $1<hr><div$1>', $content); 483 $content = preg_replace('/<page([^>]*)>/isU', '<hr>'.HTML2PDF_locale::get('vue03').' : $1<hr><div$1>', $content); 484 $content = preg_replace('/<\/page([^>]*)>/isU', '</div><hr>', $content); 485 $content = preg_replace('/<bookmark([^>]*)>/isU', '<hr>bookmark : $1<hr>', $content); 486 $content = preg_replace('/<\/bookmark([^>]*)>/isU', '', $content); 487 $content = preg_replace('/<barcode([^>]*)>/isU', '<hr>barcode : $1<hr>', $content); 488 $content = preg_replace('/<\/barcode([^>]*)>/isU', '', $content); 489 $content = preg_replace('/<qrcode([^>]*)>/isU', '<hr>qrcode : $1<hr>', $content); 490 $content = preg_replace('/<\/qrcode([^>]*)>/isU', '', $content); 491 492 echo '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> 493 <html> 494 <head> 495 <title>'.HTML2PDF_locale::get('vue04').' HTML</title> 496 <meta http-equiv="Content-Type" content="text/html; charset='.$this->_encoding.'" > 497 </head> 498 <body style="padding: 10px; font-size: 10pt;font-family: Verdana;"> 499 '.$content.' 500 </body> 501 </html>'; 502 exit; 503 } 504 505 /** 506 * set the default margins of the page 507 * 508 * @access protected 509 * @param int $left (mm, left margin) 510 * @param int $top (mm, top margin) 511 * @param int $right (mm, right margin, if null => left=right) 512 * @param int $bottom (mm, bottom margin, if null => bottom=8mm) 513 */ 514 protected function _setDefaultMargins($left, $top, $right = null, $bottom = null) 515 { 516 if ($right===null) $right = $left; 517 if ($bottom===null) $bottom = 8; 518 519 $this->_defaultLeft = $this->parsingCss->ConvertToMM($left.'mm'); 520 $this->_defaultTop = $this->parsingCss->ConvertToMM($top.'mm'); 521 $this->_defaultRight = $this->parsingCss->ConvertToMM($right.'mm'); 522 $this->_defaultBottom = $this->parsingCss->ConvertToMM($bottom.'mm'); 523 } 524 525 /** 526 * create a new page 527 * 528 * @access protected 529 * @param mixed $format 530 * @param string $orientation 531 * @param array $background background information 532 * @param integer $curr real position in the html parseur (if break line in the write of a text) 533 * @param boolean $resetPageNumber 534 */ 535 protected function _setNewPage($format = null, $orientation = '', $background = null, $curr = null, $resetPageNumber=false) 536 { 537 $this->_firstPage = false; 538 539 $this->_format = $format ? $format : $this->_format; 540 $this->_orientation = $orientation ? $orientation : $this->_orientation; 541 $this->_background = $background!==null ? $background : $this->_background; 542 $this->_maxY = 0; 543 $this->_maxX = 0; 544 $this->_maxH = 0; 545 $this->_maxE = 0; 546 547 $this->pdf->SetMargins($this->_defaultLeft, $this->_defaultTop, $this->_defaultRight); 548 549 if ($resetPageNumber) { 550 $this->pdf->startPageGroup(); 551 } 552 553 $this->pdf->AddPage($this->_orientation, $this->_format); 554 555 if ($resetPageNumber) { 556 $this->pdf->myStartPageGroup(); 557 } 558 559 $this->_page++; 560 561 if (!$this->_subPart && !$this->_isSubPart) { 562 if (is_array($this->_background)) { 563 if (isset($this->_background['color']) && $this->_background['color']) { 564 $this->pdf->setFillColorArray($this->_background['color']); 565 $this->pdf->Rect(0, 0, $this->pdf->getW(), $this->pdf->getH(), 'F'); 566 } 567 568 if (isset($this->_background['img']) && $this->_background['img']) 569 $this->pdf->Image($this->_background['img'], $this->_background['posX'], $this->_background['posY'], $this->_background['width']); 570 } 571 572 $this->_setPageHeader(); 573 $this->_setPageFooter(); 574 } 575 576 $this->_setMargins(); 577 $this->pdf->setY($this->_margeTop); 578 579 $this->_setNewPositionForNewLine($curr); 580 $this->_maxH = 0; 581 } 582 583 /** 584 * set the real margin, using the default margins and the page margins 585 * 586 * @access protected 587 */ 588 protected function _setMargins() 589 { 590 // prepare the margins 591 $this->_margeLeft = $this->_defaultLeft + (isset($this->_background['left']) ? $this->_background['left'] : 0); 592 $this->_margeRight = $this->_defaultRight + (isset($this->_background['right']) ? $this->_background['right'] : 0); 593 $this->_margeTop = $this->_defaultTop + (isset($this->_background['top']) ? $this->_background['top'] : 0); 594 $this->_margeBottom = $this->_defaultBottom + (isset($this->_background['bottom']) ? $this->_background['bottom'] : 0); 595 596 // set the PDF margins 597 $this->pdf->SetMargins($this->_margeLeft, $this->_margeTop, $this->_margeRight); 598 $this->pdf->SetAutoPageBreak(false, $this->_margeBottom); 599 600 // set the float Margins 601 $this->_pageMarges = array(); 602 if ($this->_isInParagraph!==false) { 603 $this->_pageMarges[floor($this->_margeTop*100)] = array($this->_isInParagraph[0], $this->pdf->getW()-$this->_isInParagraph[1]); 604 } else { 605 $this->_pageMarges[floor($this->_margeTop*100)] = array($this->_margeLeft, $this->pdf->getW()-$this->_margeRight); 606 } 607 } 608 609 /** 610 * add a debug step 611 * 612 * @access protected 613 * @param string $name step name 614 * @param boolean $level (true=up, false=down, null=nothing to do) 615 * @return $this 616 */ 617 protected function _DEBUG_add($name, $level=null) 618 { 619 // if true : UP 620 if ($level===true) $this->_debugLevel++; 621 622 $name = str_repeat(' ', $this->_debugLevel). $name.($level===true ? ' Begin' : ($level===false ? ' End' : '')); 623 $time = microtime(true); 624 $usage = ($this->_debugOkUsage ? memory_get_usage() : 0); 625 $peak = ($this->_debugOkPeak ? memory_get_peak_usage() : 0); 626 627 $this->_DEBUG_stepline( 628 $name, 629 number_format(($time - $this->_debugStartTime)*1000, 1, '.', ' ').' ms', 630 number_format(($time - $this->_debugLastTime)*1000, 1, '.', ' ').' ms', 631 number_format($usage/1024, 1, '.', ' ').' Ko', 632 number_format($peak/1024, 1, '.', ' ').' Ko' 633 ); 634 635 $this->_debugLastTime = $time; 636 637 // it false : DOWN 638 if ($level===false) $this->_debugLevel--; 639 640 return $this; 641 } 642 643 /** 644 * display a debug line 645 * 646 * 647 * @access protected 648 * @param string $name 649 * @param string $timeTotal 650 * @param string $timeStep 651 * @param string $memoryUsage 652 * @param string $memoryPeak 653 */ 654 protected function _DEBUG_stepline($name, $timeTotal, $timeStep, $memoryUsage, $memoryPeak) 655 { 656 $txt = str_pad($name, 30, ' ', STR_PAD_RIGHT). 657 str_pad($timeTotal, 12, ' ', STR_PAD_LEFT). 658 str_pad($timeStep, 12, ' ', STR_PAD_LEFT). 659 str_pad($memoryUsage, 15, ' ', STR_PAD_LEFT). 660 str_pad($memoryPeak, 15, ' ', STR_PAD_LEFT); 661 662 echo '<pre style="padding:0; margin:0">'.$txt.'</pre>'; 663 } 664 665 /** 666 * get the Min and Max X, for Y (use the float margins) 667 * 668 * @access protected 669 * @param float $y 670 * @return array(float, float) 671 */ 672 protected function _getMargins($y) 673 { 674 $y = floor($y*100); 675 $x = array($this->pdf->getlMargin(), $this->pdf->getW()-$this->pdf->getrMargin()); 676 677 foreach ($this->_pageMarges as $mY => $mX) 678 if ($mY<=$y) $x = $mX; 679 680 return $x; 681 } 682 683 /** 684 * Add margins, for a float 685 * 686 * @access protected 687 * @param string $float (left / right) 688 * @param float $xLeft 689 * @param float $yTop 690 * @param float $xRight 691 * @param float $yBottom 692 */ 693 protected function _addMargins($float, $xLeft, $yTop, $xRight, $yBottom) 694 { 695 // get the current float margins, for top and bottom 696 $oldTop = $this->_getMargins($yTop); 697 $oldBottom = $this->_getMargins($yBottom); 698 699 // update the top float margin 700 if ($float=='left' && $oldTop[0]<$xRight) $oldTop[0] = $xRight; 701 if ($float=='right' && $oldTop[1]>$xLeft) $oldTop[1] = $xLeft; 702 703 $yTop = floor($yTop*100); 704 $yBottom = floor($yBottom*100); 705 706 // erase all the float margins that are smaller than the new one 707 foreach ($this->_pageMarges as $mY => $mX) { 708 if ($mY<$yTop) continue; 709 if ($mY>$yBottom) break; 710 if ($float=='left' && $this->_pageMarges[$mY][0]<$xRight) unset($this->_pageMarges[$mY]); 711 if ($float=='right' && $this->_pageMarges[$mY][1]>$xLeft) unset($this->_pageMarges[$mY]); 712 } 713 714 // save the new Top and Bottom margins 715 $this->_pageMarges[$yTop] = $oldTop; 716 $this->_pageMarges[$yBottom] = $oldBottom; 717 718 // sort the margins 719 ksort($this->_pageMarges); 720 721 // we are just after float 722 $this->_isAfterFloat = true; 723 } 724 725 /** 726 * Save old margins (push), and set new ones 727 * 728 * @access protected 729 * @param float $ml left margin 730 * @param float $mt top margin 731 * @param float $mr right margin 732 */ 733 protected function _saveMargin($ml, $mt, $mr) 734 { 735 // save old margins 736 $this->_marges[] = array('l' => $this->pdf->getlMargin(), 't' => $this->pdf->gettMargin(), 'r' => $this->pdf->getrMargin(), 'page' => $this->_pageMarges); 737 738 // set new ones 739 $this->pdf->SetMargins($ml, $mt, $mr); 740 741 // prepare for float margins 742 $this->_pageMarges = array(); 743 $this->_pageMarges[floor($mt*100)] = array($ml, $this->pdf->getW()-$mr); 744 } 745 746 /** 747 * load the last saved margins (pop) 748 * 749 * @access protected 750 */ 751 protected function _loadMargin() 752 { 753 $old = array_pop($this->_marges); 754 if ($old) { 755 $ml = $old['l']; 756 $mt = $old['t']; 757 $mr = $old['r']; 758 $mP = $old['page']; 759 } else { 760 $ml = $this->_margeLeft; 761 $mt = 0; 762 $mr = $this->_margeRight; 763 $mP = array($mt => array($ml, $this->pdf->getW()-$mr)); 764 } 765 766 $this->pdf->SetMargins($ml, $mt, $mr); 767 $this->_pageMarges = $mP; 768 } 769 770 /** 771 * save the current maxs (push) 772 * 773 * @access protected 774 */ 775 protected function _saveMax() 776 { 777 $this->_maxSave[] = array($this->_maxX, $this->_maxY, $this->_maxH, $this->_maxE); 778 } 779 780 /** 781 * load the last saved current maxs (pop) 782 * 783 * @access protected 784 */ 785 protected function _loadMax() 786 { 787 $old = array_pop($this->_maxSave); 788 789 if ($old) { 790 $this->_maxX = $old[0]; 791 $this->_maxY = $old[1]; 792 $this->_maxH = $old[2]; 793 $this->_maxE = $old[3]; 794 } else { 795 $this->_maxX = 0; 796 $this->_maxY = 0; 797 $this->_maxH = 0; 798 $this->_maxE = 0; 799 } 800 } 801 802 /** 803 * draw the PDF header with the HTML in page_header 804 * 805 * @access protected 806 */ 807 protected function _setPageHeader() 808 { 809 if (!count($this->_subHEADER)) return false; 810 811 $oldParsePos = $this->_parsePos; 812 $oldParseCode = $this->parsingHtml->code; 813 814 $this->_parsePos = 0; 815 $this->parsingHtml->code = $this->_subHEADER; 816 $this->_makeHTMLcode(); 817 818 $this->_parsePos = $oldParsePos; 819 $this->parsingHtml->code = $oldParseCode; 820 } 821 822 /** 823 * draw the PDF footer with the HTML in page_footer 824 * 825 * @access protected 826 */ 827 protected function _setPageFooter() 828 { 829 if (!count($this->_subFOOTER)) return false; 830 831 $oldParsePos = $this->_parsePos; 832 $oldParseCode = $this->parsingHtml->code; 833 834 $this->_parsePos = 0; 835 $this->parsingHtml->code = $this->_subFOOTER; 836 $this->_isInFooter = true; 837 $this->_makeHTMLcode(); 838 $this->_isInFooter = false; 839 840 $this->_parsePos = $oldParsePos; 841 $this->parsingHtml->code = $oldParseCode; 842 } 843 844 /** 845 * new line, with a specific height 846 * 847 * @access protected 848 * @param float $h 849 * @param integer $curr real current position in the text, if new line in the write of a text 850 */ 851 protected function _setNewLine($h, $curr = null) 852 { 853 $this->pdf->Ln($h); 854 $this->_setNewPositionForNewLine($curr); 855 } 856 857 /** 858 * calculate the start position of the next line, depending on the text-align 859 * 860 * @access protected 861 * @param integer $curr real current position in the text, if new line in the write of a text 862 */ 863 protected function _setNewPositionForNewLine($curr = null) 864 { 865 // get the margins for the current line 866 list($lx, $rx) = $this->_getMargins($this->pdf->getY()); 867 $this->pdf->setX($lx); 868 $wMax = $rx-$lx; 869 $this->_currentH = 0; 870 871 // if subPart => return because align left 872 if ($this->_subPart || $this->_isSubPart || $this->_isForOneLine) { 873 $this->pdf->setWordSpacing(0); 874 return null; 875 } 876 877 // create the sub object 878 $sub = null; 879 $this->_createSubHTML($sub); 880 $sub->_saveMargin(0, 0, $sub->pdf->getW()-$wMax); 881 $sub->_isForOneLine = true; 882 $sub->_parsePos = $this->_parsePos; 883 $sub->parsingHtml->code = $this->parsingHtml->code; 884 885 // if $curr => adapt the current position of the parsing 886 if ($curr!==null && $sub->parsingHtml->code[$this->_parsePos]['name']=='write') { 887 $txt = $sub->parsingHtml->code[$this->_parsePos]['param']['txt']; 888 $txt = str_replace('[[page_cu]]', $sub->pdf->getMyNumPage($this->_page), $txt); 889 $sub->parsingHtml->code[$this->_parsePos]['param']['txt'] = substr($txt, $curr+1); 890 } else 891 $sub->_parsePos++; 892 893 // for each element of the parsing => load the action 894 $res = null; 895 for ($sub->_parsePos; $sub->_parsePos<count($sub->parsingHtml->code); $sub->_parsePos++) { 896 $action = $sub->parsingHtml->code[$sub->_parsePos]; 897 $res = $sub->_executeAction($action); 898 if (!$res) break; 899 } 900 901 $w = $sub->_maxX; // max width 902 $h = $sub->_maxH; // max height 903 $e = ($res===null ? $sub->_maxE : 0); // maxnumber of elemets on the line 904 905 // destroy the sub HTML 906 $this->_destroySubHTML($sub); 907 908 // adapt the start of the line, depending on the text-align 909 if ($this->parsingCss->value['text-align']=='center') 910 $this->pdf->setX(($rx+$this->pdf->getX()-$w)*0.5-0.01); 911 else if ($this->parsingCss->value['text-align']=='right') 912 $this->pdf->setX($rx-$w-0.01); 913 else 914 $this->pdf->setX($lx); 915 916 // set the height of the line 917 $this->_currentH = $h; 918 919 // if justify => set the word spacing 920 if ($this->parsingCss->value['text-align']=='justify' && $e>1) { 921 $this->pdf->setWordSpacing(($wMax-$w)/($e-1)); 922 } else { 923 $this->pdf->setWordSpacing(0); 924 } 925 } 926 927 /** 928 * prepare HTML2PDF::$_subobj (used for create the sub HTML2PDF objects 929 * 930 * @access protected 931 */ 932 protected function _prepareSubObj() 933 { 934 $pdf = null; 935 936 // create the sub object 937 HTML2PDF::$_subobj = new HTML2PDF( 938 $this->_orientation, 939 $this->_format, 940 $this->_langue, 941 $this->_unicode, 942 $this->_encoding, 943 array($this->_defaultLeft,$this->_defaultTop,$this->_defaultRight,$this->_defaultBottom) 944 ); 945 946 // init 947 HTML2PDF::$_subobj->setTestTdInOnePage($this->_testTdInOnepage); 948 HTML2PDF::$_subobj->setTestIsImage($this->_testIsImage); 949 HTML2PDF::$_subobj->setTestIsDeprecated($this->_testIsDeprecated); 950 HTML2PDF::$_subobj->setDefaultFont($this->_defaultFont); 951 HTML2PDF::$_subobj->parsingCss->css = &$this->parsingCss->css; 952 HTML2PDF::$_subobj->parsingCss->cssKeys = &$this->parsingCss->cssKeys; 953 954 // clone font from the original PDF 955 HTML2PDF::$_subobj->pdf->cloneFontFrom($this->pdf); 956 957 // remove the link to the parent 958 HTML2PDF::$_subobj->parsingCss->setPdfParent($pdf); 959 } 960 961 /** 962 * create a sub HTML2PDF, to calculate the multi-tables 963 * 964 * @access protected 965 * @param &HTML2PDF $subHtml sub HTML2PDF to create 966 * @param integer $cellmargin if in a TD : cellmargin of this td 967 */ 968 protected function _createSubHTML(&$subHtml, $cellmargin=0) 969 { 970 // prepare the subObject, if never prepare before 971 if (HTML2PDF::$_subobj===null) { 972 $this->_prepareSubObj(); 973 } 974 975 // calculate the width to use 976 if ($this->parsingCss->value['width']) { 977 $marge = $cellmargin*2; 978 $marge+= $this->parsingCss->value['padding']['l'] + $this->parsingCss->value['padding']['r']; 979 $marge+= $this->parsingCss->value['border']['l']['width'] + $this->parsingCss->value['border']['r']['width']; 980 $marge = $this->pdf->getW() - $this->parsingCss->value['width'] + $marge; 981 } else { 982 $marge = $this->_margeLeft+$this->_margeRight; 983 } 984 985 // BUGFIX : we have to call the method, because of a bug in php 5.1.6 986 HTML2PDF::$_subobj->pdf->getPage(); 987 988 // clone the sub oject 989 $subHtml = clone HTML2PDF::$_subobj; 990 $subHtml->parsingCss->table = $this->parsingCss->table; 991 $subHtml->parsingCss->value = $this->parsingCss->value; 992 $subHtml->initSubHtml( 993 $this->_format, 994 $this->_orientation, 995 $marge, 996 $this->_page, 997 $this->_defList, 998 $this->pdf->getMyLastPageGroup(), 999 $this->pdf->getMyLastPageGroupNb() 1000 ); 1001 } 1002 1003 /** 1004 * destroy a subHTML2PDF 1005 * 1006 * @access protected 1007 */ 1008 protected function _destroySubHTML(&$subHtml) 1009 { 1010 unset($subHtml); 1011 $subHtml = null; 1012 } 1013 1014 /** 1015 * Convert a arabic number in roman number 1016 * 1017 * @access protected 1018 * @param integer $nbArabic 1019 * @return string $nbRoman 1020 */ 1021 protected function _listeArab2Rom($nbArabic) 1022 { 1023 $nbBaseTen = array('I','X','C','M'); 1024 $nbBaseFive = array('V','L','D'); 1025 $nbRoman = ''; 1026 1027 if ($nbArabic<1) return $nbArabic; 1028 if ($nbArabic>3999) return $nbArabic; 1029 1030 for ($i=3; $i>=0 ; $i--) { 1031 $chiffre=floor($nbArabic/pow(10, $i)); 1032 if ($chiffre>=1) { 1033 $nbArabic=$nbArabic-$chiffre*pow(10, $i); 1034 if ($chiffre<=3) { 1035 for ($j=$chiffre; $j>=1; $j--) { 1036 $nbRoman=$nbRoman.$nbBaseTen[$i]; 1037 } 1038 } else if ($chiffre==9) { 1039 $nbRoman=$nbRoman.$nbBaseTen[$i].$nbBaseTen[$i+1]; 1040 } else if ($chiffre==4) { 1041 $nbRoman=$nbRoman.$nbBaseTen[$i].$nbBaseFive[$i]; 1042 } else { 1043 $nbRoman=$nbRoman.$nbBaseFive[$i]; 1044 for ($j=$chiffre-5; $j>=1; $j--) { 1045 $nbRoman=$nbRoman.$nbBaseTen[$i]; 1046 } 1047 } 1048 } 1049 } 1050 return $nbRoman; 1051 } 1052 1053 /** 1054 * add a LI to the current level 1055 * 1056 * @access protected 1057 */ 1058 protected function _listeAddLi() 1059 { 1060 $this->_defList[count($this->_defList)-1]['nb']++; 1061 } 1062 1063 /** 1064 * get the width to use for the column of the list 1065 * 1066 * @access protected 1067 * @return string $width 1068 */ 1069 protected function _listeGetWidth() 1070 { 1071 return '7mm'; 1072 } 1073 1074 /** 1075 * get the padding to use for the column of the list 1076 * 1077 * @access protected 1078 * @return string $padding 1079 */ 1080 protected function _listeGetPadding() 1081 { 1082 return '1mm'; 1083 } 1084 1085 /** 1086 * get the information of the li on the current level 1087 * 1088 * @access protected 1089 * @return array(fontName, small size, string) 1090 */ 1091 protected function _listeGetLi() 1092 { 1093 $im = $this->_defList[count($this->_defList)-1]['img']; 1094 $st = $this->_defList[count($this->_defList)-1]['style']; 1095 $nb = $this->_defList[count($this->_defList)-1]['nb']; 1096 $up = (substr($st, 0, 6)=='upper-'); 1097 1098 if ($im) return array(false, false, $im); 1099 1100 switch($st) 1101 { 1102 case 'none': 1103 return array('helvetica', true, ' '); 1104 1105 case 'upper-alpha': 1106 case 'lower-alpha': 1107 $str = ''; 1108 while ($nb>26) { 1109 $str = chr(96+$nb%26).$str; 1110 $nb = floor($nb/26); 1111 } 1112 $str = chr(96+$nb).$str; 1113 1114 return array('helvetica', false, ($up ? strtoupper($str) : $str).'.'); 1115 1116 case 'upper-roman': 1117 case 'lower-roman': 1118 $str = $this->_listeArab2Rom($nb); 1119 1120 return array('helvetica', false, ($up ? strtoupper($str) : $str).'.'); 1121 1122 case 'decimal': 1123 return array('helvetica', false, $nb.'.'); 1124 1125 case 'square': 1126 return array('zapfdingbats', true, chr(110)); 1127 1128 case 'circle': 1129 return array('zapfdingbats', true, chr(109)); 1130 1131 case 'disc': 1132 default: 1133 return array('zapfdingbats', true, chr(108)); 1134 } 1135 } 1136 1137 /** 1138 * add a level to the list 1139 * 1140 * @access protected 1141 * @param string $type : ul, ol 1142 * @param string $style : lower-alpha, ... 1143 * @param string $img 1144 */ 1145 protected function _listeAddLevel($type = 'ul', $style = '', $img = null) 1146 { 1147 // get the url of the image, if we want to use a image 1148 if ($img) { 1149 if (preg_match('/^url\(([^)]+)\)$/isU', trim($img), $match)) { 1150 $img = $match[1]; 1151 } else { 1152 $img = null; 1153 } 1154 } else { 1155 $img = null; 1156 } 1157 1158 // prepare the datas 1159 if (!in_array($type, array('ul', 'ol'))) $type = 'ul'; 1160 if (!in_array($style, array('lower-alpha', 'upper-alpha', 'upper-roman', 'lower-roman', 'decimal', 'square', 'circle', 'disc', 'none'))) $style = ''; 1161 1162 if (!$style) { 1163 if ($type=='ul') $style = 'disc'; 1164 else $style = 'decimal'; 1165 } 1166 1167 // add the new level 1168 $this->_defList[count($this->_defList)] = array('style' => $style, 'nb' => 0, 'img' => $img); 1169 } 1170 1171 /** 1172 * remove a level to the list 1173 * 1174 * @access protected 1175 */ 1176 protected function _listeDelLevel() 1177 { 1178 if (count($this->_defList)) { 1179 unset($this->_defList[count($this->_defList)-1]); 1180 $this->_defList = array_values($this->_defList); 1181 } 1182 } 1183 1184 /** 1185 * execute the actions to convert the html 1186 * 1187 * @access protected 1188 */ 1189 protected function _makeHTMLcode() 1190 { 1191 // foreach elements of the parsing 1192 for ($this->_parsePos=0; $this->_parsePos<count($this->parsingHtml->code); $this->_parsePos++) { 1193 1194 // get the action to do 1195 $action = $this->parsingHtml->code[$this->_parsePos]; 1196 1197 // if it is a opening of table / ul / ol 1198 if (in_array($action['name'], array('table', 'ul', 'ol')) && !$action['close']) { 1199 1200 // we will work as a sub HTML to calculate the size of the element 1201 $this->_subPart = true; 1202 1203 // get the name of the opening tag 1204 $tagOpen = $action['name']; 1205 1206 // save the actual pos on the parsing 1207 $this->_tempPos = $this->_parsePos; 1208 1209 // foreach elements, while we are in the opened tag 1210 while (isset($this->parsingHtml->code[$this->_tempPos]) && !($this->parsingHtml->code[$this->_tempPos]['name']==$tagOpen && $this->parsingHtml->code[$this->_tempPos]['close'])) { 1211 // make the action 1212 $this->_executeAction($this->parsingHtml->code[$this->_tempPos]); 1213 $this->_tempPos++; 1214 } 1215 1216 // execute the closure of the tag 1217 if (isset($this->parsingHtml->code[$this->_tempPos])) { 1218 $this->_executeAction($this->parsingHtml->code[$this->_tempPos]); 1219 } 1220 1221 // end of the sub part 1222 $this->_subPart = false; 1223 } 1224 1225 // execute the action 1226 $this->_executeAction($action); 1227 } 1228 } 1229 1230 /** 1231 * execute the action from the parsing 1232 * 1233 * @access protected 1234 * @param array $action 1235 */ 1236 protected function _executeAction($action) 1237 { 1238 // name of the action 1239 $fnc = ($action['close'] ? '_tag_close_' : '_tag_open_').strtoupper($action['name']); 1240 1241 // parameters of the action 1242 $param = $action['param']; 1243 1244 // if it the first action of the first page, and if it is not a open tag of PAGE => create the new page 1245 if ($fnc!='_tag_open_PAGE' && $this->_firstPage) { 1246 $this->_setNewPage(); 1247 } 1248 1249 // the action must exist 1250 if (!is_callable(array(&$this, $fnc))) { 1251 throw new HTML2PDF_exception(1, strtoupper($action['name']), $this->parsingHtml->getHtmlErrorCode($action['html_pos'])); 1252 } 1253 1254 // lauch the action 1255 $res = $this->{$fnc}($param); 1256 1257 // save the name of the action 1258 $this->_previousCall = $fnc; 1259 1260 // return the result 1261 return $res; 1262 } 1263 1264 /** 1265 * get the position of the element on the current line, depending on his height 1266 * 1267 * @access protected 1268 * @param float $h 1269 * @return float 1270 */ 1271 protected function _getElementY($h) 1272 { 1273 if ($this->_subPart || $this->_isSubPart || !$this->_currentH || $this->_currentH<$h) 1274 return 0; 1275 1276 return ($this->_currentH-$h)*0.8; 1277 } 1278 1279 /** 1280 * make a break line 1281 * 1282 * @access protected 1283 * @param float $h current line height 1284 * @param integer $curr real current position in the text, if new line in the write of a text 1285 */ 1286 protected function _makeBreakLine($h, $curr = null) 1287 { 1288 if ($h) { 1289 if (($this->pdf->getY()+$h<$this->pdf->getH() - $this->pdf->getbMargin()) || $this->_isInOverflow || $this->_isInFooter) 1290 $this->_setNewLine($h, $curr); 1291 else 1292 $this->_setNewPage(null, '', null, $curr); 1293 } else { 1294 $this->_setNewPositionForNewLine($curr); 1295 } 1296 1297 $this->_maxH = 0; 1298 $this->_maxE = 0; 1299 } 1300 1301 /** 1302 * display a image 1303 * 1304 * @access protected 1305 * @param string $src 1306 * @param boolean $subLi if true=image of a list 1307 * @return boolean depending on "isForOneLine" 1308 */ 1309 protected function _drawImage($src, $subLi=false) 1310 { 1311 // get the size of the image 1312 // WARNING : if URL, "allow_url_fopen" must turned to "on" in php.ini 1313 $infos=@getimagesize($src); 1314 1315 // if the image does not exist, or can not be loaded 1316 if (count($infos)<2) { 1317 // if the test is activ => exception 1318 if ($this->_testIsImage) { 1319 throw new HTML2PDF_exception(6, $src); 1320 } 1321 1322 // else, display a gray rectangle 1323 $src = null; 1324 $infos = array(16, 16); 1325 } 1326 1327 // convert the size of the image in the unit of the PDF 1328 $imageWidth = $infos[0]/$this->pdf->getK(); 1329 $imageHeight = $infos[1]/$this->pdf->getK(); 1330 1331 // calculate the size from the css style 1332 if ($this->parsingCss->value['width'] && $this->parsingCss->value['height']) { 1333 $w = $this->parsingCss->value['width']; 1334 $h = $this->parsingCss->value['height']; 1335 } else if ($this->parsingCss->value['width']) { 1336 $w = $this->parsingCss->value['width']; 1337 $h = $imageHeight*$w/$imageWidth; 1338 } else if ($this->parsingCss->value['height']) { 1339 $h = $this->parsingCss->value['height']; 1340 $w = $imageWidth*$h/$imageHeight; 1341 } else { 1342 // convert px to pt 1343 $w = 72./96.*$imageWidth; 1344 $h = 72./96.*$imageHeight; 1345 } 1346 1347 // are we in a float 1348 $float = $this->parsingCss->getFloat(); 1349 1350 // if we are in a float, but if something else if on the line => Break Line 1351 if ($float && $this->_maxH) { 1352 // make the break line (false if we are in "_isForOneLine" mode) 1353 if (!$this->_tag_open_BR(array())) { 1354 return false; 1355 } 1356 } 1357 1358 // position of the image 1359 $x = $this->pdf->getX(); 1360 $y = $this->pdf->getY(); 1361 1362 // if the image can not be put on the current line => new line 1363 if (!$float && ($x + $w>$this->pdf->getW() - $this->pdf->getrMargin()) && $this->_maxH) { 1364 if ($this->_isForOneLine) { 1365 return false; 1366 } 1367 1368 // set the new line 1369 $hnl = max($this->_maxH, $this->parsingCss->getLineHeight()); 1370 $this->_setNewLine($hnl); 1371 1372 // get the new position 1373 $x = $this->pdf->getX(); 1374 $y = $this->pdf->getY(); 1375 } 1376 1377 // if the image can not be put on the current page 1378 if (($y + $h>$this->pdf->getH() - $this->pdf->getbMargin()) && !$this->_isInOverflow) { 1379 // new page 1380 $this->_setNewPage(); 1381 1382 // get the new position 1383 $x = $this->pdf->getX(); 1384 $y = $this->pdf->getY(); 1385 } 1386 1387 // correction for display the image of a list 1388 $hT = 0.80*$this->parsingCss->value['font-size']; 1389 if ($subLi && $h<$hT) { 1390 $y+=($hT-$h); 1391 } 1392 1393 // add the margin top 1394 $yc = $y-$this->parsingCss->value['margin']['t']; 1395 1396 // get the width and the position of the parent 1397 $old = $this->parsingCss->getOldValues(); 1398 if ( $old['width']) { 1399 $parentWidth = $old['width']; 1400 $parentX = $x; 1401 } else { 1402 $parentWidth = $this->pdf->getW() - $this->pdf->getlMargin() - $this->pdf->getrMargin(); 1403 $parentX = $this->pdf->getlMargin(); 1404 } 1405 1406 // if we are in a gloat => adapt the parent position and width 1407 if ($float) { 1408 list($lx, $rx) = $this->_getMargins($yc); 1409 $parentX = $lx; 1410 $parentWidth = $rx-$lx; 1411 } 1412 1413 // calculate the position of the image, if align to the right 1414 if ($parentWidth>$w && $float!='left') { 1415 if ($float=='right' || $this->parsingCss->value['text-align']=='li_right') $x = $parentX + $parentWidth - $w-$this->parsingCss->value['margin']['r']-$this->parsingCss->value['margin']['l']; 1416 } 1417 1418 // display the image 1419 if (!$this->_subPart && !$this->_isSubPart) { 1420 if ($src) { 1421 $this->pdf->Image($src, $x, $y, $w, $h, '', $this->_isInLink); 1422 } else { 1423 // rectangle if the image can not be loaded 1424 $this->pdf->setFillColorArray(array(240, 220, 220)); 1425 $this->pdf->Rect($x, $y, $w, $h, 'F'); 1426 } 1427 } 1428 1429 // apply the margins 1430 $x-= $this->parsingCss->value['margin']['l']; 1431 $y-= $this->parsingCss->value['margin']['t']; 1432 $w+= $this->parsingCss->value['margin']['l'] + $this->parsingCss->value['margin']['r']; 1433 $h+= $this->parsingCss->value['margin']['t'] + $this->parsingCss->value['margin']['b']; 1434 1435 if ($float=='left') { 1436 // save the current max 1437 $this->_maxX = max($this->_maxX, $x+$w); 1438 $this->_maxY = max($this->_maxY, $y+$h); 1439 1440 // add the image to the margins 1441 $this->_addMargins($float, $x, $y, $x+$w, $y+$h); 1442 1443 // get the new position 1444 list($lx, $rx) = $this->_getMargins($yc); 1445 $this->pdf->setXY($lx, $yc); 1446 } else if ($float=='right') { 1447 // save the current max. We don't save the X because it is not the real max of the line 1448 $this->_maxY = max($this->_maxY, $y+$h); 1449 1450 // add the image to the margins 1451 $this->_addMargins($float, $x, $y, $x+$w, $y+$h); 1452 1453 // get the new position 1454 list($lx, $rx) = $this->_getMargins($yc); 1455 $this->pdf->setXY($lx, $yc); 1456 } else { 1457 // set the new position at the end of the image 1458 $this->pdf->setX($x+$w); 1459 1460 // save the current max 1461 $this->_maxX = max($this->_maxX, $x+$w); 1462 $this->_maxY = max($this->_maxY, $y+$h); 1463 $this->_maxH = max($this->_maxH, $h); 1464 } 1465 1466 return true; 1467 } 1468 1469 /** 1470 * draw a rectangle 1471 * 1472 * @access protected 1473 * @param float $x 1474 * @param float $y 1475 * @param float $w 1476 * @param float $h 1477 * @param array $border 1478 * @param float $padding - internal marge of the rectanble => not used, but... 1479 * @param float $margin - external marge of the rectanble 1480 * @param array $background 1481 * @return boolean 1482 */ 1483 protected function _drawRectangle($x, $y, $w, $h, $border, $padding, $margin, $background) 1484 { 1485 // if we are in a subpart or if height is null => return false 1486 if ($this->_subPart || $this->_isSubPart || $h===null) return false; 1487 1488 // add the margin 1489 $x+= $margin; 1490 $y+= $margin; 1491 $w-= $margin*2; 1492 $h-= $margin*2; 1493 1494 // get the radius of the border 1495 $outTL = $border['radius']['tl']; 1496 $outTR = $border['radius']['tr']; 1497 $outBR = $border['radius']['br']; 1498 $outBL = $border['radius']['bl']; 1499 1500 // prepare the out radius 1501 $outTL = ($outTL[0] && $outTL[1]) ? $outTL : null; 1502 $outTR = ($outTR[0] && $outTR[1]) ? $outTR : null; 1503 $outBR = ($outBR[0] && $outBR[1]) ? $outBR : null; 1504 $outBL = ($outBL[0] && $outBL[1]) ? $outBL : null; 1505 1506 // prepare the in radius 1507 $inTL = $outTL; 1508 $inTR = $outTR; 1509 $inBR = $outBR; 1510 $inBL = $outBL; 1511 1512 if (is_array($inTL)) { 1513 $inTL[0]-= $border['l']['width']; 1514 $inTL[1]-= $border['t']['width']; 1515 } 1516 if (is_array($inTR)) { 1517 $inTR[0]-= $border['r']['width']; 1518 $inTR[1]-= $border['t']['width']; 1519 } 1520 if (is_array($inBR)) { 1521 $inBR[0]-= $border['r']['width']; 1522 $inBR[1]-= $border['b']['width']; 1523 } 1524 if (is_array($inBL)) { 1525 $inBL[0]-= $border['l']['width']; 1526 $inBL[1]-= $border['b']['width']; 1527 } 1528 1529 if ($inTL[0]<=0 || $inTL[1]<=0) $inTL = null; 1530 if ($inTR[0]<=0 || $inTR[1]<=0) $inTR = null; 1531 if ($inBR[0]<=0 || $inBR[1]<=0) $inBR = null; 1532 if ($inBL[0]<=0 || $inBL[1]<=0) $inBL = null; 1533 1534 // prepare the background color 1535 $pdfStyle = ''; 1536 if ($background['color']) { 1537 $this->pdf->setFillColorArray($background['color']); 1538 $pdfStyle.= 'F'; 1539 } 1540 1541 // if we have a background to fill => fill it with a path (because of the radius) 1542 if ($pdfStyle) { 1543 $this->pdf->clippingPathStart($x, $y, $w, $h, $outTL, $outTR, $outBL, $outBR); 1544 $this->pdf->Rect($x, $y, $w, $h, $pdfStyle); 1545 $this->pdf->clippingPathStop(); 1546 } 1547 1548 // prepare the background image 1549 if ($background['image']) { 1550 $iName = $background['image']; 1551 $iPosition = $background['position']!==null ? $background['position'] : array(0, 0); 1552 $iRepeat = $background['repeat']!==null ? $background['repeat'] : array(true, true); 1553 1554 // size of the background without the borders 1555 $bX = $x; 1556 $bY = $y; 1557 $bW = $w; 1558 $bH = $h; 1559 1560 if ($border['b']['width']) { 1561 $bH-= $border['b']['width']; 1562 } 1563 if ($border['l']['width']) { 1564 $bW-= $border['l']['width']; 1565 $bX+= $border['l']['width']; 1566 } 1567 if ($border['t']['width']) { 1568 $bH-= $border['t']['width']; 1569 $bY+= $border['t']['width']; 1570 } 1571 if ($border['r']['width']) { 1572 $bW-= $border['r']['width']; 1573 } 1574 1575 // get the size of the image 1576 // WARNING : if URL, "allow_url_fopen" must turned to "on" in php.ini 1577 $imageInfos=@getimagesize($iName); 1578 1579 // if the image can not be loaded 1580 if (count($imageInfos)<2) { 1581 if ($this->_testIsImage) { 1582 throw new HTML2PDF_exception(6, $iName); 1583 } 1584 } else { 1585 // convert the size of the image from pixel to the unit of the PDF 1586 $imageWidth = 72./96.*$imageInfos[0]/$this->pdf->getK(); 1587 $imageHeight = 72./96.*$imageInfos[1]/$this->pdf->getK(); 1588 1589 // prepare the position of the backgroung 1590 if ($iRepeat[0]) $iPosition[0] = $bX; 1591 else if (preg_match('/^([-]?[0-9\.]+)%/isU', $iPosition[0], $match)) $iPosition[0] = $bX + $match[1]*($bW-$imageWidth)/100; 1592 else $iPosition[0] = $bX+$iPosition[0]; 1593 1594 if ($iRepeat[1]) $iPosition[1] = $bY; 1595 else if (preg_match('/^([-]?[0-9\.]+)%/isU', $iPosition[1], $match)) $iPosition[1] = $bY + $match[1]*($bH-$imageHeight)/100; 1596 else $iPosition[1] = $bY+$iPosition[1]; 1597 1598 $imageXmin = $bX; 1599 $imageXmax = $bX+$bW; 1600 $imageYmin = $bY; 1601 $imageYmax = $bY+$bH; 1602 1603 if (!$iRepeat[0] && !$iRepeat[1]) { 1604 $imageXmin = $iPosition[0]; $imageXmax = $iPosition[0]+$imageWidth; 1605 $imageYmin = $iPosition[1]; $imageYmax = $iPosition[1]+$imageHeight; 1606 } else if ($iRepeat[0] && !$iRepeat[1]) { 1607 $imageYmin = $iPosition[1]; $imageYmax = $iPosition[1]+$imageHeight; 1608 } else if (!$iRepeat[0] && $iRepeat[1]) { 1609 $imageXmin = $iPosition[0]; $imageXmax = $iPosition[0]+$imageWidth; 1610 } 1611 1612 // build the path to display the image (because of radius) 1613 $this->pdf->clippingPathStart($bX, $bY, $bW, $bH, $inTL, $inTR, $inBL, $inBR); 1614 1615 // repeat the image 1616 for ($iY=$imageYmin; $iY<$imageYmax; $iY+=$imageHeight) { 1617 for ($iX=$imageXmin; $iX<$imageXmax; $iX+=$imageWidth) { 1618 $cX = null; 1619 $cY = null; 1620 $cW = $imageWidth; 1621 $cH = $imageHeight; 1622 if ($imageYmax-$iY<$imageHeight) { 1623 $cX = $iX; 1624 $cY = $iY; 1625 $cH = $imageYmax-$iY; 1626 } 1627 if ($imageXmax-$iX<$imageWidth) { 1628 $cX = $iX; 1629 $cY = $iY; 1630 $cW = $imageXmax-$iX; 1631 } 1632 1633 $this->pdf->Image($iName, $iX, $iY, $imageWidth, $imageHeight, '', ''); 1634 } 1635 } 1636 1637 // end of the path 1638 $this->pdf->clippingPathStop(); 1639 } 1640 } 1641 1642 // adding some loose (0.01mm) 1643 $loose = 0.01; 1644 $x-= $loose; 1645 $y-= $loose; 1646 $w+= 2.*$loose; 1647 $h+= 2.*$loose; 1648 if ($border['l']['width']) $border['l']['width']+= 2.*$loose; 1649 if ($border['t']['width']) $border['t']['width']+= 2.*$loose; 1650 if ($border['r']['width']) $border['r']['width']+= 2.*$loose; 1651 if ($border['b']['width']) $border['b']['width']+= 2.*$loose; 1652 1653 // prepare the test on borders 1654 $testBl = ($border['l']['width'] && $border['l']['color'][0]!==null); 1655 $testBt = ($border['t']['width'] && $border['t']['color'][0]!==null); 1656 $testBr = ($border['r']['width'] && $border['r']['color'][0]!==null); 1657 $testBb = ($border['b']['width'] && $border['b']['color'][0]!==null); 1658 1659 // draw the radius bottom-left 1660 if (is_array($outBL) && ($testBb || $testBl)) { 1661 if ($inBL) { 1662 $courbe = array(); 1663 $courbe[] = $x+$outBL[0]; $courbe[] = $y+$h; 1664 $courbe[] = $x; $courbe[] = $y+$h-$outBL[1]; 1665 $courbe[] = $x+$outBL[0]; $courbe[] = $y+$h-$border['b']['width']; 1666 $courbe[] = $x+$border['l']['width']; $courbe[] = $y+$h-$outBL[1]; 1667 $courbe[] = $x+$outBL[0]; $courbe[] = $y+$h-$outBL[1]; 1668 } else { 1669 $courbe = array(); 1670 $courbe[] = $x+$outBL[0]; $courbe[] = $y+$h; 1671 $courbe[] = $x; $courbe[] = $y+$h-$outBL[1]; 1672 $courbe[] = $x+$border['l']['width']; $courbe[] = $y+$h-$border['b']['width']; 1673 $courbe[] = $x+$outBL[0]; $courbe[] = $y+$h-$outBL[1]; 1674 } 1675 $this->_drawCurve($courbe, $border['l']['color']); 1676 } 1677 1678 // draw the radius left-top 1679 if (is_array($outTL) && ($testBt || $testBl)) { 1680 if ($inTL) { 1681 $courbe = array(); 1682 $courbe[] = $x; $courbe[] = $y+$outTL[1]; 1683 $courbe[] = $x+$outTL[0]; $courbe[] = $y; 1684 $courbe[] = $x+$border['l']['width']; $courbe[] = $y+$outTL[1]; 1685 $courbe[] = $x+$outTL[0]; $courbe[] = $y+$border['t']['width']; 1686 $courbe[] = $x+$outTL[0]; $courbe[] = $y+$outTL[1]; 1687 } else { 1688 $courbe = array(); 1689 $courbe[] = $x; $courbe[] = $y+$outTL[1]; 1690 $courbe[] = $x+$outTL[0]; $courbe[] = $y; 1691 $courbe[] = $x+$border['l']['width']; $courbe[] = $y+$border['t']['width']; 1692 $courbe[] = $x+$outTL[0]; $courbe[] = $y+$outTL[1]; 1693 } 1694 $this->_drawCurve($courbe, $border['t']['color']); 1695 } 1696 1697 // draw the radius top-right 1698 if (is_array($outTR) && ($testBt || $testBr)) { 1699 if ($inTR) { 1700 $courbe = array(); 1701 $courbe[] = $x+$w-$outTR[0]; $courbe[] = $y; 1702 $courbe[] = $x+$w; $courbe[] = $y+$outTR[1]; 1703 $courbe[] = $x+$w-$outTR[0]; $courbe[] = $y+$border['t']['width']; 1704 $courbe[] = $x+$w-$border['r']['width']; $courbe[] = $y+$outTR[1]; 1705 $courbe[] = $x+$w-$outTR[0]; $courbe[] = $y+$outTR[1]; 1706 } else { 1707 $courbe = array(); 1708 $courbe[] = $x+$w-$outTR[0]; $courbe[] = $y; 1709 $courbe[] = $x+$w; $courbe[] = $y+$outTR[1]; 1710 $courbe[] = $x+$w-$border['r']['width']; $courbe[] = $y+$border['t']['width']; 1711 $courbe[] = $x+$w-$outTR[0]; $courbe[] = $y+$outTR[1]; 1712 } 1713 $this->_drawCurve($courbe, $border['r']['color']); 1714 } 1715 1716 // draw the radius right-bottom 1717 if (is_array($outBR) && ($testBb || $testBr)) { 1718 if ($inBR) { 1719 $courbe = array(); 1720 $courbe[] = $x+$w; $courbe[] = $y+$h-$outBR[1]; 1721 $courbe[] = $x+$w-$outBR[0]; $courbe[] = $y+$h; 1722 $courbe[] = $x+$w-$border['r']['width']; $courbe[] = $y+$h-$outBR[1]; 1723 $courbe[] = $x+$w-$outBR[0]; $courbe[] = $y+$h-$border['b']['width']; 1724 $courbe[] = $x+$w-$outBR[0]; $courbe[] = $y+$h-$outBR[1]; 1725 } else { 1726 $courbe = array(); 1727 $courbe[] = $x+$w; $courbe[] = $y+$h-$outBR[1]; 1728 $courbe[] = $x+$w-$outBR[0]; $courbe[] = $y+$h; 1729 $courbe[] = $x+$w-$border['r']['width']; $courbe[] = $y+$h-$border['b']['width']; 1730 $courbe[] = $x+$w-$outBR[0]; $courbe[] = $y+$h-$outBR[1]; 1731 } 1732 $this->_drawCurve($courbe, $border['b']['color']); 1733 } 1734 1735 // draw the left border 1736 if ($testBl) { 1737 $pt = array(); 1738 $pt[] = $x; $pt[] = $y+$h; 1739 $pt[] = $x; $pt[] = $y+$h-$border['b']['width']; 1740 $pt[] = $x; $pt[] = $y+$border['t']['width']; 1741 $pt[] = $x; $pt[] = $y; 1742 $pt[] = $x+$border['l']['width']; $pt[] = $y+$border['t']['width']; 1743 $pt[] = $x+$border['l']['width']; $pt[] = $y+$h-$border['b']['width']; 1744 1745 $bord = 3; 1746 if (is_array($outBL)) { 1747 $bord-=1; 1748 $pt[3] -= $outBL[1] - $border['b']['width']; 1749 if ($inBL) $pt[11]-= $inBL[1]; 1750 unset($pt[0]);unset($pt[1]); 1751 } 1752 if (is_array($outTL)) { 1753 $bord-=2; 1754 $pt[5] += $outTL[1]-$border['t']['width']; 1755 if ($inTL) $pt[9] += $inTL[1]; 1756 unset($pt[6]);unset($pt[7]); 1757 } 1758 1759 $pt = array_values($pt); 1760 $this->_drawLine($pt, $border['l']['color'], $border['l']['type'], $border['l']['width'], $bord); 1761 } 1762 1763 // draw the top border 1764 if ($testBt) { 1765 $pt = array(); 1766 $pt[] = $x; $pt[] = $y; 1767 $pt[] = $x+$border['l']['width']; $pt[] = $y; 1768 $pt[] = $x+$w-$border['r']['width']; $pt[] = $y; 1769 $pt[] = $x+$w; $pt[] = $y; 1770 $pt[] = $x+$w-$border['r']['width']; $pt[] = $y+$border['t']['width']; 1771 $pt[] = $x+$border['l']['width']; $pt[] = $y+$border['t']['width']; 1772 1773 $bord = 3; 1774 if (is_array($outTL)) { 1775 $bord-=1; 1776 $pt[2] += $outTL[0] - $border['l']['width']; 1777 if ($inTL) $pt[10]+= $inTL[0]; 1778 unset($pt[0]);unset($pt[1]); 1779 } 1780 if (is_array($outTR)) { 1781 $bord-=2; 1782 $pt[4] -= $outTR[0] - $border['r']['width']; 1783 if ($inTR) $pt[8] -= $inTR[0]; 1784 unset($pt[6]);unset($pt[7]); 1785 } 1786 1787 $pt = array_values($pt); 1788 $this->_drawLine($pt, $border['t']['color'], $border['t']['type'], $border['t']['width'], $bord); 1789 } 1790 1791 // draw the right border 1792 if ($testBr) { 1793 $pt = array(); 1794 $pt[] = $x+$w; $pt[] = $y; 1795 $pt[] = $x+$w; $pt[] = $y+$border['t']['width']; 1796 $pt[] = $x+$w; $pt[] = $y+$h-$border['b']['width']; 1797 $pt[] = $x+$w; $pt[] = $y+$h; 1798 $pt[] = $x+$w-$border['r']['width']; $pt[] = $y+$h-$border['b']['width']; 1799 $pt[] = $x+$w-$border['r']['width']; $pt[] = $y+$border['t']['width']; 1800 1801 $bord = 3; 1802 if (is_array($outTR)) { 1803 $bord-=1; 1804 $pt[3] += $outTR[1] - $border['t']['width']; 1805 if ($inTR) $pt[11]+= $inTR[1]; 1806 unset($pt[0]);unset($pt[1]); 1807 } 1808 if (is_array($outBR)) { 1809 $bord-=2; 1810 $pt[5] -= $outBR[1] - $border['b']['width']; 1811 if ($inBR) $pt[9] -= $inBR[1]; 1812 unset($pt[6]);unset($pt[7]); 1813 } 1814 1815 $pt = array_values($pt); 1816 $this->_drawLine($pt, $border['r']['color'], $border['r']['type'], $border['r']['width'], $bord); 1817 } 1818 1819 // draw the bottom border 1820 if ($testBb) { 1821 $pt = array(); 1822 $pt[] = $x+$w; $pt[] = $y+$h; 1823 $pt[] = $x+$w-$border['r']['width']; $pt[] = $y+$h; 1824 $pt[] = $x+$border['l']['width']; $pt[] = $y+$h; 1825 $pt[] = $x; $pt[] = $y+$h; 1826 $pt[] = $x+$border['l']['width']; $pt[] = $y+$h-$border['b']['width']; 1827 $pt[] = $x+$w-$border['r']['width']; $pt[] = $y+$h-$border['b']['width']; 1828 1829 $bord = 3; 1830 if (is_array($outBL)) { 1831 $bord-=2; 1832 $pt[4] += $outBL[0] - $border['l']['width']; 1833 if ($inBL) $pt[8] += $inBL[0]; 1834 unset($pt[6]);unset($pt[7]); 1835 } 1836 if (is_array($outBR)) { 1837 $bord-=1; 1838 $pt[2] -= $outBR[0] - $border['r']['width']; 1839 if ($inBR) $pt[10]-= $inBR[0]; 1840 unset($pt[0]);unset($pt[1]); 1841 1842 } 1843 1844 $pt = array_values($pt); 1845 $this->_drawLine($pt, $border['b']['color'], $border['b']['type'], $border['b']['width'], $bord); 1846 } 1847 1848 if ($background['color']) { 1849 $this->pdf->setFillColorArray($background['color']); 1850 } 1851 1852 return true; 1853 } 1854 1855 /** 1856 * draw a curve (for border radius) 1857 * 1858 * @access protected 1859 * @param array $pt 1860 * @param array $color 1861 */ 1862 protected function _drawCurve($pt, $color) 1863 { 1864 $this->pdf->setFillColorArray($color); 1865 1866 if (count($pt)==10) 1867 $this->pdf->drawCurve($pt[0], $pt[1], $pt[2], $pt[3], $pt[4], $pt[5], $pt[6], $pt[7], $pt[8], $pt[9]); 1868 else 1869 $this->pdf->drawCorner($pt[0], $pt[1], $pt[2], $pt[3], $pt[4], $pt[5], $pt[6], $pt[7]); 1870 } 1871 1872 /** 1873 * draw a ligne with a specific type, and specific start and end for radius 1874 * 1875 * @access protected 1876 * @param array $pt 1877 * @param float $color 1878 * @param string $type (dashed, dotted, double, solid) 1879 * @param float $width 1880 * @param integer $radius (binary from 0 to 3 with 1=>start with a radius, 2=>end with a radius) 1881 */ 1882 protected function _drawLine($pt, $color, $type, $width, $radius=3) 1883 { 1884 // set the fill color 1885 $this->pdf->setFillColorArray($color); 1886 1887 // if dashed or dotted 1888 if ($type=='dashed' || $type=='dotted') { 1889 1890 // clean the end of the line, if radius 1891 if ($radius==1) { 1892 $tmp = array(); $tmp[]=$pt[0]; $tmp[]=$pt[1]; $tmp[]=$pt[2]; $tmp[]=$pt[3]; $tmp[]=$pt[8]; $tmp[]=$pt[9]; 1893 $this->pdf->Polygon($tmp, 'F'); 1894 1895 $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]; 1896 $pt = $tmp; 1897 } else if ($radius==2) { 1898 $tmp = array(); $tmp[]=$pt[2]; $tmp[]=$pt[3]; $tmp[]=$pt[4]; $tmp[]=$pt[5]; $tmp[]=$pt[6]; $tmp[]=$pt[7]; 1899 $this->pdf->Polygon($tmp, 'F'); 1900 1901 $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]; 1902 $pt = $tmp; 1903 } else if ($radius==3) { 1904 $tmp = array(); $tmp[]=$pt[0]; $tmp[]=$pt[1]; $tmp[]=$pt[2]; $tmp[]=$pt[3]; $tmp[]=$pt[10]; $tmp[]=$pt[11]; 1905 $this->pdf->Polygon($tmp, 'F'); 1906 1907 $tmp = array(); $tmp[]=$pt[4]; $tmp[]=$pt[5]; $tmp[]=$pt[6]; $tmp[]=$pt[7]; $tmp[]=$pt[8]; $tmp[]=$pt[9]; 1908 $this->pdf->Polygon($tmp, 'F'); 1909 1910 $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]; 1911 $pt = $tmp; 1912 } 1913 1914 // horisontal or vertical line 1915 if ($pt[2]==$pt[0]) { 1916 $l = abs(($pt[3]-$pt[1])*0.5); 1917 $px = 0; 1918 $py = $width; 1919 $x1 = $pt[0]; $y1 = ($pt[3]+$pt[1])*0.5; 1920 $x2 = $pt[6]; $y2 = ($pt[7]+$pt[5])*0.5; 1921 } else { 1922 $l = abs(($pt[2]-$pt[0])*0.5); 1923 $px = $width; 1924 $py = 0; 1925 $x1 = ($pt[2]+$pt[0])*0.5; $y1 = $pt[1]; 1926 $x2 = ($pt[6]+$pt[4])*0.5; $y2 = $pt[7]; 1927 } 1928 1929 // if dashed : 3x bigger than dotted 1930 if ($type=='dashed') { 1931 $px = $px*3.; 1932 $py = $py*3.; 1933 } 1934 $mode = ($l/($px+$py)<.5); 1935 1936 // display the dotted/dashed line 1937 for ($i=0; $l-($px+$py)*($i-0.5)>0; $i++) { 1938 if (($i%2)==$mode) { 1939 $j = $i-0.5; 1940 $lx1 = $px*($j); if ($lx1<-$l) $lx1 =-$l; 1941 $ly1 = $py*($j); if ($ly1<-$l) $ly1 =-$l; 1942 $lx2 = $px*($j+1); if ($lx2>$l) $lx2 = $l; 1943 $ly2 = $py*($j+1); if ($ly2>$l) $ly2 = $l; 1944 1945 $tmp = array(); 1946 $tmp[] = $x1+$lx1; $tmp[] = $y1+$ly1; 1947 $tmp[] = $x1+$lx2; $tmp[] = $y1+$ly2; 1948 $tmp[] = $x2+$lx2; $tmp[] = $y2+$ly2; 1949 $tmp[] = $x2+$lx1; $tmp[] = $y2+$ly1; 1950 $this->pdf->Polygon($tmp, 'F'); 1951 1952 if ($j>0) { 1953 $tmp = array(); 1954 $tmp[] = $x1-$lx1; $tmp[] = $y1-$ly1; 1955 $tmp[] = $x1-$lx2; $tmp[] = $y1-$ly2; 1956 $tmp[] = $x2-$lx2; $tmp[] = $y2-$ly2; 1957 $tmp[] = $x2-$lx1; $tmp[] = $y2-$ly1; 1958 $this->pdf->Polygon($tmp, 'F'); 1959 } 1960 } 1961 } 1962 } else if ($type=='double') { 1963 1964 // if double, 2 lines : 0=>1/3 and 2/3=>1 1965 $pt1 = $pt; 1966 $pt2 = $pt; 1967 1968 if (count($pt)==12) { 1969 // line 1 1970 $pt1[0] = ($pt[0]-$pt[10])*0.33 + $pt[10]; 1971 $pt1[1] = ($pt[1]-$pt[11])*0.33 + $pt[11]; 1972 $pt1[2] = ($pt[2]-$pt[10])*0.33 + $pt[10]; 1973 $pt1[3] = ($pt[3]-$pt[11])*0.33 + $pt[11]; 1974 $pt1[4] = ($pt[4]-$pt[8])*0.33 + $pt[8]; 1975 $pt1[5] = ($pt[5]-$pt[9])*0.33 + $pt[9]; 1976 $pt1[6] = ($pt[6]-$pt[8])*0.33 + $pt[8]; 1977 $pt1[7] = ($pt[7]-$pt[9])*0.33 + $pt[9]; 1978 $pt2[10]= ($pt[10]-$pt[0])*0.33 + $pt[0]; 1979 $pt2[11]= ($pt[11]-$pt[1])*0.33 + $pt[1]; 1980 1981 // line 2 1982 $pt2[2] = ($pt[2] -$pt[0])*0.33 + $pt[0]; 1983 $pt2[3] = ($pt[3] -$pt[1])*0.33 + $pt[1]; 1984 $pt2[4] = ($pt[4] -$pt[6])*0.33 + $pt[6]; 1985 $pt2[5] = ($pt[5] -$pt[7])*0.33 + $pt[7]; 1986 $pt2[8] = ($pt[8] -$pt[6])*0.33 + $pt[6]; 1987 $pt2[9] = ($pt[9] -$pt[7])*0.33 + $pt[7]; 1988 } else { 1989 // line 1 1990 $pt1[0] = ($pt[0]-$pt[6])*0.33 + $pt[6]; 1991 $pt1[1] = ($pt[1]-$pt[7])*0.33 + $pt[7]; 1992 $pt1[2] = ($pt[2]-$pt[4])*0.33 + $pt[4]; 1993 $pt1[3] = ($pt[3]-$pt[5])*0.33 + $pt[5]; 1994 1995 // line 2 1996 $pt2[6] = ($pt[6]-$pt[0])*0.33 + $pt[0]; 1997 $pt2[7] = ($pt[7]-$pt[1])*0.33 + $pt[1]; 1998 $pt2[4] = ($pt[4]-$pt[2])*0.33 + $pt[2]; 1999 $pt2[5] = ($pt[5]-$pt[3])*0.33 + $pt[3]; 2000 } 2001 $this->pdf->Polygon($pt1, 'F'); 2002 $this->pdf->Polygon($pt2, 'F'); 2003 } else if ($type=='solid') { 2004 // solid line : draw directly the polygon 2005 $this->pdf->Polygon($pt, 'F'); 2006 } 2007 } 2008 2009 /** 2010 * prepare a transform matrix, only for drawing a SVG graphic 2011 * 2012 * @access protected 2013 * @param string $transform 2014 * @return array $matrix 2015 */ 2016 protected function _prepareTransform($transform) 2017 { 2018 // it can not be empty 2019 if (!$transform) return null; 2020 2021 // sctions must be like scale(...) 2022 if (!preg_match_all('/([a-z]+)\(([^\)]*)\)/isU', $transform, $match)) return null; 2023 2024 // prepare the list of the actions 2025 $actions = array(); 2026 2027 // for actions 2028 for ($k=0; $k<count($match[0]); $k++) { 2029 2030 // get the name of the action 2031 $name = strtolower($match[1][$k]); 2032 2033 // get the parameters of the action 2034 $val = explode(',', trim($match[2][$k])); 2035 foreach ($val as $i => $j) { 2036 $val[$i] = trim($j); 2037 } 2038 2039 // prepare the matrix, depending on the action 2040 switch($name) 2041 { 2042 case 'scale': 2043 if (!isset($val[0])) $val[0] = 1.; else $val[0] = 1.*$val[0]; 2044 if (!isset($val[1])) $val[1] = $val[0]; else $val[1] = 1.*$val[1]; 2045 $actions[] = array($val[0],0,0,$val[1],0,0); 2046 break; 2047 2048 case 'translate': 2049 if (!isset($val[0])) $val[0] = 0.; else $val[0] = $this->parsingCss->ConvertToMM($val[0], $this->_isInDraw['w']); 2050 if (!isset($val[1])) $val[1] = 0.; else $val[1] = $this->parsingCss->ConvertToMM($val[1], $this->_isInDraw['h']); 2051 $actions[] = array(1,0,0,1,$val[0],$val[1]); 2052 break; 2053 2054 case 'rotate': 2055 if (!isset($val[0])) $val[0] = 0.; else $val[0] = $val[0]*M_PI/180.; 2056 if (!isset($val[1])) $val[1] = 0.; else $val[1] = $this->parsingCss->ConvertToMM($val[1], $this->_isInDraw['w']); 2057 if (!isset($val[2])) $val[2] = 0.; else $val[2] = $this->parsingCss->ConvertToMM($val[2], $this->_isInDraw['h']); 2058 if ($val[1] || $val[2]) $actions[] = array(1,0,0,1,-$val[1],-$val[2]); 2059 $actions[] = array(cos($val[0]),sin($val[0]),-sin($val[0]),cos($val[0]),0,0); 2060 if ($val[1] || $val[2]) $actions[] = array(1,0,0,1,$val[1],$val[2]); 2061 break; 2062 2063 case 'skewx': 2064 if (!isset($val[0])) $val[0] = 0.; else $val[0] = $val[0]*M_PI/180.; 2065 $actions[] = array(1,0,tan($val[0]),1,0,0); 2066 break; 2067 2068 case 'skewy': 2069 if (!isset($val[0])) $val[0] = 0.; else $val[0] = $val[0]*M_PI/180.; 2070 $actions[] = array(1,tan($val[0]),0,1,0,0); 2071 break; 2072 case 'matrix': 2073 if (!isset($val[0])) $val[0] = 0.; else $val[0] = $val[0]*1.; 2074 if (!isset($val[1])) $val[1] = 0.; else $val[1] = $val[1]*1.; 2075 if (!isset($val[2])) $val[2] = 0.; else $val[2] = $val[2]*1.; 2076 if (!isset($val[3])) $val[3] = 0.; else $val[3] = $val[3]*1.; 2077 if (!isset($val[4])) $val[4] = 0.; else $val[4] = $this->parsingCss->ConvertToMM($val[4], $this->_isInDraw['w']); 2078 if (!isset($val[5])) $val[5] = 0.; else $val[5] = $this->parsingCss->ConvertToMM($val[5], $this->_isInDraw['h']); 2079 $actions[] =$val; 2080 break; 2081 } 2082 } 2083 2084 // if ther is no actions => return 2085 if (!$actions) return null; 2086 2087 // get the first matrix 2088 $m = $actions[0]; unset($actions[0]); 2089 2090 // foreach matrix => multiply to the last matrix 2091 foreach ($actions as $n) { 2092 $m = array( 2093 $m[0]*$n[0]+$m[2]*$n[1], 2094 $m[1]*$n[0]+$m[3]*$n[1], 2095 $m[0]*$n[2]+$m[2]*$n[3], 2096 $m[1]*$n[2]+$m[3]*$n[3], 2097 $m[0]*$n[4]+$m[2]*$n[5]+$m[4], 2098 $m[1]*$n[4]+$m[3]*$n[5]+$m[5] 2099 ); 2100 } 2101 2102 // return the matrix 2103 return $m; 2104 } 2105 2106 /** 2107 * @access protected 2108 * @param &array $cases 2109 * @param &array $corr 2110 */ 2111 protected function _calculateTableCellSize(&$cases, &$corr) 2112 { 2113 if (!isset($corr[0])) return true; 2114 2115 // for each cell without colspan, we get the max width for each column 2116 $sw = array(); 2117 for ($x=0; $x<count($corr[0]); $x++) { 2118 $m=0; 2119 for ($y=0; $y<count($corr); $y++) { 2120 if (isset($corr[$y][$x]) && is_array($corr[$y][$x]) && $corr[$y][$x][2]==1) { 2121 $m = max($m, $cases[$corr[$y][$x][1]][$corr[$y][$x][0]]['w']); 2122 } 2123 } 2124 $sw[$x] = $m; 2125 } 2126 2127 // for each cell with colspan, we adapt the width of each column 2128 for ($x=0; $x<count($corr[0]); $x++) { 2129 for ($y=0; $y<count($corr); $y++) { 2130 if (isset($corr[$y][$x]) && is_array($corr[$y][$x]) && $corr[$y][$x][2]>1) { 2131 2132 // sum the max width of each column in colspan 2133 $s = 0; for ($i=0; $i<$corr[$y][$x][2]; $i++) $s+= $sw[$x+$i]; 2134 2135 // if the max width is < the width of the cell with colspan => we adapt the width of each max width 2136 if ($s>0 && $s<$cases[$corr[$y][$x][1]][$corr[$y][$x][0]]['w']) { 2137 for ($i=0; $i<$corr[$y][$x][2]; $i++) { 2138 $sw[$x+$i] = $sw[$x+$i]/$s*$cases[$corr[$y][$x][1]][$corr[$y][$x][0]]['w']; 2139 } 2140 } 2141 } 2142 } 2143 } 2144 2145 // set the new width, for each cell 2146 for ($x=0; $x<count($corr[0]); $x++) { 2147 for ($y=0; $y<count($corr); $y++) { 2148 if (isset($corr[$y][$x]) && is_array($corr[$y][$x])) { 2149 // without colspan 2150 if ($corr[$y][$x][2]==1) { 2151 $cases[$corr[$y][$x][1]][$corr[$y][$x][0]]['w'] = $sw[$x]; 2152 // with colspan 2153 } else { 2154 $s = 0; 2155 for ($i=0; $i<$corr[$y][$x][2]; $i++) { 2156 $s+= $sw[$x+$i]; 2157 } 2158 $cases[$corr[$y][$x][1]][$corr[$y][$x][0]]['w'] = $s; 2159 } 2160 } 2161 } 2162 } 2163 2164 // for each cell without rowspan, we get the max height for each line 2165 $sh = array(); 2166 for ($y=0; $y<count($corr); $y++) { 2167 $m=0; 2168 for ($x=0; $x<count($corr[0]); $x++) { 2169 if (isset($corr[$y][$x]) && is_array($corr[$y][$x]) && $corr[$y][$x][3]==1) { 2170 $m = max($m, $cases[$corr[$y][$x][1]][$corr[$y][$x][0]]['h']); 2171 } 2172 } 2173 $sh[$y] = $m; 2174 } 2175 2176 // for each cell with rowspan, we adapt the height of each line 2177 for ($y=0; $y<count($corr); $y++) { 2178 for ($x=0; $x<count($corr[0]); $x++) { 2179 if (isset($corr[$y][$x]) && is_array($corr[$y][$x]) && $corr[$y][$x][3]>1) { 2180 2181 // sum the max height of each line in rowspan 2182 $s = 0; for ($i=0; $i<$corr[$y][$x][3]; $i++) $s+= $sh[$y+$i]; 2183 2184 // if the max height is < the height of the cell with rowspan => we adapt the height of each max height 2185 if ($s>0 && $s<$cases[$corr[$y][$x][1]][$corr[$y][$x][0]]['h']) { 2186 for ($i=0; $i<$corr[$y][$x][3]; $i++) { 2187 $sh[$y+$i] = $sh[$y+$i]/$s*$cases[$corr[$y][$x][1]][$corr[$y][$x][0]]['h']; 2188 } 2189 } 2190 } 2191 } 2192 } 2193 2194 // set the new height, for each cell 2195 for ($y=0; $y<count($corr); $y++) { 2196 for ($x=0; $x<count($corr[0]); $x++) { 2197 if (isset($corr[$y][$x]) && is_array($corr[$y][$x])) { 2198 // without rowspan 2199 if ($corr[$y][$x][3]==1) { 2200 $cases[$corr[$y][$x][1]][$corr[$y][$x][0]]['h'] = $sh[$y]; 2201 // with rowspan 2202 } else { 2203 $s = 0; 2204 for ($i=0; $i<$corr[$y][$x][3]; $i++) { 2205 $s+= $sh[$y+$i]; 2206 } 2207 $cases[$corr[$y][$x][1]][$corr[$y][$x][0]]['h'] = $s; 2208 2209 for ($j=1; $j<$corr[$y][$x][3]; $j++) { 2210 $tx = $x+1; 2211 $ty = $y+$j; 2212 for (true; isset($corr[$ty][$tx]) && !is_array($corr[$ty][$tx]); $tx++); 2213 if (isset($corr[$ty][$tx])) { 2214 $cases[$corr[$ty][$tx][1]][$corr[$ty][$tx][0]]['dw']+= $cases[$corr[$y][$x][1]][$corr[$y][$x][0]]['w']; 2215 } 2216 } 2217 } 2218 } 2219 } 2220 } 2221 } 2222 2223 /** 2224 * tag : PAGE 2225 * mode : OPEN 2226 * 2227 * @param array $param 2228 * @return boolean 2229 */ 2230 protected function _tag_open_PAGE($param) 2231 { 2232 if ($this->_isForOneLine) return false; 2233 if ($this->_debugActif) $this->_DEBUG_add('PAGE '.($this->_page+1), true); 2234 2235 $newPageSet= (!isset($param['pageset']) || $param['pageset']!='old'); 2236 2237 $resetPageNumber = (isset($param['pagegroup']) && $param['pagegroup']=='new'); 2238 2239 $this->_maxH = 0; 2240 2241 // if new page set asked 2242 if ($newPageSet) { 2243 $this->_subHEADER = array(); 2244 $this->_subFOOTER = array(); 2245 2246 // orientation 2247 $orientation = ''; 2248 if (isset($param['orientation'])) { 2249 $param['orientation'] = strtolower($param['orientation']); 2250 if ($param['orientation']=='p') $orientation = 'P'; 2251 if ($param['orientation']=='portrait') $orientation = 'P'; 2252 2253 if ($param['orientation']=='l') $orientation = 'L'; 2254 if ($param['orientation']=='paysage') $orientation = 'L'; 2255 if ($param['orientation']=='landscape') $orientation = 'L'; 2256 } 2257 2258 // format 2259 $format = null; 2260 if (isset($param['format'])) { 2261 $format = strtolower($param['format']); 2262 if (preg_match('/^([0-9]+)x([0-9]+)$/isU', $format, $match)) { 2263 $format = array(intval($match[1]), intval($match[2])); 2264 } 2265 } 2266 2267 // background 2268 $background = array(); 2269 if (isset($param['backimg'])) { 2270 $background['img'] = isset($param['backimg']) ? $param['backimg'] : ''; // src of the image 2271 $background['posX'] = isset($param['backimgx']) ? $param['backimgx'] : 'center'; // horizontale position of the image 2272 $background['posY'] = isset($param['backimgy']) ? $param['backimgy'] : 'middle'; // vertical position of the image 2273 $background['width'] = isset($param['backimgw']) ? $param['backimgw'] : '100%'; // width of the image (100% = page width) 2274 2275 // convert the src of the image, if parameters 2276 $background['img'] = str_replace('&', '&', $background['img']); 2277 2278 // convert the positions 2279 if ($background['posX']=='left') $background['posX'] = '0%'; 2280 if ($background['posX']=='center') $background['posX'] = '50%'; 2281 if ($background['posX']=='right') $background['posX'] = '100%'; 2282 if ($background['posY']=='top') $background['posY'] = '0%'; 2283 if ($background['posY']=='middle') $background['posY'] = '50%'; 2284 if ($background['posY']=='bottom') $background['posY'] = '100%'; 2285 2286 if ($background['img']) { 2287 // get the size of the image 2288 // WARNING : if URL, "allow_url_fopen" must turned to "on" in php.ini 2289 $infos=@getimagesize($background['img']); 2290 if (count($infos)>1) { 2291 $imageWidth = $this->parsingCss->ConvertToMM($background['width'], $this->pdf->getW()); 2292 $imageHeight = $imageWidth*$infos[1]/$infos[0]; 2293 2294 $background['width'] = $imageWidth; 2295 $background['posX'] = $this->parsingCss->ConvertToMM($background['posX'], $this->pdf->getW() - $imageWidth); 2296 $background['posY'] = $this->parsingCss->ConvertToMM($background['posY'], $this->pdf->getH() - $imageHeight); 2297 } else { 2298 $background = array(); 2299 } 2300 } else { 2301 $background = array(); 2302 } 2303 } 2304 2305 // margins of the page 2306 $background['top'] = isset($param['backtop']) ? $param['backtop'] : '0'; 2307 $background['bottom'] = isset($param['backbottom']) ? $param['backbottom'] : '0'; 2308 $background['left'] = isset($param['backleft']) ? $param['backleft'] : '0'; 2309 $background['right'] = isset($param['backright']) ? $param['backright'] : '0'; 2310 2311 // if no unit => mm 2312 if (preg_match('/^([0-9]*)$/isU', $background['top'])) $background['top'] .= 'mm'; 2313 if (preg_match('/^([0-9]*)$/isU', $background['bottom'])) $background['bottom'] .= 'mm'; 2314 if (preg_match('/^([0-9]*)$/isU', $background['left'])) $background['left'] .= 'mm'; 2315 if (preg_match('/^([0-9]*)$/isU', $background['right'])) $background['right'] .= 'mm'; 2316 2317 // convert to mm 2318 $background['top'] = $this->parsingCss->ConvertToMM($background['top'], $this->pdf->getH()); 2319 $background['bottom'] = $this->parsingCss->ConvertToMM($background['bottom'], $this->pdf->getH()); 2320 $background['left'] = $this->parsingCss->ConvertToMM($background['left'], $this->pdf->getW()); 2321 $background['right'] = $this->parsingCss->ConvertToMM($background['right'], $this->pdf->getW()); 2322 2323 // get the background color 2324 $res = false; 2325 $background['color'] = isset($param['backcolor']) ? $this->parsingCss->convertToColor($param['backcolor'], $res) : null; 2326 if (!$res) $background['color'] = null; 2327 2328 $this->parsingCss->save(); 2329 $this->parsingCss->analyse('PAGE', $param); 2330 $this->parsingCss->setPosition(); 2331 $this->parsingCss->fontSet(); 2332 2333 // new page 2334 $this->_setNewPage($format, $orientation, $background, null, $resetPageNumber); 2335 2336 // automatic footer 2337 if (isset($param['footer'])) { 2338 $lst = explode(';', $param['footer']); 2339 foreach ($lst as $key => $val) $lst[$key] = trim(strtolower($val)); 2340 $page = in_array('page', $lst); 2341 $date = in_array('date', $lst); 2342 $hour = in_array('heure', $lst); 2343 $form = in_array('form', $lst); 2344 } else { 2345 $page = null; 2346 $date = null; 2347 $hour = null; 2348 $form = null; 2349 } 2350 $this->pdf->SetMyFooter($page, $date, $hour, $form); 2351 // else => we use the last page set used 2352 } else { 2353 $this->parsingCss->save(); 2354 $this->parsingCss->analyse('PAGE', $param); 2355 $this->parsingCss->setPosition(); 2356 $this->parsingCss->fontSet(); 2357 2358 $this->_setNewPage(null, null, null, null, $resetPageNumber); 2359 } 2360 2361 return true; 2362 } 2363 2364 /** 2365 * tag : PAGE 2366 * mode : CLOSE 2367 * 2368 * @param array $param 2369 * @return boolean 2370 */ 2371 protected function _tag_close_PAGE($param) 2372 { 2373 if ($this->_isForOneLine) return false; 2374 2375 $this->_maxH = 0; 2376 2377 $this->parsingCss->load(); 2378 $this->parsingCss->fontSet(); 2379 2380 if ($this->_debugActif) $this->_DEBUG_add('PAGE '.$this->_page, false); 2381 2382 return true; 2383 } 2384 2385 /** 2386 * tag : PAGE_HEADER 2387 * mode : OPEN 2388 * 2389 * @param array $param 2390 * @return boolean 2391 */ 2392 protected function _tag_open_PAGE_HEADER($param) 2393 { 2394 if ($this->_isForOneLine) return false; 2395 2396 $this->_subHEADER = array(); 2397 for ($this->_parsePos; $this->_parsePos<count($this->parsingHtml->code); $this->_parsePos++) { 2398 $action = $this->parsingHtml->code[$this->_parsePos]; 2399 if ($action['name']=='page_header') $action['name']='page_header_sub'; 2400 $this->_subHEADER[] = $action; 2401 if (strtolower($action['name'])=='page_header_sub' && $action['close']) break; 2402 } 2403 2404 $this->_setPageHeader(); 2405 2406 return true; 2407 } 2408 2409 /** 2410 * tag : PAGE_FOOTER 2411 * mode : OPEN 2412 * 2413 * @param array $param 2414 * @return boolean 2415 */ 2416 protected function _tag_open_PAGE_FOOTER($param) 2417 { 2418 if ($this->_isForOneLine) return false; 2419 2420 $this->_subFOOTER = array(); 2421 for ($this->_parsePos; $this->_parsePos<count($this->parsingHtml->code); $this->_parsePos++) { 2422 $action = $this->parsingHtml->code[$this->_parsePos]; 2423 if ($action['name']=='page_footer') $action['name']='page_footer_sub'; 2424 $this->_subFOOTER[] = $action; 2425 if (strtolower($action['name'])=='page_footer_sub' && $action['close']) break; 2426 } 2427 2428 $this->_setPageFooter(); 2429 2430 return true; 2431 } 2432 2433 /** 2434 * It is not a real tag. Does not use it directly 2435 * 2436 * @param array $param 2437 * @return boolean 2438 */ 2439 protected function _tag_open_PAGE_HEADER_SUB($param) 2440 { 2441 if ($this->_isForOneLine) return false; 2442 2443 // save the current stat 2444 $this->_subSTATES = array(); 2445 $this->_subSTATES['x'] = $this->pdf->getX(); 2446 $this->_subSTATES['y'] = $this->pdf->getY(); 2447 $this->_subSTATES['s'] = $this->parsingCss->value; 2448 $this->_subSTATES['t'] = $this->parsingCss->table; 2449 $this->_subSTATES['ml'] = $this->_margeLeft; 2450 $this->_subSTATES['mr'] = $this->_margeRight; 2451 $this->_subSTATES['mt'] = $this->_margeTop; 2452 $this->_subSTATES['mb'] = $this->_margeBottom; 2453 $this->_subSTATES['mp'] = $this->_pageMarges; 2454 2455 // new stat for the header 2456 $this->_pageMarges = array(); 2457 $this->_margeLeft = $this->_defaultLeft; 2458 $this->_margeRight = $this->_defaultRight; 2459 $this->_margeTop = $this->_defaultTop; 2460 $this->_margeBottom = $this->_defaultBottom; 2461 $this->pdf->SetMargins($this->_margeLeft, $this->_margeTop, $this->_margeRight); 2462 $this->pdf->SetAutoPageBreak(false, $this->_margeBottom); 2463 $this->pdf->setXY($this->_defaultLeft, $this->_defaultTop); 2464 2465 $this->parsingCss->initStyle(); 2466 $this->parsingCss->resetStyle(); 2467 $this->parsingCss->value['width'] = $this->pdf->getW() - $this->_defaultLeft - $this->_defaultRight; 2468 $this->parsingCss->table = array(); 2469 2470 $this->parsingCss->save(); 2471 $this->parsingCss->analyse('page_header_sub', $param); 2472 $this->parsingCss->setPosition(); 2473 $this->parsingCss->fontSet(); 2474 $this->_setNewPositionForNewLine(); 2475 return true; 2476 } 2477 2478 /** 2479 * It is not a real tag. Does not use it directly 2480 * 2481 * @param array $param 2482 * @return boolean 2483 */ 2484 protected function _tag_close_PAGE_HEADER_SUB($param) 2485 { 2486 if ($this->_isForOneLine) return false; 2487 2488 $this->parsingCss->load(); 2489 2490 // restore the stat 2491 $this->parsingCss->value = $this->_subSTATES['s']; 2492 $this->parsingCss->table = $this->_subSTATES['t']; 2493 $this->_pageMarges = $this->_subSTATES['mp']; 2494 $this->_margeLeft = $this->_subSTATES['ml']; 2495 $this->_margeRight = $this->_subSTATES['mr']; 2496 $this->_margeTop = $this->_subSTATES['mt']; 2497 $this->_margeBottom = $this->_subSTATES['mb']; 2498 $this->pdf->SetMargins($this->_margeLeft, $this->_margeTop, $this->_margeRight); 2499 $this->pdf->setbMargin($this->_margeBottom); 2500 $this->pdf->SetAutoPageBreak(false, $this->_margeBottom); 2501 $this->pdf->setXY($this->_subSTATES['x'], $this->_subSTATES['y']); 2502 2503 $this->parsingCss->fontSet(); 2504 $this->_maxH = 0; 2505 2506 return true; 2507 } 2508 2509 /** 2510 * It is not a real tag. Does not use it directly 2511 * 2512 * @param array $param 2513 * @return boolean 2514 */ 2515 protected function _tag_open_PAGE_FOOTER_SUB($param) 2516 { 2517 if ($this->_isForOneLine) return false; 2518 2519 // save the current stat 2520 $this->_subSTATES = array(); 2521 $this->_subSTATES['x'] = $this->pdf->getX(); 2522 $this->_subSTATES['y'] = $this->pdf->getY(); 2523 $this->_subSTATES['s'] = $this->parsingCss->value; 2524 $this->_subSTATES['t'] = $this->parsingCss->table; 2525 $this->_subSTATES['ml'] = $this->_margeLeft; 2526 $this->_subSTATES['mr'] = $this->_margeRight; 2527 $this->_subSTATES['mt'] = $this->_margeTop; 2528 $this->_subSTATES['mb'] = $this->_margeBottom; 2529 $this->_subSTATES['mp'] = $this->_pageMarges; 2530 2531 // new stat for the footer 2532 $this->_pageMarges = array(); 2533 $this->_margeLeft = $this->_defaultLeft; 2534 $this->_margeRight = $this->_defaultRight; 2535 $this->_margeTop = $this->_defaultTop; 2536 $this->_margeBottom = $this->_defaultBottom; 2537 $this->pdf->SetMargins($this->_margeLeft, $this->_margeTop, $this->_margeRight); 2538 $this->pdf->SetAutoPageBreak(false, $this->_margeBottom); 2539 $this->pdf->setXY($this->_defaultLeft, $this->_defaultTop); 2540 2541 $this->parsingCss->initStyle(); 2542 $this->parsingCss->resetStyle(); 2543 $this->parsingCss->value['width'] = $this->pdf->getW() - $this->_defaultLeft - $this->_defaultRight; 2544 $this->parsingCss->table = array(); 2545 2546 // we create a sub HTML2PFDF, and we execute on it the content of the footer, to get the height of it 2547 $sub = null; 2548 $this->_createSubHTML($sub); 2549 $sub->parsingHtml->code = $this->parsingHtml->getLevel($this->_parsePos); 2550 $sub->_makeHTMLcode(); 2551 $this->pdf->setY($this->pdf->getH() - $sub->_maxY - $this->_defaultBottom - 0.01); 2552 $this->_destroySubHTML($sub); 2553 2554 $this->parsingCss->save(); 2555 $this->parsingCss->analyse('page_footer_sub', $param); 2556 $this->parsingCss->setPosition(); 2557 $this->parsingCss->fontSet(); 2558 $this->_setNewPositionForNewLine(); 2559 2560 return true; 2561 } 2562 2563 /** 2564 * It is not a real tag. Does not use it directly 2565 * 2566 * @param array $param 2567 * @return boolean 2568 */ 2569 protected function _tag_close_PAGE_FOOTER_SUB($param) 2570 { 2571 if ($this->_isForOneLine) return false; 2572 2573 $this->parsingCss->load(); 2574 2575 $this->parsingCss->value = $this->_subSTATES['s']; 2576 $this->parsingCss->table = $this->_subSTATES['t']; 2577 $this->_pageMarges = $this->_subSTATES['mp']; 2578 $this->_margeLeft = $this->_subSTATES['ml']; 2579 $this->_margeRight = $this->_subSTATES['mr']; 2580 $this->_margeTop = $this->_subSTATES['mt']; 2581 $this->_margeBottom = $this->_subSTATES['mb']; 2582 $this->pdf->SetMargins($this->_margeLeft, $this->_margeTop, $this->_margeRight); 2583 $this->pdf->SetAutoPageBreak(false, $this->_margeBottom); 2584 $this->pdf->setXY($this->_subSTATES['x'], $this->_subSTATES['y']); 2585 2586 $this->parsingCss->fontSet(); 2587 $this->_maxH = 0; 2588 2589 return true; 2590 } 2591 2592 /** 2593 * tag : NOBREAK 2594 * mode : OPEN 2595 * 2596 * @param array $param 2597 * @return boolean 2598 */ 2599 protected function _tag_open_NOBREAK($param) 2600 { 2601 if ($this->_isForOneLine) return false; 2602 2603 $this->_maxH = 0; 2604 2605 // create a sub HTML2PDF to execute the content of the tag, to get the dimensions 2606 $sub = null; 2607 $this->_createSubHTML($sub); 2608 $sub->parsingHtml->code = $this->parsingHtml->getLevel($this->_parsePos); 2609 $sub->_makeHTMLcode(); 2610 $y = $this->pdf->getY(); 2611 2612 // if the content does not fit on the page => new page 2613 if ( 2614 $sub->_maxY < ($this->pdf->getH() - $this->pdf->gettMargin()-$this->pdf->getbMargin()) && 2615 $y + $sub->_maxY>=($this->pdf->getH() - $this->pdf->getbMargin()) 2616 ) { 2617 $this->_setNewPage(); 2618 } 2619 2620 // destroy the sub HTML2PDF 2621 $this->_destroySubHTML($sub); 2622 2623 return true; 2624 } 2625 2626 2627 /** 2628 * tag : NOBREAK 2629 * mode : CLOSE 2630 * 2631 * @param array $param 2632 * @return boolean 2633 */ 2634 protected function _tag_close_NOBREAK($param) 2635 { 2636 if ($this->_isForOneLine) return false; 2637 2638 $this->_maxH = 0; 2639 2640 return true; 2641 } 2642 2643 /** 2644 * tag : DIV 2645 * mode : OPEN 2646 * 2647 * @param array $param 2648 * @param string $other name of tag that used the div tag 2649 * @return boolean 2650 */ 2651 protected function _tag_open_DIV($param, $other = 'div') 2652 { 2653 if ($this->_isForOneLine) return false; 2654 if ($this->_debugActif) $this->_DEBUG_add(strtoupper($other), true); 2655 2656 $this->parsingCss->save(); 2657 $this->parsingCss->analyse($other, $param); 2658 $this->parsingCss->fontSet(); 2659 2660 // for fieldset and legend 2661 if (in_array($other, array('fieldset', 'legend'))) { 2662 if (isset($param['moveTop'])) $this->parsingCss->value['margin']['t'] += $param['moveTop']; 2663 if (isset($param['moveLeft'])) $this->parsingCss->value['margin']['l'] += $param['moveLeft']; 2664 if (isset($param['moveDown'])) $this->parsingCss->value['margin']['b'] += $param['moveDown']; 2665 } 2666 2667 $alignObject = null; 2668 if ($this->parsingCss->value['margin-auto']) $alignObject = 'center'; 2669 2670 $marge = array(); 2671 $marge['l'] = $this->parsingCss->value['border']['l']['width'] + $this->parsingCss->value['padding']['l']+0.03; 2672 $marge['r'] = $this->parsingCss->value['border']['r']['width'] + $this->parsingCss->value['padding']['r']+0.03; 2673 $marge['t'] = $this->parsingCss->value['border']['t']['width'] + $this->parsingCss->value['padding']['t']+0.03; 2674 $marge['b'] = $this->parsingCss->value['border']['b']['width'] + $this->parsingCss->value['padding']['b']+0.03; 2675 2676 // extract the content of the div 2677 $level = $this->parsingHtml->getLevel($this->_parsePos); 2678 2679 // create a sub HTML2PDF to get the dimensions of the content of the div 2680 $w = 0; $h = 0; 2681 if (count($level)) { 2682 $sub = null; 2683 $this->_createSubHTML($sub); 2684 $sub->parsingHtml->code = $level; 2685 $sub->_makeHTMLcode(); 2686 $w = $sub->_maxX; 2687 $h = $sub->_maxY; 2688 $this->_destroySubHTML($sub); 2689 } 2690 $wReel = $w; 2691 $hReel = $h; 2692 2693 $w+= $marge['l']+$marge['r']+0.001; 2694 $h+= $marge['t']+$marge['b']+0.001; 2695 2696 if ($this->parsingCss->value['overflow']=='hidden') { 2697 $overW = max($w, $this->parsingCss->value['width']); 2698 $overH = max($h, $this->parsingCss->value['height']); 2699 $overflow = true; 2700 $this->parsingCss->value['old_maxX'] = $this->_maxX; 2701 $this->parsingCss->value['old_maxY'] = $this->_maxY; 2702 $this->parsingCss->value['old_maxH'] = $this->_maxH; 2703 $this->parsingCss->value['old_overflow'] = $this->_isInOverflow; 2704 $this->_isInOverflow = true; 2705 } else { 2706 $overW = null; 2707 $overH = null; 2708 $overflow = false; 2709 $this->parsingCss->value['width'] = max($w, $this->parsingCss->value['width']); 2710 $this->parsingCss->value['height'] = max($h, $this->parsingCss->value['height']); 2711 } 2712 2713 switch($this->parsingCss->value['rotate']) 2714 { 2715 case 90: 2716 $tmp = $overH; $overH = $overW; $overW = $tmp; 2717 $tmp = $hReel; $hReel = $wReel; $wReel = $tmp; 2718 unset($tmp); 2719 $w = $this->parsingCss->value['height']; 2720 $h = $this->parsingCss->value['width']; 2721 $tX =-$h; 2722 $tY = 0; 2723 break; 2724 2725 case 180: 2726 $w = $this->parsingCss->value['width']; 2727 $h = $this->parsingCss->value['height']; 2728 $tX = -$w; 2729 $tY = -$h; 2730 break; 2731 2732 case 270: 2733 $tmp = $overH; $overH = $overW; $overW = $tmp; 2734 $tmp = $hReel; $hReel = $wReel; $wReel = $tmp; 2735 unset($tmp); 2736 $w = $this->parsingCss->value['height']; 2737 $h = $this->parsingCss->value['width']; 2738 $tX = 0; 2739 $tY =-$w; 2740 break; 2741 2742 default: 2743 $w = $this->parsingCss->value['width']; 2744 $h = $this->parsingCss->value['height']; 2745 $tX = 0; 2746 $tY = 0; 2747 break; 2748 } 2749 2750 if (!$this->parsingCss->value['position']) { 2751 if ( 2752 $w < ($this->pdf->getW() - $this->pdf->getlMargin()-$this->pdf->getrMargin()) && 2753 $this->pdf->getX() + $w>=($this->pdf->getW() - $this->pdf->getrMargin()) 2754 ) 2755 $this->_tag_open_BR(array()); 2756 2757 if ( 2758 ($h < ($this->pdf->getH() - $this->pdf->gettMargin()-$this->pdf->getbMargin())) && 2759 ($this->pdf->getY() + $h>=($this->pdf->getH() - $this->pdf->getbMargin())) && 2760 !$this->_isInOverflow 2761 ) 2762 $this->_setNewPage(); 2763 2764 $old = $this->parsingCss->getOldValues(); 2765 $parentWidth = $old['width'] ? $old['width'] : $this->pdf->getW() - $this->pdf->getlMargin() - $this->pdf->getrMargin(); 2766 2767