1<?php 2 3namespace Mpdf; 4 5use Mpdf\Config\ConfigVariables; 6use Mpdf\Config\FontVariables; 7 8use Mpdf\Conversion; 9 10use Mpdf\Css\Border; 11use Mpdf\Css\TextVars; 12 13use \dokuwiki\plugin\dw2pdf\DokuImageProcessorDecorator as ImageProcessor; 14use Mpdf\Log\Context as LogContext; 15 16use Mpdf\Fonts\MetricsGenerator; 17 18use Mpdf\Output\Destination; 19 20use Mpdf\QrCode; 21 22use Mpdf\Utils\Arrays; 23use Mpdf\Utils\NumericString; 24use Mpdf\Utils\UtfString; 25 26use Psr\Log\LoggerInterface; 27use Psr\Log\NullLogger; 28 29/** 30 * mPDF, PHP library generating PDF files from UTF-8 encoded HTML 31 * 32 * based on FPDF by Olivier Plathey 33 * and HTML2FPDF by Renato Coelho 34 * 35 * @license GPL-2.0 36 */ 37class Mpdf implements \Psr\Log\LoggerAwareInterface 38{ 39 40 use Strict; 41 use FpdiTrait; 42 43 const VERSION = '8.0.7'; 44 45 const SCALE = 72 / 25.4; 46 47 var $useFixedNormalLineHeight; // mPDF 6 48 var $useFixedTextBaseline; // mPDF 6 49 var $adjustFontDescLineheight; // mPDF 6 50 var $interpolateImages; // mPDF 6 51 var $defaultPagebreakType; // mPDF 6 pagebreaktype 52 var $indexUseSubentries; // mPDF 6 53 54 var $autoScriptToLang; // mPDF 6 55 var $baseScript; // mPDF 6 56 var $autoVietnamese; // mPDF 6 57 var $autoArabic; // mPDF 6 58 59 var $CJKforceend; 60 var $h2bookmarks; 61 var $h2toc; 62 var $decimal_align; 63 var $margBuffer; 64 var $splitTableBorderWidth; 65 66 var $bookmarkStyles; 67 var $useActiveForms; 68 69 var $repackageTTF; 70 var $allowCJKorphans; 71 var $allowCJKoverflow; 72 73 var $useKerning; 74 var $restrictColorSpace; 75 var $bleedMargin; 76 var $crossMarkMargin; 77 var $cropMarkMargin; 78 var $cropMarkLength; 79 var $nonPrintMargin; 80 81 var $PDFX; 82 var $PDFXauto; 83 84 var $PDFA; 85 var $PDFAversion = '1-B'; 86 var $PDFAauto; 87 var $ICCProfile; 88 89 var $printers_info; 90 var $iterationCounter; 91 var $smCapsScale; 92 var $smCapsStretch; 93 94 var $backupSubsFont; 95 var $backupSIPFont; 96 var $fonttrans; 97 var $debugfonts; 98 var $useAdobeCJK; 99 var $percentSubset; 100 var $maxTTFFilesize; 101 var $BMPonly; 102 103 var $tableMinSizePriority; 104 105 var $dpi; 106 var $watermarkImgAlphaBlend; 107 var $watermarkImgBehind; 108 var $justifyB4br; 109 var $packTableData; 110 var $pgsIns; 111 var $simpleTables; 112 var $enableImports; 113 114 var $debug; 115 116 var $setAutoTopMargin; 117 var $setAutoBottomMargin; 118 var $autoMarginPadding; 119 var $collapseBlockMargins; 120 var $falseBoldWeight; 121 var $normalLineheight; 122 var $incrementFPR1; 123 var $incrementFPR2; 124 var $incrementFPR3; 125 var $incrementFPR4; 126 127 var $SHYlang; 128 var $SHYleftmin; 129 var $SHYrightmin; 130 var $SHYcharmin; 131 var $SHYcharmax; 132 var $SHYlanguages; 133 134 // PageNumber Conditional Text 135 var $pagenumPrefix; 136 var $pagenumSuffix; 137 138 var $nbpgPrefix; 139 var $nbpgSuffix; 140 var $showImageErrors; 141 var $allow_output_buffering; 142 var $autoPadding; 143 var $tabSpaces; 144 var $autoLangToFont; 145 var $watermarkTextAlpha; 146 var $watermarkImageAlpha; 147 var $watermark_size; 148 var $watermark_pos; 149 var $annotSize; 150 var $annotMargin; 151 var $annotOpacity; 152 var $title2annots; 153 var $keepColumns; 154 var $keep_table_proportions; 155 var $ignore_table_widths; 156 var $ignore_table_percents; 157 var $list_number_suffix; 158 159 var $list_auto_mode; // mPDF 6 160 var $list_indent_first_level; // mPDF 6 161 var $list_indent_default; // mPDF 6 162 var $list_indent_default_mpdf; 163 var $list_marker_offset; // mPDF 6 164 var $list_symbol_size; 165 166 var $useSubstitutions; 167 var $CSSselectMedia; 168 169 var $forcePortraitHeaders; 170 var $forcePortraitMargins; 171 var $displayDefaultOrientation; 172 var $ignore_invalid_utf8; 173 var $allowedCSStags; 174 var $onlyCoreFonts; 175 var $allow_charset_conversion; 176 177 var $jSWord; 178 var $jSmaxChar; 179 var $jSmaxCharLast; 180 var $jSmaxWordLast; 181 182 var $max_colH_correction; 183 184 var $table_error_report; 185 var $table_error_report_param; 186 var $biDirectional; 187 var $text_input_as_HTML; 188 var $anchor2Bookmark; 189 var $shrink_tables_to_fit; 190 191 var $allow_html_optional_endtags; 192 193 var $img_dpi; 194 var $whitelistStreamWrappers; 195 196 var $defaultheaderfontsize; 197 var $defaultheaderfontstyle; 198 var $defaultheaderline; 199 var $defaultfooterfontsize; 200 var $defaultfooterfontstyle; 201 var $defaultfooterline; 202 var $header_line_spacing; 203 var $footer_line_spacing; 204 205 var $pregCJKchars; 206 var $pregRTLchars; 207 var $pregCURSchars; // mPDF 6 208 209 var $mirrorMargins; 210 var $watermarkText; 211 var $watermarkAngle; 212 var $watermarkImage; 213 var $showWatermarkText; 214 var $showWatermarkImage; 215 216 var $svgAutoFont; 217 var $svgClasses; 218 219 var $fontsizes; 220 221 var $defaultPageNumStyle; // mPDF 6 222 223 ////////////////////// 224 // INTERNAL VARIABLES 225 ////////////////////// 226 var $extrapagebreak; // mPDF 6 pagebreaktype 227 228 var $uniqstr; // mPDF 5.7.2 229 var $hasOC; 230 231 var $textvar; // mPDF 5.7.1 232 var $fontLanguageOverride; // mPDF 5.7.1 233 var $OTLtags; // mPDF 5.7.1 234 var $OTLdata; // mPDF 5.7.1 235 236 var $useDictionaryLBR; 237 var $useTibetanLBR; 238 239 var $writingToC; 240 var $layers; 241 var $layerDetails; 242 var $current_layer; 243 var $open_layer_pane; 244 var $decimal_offset; 245 var $inMeter; 246 247 var $CJKleading; 248 var $CJKfollowing; 249 var $CJKoverflow; 250 251 var $textshadow; 252 253 var $colsums; 254 var $spanborder; 255 var $spanborddet; 256 257 var $visibility; 258 259 var $kerning; 260 var $fixedlSpacing; 261 var $minwSpacing; 262 var $lSpacingCSS; 263 var $wSpacingCSS; 264 265 var $spotColorIDs; 266 var $SVGcolors; 267 var $spotColors; 268 var $defTextColor; 269 var $defDrawColor; 270 var $defFillColor; 271 272 var $tableBackgrounds; 273 var $inlineDisplayOff; 274 var $kt_y00; 275 var $kt_p00; 276 var $upperCase; 277 var $checkSIP; 278 var $checkSMP; 279 var $checkCJK; 280 281 var $watermarkImgAlpha; 282 var $PDFAXwarnings; 283 284 var $MetadataRoot; 285 var $OutputIntentRoot; 286 var $InfoRoot; 287 var $associatedFilesRoot; 288 289 var $pdf_version; 290 291 private $fontDir; 292 293 var $tempDir; 294 295 var $allowAnnotationFiles; 296 297 var $fontdata; 298 299 var $noImageFile; 300 var $lastblockbottommargin; 301 var $baselineC; 302 303 // mPDF 5.7.3 inline text-decoration parameters 304 var $baselineSup; 305 var $baselineSub; 306 var $baselineS; 307 var $baselineO; 308 309 var $subPos; 310 var $subArrMB; 311 var $ReqFontStyle; 312 var $tableClipPath; 313 314 var $fullImageHeight; 315 316 var $inFixedPosBlock; // Internal flag for position:fixed block 317 var $fixedPosBlock; // Buffer string for position:fixed block 318 var $fixedPosBlockDepth; 319 var $fixedPosBlockBBox; 320 var $fixedPosBlockSave; 321 var $maxPosL; 322 var $maxPosR; 323 var $loaded; 324 325 var $extraFontSubsets; 326 327 var $docTemplateStart; // Internal flag for page (page no. -1) that docTemplate starts on 328 329 var $time0; 330 331 var $hyphenationDictionaryFile; 332 333 var $spanbgcolorarray; 334 var $default_font; 335 var $headerbuffer; 336 var $lastblocklevelchange; 337 var $nestedtablejustfinished; 338 var $linebreakjustfinished; 339 var $cell_border_dominance_L; 340 var $cell_border_dominance_R; 341 var $cell_border_dominance_T; 342 var $cell_border_dominance_B; 343 var $table_keep_together; 344 var $plainCell_properties; 345 var $shrin_k1; 346 var $outerfilled; 347 348 var $blockContext; 349 var $floatDivs; 350 351 var $patterns; 352 var $pageBackgrounds; 353 354 var $bodyBackgroundGradient; 355 var $bodyBackgroundImage; 356 var $bodyBackgroundColor; 357 358 var $writingHTMLheader; // internal flag - used both for writing HTMLHeaders/Footers and FixedPos block 359 var $writingHTMLfooter; 360 361 var $angle; 362 363 var $gradients; 364 365 var $kwt_Reference; 366 var $kwt_BMoutlines; 367 var $kwt_toc; 368 369 var $tbrot_BMoutlines; 370 var $tbrot_toc; 371 372 var $col_BMoutlines; 373 var $col_toc; 374 375 var $floatbuffer; 376 var $floatmargins; 377 378 var $bullet; 379 var $bulletarray; 380 381 var $currentLang; 382 var $default_lang; 383 384 var $default_available_fonts; 385 386 var $pageTemplate; 387 var $docTemplate; 388 var $docTemplateContinue; 389 390 var $arabGlyphs; 391 var $arabHex; 392 var $persianGlyphs; 393 var $persianHex; 394 var $arabVowels; 395 var $arabPrevLink; 396 var $arabNextLink; 397 398 var $formobjects; // array of Form Objects for WMF 399 var $InlineProperties; 400 var $InlineAnnots; 401 var $InlineBDF; // mPDF 6 Bidirectional formatting 402 var $InlineBDFctr; // mPDF 6 403 404 var $ktAnnots; 405 var $tbrot_Annots; 406 var $kwt_Annots; 407 var $columnAnnots; 408 var $columnForms; 409 var $tbrotForms; 410 411 var $PageAnnots; 412 413 var $pageDim; // Keep track of page wxh for orientation changes - set in _beginpage, used in _putannots 414 415 var $breakpoints; 416 417 var $tableLevel; 418 var $tbctr; 419 var $innermostTableLevel; 420 var $saveTableCounter; 421 var $cellBorderBuffer; 422 423 var $saveHTMLFooter_height; 424 var $saveHTMLFooterE_height; 425 426 var $firstPageBoxHeader; 427 var $firstPageBoxHeaderEven; 428 var $firstPageBoxFooter; 429 var $firstPageBoxFooterEven; 430 431 var $page_box; 432 433 var $show_marks; // crop or cross marks 434 var $basepathIsLocal; 435 436 var $use_kwt; 437 var $kwt; 438 var $kwt_height; 439 var $kwt_y0; 440 var $kwt_x0; 441 var $kwt_buffer; 442 var $kwt_Links; 443 var $kwt_moved; 444 var $kwt_saved; 445 446 var $PageNumSubstitutions; 447 448 var $table_borders_separate; 449 var $base_table_properties; 450 var $borderstyles; 451 452 var $blockjustfinished; 453 454 var $orig_bMargin; 455 var $orig_tMargin; 456 var $orig_lMargin; 457 var $orig_rMargin; 458 var $orig_hMargin; 459 var $orig_fMargin; 460 461 var $pageHTMLheaders; 462 var $pageHTMLfooters; 463 464 var $saveHTMLHeader; 465 var $saveHTMLFooter; 466 467 var $HTMLheaderPageLinks; 468 var $HTMLheaderPageAnnots; 469 var $HTMLheaderPageForms; 470 471 // See Config\FontVariables for these next 5 values 472 var $available_unifonts; 473 var $sans_fonts; 474 var $serif_fonts; 475 var $mono_fonts; 476 var $defaultSubsFont; 477 478 // List of ALL available CJK fonts (incl. styles) (Adobe add-ons) hw removed 479 var $available_CJK_fonts; 480 481 var $HTMLHeader; 482 var $HTMLFooter; 483 var $HTMLHeaderE; 484 var $HTMLFooterE; 485 var $bufferoutput; 486 487 // CJK fonts 488 var $Big5_widths; 489 var $GB_widths; 490 var $SJIS_widths; 491 var $UHC_widths; 492 493 // SetProtection 494 var $encrypted; 495 496 var $enc_obj_id; // encryption object id 497 498 // Bookmark 499 var $BMoutlines; 500 var $OutlineRoot; 501 502 // INDEX 503 var $ColActive; 504 var $Reference; 505 var $CurrCol; 506 var $NbCol; 507 var $y0; // Top ordinate of columns 508 509 var $ColL; 510 var $ColWidth; 511 var $ColGap; 512 513 // COLUMNS 514 var $ColR; 515 var $ChangeColumn; 516 var $columnbuffer; 517 var $ColDetails; 518 var $columnLinks; 519 var $colvAlign; 520 521 // Substitutions 522 var $substitute; // Array of substitution strings e.g. <ttz>112</ttz> 523 var $entsearch; // Array of HTML entities (>ASCII 127) to substitute 524 var $entsubstitute; // Array of substitution decimal unicode for the Hi entities 525 526 // Default values if no style sheet offered (cf. http://www.w3.org/TR/CSS21/sample.html) 527 var $defaultCSS; 528 var $defaultCssFile; 529 530 var $lastoptionaltag; // Save current block item which HTML specifies optionsl endtag 531 var $pageoutput; 532 var $charset_in; 533 var $blk; 534 var $blklvl; 535 var $ColumnAdjust; 536 537 var $ws; // Word spacing 538 539 var $HREF; 540 var $pgwidth; 541 var $fontlist; 542 var $oldx; 543 var $oldy; 544 var $B; 545 var $I; 546 547 var $tdbegin; 548 var $table; 549 var $cell; 550 var $col; 551 var $row; 552 553 var $divbegin; 554 var $divwidth; 555 var $divheight; 556 var $spanbgcolor; 557 558 // mPDF 6 Used for table cell (block-type) properties 559 var $cellTextAlign; 560 var $cellLineHeight; 561 var $cellLineStackingStrategy; 562 var $cellLineStackingShift; 563 564 // mPDF 6 Lists 565 var $listcounter; 566 var $listlvl; 567 var $listtype; 568 var $listitem; 569 570 var $pjustfinished; 571 var $ignorefollowingspaces; 572 var $SMALL; 573 var $BIG; 574 var $dash_on; 575 var $dotted_on; 576 577 var $textbuffer; 578 var $currentfontstyle; 579 var $currentfontfamily; 580 var $currentfontsize; 581 var $colorarray; 582 var $bgcolorarray; 583 var $internallink; 584 var $enabledtags; 585 586 var $lineheight; 587 var $default_lineheight_correction; 588 var $basepath; 589 var $textparam; 590 591 var $specialcontent; 592 var $selectoption; 593 var $objectbuffer; 594 595 // Table Rotation 596 var $table_rotate; 597 var $tbrot_maxw; 598 var $tbrot_maxh; 599 var $tablebuffer; 600 var $tbrot_align; 601 var $tbrot_Links; 602 603 var $keep_block_together; // Keep a Block from page-break-inside: avoid 604 605 var $tbrot_y0; 606 var $tbrot_x0; 607 var $tbrot_w; 608 var $tbrot_h; 609 610 var $mb_enc; 611 var $originalMbEnc; 612 var $originalMbRegexEnc; 613 614 var $directionality; 615 616 var $extgstates; // Used for alpha channel - Transparency (Watermark) 617 var $mgl; 618 var $mgt; 619 var $mgr; 620 var $mgb; 621 622 var $tts; 623 var $ttz; 624 var $tta; 625 626 // Best to alter the below variables using default stylesheet above 627 var $page_break_after_avoid; 628 var $margin_bottom_collapse; 629 var $default_font_size; // in pts 630 var $original_default_font_size; // used to save default sizes when using table default 631 var $original_default_font; 632 var $watermark_font; 633 var $defaultAlign; 634 635 // TABLE 636 var $defaultTableAlign; 637 var $tablethead; 638 var $thead_font_weight; 639 var $thead_font_style; 640 var $thead_font_smCaps; 641 var $thead_valign_default; 642 var $thead_textalign_default; 643 var $tabletfoot; 644 var $tfoot_font_weight; 645 var $tfoot_font_style; 646 var $tfoot_font_smCaps; 647 var $tfoot_valign_default; 648 var $tfoot_textalign_default; 649 650 var $trow_text_rotate; 651 652 var $cellPaddingL; 653 var $cellPaddingR; 654 var $cellPaddingT; 655 var $cellPaddingB; 656 var $table_border_attr_set; 657 var $table_border_css_set; 658 659 var $shrin_k; // factor with which to shrink tables - used internally - do not change 660 var $shrink_this_table_to_fit; // 0 or false to disable; value (if set) gives maximum factor to reduce fontsize 661 var $MarginCorrection; // corrects for OddEven Margins 662 var $margin_footer; 663 var $margin_header; 664 665 var $tabletheadjustfinished; 666 var $usingCoreFont; 667 var $charspacing; 668 669 var $js; 670 671 /** 672 * Set timeout for cURL 673 * 674 * @var int 675 */ 676 var $curlTimeout; 677 678 /** 679 * Set to true to follow redirects with cURL. 680 * 681 * @var bool 682 */ 683 var $curlFollowLocation; 684 685 /** 686 * Set your own CA certificate store for SSL Certificate verification when using cURL 687 * 688 * Useful setting to use on hosts with outdated CA certificates. 689 * 690 * Download the latest CA certificate from https://curl.haxx.se/docs/caextract.html 691 * 692 * @var string The absolute path to the pem file 693 */ 694 var $curlCaCertificate; 695 696 /** 697 * Set to true to allow unsafe SSL HTTPS requests. 698 * 699 * Can be useful when using CDN with HTTPS and if you don't want to configure settings with SSL certificates. 700 * 701 * @var bool 702 */ 703 var $curlAllowUnsafeSslRequests; 704 705 /** 706 * Set the proxy for cURL. 707 * 708 * @see https://curl.haxx.se/libcurl/c/CURLOPT_PROXY.html 709 * 710 * @var string 711 */ 712 var $curlProxy; 713 714 /** 715 * Set the proxy auth for cURL. 716 * 717 * @see https://curl.haxx.se/libcurl/c/CURLOPT_PROXYUSERPWD.html 718 * 719 * @var string 720 */ 721 var $curlProxyAuth; 722 723 /** 724 * Set the User-Agent header in the HTTP requests sent by cURL. 725 * 726 * @see https://curl.haxx.se/libcurl/c/CURLOPT_USERAGENT.html 727 * 728 * @var string User Agent header 729 */ 730 var $curlUserAgent; 731 732 // Private properties FROM FPDF 733 var $DisplayPreferences; 734 var $flowingBlockAttr; 735 736 var $page; // current page number 737 738 var $n; // current object number 739 var $n_js; // current object number 740 741 var $n_ocg_hidden; 742 var $n_ocg_print; 743 var $n_ocg_view; 744 745 var $offsets; // array of object offsets 746 var $buffer; // buffer holding in-memory PDF 747 var $pages; // array containing pages 748 var $state; // current document state 749 var $compress; // compression flag 750 751 var $DefOrientation; // default orientation 752 var $CurOrientation; // current orientation 753 var $OrientationChanges; // array indicating orientation changes 754 755 var $fwPt; 756 var $fhPt; // dimensions of page format in points 757 var $fw; 758 var $fh; // dimensions of page format in user unit 759 var $wPt; 760 var $hPt; // current dimensions of page in points 761 762 var $w; 763 var $h; // current dimensions of page in user unit 764 765 var $lMargin; // left margin 766 var $tMargin; // top margin 767 var $rMargin; // right margin 768 var $bMargin; // page break margin 769 var $cMarginL; // cell margin Left 770 var $cMarginR; // cell margin Right 771 var $cMarginT; // cell margin Left 772 var $cMarginB; // cell margin Right 773 774 var $DeflMargin; // Default left margin 775 var $DefrMargin; // Default right margin 776 777 var $x; 778 var $y; // current position in user unit for cell positioning 779 780 var $lasth; // height of last cell printed 781 var $LineWidth; // line width in user unit 782 783 var $CoreFonts; // array of standard font names 784 var $fonts; // array of used fonts 785 var $FontFiles; // array of font files 786 787 var $images; // array of used images 788 var $imageVars = []; // array of image vars 789 790 var $PageLinks; // array of links in pages 791 var $links; // array of internal links 792 var $FontFamily; // current font family 793 var $FontStyle; // current font style 794 var $CurrentFont; // current font info 795 var $FontSizePt; // current font size in points 796 var $FontSize; // current font size in user unit 797 var $DrawColor; // commands for drawing color 798 var $FillColor; // commands for filling color 799 var $TextColor; // commands for text color 800 var $ColorFlag; // indicates whether fill and text colors are different 801 var $autoPageBreak; // automatic page breaking 802 var $PageBreakTrigger; // threshold used to trigger page breaks 803 var $InFooter; // flag set when processing footer 804 805 var $InHTMLFooter; 806 var $processingFooter; // flag set when processing footer - added for columns 807 var $processingHeader; // flag set when processing header - added for columns 808 var $ZoomMode; // zoom display mode 809 var $LayoutMode; // layout display mode 810 var $title; // title 811 var $subject; // subject 812 var $author; // author 813 var $keywords; // keywords 814 var $creator; // creator 815 816 var $customProperties; // array of custom document properties 817 818 var $associatedFiles; // associated files (see SetAssociatedFiles below) 819 var $additionalXmpRdf; // additional rdf added in xmp 820 821 var $aliasNbPg; // alias for total number of pages 822 var $aliasNbPgGp; // alias for total number of pages in page group 823 824 var $ispre; 825 var $outerblocktags; 826 var $innerblocktags; 827 828 public $exposeVersion; 829 830 /** 831 * @var string 832 */ 833 private $fontDescriptor; 834 835 /** 836 * @var \Mpdf\Otl 837 */ 838 private $otl; 839 840 /** 841 * @var \Mpdf\CssManager 842 */ 843 private $cssManager; 844 845 /** 846 * @var \Mpdf\Gradient 847 */ 848 private $gradient; 849 850 /** 851 * @var \Mpdf\Image\Bmp 852 */ 853 private $bmp; 854 855 /** 856 * @var \Mpdf\Image\Wmf 857 */ 858 private $wmf; 859 860 /** 861 * @var \Mpdf\TableOfContents 862 */ 863 private $tableOfContents; 864 865 /** 866 * @var \Mpdf\Form 867 */ 868 private $form; 869 870 /** 871 * @var \Mpdf\DirectWrite 872 */ 873 private $directWrite; 874 875 /** 876 * @var \Mpdf\Cache 877 */ 878 private $cache; 879 880 /** 881 * @var \Mpdf\Fonts\FontCache 882 */ 883 private $fontCache; 884 885 /** 886 * @var \Mpdf\Fonts\FontFileFinder 887 */ 888 private $fontFileFinder; 889 890 /** 891 * @var \Mpdf\Tag 892 */ 893 private $tag; 894 895 /** 896 * @var \Mpdf\Barcode 897 * @todo solve Tag dependency and make private 898 */ 899 public $barcode; 900 901 /** 902 * @var \Mpdf\QrCode\QrCode 903 */ 904 private $qrcode; 905 906 /** 907 * @var \Mpdf\SizeConverter 908 */ 909 private $sizeConverter; 910 911 /** 912 * @var \Mpdf\Color\ColorConverter 913 */ 914 private $colorConverter; 915 916 /** 917 * @var \Mpdf\Color\ColorModeConverter 918 */ 919 private $colorModeConverter; 920 921 /** 922 * @var \Mpdf\Color\ColorSpaceRestrictor 923 */ 924 private $colorSpaceRestrictor; 925 926 /** 927 * @var \Mpdf\Hyphenator 928 */ 929 private $hyphenator; 930 931 /** 932 * @var \Mpdf\Pdf\Protection 933 */ 934 private $protection; 935 936 /** 937 * @var \Mpdf\RemoteContentFetcher 938 */ 939 private $remoteContentFetcher; 940 941 /** 942 * @var ImageProcessor 943 */ 944 private $imageProcessor; 945 946 /** 947 * @var \Mpdf\Language\LanguageToFontInterface 948 */ 949 private $languageToFont; 950 951 /** 952 * @var \Mpdf\Language\ScriptToLanguageInterface 953 */ 954 private $scriptToLanguage; 955 956 /** 957 * @var \Psr\Log\LoggerInterface 958 */ 959 private $logger; 960 961 /** 962 * @var \Mpdf\Writer\BaseWriter 963 */ 964 private $writer; 965 966 /** 967 * @var \Mpdf\Writer\FontWriter 968 */ 969 private $fontWriter; 970 971 /** 972 * @var \Mpdf\Writer\MetadataWriter 973 */ 974 private $metadataWriter; 975 976 /** 977 * @var \Mpdf\Writer\ImageWriter 978 */ 979 private $imageWriter; 980 981 /** 982 * @var \Mpdf\Writer\FormWriter 983 */ 984 private $formWriter; 985 986 /** 987 * @var \Mpdf\Writer\PageWriter 988 */ 989 private $pageWriter; 990 991 /** 992 * @var \Mpdf\Writer\BookmarkWriter 993 */ 994 private $bookmarkWriter; 995 996 /** 997 * @var \Mpdf\Writer\OptionalContentWriter 998 */ 999 private $optionalContentWriter; 1000 1001 /** 1002 * @var \Mpdf\Writer\ColorWriter 1003 */ 1004 private $colorWriter; 1005 1006 /** 1007 * @var \Mpdf\Writer\BackgroundWriter 1008 */ 1009 private $backgroundWriter; 1010 1011 /** 1012 * @var \Mpdf\Writer\JavaScriptWriter 1013 */ 1014 private $javaScriptWriter; 1015 1016 /** 1017 * @var \Mpdf\Writer\ResourceWriter 1018 */ 1019 private $resourceWriter; 1020 1021 /** 1022 * @var string[] 1023 */ 1024 private $services; 1025 1026 /** 1027 * @param mixed[] $config 1028 */ 1029 public function __construct(array $config = []) 1030 { 1031 $this->_dochecks(); 1032 1033 list( 1034 $mode, 1035 $format, 1036 $default_font_size, 1037 $default_font, 1038 $mgl, 1039 $mgr, 1040 $mgt, 1041 $mgb, 1042 $mgh, 1043 $mgf, 1044 $orientation 1045 ) = $this->initConstructorParams($config); 1046 1047 $this->logger = new NullLogger(); 1048 1049 $originalConfig = $config; 1050 $config = $this->initConfig($originalConfig); 1051 1052 $serviceFactory = new ServiceFactory(); 1053 $services = $serviceFactory->getServices( 1054 $this, 1055 $this->logger, 1056 $config, 1057 $this->restrictColorSpace, 1058 $this->languageToFont, 1059 $this->scriptToLanguage, 1060 $this->fontDescriptor, 1061 $this->bmp, 1062 $this->directWrite, 1063 $this->wmf 1064 ); 1065 1066 $this->services = []; 1067 1068 foreach ($services as $key => $service) { 1069 $this->{$key} = $service; 1070 $this->services[] = $key; 1071 } 1072 1073 $this->time0 = microtime(true); 1074 1075 $this->writingToC = false; 1076 1077 $this->layers = []; 1078 $this->current_layer = 0; 1079 $this->open_layer_pane = false; 1080 1081 $this->visibility = 'visible'; 1082 1083 $this->tableBackgrounds = []; 1084 $this->uniqstr = '20110230'; // mPDF 5.7.2 1085 $this->kt_y00 = 0; 1086 $this->kt_p00 = 0; 1087 $this->BMPonly = []; 1088 $this->page = 0; 1089 $this->n = 2; 1090 $this->buffer = ''; 1091 $this->objectbuffer = []; 1092 $this->pages = []; 1093 $this->OrientationChanges = []; 1094 $this->state = 0; 1095 $this->fonts = []; 1096 $this->FontFiles = []; 1097 $this->images = []; 1098 $this->links = []; 1099 $this->InFooter = false; 1100 $this->processingFooter = false; 1101 $this->processingHeader = false; 1102 $this->lasth = 0; 1103 $this->FontFamily = ''; 1104 $this->FontStyle = ''; 1105 $this->FontSizePt = 9; 1106 1107 // Small Caps 1108 $this->inMeter = false; 1109 $this->decimal_offset = 0; 1110 1111 $this->PDFAXwarnings = []; 1112 1113 $this->defTextColor = $this->TextColor = $this->SetTColor($this->colorConverter->convert(0, $this->PDFAXwarnings), true); 1114 $this->defDrawColor = $this->DrawColor = $this->SetDColor($this->colorConverter->convert(0, $this->PDFAXwarnings), true); 1115 $this->defFillColor = $this->FillColor = $this->SetFColor($this->colorConverter->convert(255, $this->PDFAXwarnings), true); 1116 1117 $this->upperCase = require __DIR__ . '/../data/upperCase.php'; 1118 1119 $this->extrapagebreak = true; // mPDF 6 pagebreaktype 1120 1121 $this->ColorFlag = false; 1122 $this->extgstates = []; 1123 1124 $this->mb_enc = 'windows-1252'; 1125 $this->originalMbEnc = mb_internal_encoding(); 1126 $this->originalMbRegexEnc = mb_regex_encoding(); 1127 1128 $this->directionality = 'ltr'; 1129 $this->defaultAlign = 'L'; 1130 $this->defaultTableAlign = 'L'; 1131 1132 $this->fixedPosBlockSave = []; 1133 $this->extraFontSubsets = 0; 1134 1135 $this->blockContext = 1; 1136 $this->floatDivs = []; 1137 $this->DisplayPreferences = ''; 1138 1139 // Tiling patterns used for backgrounds 1140 $this->patterns = []; 1141 $this->pageBackgrounds = []; 1142 $this->gradients = []; 1143 1144 // internal flag - used both for writing HTMLHeaders/Footers and FixedPos block 1145 $this->writingHTMLheader = false; 1146 // internal flag - used both for writing HTMLHeaders/Footers and FixedPos block 1147 $this->writingHTMLfooter = false; 1148 1149 $this->kwt_Reference = []; 1150 $this->kwt_BMoutlines = []; 1151 $this->kwt_toc = []; 1152 1153 $this->tbrot_BMoutlines = []; 1154 $this->tbrot_toc = []; 1155 1156 $this->col_BMoutlines = []; 1157 $this->col_toc = []; 1158 1159 $this->pgsIns = []; 1160 $this->PDFAXwarnings = []; 1161 $this->inlineDisplayOff = false; 1162 $this->lSpacingCSS = ''; 1163 $this->wSpacingCSS = ''; 1164 $this->fixedlSpacing = false; 1165 $this->minwSpacing = 0; 1166 1167 // Baseline for text 1168 $this->baselineC = 0.35; 1169 1170 // mPDF 5.7.3 inline text-decoration parameters 1171 // Sets default change in baseline for <sup> text as factor of preceeding fontsize 1172 // 0.35 has been recommended; 0.5 matches applications like MS Word 1173 $this->baselineSup = 0.5; 1174 1175 // Sets default change in baseline for <sub> text as factor of preceeding fontsize 1176 $this->baselineSub = -0.2; 1177 // Sets default height for <strike> text as factor of fontsize 1178 $this->baselineS = 0.3; 1179 // Sets default height for overline text as factor of fontsize 1180 $this->baselineO = 1.1; 1181 1182 $this->noImageFile = __DIR__ . '/../data/no_image.jpg'; 1183 $this->subPos = 0; 1184 1185 $this->fullImageHeight = false; 1186 $this->floatbuffer = []; 1187 $this->floatmargins = []; 1188 $this->formobjects = []; // array of Form Objects for WMF 1189 $this->InlineProperties = []; 1190 $this->InlineAnnots = []; 1191 $this->InlineBDF = []; // mPDF 6 1192 $this->InlineBDFctr = 0; // mPDF 6 1193 $this->tbrot_Annots = []; 1194 $this->kwt_Annots = []; 1195 $this->columnAnnots = []; 1196 $this->PageLinks = []; 1197 $this->OrientationChanges = []; 1198 $this->pageDim = []; 1199 $this->saveHTMLHeader = []; 1200 $this->saveHTMLFooter = []; 1201 $this->PageAnnots = []; 1202 $this->PageNumSubstitutions = []; 1203 $this->breakpoints = []; // used in columnbuffer 1204 $this->tableLevel = 0; 1205 $this->tbctr = []; // counter for nested tables at each level 1206 $this->page_box = []; 1207 $this->show_marks = ''; // crop or cross marks 1208 $this->kwt = false; 1209 $this->kwt_height = 0; 1210 $this->kwt_y0 = 0; 1211 $this->kwt_x0 = 0; 1212 $this->kwt_buffer = []; 1213 $this->kwt_Links = []; 1214 $this->kwt_moved = false; 1215 $this->kwt_saved = false; 1216 $this->PageNumSubstitutions = []; 1217 $this->base_table_properties = []; 1218 $this->borderstyles = ['inset', 'groove', 'outset', 'ridge', 'dotted', 'dashed', 'solid', 'double']; 1219 $this->tbrot_align = 'C'; 1220 1221 $this->pageHTMLheaders = []; 1222 $this->pageHTMLfooters = []; 1223 $this->HTMLheaderPageLinks = []; 1224 $this->HTMLheaderPageAnnots = []; 1225 1226 $this->HTMLheaderPageForms = []; 1227 $this->columnForms = []; 1228 $this->tbrotForms = []; 1229 1230 $this->pageoutput = []; 1231 1232 $this->bufferoutput = false; 1233 1234 $this->encrypted = false; 1235 1236 $this->BMoutlines = []; 1237 $this->ColActive = 0; // Flag indicating that columns are on (the index is being processed) 1238 $this->Reference = []; // Array containing the references 1239 $this->CurrCol = 0; // Current column number 1240 $this->ColL = [0]; // Array of Left pos of columns - absolute - needs Margin correction for Odd-Even 1241 $this->ColR = [0]; // Array of Right pos of columns - absolute pos - needs Margin correction for Odd-Even 1242 $this->ChangeColumn = 0; 1243 $this->columnbuffer = []; 1244 $this->ColDetails = []; // Keeps track of some column details 1245 $this->columnLinks = []; // Cross references PageLinks 1246 $this->substitute = []; // Array of substitution strings e.g. <ttz>112</ttz> 1247 $this->entsearch = []; // Array of HTML entities (>ASCII 127) to substitute 1248 $this->entsubstitute = []; // Array of substitution decimal unicode for the Hi entities 1249 $this->lastoptionaltag = ''; 1250 $this->charset_in = ''; 1251 $this->blk = []; 1252 $this->blklvl = 0; 1253 $this->tts = false; 1254 $this->ttz = false; 1255 $this->tta = false; 1256 $this->ispre = false; 1257 1258 $this->checkSIP = false; 1259 $this->checkSMP = false; 1260 $this->checkCJK = false; 1261 1262 $this->page_break_after_avoid = false; 1263 $this->margin_bottom_collapse = false; 1264 $this->tablethead = 0; 1265 $this->tabletfoot = 0; 1266 $this->table_border_attr_set = 0; 1267 $this->table_border_css_set = 0; 1268 $this->shrin_k = 1.0; 1269 $this->shrink_this_table_to_fit = 0; 1270 $this->MarginCorrection = 0; 1271 1272 $this->tabletheadjustfinished = false; 1273 $this->usingCoreFont = false; 1274 $this->charspacing = 0; 1275 1276 $this->autoPageBreak = true; 1277 1278 $this->_setPageSize($format, $orientation); 1279 $this->DefOrientation = $orientation; 1280 1281 $this->margin_header = $mgh; 1282 $this->margin_footer = $mgf; 1283 1284 $bmargin = $mgb; 1285 1286 $this->DeflMargin = $mgl; 1287 $this->DefrMargin = $mgr; 1288 1289 $this->orig_tMargin = $mgt; 1290 $this->orig_bMargin = $bmargin; 1291 $this->orig_lMargin = $this->DeflMargin; 1292 $this->orig_rMargin = $this->DefrMargin; 1293 $this->orig_hMargin = $this->margin_header; 1294 $this->orig_fMargin = $this->margin_footer; 1295 1296 if ($this->setAutoTopMargin == 'pad') { 1297 $mgt += $this->margin_header; 1298 } 1299 if ($this->setAutoBottomMargin == 'pad') { 1300 $mgb += $this->margin_footer; 1301 } 1302 1303 // sets l r t margin 1304 $this->SetMargins($this->DeflMargin, $this->DefrMargin, $mgt); 1305 1306 // Automatic page break 1307 // sets $this->bMargin & PageBreakTrigger 1308 $this->SetAutoPageBreak($this->autoPageBreak, $bmargin); 1309 1310 $this->pgwidth = $this->w - $this->lMargin - $this->rMargin; 1311 1312 // Interior cell margin (1 mm) ? not used 1313 $this->cMarginL = 1; 1314 $this->cMarginR = 1; 1315 1316 // Line width (0.2 mm) 1317 $this->LineWidth = .567 / Mpdf::SCALE; 1318 1319 // Enable all tags as default 1320 $this->DisableTags(); 1321 // Full width display mode 1322 $this->SetDisplayMode(100); // fullwidth? 'fullpage' 1323 1324 // Compression 1325 $this->SetCompression(true); 1326 // Set default display preferences 1327 $this->SetDisplayPreferences(''); 1328 1329 $this->initFontConfig($originalConfig); 1330 1331 // Available fonts 1332 $this->available_unifonts = []; 1333 foreach ($this->fontdata as $f => $fs) { 1334 if (isset($fs['R']) && $fs['R']) { 1335 $this->available_unifonts[] = $f; 1336 } 1337 if (isset($fs['B']) && $fs['B']) { 1338 $this->available_unifonts[] = $f . 'B'; 1339 } 1340 if (isset($fs['I']) && $fs['I']) { 1341 $this->available_unifonts[] = $f . 'I'; 1342 } 1343 if (isset($fs['BI']) && $fs['BI']) { 1344 $this->available_unifonts[] = $f . 'BI'; 1345 } 1346 } 1347 1348 $this->default_available_fonts = $this->available_unifonts; 1349 1350 $optcore = false; 1351 $onlyCoreFonts = false; 1352 if (preg_match('/([\-+])aCJK/i', $mode, $m)) { 1353 $mode = preg_replace('/([\-+])aCJK/i', '', $mode); // mPDF 6 1354 if ($m[1] == '+') { 1355 $this->useAdobeCJK = true; 1356 } else { 1357 $this->useAdobeCJK = false; 1358 } 1359 } 1360 1361 if (strlen($mode) == 1) { 1362 if ($mode == 's') { 1363 $this->percentSubset = 100; 1364 $mode = ''; 1365 } elseif ($mode == 'c') { 1366 $onlyCoreFonts = true; 1367 $mode = ''; 1368 } 1369 } elseif (substr($mode, -2) == '-s') { 1370 $this->percentSubset = 100; 1371 $mode = substr($mode, 0, strlen($mode) - 2); 1372 } elseif (substr($mode, -2) == '-c') { 1373 $onlyCoreFonts = true; 1374 $mode = substr($mode, 0, strlen($mode) - 2); 1375 } elseif (substr($mode, -2) == '-x') { 1376 $optcore = true; 1377 $mode = substr($mode, 0, strlen($mode) - 2); 1378 } 1379 1380 // Autodetect if mode is a language_country string (en-GB or en_GB or en) 1381 if ($mode && $mode != 'UTF-8') { // mPDF 6 1382 list ($coreSuitable, $mpdf_pdf_unifont) = $this->languageToFont->getLanguageOptions($mode, $this->useAdobeCJK); 1383 if ($coreSuitable && $optcore) { 1384 $onlyCoreFonts = true; 1385 } 1386 if ($mpdf_pdf_unifont) { // mPDF 6 1387 $default_font = $mpdf_pdf_unifont; 1388 } 1389 $this->currentLang = $mode; 1390 $this->default_lang = $mode; 1391 } 1392 1393 $this->onlyCoreFonts = $onlyCoreFonts; 1394 1395 if ($this->onlyCoreFonts) { 1396 $this->setMBencoding('windows-1252'); // sets $this->mb_enc 1397 } else { 1398 $this->setMBencoding('UTF-8'); // sets $this->mb_enc 1399 } 1400 @mb_regex_encoding('UTF-8'); // required only for mb_ereg... and mb_split functions 1401 1402 // Adobe CJK fonts 1403 $this->available_CJK_fonts = [ 1404 'gb', 1405 'big5', 1406 'sjis', 1407 'uhc', 1408 'gbB', 1409 'big5B', 1410 'sjisB', 1411 'uhcB', 1412 'gbI', 1413 'big5I', 1414 'sjisI', 1415 'uhcI', 1416 'gbBI', 1417 'big5BI', 1418 'sjisBI', 1419 'uhcBI', 1420 ]; 1421 1422 // Standard fonts 1423 $this->CoreFonts = [ 1424 'ccourier' => 'Courier', 1425 'ccourierB' => 'Courier-Bold', 1426 'ccourierI' => 'Courier-Oblique', 1427 'ccourierBI' => 'Courier-BoldOblique', 1428 'chelvetica' => 'Helvetica', 1429 'chelveticaB' => 'Helvetica-Bold', 1430 'chelveticaI' => 'Helvetica-Oblique', 1431 'chelveticaBI' => 'Helvetica-BoldOblique', 1432 'ctimes' => 'Times-Roman', 1433 'ctimesB' => 'Times-Bold', 1434 'ctimesI' => 'Times-Italic', 1435 'ctimesBI' => 'Times-BoldItalic', 1436 'csymbol' => 'Symbol', 1437 'czapfdingbats' => 'ZapfDingbats' 1438 ]; 1439 1440 $this->fontlist = [ 1441 "ctimes", 1442 "ccourier", 1443 "chelvetica", 1444 "csymbol", 1445 "czapfdingbats" 1446 ]; 1447 1448 // Substitutions 1449 $this->setHiEntitySubstitutions(); 1450 1451 if ($this->onlyCoreFonts) { 1452 $this->useSubstitutions = true; 1453 $this->SetSubstitutions(); 1454 } else { 1455 $this->useSubstitutions = $config['useSubstitutions']; 1456 } 1457 1458 if (file_exists($this->defaultCssFile)) { 1459 $css = file_get_contents($this->defaultCssFile); 1460 $this->cssManager->ReadCSS('<style> ' . $css . ' </style>'); 1461 } else { 1462 throw new \Mpdf\MpdfException(sprintf('Unable to read default CSS file "%s"', $this->defaultCssFile)); 1463 } 1464 1465 if ($default_font == '') { 1466 if ($this->onlyCoreFonts) { 1467 if (in_array(strtolower($this->defaultCSS['BODY']['FONT-FAMILY']), $this->mono_fonts)) { 1468 $default_font = 'ccourier'; 1469 } elseif (in_array(strtolower($this->defaultCSS['BODY']['FONT-FAMILY']), $this->sans_fonts)) { 1470 $default_font = 'chelvetica'; 1471 } else { 1472 $default_font = 'ctimes'; 1473 } 1474 } else { 1475 $default_font = $this->defaultCSS['BODY']['FONT-FAMILY']; 1476 } 1477 } 1478 if (!$default_font_size) { 1479 $mmsize = $this->sizeConverter->convert($this->defaultCSS['BODY']['FONT-SIZE']); 1480 $default_font_size = $mmsize * (Mpdf::SCALE); 1481 } 1482 1483 if ($default_font) { 1484 $this->SetDefaultFont($default_font); 1485 } 1486 if ($default_font_size) { 1487 $this->SetDefaultFontSize($default_font_size); 1488 } 1489 1490 $this->SetLineHeight(); // lineheight is in mm 1491 1492 $this->SetFColor($this->colorConverter->convert(255, $this->PDFAXwarnings)); 1493 $this->HREF = ''; 1494 $this->oldy = -1; 1495 $this->B = 0; 1496 $this->I = 0; 1497 1498 // mPDF 6 Lists 1499 $this->listlvl = 0; 1500 $this->listtype = []; 1501 $this->listitem = []; 1502 $this->listcounter = []; 1503 1504 $this->tdbegin = false; 1505 $this->table = []; 1506 $this->cell = []; 1507 $this->col = -1; 1508 $this->row = -1; 1509 $this->cellBorderBuffer = []; 1510 1511 $this->divbegin = false; 1512 // mPDF 6 1513 $this->cellTextAlign = ''; 1514 $this->cellLineHeight = ''; 1515 $this->cellLineStackingStrategy = ''; 1516 $this->cellLineStackingShift = ''; 1517 1518 $this->divwidth = 0; 1519 $this->divheight = 0; 1520 $this->spanbgcolor = false; 1521 $this->spanborder = false; 1522 $this->spanborddet = []; 1523 1524 $this->blockjustfinished = false; 1525 $this->ignorefollowingspaces = true; // in order to eliminate exceeding left-side spaces 1526 $this->dash_on = false; 1527 $this->dotted_on = false; 1528 $this->textshadow = ''; 1529 1530 $this->currentfontfamily = ''; 1531 $this->currentfontsize = ''; 1532 $this->currentfontstyle = ''; 1533 $this->colorarray = ''; // mPDF 6 1534 $this->spanbgcolorarray = ''; // mPDF 6 1535 $this->textbuffer = []; 1536 $this->internallink = []; 1537 $this->basepath = ""; 1538 1539 $this->SetBasePath(''); 1540 1541 $this->textparam = []; 1542 1543 $this->specialcontent = ''; 1544 $this->selectoption = []; 1545 } 1546 1547 public function cleanup() 1548 { 1549 mb_internal_encoding($this->originalMbEnc); 1550 @mb_regex_encoding($this->originalMbRegexEnc); 1551 } 1552 1553 /** 1554 * @param \Psr\Log\LoggerInterface 1555 * 1556 * @return \Mpdf\Mpdf 1557 */ 1558 public function setLogger(LoggerInterface $logger) 1559 { 1560 $this->logger = $logger; 1561 1562 foreach ($this->services as $name) { 1563 if ($this->$name && $this->$name instanceof \Psr\Log\LoggerAwareInterface) { 1564 $this->$name->setLogger($logger); 1565 } 1566 } 1567 1568 return $this; 1569 } 1570 1571 private function initConfig(array $config) 1572 { 1573 $configObject = new ConfigVariables(); 1574 $defaults = $configObject->getDefaults(); 1575 $config = array_intersect_key($config + $defaults, $defaults); 1576 1577 foreach ($config as $var => $val) { 1578 $this->{$var} = $val; 1579 } 1580 1581 return $config; 1582 } 1583 1584 private function initConstructorParams(array $config) 1585 { 1586 $constructor = [ 1587 'mode' => '', 1588 'format' => 'A4', 1589 'default_font_size' => 0, 1590 'default_font' => '', 1591 'margin_left' => 15, 1592 'margin_right' => 15, 1593 'margin_top' => 16, 1594 'margin_bottom' => 16, 1595 'margin_header' => 9, 1596 'margin_footer' => 9, 1597 'orientation' => 'P', 1598 ]; 1599 1600 foreach ($constructor as $key => $val) { 1601 if (isset($config[$key])) { 1602 $constructor[$key] = $config[$key]; 1603 } 1604 } 1605 1606 return array_values($constructor); 1607 } 1608 1609 private function initFontConfig(array $config) 1610 { 1611 $configObject = new FontVariables(); 1612 $defaults = $configObject->getDefaults(); 1613 $config = array_intersect_key($config + $defaults, $defaults); 1614 foreach ($config as $var => $val) { 1615 $this->{$var} = $val; 1616 } 1617 1618 return $config; 1619 } 1620 1621 function _setPageSize($format, &$orientation) 1622 { 1623 if (is_string($format)) { 1624 1625 if (empty($format)) { 1626 $format = 'A4'; 1627 } 1628 1629 // e.g. A4-L = A4 landscape, A4-P = A4 portrait 1630 if (preg_match('/([0-9a-zA-Z]*)-([P,L])/i', $format, $m)) { 1631 $format = $m[1]; 1632 $orientation = $m[2]; 1633 } elseif (empty($orientation)) { 1634 $orientation = 'P'; 1635 } 1636 1637 $format = PageFormat::getSizeFromName($format); 1638 1639 $this->fwPt = $format[0]; 1640 $this->fhPt = $format[1]; 1641 1642 } else { 1643 1644 if (!$format[0] || !$format[1]) { 1645 throw new \Mpdf\MpdfException('Invalid page format: ' . $format[0] . ' ' . $format[1]); 1646 } 1647 1648 $this->fwPt = $format[0] * Mpdf::SCALE; 1649 $this->fhPt = $format[1] * Mpdf::SCALE; 1650 } 1651 1652 $this->fw = $this->fwPt / Mpdf::SCALE; 1653 $this->fh = $this->fhPt / Mpdf::SCALE; 1654 1655 // Page orientation 1656 $orientation = strtolower($orientation); 1657 if ($orientation === 'p' || $orientation == 'portrait') { 1658 $orientation = 'P'; 1659 $this->wPt = $this->fwPt; 1660 $this->hPt = $this->fhPt; 1661 } elseif ($orientation === 'l' || $orientation == 'landscape') { 1662 $orientation = 'L'; 1663 $this->wPt = $this->fhPt; 1664 $this->hPt = $this->fwPt; 1665 } else { 1666 throw new \Mpdf\MpdfException('Incorrect orientation: ' . $orientation); 1667 } 1668 1669 $this->CurOrientation = $orientation; 1670 1671 $this->w = $this->wPt / Mpdf::SCALE; 1672 $this->h = $this->hPt / Mpdf::SCALE; 1673 } 1674 1675 function RestrictUnicodeFonts($res) 1676 { 1677 // $res = array of (Unicode) fonts to restrict to: e.g. norasi|norasiB - language specific 1678 if (count($res)) { // Leave full list of available fonts if passed blank array 1679 $this->available_unifonts = $res; 1680 } else { 1681 $this->available_unifonts = $this->default_available_fonts; 1682 } 1683 if (count($this->available_unifonts) == 0) { 1684 $this->available_unifonts[] = $this->default_available_fonts[0]; 1685 } 1686 $this->available_unifonts = array_values($this->available_unifonts); 1687 } 1688 1689 function setMBencoding($enc) 1690 { 1691 if ($this->mb_enc != $enc) { 1692 $this->mb_enc = $enc; 1693 mb_internal_encoding($this->mb_enc); 1694 } 1695 } 1696 1697 function SetMargins($left, $right, $top) 1698 { 1699 // Set left, top and right margins 1700 $this->lMargin = $left; 1701 $this->rMargin = $right; 1702 $this->tMargin = $top; 1703 } 1704 1705 function ResetMargins() 1706 { 1707 // ReSet left, top margins 1708 if (($this->forcePortraitHeaders || $this->forcePortraitMargins) && $this->DefOrientation == 'P' && $this->CurOrientation == 'L') { 1709 if (($this->mirrorMargins) && (($this->page) % 2 == 0)) { // EVEN 1710 $this->tMargin = $this->orig_rMargin; 1711 $this->bMargin = $this->orig_lMargin; 1712 } else { // ODD // OR NOT MIRRORING MARGINS/FOOTERS 1713 $this->tMargin = $this->orig_lMargin; 1714 $this->bMargin = $this->orig_rMargin; 1715 } 1716 $this->lMargin = $this->DeflMargin; 1717 $this->rMargin = $this->DefrMargin; 1718 $this->MarginCorrection = 0; 1719 $this->PageBreakTrigger = $this->h - $this->bMargin; 1720 } elseif (($this->mirrorMargins) && (($this->page) % 2 == 0)) { // EVEN 1721 $this->lMargin = $this->DefrMargin; 1722 $this->rMargin = $this->DeflMargin; 1723 $this->MarginCorrection = $this->DefrMargin - $this->DeflMargin; 1724 } else { // ODD // OR NOT MIRRORING MARGINS/FOOTERS 1725 $this->lMargin = $this->DeflMargin; 1726 $this->rMargin = $this->DefrMargin; 1727 if ($this->mirrorMargins) { 1728 $this->MarginCorrection = $this->DeflMargin - $this->DefrMargin; 1729 } 1730 } 1731 $this->x = $this->lMargin; 1732 } 1733 1734 function SetLeftMargin($margin) 1735 { 1736 // Set left margin 1737 $this->lMargin = $margin; 1738 if ($this->page > 0 and $this->x < $margin) { 1739 $this->x = $margin; 1740 } 1741 } 1742 1743 function SetTopMargin($margin) 1744 { 1745 // Set top margin 1746 $this->tMargin = $margin; 1747 } 1748 1749 function SetRightMargin($margin) 1750 { 1751 // Set right margin 1752 $this->rMargin = $margin; 1753 } 1754 1755 function SetAutoPageBreak($auto, $margin = 0) 1756 { 1757 // Set auto page break mode and triggering margin 1758 $this->autoPageBreak = $auto; 1759 $this->bMargin = $margin; 1760 $this->PageBreakTrigger = $this->h - $margin; 1761 } 1762 1763 function SetDisplayMode($zoom, $layout = 'continuous') 1764 { 1765 $allowedZoomModes = ['fullpage', 'fullwidth', 'real', 'default', 'none']; 1766 1767 if (in_array($zoom, $allowedZoomModes, true) || is_numeric($zoom)) { 1768 $this->ZoomMode = $zoom; 1769 } else { 1770 throw new \Mpdf\MpdfException('Incorrect zoom display mode: ' . $zoom); 1771 } 1772 1773 $allowedLayoutModes = ['single', 'continuous', 'two', 'twoleft', 'tworight', 'default']; 1774 1775 if (in_array($layout, $allowedLayoutModes, true)) { 1776 $this->LayoutMode = $layout; 1777 } else { 1778 throw new \Mpdf\MpdfException('Incorrect layout display mode: ' . $layout); 1779 } 1780 } 1781 1782 function SetCompression($compress) 1783 { 1784 // Set page compression 1785 if (function_exists('gzcompress')) { 1786 $this->compress = $compress; 1787 } else { 1788 $this->compress = false; 1789 } 1790 } 1791 1792 function SetTitle($title) 1793 { 1794 // Title of document // Arrives as UTF-8 1795 $this->title = $title; 1796 } 1797 1798 function SetSubject($subject) 1799 { 1800 // Subject of document 1801 $this->subject = $subject; 1802 } 1803 1804 function SetAuthor($author) 1805 { 1806 // Author of document 1807 $this->author = $author; 1808 } 1809 1810 function SetKeywords($keywords) 1811 { 1812 // Keywords of document 1813 $this->keywords = $keywords; 1814 } 1815 1816 function SetCreator($creator) 1817 { 1818 // Creator of document 1819 $this->creator = $creator; 1820 } 1821 1822 function AddCustomProperty($key, $value) 1823 { 1824 $this->customProperties[$key] = $value; 1825 } 1826 1827 /** 1828 * Set one or multiple associated file ("/AF" as required by PDF/A-3) 1829 * 1830 * param $files is an array of hash containing: 1831 * path: file path on FS 1832 * content: file content 1833 * name: file name (not necessarily the same as the file on FS) 1834 * mime (optional): file mime type (will show up as /Subtype in the PDF) 1835 * description (optional): file description 1836 * AFRelationship (optional): PDF/A-3 AFRelationship (e.g. "Alternative") 1837 * 1838 * e.g. to associate 1 file: 1839 * [[ 1840 * 'path' => 'tmp/1234.xml', 1841 * 'content' => 'file content', 1842 * 'name' => 'public_name.xml', 1843 * 'mime' => 'text/xml', 1844 * 'description' => 'foo', 1845 * 'AFRelationship' => 'Alternative', 1846 * ]] 1847 * 1848 * @param mixed[] $files Array of arrays of associated files. See above 1849 */ 1850 function SetAssociatedFiles(array $files) 1851 { 1852 $this->associatedFiles = $files; 1853 } 1854 1855 function SetAdditionalXmpRdf($s) 1856 { 1857 $this->additionalXmpRdf = $s; 1858 } 1859 1860 function SetAnchor2Bookmark($x) 1861 { 1862 $this->anchor2Bookmark = $x; 1863 } 1864 1865 public function AliasNbPages($alias = '{nb}') 1866 { 1867 // Define an alias for total number of pages 1868 $this->aliasNbPg = $alias; 1869 } 1870 1871 public function AliasNbPageGroups($alias = '{nbpg}') 1872 { 1873 // Define an alias for total number of pages in a group 1874 $this->aliasNbPgGp = $alias; 1875 } 1876 1877 function SetAlpha($alpha, $bm = 'Normal', $return = false, $mode = 'B') 1878 { 1879 // alpha: real value from 0 (transparent) to 1 (opaque) 1880 // bm: blend mode, one of the following: 1881 // Normal, Multiply, Screen, Overlay, Darken, Lighten, ColorDodge, ColorBurn, 1882 // HardLight, SoftLight, Difference, Exclusion, Hue, Saturation, Color, Luminosity 1883 // set alpha for stroking (CA) and non-stroking (ca) operations 1884 // mode determines F (fill) S (stroke) B (both) 1885 if (($this->PDFA || $this->PDFX) && $alpha != 1) { 1886 if (($this->PDFA && !$this->PDFAauto) || ($this->PDFX && !$this->PDFXauto)) { 1887 $this->PDFAXwarnings[] = "Image opacity must be 100% (Opacity changed to 100%)"; 1888 } 1889 $alpha = 1; 1890 } 1891 $a = ['BM' => '/' . $bm]; 1892 if ($mode == 'F' || $mode == 'B') { 1893 $a['ca'] = $alpha; // mPDF 5.7.2 1894 } 1895 if ($mode == 'S' || $mode == 'B') { 1896 $a['CA'] = $alpha; // mPDF 5.7.2 1897 } 1898 $gs = $this->AddExtGState($a); 1899 if ($return) { 1900 return sprintf('/GS%d gs', $gs); 1901 } else { 1902 $this->writer->write(sprintf('/GS%d gs', $gs)); 1903 } 1904 } 1905 1906 function AddExtGState($parms) 1907 { 1908 $n = count($this->extgstates); 1909 // check if graphics state already exists 1910 for ($i = 1; $i <= $n; $i++) { 1911 if (count($this->extgstates[$i]['parms']) == count($parms)) { 1912 $same = true; 1913 foreach ($this->extgstates[$i]['parms'] as $k => $v) { 1914 if (!isset($parms[$k]) || $parms[$k] != $v) { 1915 $same = false; 1916 break; 1917 } 1918 } 1919 if ($same) { 1920 return $i; 1921 } 1922 } 1923 } 1924 $n++; 1925 $this->extgstates[$n]['parms'] = $parms; 1926 return $n; 1927 } 1928 1929 function SetVisibility($v) 1930 { 1931 if (($this->PDFA || $this->PDFX) && $this->visibility != 'visible') { 1932 $this->PDFAXwarnings[] = "Cannot set visibility to anything other than full when using PDFA or PDFX"; 1933 return ''; 1934 } elseif (!$this->PDFA && !$this->PDFX) { 1935 $this->pdf_version = '1.5'; 1936 } 1937 if ($this->visibility != 'visible') { 1938 $this->writer->write('EMC'); 1939 $this->hasOC = intval($this->hasOC); 1940 } 1941 if ($v == 'printonly') { 1942 $this->writer->write('/OC /OC1 BDC'); 1943 $this->hasOC = ($this->hasOC | 1); 1944 } elseif ($v == 'screenonly') { 1945 $this->writer->write('/OC /OC2 BDC'); 1946 $this->hasOC = ($this->hasOC | 2); 1947 } elseif ($v == 'hidden') { 1948 $this->writer->write('/OC /OC3 BDC'); 1949 $this->hasOC = ($this->hasOC | 4); 1950 } elseif ($v != 'visible') { 1951 throw new \Mpdf\MpdfException('Incorrect visibility: ' . $v); 1952 } 1953 $this->visibility = $v; 1954 } 1955 1956 function Open() 1957 { 1958 // Begin document 1959 if ($this->state == 0) { 1960 // Was is function _begindoc() 1961 // Start document 1962 $this->state = 1; 1963 $this->writer->write('%PDF-' . $this->pdf_version); 1964 $this->writer->write('%' . chr(226) . chr(227) . chr(207) . chr(211)); // 4 chars > 128 to show binary file 1965 } 1966 } 1967 1968 function Close() 1969 { 1970 // @log Closing last page 1971 1972 // Terminate document 1973 if ($this->state == 3) { 1974 return; 1975 } 1976 if ($this->page == 0) { 1977 $this->AddPage($this->CurOrientation); 1978 } 1979 if (count($this->cellBorderBuffer)) { 1980 $this->printcellbuffer(); 1981 } // *TABLES* 1982 if ($this->tablebuffer) { 1983 $this->printtablebuffer(); 1984 } // *TABLES* 1985 /* -- COLUMNS -- */ 1986 1987 if ($this->ColActive) { 1988 $this->SetColumns(0); 1989 $this->ColActive = 0; 1990 if (count($this->columnbuffer)) { 1991 $this->printcolumnbuffer(); 1992 } 1993 } 1994 /* -- END COLUMNS -- */ 1995 1996 // BODY Backgrounds 1997 $s = ''; 1998 1999 $s .= $this->PrintBodyBackgrounds(); 2000 $s .= $this->PrintPageBackgrounds(); 2001 2002 $this->pages[$this->page] = preg_replace( 2003 '/(___BACKGROUND___PATTERNS' . $this->uniqstr . ')/', 2004 "\n" . $s . "\n" . '\\1', 2005 $this->pages[$this->page] 2006 ); 2007 2008 $this->pageBackgrounds = []; 2009 2010 if ($this->visibility != 'visible') { 2011 $this->SetVisibility('visible'); 2012 } 2013 2014 $this->EndLayer(); 2015 2016 if (!$this->tableOfContents->TOCmark) { // Page footer 2017 $this->InFooter = true; 2018 $this->Footer(); 2019 $this->InFooter = false; 2020 } 2021 2022 if ($this->tableOfContents->TOCmark || count($this->tableOfContents->m_TOC)) { 2023 $this->tableOfContents->insertTOC(); 2024 } 2025 2026 // *TOC* 2027 // Close page 2028 $this->_endpage(); 2029 2030 // Close document 2031 $this->_enddoc(); 2032 } 2033 2034 /* -- BACKGROUNDS -- */ 2035 2036 function _resizeBackgroundImage($imw, $imh, $cw, $ch, $resize, $repx, $repy, $pba = [], $size = []) 2037 { 2038 // pba is background positioning area (from CSS background-origin) may not always be set [x,y,w,h] 2039 // size is from CSS3 background-size - takes precendence over old resize 2040 // $w - absolute length or % or auto or cover | contain 2041 // $h - absolute length or % or auto or cover | contain 2042 if (isset($pba['w'])) { 2043 $cw = $pba['w']; 2044 } 2045 if (isset($pba['h'])) { 2046 $ch = $pba['h']; 2047 } 2048 2049 $cw = $cw * Mpdf::SCALE; 2050 $ch = $ch * Mpdf::SCALE; 2051 if (empty($size) && !$resize) { 2052 return [$imw, $imh, $repx, $repy]; 2053 } 2054 2055 if (isset($size['w']) && $size['w']) { 2056 if ($size['w'] == 'contain') { 2057 // Scale the image, while preserving its intrinsic aspect ratio (if any), 2058 // to the largest size such that both its width and its height can fit inside the background positioning area. 2059 // Same as resize==3 2060 $h = $imh * $cw / $imw; 2061 $w = $cw; 2062 if ($h > $ch) { 2063 $w = $w * $ch / $h; 2064 $h = $ch; 2065 } 2066 } elseif ($size['w'] == 'cover') { 2067 // Scale the image, while preserving its intrinsic aspect ratio (if any), 2068 // to the smallest size such that both its width and its height can completely cover the background positioning area. 2069 $h = $imh * $cw / $imw; 2070 $w = $cw; 2071 if ($h < $ch) { 2072 $w = $w * $h / $ch; 2073 $h = $ch; 2074 } 2075 } else { 2076 if (stristr($size['w'], '%')) { 2077 $size['w'] = (float) $size['w']; 2078 $size['w'] /= 100; 2079 $size['w'] = ($cw * $size['w']); 2080 } 2081 if (stristr($size['h'], '%')) { 2082 $size['h'] = (float) $size['h']; 2083 $size['h'] /= 100; 2084 $size['h'] = ($ch * $size['h']); 2085 } 2086 if ($size['w'] == 'auto' && $size['h'] == 'auto') { 2087 $w = $imw; 2088 $h = $imh; 2089 } elseif ($size['w'] == 'auto' && $size['h'] != 'auto') { 2090 $w = $imw * $size['h'] / $imh; 2091 $h = $size['h']; 2092 } elseif ($size['w'] != 'auto' && $size['h'] == 'auto') { 2093 $h = $imh * $size['w'] / $imw; 2094 $w = $size['w']; 2095 } else { 2096 $w = $size['w']; 2097 $h = $size['h']; 2098 } 2099 } 2100 return [$w, $h, $repx, $repy]; 2101 } elseif ($resize == 1 && $imw > $cw) { 2102 $h = $imh * $cw / $imw; 2103 return [$cw, $h, $repx, $repy]; 2104 } elseif ($resize == 2 && $imh > $ch) { 2105 $w = $imw * $ch / $imh; 2106 return [$w, $ch, $repx, $repy]; 2107 } elseif ($resize == 3) { 2108 $w = $imw; 2109 $h = $imh; 2110 if ($w > $cw) { 2111 $h = $h * $cw / $w; 2112 $w = $cw; 2113 } 2114 if ($h > $ch) { 2115 $w = $w * $ch / $h; 2116 $h = $ch; 2117 } 2118 return [$w, $h, $repx, $repy]; 2119 } elseif ($resize == 4) { 2120 $h = $imh * $cw / $imw; 2121 return [$cw, $h, $repx, $repy]; 2122 } elseif ($resize == 5) { 2123 $w = $imw * $ch / $imh; 2124 return [$w, $ch, $repx, $repy]; 2125 } elseif ($resize == 6) { 2126 return [$cw, $ch, $repx, $repy]; 2127 } 2128 return [$imw, $imh, $repx, $repy]; 2129 } 2130 2131 function SetBackground(&$properties, &$maxwidth) 2132 { 2133 if (isset($properties['BACKGROUND-ORIGIN']) && ($properties['BACKGROUND-ORIGIN'] == 'border-box' || $properties['BACKGROUND-ORIGIN'] == 'content-box')) { 2134 $origin = $properties['BACKGROUND-ORIGIN']; 2135 } else { 2136 $origin = 'padding-box'; 2137 } 2138 2139 if (isset($properties['BACKGROUND-SIZE'])) { 2140 if (stristr($properties['BACKGROUND-SIZE'], 'contain')) { 2141 $bsw = $bsh = 'contain'; 2142 } elseif (stristr($properties['BACKGROUND-SIZE'], 'cover')) { 2143 $bsw = $bsh = 'cover'; 2144 } else { 2145 $bsw = $bsh = 'auto'; 2146 $sz = preg_split('/\s+/', trim($properties['BACKGROUND-SIZE'])); 2147 if (count($sz) == 2) { 2148 $bsw = $sz[0]; 2149 $bsh = $sz[1]; 2150 } else { 2151 $bsw = $sz[0]; 2152 } 2153 if (!stristr($bsw, '%') && !stristr($bsw, 'auto')) { 2154 $bsw = $this->sizeConverter->convert($bsw, $maxwidth, $this->FontSize); 2155 } 2156 if (!stristr($bsh, '%') && !stristr($bsh, 'auto')) { 2157 $bsh = $this->sizeConverter->convert($bsh, $maxwidth, $this->FontSize); 2158 } 2159 } 2160 $size = ['w' => $bsw, 'h' => $bsh]; 2161 } else { 2162 $size = false; 2163 } // mPDF 6 2164 if (preg_match('/(-moz-)*(repeating-)*(linear|radial)-gradient/', $properties['BACKGROUND-IMAGE'])) { 2165 return ['gradient' => $properties['BACKGROUND-IMAGE'], 'origin' => $origin, 'size' => $size]; 2166 } else { 2167 $file = $properties['BACKGROUND-IMAGE']; 2168 $sizesarray = $this->Image($file, 0, 0, 0, 0, '', '', false, false, false, false, true); 2169 if (isset($sizesarray['IMAGE_ID'])) { 2170 $image_id = $sizesarray['IMAGE_ID']; 2171 $orig_w = $sizesarray['WIDTH'] * Mpdf::SCALE; // in user units i.e. mm 2172 $orig_h = $sizesarray['HEIGHT'] * Mpdf::SCALE; // (using $this->img_dpi) 2173 if (isset($properties['BACKGROUND-IMAGE-RESOLUTION'])) { 2174 if (preg_match('/from-image/i', $properties['BACKGROUND-IMAGE-RESOLUTION']) && isset($sizesarray['set-dpi']) && $sizesarray['set-dpi'] > 0) { 2175 $orig_w *= $this->img_dpi / $sizesarray['set-dpi']; 2176 $orig_h *= $this->img_dpi / $sizesarray['set-dpi']; 2177 } elseif (preg_match('/(\d+)dpi/i', $properties['BACKGROUND-IMAGE-RESOLUTION'], $m)) { 2178 $dpi = $m[1]; 2179 if ($dpi > 0) { 2180 $orig_w *= $this->img_dpi / $dpi; 2181 $orig_h *= $this->img_dpi / $dpi; 2182 } 2183 } 2184 } 2185 $x_repeat = true; 2186 $y_repeat = true; 2187 if (isset($properties['BACKGROUND-REPEAT'])) { 2188 if ($properties['BACKGROUND-REPEAT'] == 'no-repeat' || $properties['BACKGROUND-REPEAT'] == 'repeat-x') { 2189 $y_repeat = false; 2190 } 2191 if ($properties['BACKGROUND-REPEAT'] == 'no-repeat' || $properties['BACKGROUND-REPEAT'] == 'repeat-y') { 2192 $x_repeat = false; 2193 } 2194 } 2195 $x_pos = 0; 2196 $y_pos = 0; 2197 if (isset($properties['BACKGROUND-POSITION'])) { 2198 $ppos = preg_split('/\s+/', $properties['BACKGROUND-POSITION']); 2199 $x_pos = $ppos[0]; 2200 $y_pos = $ppos[1]; 2201 if (!stristr($x_pos, '%')) { 2202 $x_pos = $this->sizeConverter->convert($x_pos, $maxwidth, $this->FontSize); 2203 } 2204 if (!stristr($y_pos, '%')) { 2205 $y_pos = $this->sizeConverter->convert($y_pos, $maxwidth, $this->FontSize); 2206 } 2207 } 2208 if (isset($properties['BACKGROUND-IMAGE-RESIZE'])) { 2209 $resize = $properties['BACKGROUND-IMAGE-RESIZE']; 2210 } else { 2211 $resize = 0; 2212 } 2213 if (isset($properties['BACKGROUND-IMAGE-OPACITY'])) { 2214 $opacity = $properties['BACKGROUND-IMAGE-OPACITY']; 2215 } else { 2216 $opacity = 1; 2217 } 2218 return ['image_id' => $image_id, 'orig_w' => $orig_w, 'orig_h' => $orig_h, 'x_pos' => $x_pos, 'y_pos' => $y_pos, 'x_repeat' => $x_repeat, 'y_repeat' => $y_repeat, 'resize' => $resize, 'opacity' => $opacity, 'itype' => $sizesarray['itype'], 'origin' => $origin, 'size' => $size]; 2219 } 2220 } 2221 return false; 2222 } 2223 2224 /* -- END BACKGROUNDS -- */ 2225 2226 function PrintBodyBackgrounds() 2227 { 2228 $s = ''; 2229 $clx = 0; 2230 $cly = 0; 2231 $clw = $this->w; 2232 $clh = $this->h; 2233 // If using bleed and trim margins in paged media 2234 if ($this->pageDim[$this->page]['outer_width_LR'] || $this->pageDim[$this->page]['outer_width_TB']) { 2235 $clx = $this->pageDim[$this->page]['outer_width_LR'] - $this->pageDim[$this->page]['bleedMargin']; 2236 $cly = $this->pageDim[$this->page]['outer_width_TB'] - $this->pageDim[$this->page]['bleedMargin']; 2237 $clw = $this->w - 2 * $clx; 2238 $clh = $this->h - 2 * $cly; 2239 } 2240 2241 if ($this->bodyBackgroundColor) { 2242 $s .= 'q ' . $this->SetFColor($this->bodyBackgroundColor, true) . "\n"; 2243 if ($this->bodyBackgroundColor[0] == 5) { // RGBa 2244 $s .= $this->SetAlpha(ord($this->bodyBackgroundColor[4]) / 100, 'Normal', true, 'F') . "\n"; 2245 } elseif ($this->bodyBackgroundColor[0] == 6) { // CMYKa 2246 $s .= $this->SetAlpha(ord($this->bodyBackgroundColor[5]) / 100, 'Normal', true, 'F') . "\n"; 2247 } 2248 $s .= sprintf('%.3F %.3F %.3F %.3F re f Q', ($clx * Mpdf::SCALE), ($cly * Mpdf::SCALE), $clw * Mpdf::SCALE, $clh * Mpdf::SCALE) . "\n"; 2249 } 2250 2251 /* -- BACKGROUNDS -- */ 2252 if ($this->bodyBackgroundGradient) { 2253 $g = $this->gradient->parseBackgroundGradient($this->bodyBackgroundGradient); 2254 if ($g) { 2255 $s .= $this->gradient->Gradient($clx, $cly, $clw, $clh, (isset($g['gradtype']) ? $g['gradtype'] : null), $g['stops'], $g['colorspace'], $g['coords'], $g['extend'], true); 2256 } 2257 } 2258 if ($this->bodyBackgroundImage) { 2259 if (isset($this->bodyBackgroundImage['gradient']) && $this->bodyBackgroundImage['gradient'] && preg_match('/(-moz-)*(repeating-)*(linear|radial)-gradient/', $this->bodyBackgroundImage['gradient'])) { 2260 $g = $this->gradient->parseMozGradient($this->bodyBackgroundImage['gradient']); 2261 if ($g) { 2262 $s .= $this->gradient->Gradient($clx, $cly, $clw, $clh, $g['type'], $g['stops'], $g['colorspace'], $g['coords'], $g['extend'], true); 2263 } 2264 } elseif ($this->bodyBackgroundImage['image_id']) { // Background pattern 2265 $n = count($this->patterns) + 1; 2266 // If using resize, uses TrimBox (not including the bleed) 2267 list($orig_w, $orig_h, $x_repeat, $y_repeat) = $this->_resizeBackgroundImage($this->bodyBackgroundImage['orig_w'], $this->bodyBackgroundImage['orig_h'], $clw, $clh, $this->bodyBackgroundImage['resize'], $this->bodyBackgroundImage['x_repeat'], $this->bodyBackgroundImage['y_repeat']); 2268 2269 $this->patterns[$n] = ['x' => $clx, 'y' => $cly, 'w' => $clw, 'h' => $clh, 'pgh' => $this->h, 'image_id' => $this->bodyBackgroundImage['image_id'], 'orig_w' => $orig_w, 'orig_h' => $orig_h, 'x_pos' => $this->bodyBackgroundImage['x_pos'], 'y_pos' => $this->bodyBackgroundImage['y_pos'], 'x_repeat' => $x_repeat, 'y_repeat' => $y_repeat, 'itype' => $this->bodyBackgroundImage['itype']]; 2270 if (($this->bodyBackgroundImage['opacity'] > 0 || $this->bodyBackgroundImage['opacity'] === '0') && $this->bodyBackgroundImage['opacity'] < 1) { 2271 $opac = $this->SetAlpha($this->bodyBackgroundImage['opacity'], 'Normal', true); 2272 } else { 2273 $opac = ''; 2274 } 2275 $s .= sprintf('q /Pattern cs /P%d scn %s %.3F %.3F %.3F %.3F re f Q', $n, $opac, ($clx * Mpdf::SCALE), ($cly * Mpdf::SCALE), $clw * Mpdf::SCALE, $clh * Mpdf::SCALE) . "\n"; 2276 } 2277 } 2278 /* -- END BACKGROUNDS -- */ 2279 return $s; 2280 } 2281 2282 function _setClippingPath($clx, $cly, $clw, $clh) 2283 { 2284 $s = ' q 0 w '; // Line width=0 2285 $s .= sprintf('%.3F %.3F m ', ($clx) * Mpdf::SCALE, ($this->h - ($cly)) * Mpdf::SCALE); // start point TL before the arc 2286 $s .= sprintf('%.3F %.3F l ', ($clx) * Mpdf::SCALE, ($this->h - ($cly + $clh)) * Mpdf::SCALE); // line to BL 2287 $s .= sprintf('%.3F %.3F l ', ($clx + $clw) * Mpdf::SCALE, ($this->h - ($cly + $clh)) * Mpdf::SCALE); // line to BR 2288 $s .= sprintf('%.3F %.3F l ', ($clx + $clw) * Mpdf::SCALE, ($this->h - ($cly)) * Mpdf::SCALE); // line to TR 2289 $s .= sprintf('%.3F %.3F l ', ($clx) * Mpdf::SCALE, ($this->h - ($cly)) * Mpdf::SCALE); // line to TL 2290 $s .= ' W n '; // Ends path no-op & Sets the clipping path 2291 return $s; 2292 } 2293 2294 function PrintPageBackgrounds($adjustmenty = 0) 2295 { 2296 $s = ''; 2297 2298 ksort($this->pageBackgrounds); 2299 2300 foreach ($this->pageBackgrounds as $bl => $pbs) { 2301 2302 foreach ($pbs as $pb) { 2303 2304 if ((!isset($pb['image_id']) && !isset($pb['gradient'])) || isset($pb['shadowonly'])) { // Background colour or boxshadow 2305 2306 if ($pb['z-index'] > 0) { 2307 $this->current_layer = $pb['z-index']; 2308 $s .= "\n" . '/OCBZ-index /ZI' . $pb['z-index'] . ' BDC' . "\n"; 2309 } 2310 2311 if ($pb['visibility'] != 'visible') { 2312 if ($pb['visibility'] == 'printonly') { 2313 $s .= '/OC /OC1 BDC' . "\n"; 2314 } elseif ($pb['visibility'] == 'screenonly') { 2315 $s .= '/OC /OC2 BDC' . "\n"; 2316 } elseif ($pb['visibility'] == 'hidden') { 2317 $s .= '/OC /OC3 BDC' . "\n"; 2318 } 2319 } 2320 2321 // Box shadow 2322 if (isset($pb['shadow']) && $pb['shadow']) { 2323 $s .= $pb['shadow'] . "\n"; 2324 } 2325 2326 if (isset($pb['clippath']) && $pb['clippath']) { 2327 $s .= $pb['clippath'] . "\n"; 2328 } 2329 2330 $s .= 'q ' . $this->SetFColor($pb['col'], true) . "\n"; 2331 2332 if ($pb['col'] && $pb['col'][0] === '5') { // RGBa 2333 $s .= $this->SetAlpha(ord($pb['col'][4]) / 100, 'Normal', true, 'F') . "\n"; 2334 } elseif ($pb['col'] && $pb['col'][0] === '6') { // CMYKa 2335 $s .= $this->SetAlpha(ord($pb['col'][5]) / 100, 'Normal', true, 'F') . "\n"; 2336 } 2337 2338 $s .= sprintf('%.3F %.3F %.3F %.3F re f Q', $pb['x'] * Mpdf::SCALE, ($this->h - $pb['y']) * Mpdf::SCALE, $pb['w'] * Mpdf::SCALE, -$pb['h'] * Mpdf::SCALE) . "\n"; 2339 2340 if (isset($pb['clippath']) && $pb['clippath']) { 2341 $s .= 'Q' . "\n"; 2342 } 2343 2344 if ($pb['visibility'] != 'visible') { 2345 $s .= 'EMC' . "\n"; 2346 } 2347 2348 if ($pb['z-index'] > 0) { 2349 $s .= "\n" . 'EMCBZ-index' . "\n"; 2350 $this->current_layer = 0; 2351 } 2352 } 2353 } 2354 2355 /* -- BACKGROUNDS -- */ 2356 foreach ($pbs as $pb) { 2357 2358 if ((isset($pb['gradient']) && $pb['gradient']) || (isset($pb['image_id']) && $pb['image_id'])) { 2359 2360 if ($pb['z-index'] > 0) { 2361 $this->current_layer = $pb['z-index']; 2362 $s .= "\n" . '/OCGZ-index /ZI' . $pb['z-index'] . ' BDC' . "\n"; 2363 } 2364 2365 if ($pb['visibility'] != 'visible') { 2366 if ($pb['visibility'] == 'printonly') { 2367 $s .= '/OC /OC1 BDC' . "\n"; 2368 } elseif ($pb['visibility'] == 'screenonly') { 2369 $s .= '/OC /OC2 BDC' . "\n"; 2370 } elseif ($pb['visibility'] == 'hidden') { 2371 $s .= '/OC /OC3 BDC' . "\n"; 2372 } 2373 } 2374 2375 } 2376 2377 if (isset($pb['gradient']) && $pb['gradient']) { 2378 2379 if (isset($pb['clippath']) && $pb['clippath']) { 2380 $s .= $pb['clippath'] . "\n"; 2381 } 2382 2383 $s .= $this->gradient->Gradient($pb['x'], $pb['y'], $pb['w'], $pb['h'], $pb['gradtype'], $pb['stops'], $pb['colorspace'], $pb['coords'], $pb['extend'], true); 2384 2385 if (isset($pb['clippath']) && $pb['clippath']) { 2386 $s .= 'Q' . "\n"; 2387 } 2388 2389 } elseif (isset($pb['image_id']) && $pb['image_id']) { // Background Image 2390 2391 $pb['y'] -= $adjustmenty; 2392 $pb['h'] += $adjustmenty; 2393 $n = count($this->patterns) + 1; 2394 2395 list($orig_w, $orig_h, $x_repeat, $y_repeat) = $this->_resizeBackgroundImage($pb['orig_w'], $pb['orig_h'], $pb['w'], $pb['h'], $pb['resize'], $pb['x_repeat'], $pb['y_repeat'], $pb['bpa'], $pb['size']); 2396 2397 $this->patterns[$n] = ['x' => $pb['x'], 'y' => $pb['y'], 'w' => $pb['w'], 'h' => $pb['h'], 'pgh' => $this->h, 'image_id' => $pb['image_id'], 'orig_w' => $orig_w, 'orig_h' => $orig_h, 'x_pos' => $pb['x_pos'], 'y_pos' => $pb['y_pos'], 'x_repeat' => $x_repeat, 'y_repeat' => $y_repeat, 'itype' => $pb['itype'], 'bpa' => $pb['bpa']]; 2398 2399 $x = $pb['x'] * Mpdf::SCALE; 2400 $y = ($this->h - $pb['y']) * Mpdf::SCALE; 2401 $w = $pb['w'] * Mpdf::SCALE; 2402 $h = -$pb['h'] * Mpdf::SCALE; 2403 2404 if (isset($pb['clippath']) && $pb['clippath']) { 2405 $s .= $pb['clippath'] . "\n"; 2406 } 2407 2408 if ($this->writingHTMLfooter || $this->writingHTMLheader) { // Write each (tiles) image rather than use as a pattern 2409 2410 $iw = $pb['orig_w'] / Mpdf::SCALE; 2411 $ih = $pb['orig_h'] / Mpdf::SCALE; 2412 2413 $w = $pb['w']; 2414 $h = $pb['h']; 2415 $x0 = $pb['x']; 2416 $y0 = $pb['y']; 2417 2418 if (isset($pb['bpa']) && $pb['bpa']) { 2419 $w = $pb['bpa']['w']; 2420 $h = $pb['bpa']['h']; 2421 $x0 = $pb['bpa']['x']; 2422 $y0 = $pb['bpa']['y']; 2423 } 2424 2425 if (isset($pb['size']['w']) && $pb['size']['w']) { 2426 $size = $pb['size']; 2427 2428 if ($size['w'] == 'contain') { 2429 // Scale the image, while preserving its intrinsic aspect ratio (if any), to the largest 2430 // size such that both its width and its height can fit inside the background positioning area. 2431 // Same as resize==3 2432 $ih = $ih * $pb['bpa']['w'] / $iw; 2433 $iw = $pb['bpa']['w']; 2434 if ($ih > $pb['bpa']['h']) { 2435 $iw = $iw * $pb['bpa']['h'] / $ih; 2436 $ih = $pb['bpa']['h']; 2437 } 2438 } elseif ($size['w'] == 'cover') { 2439 // Scale the image, while preserving its intrinsic aspect ratio (if any), to the smallest 2440 // size such that both its width and its height can completely cover the background positioning area. 2441 $ih = $ih * $pb['bpa']['w'] / $iw; 2442 $iw = $pb['bpa']['w']; 2443 if ($ih < $pb['bpa']['h']) { 2444 $iw = $iw * $ih / $pb['bpa']['h']; 2445 $ih = $pb['bpa']['h']; 2446 } 2447 } else { 2448 2449 if (NumericString::containsPercentChar($size['w'])) { 2450 $size['w'] = NumericString::removePercentChar($size['w']); 2451 $size['w'] /= 100; 2452 $size['w'] = ($pb['bpa']['w'] * $size['w']); 2453 } 2454 2455 if (NumericString::containsPercentChar($size['h'])) { 2456 $size['h'] = NumericString::removePercentChar($size['h']); 2457 $size['h'] /= 100; 2458 $size['h'] = ($pb['bpa']['h'] * $size['h']); 2459 } 2460 2461 if ($size['w'] == 'auto' && $size['h'] == 'auto') { 2462 $iw = $iw; 2463 $ih = $ih; 2464 } elseif ($size['w'] == 'auto' && $size['h'] != 'auto') { 2465 $iw = $iw * $size['h'] / $ih; 2466 $ih = $size['h']; 2467 } elseif ($size['w'] != 'auto' && $size['h'] == 'auto') { 2468 $ih = $ih * $size['w'] / $iw; 2469 $iw = $size['w']; 2470 } else { 2471 $iw = $size['w']; 2472 $ih = $size['h']; 2473 } 2474 } 2475 } 2476 2477 // Number to repeat 2478 if ($pb['x_repeat']) { 2479 $nx = ceil($pb['w'] / $iw) + 1; 2480 } else { 2481 $nx = 1; 2482 } 2483 2484 if ($pb['y_repeat']) { 2485 $ny = ceil($pb['h'] / $ih) + 1; 2486 } else { 2487 $ny = 1; 2488 } 2489 2490 $x_pos = $pb['x_pos']; 2491 if (stristr($x_pos, '%')) { 2492 $x_pos = (float) $x_pos; 2493 $x_pos /= 100; 2494 $x_pos = ($pb['bpa']['w'] * $x_pos) - ($iw * $x_pos); 2495 } 2496 2497 $y_pos = $pb['y_pos']; 2498 2499 if (stristr($y_pos, '%')) { 2500 $y_pos = (float) $y_pos; 2501 $y_pos /= 100; 2502 $y_pos = ($pb['bpa']['h'] * $y_pos) - ($ih * $y_pos); 2503 } 2504 2505 if ($nx > 1) { 2506 while ($x_pos > ($pb['x'] - $pb['bpa']['x'])) { 2507 $x_pos -= $iw; 2508 } 2509 } 2510 2511 if ($ny > 1) { 2512 while ($y_pos > ($pb['y'] - $pb['bpa']['y'])) { 2513 $y_pos -= $ih; 2514 } 2515 } 2516 2517 for ($xi = 0; $xi < $nx; $xi++) { 2518 for ($yi = 0; $yi < $ny; $yi++) { 2519 $x = $x0 + $x_pos + ($iw * $xi); 2520 $y = $y0 + $y_pos + ($ih * $yi); 2521 if ($pb['opacity'] > 0 && $pb['opacity'] < 1) { 2522 $opac = $this->SetAlpha($pb['opacity'], 'Normal', true); 2523 } else { 2524 $opac = ''; 2525 } 2526 $s .= sprintf("q %s %.3F 0 0 %.3F %.3F %.3F cm /I%d Do Q", $opac, $iw * Mpdf::SCALE, $ih * Mpdf::SCALE, $x * Mpdf::SCALE, ($this->h - ($y + $ih)) * Mpdf::SCALE, $pb['image_id']) . "\n"; 2527 } 2528 } 2529 2530 } else { 2531 if (($pb['opacity'] > 0 || $pb['opacity'] === '0') && $pb['opacity'] < 1) { 2532 $opac = $this->SetAlpha($pb['opacity'], 'Normal', true); 2533 } else { 2534 $opac = ''; 2535 } 2536 $s .= sprintf('q /Pattern cs /P%d scn %s %.3F %.3F %.3F %.3F re f Q', $n, $opac, $x, $y, $w, $h) . "\n"; 2537 } 2538 2539 if (isset($pb['clippath']) && $pb['clippath']) { 2540 $s .= 'Q' . "\n"; 2541 } 2542 } 2543 2544 if ((isset($pb['gradient']) && $pb['gradient']) || (isset($pb['image_id']) && $pb['image_id'])) { 2545 if ($pb['visibility'] != 'visible') { 2546 $s .= 'EMC' . "\n"; 2547 } 2548 2549 if ($pb['z-index'] > 0) { 2550 $s .= "\n" . 'EMCGZ-index' . "\n"; 2551 $this->current_layer = 0; 2552 } 2553 } 2554 } 2555 /* -- END BACKGROUNDS -- */ 2556 } 2557 2558 return $s; 2559 } 2560 2561 function PrintTableBackgrounds($adjustmenty = 0) 2562 { 2563 $s = ''; 2564 /* -- BACKGROUNDS -- */ 2565 ksort($this->tableBackgrounds); 2566 foreach ($this->tableBackgrounds as $bl => $pbs) { 2567 foreach ($pbs as $pb) { 2568 if ((!isset($pb['gradient']) || !$pb['gradient']) && (!isset($pb['image_id']) || !$pb['image_id'])) { 2569 $s .= 'q ' . $this->SetFColor($pb['col'], true) . "\n"; 2570 if ($pb['col'][0] == 5) { // RGBa 2571 $s .= $this->SetAlpha(ord($pb['col'][4]) / 100, 'Normal', true, 'F') . "\n"; 2572 } elseif ($pb['col'][0] == 6) { // CMYKa 2573 $s .= $this->SetAlpha(ord($pb['col'][5]) / 100, 'Normal', true, 'F') . "\n"; 2574 } 2575 $s .= sprintf('%.3F %.3F %.3F %.3F re %s Q', $pb['x'] * Mpdf::SCALE, ($this->h - $pb['y']) * Mpdf::SCALE, $pb['w'] * Mpdf::SCALE, -$pb['h'] * Mpdf::SCALE, 'f') . "\n"; 2576 } 2577 if (isset($pb['gradient']) && $pb['gradient']) { 2578 if (isset($pb['clippath']) && $pb['clippath']) { 2579 $s .= $pb['clippath'] . "\n"; 2580 } 2581 $s .= $this->gradient->Gradient($pb['x'], $pb['y'], $pb['w'], $pb['h'], $pb['gradtype'], $pb['stops'], $pb['colorspace'], $pb['coords'], $pb['extend'], true); 2582 if (isset($pb['clippath']) && $pb['clippath']) { 2583 $s .= 'Q' . "\n"; 2584 } 2585 } 2586 if (isset($pb['image_id']) && $pb['image_id']) { // Background pattern 2587 $pb['y'] -= $adjustmenty; 2588 $pb['h'] += $adjustmenty; 2589 $n = count($this->patterns) + 1; 2590 list($orig_w, $orig_h, $x_repeat, $y_repeat) = $this->_resizeBackgroundImage($pb['orig_w'], $pb['orig_h'], $pb['w'], $pb['h'], $pb['resize'], $pb['x_repeat'], $pb['y_repeat']); 2591 $this->patterns[$n] = ['x' => $pb['x'], 'y' => $pb['y'], 'w' => $pb['w'], 'h' => $pb['h'], 'pgh' => $this->h, 'image_id' => $pb['image_id'], 'orig_w' => $orig_w, 'orig_h' => $orig_h, 'x_pos' => $pb['x_pos'], 'y_pos' => $pb['y_pos'], 'x_repeat' => $x_repeat, 'y_repeat' => $y_repeat, 'itype' => $pb['itype']]; 2592 $x = $pb['x'] * Mpdf::SCALE; 2593 $y = ($this->h - $pb['y']) * Mpdf::SCALE; 2594 $w = $pb['w'] * Mpdf::SCALE; 2595 $h = -$pb['h'] * Mpdf::SCALE; 2596 2597 // mPDF 5.7.3 2598 if (($this->writingHTMLfooter || $this->writingHTMLheader) && (!isset($pb['clippath']) || $pb['clippath'] == '')) { 2599 // Set clipping path 2600 $pb['clippath'] = sprintf(' q 0 w %.3F %.3F m %.3F %.3F l %.3F %.3F l %.3F %.3F l %.3F %.3F l W n ', $x, $y, $x, $y + $h, $x + $w, $y + $h, $x + $w, $y, $x, $y); 2601 } 2602 2603 if (isset($pb['clippath']) && $pb['clippath']) { 2604 $s .= $pb['clippath'] . "\n"; 2605 } 2606 2607 // mPDF 5.7.3 2608 if ($this->writingHTMLfooter || $this->writingHTMLheader) { // Write each (tiles) image rather than use as a pattern 2609 $iw = $pb['orig_w'] / Mpdf::SCALE; 2610 $ih = $pb['orig_h'] / Mpdf::SCALE; 2611 2612 $w = $pb['w']; 2613 $h = $pb['h']; 2614 $x0 = $pb['x']; 2615 $y0 = $pb['y']; 2616 2617 if (isset($pb['bpa']) && $pb['bpa']) { 2618 $w = $pb['bpa']['w']; 2619 $h = $pb['bpa']['h']; 2620 $x0 = $pb['bpa']['x']; 2621 $y0 = $pb['bpa']['y']; 2622 } // At present 'bpa' (background page area) is not set for tablebackgrounds - only pagebackgrounds 2623 // For now, just set it as: 2624 else { 2625 $pb['bpa'] = ['x' => $x0, 'y' => $y0, 'w' => $w, 'h' => $h]; 2626 } 2627 2628 if (isset($pb['size']['w']) && $pb['size']['w']) { 2629 $size = $pb['size']; 2630 2631 if ($size['w'] == 'contain') { 2632 // Scale the image, while preserving its intrinsic aspect ratio (if any), to the largest size such that both its width and its height can fit inside the background positioning area. 2633 // Same as resize==3 2634 $ih = $ih * $pb['bpa']['w'] / $iw; 2635 $iw = $pb['bpa']['w']; 2636 if ($ih > $pb['bpa']['h']) { 2637 $iw = $iw * $pb['bpa']['h'] / $ih; 2638 $ih = $pb['bpa']['h']; 2639 } 2640 } elseif ($size['w'] == 'cover') { 2641 // Scale the image, while preserving its intrinsic aspect ratio (if any), to the smallest size such that both its width and its height can completely cover the background positioning area. 2642 $ih = $ih * $pb['bpa']['w'] / $iw; 2643 $iw = $pb['bpa']['w']; 2644 if ($ih < $pb['bpa']['h']) { 2645 $iw = $iw * $ih / $pb['bpa']['h']; 2646 $ih = $pb['bpa']['h']; 2647 } 2648 } else { 2649 if (NumericString::containsPercentChar($size['w'])) { 2650 $size['w'] = NumericString::removePercentChar($size['w']); 2651 $size['w'] /= 100; 2652 $size['w'] = ($pb['bpa']['w'] * $size['w']); 2653 } 2654 if (NumericString::containsPercentChar($size['h'])) { 2655 $size['h'] = NumericString::removePercentChar($size['h']); 2656 $size['h'] /= 100; 2657 $size['h'] = ($pb['bpa']['h'] * $size['h']); 2658 } 2659 if ($size['w'] == 'auto' && $size['h'] == 'auto') { 2660 $iw = $iw; 2661 $ih = $ih; 2662 } elseif ($size['w'] == 'auto' && $size['h'] != 'auto') { 2663 $iw = $iw * $size['h'] / $ih; 2664 $ih = $size['h']; 2665 } elseif ($size['w'] != 'auto' && $size['h'] == 'auto') { 2666 $ih = $ih * $size['w'] / $iw; 2667 $iw = $size['w']; 2668 } else { 2669 $iw = $size['w']; 2670 $ih = $size['h']; 2671 } 2672 } 2673 } 2674 2675 // Number to repeat 2676 if (isset($pb['x_repeat']) && $pb['x_repeat']) { 2677 $nx = ceil($pb['w'] / $iw) + 1; 2678 } else { 2679 $nx = 1; 2680 } 2681 if (isset($pb['y_repeat']) && $pb['y_repeat']) { 2682 $ny = ceil($pb['h'] / $ih) + 1; 2683 } else { 2684 $ny = 1; 2685 } 2686 2687 $x_pos = $pb['x_pos']; 2688 if (NumericString::containsPercentChar($x_pos)) { 2689 $x_pos = NumericString::removePercentChar($x_pos); 2690 $x_pos /= 100; 2691 $x_pos = ($pb['bpa']['w'] * $x_pos) - ($iw * $x_pos); 2692 } 2693 $y_pos = $pb['y_pos']; 2694 if (NumericString::containsPercentChar($y_pos)) { 2695 $y_pos = NumericString::removePercentChar($y_pos); 2696 $y_pos /= 100; 2697 $y_pos = ($pb['bpa']['h'] * $y_pos) - ($ih * $y_pos); 2698 } 2699 if ($nx > 1) { 2700 while ($x_pos > ($pb['x'] - $pb['bpa']['x'])) { 2701 $x_pos -= $iw; 2702 } 2703 } 2704 if ($ny > 1) { 2705 while ($y_pos > ($pb['y'] - $pb['bpa']['y'])) { 2706 $y_pos -= $ih; 2707 } 2708 } 2709 for ($xi = 0; $xi < $nx; $xi++) { 2710 for ($yi = 0; $yi < $ny; $yi++) { 2711 $x = $x0 + $x_pos + ($iw * $xi); 2712 $y = $y0 + $y_pos + ($ih * $yi); 2713 if ($pb['opacity'] > 0 && $pb['opacity'] < 1) { 2714 $opac = $this->SetAlpha($pb['opacity'], 'Normal', true); 2715 } else { 2716 $opac = ''; 2717 } 2718 $s .= sprintf("q %s %.3F 0 0 %.3F %.3F %.3F cm /I%d Do Q", $opac, $iw * Mpdf::SCALE, $ih * Mpdf::SCALE, $x * Mpdf::SCALE, ($this->h - ($y + $ih)) * Mpdf::SCALE, $pb['image_id']) . "\n"; 2719 } 2720 } 2721 } else { 2722 if (($pb['opacity'] > 0 || $pb['opacity'] === '0') && $pb['opacity'] < 1) { 2723 $opac = $this->SetAlpha($pb['opacity'], 'Normal', true); 2724 } else { 2725 $opac = ''; 2726 } 2727 $s .= sprintf('q /Pattern cs /P%d scn %s %.3F %.3F %.3F %.3F re f Q', $n, $opac, $x, $y, $w, $h) . "\n"; 2728 } 2729 2730 if (isset($pb['clippath']) && $pb['clippath']) { 2731 $s .= 'Q' . "\n"; 2732 } 2733 } 2734 } 2735 } 2736 /* -- END BACKGROUNDS -- */ 2737 return $s; 2738 } 2739 2740 function BeginLayer($id) 2741 { 2742 if ($this->current_layer > 0) { 2743 $this->EndLayer(); 2744 } 2745 if ($id < 1) { 2746 return false; 2747 } 2748 if (!isset($this->layers[$id])) { 2749 $this->layers[$id] = ['name' => 'Layer ' . ($id)]; 2750 if (($this->PDFA || $this->PDFX)) { 2751 $this->PDFAXwarnings[] = "Cannot use layers when using PDFA or PDFX"; 2752 return ''; 2753 } elseif (!$this->PDFA && !$this->PDFX) { 2754 $this->pdf_version = '1.5'; 2755 } 2756 } 2757 $this->current_layer = $id; 2758 $this->writer->write('/OCZ-index /ZI' . $id . ' BDC'); 2759 2760 $this->pageoutput[$this->page] = []; 2761 } 2762 2763 function EndLayer() 2764 { 2765 if ($this->current_layer > 0) { 2766 $this->writer->write('EMCZ-index'); 2767 $this->current_layer = 0; 2768 } 2769 } 2770 2771 function AddPageByArray($a) 2772 { 2773 if (!is_array($a)) { 2774 $a = []; 2775 } 2776 2777 $orientation = (isset($a['orientation']) ? $a['orientation'] : ''); 2778 $condition = (isset($a['condition']) ? $a['condition'] : (isset($a['type']) ? $a['type'] : '')); 2779 $resetpagenum = (isset($a['resetpagenum']) ? $a['resetpagenum'] : ''); 2780 $pagenumstyle = (isset($a['pagenumstyle']) ? $a['pagenumstyle'] : ''); 2781 $suppress = (isset($a['suppress']) ? $a['suppress'] : ''); 2782 $mgl = (isset($a['mgl']) ? $a['mgl'] : (isset($a['margin-left']) ? $a['margin-left'] : '')); 2783 $mgr = (isset($a['mgr']) ? $a['mgr'] : (isset($a['margin-right']) ? $a['margin-right'] : '')); 2784 $mgt = (isset($a['mgt']) ? $a['mgt'] : (isset($a['margin-top']) ? $a['margin-top'] : '')); 2785 $mgb = (isset($a['mgb']) ? $a['mgb'] : (isset($a['margin-bottom']) ? $a['margin-bottom'] : '')); 2786 $mgh = (isset($a['mgh']) ? $a['mgh'] : (isset($a['margin-header']) ? $a['margin-header'] : '')); 2787 $mgf = (isset($a['mgf']) ? $a['mgf'] : (isset($a['margin-footer']) ? $a['margin-footer'] : '')); 2788 $ohname = (isset($a['ohname']) ? $a['ohname'] : (isset($a['odd-header-name']) ? $a['odd-header-name'] : '')); 2789 $ehname = (isset($a['ehname']) ? $a['ehname'] : (isset($a['even-header-name']) ? $a['even-header-name'] : '')); 2790 $ofname = (isset($a['ofname']) ? $a['ofname'] : (isset($a['odd-footer-name']) ? $a['odd-footer-name'] : '')); 2791 $efname = (isset($a['efname']) ? $a['efname'] : (isset($a['even-footer-name']) ? $a['even-footer-name'] : '')); 2792 $ohvalue = (isset($a['ohvalue']) ? $a['ohvalue'] : (isset($a['odd-header-value']) ? $a['odd-header-value'] : 0)); 2793 $ehvalue = (isset($a['ehvalue']) ? $a['ehvalue'] : (isset($a['even-header-value']) ? $a['even-header-value'] : 0)); 2794 $ofvalue = (isset($a['ofvalue']) ? $a['ofvalue'] : (isset($a['odd-footer-value']) ? $a['odd-footer-value'] : 0)); 2795 $efvalue = (isset($a['efvalue']) ? $a['efvalue'] : (isset($a['even-footer-value']) ? $a['even-footer-value'] : 0)); 2796 $pagesel = (isset($a['pagesel']) ? $a['pagesel'] : (isset($a['pageselector']) ? $a['pageselector'] : '')); 2797 $newformat = (isset($a['newformat']) ? $a['newformat'] : (isset($a['sheet-size']) ? $a['sheet-size'] : '')); 2798 2799 $this->AddPage($orientation, $condition, $resetpagenum, $pagenumstyle, $suppress, $mgl, $mgr, $mgt, $mgb, $mgh, $mgf, $ohname, $ehname, $ofname, $efname, $ohvalue, $ehvalue, $ofvalue, $efvalue, $pagesel, $newformat); 2800 } 2801 2802 // mPDF 6 pagebreaktype 2803 function _preForcedPagebreak($pagebreaktype) 2804 { 2805 if ($pagebreaktype == 'cloneall') { 2806 // Close any open block tags 2807 $arr = []; 2808 $ai = 0; 2809 for ($b = $this->blklvl; $b > 0; $b--) { 2810 $this->tag->CloseTag($this->blk[$b]['tag'], $arr, $ai); 2811 } 2812 if ($this->blklvl == 0 && !empty($this->textbuffer)) { // Output previously buffered content 2813 $this->printbuffer($this->textbuffer, 1); 2814 $this->textbuffer = []; 2815 } 2816 } elseif ($pagebreaktype == 'clonebycss') { 2817 // Close open block tags whilst box-decoration-break==clone 2818 $arr = []; 2819 $ai = 0; 2820 for ($b = $this->blklvl; $b > 0; $b--) { 2821 if (isset($this->blk[$b]['box_decoration_break']) && $this->blk[$b]['box_decoration_break'] == 'clone') { 2822 $this->tag->CloseTag($this->blk[$b]['tag'], $arr, $ai); 2823 } else { 2824 if ($b == $this->blklvl && !empty($this->textbuffer)) { // Output previously buffered content 2825 $this->printbuffer($this->textbuffer, 1); 2826 $this->textbuffer = []; 2827 } 2828 break; 2829 } 2830 } 2831 } elseif (!empty($this->textbuffer)) { // Output previously buffered content 2832 $this->printbuffer($this->textbuffer, 1); 2833 $this->textbuffer = []; 2834 } 2835 } 2836 2837 // mPDF 6 pagebreaktype 2838 function _postForcedPagebreak($pagebreaktype, $startpage, $save_blk, $save_blklvl) 2839 { 2840 if ($pagebreaktype == 'cloneall') { 2841 $this->blk = []; 2842 $this->blk[0] = $save_blk[0]; 2843 // Re-open block tags 2844 $this->blklvl = 0; 2845 $arr = []; 2846 $i = 0; 2847 for ($b = 1; $b <= $save_blklvl; $b++) { 2848 $this->tag->OpenTag($save_blk[$b]['tag'], $save_blk[$b]['attr'], $arr, $i); 2849 } 2850 } elseif ($pagebreaktype == 'clonebycss') { 2851 $this->blk = []; 2852 $this->blk[0] = $save_blk[0]; 2853 // Don't re-open tags for lowest level elements - so need to do some adjustments 2854 for ($b = 1; $b <= $this->blklvl; $b++) { 2855 $this->blk[$b] = $save_blk[$b]; 2856 $this->blk[$b]['startpage'] = 0; 2857 $this->blk[$b]['y0'] = $this->y; // ?? $this->tMargin 2858 if (($this->page - $startpage) % 2) { 2859 if (isset($this->blk[$b]['x0'])) { 2860 $this->blk[$b]['x0'] += $this->MarginCorrection; 2861 } else { 2862 $this->blk[$b]['x0'] = $this->MarginCorrection; 2863 } 2864 } 2865 // for Float DIV 2866 $this->blk[$b]['marginCorrected'][$this->page] = true; 2867 } 2868 2869 // Re-open block tags for any that have box_decoration_break==clone 2870 $arr = []; 2871 $i = 0; 2872 for ($b = $this->blklvl + 1; $b <= $save_blklvl; $b++) { 2873 if ($b < $this->blklvl) { 2874 $this->lastblocklevelchange = -1; 2875 } 2876 $this->tag->OpenTag($save_blk[$b]['tag'], $save_blk[$b]['attr'], $arr, $i); 2877 } 2878 if ($this->blk[$this->blklvl]['box_decoration_break'] != 'clone') { 2879 $this->lastblocklevelchange = -1; 2880 } 2881 } else { 2882 $this->lastblocklevelchange = -1; 2883 } 2884 } 2885 2886 function AddPage( 2887 $orientation = '', 2888 $condition = '', 2889 $resetpagenum = '', 2890 $pagenumstyle = '', 2891 $suppress = '', 2892 $mgl = '', 2893 $mgr = '', 2894 $mgt = '', 2895 $mgb = '', 2896 $mgh = '', 2897 $mgf = '', 2898 $ohname = '', 2899 $ehname = '', 2900 $ofname = '', 2901 $efname = '', 2902 $ohvalue = 0, 2903 $ehvalue = 0, 2904 $ofvalue = 0, 2905 $efvalue = 0, 2906 $pagesel = '', 2907 $newformat = '' 2908 ) { 2909 /* -- CSS-FLOAT -- */ 2910 // Float DIV 2911 // Cannot do with columns on, or if any change in page orientation/margins etc. 2912 // If next page already exists - i.e background /headers and footers already written 2913 if ($this->state > 0 && $this->page < count($this->pages)) { 2914 $bak_cml = $this->cMarginL; 2915 $bak_cmr = $this->cMarginR; 2916 $bak_dw = $this->divwidth; 2917 // Paint Div Border if necessary 2918 if ($this->blklvl > 0) { 2919 $save_tr = $this->table_rotate; // *TABLES* 2920 $this->table_rotate = 0; // *TABLES* 2921 if (isset($this->blk[$this->blklvl]['y0']) && $this->y == $this->blk[$this->blklvl]['y0']) { 2922 $this->blk[$this->blklvl]['startpage'] ++; 2923 } 2924 if ((isset($this->blk[$this->blklvl]['y0']) && $this->y > $this->blk[$this->blklvl]['y0']) || $this->flowingBlockAttr['is_table']) { 2925 $toplvl = $this->blklvl; 2926 } else { 2927 $toplvl = $this->blklvl - 1; 2928 } 2929 $sy = $this->y; 2930 for ($bl = 1; $bl <= $toplvl; $bl++) { 2931 $this->PaintDivBB('pagebottom', 0, $bl); 2932 } 2933 $this->y = $sy; 2934 $this->table_rotate = $save_tr; // *TABLES* 2935 } 2936 $s = $this->PrintPageBackgrounds(); 2937 2938 // Writes after the marker so not overwritten later by page background etc. 2939 $this->pages[$this->page] = preg_replace( 2940 '/(___BACKGROUND___PATTERNS' . $this->uniqstr . ')/', 2941 '\\1' . "\n" . $s . "\n", 2942 $this->pages[$this->page] 2943 ); 2944 2945 $this->pageBackgrounds = []; 2946 $family = $this->FontFamily; 2947 $style = $this->FontStyle; 2948 $size = $this->FontSizePt; 2949 $lw = $this->LineWidth; 2950 $dc = $this->DrawColor; 2951 $fc = $this->FillColor; 2952 $tc = $this->TextColor; 2953 $cf = $this->ColorFlag; 2954 2955 $this->printfloatbuffer(); 2956 2957 // Move to next page 2958 $this->page++; 2959 2960 $this->ResetMargins(); 2961 $this->SetAutoPageBreak($this->autoPageBreak, $this->bMargin); 2962 $this->x = $this->lMargin; 2963 $this->y = $this->tMargin; 2964 $this->FontFamily = ''; 2965 $this->writer->write('2 J'); 2966 $this->LineWidth = $lw; 2967 $this->writer->write(sprintf('%.3F w', $lw * Mpdf::SCALE)); 2968 2969 if ($family) { 2970 $this->SetFont($family, $style, $size, true, true); 2971 } 2972 2973 $this->DrawColor = $dc; 2974 2975 if ($dc != $this->defDrawColor) { 2976 $this->writer->write($dc); 2977 } 2978 2979 $this->FillColor = $fc; 2980 2981 if ($fc != $this->defFillColor) { 2982 $this->writer->write($fc); 2983 } 2984 2985 $this->TextColor = $tc; 2986 $this->ColorFlag = $cf; 2987 2988 for ($bl = 1; $bl <= $this->blklvl; $bl++) { 2989 $this->blk[$bl]['y0'] = $this->y; 2990 // Don't correct more than once for background DIV containing a Float 2991 if (!isset($this->blk[$bl]['marginCorrected'][$this->page])) { 2992 if (isset($this->blk[$bl]['x0'])) { 2993 $this->blk[$bl]['x0'] += $this->MarginCorrection; 2994 } else { 2995 $this->blk[$bl]['x0'] = $this->MarginCorrection; 2996 } 2997 } 2998 $this->blk[$bl]['marginCorrected'][$this->page] = true; 2999 } 3000 3001 $this->cMarginL = $bak_cml; 3002 $this->cMarginR = $bak_cmr; 3003 $this->divwidth = $bak_dw; 3004 3005 return ''; 3006 } 3007 /* -- END CSS-FLOAT -- */ 3008 3009 // Start a new page 3010 if ($this->state == 0) { 3011 $this->Open(); 3012 } 3013 3014 $bak_cml = $this->cMarginL; 3015 $bak_cmr = $this->cMarginR; 3016 $bak_dw = $this->divwidth; 3017 3018 $bak_lh = $this->lineheight; 3019 3020 $orientation = substr(strtoupper($orientation), 0, 1); 3021 $condition = strtoupper($condition); 3022 3023 3024 if ($condition == 'E') { // only adds new page if needed to create an Even page 3025 if (!$this->mirrorMargins || ($this->page) % 2 == 0) { 3026 return false; 3027 } 3028 } elseif ($condition == 'O') { // only adds new page if needed to create an Odd page 3029 if (!$this->mirrorMargins || ($this->page) % 2 == 1) { 3030 return false; 3031 } 3032 } elseif ($condition == 'NEXT-EVEN') { // always adds at least one new page to create an Even page 3033 if (!$this->mirrorMargins) { 3034 $condition = ''; 3035 } else { 3036 if ($pagesel) { 3037 $pbch = $pagesel; 3038 $pagesel = ''; 3039 } // *CSS-PAGE* 3040 else { 3041 $pbch = false; 3042 } // *CSS-PAGE* 3043 $this->AddPage($this->CurOrientation, 'O'); 3044 $this->extrapagebreak = true; // mPDF 6 pagebreaktype 3045 if ($pbch) { 3046 $pagesel = $pbch; 3047 } // *CSS-PAGE* 3048 $condition = ''; 3049 } 3050 } elseif ($condition == 'NEXT-ODD') { // always adds at least one new page to create an Odd page 3051 if (!$this->mirrorMargins) { 3052 $condition = ''; 3053 } else { 3054 if ($pagesel) { 3055 $pbch = $pagesel; 3056 $pagesel = ''; 3057 } // *CSS-PAGE* 3058 else { 3059 $pbch = false; 3060 } // *CSS-PAGE* 3061 $this->AddPage($this->CurOrientation, 'E'); 3062 $this->extrapagebreak = true; // mPDF 6 pagebreaktype 3063 if ($pbch) { 3064 $pagesel = $pbch; 3065 } // *CSS-PAGE* 3066 $condition = ''; 3067 } 3068 } 3069 3070 if ($resetpagenum || $pagenumstyle || $suppress) { 3071 $this->PageNumSubstitutions[] = ['from' => ($this->page + 1), 'reset' => $resetpagenum, 'type' => $pagenumstyle, 'suppress' => $suppress]; 3072 } 3073 3074 $save_tr = $this->table_rotate; // *TABLES* 3075 $this->table_rotate = 0; // *TABLES* 3076 $save_kwt = $this->kwt; 3077 $this->kwt = 0; 3078 $save_layer = $this->current_layer; 3079 $save_vis = $this->visibility; 3080 3081 if ($this->visibility != 'visible') { 3082 $this->SetVisibility('visible'); 3083 } 3084 3085 $this->EndLayer(); 3086 3087 // Paint Div Border if necessary 3088 // PAINTS BACKGROUND COLOUR OR BORDERS for DIV - DISABLED FOR COLUMNS (cf. AcceptPageBreak) AT PRESENT in ->PaintDivBB 3089 if (!$this->ColActive && $this->blklvl > 0) { 3090 if (isset($this->blk[$this->blklvl]['y0']) && $this->y == $this->blk[$this->blklvl]['y0'] && !$this->extrapagebreak) { // mPDF 6 pagebreaktype 3091 if (isset($this->blk[$this->blklvl]['startpage'])) { 3092 $this->blk[$this->blklvl]['startpage'] ++; 3093 } else { 3094 $this->blk[$this->blklvl]['startpage'] = 1; 3095 } 3096 } 3097 if ((isset($this->blk[$this->blklvl]['y0']) && $this->y > $this->blk[$this->blklvl]['y0']) || $this->flowingBlockAttr['is_table'] || $this->extrapagebreak) { 3098 $toplvl = $this->blklvl; 3099 } // mPDF 6 pagebreaktype 3100 else { 3101 $toplvl = $this->blklvl - 1; 3102 } 3103 $sy = $this->y; 3104 for ($bl = 1; $bl <= $toplvl; $bl++) { 3105 if (isset($this->blk[$bl]['z-index']) && $this->blk[$bl]['z-index'] > 0) { 3106 $this->BeginLayer($this->blk[$bl]['z-index']); 3107 } 3108 if (isset($this->blk[$bl]['visibility']) && $this->blk[$bl]['visibility'] && $this->blk[$bl]['visibility'] != 'visible') { 3109 $this->SetVisibility($this->blk[$bl]['visibility']); 3110 } 3111 $this->PaintDivBB('pagebottom', 0, $bl); 3112 } 3113 $this->y = $sy; 3114 // RESET block y0 and x0 - see below 3115 } 3116 $this->extrapagebreak = false; // mPDF 6 pagebreaktype 3117 3118 if ($this->visibility != 'visible') { 3119 $this->SetVisibility('visible'); 3120 } 3121 3122 $this->EndLayer(); 3123 3124 // BODY Backgrounds 3125 if ($this->page > 0) { 3126 $s = ''; 3127 $s .= $this->PrintBodyBackgrounds(); 3128 3129 $s .= $this->PrintPageBackgrounds(); 3130 $this->pages[$this->page] = preg_replace('/(___BACKGROUND___PATTERNS' . $this->uniqstr . ')/', "\n" . $s . "\n" . '\\1', $this->pages[$this->page]); 3131 $this->pageBackgrounds = []; 3132 } 3133 3134 $save_kt = $this->keep_block_together; 3135 $this->keep_block_together = 0; 3136 3137 $save_cols = false; 3138 3139 /* -- COLUMNS -- */ 3140 if ($this->ColActive) { 3141 $save_cols = true; 3142 $save_nbcol = $this->NbCol; // other values of gap and vAlign will not change by setting Columns off 3143 $this->SetColumns(0); 3144 } 3145 /* -- END COLUMNS -- */ 3146 3147 $family = $this->FontFamily; 3148 $style = $this->FontStyle; 3149 $size = $this->FontSizePt; 3150 $this->ColumnAdjust = true; // enables column height adjustment for the page 3151 $lw = $this->LineWidth; 3152 $dc = $this->DrawColor; 3153 $fc = $this->FillColor; 3154 $tc = $this->TextColor; 3155 $cf = $this->ColorFlag; 3156 if ($this->page > 0) { 3157 // Page footer 3158 $this->InFooter = true; 3159 3160 $this->Reset(); 3161 $this->pageoutput[$this->page] = []; 3162 3163 $this->Footer(); 3164 // Close page 3165 $this->_endpage(); 3166 } 3167 3168 // Start new page 3169 $this->_beginpage($orientation, $mgl, $mgr, $mgt, $mgb, $mgh, $mgf, $ohname, $ehname, $ofname, $efname, $ohvalue, $ehvalue, $ofvalue, $efvalue, $pagesel, $newformat); 3170 3171 if ($this->docTemplate) { 3172 $currentReaderId = $this->currentReaderId; 3173 3174 $pagecount = $this->setSourceFile($this->docTemplate); 3175 if (($this->page - $this->docTemplateStart) > $pagecount) { 3176 if ($this->docTemplateContinue) { 3177 $tplIdx = $this->importPage($pagecount); 3178 $this->useTemplate($tplIdx); 3179 } 3180 } else { 3181 $tplIdx = $this->importPage(($this->page - $this->docTemplateStart)); 3182 $this->useTemplate($tplIdx); 3183 } 3184 3185 $this->currentReaderId = $currentReaderId; 3186 } 3187 3188 if ($this->pageTemplate) { 3189 $this->useTemplate($this->pageTemplate); 3190 } 3191 3192 // Tiling Patterns 3193 $this->writer->write('___PAGE___START' . $this->uniqstr); 3194 $this->writer->write('___BACKGROUND___PATTERNS' . $this->uniqstr); 3195 $this->writer->write('___HEADER___MARKER' . $this->uniqstr); 3196 $this->pageBackgrounds = []; 3197 3198 // Set line cap style to square 3199 $this->SetLineCap(2); 3200 // Set line width 3201 $this->LineWidth = $lw; 3202 $this->writer->write(sprintf('%.3F w', $lw * Mpdf::SCALE)); 3203 // Set font 3204 if ($family) { 3205 $this->SetFont($family, $style, $size, true, true); // forces write 3206 } 3207 3208 // Set colors 3209 $this->DrawColor = $dc; 3210 if ($dc != $this->defDrawColor) { 3211 $this->writer->write($dc); 3212 } 3213 $this->FillColor = $fc; 3214 if ($fc != $this->defFillColor) { 3215 $this->writer->write($fc); 3216 } 3217 $this->TextColor = $tc; 3218 $this->ColorFlag = $cf; 3219 3220 // Page header 3221 $this->Header(); 3222 3223 // Restore line width 3224 if ($this->LineWidth != $lw) { 3225 $this->LineWidth = $lw; 3226 $this->writer->write(sprintf('%.3F w', $lw * Mpdf::SCALE)); 3227 } 3228 // Restore font 3229 if ($family) { 3230 $this->SetFont($family, $style, $size, true, true); // forces write 3231 } 3232 3233 // Restore colors 3234 if ($this->DrawColor != $dc) { 3235 $this->DrawColor = $dc; 3236 $this->writer->write($dc); 3237 } 3238 if ($this->FillColor != $fc) { 3239 $this->FillColor = $fc; 3240 $this->writer->write($fc); 3241 } 3242 $this->TextColor = $tc; 3243 $this->ColorFlag = $cf; 3244 $this->InFooter = false; 3245 3246 if ($save_layer > 0) { 3247 $this->BeginLayer($save_layer); 3248 } 3249 3250 if ($save_vis != 'visible') { 3251 $this->SetVisibility($save_vis); 3252 } 3253 3254 /* -- COLUMNS -- */ 3255 if ($save_cols) { 3256 // Restore columns 3257 $this->SetColumns($save_nbcol, $this->colvAlign, $this->ColGap); 3258 } 3259 if ($this->ColActive) { 3260 $this->SetCol(0); 3261 } 3262 /* -- END COLUMNS -- */ 3263 3264 3265 // RESET BLOCK BORDER TOP 3266 if (!$this->ColActive) { 3267 for ($bl = 1; $bl <= $this->blklvl; $bl++) { 3268 $this->blk[$bl]['y0'] = $this->y; 3269 if (isset($this->blk[$bl]['x0'])) { 3270 $this->blk[$bl]['x0'] += $this->MarginCorrection; 3271 } else { 3272 $this->blk[$bl]['x0'] = $this->MarginCorrection; 3273 } 3274 // Added mPDF 3.0 Float DIV 3275 $this->blk[$bl]['marginCorrected'][$this->page] = true; 3276 } 3277 } 3278 3279 3280 $this->table_rotate = $save_tr; // *TABLES* 3281 $this->kwt = $save_kwt; 3282 3283 $this->keep_block_together = $save_kt; 3284 3285 $this->cMarginL = $bak_cml; 3286 $this->cMarginR = $bak_cmr; 3287 $this->divwidth = $bak_dw; 3288 3289 $this->lineheight = $bak_lh; 3290 } 3291 3292 /** 3293 * Get current page number 3294 * 3295 * @return int 3296 */ 3297 function PageNo() 3298 { 3299 return $this->page; 3300 } 3301 3302 function AddSpotColorsFromFile($file) 3303 { 3304 $colors = @file($file); 3305 if (!$colors) { 3306 throw new \Mpdf\MpdfException("Cannot load spot colors file - " . $file); 3307 } 3308 foreach ($colors as $sc) { 3309 list($name, $c, $m, $y, $k) = preg_split("/\t/", $sc); 3310 $c = intval($c); 3311 $m = intval($m); 3312 $y = intval($y); 3313 $k = intval($k); 3314 $this->AddSpotColor($name, $c, $m, $y, $k); 3315 } 3316 } 3317 3318 function AddSpotColor($name, $c, $m, $y, $k) 3319 { 3320 $name = strtoupper(trim($name)); 3321 if (!isset($this->spotColors[$name])) { 3322 $i = count($this->spotColors) + 1; 3323 $this->spotColors[$name] = ['i' => $i, 'c' => $c, 'm' => $m, 'y' => $y, 'k' => $k]; 3324 $this->spotColorIDs[$i] = $name; 3325 } 3326 } 3327 3328 function SetColor($col, $type = '') 3329 { 3330 $out = ''; 3331 if (!$col) { 3332 return ''; 3333 } // mPDF 6 3334 if ($col[0] == 3 || $col[0] == 5) { // RGB / RGBa 3335 $out = sprintf('%.3F %.3F %.3F rg', ord($col[1]) / 255, ord($col[2]) / 255, ord($col[3]) / 255); 3336 } elseif ($col[0] == 1) { // GRAYSCALE 3337 $out = sprintf('%.3F g', ord($col[1]) / 255); 3338 } elseif ($col[0] == 2) { // SPOT COLOR 3339 $out = sprintf('/CS%d cs %.3F scn', ord($col[1]), ord($col[2]) / 100); 3340 } elseif ($col[0] == 4 || $col[0] == 6) { // CMYK / CMYKa 3341 $out = sprintf('%.3F %.3F %.3F %.3F k', ord($col[1]) / 100, ord($col[2]) / 100, ord($col[3]) / 100, ord($col[4]) / 100); 3342 } 3343 if ($type == 'Draw') { 3344 $out = strtoupper($out); 3345 } // e.g. rg => RG 3346 elseif ($type == 'CodeOnly') { 3347 $out = preg_replace('/\s(rg|g|k)/', '', $out); 3348 } 3349 return $out; 3350 } 3351 3352 function SetDColor($col, $return = false) 3353 { 3354 $out = $this->SetColor($col, 'Draw'); 3355 if ($return) { 3356 return $out; 3357 } 3358 if ($out == '') { 3359 return ''; 3360 } 3361 $this->DrawColor = $out; 3362 if ($this->page > 0 && ((isset($this->pageoutput[$this->page]['DrawColor']) && $this->pageoutput[$this->page]['DrawColor'] != $this->DrawColor) || !isset($this->pageoutput[$this->page]['DrawColor']))) { 3363 $this->writer->write($this->DrawColor); 3364 } 3365 $this->pageoutput[$this->page]['DrawColor'] = $this->DrawColor; 3366 } 3367 3368 function SetFColor($col, $return = false) 3369 { 3370 $out = $this->SetColor($col, 'Fill'); 3371 if ($return) { 3372 return $out; 3373 } 3374 if ($out == '') { 3375 return ''; 3376 } 3377 $this->FillColor = $out; 3378 $this->ColorFlag = ($out != $this->TextColor); 3379 if ($this->page > 0 && ((isset($this->pageoutput[$this->page]['FillColor']) && $this->pageoutput[$this->page]['FillColor'] != $this->FillColor) || !isset($this->pageoutput[$this->page]['FillColor']))) { 3380 $this->writer->write($this->FillColor); 3381 } 3382 $this->pageoutput[$this->page]['FillColor'] = $this->FillColor; 3383 } 3384 3385 function SetTColor($col, $return = false) 3386 { 3387 $out = $this->SetColor($col, 'Text'); 3388 if ($return) { 3389 return $out; 3390 } 3391 if ($out == '') { 3392 return ''; 3393 } 3394 $this->TextColor = $out; 3395 $this->ColorFlag = ($this->FillColor != $out); 3396 } 3397 3398 function SetDrawColor($r, $g = -1, $b = -1, $col4 = -1, $return = false) 3399 { 3400 // Set color for all stroking operations 3401 $col = []; 3402 if (($r == 0 and $g == 0 and $b == 0 && $col4 == -1) or $g == -1) { 3403 $col = $this->colorConverter->convert($r, $this->PDFAXwarnings); 3404 } elseif ($col4 == -1) { 3405 $col = $this->colorConverter->convert('rgb(' . $r . ',' . $g . ',' . $b . ')', $this->PDFAXwarnings); 3406 } else { 3407 $col = $this->colorConverter->convert('cmyk(' . $r . ',' . $g . ',' . $b . ',' . $col4 . ')', $this->PDFAXwarnings); 3408 } 3409 $out = $this->SetDColor($col, $return); 3410 return $out; 3411 } 3412 3413 function SetFillColor($r, $g = -1, $b = -1, $col4 = -1, $return = false) 3414 { 3415 // Set color for all filling operations 3416 $col = []; 3417 if (($r == 0 and $g == 0 and $b == 0 && $col4 == -1) or $g == -1) { 3418 $col = $this->colorConverter->convert($r, $this->PDFAXwarnings); 3419 } elseif ($col4 == -1) { 3420 $col = $this->colorConverter->convert('rgb(' . $r . ',' . $g . ',' . $b . ')', $this->PDFAXwarnings); 3421 } else { 3422 $col = $this->colorConverter->convert('cmyk(' . $r . ',' . $g . ',' . $b . ',' . $col4 . ')', $this->PDFAXwarnings); 3423 } 3424 $out = $this->SetFColor($col, $return); 3425 return $out; 3426 } 3427 3428 function SetTextColor($r, $g = -1, $b = -1, $col4 = -1, $return = false) 3429 { 3430 // Set color for text 3431 $col = []; 3432 if (($r == 0 and $g == 0 and $b == 0 && $col4 == -1) or $g == -1) { 3433 $col = $this->colorConverter->convert($r, $this->PDFAXwarnings); 3434 } elseif ($col4 == -1) { 3435 $col = $this->colorConverter->convert('rgb(' . $r . ',' . $g . ',' . $b . ')', $this->PDFAXwarnings); 3436 } else { 3437 $col = $this->colorConverter->convert('cmyk(' . $r . ',' . $g . ',' . $b . ',' . $col4 . ')', $this->PDFAXwarnings); 3438 } 3439 $out = $this->SetTColor($col, $return); 3440 return $out; 3441 } 3442 3443 function _getCharWidth(&$cw, $u, $isdef = true) 3444 { 3445 $w = 0; 3446 3447 if ($u == 0) { 3448 $w = false; 3449 } elseif (isset($cw[$u * 2 + 1])) { 3450 $w = (ord($cw[$u * 2]) << 8) + ord($cw[$u * 2 + 1]); 3451 } 3452 3453 if ($w == 65535) { 3454 return 0; 3455 } elseif ($w) { 3456 return $w; 3457 } elseif ($isdef) { 3458 return false; 3459 } else { 3460 return 0; 3461 } 3462 } 3463 3464 function _charDefined(&$cw, $u) 3465 { 3466 $w = 0; 3467 if ($u == 0) { 3468 return false; 3469 } 3470 if (isset($cw[$u * 2 + 1])) { 3471 $w = (ord($cw[$u * 2]) << 8) + ord($cw[$u * 2 + 1]); 3472 } 3473 3474 return (bool) $w; 3475 } 3476 3477 function GetCharWidthCore($c) 3478 { 3479 // Get width of a single character in the current Core font 3480 $c = (string) $c; 3481 $w = 0; 3482 // Soft Hyphens chr(173) 3483 if ($c == chr(173) && $this->FontFamily != 'csymbol' && $this->FontFamily != 'czapfdingbats') { 3484 return 0; 3485 } elseif (($this->textvar & TextVars::FC_SMALLCAPS) && isset($this->upperCase[ord($c)])) { // mPDF 5.7.1 3486 $charw = $this->CurrentFont['cw'][chr($this->upperCase[ord($c)])]; 3487 if ($charw !== false) { 3488 $charw = $charw * $this->smCapsScale * $this->smCapsStretch / 100; 3489 $w+=$charw; 3490 } 3491 } elseif (isset($this->CurrentFont['cw'][$c])) { 3492 $w += $this->CurrentFont['cw'][$c]; 3493 } elseif (isset($this->CurrentFont['cw'][ord($c)])) { 3494 $w += $this->CurrentFont['cw'][ord($c)]; 3495 } 3496 $w *= ($this->FontSize / 1000); 3497 if ($this->minwSpacing || $this->fixedlSpacing) { 3498 if ($c == ' ') { 3499 $nb_spaces = 1; 3500 } else { 3501 $nb_spaces = 0; 3502 } 3503 $w += $this->fixedlSpacing + ($nb_spaces * $this->minwSpacing); 3504 } 3505 return ($w); 3506 } 3507 3508 function GetCharWidthNonCore($c, $addSubset = true) 3509 { 3510 // Get width of a single character in the current Non-Core font 3511 $c = (string) $c; 3512 $w = 0; 3513 $unicode = $this->UTF8StringToArray($c, $addSubset); 3514 $char = $unicode[0]; 3515 /* -- CJK-FONTS -- */ 3516 if ($this->CurrentFont['type'] == 'Type0') { // CJK Adobe fonts 3517 if ($char == 173) { 3518 return 0; 3519 } // Soft Hyphens 3520 elseif (isset($this->CurrentFont['cw'][$char])) { 3521 $w+=$this->CurrentFont['cw'][$char]; 3522 } elseif (isset($this->CurrentFont['MissingWidth'])) { 3523 $w += $this->CurrentFont['MissingWidth']; 3524 } else { 3525 $w += 500; 3526 } 3527 } else { 3528 /* -- END CJK-FONTS -- */ 3529 if ($char == 173) { 3530 return 0; 3531 } // Soft Hyphens 3532 elseif (($this->textvar & TextVars::FC_SMALLCAPS) && isset($this->upperCase[$char])) { // mPDF 5.7.1 3533 $charw = $this->_getCharWidth($this->CurrentFont['cw'], $this->upperCase[$char]); 3534 if ($charw !== false) { 3535 $charw = $charw * $this->smCapsScale * $this->smCapsStretch / 100; 3536 $w+=$charw; 3537 } elseif (isset($this->CurrentFont['desc']['MissingWidth'])) { 3538 $w += $this->CurrentFont['desc']['MissingWidth']; 3539 } elseif (isset($this->CurrentFont['MissingWidth'])) { 3540 $w += $this->CurrentFont['MissingWidth']; 3541 } else { 3542 $w += 500; 3543 } 3544 } else { 3545 $charw = $this->_getCharWidth($this->CurrentFont['cw'], $char); 3546 if ($charw !== false) { 3547 $w+=$charw; 3548 } elseif (isset($this->CurrentFont['desc']['MissingWidth'])) { 3549 $w += $this->CurrentFont['desc']['MissingWidth']; 3550 } elseif (isset($this->CurrentFont['MissingWidth'])) { 3551 $w += $this->CurrentFont['MissingWidth']; 3552 } else { 3553 $w += 500; 3554 } 3555 } 3556 } // *CJK-FONTS* 3557 $w *= ($this->FontSize / 1000); 3558 if ($this->minwSpacing || $this->fixedlSpacing) { 3559 if ($c == ' ') { 3560 $nb_spaces = 1; 3561 } else { 3562 $nb_spaces = 0; 3563 } 3564 $w += $this->fixedlSpacing + ($nb_spaces * $this->minwSpacing); 3565 } 3566 return ($w); 3567 } 3568 3569 function GetCharWidth($c, $addSubset = true) 3570 { 3571 if (!$this->usingCoreFont) { 3572 return $this->GetCharWidthNonCore($c, $addSubset); 3573 } else { 3574 return $this->GetCharWidthCore($c); 3575 } 3576 } 3577 3578 function GetStringWidth($s, $addSubset = true, $OTLdata = false, $textvar = 0, $includeKashida = false) 3579 { 3580 // mPDF 5.7.1 3581 // Get width of a string in the current font 3582 $s = (string) $s; 3583 $cw = &$this->CurrentFont['cw']; 3584 $w = 0; 3585 $kerning = 0; 3586 $lastchar = 0; 3587 $nb_carac = 0; 3588 $nb_spaces = 0; 3589 $kashida = 0; 3590 // mPDF ITERATION 3591 if ($this->iterationCounter) { 3592 $s = preg_replace('/{iteration ([a-zA-Z0-9_]+)}/', '\\1', $s); 3593 } 3594 if (!$this->usingCoreFont) { 3595 $discards = substr_count($s, "\xc2\xad"); // mPDF 6 soft hyphens [U+00AD] 3596 $unicode = $this->UTF8StringToArray($s, $addSubset); 3597 if ($this->minwSpacing || $this->fixedlSpacing) { 3598 $nb_spaces = mb_substr_count($s, ' ', $this->mb_enc); 3599 $nb_carac = count($unicode) - $discards; // mPDF 6 3600 // mPDF 5.7.1 3601 // Use GPOS OTL 3602 if (isset($this->CurrentFont['useOTL']) && $this->CurrentFont['useOTL']) { 3603 if (isset($OTLdata['group']) && $OTLdata['group']) { 3604 $nb_carac -= substr_count($OTLdata['group'], 'M'); 3605 } 3606 } 3607 } 3608 /* -- CJK-FONTS -- */ 3609 if ($this->CurrentFont['type'] == 'Type0') { // CJK Adobe fonts 3610 foreach ($unicode as $char) { 3611 if ($char == 0x00AD) { 3612 continue; 3613 } // mPDF 6 soft hyphens [U+00AD] 3614 if (isset($cw[$char])) { 3615 $w+=$cw[$char]; 3616 } elseif (isset($this->CurrentFont['MissingWidth'])) { 3617 $w += $this->CurrentFont['MissingWidth']; 3618 } else { 3619 $w += 500; 3620 } 3621 } 3622 } else { 3623 /* -- END CJK-FONTS -- */ 3624 foreach ($unicode as $i => $char) { 3625 if ($char == 0x00AD) { 3626 continue; 3627 } // mPDF 6 soft hyphens [U+00AD] 3628 if (($textvar & TextVars::FC_SMALLCAPS) && isset($this->upperCase[$char])) { 3629 $charw = $this->_getCharWidth($cw, $this->upperCase[$char]); 3630 if ($charw !== false) { 3631 $charw = $charw * $this->smCapsScale * $this->smCapsStretch / 100; 3632 $w+=$charw; 3633 } elseif (isset($this->CurrentFont['desc']['MissingWidth'])) { 3634 $w += $this->CurrentFont['desc']['MissingWidth']; 3635 } elseif (isset($this->CurrentFont['MissingWidth'])) { 3636 $w += $this->CurrentFont['MissingWidth']; 3637 } else { 3638 $w += 500; 3639 } 3640 } else { 3641 $charw = $this->_getCharWidth($cw, $char); 3642 if ($charw !== false) { 3643 $w+=$charw; 3644 } elseif (isset($this->CurrentFont['desc']['MissingWidth'])) { 3645 $w += $this->CurrentFont['desc']['MissingWidth']; 3646 } elseif (isset($this->CurrentFont['MissingWidth'])) { 3647 $w += $this->CurrentFont['MissingWidth']; 3648 } else { 3649 $w += 500; 3650 } 3651 // mPDF 5.7.1 3652 // Use GPOS OTL 3653 // ...GetStringWidth... 3654 if (isset($this->CurrentFont['useOTL']) && ($this->CurrentFont['useOTL'] & 0xFF) && !empty($OTLdata)) { 3655 if (isset($OTLdata['GPOSinfo'][$i]['wDir']) && $OTLdata['GPOSinfo'][$i]['wDir'] == 'RTL') { 3656 if (isset($OTLdata['GPOSinfo'][$i]['XAdvanceR']) && $OTLdata['GPOSinfo'][$i]['XAdvanceR']) { 3657 $w += $OTLdata['GPOSinfo'][$i]['XAdvanceR'] * 1000 / $this->CurrentFont['unitsPerEm']; 3658 } 3659 } else { 3660 if (isset($OTLdata['GPOSinfo'][$i]['XAdvanceL']) && $OTLdata['GPOSinfo'][$i]['XAdvanceL']) { 3661 $w += $OTLdata['GPOSinfo'][$i]['XAdvanceL'] * 1000 / $this->CurrentFont['unitsPerEm']; 3662 } 3663 } 3664 // Kashida from GPOS 3665 // Kashida is set as an absolute length value (already set as a proportion based on useKashida %) 3666 if ($includeKashida && isset($OTLdata['GPOSinfo'][$i]['kashida_space']) && $OTLdata['GPOSinfo'][$i]['kashida_space']) { 3667 $kashida += $OTLdata['GPOSinfo'][$i]['kashida_space']; 3668 } 3669 } 3670 if (($textvar & TextVars::FC_KERNING) && $lastchar) { 3671 if (isset($this->CurrentFont['kerninfo'][$lastchar][$char])) { 3672 $kerning += $this->CurrentFont['kerninfo'][$lastchar][$char]; 3673 } 3674 } 3675 $lastchar = $char; 3676 } 3677 } 3678 } // *CJK-FONTS* 3679 } else { 3680 if ($this->FontFamily != 'csymbol' && $this->FontFamily != 'czapfdingbats') { 3681 $s = str_replace(chr(173), '', $s); 3682 } 3683 $nb_carac = $l = strlen($s); 3684 if ($this->minwSpacing || $this->fixedlSpacing) { 3685 $nb_spaces = substr_count($s, ' '); 3686 } 3687 for ($i = 0; $i < $l; $i++) { 3688 if (($textvar & TextVars::FC_SMALLCAPS) && isset($this->upperCase[ord($s[$i])])) { // mPDF 5.7.1 3689 $charw = $cw[chr($this->upperCase[ord($s[$i])])]; 3690 if ($charw !== false) { 3691 $charw = $charw * $this->smCapsScale * $this->smCapsStretch / 100; 3692 $w+=$charw; 3693 } 3694 } elseif (isset($cw[$s[$i]])) { 3695 $w += $cw[$s[$i]]; 3696 } elseif (isset($cw[ord($s[$i])])) { 3697 $w += $cw[ord($s[$i])]; 3698 } 3699 if (($textvar & TextVars::FC_KERNING) && $i > 0) { // mPDF 5.7.1 3700 if (isset($this->CurrentFont['kerninfo'][$s[($i - 1)]][$s[$i]])) { 3701 $kerning += $this->CurrentFont['kerninfo'][$s[($i - 1)]][$s[$i]]; 3702 } 3703 } 3704 } 3705 } 3706 unset($cw); 3707 if ($textvar & TextVars::FC_KERNING) { 3708 $w += $kerning; 3709 } // mPDF 5.7.1 3710 $w *= ($this->FontSize / 1000); 3711 $w += (($nb_carac + $nb_spaces) * $this->fixedlSpacing) + ($nb_spaces * $this->minwSpacing); 3712 $w += $kashida / Mpdf::SCALE; 3713 3714 return ($w); 3715 } 3716 3717 function SetLineWidth($width) 3718 { 3719 // Set line width 3720 $this->LineWidth = $width; 3721 $lwout = (sprintf('%.3F w', $width * Mpdf::SCALE)); 3722 if ($this->page > 0 && ((isset($this->pageoutput[$this->page]['LineWidth']) && $this->pageoutput[$this->page]['LineWidth'] != $lwout) || !isset($this->pageoutput[$this->page]['LineWidth']))) { 3723 $this->writer->write($lwout); 3724 } 3725 $this->pageoutput[$this->page]['LineWidth'] = $lwout; 3726 } 3727 3728 function Line($x1, $y1, $x2, $y2) 3729 { 3730 // Draw a line 3731 $this->writer->write(sprintf('%.3F %.3F m %.3F %.3F l S', $x1 * Mpdf::SCALE, ($this->h - $y1) * Mpdf::SCALE, $x2 * Mpdf::SCALE, ($this->h - $y2) * Mpdf::SCALE)); 3732 } 3733 3734 function Arrow($x1, $y1, $x2, $y2, $headsize = 3, $fill = 'B', $angle = 25) 3735 { 3736 // F == fill // S == stroke // B == stroke and fill 3737 // angle = splay of arrowhead - 1 - 89 degrees 3738 if ($fill == 'F') { 3739 $fill = 'f'; 3740 } elseif ($fill == 'FD' or $fill == 'DF' or $fill == 'B') { 3741 $fill = 'B'; 3742 } else { 3743 $fill = 'S'; 3744 } 3745 $a = atan2(($y2 - $y1), ($x2 - $x1)); 3746 $b = $a + deg2rad($angle); 3747 $c = $a - deg2rad($angle); 3748 $x3 = $x2 - ($headsize * cos($b)); 3749 $y3 = $this->h - ($y2 - ($headsize * sin($