PageRenderTime 83ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 2ms

/application/helpers/mpdf/mpdf.php

https://bitbucket.org/Korrigan33/fusioninvoice
PHP | 13048 lines | 10673 code | 1240 blank | 1135 comment | 4328 complexity | 6c9dc135cb0588ed57876750254b172b MD5 | raw file
Possible License(s): LGPL-2.1
  1. <?php
  2. // ******************************************************************************
  3. // Software: mPDF, Unicode-HTML Free PDF generator *
  4. // Version: 5.6 based on *
  5. // FPDF by Olivier PLATHEY *
  6. // HTML2FPDF by Renato Coelho *
  7. // Date: 2013-01-20 *
  8. // Author: Ian Back <ianb@bpm1.com> *
  9. // License: GPL *
  10. // *
  11. // Changes: See changelog.txt *
  12. // ******************************************************************************
  13. define('mPDF_VERSION','5.6');
  14. //Scale factor
  15. define('_MPDFK', (72/25.4));
  16. /*-- HTML-CSS --*/
  17. define('AUTOFONT_CJK',1);
  18. define('AUTOFONT_THAIVIET',2);
  19. define('AUTOFONT_RTL',4);
  20. define('AUTOFONT_INDIC',8);
  21. define('AUTOFONT_ALL',15);
  22. define('_BORDER_ALL',15);
  23. define('_BORDER_TOP',8);
  24. define('_BORDER_RIGHT',4);
  25. define('_BORDER_BOTTOM',2);
  26. define('_BORDER_LEFT',1);
  27. /*-- END HTML-CSS --*/
  28. if (!defined('_MPDF_PATH')) define('_MPDF_PATH', dirname(preg_replace('/\\\\/','/',__FILE__)) . '/');
  29. if (!defined('_MPDF_URI')) define('_MPDF_URI',_MPDF_PATH);
  30. require_once(_MPDF_PATH.'includes/functions.php');
  31. require_once(_MPDF_PATH.'config_cp.php');
  32. if (!defined('_JPGRAPH_PATH')) define("_JPGRAPH_PATH", _MPDF_PATH.'jpgraph/');
  33. if (!defined('_MPDF_TEMP_PATH')) define("_MPDF_TEMP_PATH", _MPDF_PATH.'tmp/');
  34. if (!defined('_MPDF_TTFONTPATH')) { define('_MPDF_TTFONTPATH',_MPDF_PATH.'ttfonts/'); }
  35. if (!defined('_MPDF_TTFONTDATAPATH')) { define('_MPDF_TTFONTDATAPATH',_MPDF_PATH.'ttfontdata/'); }
  36. $errorlevel=error_reporting();
  37. $errorlevel=error_reporting($errorlevel & ~E_NOTICE);
  38. //error_reporting(E_ALL);
  39. if(function_exists("date_default_timezone_set")) {
  40. if (ini_get("date.timezone")=="") { date_default_timezone_set("Europe/London"); }
  41. }
  42. if (!function_exists("mb_strlen")) { die("Error - mPDF requires mb_string functions. Ensure that PHP is compiled with php_mbstring.dll enabled."); }
  43. if (!defined('PHP_VERSION_ID')) {
  44. $version = explode('.', PHP_VERSION);
  45. define('PHP_VERSION_ID', ($version[0] * 10000 + $version[1] * 100 + $version[2]));
  46. }
  47. // Machine dependent number of bytes used to pack "double" into binary (used in cacheTables)
  48. $test = pack("d", 134455.474557333333666);
  49. define("_DSIZE", strlen($test));
  50. class mPDF
  51. {
  52. ///////////////////////////////
  53. // EXTERNAL (PUBLIC) VARIABLES
  54. // Define these in config.php
  55. ///////////////////////////////
  56. var $margBuffer; // mPDF 5.4.04
  57. var $splitTableBorderWidth; // mPDF 5.4.16
  58. var $cacheTables;
  59. var $bookmarkStyles;
  60. var $useActiveForms;
  61. var $repackageTTF;
  62. var $allowCJKorphans;
  63. var $allowCJKoverflow;
  64. var $useKerning;
  65. var $restrictColorSpace;
  66. var $bleedMargin;
  67. var $crossMarkMargin;
  68. var $cropMarkMargin;
  69. var $cropMarkLength;
  70. var $nonPrintMargin;
  71. var $PDFX;
  72. var $PDFXauto;
  73. var $PDFA;
  74. var $PDFAauto;
  75. var $ICCProfile;
  76. var $printers_info;
  77. var $iterationCounter;
  78. var $smCapsScale;
  79. var $smCapsStretch;
  80. var $backupSubsFont;
  81. var $backupSIPFont;
  82. var $debugfonts;
  83. var $useAdobeCJK;
  84. var $percentSubset;
  85. var $maxTTFFilesize;
  86. var $BMPonly;
  87. var $tableMinSizePriority;
  88. var $dpi;
  89. var $watermarkImgAlphaBlend;
  90. var $watermarkImgBehind;
  91. var $justifyB4br;
  92. var $packTableData;
  93. var $pgsIns;
  94. var $simpleTables;
  95. var $enableImports;
  96. var $debug;
  97. var $showStats;
  98. var $setAutoTopMargin;
  99. var $setAutoBottomMargin;
  100. var $autoMarginPadding;
  101. var $collapseBlockMargins;
  102. var $falseBoldWeight;
  103. var $normalLineheight;
  104. var $progressBar;
  105. var $incrementFPR1;
  106. var $incrementFPR2;
  107. var $incrementFPR3;
  108. var $incrementFPR4;
  109. var $hyphenate;
  110. var $hyphenateTables;
  111. var $SHYlang;
  112. var $SHYleftmin;
  113. var $SHYrightmin;
  114. var $SHYcharmin;
  115. var $SHYcharmax;
  116. var $SHYlanguages;
  117. // PageNumber Conditional Text
  118. var $pagenumPrefix;
  119. var $pagenumSuffix;
  120. var $nbpgPrefix;
  121. var $nbpgSuffix;
  122. var $showImageErrors;
  123. var $allow_output_buffering;
  124. var $autoPadding;
  125. var $useGraphs;
  126. var $autoFontGroupSize;
  127. var $tabSpaces;
  128. var $useLang;
  129. var $restoreBlockPagebreaks;
  130. var $watermarkTextAlpha;
  131. var $watermarkImageAlpha;
  132. var $watermark_size;
  133. var $watermark_pos;
  134. var $annotSize;
  135. var $annotMargin;
  136. var $annotOpacity;
  137. var $title2annots;
  138. var $keepColumns;
  139. var $keep_table_proportions;
  140. var $ignore_table_widths;
  141. var $ignore_table_percents;
  142. var $list_align_style;
  143. var $list_number_suffix;
  144. var $useSubstitutions;
  145. var $CSSselectMedia;
  146. var $forcePortraitHeaders;
  147. var $forcePortraitMargins;
  148. var $displayDefaultOrientation;
  149. var $ignore_invalid_utf8;
  150. var $allowedCSStags;
  151. var $onlyCoreFonts;
  152. var $allow_charset_conversion;
  153. var $jSWord;
  154. var $jSmaxChar;
  155. var $jSmaxCharLast;
  156. var $jSmaxWordLast;
  157. var $orphansAllowed;
  158. var $max_colH_correction;
  159. var $table_error_report;
  160. var $table_error_report_param;
  161. var $biDirectional;
  162. var $text_input_as_HTML;
  163. var $anchor2Bookmark;
  164. var $list_indent_first_level;
  165. var $shrink_tables_to_fit;
  166. var $allow_html_optional_endtags;
  167. var $img_dpi;
  168. var $defaultheaderfontsize;
  169. var $defaultheaderfontstyle;
  170. var $defaultheaderline;
  171. var $defaultfooterfontsize;
  172. var $defaultfooterfontstyle;
  173. var $defaultfooterline;
  174. var $header_line_spacing;
  175. var $footer_line_spacing;
  176. var $pregUHCchars;
  177. var $pregSJISchars;
  178. var $pregCJKchars;
  179. var $pregASCIIchars1;
  180. var $pregASCIIchars2;
  181. var $pregASCIIchars3;
  182. var $pregVIETchars;
  183. var $pregVIETPluschars;
  184. var $pregRTLchars;
  185. var $pregHEBchars;
  186. var $pregARABICchars;
  187. var $pregNonARABICchars;
  188. // INDIC
  189. var $pregHIchars;
  190. var $pregBNchars;
  191. var $pregPAchars;
  192. var $pregGUchars;
  193. var $pregORchars;
  194. var $pregTAchars;
  195. var $pregTEchars;
  196. var $pregKNchars;
  197. var $pregMLchars;
  198. var $pregSHchars;
  199. var $pregINDextra;
  200. var $mirrorMargins;
  201. var $default_lineheight_correction;
  202. var $watermarkText;
  203. var $watermarkImage;
  204. var $showWatermarkText;
  205. var $showWatermarkImage;
  206. var $fontsizes;
  207. // Aliases for backward compatability
  208. var $UnvalidatedText; // alias = $watermarkText
  209. var $TopicIsUnvalidated; // alias = $showWatermarkText
  210. var $useOddEven; // alias = $mirrorMargins
  211. var $useSubstitutionsMB; // alias = $useSubstitutions
  212. //////////////////////
  213. // CLASS OBJECTS
  214. //////////////////////
  215. var $grad;
  216. var $bmp;
  217. var $wmf;
  218. var $tocontents;
  219. var $form;
  220. var $directw;
  221. //////////////////////
  222. // INTERNAL VARIABLES
  223. //////////////////////
  224. var $inMeter; // mPDF 5.5.09
  225. var $CJKleading;
  226. var $CJKfollowing;
  227. var $CJKoverflow;
  228. var $textshadow;
  229. var $colsums;
  230. var $spanborder;
  231. var $spanborddet;
  232. var $visibility;
  233. var $useRC128encryption;
  234. var $uniqid;
  235. var $kerning;
  236. var $fixedlSpacing;
  237. var $minwSpacing;
  238. var $lSpacingCSS;
  239. var $wSpacingCSS;
  240. var $listDir;
  241. var $spotColorIDs;
  242. var $SVGcolors;
  243. var $spotColors;
  244. var $defTextColor;
  245. var $defDrawColor;
  246. var $defFillColor;
  247. var $tableBackgrounds;
  248. var $inlineDisplayOff;
  249. var $kt_y00;
  250. var $kt_p00;
  251. var $upperCase;
  252. var $checkSIP;
  253. var $checkSMP;
  254. var $checkCJK;
  255. var $tableCJK;
  256. var $watermarkImgAlpha;
  257. var $PDFAXwarnings;
  258. var $MetadataRoot;
  259. var $OutputIntentRoot;
  260. var $InfoRoot;
  261. var $current_filename;
  262. var $parsers;
  263. var $current_parser;
  264. var $_obj_stack;
  265. var $_don_obj_stack;
  266. var $_current_obj_id;
  267. var $tpls;
  268. var $tpl;
  269. var $tplprefix;
  270. var $_res;
  271. var $pdf_version;
  272. var $noImageFile;
  273. var $lastblockbottommargin;
  274. var $baselineC;
  275. var $subPos;
  276. var $subArrMB;
  277. var $ReqFontStyle;
  278. var $tableClipPath ;
  279. var $forceExactLineheight;
  280. var $listOcc;
  281. var $fullImageHeight;
  282. var $inFixedPosBlock; // Internal flag for position:fixed block
  283. var $fixedPosBlock; // Buffer string for position:fixed block
  284. var $fixedPosBlockDepth;
  285. var $fixedPosBlockBBox;
  286. var $fixedPosBlockSave;
  287. var $maxPosL;
  288. var $maxPosR;
  289. var $loaded;
  290. var $extraFontSubsets;
  291. var $docTemplateStart; // Internal flag for page (page no. -1) that docTemplate starts on
  292. var $time0;
  293. // Classes
  294. var $indic;
  295. var $barcode;
  296. var $SHYpatterns;
  297. var $loadedSHYpatterns;
  298. var $loadedSHYdictionary;
  299. var $SHYdictionary;
  300. var $SHYdictionaryWords;
  301. var $spanbgcolorarray;
  302. var $default_font;
  303. var $list_lineheight;
  304. var $headerbuffer;
  305. var $lastblocklevelchange;
  306. var $nestedtablejustfinished;
  307. var $linebreakjustfinished;
  308. var $cell_border_dominance_L;
  309. var $cell_border_dominance_R;
  310. var $cell_border_dominance_T;
  311. var $cell_border_dominance_B;
  312. var $tbCSSlvl;
  313. var $listCSSlvl;
  314. var $table_keep_together;
  315. var $plainCell_properties;
  316. var $inherit_lineheight;
  317. var $listitemtype;
  318. var $shrin_k1;
  319. var $outerfilled;
  320. var $blockContext;
  321. var $floatDivs;
  322. var $tablecascadeCSS;
  323. var $listcascadeCSS;
  324. var $patterns;
  325. var $pageBackgrounds;
  326. var $bodyBackgroundGradient;
  327. var $bodyBackgroundImage;
  328. var $bodyBackgroundColor;
  329. var $writingHTMLheader; // internal flag - used both for writing HTMLHeaders/Footers and FixedPos block
  330. var $writingHTMLfooter;
  331. var $autoFontGroups;
  332. var $angle;
  333. var $gradients;
  334. var $kwt_Reference;
  335. var $kwt_BMoutlines;
  336. var $kwt_toc;
  337. var $tbrot_Reference;
  338. var $tbrot_BMoutlines;
  339. var $tbrot_toc;
  340. var $col_Reference;
  341. var $col_BMoutlines;
  342. var $col_toc;
  343. var $currentGraphId;
  344. var $graphs;
  345. var $floatbuffer;
  346. var $floatmargins;
  347. var $bullet;
  348. var $bulletarray;
  349. var $rtlAsArabicFarsi; // DEPRACATED
  350. var $currentLang;
  351. var $default_lang;
  352. var $default_available_fonts;
  353. var $pageTemplate;
  354. var $docTemplate;
  355. var $docTemplateContinue;
  356. var $arabGlyphs;
  357. var $arabHex;
  358. var $persianGlyphs;
  359. var $persianHex;
  360. var $arabVowels;
  361. var $arabPrevLink;
  362. var $arabNextLink;
  363. var $formobjects; // array of Form Objects for WMF
  364. var $InlineProperties;
  365. var $InlineAnnots;
  366. var $ktAnnots;
  367. var $tbrot_Annots;
  368. var $kwt_Annots;
  369. var $columnAnnots;
  370. var $columnForms;
  371. var $PageAnnots;
  372. var $pageDim; // Keep track of page wxh for orientation changes - set in _beginpage, used in _putannots
  373. var $breakpoints;
  374. var $tableLevel;
  375. var $tbctr;
  376. var $innermostTableLevel;
  377. var $saveTableCounter;
  378. var $cellBorderBuffer;
  379. var $saveHTMLFooter_height;
  380. var $saveHTMLFooterE_height;
  381. var $firstPageBoxHeader;
  382. var $firstPageBoxHeaderEven;
  383. var $firstPageBoxFooter;
  384. var $firstPageBoxFooterEven;
  385. var $page_box;
  386. var $show_marks; // crop or cross marks
  387. var $basepathIsLocal;
  388. var $use_kwt;
  389. var $kwt;
  390. var $kwt_height;
  391. var $kwt_y0;
  392. var $kwt_x0;
  393. var $kwt_buffer;
  394. var $kwt_Links;
  395. var $kwt_moved;
  396. var $kwt_saved;
  397. var $PageNumSubstitutions;
  398. var $table_borders_separate;
  399. var $base_table_properties;
  400. var $borderstyles;
  401. var $listjustfinished;
  402. var $blockjustfinished;
  403. var $orig_bMargin;
  404. var $orig_tMargin;
  405. var $orig_lMargin;
  406. var $orig_rMargin;
  407. var $orig_hMargin;
  408. var $orig_fMargin;
  409. var $pageheaders;
  410. var $pagefooters;
  411. var $pageHTMLheaders;
  412. var $pageHTMLfooters;
  413. var $saveHTMLHeader;
  414. var $saveHTMLFooter;
  415. var $HTMLheaderPageLinks;
  416. var $HTMLheaderPageAnnots;
  417. var $HTMLheaderPageForms;
  418. // See config_fonts.php for these next 5 values
  419. var $available_unifonts;
  420. var $sans_fonts;
  421. var $serif_fonts;
  422. var $mono_fonts;
  423. var $defaultSubsFont;
  424. // List of ALL available CJK fonts (incl. styles) (Adobe add-ons) hw removed
  425. var $available_CJK_fonts;
  426. var $cascadeCSS;
  427. var $HTMLHeader;
  428. var $HTMLFooter;
  429. var $HTMLHeaderE;
  430. var $HTMLFooterE;
  431. var $bufferoutput;
  432. var $showdefaultpagenos; // DEPRACATED -left for backward compatability
  433. // CJK fonts
  434. var $Big5_widths;
  435. var $GB_widths;
  436. var $SJIS_widths;
  437. var $UHC_widths;
  438. // SetProtection
  439. var $encrypted; //whether document is protected
  440. var $Uvalue; //U entry in pdf document
  441. var $Ovalue; //O entry in pdf document
  442. var $Pvalue; //P entry in pdf document
  443. var $enc_obj_id; //encryption object id
  444. var $last_rc4_key; //last RC4 key encrypted (cached for optimisation)
  445. var $last_rc4_key_c; //last RC4 computed key
  446. var $encryption_key;
  447. var $padding; //used for encryption
  448. // Bookmark
  449. var $BMoutlines;
  450. var $OutlineRoot;
  451. // INDEX
  452. var $ColActive;
  453. var $Reference;
  454. var $CurrCol;
  455. var $NbCol;
  456. var $y0; //Top ordinate of columns
  457. var $ColL;
  458. var $ColWidth;
  459. var $ColGap;
  460. // COLUMNS
  461. var $ColR;
  462. var $ChangeColumn;
  463. var $columnbuffer;
  464. var $ColDetails;
  465. var $columnLinks;
  466. var $colvAlign;
  467. // Substitutions
  468. var $substitute; // Array of substitution strings e.g. <ttz>112</ttz>
  469. var $entsearch; // Array of HTML entities (>ASCII 127) to substitute
  470. var $entsubstitute; // Array of substitution decimal unicode for the Hi entities
  471. // Default values if no style sheet offered (cf. http://www.w3.org/TR/CSS21/sample.html)
  472. var $defaultCSS;
  473. var $linemaxfontsize;
  474. var $lineheight_correction;
  475. var $lastoptionaltag; // Save current block item which HTML specifies optionsl endtag
  476. var $pageoutput;
  477. var $charset_in;
  478. var $blk;
  479. var $blklvl;
  480. var $ColumnAdjust;
  481. var $ws; // Word spacing
  482. var $HREF;
  483. var $pgwidth;
  484. var $fontlist;
  485. var $oldx;
  486. var $oldy;
  487. var $B;
  488. var $U; //underlining flag
  489. var $S; // SmallCaps flag
  490. var $I;
  491. var $tdbegin;
  492. var $table;
  493. var $cell;
  494. var $col;
  495. var $row;
  496. var $divbegin;
  497. var $divalign;
  498. var $divwidth;
  499. var $divheight;
  500. var $divrevert;
  501. var $spanbgcolor;
  502. var $spanlvl;
  503. var $listlvl;
  504. var $listnum;
  505. var $listtype;
  506. var $listoccur;
  507. var $listlist;
  508. var $listitem;
  509. var $pjustfinished;
  510. var $ignorefollowingspaces;
  511. var $SUP;
  512. var $SUB;
  513. var $SMALL;
  514. var $BIG;
  515. var $toupper;
  516. var $tolower;
  517. var $capitalize;
  518. var $dash_on;
  519. var $dotted_on;
  520. var $strike;
  521. var $CSS;
  522. var $textbuffer;
  523. var $currentfontstyle;
  524. var $currentfontfamily;
  525. var $currentfontsize;
  526. var $colorarray;
  527. var $bgcolorarray;
  528. var $internallink;
  529. var $enabledtags;
  530. var $lineheight;
  531. var $basepath;
  532. var $outlineparam;
  533. var $outline_on;
  534. var $specialcontent;
  535. var $selectoption;
  536. var $objectbuffer;
  537. // Table Rotation
  538. var $table_rotate;
  539. var $tbrot_maxw;
  540. var $tbrot_maxh;
  541. var $tablebuffer;
  542. var $tbrot_align;
  543. var $tbrot_Links;
  544. var $divbuffer; // Buffer used when keeping DIV on one page
  545. var $keep_block_together; // Keep a Block from page-break-inside: avoid
  546. var $ktLinks; // Keep-together Block links array
  547. var $ktBlock; // Keep-together Block array
  548. var $ktForms;
  549. var $ktReference;
  550. var $ktBMoutlines;
  551. var $_kttoc;
  552. var $tbrot_y0;
  553. var $tbrot_x0;
  554. var $tbrot_w;
  555. var $tbrot_h;
  556. var $mb_enc;
  557. var $directionality;
  558. var $extgstates; // Used for alpha channel - Transparency (Watermark)
  559. var $mgl;
  560. var $mgt;
  561. var $mgr;
  562. var $mgb;
  563. var $tts;
  564. var $ttz;
  565. var $tta;
  566. var $headerDetails;
  567. var $footerDetails;
  568. // Best to alter the below variables using default stylesheet above
  569. var $page_break_after_avoid;
  570. var $margin_bottom_collapse;
  571. var $list_indent;
  572. var $list_align;
  573. var $list_margin_bottom;
  574. var $default_font_size; // in pts
  575. var $original_default_font_size; // used to save default sizes when using table default
  576. var $original_default_font;
  577. var $watermark_font;
  578. var $defaultAlign;
  579. // TABLE
  580. var $defaultTableAlign;
  581. var $tablethead;
  582. var $thead_font_weight;
  583. var $thead_font_style;
  584. var $thead_font_smCaps;
  585. var $thead_valign_default;
  586. var $thead_textalign_default;
  587. var $tabletfoot;
  588. var $tfoot_font_weight;
  589. var $tfoot_font_style;
  590. var $tfoot_font_smCaps;
  591. var $tfoot_valign_default;
  592. var $tfoot_textalign_default;
  593. var $trow_text_rotate;
  594. var $cellPaddingL;
  595. var $cellPaddingR;
  596. var $cellPaddingT;
  597. var $cellPaddingB;
  598. var $table_lineheight;
  599. var $table_border_attr_set;
  600. var $table_border_css_set;
  601. var $shrin_k; // factor with which to shrink tables - used internally - do not change
  602. var $shrink_this_table_to_fit; // 0 or false to disable; value (if set) gives maximum factor to reduce fontsize
  603. var $MarginCorrection; // corrects for OddEven Margins
  604. var $margin_footer;
  605. var $margin_header;
  606. var $tabletheadjustfinished;
  607. var $usingCoreFont;
  608. var $charspacing;
  609. //Private properties FROM FPDF
  610. var $DisplayPreferences;
  611. var $outlines;
  612. var $flowingBlockAttr;
  613. var $page; //current page number
  614. var $n; //current object number
  615. var $offsets; //array of object offsets
  616. var $buffer; //buffer holding in-memory PDF
  617. var $pages; //array containing pages
  618. var $state; //current document state
  619. var $compress; //compression flag
  620. var $DefOrientation; //default orientation
  621. var $CurOrientation; //current orientation
  622. var $OrientationChanges; //array indicating orientation changes
  623. var $k; //scale factor (number of points in user unit)
  624. var $fwPt;
  625. var $fhPt; //dimensions of page format in points
  626. var $fw;
  627. var $fh; //dimensions of page format in user unit
  628. var $wPt;
  629. var $hPt; //current dimensions of page in points
  630. var $w;
  631. var $h; //current dimensions of page in user unit
  632. var $lMargin; //left margin
  633. var $tMargin; //top margin
  634. var $rMargin; //right margin
  635. var $bMargin; //page break margin
  636. var $cMarginL; //cell margin Left
  637. var $cMarginR; //cell margin Right
  638. var $cMarginT; //cell margin Left
  639. var $cMarginB; //cell margin Right
  640. var $DeflMargin; //Default left margin
  641. var $DefrMargin; //Default right margin
  642. var $x;
  643. var $y; //current position in user unit for cell positioning
  644. var $lasth; //height of last cell printed
  645. var $LineWidth; //line width in user unit
  646. var $CoreFonts; //array of standard font names
  647. var $fonts; //array of used fonts
  648. var $FontFiles; //array of font files
  649. var $images; //array of used images
  650. var $PageLinks; //array of links in pages
  651. var $links; //array of internal links
  652. var $FontFamily; //current font family
  653. var $FontStyle; //current font style
  654. var $CurrentFont; //current font info
  655. var $FontSizePt; //current font size in points
  656. var $FontSize; //current font size in user unit
  657. var $DrawColor; //commands for drawing color
  658. var $FillColor; //commands for filling color
  659. var $TextColor; //commands for text color
  660. var $ColorFlag; //indicates whether fill and text colors are different
  661. var $autoPageBreak; //automatic page breaking
  662. var $PageBreakTrigger; //threshold used to trigger page breaks
  663. var $InFooter; //flag set when processing footer
  664. var $InHTMLFooter;
  665. var $processingFooter; //flag set when processing footer - added for columns
  666. var $processingHeader; //flag set when processing header - added for columns
  667. var $ZoomMode; //zoom display mode
  668. var $LayoutMode; //layout display mode
  669. var $title; //title
  670. var $subject; //subject
  671. var $author; //author
  672. var $keywords; //keywords
  673. var $creator; //creator
  674. var $aliasNbPg; //alias for total number of pages
  675. var $aliasNbPgGp; //alias for total number of pages in page group
  676. var $aliasNbPgHex;
  677. var $aliasNbPgGpHex;
  678. var $ispre;
  679. var $outerblocktags;
  680. var $innerblocktags;
  681. // **********************************
  682. // **********************************
  683. // **********************************
  684. // **********************************
  685. // **********************************
  686. // **********************************
  687. // **********************************
  688. // **********************************
  689. // **********************************
  690. function mPDF($mode='',$format='A4',$default_font_size=0,$default_font='',$mgl=15,$mgr=15,$mgt=16,$mgb=16,$mgh=9,$mgf=9, $orientation='P') {
  691. /*-- BACKGROUNDS --*/
  692. if (!class_exists('grad', false)) { include(_MPDF_PATH.'classes/grad.php'); }
  693. if (empty($this->grad)) { $this->grad = new grad($this); }
  694. /*-- END BACKGROUNDS --*/
  695. /*-- FORMS --*/
  696. if (!class_exists('form', false)) { include(_MPDF_PATH.'classes/form.php'); }
  697. if (empty($this->form)) { $this->form = new form($this); }
  698. /*-- END FORMS --*/
  699. $this->time0 = microtime(true);
  700. //Some checks
  701. $this->_dochecks();
  702. // Set up Aliases for backwards compatability
  703. $this->UnvalidatedText =& $this->watermarkText;
  704. $this->TopicIsUnvalidated =& $this->showWatermarkText;
  705. $this->AliasNbPg =& $this->aliasNbPg;
  706. $this->AliasNbPgGp =& $this->aliasNbPgGp;
  707. $this->BiDirectional =& $this->biDirectional;
  708. $this->Anchor2Bookmark =& $this->anchor2Bookmark;
  709. $this->KeepColumns =& $this->keepColumns;
  710. $this->useOddEven =& $this->mirrorMargins;
  711. $this->useSubstitutionsMB =& $this->useSubstitutions;
  712. $this->visibility='visible';
  713. //Initialization of properties
  714. $this->spotColors=array();
  715. $this->spotColorIDs = array();
  716. $this->tableBackgrounds = array();
  717. $this->kt_y00 = '';
  718. $this->kt_p00 = '';
  719. $this->iterationCounter = false;
  720. $this->BMPonly = array();
  721. $this->page=0;
  722. $this->n=2;
  723. $this->buffer='';
  724. $this->objectbuffer = array();
  725. $this->pages=array();
  726. $this->OrientationChanges=array();
  727. $this->state=0;
  728. $this->fonts=array();
  729. $this->FontFiles=array();
  730. $this->images=array();
  731. $this->links=array();
  732. $this->InFooter=false;
  733. $this->processingFooter=false;
  734. $this->processingHeader=false;
  735. $this->lasth=0;
  736. $this->FontFamily='';
  737. $this->FontStyle='';
  738. $this->FontSizePt=9;
  739. $this->U=false;
  740. // Small Caps
  741. $this->upperCase = array();
  742. $this->S = false;
  743. $this->smCapsScale = 1;
  744. $this->smCapsStretch = 100;
  745. $this->margBuffer = 0; // mPDF 5.4.04
  746. $this->inMeter = false; // mPDF 5.5.09
  747. $this->defTextColor = $this->TextColor = $this->SetTColor($this->ConvertColor(0),true);
  748. $this->defDrawColor = $this->DrawColor = $this->SetDColor($this->ConvertColor(0),true);
  749. $this->defFillColor = $this->FillColor = $this->SetFColor($this->ConvertColor(255),true);
  750. //SVG color names array
  751. //http://www.w3schools.com/css/css_colornames.asp
  752. $this->SVGcolors = array('antiquewhite'=>'#FAEBD7','aqua'=>'#00FFFF','aquamarine'=>'#7FFFD4','beige'=>'#F5F5DC','black'=>'#000000',
  753. 'blue'=>'#0000FF','brown'=>'#A52A2A','cadetblue'=>'#5F9EA0','chocolate'=>'#D2691E','cornflowerblue'=>'#6495ED','crimson'=>'#DC143C',
  754. 'darkblue'=>'#00008B','darkgoldenrod'=>'#B8860B','darkgreen'=>'#006400','darkmagenta'=>'#8B008B','darkorange'=>'#FF8C00',
  755. 'darkred'=>'#8B0000','darkseagreen'=>'#8FBC8F','darkslategray'=>'#2F4F4F','darkviolet'=>'#9400D3','deepskyblue'=>'#00BFFF',
  756. 'dodgerblue'=>'#1E90FF','firebrick'=>'#B22222','forestgreen'=>'#228B22','fuchsia'=>'#FF00FF','gainsboro'=>'#DCDCDC','gold'=>'#FFD700',
  757. 'gray'=>'#808080','green'=>'#008000','greenyellow'=>'#ADFF2F','hotpink'=>'#FF69B4','indigo'=>'#4B0082','khaki'=>'#F0E68C',
  758. 'lavenderblush'=>'#FFF0F5','lemonchiffon'=>'#FFFACD','lightcoral'=>'#F08080','lightgoldenrodyellow'=>'#FAFAD2','lightgreen'=>'#90EE90',
  759. 'lightsalmon'=>'#FFA07A','lightskyblue'=>'#87CEFA','lightslategray'=>'#778899','lightyellow'=>'#FFFFE0','lime'=>'#00FF00','limegreen'=>'#32CD32',
  760. 'magenta'=>'#FF00FF','maroon'=>'#800000','mediumaquamarine'=>'#66CDAA','mediumorchid'=>'#BA55D3','mediumseagreen'=>'#3CB371',
  761. 'mediumspringgreen'=>'#00FA9A','mediumvioletred'=>'#C71585','midnightblue'=>'#191970','mintcream'=>'#F5FFFA','moccasin'=>'#FFE4B5','navy'=>'#000080',
  762. 'olive'=>'#808000','orange'=>'#FFA500','orchid'=>'#DA70D6','palegreen'=>'#98FB98',
  763. 'palevioletred'=>'#D87093','peachpuff'=>'#FFDAB9','pink'=>'#FFC0CB','powderblue'=>'#B0E0E6','purple'=>'#800080',
  764. 'red'=>'#FF0000','royalblue'=>'#4169E1','salmon'=>'#FA8072','seagreen'=>'#2E8B57','sienna'=>'#A0522D','silver'=>'#C0C0C0','skyblue'=>'#87CEEB',
  765. 'slategray'=>'#708090','springgreen'=>'#00FF7F','steelblue'=>'#4682B4','tan'=>'#D2B48C','teal'=>'#008080','thistle'=>'#D8BFD8','turquoise'=>'#40E0D0',
  766. 'violetred'=>'#D02090','white'=>'#FFFFFF','yellow'=>'#FFFF00',
  767. 'aliceblue'=>'#f0f8ff', 'azure'=>'#f0ffff', 'bisque'=>'#ffe4c4', 'blanchedalmond'=>'#ffebcd', 'blueviolet'=>'#8a2be2', 'burlywood'=>'#deb887',
  768. 'chartreuse'=>'#7fff00', 'coral'=>'#ff7f50', 'cornsilk'=>'#fff8dc', 'cyan'=>'#00ffff', 'darkcyan'=>'#008b8b', 'darkgray'=>'#a9a9a9',
  769. 'darkgrey'=>'#a9a9a9', 'darkkhaki'=>'#bdb76b', 'darkolivegreen'=>'#556b2f', 'darkorchid'=>'#9932cc', 'darksalmon'=>'#e9967a',
  770. 'darkslateblue'=>'#483d8b', 'darkslategrey'=>'#2f4f4f', 'darkturquoise'=>'#00ced1', 'deeppink'=>'#ff1493', 'dimgray'=>'#696969',
  771. 'dimgrey'=>'#696969', 'floralwhite'=>'#fffaf0', 'ghostwhite'=>'#f8f8ff', 'goldenrod'=>'#daa520', 'grey'=>'#808080', 'honeydew'=>'#f0fff0',
  772. 'indianred'=>'#cd5c5c', 'ivory'=>'#fffff0', 'lavender'=>'#e6e6fa', 'lawngreen'=>'#7cfc00', 'lightblue'=>'#add8e6', 'lightcyan'=>'#e0ffff',
  773. 'lightgray'=>'#d3d3d3', 'lightgrey'=>'#d3d3d3', 'lightpink'=>'#ffb6c1', 'lightseagreen'=>'#20b2aa', 'lightslategrey'=>'#778899',
  774. 'lightsteelblue'=>'#b0c4de', 'linen'=>'#faf0e6', 'mediumblue'=>'#0000cd', 'mediumpurple'=>'#9370db', 'mediumslateblue'=>'#7b68ee',
  775. 'mediumturquoise'=>'#48d1cc', 'mistyrose'=>'#ffe4e1', 'navajowhite'=>'#ffdead', 'oldlace'=>'#fdf5e6', 'olivedrab'=>'#6b8e23', 'orangered'=>'#ff4500',
  776. 'palegoldenrod'=>'#eee8aa', 'paleturquoise'=>'#afeeee', 'papayawhip'=>'#ffefd5', 'peru'=>'#cd853f', 'plum'=>'#dda0dd', 'rosybrown'=>'#bc8f8f',
  777. 'saddlebrown'=>'#8b4513', 'sandybrown'=>'#f4a460', 'seashell'=>'#fff5ee', 'slateblue'=>'#6a5acd', 'slategrey'=>'#708090', 'snow'=>'#fffafa',
  778. 'tomato'=>'#ff6347', 'violet'=>'#ee82ee', 'wheat'=>'#f5deb3', 'whitesmoke'=>'#f5f5f5', 'yellowgreen'=>'#9acd32');
  779. $this->ColorFlag=false;
  780. $this->extgstates = array();
  781. $this->mb_enc='windows-1252';
  782. $this->directionality='ltr';
  783. $this->defaultAlign = 'L';
  784. $this->defaultTableAlign = 'L';
  785. $this->fixedPosBlockSave = array();
  786. $this->extraFontSubsets = 0;
  787. $this->SHYpatterns = array();
  788. $this->loadedSHYdictionary = false;
  789. $this->SHYdictionary = array();
  790. $this->SHYdictionaryWords = array();
  791. $this->blockContext = 1;
  792. $this->floatDivs = array();
  793. $this->DisplayPreferences='';
  794. $this->tablecascadeCSS = array();
  795. $this->listcascadeCSS = array();
  796. $this->patterns = array(); // Tiling patterns used for backgrounds
  797. $this->pageBackgrounds = array();
  798. $this->writingHTMLheader = false; // internal flag - used both for writing HTMLHeaders/Footers and FixedPos block
  799. $this->writingHTMLfooter = false; // internal flag - used both for writing HTMLHeaders/Footers and FixedPos block
  800. $this->gradients = array();
  801. $this->kwt_Reference = array();
  802. $this->kwt_BMoutlines = array();
  803. $this->kwt_toc = array();
  804. $this->tbrot_Reference = array();
  805. $this->tbrot_BMoutlines = array();
  806. $this->tbrot_toc = array();
  807. $this->col_Reference = array();
  808. $this->col_BMoutlines = array();
  809. $this->col_toc = array();
  810. $this->graphs = array();
  811. $this->pgsIns = array();
  812. $this->PDFAXwarnings = array();
  813. $this->inlineDisplayOff = false;
  814. $this->kerning = false;
  815. $this->lSpacingCSS = '';
  816. $this->wSpacingCSS = '';
  817. $this->fixedlSpacing = false;
  818. $this->minwSpacing = 0;
  819. $this->baselineC = 0.35; // Baseline for text
  820. $this->noImageFile = str_replace("\\","/",dirname(__FILE__)) . '/includes/no_image.jpg';
  821. $this->subPos = 0;
  822. $this->forceExactLineheight = false;
  823. $this->listOcc = 0;
  824. $this->normalLineheight = 1.3;
  825. // These are intended as configuration variables, and should be set in config.php - which will override these values;
  826. // set here as failsafe as will cause an error if not defined
  827. $this->incrementFPR1 = 10;
  828. $this->incrementFPR2 = 10;
  829. $this->incrementFPR3 = 10;
  830. $this->incrementFPR4 = 10;
  831. $this->fullImageHeight = false;
  832. $this->floatbuffer = array();
  833. $this->floatmargins = array();
  834. $this->autoFontGroups = 0;
  835. $this->formobjects=array(); // array of Form Objects for WMF
  836. $this->InlineProperties=array();
  837. $this->InlineAnnots=array();
  838. $this->ktAnnots=array();
  839. $this->tbrot_Annots=array();
  840. $this->kwt_Annots=array();
  841. $this->columnAnnots=array();
  842. $this->pageDim=array();
  843. $this->breakpoints = array(); // used in columnbuffer
  844. $this->tableLevel=0;
  845. $this->tbctr=array(); // counter for nested tables at each level
  846. $this->page_box = array();
  847. $this->show_marks = ''; // crop or cross marks
  848. $this->kwt = false;
  849. $this->kwt_height = 0;
  850. $this->kwt_y0 = 0;
  851. $this->kwt_x0 = 0;
  852. $this->kwt_buffer = array();
  853. $this->kwt_Links = array();
  854. $this->kwt_moved = false;
  855. $this->kwt_saved = false;
  856. $this->PageNumSubstitutions = array();
  857. $this->base_table_properties=array();
  858. $this->borderstyles = array('inset','groove','outset','ridge','dotted','dashed','solid','double');
  859. $this->tbrot_align = 'C';
  860. $this->pageheaders=array();
  861. $this->pagefooters=array();
  862. $this->pageHTMLheaders=array();
  863. $this->pageHTMLfooters=array();
  864. $this->HTMLheaderPageLinks = array();
  865. $this->HTMLheaderPageAnnots = array();
  866. $this->ktForms = array();
  867. $this->HTMLheaderPageForms = array();
  868. $this->columnForms = array();
  869. $this->tbrotForms = array();
  870. $this->useRC128encryption = false;
  871. $this->uniqid = '';
  872. $this->cascadeCSS = array();
  873. $this->bufferoutput = false;
  874. $this->encrypted=false; //whether document is protected
  875. $this->BMoutlines=array();
  876. $this->ColActive=0; //Flag indicating that columns are on (the index is being processed)
  877. $this->Reference=array(); //Array containing the references
  878. $this->CurrCol=0; //Current column number
  879. $this->ColL = array(0); // Array of Left pos of columns - absolute - needs Margin correction for Odd-Even
  880. $this->ColR = array(0); // Array of Right pos of columns - absolute pos - needs Margin correction for Odd-Even
  881. $this->ChangeColumn = 0;
  882. $this->columnbuffer = array();
  883. $this->ColDetails = array(); // Keeps track of some column details
  884. $this->columnLinks = array(); // Cross references PageLinks
  885. $this->substitute = array(); // Array of substitution strings e.g. <ttz>112</ttz>
  886. $this->entsearch = array(); // Array of HTML entities (>ASCII 127) to substitute
  887. $this->entsubstitute = array(); // Array of substitution decimal unicode for the Hi entities
  888. $this->lastoptionaltag = '';
  889. $this->charset_in = '';
  890. $this->blk = array();
  891. $this->blklvl = 0;
  892. $this->tts = false;
  893. $this->ttz = false;
  894. $this->tta = false;
  895. $this->ispre=false;
  896. $this->checkSIP = false;
  897. $this->checkSMP = false;
  898. $this->checkCJK = false;
  899. $this->tableCJK = false;
  900. $this->headerDetails=array();
  901. $this->footerDetails=array();
  902. $this->page_break_after_avoid = false;
  903. $this->margin_bottom_collapse = false;
  904. $this->tablethead = 0;
  905. $this->tabletfoot = 0;
  906. $this->table_border_attr_set = 0;
  907. $this->table_border_css_set = 0;
  908. $this->shrin_k = 1.0;
  909. $this->shrink_this_table_to_fit = 0;
  910. $this->MarginCorrection = 0;
  911. $this->tabletheadjustfinished = false;
  912. $this->usingCoreFont = false;
  913. $this->charspacing=0;
  914. $this->outlines=array();
  915. $this->autoPageBreak = true;
  916. require(_MPDF_PATH.'config.php'); // config data
  917. $this->_setPageSize($format, $orientation);
  918. $this->DefOrientation=$orientation;
  919. $this->margin_header=$mgh;
  920. $this->margin_footer=$mgf;
  921. $bmargin=$mgb;
  922. $this->DeflMargin = $mgl;
  923. $this->DefrMargin = $mgr;
  924. $this->orig_tMargin = $mgt;
  925. $this->orig_bMargin = $bmargin;
  926. $this->orig_lMargin = $this->DeflMargin;
  927. $this->orig_rMargin = $this->DefrMargin;
  928. $this->orig_hMargin = $this->margin_header;
  929. $this->orig_fMargin = $this->margin_footer;
  930. if ($this->setAutoTopMargin=='pad') { $mgt += $this->margin_header; }
  931. if ($this->setAutoBottomMargin=='pad') { $mgb += $this->margin_footer; }
  932. $this->SetMargins($this->DeflMargin,$this->DefrMargin,$mgt); // sets l r t margin
  933. //Automatic page break
  934. $this->SetAutoPageBreak($this->autoPageBreak,$bmargin); // sets $this->bMargin & PageBreakTrigger
  935. $this->pgwidth = $this->w - $this->lMargin - $this->rMargin;
  936. //Interior cell margin (1 mm) ? not used
  937. $this->cMarginL = 1;
  938. $this->cMarginR = 1;
  939. //Line width (0.2 mm)
  940. $this->LineWidth=.567/_MPDFK;
  941. //To make the function Footer() work - replaces {nb} with page number
  942. $this->AliasNbPages();
  943. $this->AliasNbPageGroups();
  944. $this->aliasNbPgHex = '{nbHEXmarker}';
  945. $this->aliasNbPgGpHex = '{nbpgHEXmarker}';
  946. //Enable all tags as default
  947. $this->DisableTags();
  948. //Full width display mode
  949. $this->SetDisplayMode(100); // fullwidth? 'fullpage'
  950. //Compression
  951. $this->SetCompression(true);
  952. //Set default display preferences
  953. $this->SetDisplayPreferences('');
  954. // Font data
  955. require(_MPDF_PATH.'config_fonts.php');
  956. // Available fonts
  957. $this->available_unifonts = array();
  958. foreach ($this->fontdata AS $f => $fs) {
  959. if (isset($fs['R']) && $fs['R']) { $this->available_unifonts[] = $f; }
  960. if (isset($fs['B']) && $fs['B']) { $this->available_unifonts[] = $f.'B'; }
  961. if (isset($fs['I']) && $fs['I']) { $this->available_unifonts[] = $f.'I'; }
  962. if (isset($fs['BI']) && $fs['BI']) { $this->available_unifonts[] = $f.'BI'; }
  963. }
  964. $this->default_available_fonts = $this->available_unifonts;
  965. $optcore = false;
  966. $onlyCoreFonts = false;
  967. if (preg_match('/([\-+])aCJK/i',$mode, $m)) {
  968. preg_replace('/([\-+])aCJK/i','',$mode);
  969. if ($m[1]=='+') { $this->useAdobeCJK = true; }
  970. else { $this->useAdobeCJK = false; }
  971. }
  972. if (strlen($mode)==1) {
  973. if ($mode=='s') { $this->percentSubset = 100; $mode = ''; }
  974. else if ($mode=='c') { $onlyCoreFonts = true; $mode = ''; }
  975. }
  976. else if (substr($mode,-2)=='-s') {
  977. $this->percentSubset = 100;
  978. $mode = substr($mode,0,strlen($mode)-2);
  979. }
  980. else if (substr($mode,-2)=='-c') {
  981. $onlyCoreFonts = true;
  982. $mode = substr($mode,0,strlen($mode)-2);
  983. }
  984. else if (substr($mode,-2)=='-x') {
  985. $optcore = true;
  986. $mode = substr($mode,0,strlen($mode)-2);
  987. }
  988. // Autodetect if mode is a language_country string (en-GB or en_GB or en)
  989. if ((strlen($mode) == 5 && $mode != 'UTF-8') || strlen($mode) == 2) {
  990. list ($coreSuitable,$mpdf_pdf_unifonts) = GetLangOpts($mode, $this->useAdobeCJK);
  991. if ($coreSuitable && $optcore) { $onlyCoreFonts = true; }
  992. if ($mpdf_pdf_unifonts) {
  993. $this->RestrictUnicodeFonts($mpdf_pdf_unifonts);
  994. $this->default_available_fonts = $mpdf_pdf_unifonts;
  995. }
  996. $this->currentLang = $mode;
  997. $this->default_lang = $mode;
  998. }
  999. $this->onlyCoreFonts = $onlyCoreFonts;
  1000. if ($this->onlyCoreFonts) {
  1001. $this->setMBencoding('windows-1252'); // sets $this->mb_enc
  1002. }
  1003. else {
  1004. $this->setMBencoding('UTF-8'); // sets $this->mb_enc
  1005. }
  1006. @mb_regex_encoding('UTF-8'); // required only for mb_ereg... and mb_split functions
  1007. // Adobe CJK fonts
  1008. $this->available_CJK_fonts = array('gb','big5','sjis','uhc','gbB','big5B','sjisB','uhcB','gbI','big5I','sjisI','uhcI',
  1009. 'gbBI','big5BI','sjisBI','uhcBI');
  1010. //Standard fonts
  1011. $this->CoreFonts=array('ccourier'=>'Courier','ccourierB'=>'Courier-Bold','ccourierI'=>'Courier-Oblique','ccourierBI'=>'Courier-BoldOblique',
  1012. 'chelvetica'=>'Helvetica','chelveticaB'=>'Helvetica-Bold','chelveticaI'=>'Helvetica-Oblique','chelveticaBI'=>'Helvetica-BoldOblique',
  1013. 'ctimes'=>'Times-Roman','ctimesB'=>'Times-Bold','ctimesI'=>'Times-Italic','ctimesBI'=>'Times-BoldItalic',
  1014. 'csymbol'=>'Symbol','czapfdingbats'=>'ZapfDingbats');
  1015. $this->fontlist=array("ctimes","ccourier","chelvetica","csymbol","czapfdingbats");
  1016. // Substitutions
  1017. $this->setHiEntitySubstitutions();
  1018. if ($this->onlyCoreFonts) {
  1019. $this->useSubstitutions = true;
  1020. $this->SetSubstitutions();
  1021. }
  1022. else { $this->useSubstitutions = false; }
  1023. /*-- HTML-CSS --*/
  1024. if (file_exists(_MPDF_PATH.'mpdf.css')) {
  1025. $css = file_get_contents(_MPDF_PATH.'mpdf.css');
  1026. $css2 = $this->ReadDefaultCSS($css);
  1027. $this->defaultCSS = $this->array_merge_recursive_unique($this->defaultCSS,$css2);
  1028. }
  1029. /*-- END HTML-CSS --*/
  1030. if ($default_font=='') {
  1031. if ($this->onlyCoreFonts) {
  1032. if (in_array(strtolower($this->defaultCSS['BODY']['FONT-FAMILY']),$this->mono_fonts)) { $default_font = 'ccourier'; }
  1033. else if (in_array(strtolower($this->defaultCSS['BODY']['FONT-FAMILY']),$this->sans_fonts)) { $default_font = 'chelvetica'; }
  1034. else { $default_font = 'ctimes'; }
  1035. }
  1036. else { $default_font = $this->defaultCSS['BODY']['FONT-FAMILY']; }
  1037. }
  1038. if (!$default_font_size) {
  1039. $mmsize = $this->ConvertSize($this->defaultCSS['BODY']['FONT-SIZE']);
  1040. $default_font_size = $mmsize*(_MPDFK);
  1041. }
  1042. if ($default_font) { $this->SetDefaultFont($default_font); }
  1043. if ($default_font_size) { $this->SetDefaultFontSize($default_font_size); }
  1044. $this->SetLineHeight(); // lineheight is in mm
  1045. $this->SetFColor($this->ConvertColor(255));
  1046. $this->HREF='';
  1047. $this->oldy=-1;
  1048. $this->B=0;
  1049. $this->U=false;
  1050. $this->S=false;
  1051. $this->I=0;
  1052. $this->listlvl=0;
  1053. $this->listnum=0;
  1054. $this->listtype='';
  1055. $this->listoccur=array();
  1056. $this->listlist=array();
  1057. $this->listitem=array();
  1058. $this->tdbegin=false;
  1059. $this->table=array();
  1060. $this->cell=array();
  1061. $this->col=-1;
  1062. $this->row=-1;
  1063. $this->cellBorderBuffer = array();
  1064. $this->divbegin=false;
  1065. $this->divalign='';
  1066. $this->divwidth=0;
  1067. $this->divheight=0;
  1068. $this->spanbgcolor=false;
  1069. $this->divrevert=false;
  1070. $this->spanborder=false;
  1071. $this->spanborddet=array();
  1072. $this->blockjustfinished=false;
  1073. $this->listjustfinished=false;
  1074. $this->ignorefollowingspaces = true; //in order to eliminate exceeding left-side spaces
  1075. $this->toupper=false;
  1076. $this->tolower=false;
  1077. $this->capitalize=false;
  1078. $this->dash_on=false;
  1079. $this->dotted_on=false;
  1080. $this->SUP=false;
  1081. $this->SUB=false;
  1082. $this->strike=false;
  1083. $this->textshadow='';
  1084. $this->currentfontfamily='';
  1085. $this->currentfontsize='';
  1086. $this->currentfontstyle='';
  1087. $this->colorarray=array();
  1088. $this->spanbgcolorarray=array();
  1089. $this->textbuffer=array();
  1090. $this->CSS=array();
  1091. $this->internallink=array();
  1092. $this->basepath = "";
  1093. $this->SetBasePath('');
  1094. $this->outlineparam = array();
  1095. $this->outline_on = false;
  1096. $this->specialcontent = '';
  1097. $this->selectoption = array();
  1098. /*-- IMPORTS --*/
  1099. $this->tpls = array();
  1100. $this->tpl = 0;
  1101. $this->tplprefix = "/TPL";
  1102. $this->res = array();
  1103. if ($this->enableImports) {
  1104. $this->SetImportUse();
  1105. }
  1106. /*-- END IMPORTS --*/
  1107. if ($this->progressBar) { $this->StartProgressBarOutput($this->progressBar) ; } // *PROGRESS-BAR*
  1108. }
  1109. function _setPageSize($format, &$orientation) {
  1110. //Page format
  1111. if(is_string($format))
  1112. {
  1113. if ($format=='') { $format = 'A4'; }
  1114. $pfo = 'P';
  1115. if(preg_match('/([0-9a-zA-Z]*)-L/i',$format,$m)) { // e.g. A4-L = A4 landscape
  1116. $format=$m[1];
  1117. $pfo='L';
  1118. }
  1119. $format = $this->_getPageFormat($format);
  1120. if (!$format) { $this->Error('Unknown page format: '.$format); }
  1121. else { $orientation = $pfo; }
  1122. $this->fwPt=$format[0];
  1123. $this->fhPt=$format[1];
  1124. }
  1125. else
  1126. {
  1127. if (!$format[0] || !$format[1]) { $this->Error('Invalid page format: '.$format[0].' '.$format[1]); }
  1128. $this->fwPt=$format[0]*_MPDFK;
  1129. $this->fhPt=$format[1]*_MPDFK;
  1130. }
  1131. $this->fw=$this->fwPt/_MPDFK;
  1132. $this->fh=$this->fhPt/_MPDFK;
  1133. //Page orientation
  1134. $orientation=strtolower($orientation);
  1135. if($orientation=='p' or $orientation=='portrait')
  1136. {
  1137. $orientation='P';
  1138. $this->wPt=$this->fwPt;
  1139. $this->hPt=$this->fhPt;
  1140. }
  1141. elseif($orientation=='l' or $orientation=='landscape')
  1142. {
  1143. $orientation='L';
  1144. $this->wPt=$this->fhPt;
  1145. $this->hPt=$this->fwPt;
  1146. }
  1147. else $this->Error('Incorrect orientation: '.$orientation);
  1148. $this->CurOrientation=$orientation;
  1149. $this->w=$this->wPt/_MPDFK;
  1150. $this->h=$this->hPt/_MPDFK;
  1151. }
  1152. function _getPageFormat($format) {
  1153. switch (strtoupper($format)) {
  1154. case '4A0': {$format = array(4767.87,6740.79); break;}
  1155. case '2A0': {$format = array(3370.39,4767.87); break;}
  1156. case 'A0': {$format = array(2383.94,3370.39); break;}
  1157. case 'A1': {$format = array(1683.78,2383.94); break;}
  1158. case 'A2': {$format = array(1190.55,1683.78); break;}
  1159. case 'A3': {$format = array(841.89,1190.55); break;}
  1160. case 'A4': default: {$format = array(595.28,841.89); break;}
  1161. case 'A5': {$format = array(419.53,595.28); break;}
  1162. case 'A6': {$format = array(297.64,419.53); break;}
  1163. case 'A7': {$format = array(209.76,297.64); break;}
  1164. case 'A8': {$format = array(147.40,209.76); break;}
  1165. case 'A9': {$format = array(104.88,147.40); break;}
  1166. case 'A10': {$format = array(73.70,104.88); break;}
  1167. case 'B0': {$format = array(2834.65,4008.19); break;}
  1168. case 'B1': {$format = array(2004.09,2834.65); break;}
  1169. case 'B2': {$format = array(1417.32,2004.09); break;}
  1170. case 'B3': {$format = array(1000.63,1417.32); break;}
  1171. case 'B4': {$format = array(708.66,1000.63); break;}
  1172. case 'B5': {$format = array(498.90,708.66); break;}
  1173. case 'B6': {$format = array(354.33,498.90); break;}
  1174. case 'B7': {$format = array(249.45,354.33); break;}
  1175. case 'B8': {$format = array(175.75,249.45); break;}
  1176. case 'B9': {$format = array(124.72,175.75); break;}
  1177. case 'B10': {$format = array(87.87,124.72); break;}
  1178. case 'C0': {$format = array(2599.37,3676.54); break;}
  1179. case 'C1': {$format = array(1836.85,2599.37); break;}
  1180. case 'C2': {$format = array(1298.27,1836.85); break;}
  1181. case 'C3': {$format = array(918.43,1298.27); break;}
  1182. case 'C4': {$format = array(649.13,918.43); break;}
  1183. case 'C5': {$format = array(459.21,649.13); break;}
  1184. case 'C6': {$format = array(323.15,459.21); break;}
  1185. case 'C7': {$format = array(229.61,323.15); break;}
  1186. case 'C8': {$format = array(161.57,229.61); break;}
  1187. case 'C9': {$format = array(113.39,161.57); break;}
  1188. case 'C10': {$format = array(79.37,113.39); break;}
  1189. case 'RA0': {$format = array(2437.80,3458.27); break;}
  1190. case 'RA1': {$format = array(1729.13,2437.80); break;}
  1191. case 'RA2': {$format = array(1218.90,1729.13); break;}
  1192. case 'RA3': {$format = array(864.57,1218.90); break;}
  1193. case 'RA4': {$format = array(609.45,864.57); break;}
  1194. case 'SRA0': {$format = array(2551.18,3628.35); break;}
  1195. case 'SRA1': {$format = array(1814.17,2551.18); break;}
  1196. case 'SRA2': {$format = array(1275.59,1814.17); break;}
  1197. case 'SRA3': {$format = array(907.09,1275.59); break;}
  1198. case 'SRA4': {$format = array(637.80,907.09); break;}
  1199. case 'LETTER': {$format = array(612.00,792.00); break;}
  1200. case 'LEGAL': {$format = array(612.00,1008.00); break;}
  1201. case 'LEDGER': {$format = array(279.00,432.00); break;}
  1202. case 'TABLOID': {$format = array(279.00,432.00); break;}
  1203. case 'EXECUTIVE': {$format = array(521.86,756.00); break;}
  1204. case 'FOLIO': {$format = array(612.00,936.00); break;}
  1205. case 'B': {$format=array(362.83,561.26 ); break;} // 'B' format paperback size 128x198mm
  1206. case 'A': {$format=array(314.65,504.57 ); break;} // 'A' format paperback size 111x178mm
  1207. case 'DEMY': {$format=array(382.68,612.28 ); break;} // 'Demy' format paperback size 135x216mm
  1208. case 'ROYAL': {$format=array(433.70,663.30 ); break;} // 'Royal' format paperback size 153x234mm
  1209. default: $format = false;
  1210. }
  1211. return $format;
  1212. }
  1213. /*-- PROGRESS-BAR --*/
  1214. function StartProgressBarOutput($mode=1) {
  1215. // must be relative path, or URI (not a file system path)
  1216. if (!defined('_MPDF_URI')) {
  1217. $this->progressBar = false;
  1218. if ($this->debug) { $this->Error("You need to define _MPDF_URI to use the progress bar!"); }
  1219. else return false;
  1220. }
  1221. $this->progressBar = $mode;
  1222. if ($this->progbar_altHTML) {
  1223. echo $this->progbar_altHTML;
  1224. }
  1225. else {
  1226. echo '<html>
  1227. <head>
  1228. <title>mPDF File Progress</title>
  1229. <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  1230. <link rel="stylesheet" type="text/css" href="'._MPDF_URI.'progbar.css" />
  1231. </head>
  1232. <body>
  1233. <div class="main">
  1234. <div class="heading">'.$this->progbar_heading.'</div>
  1235. <div class="demo">
  1236. ';
  1237. if ($this->progressBar==2) { echo ' <table width="100%"><tr><td style="width: 50%;">
  1238. <span class="barheading">Writing HTML code</span> <br/>
  1239. <div class="progressBar">
  1240. <div id="element1" class="innerBar">&nbsp;</div>
  1241. </div>
  1242. <span class="code" id="box1"></span>
  1243. </td><td style="width: 50%;">
  1244. <span class="barheading">Autosizing elements</span> <br/>
  1245. <div class="progressBar">
  1246. <div id="element4" class="innerBar">&nbsp;</div>
  1247. </div>
  1248. <span class="code" id="box4"></span>
  1249. <br/><br/>
  1250. <span class="barheading">Writing Tables</span> <br/>
  1251. <div class="progressBar">
  1252. <div id="element7" class="innerBar">&nbsp;</div>
  1253. </div>
  1254. <span class="code" id="box7"></span>
  1255. </td></tr>
  1256. <tr><td><br /><br /></td><td></td></tr>
  1257. <tr><td style="width: 50%;">
  1258. '; }
  1259. echo ' <span class="barheading">Writing PDF file</span> <br/>
  1260. <div class="progressBar">
  1261. <div id="element2" class="innerBar">&nbsp;</div>
  1262. </div>
  1263. <span class="code" id="box2"></span>
  1264. ';
  1265. if ($this->progressBar==2) { echo '
  1266. </td><td style="width: 50%;">
  1267. <span class="barheading">Memory usage</span> <br/>
  1268. <div class="progressBar">
  1269. <div id="element5" class="innerBar">&nbsp;</div>
  1270. </div>
  1271. <span id="box5">0</span> '.ini_get("memory_limit").'<br />
  1272. <br/><br/>
  1273. <span class="barheading">Memory usage (peak)</span> <br/>
  1274. <div class="progressBar">
  1275. <div id="element6" class="innerBar">&nbsp;</div>
  1276. </div>
  1277. <span id="box6">0</span> '.ini_get("memory_limit").'<br />
  1278. </td></tr>
  1279. </table>
  1280. '; }
  1281. echo ' <br/><br/>
  1282. <span id="box3"></span>
  1283. </div>
  1284. ';
  1285. }
  1286. ob_flush();
  1287. flush();
  1288. }
  1289. function UpdateProgressBar($el,$val,$txt='') {
  1290. // $val should be a string - 5 = actual value, +15 = increment
  1291. if ($this->progressBar<2) {
  1292. if ($el>3) { return; }
  1293. else if ($el ==1) { $el = 2; }
  1294. }
  1295. echo '<script type="text/javascript">';
  1296. if ($val) { echo ' document.getElementById(\'element'.$el.'\').style.width=\''.$val.'%\'; '; }
  1297. if ($txt) { echo ' document.getElementById(\'box'.$el.'\').innerHTML=\''.$txt.'\'; '; }
  1298. if ($this->progressBar==2) {
  1299. $m = round(memory_get_usage(true)/1048576);
  1300. $m2 = round(memory_get_peak_usage(true)/1048576);
  1301. $mem = $m * 100 / (ini_get("memory_limit")+0);
  1302. $mem2 = $m2 * 100 / (ini_get("memory_limit")+0);
  1303. echo ' document.getElementById(\'element5\').style.width=\''.$mem.'%\'; ';
  1304. echo ' document.getElementById(\'element6\').style.width=\''.$mem2.'%\'; ';
  1305. echo ' document.getElementById(\'box5\').innerHTML=\''.$m.'MB / \'; ';
  1306. echo ' document.getElementById(\'box6\').innerHTML=\''.$m2.'MB / \'; ';
  1307. }
  1308. echo '</script>'."\n";
  1309. ob_flush();
  1310. flush();
  1311. }
  1312. /*-- END PROGRESS-BAR --*/
  1313. function RestrictUnicodeFonts($res) {
  1314. // $res = array of (Unicode) fonts to restrict to: e.g. norasi|norasiB - language specific
  1315. if (count($res)) { // Leave full list of available fonts if passed blank array
  1316. $this->available_unifonts = $res;
  1317. }
  1318. else { $this->available_unifonts = $this->default_available_fonts; }
  1319. if (count($this->available_unifonts) == 0) { $this->available_unifonts[] = $this->default_available_fonts[0]; }
  1320. $this->available_unifonts = array_values($this->available_unifonts);
  1321. }
  1322. function setMBencoding($enc) {
  1323. if ($this->mb_enc != $enc) {
  1324. $this->mb_enc = $enc;
  1325. mb_internal_encoding($this->mb_enc);
  1326. }
  1327. }
  1328. function SetMargins($left,$right,$top) {
  1329. //Set left, top and right margins
  1330. $this->lMargin=$left;
  1331. $this->rMargin=$right;
  1332. $this->tMargin=$top;
  1333. }
  1334. function ResetMargins() {
  1335. //ReSet left, top margins
  1336. if (($this->forcePortraitHeaders || $this->forcePortraitMargins) && $this->DefOrientation=='P' && $this->CurOrientation=='L') {
  1337. if (($this->mirrorMargins) && (($this->page)%2==0)) { // EVEN
  1338. $this->tMargin=$this->orig_rMargin;
  1339. $this->bMargin=$this->orig_lMargin;
  1340. }
  1341. else { // ODD // OR NOT MIRRORING MARGINS/FOOTERS
  1342. $this->tMargin=$this->orig_lMargin;
  1343. $this->bMargin=$this->orig_rMargin;
  1344. }
  1345. $this->lMargin=$this->DeflMargin;
  1346. $this->rMargin=$this->DefrMargin;
  1347. $this->MarginCorrection = 0;
  1348. $this->PageBreakTrigger=$this->h-$this->bMargin;
  1349. }
  1350. else if (($this->mirrorMargins) && (($this->page)%2==0)) { // EVEN
  1351. $this->lMargin=$this->DefrMargin;
  1352. $this->rMargin=$this->DeflMargin;
  1353. $this->MarginCorrection = $this->DefrMargin-$this->DeflMargin;
  1354. }
  1355. else { // ODD // OR NOT MIRRORING MARGINS/FOOTERS
  1356. $this->lMargin=$this->DeflMargin;
  1357. $this->rMargin=$this->DefrMargin;
  1358. if ($this->mirrorMargins) { $this->MarginCorrection = $this->DeflMargin-$this->DefrMargin; }
  1359. }
  1360. $this->x=$this->lMargin;
  1361. }
  1362. function SetLeftMargin($margin) {
  1363. //Set left margin
  1364. $this->lMargin=$margin;
  1365. if($this->page>0 and $this->x<$margin) $this->x=$margin;
  1366. }
  1367. function SetTopMargin($margin) {
  1368. //Set top margin
  1369. $this->tMargin=$margin;
  1370. }
  1371. function SetRightMargin($margin) {
  1372. //Set right margin
  1373. $this->rMargin=$margin;
  1374. }
  1375. function SetAutoPageBreak($auto,$margin=0) {
  1376. //Set auto page break mode and triggering margin
  1377. $this->autoPageBreak=$auto;
  1378. $this->bMargin=$margin;
  1379. $this->PageBreakTrigger=$this->h-$margin;
  1380. }
  1381. function SetDisplayMode($zoom,$layout='continuous') {
  1382. //Set display mode in viewer
  1383. if($zoom=='fullpage' or $zoom=='fullwidth' or $zoom=='real' or $zoom=='default' or !is_string($zoom))
  1384. $this->ZoomMode=$zoom;
  1385. else
  1386. $this->Error('Incorrect zoom display mode: '.$zoom);
  1387. if($layout=='single' or $layout=='continuous' or $layout=='two' or $layout=='twoleft' or $layout=='tworight' or $layout=='default')
  1388. $this->LayoutMode=$layout;
  1389. else
  1390. $this->Error('Incorrect layout display mode: '.$layout);
  1391. }
  1392. function SetCompression($compress) {
  1393. //Set page compression
  1394. if(function_exists('gzcompress')) $this->compress=$compress;
  1395. else $this->compress=false;
  1396. }
  1397. function SetTitle($title) {
  1398. //Title of document // Arrives as UTF-8
  1399. $this->title = $title;
  1400. }
  1401. function SetSubject($subject) {
  1402. //Subject of document
  1403. $this->subject= $subject;
  1404. }
  1405. function SetAuthor($author) {
  1406. //Author of document
  1407. $this->author= $author;
  1408. }
  1409. function SetKeywords($keywords) {
  1410. //Keywords of document
  1411. $this->keywords= $keywords;
  1412. }
  1413. function SetCreator($creator) {
  1414. //Creator of document
  1415. $this->creator= $creator;
  1416. }
  1417. function SetAnchor2Bookmark($x) {
  1418. $this->anchor2Bookmark = $x;
  1419. }
  1420. function AliasNbPages($alias='{nb}') {
  1421. //Define an alias for total number of pages
  1422. $this->aliasNbPg=$alias;
  1423. }
  1424. function AliasNbPageGroups($alias='{nbpg}') {
  1425. //Define an alias for total number of pages in a group
  1426. $this->aliasNbPgGp=$alias;
  1427. }
  1428. function SetAlpha($alpha, $bm='Normal', $return=false, $mode='B') {
  1429. // alpha: real value from 0 (transparent) to 1 (opaque)
  1430. // bm: blend mode, one of the following:
  1431. // Normal, Multiply, Screen, Overlay, Darken, Lighten, ColorDodge, ColorBurn,
  1432. // HardLight, SoftLight, Difference, Exclusion, Hue, Saturation, Color, Luminosity
  1433. // set alpha for stroking (CA) and non-stroking (ca) operations
  1434. // mode determines F (fill) S (stroke) B (both)
  1435. if (($this->PDFA || $this->PDFX) && $alpha!=1) {
  1436. if (($this->PDFA && !$this->PDFAauto) || ($this->PDFX && !$this->PDFXauto)) { $this->PDFAXwarnings[] = "Image opacity must be 100% (Opacity changed to 100%)"; }
  1437. $alpha = 1;
  1438. }
  1439. $a = array('BM'=>'/'.$bm);
  1440. if ($mode=='F' || $mode='B') $a['ca'] = $alpha;
  1441. if ($mode=='S' || $mode='B') $a['CA'] = $alpha;
  1442. $gs = $this->AddExtGState($a);
  1443. if ($return) { return sprintf('/GS%d gs', $gs); }
  1444. else { $this->_out(sprintf('/GS%d gs', $gs)); }
  1445. }
  1446. function AddExtGState($parms) {
  1447. $n = count($this->extgstates);
  1448. // check if graphics state already exists
  1449. for ($i=1; $i<=$n; $i++) {
  1450. if (count($this->extgstates[$i]['parms']) == count($parms)) {
  1451. $same = true;
  1452. foreach($this->extgstates[$i]['parms'] AS $k=>$v) {
  1453. if (!isset($parms[$k]) || $parms[$k] != $v) { $same = false; break; }
  1454. }
  1455. if ($same) { return $i; }
  1456. }
  1457. }
  1458. $n++;
  1459. $this->extgstates[$n]['parms'] = $parms;
  1460. return $n;
  1461. }
  1462. function SetVisibility($v) {
  1463. if (($this->PDFA || $this->PDFX) && $this->visibility!='visible') { $this->PDFAXwarnings[] = "Cannot set visibility to anything other than full when using PDFA or PDFX"; return ''; }
  1464. else if (!$this->PDFA && !$this->PDFX)
  1465. $this->pdf_version='1.5';
  1466. if($this->visibility!='visible') {
  1467. $this->_out('EMC');
  1468. $this->hasOC = true;
  1469. }
  1470. if($v=='printonly')
  1471. $this->_out('/OC /OC1 BDC');
  1472. elseif($v=='screenonly')
  1473. $this->_out('/OC /OC2 BDC');
  1474. elseif($v=='hidden')
  1475. $this->_out('/OC /OC3 BDC');
  1476. elseif($v!='visible')
  1477. $this->Error('Incorrect visibility: '.$v);
  1478. $this->visibility=$v;
  1479. }
  1480. function Error($msg) {
  1481. //Fatal error
  1482. header('Content-Type: text/html; charset=utf-8');
  1483. die('<B>mPDF error: </B>'.$msg);
  1484. }
  1485. function Open() {
  1486. //Begin document
  1487. if($this->state==0) $this->_begindoc();
  1488. }
  1489. function Close() {
  1490. if ($this->progressBar) { $this->UpdateProgressBar(2,'2','Closing last page'); } // *PROGRESS-BAR*
  1491. //Terminate document
  1492. if($this->state==3) return;
  1493. if($this->page==0) $this->AddPage($this->CurOrientation);
  1494. if (count($this->cellBorderBuffer)) { $this->printcellbuffer(); } // *TABLES*
  1495. if ($this->tablebuffer) { $this->printtablebuffer(); } // *TABLES*
  1496. /*-- COLUMNS --*/
  1497. if ($this->ColActive) {
  1498. $this->SetColumns(0);
  1499. $this->ColActive = 0;
  1500. if (count($this->columnbuffer)) { $this->printcolumnbuffer(); }
  1501. }
  1502. /*-- END COLUMNS --*/
  1503. if (count($this->divbuffer)) { $this->printdivbuffer(); }
  1504. // BODY Backgrounds
  1505. $s = '';
  1506. $s .= $this->PrintBodyBackgrounds();
  1507. $s .= $this->PrintPageBackgrounds();
  1508. $this->pages[$this->page] = preg_replace('/(___BACKGROUND___PATTERNS'.date('jY').')/', "\n".$s."\n".'\\1', $this->pages[$this->page]);
  1509. $this->pageBackgrounds = array();
  1510. if($this->visibility!='visible')
  1511. $this->SetVisibility('visible');
  1512. if (!$this->tocontents || !$this->tocontents->TOCmark) { //Page footer
  1513. $this->InFooter=true;
  1514. $this->Footer();
  1515. $this->InFooter=false;
  1516. }
  1517. if ($this->tocontents && ($this->tocontents->TOCmark || count($this->tocontents->m_TOC))) { $this->tocontents->insertTOC(); } // *TOC*
  1518. //Close page
  1519. $this->_endpage();
  1520. //Close document
  1521. $this->_enddoc();
  1522. }
  1523. /*-- BACKGROUNDS --*/
  1524. function _resizeBackgroundImage($imw, $imh, $cw, $ch, $resize=0, $repx, $repy) {
  1525. $cw = $cw*_MPDFK;
  1526. $ch = $ch*_MPDFK;
  1527. if (!$resize) { return array($imw, $imh, $repx, $repy); }
  1528. if ($resize==1 && $imw > $cw) {
  1529. $h = $imh * $cw/$imw;
  1530. $repx = false;
  1531. return array($cw, $h, $repx, $repy);
  1532. }
  1533. else if ($resize==2 && $imh > $ch) {
  1534. $w = $imw * $ch/$imh;
  1535. $repy = false;
  1536. return array($w, $ch, $repx, $repy);
  1537. }
  1538. else if ($resize==3) {
  1539. $w = $imw;
  1540. $h = $imh;
  1541. $saverepx = $repx;
  1542. if ($w > $cw) {
  1543. $h = $h * $cw/$w;
  1544. $w = $cw;
  1545. $repx = false;
  1546. }
  1547. if ($h > $ch) {
  1548. $w = $w * $ch/$h;
  1549. $h = $ch;
  1550. $repy = false;
  1551. $repx = $saverepx;
  1552. }
  1553. return array($w, $h, $repx, $repy);
  1554. }
  1555. else if ($resize==4) {
  1556. $h = $imh * $cw/$imw;
  1557. $repx = false;
  1558. return array($cw, $h, $repx, $repy);
  1559. }
  1560. else if ($resize==5) {
  1561. $w = $imw * $ch/$imh;
  1562. $repy = false;
  1563. return array($w, $ch, $repx, $repy);
  1564. }
  1565. else if ($resize==6) {
  1566. $repx = false;
  1567. $repy = false;
  1568. return array($cw, $ch, $repx, $repy);
  1569. }
  1570. return array($imw, $imh, $repx, $repy);
  1571. }
  1572. function SetBackground(&$properties, &$maxwidth) {
  1573. if (preg_match('/(-moz-)*(repeating-)*(linear|radial)-gradient/',$properties['BACKGROUND-IMAGE'])) {
  1574. return array('gradient'=>$properties['BACKGROUND-IMAGE']);
  1575. }
  1576. else {
  1577. $file = $properties['BACKGROUND-IMAGE'];
  1578. $sizesarray = $this->Image($file,0,0,0,0,'','',false, false, false, false, true);
  1579. if (isset($sizesarray['IMAGE_ID'])) {
  1580. $image_id = $sizesarray['IMAGE_ID'];
  1581. $orig_w = $sizesarray['WIDTH']*_MPDFK; // in user units i.e. mm
  1582. $orig_h = $sizesarray['HEIGHT']*_MPDFK; // (using $this->img_dpi)
  1583. if (isset($properties['BACKGROUND-IMAGE-RESOLUTION'])) {
  1584. if (preg_match('/from-image/i', $properties['BACKGROUND-IMAGE-RESOLUTION']) && isset($sizesarray['set-dpi']) && $sizesarray['set-dpi']>0) {
  1585. $orig_w *= $this->img_dpi / $sizesarray['set-dpi'];
  1586. $orig_h *= $this->img_dpi / $sizesarray['set-dpi'];
  1587. }
  1588. else if (preg_match('/(\d+)dpi/i', $properties['BACKGROUND-IMAGE-RESOLUTION'], $m)) {
  1589. $dpi = $m[1];
  1590. if ($dpi > 0) {
  1591. $orig_w *= $this->img_dpi / $dpi;
  1592. $orig_h *= $this->img_dpi / $dpi;
  1593. }
  1594. }
  1595. }
  1596. $x_repeat = true;
  1597. $y_repeat = true;
  1598. if (isset($properties['BACKGROUND-REPEAT'])) {
  1599. if ($properties['BACKGROUND-REPEAT']=='no-repeat' || $properties['BACKGROUND-REPEAT']=='repeat-x') { $y_repeat = false; }
  1600. if ($properties['BACKGROUND-REPEAT']=='no-repeat' || $properties['BACKGROUND-REPEAT']=='repeat-y') { $x_repeat = false; }
  1601. }
  1602. $x_pos = 0;
  1603. $y_pos = 0;
  1604. if (isset($properties['BACKGROUND-POSITION'])) {
  1605. $ppos = preg_split('/\s+/',$properties['BACKGROUND-POSITION']);
  1606. $x_pos = $ppos[0];
  1607. $y_pos = $ppos[1];
  1608. if (!stristr($x_pos ,'%') ) { $x_pos = $this->ConvertSize($x_pos ,$maxwidth,$this->FontSize); }
  1609. if (!stristr($y_pos ,'%') ) { $y_pos = $this->ConvertSize($y_pos ,$maxwidth,$this->FontSize); }
  1610. }
  1611. if (isset($properties['BACKGROUND-IMAGE-RESIZE'])) { $resize = $properties['BACKGROUND-IMAGE-RESIZE']; }
  1612. else { $resize = 0; }
  1613. if (isset($properties['BACKGROUND-IMAGE-OPACITY'])) { $opacity = $properties['BACKGROUND-IMAGE-OPACITY']; }
  1614. else { $opacity = 1; }
  1615. return array('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']);
  1616. }
  1617. }
  1618. return false;
  1619. }
  1620. /*-- END BACKGROUNDS --*/
  1621. function PrintBodyBackgrounds() {
  1622. $s = '';
  1623. $clx = 0;
  1624. $cly = 0;
  1625. $clw = $this->w;
  1626. $clh = $this->h;
  1627. // If using bleed and trim margins in paged media
  1628. if ($this->pageDim[$this->page]['outer_width_LR'] || $this->pageDim[$this->page]['outer_width_TB']) {
  1629. $clx = $this->pageDim[$this->page]['outer_width_LR'] - $this->pageDim[$this->page]['bleedMargin'];
  1630. $cly = $this->pageDim[$this->page]['outer_width_TB'] - $this->pageDim[$this->page]['bleedMargin'];
  1631. $clw = $this->w - 2*$clx;
  1632. $clh = $this->h - 2*$cly;
  1633. }
  1634. if ($this->bodyBackgroundColor) {
  1635. $s .= 'q ' .$this->SetFColor($this->bodyBackgroundColor, true)."\n";
  1636. if ($this->bodyBackgroundColor{0}==5) { // RGBa
  1637. $s .= $this->SetAlpha(ord($this->bodyBackgroundColor{4})/100, 'Normal', true, 'F')."\n";
  1638. }
  1639. else if ($this->bodyBackgroundColor{0}==6) { // CMYKa
  1640. $s .= $this->SetAlpha(ord($this->bodyBackgroundColor{5})/100, 'Normal', true, 'F')."\n";
  1641. }
  1642. $s .= sprintf('%.3F %.3F %.3F %.3F re f Q', ($clx*_MPDFK), ($cly*_MPDFK),$clw*_MPDFK,$clh*_MPDFK)."\n";
  1643. }
  1644. /*-- BACKGROUNDS --*/
  1645. if ($this->bodyBackgroundGradient) {
  1646. $g = $this->grad->parseBackgroundGradient($this->bodyBackgroundGradient);
  1647. if ($g) {
  1648. $s .= $this->grad->Gradient($clx, $cly, $clw, $clh, (isset($g['gradtype']) ? $g['gradtype'] : null), $g['stops'], $g['colorspace'], $g['coords'], $g['extend'], true);
  1649. }
  1650. }
  1651. if ($this->bodyBackgroundImage) {
  1652. if ( $this->bodyBackgroundImage['gradient'] && preg_match('/(-moz-)*(repeating-)*(linear|radial)-gradient/', $this->bodyBackgroundImage['gradient'])) {
  1653. $g = $this->grad->parseMozGradient( $this->bodyBackgroundImage['gradient']);
  1654. if ($g) {
  1655. $s .= $this->grad->Gradient($clx, $cly, $clw, $clh, $g['type'], $g['stops'], $g['colorspace'], $g['coords'], $g['extend'], true);
  1656. }
  1657. }
  1658. else if ($this->bodyBackgroundImage['image_id']) { // Background pattern
  1659. $n = count($this->patterns)+1;
  1660. // If using resize, uses TrimBox (not including the bleed)
  1661. 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']);
  1662. $this->patterns[$n] = array('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']);
  1663. if (($this->bodyBackgroundImage['opacity']>0 || $this->bodyBackgroundImage['opacity']==='0') && $this->bodyBackgroundImage['opacity']<1) { $opac = $this->SetAlpha($this->bodyBackgroundImage['opacity'],'Normal',true); }
  1664. else { $opac = ''; }
  1665. $s .= sprintf('q /Pattern cs /P%d scn %s %.3F %.3F %.3F %.3F re f Q', $n, $opac, ($clx*_MPDFK), ($cly*_MPDFK),$clw*_MPDFK, $clh*_MPDFK) ."\n";
  1666. }
  1667. }
  1668. /*-- END BACKGROUNDS --*/
  1669. return $s;
  1670. }
  1671. function PrintPageBackgrounds($adjustmenty=0) {
  1672. $s = '';
  1673. ksort($this->pageBackgrounds);
  1674. foreach($this->pageBackgrounds AS $bl=>$pbs) {
  1675. foreach ($pbs AS $pb) {
  1676. if ((!isset($pb['image_id']) && !isset($pb['gradient'])) || isset($pb['shadowonly'])) { // Background colour or boxshadow
  1677. if($pb['visibility']!='visible') {
  1678. if($pb['visibility']=='printonly')
  1679. $s .= '/OC /OC1 BDC'."\n";
  1680. else if($pb['visibility']=='screenonly')
  1681. $s .= '/OC /OC2 BDC'."\n";
  1682. else if($pb['visibility']=='hidden')
  1683. $s .= '/OC /OC3 BDC'."\n";
  1684. }
  1685. // Box shadow
  1686. if (isset($pb['shadow']) && $pb['shadow']) { $s .= $pb['shadow']."\n"; }
  1687. if (isset($pb['clippath']) && $pb['clippath']) { $s .= $pb['clippath']."\n"; }
  1688. $s .= 'q '.$this->SetFColor($pb['col'], true)."\n";
  1689. if ($pb['col']{0}==5) { // RGBa
  1690. $s .= $this->SetAlpha(ord($pb['col']{4})/100, 'Normal', true, 'F')."\n";
  1691. }
  1692. else if ($pb['col']{0}==6) { // CMYKa
  1693. $s .= $this->SetAlpha(ord($pb['col']{5})/100, 'Normal', true, 'F')."\n";
  1694. }
  1695. $s .= sprintf('%.3F %.3F %.3F %.3F re f Q',$pb['x']*_MPDFK,($this->h-$pb['y'])*_MPDFK,$pb['w']*_MPDFK,-$pb['h']*_MPDFK)."\n";
  1696. if (isset($pb['clippath']) && $pb['clippath']) { $s .= 'Q'."\n"; }
  1697. if($pb['visibility']!='visible')
  1698. $s .= 'EMC'."\n";
  1699. }
  1700. }
  1701. /*-- BACKGROUNDS --*/
  1702. foreach ($pbs AS $pb) {
  1703. if($pb['visibility']!='visible') {
  1704. if($pb['visibility']=='printonly')
  1705. $s .= '/OC /OC1 BDC'."\n";
  1706. else if($pb['visibility']=='screenonly')
  1707. $s .= '/OC /OC2 BDC'."\n";
  1708. else if($pb['visibility']=='hidden')
  1709. $s .= '/OC /OC3 BDC'."\n";
  1710. }
  1711. if (isset($pb['gradient']) && $pb['gradient']) {
  1712. if (isset($pb['clippath']) && $pb['clippath']) { $s .= $pb['clippath']."\n"; }
  1713. $s .= $this->grad->Gradient($pb['x'], $pb['y'], $pb['w'], $pb['h'], $pb['gradtype'], $pb['stops'], $pb['colorspace'], $pb['coords'], $pb['extend'], true);
  1714. if (isset($pb['clippath']) && $pb['clippath']) { $s .= 'Q'."\n"; }
  1715. }
  1716. else if (isset($pb['image_id']) && $pb['image_id']) { // Background pattern
  1717. $pb['y'] -= $adjustmenty;
  1718. $pb['h'] += $adjustmenty;
  1719. $n = count($this->patterns)+1;
  1720. 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']);
  1721. $this->patterns[$n] = array('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']);
  1722. $x = $pb['x']*_MPDFK;
  1723. $y = ($this->h - $pb['y'])*_MPDFK;
  1724. $w = $pb['w']*_MPDFK;
  1725. $h = -$pb['h']*_MPDFK;
  1726. if (isset($pb['clippath']) && $pb['clippath']) { $s .= $pb['clippath']."\n"; }
  1727. if ($this->writingHTMLfooter || $this->writingHTMLheader) {
  1728. $iw = $pb['orig_w']/_MPDFK;
  1729. $ih = $pb['orig_h']/_MPDFK;
  1730. $w = $pb['w'];
  1731. $h = $pb['h'];
  1732. $x0 = $pb['x'];
  1733. $y0 = $pb['y'];
  1734. // Number to repeat
  1735. if ($pb['x_repeat']) { $nx = ceil($w/$iw); }
  1736. else { $nx = 1; }
  1737. if ($pb['y_repeat']) { $ny = ceil($h/$ih); }
  1738. else { $ny = 1; }
  1739. $x_pos = $pb['x_pos'];
  1740. if (stristr($x_pos ,'%') ) {
  1741. $x_pos += 0;
  1742. $x_pos /= 100;
  1743. $x_pos = ($w * $x_pos) - ($iw * $x_pos);
  1744. }
  1745. $y_pos = $pb['y_pos'];
  1746. if (stristr($y_pos ,'%') ) {
  1747. $y_pos += 0;
  1748. $y_pos /= 100;
  1749. $y_pos = ($h * $y_pos) - ($ih * $y_pos);
  1750. }
  1751. if ($nx>1) {
  1752. while($x_pos>0) { $x_pos -= $iw; }
  1753. }
  1754. if ($ny>1) {
  1755. while($y_pos>0) { $y_pos -= $ih; }
  1756. }
  1757. for($xi=0;$xi<$nx;$xi++) {
  1758. for($yi=0;$yi<$ny;$yi++) {
  1759. $x = $x0 + $x_pos + ($iw*$xi);
  1760. $y = $y0 + $y_pos + ($ih*$yi);
  1761. if ($pb['opacity']>0 && $pb['opacity']<1) { $opac = $this->SetAlpha($pb['opacity'],'Normal',true); }
  1762. else { $opac = ''; }
  1763. $s .= sprintf("q %s %.3F 0 0 %.3F %.3F %.3F cm /I%d Do Q", $opac,$iw*_MPDFK,$ih*_MPDFK,$x*_MPDFK,($this->h-($y+$ih))*_MPDFK,$pb['image_id']) ."\n";
  1764. }
  1765. }
  1766. }
  1767. else {
  1768. if (($pb['opacity']>0 || $pb['opacity']==='0') && $pb['opacity']<1) { $opac = $this->SetAlpha($pb['opacity'],'Normal',true); }
  1769. else { $opac = ''; }
  1770. $s .= sprintf('q /Pattern cs /P%d scn %s %.3F %.3F %.3F %.3F re f Q', $n, $opac, $x, $y, $w, $h) ."\n";
  1771. }
  1772. if (isset($pb['clippath']) && $pb['clippath']) { $s .= 'Q'."\n"; }
  1773. }
  1774. if($pb['visibility']!='visible')
  1775. $s .= 'EMC'."\n";
  1776. }
  1777. /*-- END BACKGROUNDS --*/
  1778. }
  1779. return $s;
  1780. }
  1781. function PrintTableBackgrounds($adjustmenty=0) {
  1782. $s = '';
  1783. /*-- BACKGROUNDS --*/
  1784. ksort($this->tableBackgrounds);
  1785. foreach($this->tableBackgrounds AS $bl=>$pbs) {
  1786. foreach ($pbs AS $pb) {
  1787. if ((!isset($pb['gradient']) || !$pb['gradient']) && (!isset($pb['image_id']) || !$pb['image_id'])) {
  1788. $s .= 'q '.$this->SetFColor($pb['col'], true)."\n";
  1789. if ($pb['col']{0}==5) { // RGBa
  1790. $s .= $this->SetAlpha(ord($pb['col']{4})/100, 'Normal', true, 'F')."\n";
  1791. }
  1792. else if ($pb['col']{0}==6) { // CMYKa
  1793. $s .= $this->SetAlpha(ord($pb['col']{5})/100, 'Normal', true, 'F')."\n";
  1794. }
  1795. $s .= sprintf('%.3F %.3F %.3F %.3F re %s Q',$pb['x']*_MPDFK,($this->h-$pb['y'])*_MPDFK,$pb['w']*_MPDFK,-$pb['h']*_MPDFK,'f')."\n";
  1796. }
  1797. if (isset($pb['gradient']) && $pb['gradient']) {
  1798. if (isset($pb['clippath']) && $pb['clippath']) { $s .= $pb['clippath']."\n"; }
  1799. $s .= $this->grad->Gradient($pb['x'], $pb['y'], $pb['w'], $pb['h'], $pb['gradtype'], $pb['stops'], $pb['colorspace'], $pb['coords'], $pb['extend'], true);
  1800. if (isset($pb['clippath']) && $pb['clippath']) { $s .= 'Q'."\n"; }
  1801. }
  1802. if (isset($pb['image_id']) && $pb['image_id']) { // Background pattern
  1803. $pb['y'] -= $adjustmenty;
  1804. $pb['h'] += $adjustmenty;
  1805. $n = count($this->patterns)+1;
  1806. 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']);
  1807. $this->patterns[$n] = array('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']);
  1808. $x = $pb['x']*_MPDFK;
  1809. $y = ($this->h - $pb['y'])*_MPDFK;
  1810. $w = $pb['w']*_MPDFK;
  1811. $h = -$pb['h']*_MPDFK;
  1812. if (isset($pb['clippath']) && $pb['clippath']) { $s .= $pb['clippath']."\n"; }
  1813. if ($pb['opacity']>0 && $pb['opacity']<1) { $opac = $this->SetAlpha($pb['opacity'],'Normal',true); }
  1814. else { $opac = ''; }
  1815. $s .= sprintf('q /Pattern cs /P%d scn %s %.3F %.3F %.3F %.3F re f Q', $n, $opac, $x, $y, $w, $h) ."\n";
  1816. if (isset($pb['clippath']) && $pb['clippath']) { $s .= 'Q'."\n"; }
  1817. }
  1818. }
  1819. }
  1820. /*-- END BACKGROUNDS --*/
  1821. return $s;
  1822. }
  1823. // Depracated - can use AddPage for all
  1824. function AddPages($orientation='',$condition='', $resetpagenum='', $pagenumstyle='', $suppress='',$mgl='',$mgr='',$mgt='',$mgb='',$mgh='',$mgf='',$ohname='',$ehname='',$ofname='',$efname='',$ohvalue=0,$ehvalue=0,$ofvalue=0,$efvalue=0,$pagesel='',$newformat='')
  1825. {
  1826. $this->AddPage($orientation,$condition,$resetpagenum, $pagenumstyle, $suppress,$mgl,$mgr,$mgt,$mgb,$mgh,$mgf, $ohname, $ehname, $ofname, $efname, $ohvalue, $ehvalue, $ofvalue, $efvalue,$pagesel,$newformat);
  1827. }
  1828. function AddPageByArray($a) {
  1829. if (!is_array($a)) { $a = array(); }
  1830. $orientation = (isset($a['orientation']) ? $a['orientation'] : '');
  1831. $condition = (isset($a['condition']) ? $a['condition'] : (isset($a['type']) ? $a['type'] : ''));
  1832. $resetpagenum = (isset($a['resetpagenum']) ? $a['resetpagenum'] : '');
  1833. $pagenumstyle = (isset($a['pagenumstyle']) ? $a['pagenumstyle'] : '');
  1834. $suppress = (isset($a['suppress']) ? $a['suppress'] : '');
  1835. $mgl = (isset($a['mgl']) ? $a['mgl'] : (isset($a['margin-left']) ? $a['margin-left'] : ''));
  1836. $mgr = (isset($a['mgr']) ? $a['mgr'] : (isset($a['margin-right']) ? $a['margin-right'] : ''));
  1837. $mgt = (isset($a['mgt']) ? $a['mgt'] : (isset($a['margin-top']) ? $a['margin-top'] : ''));
  1838. $mgb = (isset($a['mgb']) ? $a['mgb'] : (isset($a['margin-bottom']) ? $a['margin-bottom'] : ''));
  1839. $mgh = (isset($a['mgh']) ? $a['mgh'] : (isset($a['margin-header']) ? $a['margin-header'] : ''));
  1840. $mgf = (isset($a['mgf']) ? $a['mgf'] : (isset($a['margin-footer']) ? $a['margin-footer'] : ''));
  1841. $ohname = (isset($a['ohname']) ? $a['ohname'] : (isset($a['odd-header-name']) ? $a['odd-header-name'] : ''));
  1842. $ehname = (isset($a['ehname']) ? $a['ehname'] : (isset($a['even-header-name']) ? $a['even-header-name'] : ''));
  1843. $ofname = (isset($a['ofname']) ? $a['ofname'] : (isset($a['odd-footer-name']) ? $a['odd-footer-name'] : ''));
  1844. $efname = (isset($a['efname']) ? $a['efname'] : (isset($a['even-footer-name']) ? $a['even-footer-name'] : ''));
  1845. $ohvalue = (isset($a['ohvalue']) ? $a['ohvalue'] : (isset($a['odd-header-value']) ? $a['odd-header-value'] : 0));
  1846. $ehvalue = (isset($a['ehvalue']) ? $a['ehvalue'] : (isset($a['even-header-value']) ? $a['even-header-value'] : 0));
  1847. $ofvalue = (isset($a['ofvalue']) ? $a['ofvalue'] : (isset($a['odd-footer-value']) ? $a['odd-footer-value'] : 0));
  1848. $efvalue = (isset($a['efvalue']) ? $a['efvalue'] : (isset($a['even-footer-value']) ? $a['even-footer-value'] : 0));
  1849. $pagesel = (isset($a['pagesel']) ? $a['pagesel'] : (isset($a['pageselector']) ? $a['pageselector'] : ''));
  1850. $newformat = (isset($a['newformat']) ? $a['newformat'] : (isset($a['sheet-size']) ? $a['sheet-size'] : ''));
  1851. $this->AddPage($orientation,$condition,$resetpagenum, $pagenumstyle, $suppress,$mgl,$mgr,$mgt,$mgb,$mgh,$mgf, $ohname, $ehname, $ofname, $efname, $ohvalue, $ehvalue, $ofvalue, $efvalue,$pagesel,$newformat);
  1852. }
  1853. function AddPage($orientation='',$condition='', $resetpagenum='', $pagenumstyle='', $suppress='',$mgl='',$mgr='',$mgt='',$mgb='',$mgh='',$mgf='',$ohname='',$ehname='',$ofname='',$efname='',$ohvalue=0,$ehvalue=0,$ofvalue=0,$efvalue=0,$pagesel='',$newformat='')
  1854. {
  1855. /*-- CSS-FLOAT --*/
  1856. // Float DIV
  1857. // Cannot do with columns on, or if any change in page orientation/margins etc.
  1858. // If next page already exists - i.e background /headers and footers already written
  1859. if ($this->state > 0 && $this->page < count($this->pages)) {
  1860. $bak_cml = $this->cMarginL;
  1861. $bak_cmr = $this->cMarginR;
  1862. $bak_dw = $this->divwidth;
  1863. // Paint Div Border if necessary
  1864. if ($this->blklvl > 0) {
  1865. $save_tr = $this->table_rotate; // *TABLES*
  1866. $this->table_rotate = 0; // *TABLES*
  1867. if ($this->y == $this->blk[$this->blklvl]['y0']) { $this->blk[$this->blklvl]['startpage']++; }
  1868. if (($this->y > $this->blk[$this->blklvl]['y0']) || $this->flowingBlockAttr['is_table'] ) { $toplvl = $this->blklvl; }
  1869. else { $toplvl = $this->blklvl-1; }
  1870. $sy = $this->y;
  1871. for ($bl=1;$bl<=$toplvl;$bl++) {
  1872. $this->PaintDivBB('pagebottom',0,$bl);
  1873. }
  1874. $this->y = $sy;
  1875. $this->table_rotate = $save_tr; // *TABLES*
  1876. }
  1877. $s = $this->PrintPageBackgrounds();
  1878. // Writes after the marker so not overwritten later by page background etc.
  1879. $this->pages[$this->page] = preg_replace('/(___BACKGROUND___PATTERNS'.date('jY').')/', '\\1'."\n".$s."\n", $this->pages[$this->page]);
  1880. $this->pageBackgrounds = array();
  1881. $family=$this->FontFamily;
  1882. $style=$this->FontStyle.($this->U ? 'U' : '').($this->S ? 'S' : '');
  1883. $size=$this->FontSizePt;
  1884. $lw=$this->LineWidth;
  1885. $dc=$this->DrawColor;
  1886. $fc=$this->FillColor;
  1887. $tc=$this->TextColor;
  1888. $cf=$this->ColorFlag;
  1889. $this->printfloatbuffer();
  1890. //Move to next page
  1891. $this->page++;
  1892. $this->ResetMargins();
  1893. $this->SetAutoPageBreak($this->autoPageBreak,$this->bMargin);
  1894. $this->x=$this->lMargin;
  1895. $this->y=$this->tMargin;
  1896. $this->FontFamily='';
  1897. $this->_out('2 J');
  1898. $this->LineWidth=$lw;
  1899. $this->_out(sprintf('%.3F w',$lw*_MPDFK));
  1900. if($family) $this->SetFont($family,$style,$size,true,true);
  1901. $this->DrawColor=$dc;
  1902. if($dc!=$this->defDrawColor) $this->_out($dc);
  1903. $this->FillColor=$fc;
  1904. if($fc!=$this->defFillColor) $this->_out($fc);
  1905. $this->TextColor=$tc;
  1906. $this->ColorFlag=$cf;
  1907. for($bl=1;$bl<=$this->blklvl;$bl++) {
  1908. $this->blk[$bl]['y0'] = $this->y;
  1909. // Don't correct more than once for background DIV containing a Float
  1910. if (!isset($this->blk[$bl]['marginCorrected'][$this->page])) { $this->blk[$bl]['x0'] += $this->MarginCorrection; }
  1911. $this->blk[$bl]['marginCorrected'][$this->page] = true;
  1912. }
  1913. $this->cMarginL = $bak_cml;
  1914. $this->cMarginR = $bak_cmr;
  1915. $this->divwidth = $bak_dw;
  1916. return '';
  1917. }
  1918. /*-- END CSS-FLOAT --*/
  1919. //Start a new page
  1920. if($this->state==0) $this->Open();
  1921. $bak_cml = $this->cMarginL;
  1922. $bak_cmr = $this->cMarginR;
  1923. $bak_dw = $this->divwidth;
  1924. $bak_lh = $this->lineheight;
  1925. $orientation = substr(strtoupper($orientation),0,1);
  1926. $condition = strtoupper($condition);
  1927. if ($condition == 'NEXT-EVEN') { // always adds at least one new page to create an Even page
  1928. if (!$this->mirrorMargins) { $condition = ''; }
  1929. else {
  1930. if ($pagesel) { $pbch = $pagesel; $pagesel = ''; } // *CSS-PAGE*
  1931. else { $pbch = false; } // *CSS-PAGE*
  1932. $this->AddPage($this->CurOrientation,'O');
  1933. if ($pbch ) { $pagesel = $pbch; } // *CSS-PAGE*
  1934. $condition = '';
  1935. }
  1936. }
  1937. if ($condition == 'NEXT-ODD') { // always adds at least one new page to create an Odd page
  1938. if (!$this->mirrorMargins) { $condition = ''; }
  1939. else {
  1940. if ($pagesel) { $pbch = $pagesel; $pagesel = ''; } // *CSS-PAGE*
  1941. else { $pbch = false; } // *CSS-PAGE*
  1942. $this->AddPage($this->CurOrientation,'E');
  1943. if ($pbch ) { $pagesel = $pbch; } // *CSS-PAGE*
  1944. $condition = '';
  1945. }
  1946. }
  1947. if ($condition == 'E') { // only adds new page if needed to create an Even page
  1948. if (!$this->mirrorMargins || ($this->page)%2==0) { return false; }
  1949. }
  1950. if ($condition == 'O') { // only adds new page if needed to create an Odd page
  1951. if (!$this->mirrorMargins || ($this->page)%2==1) { return false; }
  1952. }
  1953. if ($resetpagenum || $pagenumstyle || $suppress) {
  1954. $this->PageNumSubstitutions[] = array('from'=>($this->page+1), 'reset'=> $resetpagenum, 'type'=>$pagenumstyle, 'suppress'=>$suppress);
  1955. }
  1956. $save_tr = $this->table_rotate; // *TABLES*
  1957. $this->table_rotate = 0; // *TABLES*
  1958. $save_kwt = $this->kwt;
  1959. $this->kwt = 0;
  1960. // Paint Div Border if necessary
  1961. //PAINTS BACKGROUND COLOUR OR BORDERS for DIV - DISABLED FOR COLUMNS (cf. AcceptPageBreak) AT PRESENT in ->PaintDivBB
  1962. if (!$this->ColActive && $this->blklvl > 0) {
  1963. if (isset($this->blk[$this->blklvl]['y0']) && $this->y == $this->blk[$this->blklvl]['y0']) {
  1964. if (isset($this->blk[$this->blklvl]['startpage'])) { $this->blk[$this->blklvl]['startpage']++; }
  1965. else { $this->blk[$this->blklvl]['startpage'] = 1; }
  1966. }
  1967. if ((isset($this->blk[$this->blklvl]['y0']) && $this->y > $this->blk[$this->blklvl]['y0']) || $this->flowingBlockAttr['is_table'] ) { $toplvl = $this->blklvl; }
  1968. else { $toplvl = $this->blklvl-1; }
  1969. $sy = $this->y;
  1970. for ($bl=1;$bl<=$toplvl;$bl++) {
  1971. $this->PaintDivBB('pagebottom',0,$bl);
  1972. }
  1973. $this->y = $sy;
  1974. // RESET block y0 and x0 - see below
  1975. }
  1976. // BODY Backgrounds
  1977. if ($this->page > 0) {
  1978. $s = '';
  1979. $s .= $this->PrintBodyBackgrounds();
  1980. $s .= $this->PrintPageBackgrounds();
  1981. $this->pages[$this->page] = preg_replace('/(___BACKGROUND___PATTERNS'.date('jY').')/', "\n".$s."\n".'\\1', $this->pages[$this->page]);
  1982. $this->pageBackgrounds = array();
  1983. }
  1984. $save_kt = $this->keep_block_together;
  1985. $this->keep_block_together = 0;
  1986. $save_cols = false;
  1987. /*-- COLUMNS --*/
  1988. if ($this->ColActive) {
  1989. $save_cols = true;
  1990. $save_nbcol = $this->NbCol; // other values of gap and vAlign will not change by setting Columns off
  1991. $this->SetColumns(0);
  1992. }
  1993. /*-- END COLUMNS --*/
  1994. $save_vis = $this->visibility;
  1995. if($this->visibility!='visible')
  1996. $this->SetVisibility('visible');
  1997. $family=$this->FontFamily;
  1998. $style=$this->FontStyle.($this->U ? 'U' : '').($this->S ? 'S' : '');
  1999. $size=$this->FontSizePt;
  2000. $this->ColumnAdjust = true; // enables column height adjustment for the page
  2001. $lw=$this->LineWidth;
  2002. $dc=$this->DrawColor;
  2003. $fc=$this->FillColor;
  2004. $tc=$this->TextColor;
  2005. $cf=$this->ColorFlag;
  2006. if($this->page>0)
  2007. {
  2008. //Page footer
  2009. $this->InFooter=true;
  2010. $this->Reset();
  2011. $this->pageoutput[$this->page] = array();
  2012. $this->Footer();
  2013. //Close page
  2014. $this->_endpage();
  2015. }
  2016. //Start new page
  2017. $this->_beginpage($orientation,$mgl,$mgr,$mgt,$mgb,$mgh,$mgf,$ohname,$ehname,$ofname,$efname,$ohvalue,$ehvalue,$ofvalue,$efvalue,$pagesel,$newformat);
  2018. if ($this->docTemplate) {
  2019. $pagecount = $this->SetSourceFile($this->docTemplate);
  2020. if (($this->page - $this->docTemplateStart) > $pagecount) {
  2021. if ($this->docTemplateContinue) {
  2022. $tplIdx = $this->ImportPage($pagecount);
  2023. $this->UseTemplate($tplIdx);
  2024. }
  2025. }
  2026. else {
  2027. $tplIdx = $this->ImportPage(($this->page - $this->docTemplateStart));
  2028. $this->UseTemplate($tplIdx);
  2029. }
  2030. }
  2031. if ($this->pageTemplate) {
  2032. $this->UseTemplate($this->pageTemplate);
  2033. }
  2034. // Tiling Patterns
  2035. $this->_out('___PAGE___START'.date('jY'));
  2036. $this->_out('___BACKGROUND___PATTERNS'.date('jY'));
  2037. $this->_out('___HEADER___MARKER'.date('jY'));
  2038. $this->pageBackgrounds = array();
  2039. //Set line cap style to square
  2040. $this->SetLineCap(2);
  2041. //Set line width
  2042. $this->LineWidth=$lw;
  2043. $this->_out(sprintf('%.3F w',$lw*_MPDFK));
  2044. //Set font
  2045. if($family) $this->SetFont($family,$style,$size,true,true); // forces write
  2046. //Set colors
  2047. $this->DrawColor=$dc;
  2048. if($dc!=$this->defDrawColor) $this->_out($dc);
  2049. $this->FillColor=$fc;
  2050. if($fc!=$this->defFillColor) $this->_out($fc);
  2051. $this->TextColor=$tc;
  2052. $this->ColorFlag=$cf;
  2053. //Page header
  2054. $this->Header();
  2055. //Restore line width
  2056. if($this->LineWidth!=$lw)
  2057. {
  2058. $this->LineWidth=$lw;
  2059. $this->_out(sprintf('%.3F w',$lw*_MPDFK));
  2060. }
  2061. //Restore font
  2062. if($family) $this->SetFont($family,$style,$size,true,true); // forces write
  2063. //Restore colors
  2064. if($this->DrawColor!=$dc)
  2065. {
  2066. $this->DrawColor=$dc;
  2067. $this->_out($dc);
  2068. }
  2069. if($this->FillColor!=$fc)
  2070. {
  2071. $this->FillColor=$fc;
  2072. $this->_out($fc);
  2073. }
  2074. $this->TextColor=$tc;
  2075. $this->ColorFlag=$cf;
  2076. $this->InFooter=false;
  2077. if($save_vis!='visible')
  2078. $this->SetVisibility($save_vis);
  2079. /*-- COLUMNS --*/
  2080. if ($save_cols) {
  2081. // Restore columns
  2082. $this->SetColumns($save_nbcol,$this->colvAlign,$this->ColGap);
  2083. }
  2084. if ($this->ColActive) { $this->SetCol(0); }
  2085. /*-- END COLUMNS --*/
  2086. //RESET BLOCK BORDER TOP
  2087. if (!$this->ColActive) {
  2088. for($bl=1;$bl<=$this->blklvl;$bl++) {
  2089. $this->blk[$bl]['y0'] = $this->y;
  2090. if (isset($this->blk[$bl]['x0'])) { $this->blk[$bl]['x0'] += $this->MarginCorrection; }
  2091. else { $this->blk[$bl]['x0'] = $this->MarginCorrection; }
  2092. // Added mPDF 3.0 Float DIV
  2093. $this->blk[$bl]['marginCorrected'][$this->page] = true;
  2094. }
  2095. }
  2096. $this->table_rotate = $save_tr; // *TABLES*
  2097. $this->kwt = $save_kwt;
  2098. $this->keep_block_together = $save_kt ;
  2099. $this->cMarginL = $bak_cml;
  2100. $this->cMarginR = $bak_cmr;
  2101. $this->divwidth = $bak_dw;
  2102. $this->lineheight = $bak_lh;
  2103. }
  2104. function PageNo() {
  2105. //Get current page number
  2106. return $this->page;
  2107. }
  2108. function AddSpotColorsFromFile($file) {
  2109. $colors = @file($file) or die("Cannot load spot colors file - ".$file);
  2110. foreach($colors AS $sc) {
  2111. list($name, $c, $m, $y, $k) = preg_split("/\t/",$sc);
  2112. $c = intval($c);
  2113. $m = intval($m);
  2114. $y = intval($y);
  2115. $k = intval($k);
  2116. $this->AddSpotColor($name, $c, $m, $y, $k);
  2117. }
  2118. }
  2119. function AddSpotColor($name, $c, $m, $y, $k) {
  2120. $name = strtoupper(trim($name));
  2121. if(!isset($this->spotColors[$name])) {
  2122. $i=count($this->spotColors)+1;
  2123. $this->spotColors[$name]=array('i'=>$i,'c'=>$c,'m'=>$m,'y'=>$y,'k'=>$k);
  2124. $this->spotColorIDs[$i]=$name;
  2125. }
  2126. }
  2127. function SetColor($col, $type='') {
  2128. $out = '';
  2129. if ($col{0}==3 || $col{0}==5) { // RGB / RGBa
  2130. $out = sprintf('%.3F %.3F %.3F rg',ord($col{1})/255,ord($col{2})/255,ord($col{3})/255);
  2131. }
  2132. else if ($col{0}==1) { // GRAYSCALE
  2133. $out = sprintf('%.3F g',ord($col{1})/255);
  2134. }
  2135. else if ($col{0}==2) { // SPOT COLOR
  2136. $out = sprintf('/CS%d cs %.3F scn',ord($col{1}),ord($col{2})/100);
  2137. }
  2138. else if ($col{0}==4 || $col{0}==6) { // CMYK / CMYKa
  2139. $out = sprintf('%.3F %.3F %.3F %.3F k', ord($col{1})/100, ord($col{2})/100, ord($col{3})/100, ord($col{4})/100);
  2140. }
  2141. if ($type=='Draw') { $out = strtoupper($out); } // e.g. rg => RG
  2142. else if ($type=='CodeOnly') { $out = preg_replace('/\s(rg|g|k)/','',$out); }
  2143. return $out;
  2144. }
  2145. function SetDColor($col, $return=false) {
  2146. $out = $this->SetColor($col, 'Draw');
  2147. if ($return) { return $out; }
  2148. if ($out=='') { return ''; }
  2149. $this->DrawColor = $out;
  2150. if($this->page>0 && ((isset($this->pageoutput[$this->page]['DrawColor']) && $this->pageoutput[$this->page]['DrawColor'] != $this->DrawColor) || !isset($this->pageoutput[$this->page]['DrawColor']) || $this->keep_block_together)) { $this->_out($this->DrawColor); }
  2151. $this->pageoutput[$this->page]['DrawColor'] = $this->DrawColor;
  2152. }
  2153. function SetFColor($col, $return=false) {
  2154. $out = $this->SetColor($col, 'Fill');
  2155. if ($return) { return $out; }
  2156. if ($out=='') { return ''; }
  2157. $this->FillColor = $out;
  2158. $this->ColorFlag = ($out != $this->TextColor);
  2159. if($this->page>0 && ((isset($this->pageoutput[$this->page]['FillColor']) && $this->pageoutput[$this->page]['FillColor'] != $this->FillColor) || !isset($this->pageoutput[$this->page]['FillColor']) || $this->keep_block_together)) { $this->_out($this->FillColor); }
  2160. $this->pageoutput[$this->page]['FillColor'] = $this->FillColor;
  2161. }
  2162. function SetTColor($col, $return=false) {
  2163. $out = $this->SetColor($col, 'Text');
  2164. if ($return) { return $out; }
  2165. if ($out=='') { return ''; }
  2166. $this->TextColor = $out;
  2167. $this->ColorFlag = ($this->FillColor != $out);
  2168. }
  2169. function SetDrawColor($r,$g=-1,$b=-1,$col4=-1, $return=false) {
  2170. //Set color for all stroking operations
  2171. $col = array();
  2172. if(($r==0 and $g==0 and $b==0 && $col4 == -1) or $g==-1) { $col = $this->ConvertColor($r); }
  2173. else if ($col4 == -1) { $col = $this->ConvertColor('rgb('.$r.','.$g.','.$b.')'); }
  2174. else { $col = $this->ConvertColor('cmyk('.$r.','.$g.','.$b.','.$col4.')'); }
  2175. $out = $this->SetDColor($col, $return);
  2176. return $out;
  2177. }
  2178. function SetFillColor($r,$g=-1,$b=-1,$col4=-1, $return=false) {
  2179. //Set color for all filling operations
  2180. $col = array();
  2181. if(($r==0 and $g==0 and $b==0 && $col4 == -1) or $g==-1) { $col = $this->ConvertColor($r); }
  2182. else if ($col4 == -1) { $col = $this->ConvertColor('rgb('.$r.','.$g.','.$b.')'); }
  2183. else { $col = $this->ConvertColor('cmyk('.$r.','.$g.','.$b.','.$col4.')'); }
  2184. $out = $this->SetFColor($col, $return);
  2185. return $out;
  2186. }
  2187. function SetTextColor($r,$g=-1,$b=-1,$col4=-1, $return=false) {
  2188. //Set color for text
  2189. $col = array();
  2190. if(($r==0 and $g==0 and $b==0 && $col4 == -1) or $g==-1) { $col = $this->ConvertColor($r); }
  2191. else if ($col4 == -1) { $col = $this->ConvertColor('rgb('.$r.','.$g.','.$b.')'); }
  2192. else { $col = $this->ConvertColor('cmyk('.$r.','.$g.','.$b.','.$col4.')'); }
  2193. $out = $this->SetTColor($col, $return);
  2194. return $out;
  2195. }
  2196. function _getCharWidth(&$cw, $u, $isdef=true) {
  2197. if ($u==0) { $w = false; }
  2198. else { $w = (ord($cw[$u*2]) << 8) + ord($cw[$u*2+1]); }
  2199. if ($w == 65535) { return 0; }
  2200. else if ($w) { return $w; }
  2201. else if ($isdef) { return false; }
  2202. else { return 0; }
  2203. }
  2204. function _charDefined(&$cw, $u) {
  2205. if ($u==0) { return false; }
  2206. $w = (ord($cw[$u*2]) << 8) + ord($cw[$u*2+1]);
  2207. if ($w) { return true; }
  2208. else { return false; }
  2209. }
  2210. function GetCharWidthCore($c) {
  2211. //Get width of a single character in the current Core font
  2212. $c = (string)$c;
  2213. $w = 0;
  2214. // Soft Hyphens chr(173)
  2215. if ($c == chr(173) && $this->FontFamily!='csymbol' && $this->FontFamily!='czapfdingbats') {
  2216. return 0;
  2217. }
  2218. else if ($this->S && isset($this->upperCase[ord($c)])) {
  2219. $charw = $this->CurrentFont['cw'][chr($this->upperCase[ord($c)])];
  2220. if ($charw!==false) {
  2221. $charw = $charw*$this->smCapsScale * $this->smCapsStretch/100;
  2222. $w+=$charw;
  2223. }
  2224. }
  2225. else if (isset($this->CurrentFont['cw'][$c])) {
  2226. $w += $this->CurrentFont['cw'][$c];
  2227. }
  2228. else if (isset($this->CurrentFont['cw'][ord($c)])) {
  2229. $w += $this->CurrentFont['cw'][ord($c)];
  2230. }
  2231. $w *= ($this->FontSize/ 1000);
  2232. if ($this->minwSpacing || $this->fixedlSpacing) {
  2233. if ($c==' ') $nb_spaces = 1;
  2234. else $nb_spaces = 0;
  2235. $w += $this->fixedlSpacing + ($nb_spaces * $this->minwSpacing);
  2236. }
  2237. return ($w);
  2238. }
  2239. function GetCharWidthNonCore($c, $addSubset=true) {
  2240. //Get width of a single character in the current Non-Core font
  2241. $c = (string)$c;
  2242. $w = 0;
  2243. $unicode = $this->UTF8StringToArray($c, $addSubset);
  2244. $char = $unicode[0];
  2245. /*-- CJK-FONTS --*/
  2246. if ($this->CurrentFont['type'] == 'Type0') { // CJK Adobe fonts
  2247. if ($char == 173) { return 0; } // Soft Hyphens
  2248. elseif (isset($this->CurrentFont['cw'][$char])) { $w+=$this->CurrentFont['cw'][$char]; }
  2249. elseif(isset($this->CurrentFont['MissingWidth'])) { $w += $this->CurrentFont['MissingWidth']; }
  2250. else { $w += 500; }
  2251. }
  2252. else {
  2253. /*-- END CJK-FONTS --*/
  2254. if ($char == 173) { return 0; } // Soft Hyphens
  2255. else if ($this->S && isset($this->upperCase[$char])) {
  2256. $charw = $this->_getCharWidth($this->CurrentFont['cw'],$this->upperCase[$char]);
  2257. if ($charw!==false) {
  2258. $charw = $charw*$this->smCapsScale * $this->smCapsStretch/100;
  2259. $w+=$charw;
  2260. }
  2261. elseif(isset($this->CurrentFont['desc']['MissingWidth'])) { $w += $this->CurrentFont['desc']['MissingWidth']; }
  2262. elseif(isset($this->CurrentFont['MissingWidth'])) { $w += $this->CurrentFont['MissingWidth']; }
  2263. else { $w += 500; }
  2264. }
  2265. else {
  2266. $charw = $this->_getCharWidth($this->CurrentFont['cw'],$char);
  2267. if ($charw!==false) { $w+=$charw; }
  2268. elseif(isset($this->CurrentFont['desc']['MissingWidth'])) { $w += $this->CurrentFont['desc']['MissingWidth']; }
  2269. elseif(isset($this->CurrentFont['MissingWidth'])) { $w += $this->CurrentFont['MissingWidth']; }
  2270. else { $w += 500; }
  2271. }
  2272. } // *CJK-FONTS*
  2273. $w *= ($this->FontSize/ 1000);
  2274. if ($this->minwSpacing || $this->fixedlSpacing) {
  2275. if ($c==' ') $nb_spaces = 1;
  2276. else $nb_spaces = 0;
  2277. $w += $this->fixedlSpacing + ($nb_spaces * $this->minwSpacing);
  2278. }
  2279. return ($w);
  2280. }
  2281. function GetCharWidth($c, $addSubset=true) {
  2282. if (!$this->usingCoreFont) {
  2283. return $this->GetCharWidthNonCore($c, $addSubset);
  2284. }
  2285. else {
  2286. return $this->GetCharWidthCore($c);
  2287. }
  2288. }
  2289. function GetStringWidth($s, $addSubset=true) {
  2290. //Get width of a string in the current font
  2291. $s = (string)$s;
  2292. $cw = &$this->CurrentFont['cw'];
  2293. $w = 0;
  2294. $kerning = 0;
  2295. $lastchar = 0;
  2296. $nb_carac = 0;
  2297. $nb_spaces = 0;
  2298. // mPDF ITERATION
  2299. if ($this->iterationCounter) $s = preg_replace('/{iteration ([a-zA-Z0-9_]+)}/', '\\1', $s);
  2300. if (!$this->usingCoreFont) {
  2301. $s = str_replace("\xc2\xad",'',$s );
  2302. $unicode = $this->UTF8StringToArray($s, $addSubset);
  2303. if ($this->minwSpacing || $this->fixedlSpacing) {
  2304. $nb_carac = count($unicode);
  2305. $nb_spaces = mb_substr_count($s,' ', $this->mb_enc);
  2306. }
  2307. /*-- CJK-FONTS --*/
  2308. if ($this->CurrentFont['type'] == 'Type0') { // CJK Adobe fonts
  2309. foreach($unicode as $char) {
  2310. if (isset($cw[$char])) { $w+=$cw[$char]; }
  2311. elseif(isset($this->CurrentFont['MissingWidth'])) { $w += $this->CurrentFont['MissingWidth']; }
  2312. else { $w += 500; }
  2313. }
  2314. }
  2315. else {
  2316. /*-- END CJK-FONTS --*/
  2317. foreach($unicode as $char) {
  2318. if ($this->S && isset($this->upperCase[$char])) {
  2319. $charw = $this->_getCharWidth($cw,$this->upperCase[$char]);
  2320. if ($charw!==false) {
  2321. $charw = $charw*$this->smCapsScale * $this->smCapsStretch/100;
  2322. $w+=$charw;
  2323. }
  2324. elseif(isset($this->CurrentFont['desc']['MissingWidth'])) { $w += $this->CurrentFont['desc']['MissingWidth']; }
  2325. elseif(isset($this->CurrentFont['MissingWidth'])) { $w += $this->CurrentFont['MissingWidth']; }
  2326. else { $w += 500; }
  2327. }
  2328. else {
  2329. $charw = $this->_getCharWidth($cw,$char);
  2330. if ($charw!==false) { $w+=$charw; }
  2331. elseif(isset($this->CurrentFont['desc']['MissingWidth'])) { $w += $this->CurrentFont['desc']['MissingWidth']; }
  2332. elseif(isset($this->CurrentFont['MissingWidth'])) { $w += $this->CurrentFont['MissingWidth']; }
  2333. else { $w += 500; }
  2334. if ($this->kerning && $this->useKerning && $lastchar) {
  2335. if (isset($this->CurrentFont['kerninfo'][$lastchar][$char])) {
  2336. $kerning += $this->CurrentFont['kerninfo'][$lastchar][$char];
  2337. }
  2338. }
  2339. $lastchar = $char;
  2340. }
  2341. }
  2342. } // *CJK-FONTS*
  2343. }
  2344. else {
  2345. if ($this->FontFamily!='csymbol' && $this->FontFamily!='czapfdingbats') {
  2346. $s = str_replace(chr(173),'',$s );
  2347. }
  2348. $nb_carac = $l = strlen($s);
  2349. if ($this->minwSpacing || $this->fixedlSpacing) {
  2350. $nb_spaces = substr_count($s,' ');
  2351. }
  2352. for($i=0; $i<$l; $i++) {
  2353. if ($this->S && isset($this->upperCase[ord($s[$i])])) {
  2354. $charw = $cw[chr($this->upperCase[ord($s[$i])])];
  2355. if ($charw!==false) {
  2356. $charw = $charw*$this->smCapsScale * $this->smCapsStretch/100;
  2357. $w+=$charw;
  2358. }
  2359. }
  2360. else if (isset($cw[$s[$i]])) {
  2361. $w += $cw[$s[$i]];
  2362. }
  2363. else if (isset($cw[ord($s[$i])])) {
  2364. $w += $cw[ord($s[$i])];
  2365. }
  2366. if ($this->kerning && $this->useKerning && $i>0) {
  2367. if (isset($this->CurrentFont['kerninfo'][$s[($i-1)]][$s[$i]])) {
  2368. $kerning += $this->CurrentFont['kerninfo'][$s[($i-1)]][$s[$i]];
  2369. }
  2370. }
  2371. }
  2372. }
  2373. unset($cw);
  2374. if ($this->kerning && $this->useKerning) { $w += $kerning; }
  2375. $w *= ($this->FontSize/ 1000);
  2376. $w += (($nb_carac + $nb_spaces) * $this->fixedlSpacing) + ($nb_spaces * $this->minwSpacing);
  2377. return ($w);
  2378. }
  2379. function SetLineWidth($width) {
  2380. //Set line width
  2381. $this->LineWidth=$width;
  2382. $lwout = (sprintf('%.3F w',$width*_MPDFK));
  2383. if($this->page>0 && ((isset($this->pageoutput[$this->page]['LineWidth']) && $this->pageoutput[$this->page]['LineWidth'] != $lwout) || !isset($this->pageoutput[$this->page]['LineWidth']) || $this->keep_block_together)) {
  2384. $this->_out($lwout);
  2385. }
  2386. $this->pageoutput[$this->page]['LineWidth'] = $lwout;
  2387. }
  2388. function Line($x1,$y1,$x2,$y2) {
  2389. //Draw a line
  2390. $this->_out(sprintf('%.3F %.3F m %.3F %.3F l S',$x1*_MPDFK,($this->h-$y1)*_MPDFK,$x2*_MPDFK,($this->h-$y2)*_MPDFK));
  2391. }
  2392. function Arrow($x1,$y1,$x2,$y2,$headsize=3,$fill='B',$angle=25) {
  2393. //F == fill //S == stroke //B == stroke and fill
  2394. // angle = splay of arrowhead - 1 - 89 degrees
  2395. if($fill=='F') $fill='f';
  2396. elseif($fill=='FD' or $fill=='DF' or $fill=='B') $fill='B';
  2397. else $fill='S';
  2398. $a = atan2(($y2-$y1),($x2-$x1));
  2399. $b = $a + deg2rad($angle);
  2400. $c = $a - deg2rad($angle);
  2401. $x3 = $x2 - ($headsize* cos($b));
  2402. $y3 = $this->h-($y2 - ($headsize* sin($b)));
  2403. $x4 = $x2 - ($headsize* cos($c));
  2404. $y4 = $this->h-($y2 - ($headsize* sin($c)));
  2405. $x5 = $x3-($x3-$x4)/2; // mid point of base of arrowhead - to join arrow line to
  2406. $y5 = $y3-($y3-$y4)/2;
  2407. $s = '';
  2408. $s.=sprintf('%.3F %.3F m %.3F %.3F l S',$x1*_MPDFK,($this->h-$y1)*_MPDFK,$x5*_MPDFK,$y5*_MPDFK);
  2409. $this->_out($s);
  2410. $s = '';
  2411. $s.=sprintf('%.3F %.3F m %.3F %.3F l %.3F %.3F l %.3F %.3F l %.3F %.3F l ',$x5*_MPDFK,$y5*_MPDFK,$x3*_MPDFK,$y3*_MPDFK,$x2*_MPDFK,($this->h-$y2)*_MPDFK,$x4*_MPDFK,$y4*_MPDFK,$x5*_MPDFK,$y5*_MPDFK);
  2412. $s.=$fill;
  2413. $this->_out($s);
  2414. }
  2415. function Rect($x,$y,$w,$h,$style='') {
  2416. //Draw a rectangle
  2417. if($style=='F') $op='f';
  2418. elseif($style=='FD' or $style=='DF') $op='B';
  2419. else $op='S';
  2420. $this->_out(sprintf('%.3F %.3F %.3F %.3F re %s',$x*_MPDFK,($this->h-$y)*_MPDFK,$w*_MPDFK,-$h*_MPDFK,$op));
  2421. }
  2422. function AddFont($family,$style='') {
  2423. if(empty($family)) { return; }
  2424. $family = strtolower($family);
  2425. $style=strtoupper($style);
  2426. $style=str_replace('U','',$style);
  2427. if($style=='IB') $style='BI';
  2428. $fontkey = $family.$style;
  2429. // check if the font has been already added
  2430. if(isset($this->fonts[$fontkey])) {
  2431. return;
  2432. }
  2433. /*-- CJK-FONTS --*/
  2434. if (in_array($family,$this->available_CJK_fonts)) {
  2435. if (empty($this->Big5_widths)) { require(_MPDF_PATH . 'includes/CJKdata.php'); }
  2436. $this->AddCJKFont($family); // don't need to add style
  2437. return;
  2438. }
  2439. /*-- END CJK-FONTS --*/
  2440. if ($this->usingCoreFont) { die("mPDF Error - problem with Font management"); }
  2441. $stylekey = $style;
  2442. if (!$style) { $stylekey = 'R'; }
  2443. if (!isset($this->fontdata[$family][$stylekey]) || !$this->fontdata[$family][$stylekey]) {
  2444. die('mPDF Error - Font is not supported - '.$family.' '.$style);
  2445. }
  2446. $name = '';
  2447. $originalsize = 0;
  2448. $sip = false;
  2449. $smp = false;
  2450. $unAGlyphs = false; // mPDF 5.4.05
  2451. $haskerninfo = false;
  2452. $BMPselected = false;
  2453. @include(_MPDF_TTFONTDATAPATH.$fontkey.'.mtx.php');
  2454. $ttffile = '';
  2455. if (defined('_MPDF_SYSTEM_TTFONTS')) {
  2456. $ttffile = _MPDF_SYSTEM_TTFONTS.$this->fontdata[$family][$stylekey];
  2457. if (!file_exists($ttffile)) { $ttffile = ''; }
  2458. }
  2459. if (!$ttffile) {
  2460. $ttffile = _MPDF_TTFONTPATH.$this->fontdata[$family][$stylekey];
  2461. if (!file_exists($ttffile)) { die("mPDF Error - cannot find TTF TrueType font file - ".$ttffile); }
  2462. }
  2463. $ttfstat = stat($ttffile);
  2464. if (isset($this->fontdata[$family]['TTCfontID'][$stylekey])) { $TTCfontID = $this->fontdata[$family]['TTCfontID'][$stylekey]; }
  2465. else { $TTCfontID = 0; }
  2466. $BMPonly = false;
  2467. if (in_array($family,$this->BMPonly)) { $BMPonly = true; }
  2468. $regenerate = false;
  2469. if ($BMPonly && !$BMPselected) { $regenerate = true; }
  2470. else if (!$BMPonly && $BMPselected) { $regenerate = true; }
  2471. if ($this->useKerning && !$haskerninfo) { $regenerate = true; }
  2472. // mPDF 5.4.05
  2473. if (isset($this->fontdata[$family]['unAGlyphs']) && $this->fontdata[$family]['unAGlyphs'] && !$unAGlyphs) {
  2474. $regenerate = true;
  2475. $unAGlyphs = true;
  2476. }
  2477. else if ((!isset($this->fontdata[$family]['unAGlyphs']) || !$this->fontdata[$family]['unAGlyphs']) && $unAGlyphs) {
  2478. $regenerate = true;
  2479. $unAGlyphs = false;
  2480. }
  2481. if (!isset($name) || $originalsize != $ttfstat['size'] || $regenerate) {
  2482. if (!class_exists('TTFontFile', false)) { include(_MPDF_PATH .'classes/ttfontsuni.php'); }
  2483. $ttf = new TTFontFile();
  2484. $ttf->getMetrics($ttffile, $TTCfontID, $this->debugfonts, $BMPonly, $this->useKerning, $unAGlyphs); // mPDF 5.4.05
  2485. $cw = $ttf->charWidths;
  2486. $kerninfo = $ttf->kerninfo;
  2487. $haskerninfo = true;
  2488. $name = preg_replace('/[ ()]/','',$ttf->fullName);
  2489. $sip = $ttf->sipset;
  2490. $smp = $ttf->smpset;
  2491. $desc= array('Ascent'=>round($ttf->ascent),
  2492. 'Descent'=>round($ttf->descent),
  2493. 'CapHeight'=>round($ttf->capHeight),
  2494. 'Flags'=>$ttf->flags,
  2495. 'FontBBox'=>'['.round($ttf->bbox[0])." ".round($ttf->bbox[1])." ".round($ttf->bbox[2])." ".round($ttf->bbox[3]).']',
  2496. 'ItalicAngle'=>$ttf->italicAngle,
  2497. 'StemV'=>round($ttf->stemV),
  2498. 'MissingWidth'=>round($ttf->defaultWidth));
  2499. $panose = '';
  2500. // mPDF 5.5.19
  2501. if (count($ttf->panose)) {
  2502. $panoseArray = array_merge(array($ttf->sFamilyClass, $ttf->sFamilySubClass), $ttf->panose);
  2503. foreach($panoseArray as $value)
  2504. $panose .= ' '.dechex($value);
  2505. }
  2506. $up = round($ttf->underlinePosition);
  2507. $ut = round($ttf->underlineThickness);
  2508. $originalsize = $ttfstat['size']+0;
  2509. $type = 'TTF';
  2510. //Generate metrics .php file
  2511. $s='<?php'."\n";
  2512. $s.='$name=\''.$name."';\n";
  2513. $s.='$type=\''.$type."';\n";
  2514. $s.='$desc='.var_export($desc,true).";\n";
  2515. $s.='$up='.$up.";\n";
  2516. $s.='$ut='.$ut.";\n";
  2517. $s.='$ttffile=\''.$ttffile."';\n";
  2518. $s.='$TTCfontID=\''.$TTCfontID."';\n";
  2519. $s.='$originalsize='.$originalsize.";\n";
  2520. if ($sip) $s.='$sip=true;'."\n";
  2521. else $s.='$sip=false;'."\n";
  2522. if ($smp) $s.='$smp=true;'."\n";
  2523. else $s.='$smp=false;'."\n";
  2524. if ($BMPonly) $s.='$BMPselected=true;'."\n";
  2525. else $s.='$BMPselected=false;'."\n";
  2526. $s.='$fontkey=\''.$fontkey."';\n";
  2527. $s.='$panose=\''.$panose."';\n";
  2528. if ($this->useKerning) {
  2529. $s.='$kerninfo='.var_export($kerninfo,true).";\n";
  2530. $s.='$haskerninfo=true;'."\n";
  2531. }
  2532. else $s.='$haskerninfo=false;'."\n";
  2533. // mPDF 5.4.05
  2534. if ($this->fontdata[$family]['unAGlyphs']) {
  2535. $s.='$unAGlyphs=true;'."\n";
  2536. }
  2537. else $s.='$unAGlyphs=false;'."\n";
  2538. $s.="?>";
  2539. if (is_writable(dirname(_MPDF_TTFONTDATAPATH.'x'))) {
  2540. $fh = fopen(_MPDF_TTFONTDATAPATH.$fontkey.'.mtx.php',"w");
  2541. fwrite($fh,$s,strlen($s));
  2542. fclose($fh);
  2543. $fh = fopen(_MPDF_TTFONTDATAPATH.$fontkey.'.cw.dat',"wb");
  2544. fwrite($fh,$cw,strlen($cw));
  2545. fclose($fh);
  2546. @unlink(_MPDF_TTFONTDATAPATH.$fontkey.'.cgm');
  2547. @unlink(_MPDF_TTFONTDATAPATH.$fontkey.'.z');
  2548. @unlink(_MPDF_TTFONTDATAPATH.$fontkey.'.cw127.php');
  2549. @unlink(_MPDF_TTFONTDATAPATH.$fontkey.'.cw');
  2550. }
  2551. else if ($this->debugfonts) { $this->Error('Cannot write to the font caching directory - '._MPDF_TTFONTDATAPATH); }
  2552. unset($ttf);
  2553. }
  2554. else {
  2555. $cw = @file_get_contents(_MPDF_TTFONTDATAPATH.$fontkey.'.cw.dat');
  2556. }
  2557. if (isset($this->fontdata[$family]['indic']) && $this->fontdata[$family]['indic']) { $indic = true; }
  2558. else { $indic = false; }
  2559. if (isset($this->fontdata[$family]['sip-ext']) && $this->fontdata[$family]['sip-ext']) { $sipext = $this->fontdata[$family]['sip-ext']; }
  2560. else { $sipext = ''; }
  2561. $i = count($this->fonts)+$this->extraFontSubsets+1;
  2562. if ($sip || $smp) {
  2563. $this->fonts[$fontkey] = array('i'=>$i, 'type'=>$type, 'name'=>$name, 'desc'=>$desc, 'panose'=>$panose, 'up'=>$up, 'ut'=>$ut, 'cw'=>$cw, 'ttffile'=>$ttffile, 'fontkey'=>$fontkey, 'subsets'=>array(0=>range(0,127)), 'subsetfontids'=>array($i), 'used'=>false, 'indic'=>$indic, 'sip'=>$sip, 'sipext'=>$sipext, 'smp'=>$smp, 'TTCfontID' => $TTCfontID, 'unAGlyphs' => false); // mPDF 5.4.05
  2564. }
  2565. else {
  2566. $ss = array();
  2567. for ($s=32; $s<128; $s++) { $ss[$s] = $s; }
  2568. $this->fonts[$fontkey] = array('i'=>$i, 'type'=>$type, 'name'=>$name, 'desc'=>$desc, 'panose'=>$panose, 'up'=>$up, 'ut'=>$ut, 'cw'=>$cw, 'ttffile'=>$ttffile, 'fontkey'=>$fontkey, 'subset'=>$ss, 'used'=>false, 'indic'=>$indic, 'sip'=>$sip, 'sipext'=>$sipext, 'smp'=>$smp, 'TTCfontID' => $TTCfontID, 'unAGlyphs' => $unAGlyphs); // mPDF 5.4.05
  2569. }
  2570. if ($this->useKerning && $haskerninfo) { $this->fonts[$fontkey]['kerninfo'] = $kerninfo; }
  2571. $this->FontFiles[$fontkey]=array('length1'=>$originalsize, 'type'=>"TTF", 'ttffile'=>$ttffile, 'sip'=>$sip, 'smp'=>$smp);
  2572. unset($cw);
  2573. }
  2574. function SetFont($family,$style='',$size=0, $write=true, $forcewrite=false) {
  2575. $family=strtolower($family);
  2576. if (!$this->onlyCoreFonts) {
  2577. if ($family == 'sans' || $family == 'sans-serif') { $family = $this->sans_fonts[0]; }
  2578. if ($family == 'serif') { $family = $this->serif_fonts[0]; }
  2579. if ($family == 'mono' || $family == 'monospace') { $family = $this->mono_fonts[0]; }
  2580. }
  2581. if (isset($this->fonttrans[$family]) && $this->fonttrans[$family]) { $family = $this->fonttrans[$family]; }
  2582. if($family=='') {
  2583. if ($this->FontFamily) { $family=$this->FontFamily; }
  2584. else if ($this->default_font) { $family=$this->default_font; }
  2585. else { $this->Error("No font or default font set!"); }
  2586. }
  2587. $this->ReqFontStyle = $style; // required or requested style - used later for artificial bold/italic
  2588. if (($family == 'csymbol') || ($family == 'czapfdingbats') || ($family == 'ctimes') || ($family == 'ccourier') || ($family == 'chelvetica')) {
  2589. if ($this->PDFA || $this->PDFX) {
  2590. if ($family == 'csymbol' || $family == 'czapfdingbats') {
  2591. $this->Error("Symbol and Zapfdingbats cannot be embedded in mPDF (required for PDFA1-b or PDFX/1-a).");
  2592. }
  2593. if ($family == 'ctimes' || $family == 'ccourier' || $family == 'chelvetica') {
  2594. if (($this->PDFA && !$this->PDFAauto) || ($this->PDFX && !$this->PDFXauto)) { $this->PDFAXwarnings[] = "Core Adobe font ".ucfirst($family)." cannot be embedded in mPDF, which is required for PDFA1-b or PDFX/1-a. (Embedded font will be substituted.)"; }
  2595. if ($family == 'chelvetica') { $family = 'sans'; }
  2596. if ($family == 'ctimes') { $family = 'serif'; }
  2597. if ($family == 'ccourier') { $family = 'mono'; }
  2598. }
  2599. $this->usingCoreFont = false;
  2600. }
  2601. else { $this->usingCoreFont = true; }
  2602. if($family=='csymbol' || $family=='czapfdingbats') { $style=''; }
  2603. }
  2604. else { $this->usingCoreFont = false; }
  2605. $this->U=false;
  2606. $this->S=false;
  2607. if ($style) {
  2608. $style=strtoupper($style);
  2609. if(strpos($style,'U')!==false) {
  2610. $this->U=true;
  2611. $style=str_replace('U','',$style);
  2612. }
  2613. if(strpos($style,'S')!==false) {
  2614. $this->S=true;
  2615. // Small Caps
  2616. if (empty($this->upperCase)) { @include(_MPDF_PATH.'includes/upperCase.php'); }
  2617. $style=str_replace('S','',$style);
  2618. }
  2619. if ($style=='IB') $style='BI';
  2620. }
  2621. if ($size==0) $size=$this->FontSizePt;
  2622. $fontkey=$family.$style;
  2623. $stylekey = $style;
  2624. if (!$stylekey) { $stylekey = "R"; }
  2625. if (!$this->onlyCoreFonts && !$this->usingCoreFont) {
  2626. if(!isset($this->fonts[$fontkey]) || count($this->default_available_fonts) != count($this->available_unifonts) ) { // not already added
  2627. /*-- CJK-FONTS --*/
  2628. // CJK fonts
  2629. if (in_array($fontkey,$this->available_CJK_fonts)) {
  2630. if(!isset($this->fonts[$fontkey])) { // already added
  2631. if (empty($this->Big5_widths)) { require(_MPDF_PATH . 'includes/CJKdata.php'); }
  2632. $this->AddCJKFont($family); // don't need to add style
  2633. }
  2634. }
  2635. // Test to see if requested font/style is available - or substitute
  2636. else
  2637. /*-- END CJK-FONTS --*/
  2638. if (!in_array($fontkey,$this->available_unifonts)) {
  2639. // If font[nostyle] exists - set it
  2640. if (in_array($family,$this->available_unifonts)) {
  2641. $style = '';
  2642. }
  2643. // Else if only one font available - set it (assumes if only one font available it will not have a style)
  2644. else if (count($this->available_unifonts) == 1) {
  2645. $family = $this->available_unifonts[0];
  2646. $style = '';
  2647. }
  2648. else {
  2649. $found = 0;
  2650. // else substitute font of similar type
  2651. if (in_array($family,$this->sans_fonts)) {
  2652. $i = array_intersect($this->sans_fonts,$this->available_unifonts);
  2653. if (count($i)) {
  2654. $i = array_values($i);
  2655. // with requested style if possible
  2656. if (!in_array(($i[0].$style),$this->available_unifonts)) {
  2657. $style = '';
  2658. }
  2659. $family = $i[0];
  2660. $found = 1;
  2661. }
  2662. }
  2663. else if (in_array($family,$this->serif_fonts)) {
  2664. $i = array_intersect($this->serif_fonts,$this->available_unifonts);
  2665. if (count($i)) {
  2666. $i = array_values($i);
  2667. // with requested style if possible
  2668. if (!in_array(($i[0].$style),$this->available_unifonts)) {
  2669. $style = '';
  2670. }
  2671. $family = $i[0];
  2672. $found = 1;
  2673. }
  2674. }
  2675. else if (in_array($family,$this->mono_fonts)) {
  2676. $i = array_intersect($this->mono_fonts,$this->available_unifonts);
  2677. if (count($i)) {
  2678. $i = array_values($i);
  2679. // with requested style if possible
  2680. if (!in_array(($i[0].$style),$this->available_unifonts)) {
  2681. $style = '';
  2682. }
  2683. $family = $i[0];
  2684. $found = 1;
  2685. }
  2686. }
  2687. if (!$found) {
  2688. // set first available font
  2689. $fs = $this->available_unifonts[0];
  2690. preg_match('/^([a-z_0-9\-]+)([BI]{0,2})$/',$fs,$fas); // Allow "-"
  2691. // with requested style if possible
  2692. $ws = $fas[1].$style;
  2693. if (in_array($ws,$this->available_unifonts)) {
  2694. $family = $fas[1]; // leave $style as is
  2695. }
  2696. else if (in_array($fas[1],$this->available_unifonts)) {
  2697. // or without style
  2698. $family = $fas[1];
  2699. $style = '';
  2700. }
  2701. else {
  2702. // or with the style specified
  2703. $family = $fas[1];
  2704. $style = $fas[2];
  2705. }
  2706. }
  2707. }
  2708. $fontkey = $family.$style;
  2709. }
  2710. }
  2711. // try to add font (if not already added)
  2712. $this->AddFont($family, $style);
  2713. //Test if font is already selected
  2714. if($this->FontFamily == $family && $this->FontFamily == $this->currentfontfamily && $this->FontStyle == $style && $this->FontStyle == $this->currentfontstyle && $this->FontSizePt == $size && $this->FontSizePt == $this->currentfontsize && !$forcewrite) {
  2715. return $family;
  2716. }
  2717. $fontkey = $family.$style;
  2718. //Select it
  2719. $this->FontFamily = $family;
  2720. $this->FontStyle = $style;
  2721. $this->FontSizePt = $size;
  2722. $this->FontSize = $size / _MPDFK;
  2723. $this->CurrentFont = &$this->fonts[$fontkey];
  2724. if ($write) {
  2725. $fontout = (sprintf('BT /F%d %.3F Tf ET', $this->CurrentFont['i'], $this->FontSizePt));
  2726. if($this->page>0 && ((isset($this->pageoutput[$this->page]['Font']) && $this->pageoutput[$this->page]['Font'] != $fontout) || !isset($this->pageoutput[$this->page]['Font']) || $this->keep_block_together)) { $this->_out($fontout); }
  2727. $this->pageoutput[$this->page]['Font'] = $fontout;
  2728. }
  2729. // Added - currentfont (lowercase) used in HTML2PDF
  2730. $this->currentfontfamily=$family;
  2731. $this->currentfontsize=$size;
  2732. $this->currentfontstyle=$style.($this->U ? 'U' : '').($this->S ? 'S' : '');
  2733. $this->setMBencoding('UTF-8');
  2734. }
  2735. else { // if using core fonts
  2736. if ($this->PDFA || $this->PDFX) {
  2737. $this->Error('Core Adobe fonts cannot be embedded in mPDF (required for PDFA1-b or PDFX/1-a) - cannot use option to use core fonts.');
  2738. }
  2739. $this->setMBencoding('windows-1252');
  2740. //Test if font is already selected
  2741. if(($this->FontFamily == $family) AND ($this->FontStyle == $style) AND ($this->FontSizePt == $size) && !$forcewrite) {
  2742. return $family;
  2743. }
  2744. if (!isset($this->CoreFonts[$fontkey])) {
  2745. if (in_array($family,$this->serif_fonts)) { $family = 'ctimes'; }
  2746. else if (in_array($family,$this->mono_fonts)) { $family = 'ccourier'; }
  2747. else { $family = 'chelvetica'; }
  2748. $this->usingCoreFont = true;
  2749. $fontkey = $family.$style;
  2750. }
  2751. if(!isset($this->fonts[$fontkey])) {
  2752. // STANDARD CORE FONTS
  2753. if (isset($this->CoreFonts[$fontkey])) {
  2754. //Load metric file
  2755. $file=$family;
  2756. if($family=='ctimes' || $family=='chelvetica' || $family=='ccourier') { $file.=strtolower($style); }
  2757. $file.='.php';
  2758. include(_MPDF_PATH.'font/'.$file);
  2759. if(!isset($cw)) { $this->Error('Could not include font metric file'); }
  2760. $i=count($this->fonts)+$this->extraFontSubsets+1;
  2761. $this->fonts[$fontkey]=array('i'=>$i,'type'=>'core','name'=>$this->CoreFonts[$fontkey],'desc'=>$desc,'up'=>$up,'ut'=>$ut,'cw'=>$cw);
  2762. if ($this->useKerning) { $this->fonts[$fontkey]['kerninfo'] = $kerninfo; }
  2763. }
  2764. else {
  2765. die('mPDF error - Font not defined');
  2766. }
  2767. }
  2768. //Test if font is already selected
  2769. if(($this->FontFamily == $family) AND ($this->FontStyle == $style) AND ($this->FontSizePt == $size) && !$forcewrite) {
  2770. return $family;
  2771. }
  2772. //Select it
  2773. $this->FontFamily=$family;
  2774. $this->FontStyle=$style;
  2775. $this->FontSizePt=$size;
  2776. $this->FontSize=$size/_MPDFK;
  2777. $this->CurrentFont=&$this->fonts[$fontkey];
  2778. if ($write) {
  2779. $fontout = (sprintf('BT /F%d %.3F Tf ET', $this->CurrentFont['i'], $this->FontSizePt));
  2780. if($this->page>0 && ((isset($this->pageoutput[$this->page]['Font']) && $this->pageoutput[$this->page]['Font'] != $fontout) || !isset($this->pageoutput[$this->page]['Font']) || $this->keep_block_together)) { $this->_out($fontout); }
  2781. $this->pageoutput[$this->page]['Font'] = $fontout;
  2782. }
  2783. // Added - currentfont (lowercase) used in HTML2PDF
  2784. $this->currentfontfamily=$family;
  2785. $this->currentfontsize=$size;
  2786. $this->currentfontstyle=$style.($this->U ? 'U' : '').($this->S ? 'S' : '');
  2787. }
  2788. return $family;
  2789. }
  2790. function SetFontSize($size,$write=true) {
  2791. //Set font size in points
  2792. if($this->FontSizePt==$size) return;
  2793. $this->FontSizePt=$size;
  2794. $this->FontSize=$size/_MPDFK;
  2795. $this->currentfontsize=$size;
  2796. if ($write) {
  2797. $fontout = (sprintf('BT /F%d %.3F Tf ET', $this->CurrentFont['i'], $this->FontSizePt));
  2798. // Edited mPDF 3.0
  2799. if($this->page>0 && ((isset($this->pageoutput[$this->page]['Font']) && $this->pageoutput[$this->page]['Font'] != $fontout) || !isset($this->pageoutput[$this->page]['Font']) || $this->keep_block_together)) { $this->_out($fontout); }
  2800. $this->pageoutput[$this->page]['Font'] = $fontout;
  2801. }
  2802. }
  2803. function AddLink() {
  2804. //Create a new internal link
  2805. $n=count($this->links)+1;
  2806. $this->links[$n]=array(0,0);
  2807. return $n;
  2808. }
  2809. function SetLink($link,$y=0,$page=-1) {
  2810. //Set destination of internal link
  2811. if($y==-1) $y=$this->y;
  2812. if($page==-1) $page=$this->page;
  2813. $this->links[$link]=array($page,$y);
  2814. }
  2815. function Link($x,$y,$w,$h,$link) {
  2816. $l = array($x*_MPDFK,$this->hPt-$y*_MPDFK,$w*_MPDFK,$h*_MPDFK,$link);
  2817. if ($this->keep_block_together) { // Save to array - don't write yet
  2818. $this->ktLinks[$this->page][]= $l;
  2819. return;
  2820. }
  2821. else if ($this->table_rotate) { // *TABLES*
  2822. $this->tbrot_Links[$this->page][]= $l; // *TABLES*
  2823. return; // *TABLES*
  2824. } // *TABLES*
  2825. else if ($this->kwt) {
  2826. $this->kwt_Links[$this->page][]= $l;
  2827. return;
  2828. }
  2829. if ($this->writingHTMLheader || $this->writingHTMLfooter) {
  2830. $this->HTMLheaderPageLinks[]= $l;
  2831. return;
  2832. }
  2833. //Put a link on the page
  2834. $this->PageLinks[$this->page][]= $l;
  2835. // Save cross-reference to Column buffer
  2836. $ref = count($this->PageLinks[$this->page])-1; // *COLUMNS*
  2837. $this->columnLinks[$this->CurrCol][INTVAL($this->x)][INTVAL($this->y)] = $ref; // *COLUMNS*
  2838. }
  2839. function Text($x,$y,$txt) {
  2840. // Output a string
  2841. // Called (internally) by Watermark and _tableWrite [rotated cells]
  2842. // Expects input to be mb_encoded if necessary and RTL reversed
  2843. // ARTIFICIAL BOLD AND ITALIC
  2844. $s = 'q ';
  2845. if ($this->falseBoldWeight && strpos($this->ReqFontStyle,"B") !== false && strpos($this->FontStyle,"B") === false) {
  2846. $s .= '2 Tr 1 J 1 j ';
  2847. $s .= sprintf('%.3F w ',($this->FontSize/130)*_MPDFK*$this->falseBoldWeight);
  2848. $tc = strtoupper($this->TextColor); // change 0 0 0 rg to 0 0 0 RG
  2849. if($this->FillColor!=$tc) { $s .= $tc.' '; } // stroke (outline) = same colour as text(fill)
  2850. }
  2851. if (strpos($this->ReqFontStyle,"I") !== false && strpos($this->FontStyle,"I") === false) {
  2852. $aix = '1 0 0.261799 1 %.3F %.3F Tm';
  2853. }
  2854. else { $aix = '%.3F %.3F Td'; }
  2855. if($this->ColorFlag) $s.=$this->TextColor.' ';
  2856. $this->CurrentFont['used']= true;
  2857. if ($this->CurrentFont['type']=='TTF' && ($this->CurrentFont['sip'] || $this->CurrentFont['smp'])) {
  2858. $txt2 = str_replace(chr(194).chr(160),chr(32),$txt);
  2859. $txt2 = $this->UTF8toSubset($txt2);
  2860. $s.=sprintf('BT '.$aix.' %s Tj ET ',$x*_MPDFK,($this->h-$y)*_MPDFK,$txt2);
  2861. }
  2862. else if (!$this->usingCoreFont) {
  2863. $txt2 = str_replace(chr(194).chr(160),chr(32),$txt);
  2864. $this->UTF8StringToArray($txt2); // this is just to add chars to subset list
  2865. if ($this->kerning && $this->useKerning) { $s .= $this->_kern($txt2, '', $aix, $x, $y); }
  2866. else {
  2867. //Convert string to UTF-16BE without BOM
  2868. $txt2= $this->UTF8ToUTF16BE($txt2, false);
  2869. $s.=sprintf('BT '.$aix.' (%s) Tj ET ',$x*_MPDFK,($this->h-$y)*_MPDFK,$this->_escape($txt2));
  2870. }
  2871. }
  2872. else {
  2873. $txt2 = str_replace(chr(160),chr(32),$txt);
  2874. if ($this->kerning && $this->useKerning) { $s .= $this->_kern($txt2, '', $aix, $x, $y); }
  2875. else {
  2876. $s.=sprintf('BT '.$aix.' (%s) Tj ET ',$x*_MPDFK,($this->h-$y)*_MPDFK,$this->_escape($txt2));
  2877. }
  2878. }
  2879. if($this->U && $txt!='') {
  2880. $c = strtoupper($this->TextColor); // change 0 0 0 rg to 0 0 0 RG
  2881. if($this->FillColor!=$c) { $s.= ' '.$c.' '; }
  2882. if (isset($this->CurrentFont['up'])) { $up=$this->CurrentFont['up']; }
  2883. else { $up = -100; }
  2884. $adjusty = (-$up/1000* $this->FontSize);
  2885. if (isset($this->CurrentFont['ut'])) { $ut=$this->CurrentFont['ut']/1000* $this->FontSize; }
  2886. else { $ut = 60/1000* $this->FontSize; }
  2887. $olw = $this->LineWidth;
  2888. $s.=' '.(sprintf(' %.3F w',$ut*_MPDFK));
  2889. $s.=' '.$this->_dounderline($x,$y + $adjusty,$txt);
  2890. $s.=' '.(sprintf(' %.3F w',$olw*_MPDFK));
  2891. if($this->FillColor!=$c) { $s.= ' '.$this->FillColor.' '; }
  2892. }
  2893. // STRIKETHROUGH
  2894. if($this->strike && $txt!='') {
  2895. $c = strtoupper($this->TextColor); // change 0 0 0 rg to 0 0 0 RG
  2896. if($this->FillColor!=$c) { $s.= ' '.$c.' '; }
  2897. //Superscript and Subscript Y coordinate adjustment (now for striked-through texts)
  2898. if (isset($this->CurrentFont['desc']['CapHeight'])) { $ch=$this->CurrentFont['desc']['CapHeight']; }
  2899. else { $ch = 700; }
  2900. $adjusty = (-$ch/1000* $this->FontSize) * 0.35;
  2901. if (isset($this->CurrentFont['ut'])) { $ut=$this->CurrentFont['ut']/1000* $this->FontSize; }
  2902. else { $ut = 60/1000* $this->FontSize; }
  2903. $olw = $this->LineWidth;
  2904. $s.=' '.(sprintf(' %.3F w',$ut*_MPDFK));
  2905. $s.=' '.$this->_dounderline($x,$y+$adjusty,$txt);
  2906. $s.=' '.(sprintf(' %.3F w',$olw*_MPDFK));
  2907. if($this->FillColor!=$c) { $s.= ' '.$this->FillColor.' '; }
  2908. }
  2909. $s .= 'Q';
  2910. $this->_out($s);
  2911. }
  2912. /*-- DIRECTW --*/
  2913. function WriteText($x,$y,$txt) {
  2914. // Output a string using Text() but does encoding and text reversing of RTL
  2915. $txt = $this->purify_utf8_text($txt);
  2916. if ($this->text_input_as_HTML) {
  2917. $txt = $this->all_entities_to_utf8($txt);
  2918. }
  2919. if ($this->usingCoreFont) { $txt = mb_convert_encoding($txt,$this->mb_enc,'UTF-8'); }
  2920. // DIRECTIONALITY
  2921. if (preg_match("/([".$this->pregRTLchars."])/u", $txt)) { $this->biDirectional = true; } // *RTL*
  2922. $this->magic_reverse_dir($txt, true, $this->directionality); // *RTL*
  2923. // Font-specific ligature substitution for Indic fonts
  2924. if (isset($this->CurrentFont['indic']) && $this->CurrentFont['indic']) $this->ConvertIndic($txt); // *INDIC*
  2925. $this->Text($x,$y,$txt);
  2926. }
  2927. function WriteCell($w,$h=0,$txt='',$border=0,$ln=0,$align='',$fill=0,$link='', $currentx=0) {
  2928. //Output a cell using Cell() but does encoding and text reversing of RTL
  2929. $txt = $this->purify_utf8_text($txt);
  2930. if ($this->text_input_as_HTML) {
  2931. $txt = $this->all_entities_to_utf8($txt);
  2932. }
  2933. if ($this->usingCoreFont) { $txt = mb_convert_encoding($txt,$this->mb_enc,'UTF-8'); }
  2934. // DIRECTIONALITY
  2935. if (preg_match("/([".$this->pregRTLchars."])/u", $txt)) { $this->biDirectional = true; } // *RTL*
  2936. $this->magic_reverse_dir($txt, true, $this->directionality); // *RTL*
  2937. // Font-specific ligature substitution for Indic fonts
  2938. if (isset($this->CurrentFont['indic']) && $this->CurrentFont['indic']) $this->ConvertIndic($txt); // *INDIC*
  2939. $this->Cell($w,$h,$txt,$border,$ln,$align,$fill,$link, $currentx);
  2940. }
  2941. /*-- END DIRECTW --*/
  2942. function ResetSpacing() {
  2943. if ($this->ws != 0) { $this->_out('BT 0 Tw ET'); }
  2944. $this->ws=0;
  2945. if ($this->charspacing != 0) { $this->_out('BT 0 Tc ET'); }
  2946. $this->charspacing=0;
  2947. }
  2948. function SetSpacing($cs,$ws) {
  2949. if (intval($cs*1000)==0) { $cs = 0; }
  2950. if ($cs) { $this->_out(sprintf('BT %.3F Tc ET',$cs)); }
  2951. else if ($this->charspacing != 0) { $this->_out('BT 0 Tc ET'); }
  2952. $this->charspacing=$cs;
  2953. if (intval($ws*1000)==0) { $ws = 0; }
  2954. if ($ws) { $this->_out(sprintf('BT %.3F Tw ET',$ws)); }
  2955. else if ($this->ws != 0) { $this->_out('BT 0 Tw ET'); }
  2956. $this->ws=$ws;
  2957. }
  2958. // WORD SPACING
  2959. function GetJspacing($nc,$ns,$w,$inclCursive) {
  2960. $ws = 0;
  2961. $charspacing = 0;
  2962. $ww = $this->jSWord;
  2963. $ncx = $nc-1;
  2964. if ($nc == 0) { return array(0,0); }
  2965. else if ($nc==1) { $charspacing = $w; }
  2966. // Only word spacing allowed / possible
  2967. else if ($this->fixedlSpacing !== false || $inclCursive) {
  2968. if ($ns) { $ws = $w / $ns; }
  2969. }
  2970. else if (!$ns) {
  2971. $charspacing = $w / ($ncx );
  2972. if (($this->jSmaxChar > 0) && ($charspacing > $this->jSmaxChar)) {
  2973. $charspacing = $this->jSmaxChar;
  2974. }
  2975. }
  2976. else if ($ns == ($ncx )) {
  2977. $charspacing = $w / $ns;
  2978. }
  2979. else {
  2980. if ($this->usingCoreFont) {
  2981. $cs = ($w * (1 - $this->jSWord)) / ($ncx );
  2982. if (($this->jSmaxChar > 0) && ($cs > $this->jSmaxChar)) {
  2983. $cs = $this->jSmaxChar;
  2984. $ww = 1 - (($cs * ($ncx ))/$w);
  2985. }
  2986. $charspacing = $cs;
  2987. $ws = ($w * ($ww) ) / $ns;
  2988. }
  2989. else {
  2990. $cs = ($w * (1 - $this->jSWord)) / ($ncx -$ns);
  2991. if (($this->jSmaxChar > 0) && ($cs > $this->jSmaxChar)) {
  2992. $cs = $this->jSmaxChar;
  2993. $ww = 1 - (($cs * ($ncx -$ns))/$w);
  2994. }
  2995. $charspacing = $cs;
  2996. $ws = (($w * ($ww) ) / $ns) - $charspacing;
  2997. }
  2998. }
  2999. return array($charspacing,$ws);
  3000. }
  3001. function Cell($w,$h=0,$txt='',$border=0,$ln=0,$align='',$fill=0,$link='', $currentx=0, $lcpaddingL=0, $lcpaddingR=0, $valign='M', $spanfill=0, $abovefont=0, $belowfont=0, $exactWidth=false) {
  3002. //Output a cell
  3003. // Expects input to be mb_encoded if necessary and RTL reversed
  3004. // NON_BREAKING SPACE
  3005. if ($this->usingCoreFont) {
  3006. $txt = str_replace(chr(160),chr(32),$txt);
  3007. }
  3008. else {
  3009. $txt = str_replace(chr(194).chr(160),chr(32),$txt);
  3010. }
  3011. $oldcolumn = $this->CurrCol;
  3012. // Automatic page break
  3013. // Allows PAGE-BREAK-AFTER = avoid to work
  3014. if (!$this->tableLevel && (($this->y+$this->divheight>$this->PageBreakTrigger) || ($this->y+$h>$this->PageBreakTrigger) ||
  3015. ($this->y+($h*2)>$this->PageBreakTrigger && $this->blk[$this->blklvl]['page_break_after_avoid'])) and !$this->InFooter and $this->AcceptPageBreak()) {
  3016. $x=$this->x;//Current X position
  3017. // WORD SPACING
  3018. $ws=$this->ws;//Word Spacing
  3019. $charspacing=$this->charspacing;//Character Spacing
  3020. $this->ResetSpacing();
  3021. $this->AddPage($this->CurOrientation);
  3022. // Added to correct for OddEven Margins
  3023. $x += $this->MarginCorrection;
  3024. if ($currentx) {
  3025. $currentx += $this->MarginCorrection;
  3026. }
  3027. $this->x=$x;
  3028. // WORD SPACING
  3029. $this->SetSpacing($charspacing,$ws);
  3030. }
  3031. // Test: to put line through centre of cell: $this->Line($this->x,$this->y+($h/2),$this->x+50,$this->y+($h/2));
  3032. /*-- COLUMNS --*/
  3033. // COLS
  3034. // COLUMN CHANGE
  3035. if ($this->CurrCol != $oldcolumn) {
  3036. if ($currentx) {
  3037. $currentx += $this->ChangeColumn * ($this->ColWidth+$this->ColGap);
  3038. }
  3039. $this->x += $this->ChangeColumn * ($this->ColWidth+$this->ColGap);
  3040. }
  3041. // COLUMNS Update/overwrite the lowest bottom of printing y value for a column
  3042. if ($this->ColActive) {
  3043. if ($h) { $this->ColDetails[$this->CurrCol]['bottom_margin'] = $this->y+$h; }
  3044. else { $this->ColDetails[$this->CurrCol]['bottom_margin'] = $this->y+$this->divheight; }
  3045. }
  3046. /*-- END COLUMNS --*/
  3047. // KEEP BLOCK TOGETHER Update/overwrite the lowest bottom of printing y value on first page
  3048. if ($this->keep_block_together) {
  3049. if ($h) { $this->ktBlock[$this->page]['bottom_margin'] = $this->y+$h; }
  3050. // else { $this->ktBlock[$this->page]['bottom_margin'] = $this->y+$this->divheight; }
  3051. }
  3052. if($w==0) $w = $this->w-$this->rMargin-$this->x;
  3053. $s='';
  3054. if($fill==1 && $this->FillColor) {
  3055. if((isset($this->pageoutput[$this->page]['FillColor']) && $this->pageoutput[$this->page]['FillColor'] != $this->FillColor) || !isset($this->pageoutput[$this->page]['FillColor']) || $this->keep_block_together) { $s .= $this->FillColor.' '; }
  3056. $this->pageoutput[$this->page]['FillColor'] = $this->FillColor;
  3057. }
  3058. $boxtop = $this->y;
  3059. $boxheight = $h;
  3060. $boxbottom = $this->y+$h;
  3061. if($txt!='') {
  3062. // FONT SIZE - this determines the baseline caculation
  3063. if ($this->linemaxfontsize && !$this->processingHeader) { $bfs = $this->linemaxfontsize; }
  3064. else { $bfs = $this->FontSize; }
  3065. //Calculate baseline Superscript and Subscript Y coordinate adjustment
  3066. $bfx = $this->baselineC;
  3067. $baseline = $bfx*$bfs;
  3068. if($this->SUP) { $baseline += ($bfx-1.05)*$this->FontSize; }
  3069. else if($this->SUB) { $baseline += ($bfx + 0.04)*$this->FontSize; }
  3070. else if($this->bullet) { $baseline += ($bfx-0.7)*$this->FontSize; }
  3071. // Vertical align (for Images)
  3072. if ($abovefont || $belowfont) { // from flowing block - valign always M
  3073. $va = $abovefont + (0.5*$bfs);
  3074. }
  3075. else if ($this->lineheight_correction) {
  3076. if ($valign == 'T') { $va = (0.5 * $bfs * $this->lineheight_correction); }
  3077. else if ($valign == 'B') { $va = $h-(0.5 * $bfs * $this->lineheight_correction); }
  3078. else { $va = 0.5*$h; } // Middle
  3079. }
  3080. else {
  3081. if ($valign == 'T') { $va = (0.5 * $bfs * $this->default_lineheight_correction); }
  3082. else if ($valign == 'B') { $va = $h-(0.5 * $bfs * $this->default_lineheight_correction); }
  3083. else { $va = 0.5*$h; } // Middle
  3084. }
  3085. // ONLY SET THESE IF WANT TO CONFINE BORDER +/- FILL TO FIT FONTSIZE - NOT FULL CELL AS IS ORIGINAL FUNCTION
  3086. // spanfill or spanborder are set in FlowingBlock functions
  3087. if ($spanfill || !empty($this->spanborddet) || $link!='') {
  3088. $exth = 0.2; // Add to fontsize to increase height of background / link / border
  3089. $boxtop = $this->y+$baseline+$va-($this->FontSize*(1+$exth/2)*(0.5+$bfx));
  3090. $boxheight = $this->FontSize * (1+$exth);
  3091. $boxbottom = $boxtop + $boxheight;
  3092. }
  3093. }
  3094. $bbw = $tbw = $lbw = $rbw = 0; // Border widths
  3095. if (!empty($this->spanborddet)) {
  3096. if (!isset($this->spanborddet['B'])) { $this->spanborddet['B'] = array('s' => 0, 'style' => '', 'w' => 0); }
  3097. if (!isset($this->spanborddet['T'])) { $this->spanborddet['T'] = array('s' => 0, 'style' => '', 'w' => 0); }
  3098. if (!isset($this->spanborddet['L'])) { $this->spanborddet['L'] = array('s' => 0, 'style' => '', 'w' => 0); }
  3099. if (!isset($this->spanborddet['R'])) { $this->spanborddet['R'] = array('s' => 0, 'style' => '', 'w' => 0); }
  3100. $bbw = $this->spanborddet['B']['w'];
  3101. $tbw = $this->spanborddet['T']['w'];
  3102. $lbw = $this->spanborddet['L']['w'];
  3103. $rbw = $this->spanborddet['R']['w'];
  3104. }
  3105. if($fill==1 || $border==1 || !empty($this->spanborddet)) {
  3106. if (!empty($this->spanborddet)) {
  3107. if ($fill==1) {
  3108. $s.=sprintf('%.3F %.3F %.3F %.3F re f ',($this->x-$lbw)*_MPDFK,($this->h-$boxtop+$tbw)*_MPDFK,($w+$lbw+$rbw)*_MPDFK,(-$boxheight-$tbw-$bbw)*_MPDFK);
  3109. }
  3110. $s.= ' q ';
  3111. $dashon = 3;
  3112. $dashoff = 3.5;
  3113. $dot = 2.5;
  3114. if($tbw) {
  3115. $short = 0;
  3116. if ($this->spanborddet['T']['style'] == 'dashed') {
  3117. $s.=sprintf(' 0 j 0 J [%.3F %.3F] 0 d ',$tbw*$dashon*_MPDFK,$tbw*$dashoff*_MPDFK);
  3118. }
  3119. else if ($this->spanborddet['T']['style'] == 'dotted') {
  3120. $s.=sprintf(' 1 j 1 J [%.3F %.3F] %.3F d ',0.001,$tbw*$dot*_MPDFK,-$tbw/2*_MPDFK);
  3121. $short = $tbw/2;
  3122. }
  3123. else {
  3124. $s.=' 0 j 0 J [] 0 d ';
  3125. }
  3126. $c = $this->SetDColor($this->spanborddet['T']['c'],true);
  3127. if ($this->spanborddet['T']['style'] == 'double') {
  3128. $s.=sprintf(' %s %.3F w ',$c,$tbw/3*_MPDFK);
  3129. $xadj = $xadj2 = 0;
  3130. if ($this->spanborddet['L']['style'] == 'double') { $xadj = $this->spanborddet['L']['w']*2/3; }
  3131. if ($this->spanborddet['R']['style'] == 'double') { $xadj2 = $this->spanborddet['R']['w']*2/3; }
  3132. $s.=sprintf('%.3F %.3F m %.3F %.3F l S ',($this->x-$lbw)*_MPDFK,($this->h-$boxtop+$tbw*5/6)*_MPDFK,($this->x+$w+$rbw-$short)*_MPDFK,($this->h-$boxtop+$tbw*5/6)*_MPDFK);
  3133. $s.=sprintf('%.3F %.3F m %.3F %.3F l S ',($this->x-$lbw+$xadj)*_MPDFK,($this->h-$boxtop+$tbw/6)*_MPDFK,($this->x+$w+$rbw-$short-$xadj2)*_MPDFK,($this->h-$boxtop+$tbw/6)*_MPDFK);
  3134. }
  3135. else {
  3136. $s.=sprintf(' %s %.3F w ',$c,$tbw*_MPDFK);
  3137. $s.=sprintf('%.3F %.3F m %.3F %.3F l S ',($this->x-$lbw)*_MPDFK,($this->h-$boxtop+$tbw/2)*_MPDFK,($this->x+$w+$rbw-$short)*_MPDFK,($this->h-$boxtop+$tbw/2)*_MPDFK);
  3138. }
  3139. }
  3140. if($bbw) {
  3141. $short = 0;
  3142. if ($this->spanborddet['B']['style'] == 'dashed') {
  3143. $s.=sprintf(' 0 j 0 J [%.3F %.3F] 0 d ',$bbw*$dashon*_MPDFK,$bbw*$dashoff*_MPDFK);
  3144. }
  3145. else if ($this->spanborddet['B']['style'] == 'dotted') {
  3146. $s.=sprintf(' 1 j 1 J [%.3F %.3F] %.3F d ',0.001,$bbw*$dot*_MPDFK,-$bbw/2*_MPDFK);
  3147. $short = $bbw/2;
  3148. }
  3149. else {
  3150. $s.=' 0 j 0 J [] 0 d ';
  3151. }
  3152. $c = $this->SetDColor($this->spanborddet['B']['c'],true);
  3153. if ($this->spanborddet['B']['style'] == 'double') {
  3154. $s.=sprintf(' %s %.3F w ',$c,$bbw/3*_MPDFK);
  3155. $xadj = $xadj2 = 0;
  3156. if ($this->spanborddet['L']['style'] == 'double') { $xadj = $this->spanborddet['L']['w']*2/3; }
  3157. if ($this->spanborddet['R']['style'] == 'double') { $xadj2 = $this->spanborddet['R']['w']*2/3; }
  3158. $s.=sprintf('%.3F %.3F m %.3F %.3F l S ',($this->x-$lbw+$xadj)*_MPDFK,($this->h-$boxbottom-$bbw/6)*_MPDFK,($this->x+$w+$rbw-$short-$xadj2)*_MPDFK,($this->h-$boxbottom-$bbw/6)*_MPDFK);
  3159. $s.=sprintf('%.3F %.3F m %.3F %.3F l S ',($this->x-$lbw)*_MPDFK,($this->h-$boxbottom-$bbw*5/6)*_MPDFK,($this->x+$w+$rbw-$short)*_MPDFK,($this->h-$boxbottom-$bbw*5/6)*_MPDFK);
  3160. }
  3161. else {
  3162. $s.=sprintf(' %s %.3F w ',$c,$bbw*_MPDFK);
  3163. $s.=sprintf('%.3F %.3F m %.3F %.3F l S ',($this->x-$lbw)*_MPDFK,($this->h-$boxbottom-$bbw/2)*_MPDFK,($this->x+$w+$rbw-$short)*_MPDFK,($this->h-$boxbottom-$bbw/2)*_MPDFK);
  3164. }
  3165. }
  3166. if($lbw) {
  3167. $short = 0;
  3168. if ($this->spanborddet['L']['style'] == 'dashed') {
  3169. $s.=sprintf(' 0 j 0 J [%.3F %.3F] 0 d ',$lbw*$dashon*_MPDFK,$lbw*$dashoff*_MPDFK);
  3170. }
  3171. else if ($this->spanborddet['L']['style'] == 'dotted') {
  3172. $s.=sprintf(' 1 j 1 J [%.3F %.3F] %.3F d ',0.001,$lbw*$dot*_MPDFK,-$lbw/2*_MPDFK);
  3173. $short = $lbw/2;
  3174. }
  3175. else {
  3176. $s.=' 0 j 0 J [] 0 d ';
  3177. }
  3178. $c = $this->SetDColor($this->spanborddet['L']['c'],true);
  3179. if ($this->spanborddet['L']['style'] == 'double') {
  3180. $s.=sprintf(' %s %.3F w ',$c,$lbw/3*_MPDFK);
  3181. $yadj = $yadj2 = 0;
  3182. if ($this->spanborddet['T']['style'] == 'double') { $yadj = $this->spanborddet['T']['w']*2/3; }
  3183. if ($this->spanborddet['B']['style'] == 'double') { $yadj2 = $this->spanborddet['B']['w']*2/3; }
  3184. $s.=sprintf('%.3F %.3F m %.3F %.3F l S ',($this->x-$lbw/6)*_MPDFK,($this->h-$boxtop+$tbw-$yadj)*_MPDFK,($this->x-$lbw/6)*_MPDFK,($this->h-$boxbottom-$bbw+$short+$yadj2)*_MPDFK);
  3185. $s.=sprintf('%.3F %.3F m %.3F %.3F l S ',($this->x-$lbw*5/6)*_MPDFK,($this->h-$boxtop+$tbw)*_MPDFK,($this->x-$lbw*5/6)*_MPDFK,($this->h-$boxbottom-$bbw+$short)*_MPDFK);
  3186. }
  3187. else {
  3188. $s.=sprintf(' %s %.3F w ',$c,$lbw*_MPDFK);
  3189. $s.=sprintf('%.3F %.3F m %.3F %.3F l S ',($this->x-$lbw/2)*_MPDFK,($this->h-$boxtop+$tbw)*_MPDFK,($this->x-$lbw/2)*_MPDFK,($this->h-$boxbottom-$bbw+$short)*_MPDFK);
  3190. }
  3191. }
  3192. if($rbw) {
  3193. $short = 0;
  3194. if ($this->spanborddet['R']['style'] == 'dashed') {
  3195. $s.=sprintf(' 0 j 0 J [%.3F %.3F] 0 d ',$rbw*$dashon*_MPDFK,$rbw*$dashoff*_MPDFK);
  3196. }
  3197. else if ($this->spanborddet['R']['style'] == 'dotted') {
  3198. $s.=sprintf(' 1 j 1 J [%.3F %.3F] %.3F d ',0.001,$rbw*$dot*_MPDFK,-$rbw/2*_MPDFK);
  3199. $short = $rbw/2;
  3200. }
  3201. else {
  3202. $s.=' 0 j 0 J [] 0 d ';
  3203. }
  3204. $c = $this->SetDColor($this->spanborddet['R']['c'],true);
  3205. if ($this->spanborddet['R']['style'] == 'double') {
  3206. $s.=sprintf(' %s %.3F w ',$c,$rbw/3*_MPDFK);
  3207. $yadj = $yadj2 = 0;
  3208. if ($this->spanborddet['T']['style'] == 'double') { $yadj = $this->spanborddet['T']['w']*2/3; }
  3209. if ($this->spanborddet['B']['style'] == 'double') { $yadj2 = $this->spanborddet['B']['w']*2/3; }
  3210. $s.=sprintf('%.3F %.3F m %.3F %.3F l S ',($this->x+$w+$rbw/6)*_MPDFK,($this->h-$boxtop+$tbw-$yadj)*_MPDFK,($this->x+$w+$rbw/6)*_MPDFK,($this->h-$boxbottom-$bbw+$short+$yadj2)*_MPDFK);
  3211. $s.=sprintf('%.3F %.3F m %.3F %.3F l S ',($this->x+$w+$rbw*5/6)*_MPDFK,($this->h-$boxtop+$tbw)*_MPDFK,($this->x+$w+$rbw*5/6)*_MPDFK,($this->h-$boxbottom-$bbw+$short)*_MPDFK);
  3212. }
  3213. else {
  3214. $s.=sprintf(' %s %.3F w ',$c,$rbw*_MPDFK);
  3215. $s.=sprintf('%.3F %.3F m %.3F %.3F l S ',($this->x+$w+$rbw/2)*_MPDFK,($this->h-$boxtop+$tbw)*_MPDFK,($this->x+$w+$rbw/2)*_MPDFK,($this->h-$boxbottom-$bbw+$short)*_MPDFK);
  3216. }
  3217. }
  3218. $s.= ' Q ';
  3219. }
  3220. else {
  3221. if ($fill==1) $op=($border==1) ? 'B' : 'f';
  3222. else $op='S';
  3223. $s.=sprintf('%.3F %.3F %.3F %.3F re %s ',$this->x*_MPDFK,($this->h-$boxtop)*_MPDFK,$w*_MPDFK,-$boxheight*_MPDFK,$op);
  3224. }
  3225. }
  3226. if(is_string($border)) {
  3227. $x=$this->x;
  3228. $y=$this->y;
  3229. if(is_int(strpos($border,'L')))
  3230. $s.=sprintf('%.3F %.3F m %.3F %.3F l S ',$x*_MPDFK,($this->h-$boxtop)*_MPDFK,$x*_MPDFK,($this->h-($boxbottom))*_MPDFK);
  3231. if(is_int(strpos($border,'T')))
  3232. $s.=sprintf('%.3F %.3F m %.3F %.3F l S ',$x*_MPDFK,($this->h-$boxtop)*_MPDFK,($x+$w)*_MPDFK,($this->h-$boxtop)*_MPDFK);
  3233. if(is_int(strpos($border,'R')))
  3234. $s.=sprintf('%.3F %.3F m %.3F %.3F l S ',($x+$w)*_MPDFK,($this->h-$boxtop)*_MPDFK,($x+$w)*_MPDFK,($this->h-($boxbottom))*_MPDFK);
  3235. if(is_int(strpos($border,'B')))
  3236. $s.=sprintf('%.3F %.3F m %.3F %.3F l S ',$x*_MPDFK,($this->h-($boxbottom))*_MPDFK,($x+$w)*_MPDFK,($this->h-($boxbottom))*_MPDFK);
  3237. }
  3238. if($txt!='') {
  3239. if ($exactWidth)
  3240. $stringWidth = $w;
  3241. else
  3242. $stringWidth = $this->GetStringWidth($txt) + ( $this->charspacing * mb_strlen( $txt, $this->mb_enc ) / _MPDFK )
  3243. + ( $this->ws * mb_substr_count( $txt, ' ', $this->mb_enc ) / _MPDFK );
  3244. // Set x OFFSET FOR PRINTING
  3245. if($align=='R') {
  3246. $dx=$w-$this->cMarginR - $stringWidth - $lcpaddingR;
  3247. }
  3248. elseif($align=='C') {
  3249. $dx=(($w - $stringWidth )/2);
  3250. }
  3251. elseif($align=='L' or $align=='J') $dx=$this->cMarginL + $lcpaddingL;
  3252. else $dx = 0;
  3253. if($this->ColorFlag) $s .='q '.$this->TextColor.' ';
  3254. // OUTLINE
  3255. if($this->outline_on && !$this->S) {
  3256. $s .=' '.sprintf('%.3F w',$this->LineWidth*_MPDFK).' ';
  3257. $s .=" $this->DrawColor ";
  3258. $s .=" 2 Tr ";
  3259. }
  3260. else if ($this->falseBoldWeight && strpos($this->ReqFontStyle,"B") !== false && strpos($this->FontStyle,"B") === false && !$this->S) { // can't use together with OUTLINE or Small Caps
  3261. $s .= ' 2 Tr 1 J 1 j ';
  3262. $s .= ' '.sprintf('%.3F w',($this->FontSize/130)*_MPDFK*$this->falseBoldWeight).' ';
  3263. $tc = strtoupper($this->TextColor); // change 0 0 0 rg to 0 0 0 RG
  3264. if($this->FillColor!=$tc) { $s .= ' '.$tc.' '; } // stroke (outline) = same colour as text(fill)
  3265. }
  3266. if (strpos($this->ReqFontStyle,"I") !== false && strpos($this->FontStyle,"I") === false) { // Artificial italic
  3267. $aix = '1 0 0.261799 1 %.3F %.3F Tm ';
  3268. }
  3269. else { $aix = '%.3F %.3F Td '; }
  3270. // THE TEXT
  3271. $sub = '';
  3272. $this->CurrentFont['used']= true;
  3273. // WORD SPACING
  3274. // IF multibyte - Tw has no effect - need to use alternative method - do word spacing using an adjustment before each space
  3275. if ($this->ws && !$this->usingCoreFont && !$this->CurrentFont['sip'] && !$this->CurrentFont['smp'] && !$this->S) {
  3276. $sub .= ' BT 0 Tw ET ';
  3277. if ($this->kerning && $this->useKerning) { $sub .= $this->_kern($txt, 'MBTw', $aix, ($this->x+$dx), ($this->y+$baseline+$va)); }
  3278. else {
  3279. $space = " ";
  3280. //Convert string to UTF-16BE without BOM
  3281. $space= $this->UTF8ToUTF16BE($space , false);
  3282. $space=$this->_escape($space );
  3283. $sub .=sprintf('BT '.$aix,($this->x+$dx)*_MPDFK,($this->h-($this->y+$baseline+$va))*_MPDFK);
  3284. $t = explode(' ',$txt);
  3285. $sub .=sprintf(' %.3F Tc [',$this->charspacing);
  3286. $numt = count($t);
  3287. for($i=0;$i<$numt;$i++) {
  3288. $tx = $t[$i];
  3289. //Convert string to UTF-16BE without BOM
  3290. $tx = $this->UTF8ToUTF16BE($tx , false);
  3291. $tx = $this->_escape($tx);
  3292. $sub .=sprintf('(%s) ',$tx);
  3293. if (($i+1)<$numt) {
  3294. $adj = -($this->ws)*1000/$this->FontSizePt;
  3295. $sub .=sprintf('%d(%s) ',$adj,$space);
  3296. }
  3297. }
  3298. $sub .='] TJ ';
  3299. $sub .=' ET';
  3300. }
  3301. }
  3302. else {
  3303. $txt2= $txt;
  3304. if ($this->CurrentFont['type']=='TTF' && ($this->CurrentFont['sip'] || $this->CurrentFont['smp'])) {
  3305. if ($this->S) { $sub .= $this->_smallCaps($txt2, 'SIPSMP', $aix, $dx, _MPDFK, $baseline, $va); }
  3306. else {
  3307. $txt2 = $this->UTF8toSubset($txt2);
  3308. $sub .=sprintf('BT '.$aix.' %s Tj ET',($this->x+$dx)*_MPDFK,($this->h-($this->y+$baseline+$va))*_MPDFK,$txt2);
  3309. }
  3310. }
  3311. else {
  3312. if ($this->S) { $sub .= $this->_smallCaps($txt2, '', $aix, $dx, _MPDFK, $baseline, $va); }
  3313. else if ($this->kerning && $this->useKerning) { $sub .= $this->_kern($txt2, '', $aix, ($this->x+$dx), ($this->y+$baseline+$va)); }
  3314. else {
  3315. if (!$this->usingCoreFont) {
  3316. $txt2 = $this->UTF8ToUTF16BE($txt2, false);
  3317. }
  3318. $txt2=$this->_escape($txt2);
  3319. $sub .=sprintf('BT '.$aix.' (%s) Tj ET',($this->x+$dx)*_MPDFK,($this->h-($this->y+$baseline+$va))*_MPDFK,$txt2);
  3320. }
  3321. }
  3322. }
  3323. // UNDERLINE
  3324. if($this->U) {
  3325. $c = strtoupper($this->TextColor); // change 0 0 0 rg to 0 0 0 RG
  3326. if($this->FillColor!=$c) { $sub .= ' '.$c.' '; }
  3327. if (isset($this->CurrentFont['up'])) { $up=$this->CurrentFont['up']; }
  3328. else { $up = -100; }
  3329. $adjusty = (-$up/1000* $this->FontSize);
  3330. if (isset($this->CurrentFont['ut'])) { $ut=$this->CurrentFont['ut']/1000* $this->FontSize; }
  3331. else { $ut = 60/1000* $this->FontSize; }
  3332. $olw = $this->LineWidth;
  3333. $sub .=' '.(sprintf(' %.3F w 0 j 0 J ',$ut*_MPDFK));
  3334. $sub .=' '.$this->_dounderline($this->x+$dx,$this->y+$baseline+$va+$adjusty,$txt);
  3335. $sub .=' '.(sprintf(' %.3F w 2 j 2 J ',$olw*_MPDFK));
  3336. if($this->FillColor!=$c) { $sub .= ' '.$this->FillColor.' '; }
  3337. }
  3338. // STRIKETHROUGH
  3339. if($this->strike) {
  3340. $c = strtoupper($this->TextColor); // change 0 0 0 rg to 0 0 0 RG
  3341. if($this->FillColor!=$c) { $sub .= ' '.$c.' '; }
  3342. //Superscript and Subscript Y coordinate adjustment (now for striked-through texts)
  3343. if (isset($this->CurrentFont['desc']['CapHeight'])) { $ch=$this->CurrentFont['desc']['CapHeight']; }
  3344. else { $ch = 700; }
  3345. $adjusty = (-$ch/1000* $this->FontSize) * 0.35;
  3346. if (isset($this->CurrentFont['ut'])) { $ut=$this->CurrentFont['ut']/1000* $this->FontSize; }
  3347. else { $ut = 60/1000* $this->FontSize; }
  3348. $olw = $this->LineWidth;
  3349. $sub .=' '.(sprintf(' %.3F w 0 j 0 J ',$ut*_MPDFK));
  3350. $sub .=' '.$this->_dounderline($this->x+$dx,$this->y+$baseline+$va+$adjusty,$txt);
  3351. $sub .=' '.(sprintf(' %.3F w 2 j 2 J ',$olw*_MPDFK));
  3352. if($this->FillColor!=$c) { $sub .= ' '.$this->FillColor.' '; }
  3353. }
  3354. // TEXT SHADOW
  3355. if ($this->textshadow) { // First to process is last in CSS comma separated shadows
  3356. foreach($this->textshadow AS $ts) {
  3357. $s .= ' q ';
  3358. $s .= $this->SetTColor($ts['col'], true)."\n";
  3359. if ($ts['col']{0}==5 && ord($ts['col']{4})<100) { // RGBa
  3360. $s .= $this->SetAlpha(ord($ts['col']{4})/100, 'Normal', true, 'F')."\n";
  3361. }
  3362. else if ($ts['col']{0}==6 && ord($ts['col']{5})<100) { // CMYKa
  3363. $s .= $this->SetAlpha(ord($ts['col']{5})/100, 'Normal', true, 'F')."\n";
  3364. }
  3365. else if ($ts['col']{0}==1 && $ts['col']{2}==1 && ord($ts['col']{3})<100) { // Gray
  3366. $s .= $this->SetAlpha(ord($ts['col']{3})/100, 'Normal', true, 'F')."\n";
  3367. }
  3368. $s .= sprintf(' 1 0 0 1 %.4F %.4F cm', $ts['x']*_MPDFK, -$ts['y']*_MPDFK)."\n";
  3369. $s .= $sub;
  3370. $s .= ' Q ';
  3371. }
  3372. }
  3373. $s .= $sub;
  3374. // COLOR
  3375. if($this->ColorFlag) $s .=' Q';
  3376. // LINK
  3377. if($link!='') {
  3378. $this->Link($this->x,$boxtop,$w,$boxheight,$link);
  3379. }
  3380. }
  3381. if($s) $this->_out($s);
  3382. // WORD SPACING
  3383. if ($this->ws && !$this->usingCoreFont) {
  3384. $this->_out(sprintf('BT %.3F Tc ET',$this->charspacing));
  3385. }
  3386. $this->lasth=$h;
  3387. if( strpos($txt,"\n") !== false) $ln=1; // cell recognizes \n from <BR> tag
  3388. if($ln>0)
  3389. {
  3390. //Go to next line
  3391. $this->y += $h;
  3392. if($ln==1) {
  3393. //Move to next line
  3394. if ($currentx != 0) { $this->x=$currentx; }
  3395. else { $this->x=$this->lMargin; }
  3396. }
  3397. }
  3398. else $this->x+=$w;
  3399. }
  3400. function _kern($txt, $mode, $aix, $x, $y) {
  3401. if ($mode == 'MBTw') { // Multibyte requiring word spacing
  3402. $space = ' ';
  3403. //Convert string to UTF-16BE without BOM
  3404. $space= $this->UTF8ToUTF16BE($space , false);
  3405. $space=$this->_escape($space );
  3406. $s = sprintf(' BT '.$aix,$x*_MPDFK,($this->h-$y)*_MPDFK);
  3407. $t = explode(' ',$txt);
  3408. for($i=0;$i<count($t);$i++) {
  3409. $tx = $t[$i];
  3410. $tj = '(';
  3411. $unicode = $this->UTF8StringToArray($tx);
  3412. for($ti=0;$ti<count($unicode);$ti++) {
  3413. if ($ti > 0 && isset($this->CurrentFont['kerninfo'][$unicode[($ti-1)]][$unicode[$ti]])) {
  3414. $kern = -$this->CurrentFont['kerninfo'][$unicode[($ti-1)]][$unicode[$ti]];
  3415. $tj .= sprintf(')%d(',$kern);
  3416. }
  3417. $tc = code2utf($unicode[$ti]);
  3418. $tc = $this->UTF8ToUTF16BE($tc, false);
  3419. $tj .= $this->_escape($tc);
  3420. }
  3421. $tj .= ')';
  3422. $s.=sprintf(' %.3F Tc [%s] TJ',$this->charspacing,$tj);
  3423. if (($i+1)<count($t)) {
  3424. $s.=sprintf(' %.3F Tc (%s) Tj',$this->ws+$this->charspacing,$space);
  3425. }
  3426. }
  3427. $s.=' ET ';
  3428. }
  3429. else if (!$this->usingCoreFont) {
  3430. $s = '';
  3431. $tj = '(';
  3432. $unicode = $this->UTF8StringToArray($txt);
  3433. for($i=0;$i<count($unicode);$i++) {
  3434. if ($i > 0 && isset($this->CurrentFont['kerninfo'][$unicode[($i-1)]][$unicode[$i]])) {
  3435. $kern = -$this->CurrentFont['kerninfo'][$unicode[($i-1)]][$unicode[$i]];
  3436. $tj .= sprintf(')%d(',$kern);
  3437. }
  3438. $tx = code2utf($unicode[$i]);
  3439. $tx = $this->UTF8ToUTF16BE($tx, false);
  3440. $tj .= $this->_escape($tx);
  3441. }
  3442. $tj .= ')';
  3443. $s.=sprintf(' BT '.$aix.' [%s] TJ ET ',$x*_MPDFK,($this->h-$y)*_MPDFK,$tj);
  3444. }
  3445. else { // CORE Font
  3446. $s = '';
  3447. $tj = '(';
  3448. $l = strlen($txt);
  3449. for($i=0;$i<$l;$i++) {
  3450. if ($i > 0 && isset($this->CurrentFont['kerninfo'][$txt[($i-1)]][$txt[$i]])) {
  3451. $kern = -$this->CurrentFont['kerninfo'][$txt[($i-1)]][$txt[$i]];
  3452. $tj .= sprintf(')%d(',$kern);
  3453. }
  3454. $tj .= $this->_escape($txt[$i]);
  3455. }
  3456. $tj .= ')';
  3457. $s.=sprintf(' BT '.$aix.' [%s] TJ ET ',$x*_MPDFK,($this->h-$y)*_MPDFK,$tj);
  3458. }
  3459. return $s;
  3460. }
  3461. function _smallCaps($txt, $mode, $aix, $dx, $k, $baseline, $va) {
  3462. $upp = false;
  3463. $str = array();
  3464. $bits = array();
  3465. if (!$this->usingCoreFont) {
  3466. $unicode = $this->UTF8StringToArray($txt);
  3467. foreach($unicode as $char) {
  3468. if ($this->ws && $char == 32) { // space
  3469. if (count($str)) { $bits[] = array($upp, $str, false); }
  3470. $bits[] = array(false, array(32), true);
  3471. $str = array();
  3472. $upp = false;
  3473. }
  3474. else if (isset($this->upperCase[$char])) {
  3475. if (!$upp) {
  3476. if (count($str)) { $bits[] = array($upp, $str, false); }
  3477. $str = array();
  3478. }
  3479. $str[] = $this->upperCase[$char];
  3480. if ((!isset($this->CurrentFont['sip']) || !$this->CurrentFont['sip']) && (!isset($this->CurrentFont['smp']) || !$this->CurrentFont['smp'])) {
  3481. $this->CurrentFont['subset'][$this->upperCase[$char]] = $this->upperCase[$char];
  3482. }
  3483. $upp = true;
  3484. }
  3485. else {
  3486. if ($upp) {
  3487. if (count($str)) { $bits[] = array($upp, $str, false); }
  3488. $str = array();
  3489. }
  3490. $str[] = $char;
  3491. $upp = false;
  3492. }
  3493. }
  3494. }
  3495. else {
  3496. for($i=0;$i<strlen($txt);$i++) {
  3497. if (isset($this->upperCase[ord($txt[$i])]) && $this->upperCase[ord($txt[$i])] < 256) {
  3498. if (!$upp) {
  3499. if (count($str)) { $bits[] = array($upp, $str, false); }
  3500. $str = array();
  3501. }
  3502. $str[] = $this->upperCase[ord($txt[$i])];
  3503. $upp = true;
  3504. }
  3505. else {
  3506. if ($upp) {
  3507. if (count($str)) { $bits[] = array($upp, $str, false); }
  3508. $str = array();
  3509. }
  3510. $str[] = ord($txt[$i]);
  3511. $upp = false;
  3512. }
  3513. }
  3514. }
  3515. if (count($str)) { $bits[] = array($upp, $str, false); }
  3516. $fid = $this->CurrentFont['i'];
  3517. $s=sprintf(' BT '.$aix,($this->x+$dx)*$k,($this->h-($this->y+$baseline+$va))*$k);
  3518. foreach($bits AS $b) {
  3519. if ($b[0]) { $upp = true; }
  3520. else { $upp = false; }
  3521. $size = count ($b[1]);
  3522. $txt = '';
  3523. for ($i = 0; $i < $size; $i++) {
  3524. $txt .= code2utf($b[1][$i]);
  3525. }
  3526. if ($this->usingCoreFont) {
  3527. $txt = utf8_decode($txt);
  3528. }
  3529. if ($mode == 'SIPSMP') {
  3530. $txt = $this->UTF8toSubset($txt);
  3531. }
  3532. else {
  3533. if (!$this->usingCoreFont) {
  3534. $txt = $this->UTF8ToUTF16BE($txt, false);
  3535. }
  3536. $txt=$this->_escape($txt);
  3537. $txt = '('.$txt.')';
  3538. }
  3539. if ($b[2]) { // space
  3540. $s.=sprintf(' /F%d %.3F Tf %d Tz', $fid, $this->FontSizePt, 100);
  3541. $s.=sprintf(' %.3F Tc', ($this->charspacing+$this->ws));
  3542. $s.=sprintf(' %s Tj', $txt);
  3543. }
  3544. else if ($upp) {
  3545. $s.=sprintf(' /F%d %.3F Tf', $fid, $this->FontSizePt*$this->smCapsScale);
  3546. $s.=sprintf(' %d Tz', $this->smCapsStretch);
  3547. $s.=sprintf(' %.3F Tc', ($this->charspacing*100/$this->smCapsStretch));
  3548. $s.=sprintf(' %s Tj', $txt);
  3549. }
  3550. else {
  3551. $s.=sprintf(' /F%d %.3F Tf %d Tz', $fid, $this->FontSizePt, 100);
  3552. $s.=sprintf(' %.3F Tc', ($this->charspacing));
  3553. $s.=sprintf(' %s Tj', $txt);
  3554. }
  3555. }
  3556. $s.=' ET ';
  3557. return $s;
  3558. }
  3559. function MultiCell($w,$h,$txt,$border=0,$align='',$fill=0,$link='',$directionality='ltr',$encoded=false)
  3560. {
  3561. // Parameter (pre-)encoded - When called internally from ToC or textarea: mb_encoding already done - but not reverse RTL/Indic
  3562. if (!$encoded) {
  3563. $txt = $this->purify_utf8_text($txt);
  3564. if ($this->text_input_as_HTML) {
  3565. $txt = $this->all_entities_to_utf8($txt);
  3566. }
  3567. if ($this->usingCoreFont) { $txt = mb_convert_encoding($txt,$this->mb_enc,'UTF-8'); }
  3568. // Font-specific ligature substitution for Indic fonts
  3569. else if (isset($this->CurrentFont['indic']) && $this->CurrentFont['indic']) { // *INDIC*
  3570. $this->ConvertIndic($tmp); // *INDIC*
  3571. } // *INDIC*
  3572. if (preg_match("/([".$this->pregRTLchars."])/u", $txt)) { $this->biDirectional = true; } // *RTL*
  3573. }
  3574. if (!$align) { $align = $this->defaultAlign; }
  3575. //Output text with automatic or explicit line breaks
  3576. $cw=&$this->CurrentFont['cw'];
  3577. if($w==0) $w=$this->w-$this->rMargin-$this->x;
  3578. $wmax = ($w - ($this->cMarginL+$this->cMarginR));
  3579. if ($this->usingCoreFont) {
  3580. $s=str_replace("\r",'',$txt);
  3581. $nb=strlen($s);
  3582. while($nb>0 and $s[$nb-1]=="\n") $nb--;
  3583. }
  3584. else {
  3585. $s=str_replace("\r",'',$txt);
  3586. $nb=mb_strlen($s, $this->mb_enc );
  3587. while($nb>0 and mb_substr($s,$nb-1,1,$this->mb_enc )=="\n") $nb--;
  3588. }
  3589. $b=0;
  3590. if($border) {
  3591. if($border==1) {
  3592. $border='LTRB';
  3593. $b='LRT';
  3594. $b2='LR';
  3595. }
  3596. else {
  3597. $b2='';
  3598. if(is_int(strpos($border,'L'))) $b2.='L';
  3599. if(is_int(strpos($border,'R'))) $b2.='R';
  3600. $b=is_int(strpos($border,'T')) ? $b2.'T' : $b2;
  3601. }
  3602. }
  3603. $sep=-1;
  3604. $i=0;
  3605. $j=0;
  3606. $l=0;
  3607. $ns=0;
  3608. $nl=1;
  3609. if (!$this->usingCoreFont) {
  3610. $checkCursive=false;
  3611. if ($this->biDirectional) { $checkCursive=true; } // *RTL*
  3612. else if (isset($this->CurrentFont['indic']) && $this->CurrentFont['indic']) { $checkCursive=true; } // *INDIC*
  3613. while($i<$nb) {
  3614. //Get next character
  3615. $c = mb_substr($s,$i,1,$this->mb_enc );
  3616. if($c == "\n") {
  3617. //Explicit line break
  3618. // WORD SPACING
  3619. $this->ResetSpacing();
  3620. $tmp = rtrim(mb_substr($s,$j,$i-$j,$this->mb_enc));
  3621. // DIRECTIONALITY
  3622. $this->magic_reverse_dir($tmp, true, $directionality); // *RTL*
  3623. $this->Cell($w,$h,$tmp,$b,2,$align,$fill,$link);
  3624. $i++;
  3625. $sep=-1;
  3626. $j=$i;
  3627. $l=0;
  3628. $ns=0;
  3629. $nl++;
  3630. if($border and $nl==2) $b=$b2;
  3631. continue;
  3632. }
  3633. if($c == " ") {
  3634. $sep=$i;
  3635. $ls=$l;
  3636. $ns++;
  3637. }
  3638. $l += $this->GetCharWidthNonCore($c);
  3639. if($l>$wmax) {
  3640. //Automatic line break
  3641. if($sep==-1) { // Only one word
  3642. if($i==$j) $i++;
  3643. // WORD SPACING
  3644. $this->ResetSpacing();
  3645. $tmp = rtrim(mb_substr($s,$j,$i-$j,$this->mb_enc));
  3646. // DIRECTIONALITY
  3647. $this->magic_reverse_dir($tmp, true, $directionality); // *RTL*
  3648. $this->Cell($w,$h,$tmp,$b,2,$align,$fill,$link);
  3649. }
  3650. else {
  3651. $tmp = rtrim(mb_substr($s,$j,$sep-$j,$this->mb_enc));
  3652. if($align=='J') {
  3653. //////////////////////////////////////////
  3654. // JUSTIFY J using Unicode fonts (Word spacing doesn't work)
  3655. // WORD SPACING UNICODE
  3656. // Change NON_BREAKING SPACE to spaces so they are 'spaced' properly
  3657. $tmp = str_replace(chr(194).chr(160),chr(32),$tmp );
  3658. $len_ligne = $this->GetStringWidth($tmp );
  3659. $nb_carac = mb_strlen( $tmp , $this->mb_enc ) ;
  3660. $nb_spaces = mb_substr_count( $tmp ,' ', $this->mb_enc ) ;
  3661. $inclCursive=false;
  3662. if ($checkCursive) {
  3663. if (preg_match("/([".$this->pregRTLchars."])/u", $tmp)) { $inclCursive = true; } // *RTL*
  3664. if (preg_match("/([".$this->pregHIchars.$this->pregBNchars.$this->pregPAchars."])/u", $tmp)) { $inclCursive = true; } // *INDIC*
  3665. }
  3666. list($charspacing,$ws) = $this->GetJspacing($nb_carac,$nb_spaces,((($wmax) - $len_ligne) * _MPDFK),$inclCursive);
  3667. $this->SetSpacing($charspacing,$ws);
  3668. //////////////////////////////////////////
  3669. }
  3670. // DIRECTIONALITY
  3671. $this->magic_reverse_dir($tmp, true, $directionality); // *RTL*
  3672. $this->Cell($w,$h,$tmp,$b,2,$align,$fill,$link);
  3673. $i=$sep+1;
  3674. }
  3675. $sep=-1;
  3676. $j=$i;
  3677. $l=0;
  3678. $ns=0;
  3679. $nl++;
  3680. if($border and $nl==2) $b=$b2;
  3681. }
  3682. else $i++;
  3683. }
  3684. //Last chunk
  3685. // WORD SPACING
  3686. $this->ResetSpacing();
  3687. }
  3688. else {
  3689. while($i<$nb) {
  3690. //Get next character
  3691. $c=$s[$i];
  3692. if($c == "\n") {
  3693. //Explicit line break
  3694. // WORD SPACING
  3695. $this->ResetSpacing();
  3696. $this->Cell($w,$h,substr($s,$j,$i-$j),$b,2,$align,$fill,$link);
  3697. $i++;
  3698. $sep=-1;
  3699. $j=$i;
  3700. $l=0;
  3701. $ns=0;
  3702. $nl++;
  3703. if($border and $nl==2) $b=$b2;
  3704. continue;
  3705. }
  3706. if($c == " ") {
  3707. $sep=$i;
  3708. $ls=$l;
  3709. $ns++;
  3710. }
  3711. $l += $this->GetCharWidthCore($c);
  3712. if($l>$wmax) {
  3713. //Automatic line break
  3714. if($sep==-1) {
  3715. if($i==$j) $i++;
  3716. // WORD SPACING
  3717. $this->ResetSpacing();
  3718. $this->Cell($w,$h,substr($s,$j,$i-$j),$b,2,$align,$fill,$link);
  3719. }
  3720. else {
  3721. if($align=='J') {
  3722. $tmp = rtrim(substr($s,$j,$sep-$j));
  3723. //////////////////////////////////////////
  3724. // JUSTIFY J using Unicode fonts (Word spacing doesn't work)
  3725. // WORD SPACING NON_UNICDOE/CJK
  3726. // Change NON_BREAKING SPACE to spaces so they are 'spaced' properly
  3727. $tmp = str_replace(chr(160),chr(32),$tmp);
  3728. $len_ligne = $this->GetStringWidth($tmp );
  3729. $nb_carac = strlen( $tmp ) ;
  3730. $nb_spaces = substr_count( $tmp ,' ' ) ;
  3731. list($charspacing,$ws) = $this->GetJspacing($nb_carac,$nb_spaces,((($wmax) - $len_ligne) * _MPDFK),false);
  3732. $this->SetSpacing($charspacing,$ws);
  3733. //////////////////////////////////////////
  3734. }
  3735. $this->Cell($w,$h,substr($s,$j,$sep-$j),$b,2,$align,$fill,$link);
  3736. $i=$sep+1;
  3737. }
  3738. $sep=-1;
  3739. $j=$i;
  3740. $l=0;
  3741. $ns=0;
  3742. $nl++;
  3743. if($border and $nl==2) $b=$b2;
  3744. }
  3745. else $i++;
  3746. }
  3747. //Last chunk
  3748. // WORD SPACING
  3749. $this->ResetSpacing();
  3750. }
  3751. //Last chunk
  3752. if($border and is_int(strpos($border,'B'))) $b.='B';
  3753. if (!$this->usingCoreFont) {
  3754. $tmp = rtrim(mb_substr($s,$j,$i-$j,$this->mb_enc));
  3755. // DIRECTIONALITY
  3756. $this->magic_reverse_dir($tmp, true, $directionality); // *RTL*
  3757. $this->Cell($w,$h,$tmp,$b,2,$align,$fill,$link);
  3758. }
  3759. else { $this->Cell($w,$h,substr($s,$j,$i-$j),$b,2,$align,$fill,$link); }
  3760. $this->x=$this->lMargin;
  3761. }
  3762. /*-- DIRECTW --*/
  3763. function Write($h,$txt,$currentx=0,$link='',$directionality='ltr',$align='') {
  3764. if (!class_exists('directw', false)) { include(_MPDF_PATH.'classes/directw.php'); }
  3765. if (empty($this->directw)) { $this->directw = new directw($this); }
  3766. $this->directw->Write($h,$txt,$currentx,$link,$directionality,$align);
  3767. }
  3768. /*-- END DIRECTW --*/
  3769. /*-- HTML-CSS --*/
  3770. function saveInlineProperties() {
  3771. $saved = array();
  3772. $saved[ 'family' ] = $this->FontFamily;
  3773. $saved[ 'style' ] = $this->FontStyle;
  3774. $saved[ 'sizePt' ] = $this->FontSizePt;
  3775. $saved[ 'size' ] = $this->FontSize;
  3776. $saved[ 'HREF' ] = $this->HREF;
  3777. $saved[ 'underline' ] = $this->U;
  3778. $saved[ 'smCaps' ] = $this->S;
  3779. $saved[ 'strike' ] = $this->strike;
  3780. $saved[ 'textshadow' ] = $this->textshadow;
  3781. $saved[ 'SUP' ] = $this->SUP;
  3782. $saved[ 'SUB' ] = $this->SUB;
  3783. $saved[ 'linewidth' ] = $this->LineWidth;
  3784. $saved[ 'drawcolor' ] = $this->DrawColor;
  3785. $saved[ 'is_outline' ] = $this->outline_on;
  3786. $saved[ 'outlineparam' ] = $this->outlineparam;
  3787. $saved[ 'toupper' ] = $this->toupper;
  3788. $saved[ 'tolower' ] = $this->tolower;
  3789. $saved[ 'capitalize' ] = $this->capitalize;
  3790. $saved[ 'fontkerning' ] = $this->kerning;
  3791. $saved[ 'lSpacingCSS' ] = $this->lSpacingCSS;
  3792. $saved[ 'wSpacingCSS' ] = $this->wSpacingCSS;
  3793. $saved[ 'I' ] = $this->I;
  3794. $saved[ 'B' ] = $this->B;
  3795. $saved[ 'colorarray' ] = $this->colorarray;
  3796. $saved[ 'bgcolorarray' ] = $this->spanbgcolorarray;
  3797. $saved[ 'border' ] = $this->spanborddet;
  3798. $saved[ 'color' ] = $this->TextColor;
  3799. $saved[ 'bgcolor' ] = $this->FillColor;
  3800. $saved['lang'] = $this->currentLang;
  3801. $saved['display_off'] = $this->inlineDisplayOff;
  3802. return $saved;
  3803. }
  3804. function restoreInlineProperties( &$saved) {
  3805. $FontFamily = $saved[ 'family' ];
  3806. $this->FontStyle = $saved[ 'style' ];
  3807. $this->FontSizePt = $saved[ 'sizePt' ];
  3808. $this->FontSize = $saved[ 'size' ];
  3809. $this->currentLang = $saved['lang'];
  3810. if ($this->useLang && !$this->usingCoreFont) {
  3811. if ($this->currentLang != $this->default_lang && ((strlen($this->currentLang) == 5 && $this->currentLang != 'UTF-8') || strlen($this->currentLang ) == 2)) {
  3812. list ($coreSuitable,$mpdf_pdf_unifonts) = GetLangOpts($this->currentLang, $this->useAdobeCJK);
  3813. if ($mpdf_pdf_unifonts) { $this->RestrictUnicodeFonts($mpdf_pdf_unifonts); }
  3814. else { $this->RestrictUnicodeFonts($this->default_available_fonts ); }
  3815. }
  3816. else {
  3817. $this->RestrictUnicodeFonts($this->default_available_fonts );
  3818. }
  3819. }
  3820. $this->ColorFlag = ($this->FillColor != $this->TextColor); //Restore ColorFlag as well
  3821. $this->HREF = $saved[ 'HREF' ];
  3822. $this->U = $saved[ 'underline' ];
  3823. $this->S = $saved[ 'smCaps' ];
  3824. $this->strike = $saved[ 'strike' ];
  3825. $this->textshadow = $saved[ 'textshadow' ];
  3826. $this->SUP = $saved[ 'SUP' ];
  3827. $this->SUB = $saved[ 'SUB' ];
  3828. $this->LineWidth = $saved[ 'linewidth' ];
  3829. $this->DrawColor = $saved[ 'drawcolor' ];
  3830. $this->outline_on = $saved[ 'is_outline' ];
  3831. $this->outlineparam = $saved[ 'outlineparam' ];
  3832. $this->inlineDisplayOff = $saved['display_off'];
  3833. $this->toupper = $saved[ 'toupper' ];
  3834. $this->tolower = $saved[ 'tolower' ];
  3835. $this->capitalize = $saved[ 'capitalize' ];
  3836. $this->kerning = $saved[ 'fontkerning' ];
  3837. $this->lSpacingCSS = $saved[ 'lSpacingCSS' ];
  3838. if (($this->lSpacingCSS || $this->lSpacingCSS==='0') && strtoupper($this->lSpacingCSS) != 'NORMAL') {
  3839. $this->fixedlSpacing = $this->ConvertSize($this->lSpacingCSS,$this->FontSize);
  3840. }
  3841. else { $this->fixedlSpacing = false; }
  3842. $this->wSpacingCSS = $saved[ 'wSpacingCSS' ];
  3843. if ($this->wSpacingCSS && strtoupper($this->wSpacingCSS) != 'NORMAL') {
  3844. $this->minwSpacing = $this->ConvertSize($this->wSpacingCSS,$this->FontSize);
  3845. }
  3846. else { $this->minwSpacing = 0; }
  3847. $this->SetFont($FontFamily, $saved[ 'style' ].($this->U ? 'U' : '').($this->S ? 'S' : ''),$saved[ 'sizePt' ],false);
  3848. $this->currentfontstyle = $saved[ 'style' ].($this->U ? 'U' : '').($this->S ? 'S' : '');
  3849. $this->currentfontsize = $saved[ 'sizePt' ];
  3850. $this->SetStylesArray(array('S'=>$this->S, 'U'=>$this->U, 'B'=>$saved[ 'B' ], 'I'=>$saved[ 'I' ]));
  3851. $this->TextColor = $saved[ 'color' ];
  3852. $this->FillColor = $saved[ 'bgcolor' ];
  3853. $this->colorarray = $saved[ 'colorarray' ];
  3854. $cor = $saved[ 'colorarray' ];
  3855. if ($cor) $this->SetTColor($cor);
  3856. $this->spanbgcolorarray = $saved[ 'bgcolorarray' ];
  3857. $cor = $saved[ 'bgcolorarray' ];
  3858. if ($cor) $this->SetFColor($cor);
  3859. $this->spanborddet = $saved[ 'border' ];
  3860. }
  3861. // Used when ColActive for tables - updated to return first block with background fill OR borders
  3862. function GetFirstBlockFill() {
  3863. // Returns the first blocklevel that uses a bgcolor fill
  3864. $startfill = 0;
  3865. for ($i=1;$i<=$this->blklvl;$i++) {
  3866. if ($this->blk[$i]['bgcolor'] || $this->blk[$i]['border_left']['w'] || $this->blk[$i]['border_right']['w'] || $this->blk[$i]['border_top']['w'] || $this->blk[$i]['border_bottom']['w'] ) {
  3867. $startfill = $i;
  3868. break;
  3869. }
  3870. }
  3871. return $startfill;
  3872. }
  3873. function SetBlockFill($blvl) {
  3874. if ($this->blk[$blvl]['bgcolor']) {
  3875. $this->SetFColor($this->blk[$blvl]['bgcolorarray']);
  3876. return 1;
  3877. }
  3878. else {
  3879. $this->SetFColor($this->ConvertColor(255));
  3880. return 0;
  3881. }
  3882. }
  3883. //-------------------------FLOWING BLOCK------------------------------------//
  3884. //The following functions were originally written by Damon Kohler //
  3885. //--------------------------------------------------------------------------//
  3886. function saveFont() {
  3887. $saved = array();
  3888. $saved[ 'family' ] = $this->FontFamily;
  3889. $saved[ 'style' ] = $this->FontStyle;
  3890. $saved[ 'sizePt' ] = $this->FontSizePt;
  3891. $saved[ 'size' ] = $this->FontSize;
  3892. $saved[ 'curr' ] = &$this->CurrentFont;
  3893. $saved[ 'color' ] = $this->TextColor;
  3894. $saved[ 'spanbgcolor' ] = $this->spanbgcolor;
  3895. $saved[ 'spanbgcolorarray' ] = $this->spanbgcolorarray;
  3896. $saved[ 'bord' ] = $this->spanborder;
  3897. $saved[ 'border' ] = $this->spanborddet;
  3898. $saved[ 'HREF' ] = $this->HREF;
  3899. $saved[ 'underline' ] = $this->U;
  3900. $saved[ 'smCaps' ] = $this->S;
  3901. $saved[ 'strike' ] = $this->strike;
  3902. $saved[ 'textshadow' ] = $this->textshadow;
  3903. $saved[ 'SUP' ] = $this->SUP;
  3904. $saved[ 'SUB' ] = $this->SUB;
  3905. $saved[ 'linewidth' ] = $this->LineWidth;
  3906. $saved[ 'drawcolor' ] = $this->DrawColor;
  3907. $saved[ 'is_outline' ] = $this->outline_on;
  3908. $saved[ 'outlineparam' ] = $this->outlineparam;
  3909. $saved[ 'ReqFontStyle' ] = $this->ReqFontStyle;
  3910. $saved[ 'fontkerning' ] = $this->kerning;
  3911. $saved[ 'fixedlSpacing' ] = $this->fixedlSpacing;
  3912. $saved[ 'minwSpacing' ] = $this->minwSpacing;
  3913. return $saved;
  3914. }
  3915. function restoreFont( &$saved, $write=true) {
  3916. if (!isset($saved) || empty($saved)) return;
  3917. $this->FontFamily = $saved[ 'family' ];
  3918. $this->FontStyle = $saved[ 'style' ];
  3919. $this->FontSizePt = $saved[ 'sizePt' ];
  3920. $this->FontSize = $saved[ 'size' ];
  3921. $this->CurrentFont = &$saved[ 'curr' ];
  3922. $this->TextColor = $saved[ 'color' ];
  3923. $this->spanbgcolor = $saved[ 'spanbgcolor' ];
  3924. $this->spanbgcolorarray = $saved[ 'spanbgcolorarray' ];
  3925. $this->spanborder = $saved[ 'bord' ];
  3926. $this->spanborddet = $saved[ 'border' ];
  3927. $this->ColorFlag = ($this->FillColor != $this->TextColor); //Restore ColorFlag as well
  3928. $this->HREF = $saved[ 'HREF' ];
  3929. $this->U = $saved[ 'underline' ];
  3930. $this->S = $saved[ 'smCaps' ];
  3931. $this->kerning = $saved[ 'fontkerning' ];
  3932. $this->fixedlSpacing = $saved[ 'fixedlSpacing' ];
  3933. $this->minwSpacing = $saved[ 'minwSpacing' ];
  3934. $this->strike = $saved[ 'strike' ];
  3935. $this->textshadow = $saved[ 'textshadow' ];
  3936. $this->SUP = $saved[ 'SUP' ];
  3937. $this->SUB = $saved[ 'SUB' ];
  3938. $this->LineWidth = $saved[ 'linewidth' ];
  3939. $this->DrawColor = $saved[ 'drawcolor' ];
  3940. $this->outline_on = $saved[ 'is_outline' ];
  3941. $this->outlineparam = $saved[ 'outlineparam' ];
  3942. if ($write) {
  3943. $this->SetFont($saved[ 'family' ],$saved[ 'style' ].($this->U ? 'U' : '').($this->S ? 'S' : ''),$saved[ 'sizePt' ],true,true); // force output
  3944. $fontout = (sprintf('BT /F%d %.3F Tf ET', $this->CurrentFont['i'], $this->FontSizePt));
  3945. if($this->page>0 && ((isset($this->pageoutput[$this->page]['Font']) && $this->pageoutput[$this->page]['Font'] != $fontout) || !isset($this->pageoutput[$this->page]['Font']) || $this->keep_block_together)) { $this->_out($fontout); }
  3946. $this->pageoutput[$this->page]['Font'] = $fontout;
  3947. }
  3948. else
  3949. $this->SetFont($saved[ 'family' ],$saved[ 'style' ].($this->U ? 'U' : '').($this->S ? 'S' : ''),$saved[ 'sizePt' ]);
  3950. $this->ReqFontStyle = $saved[ 'ReqFontStyle' ];
  3951. }
  3952. function newFlowingBlock( $w, $h, $a = '', $is_table = false, $is_list = false, $blockstate = 0, $newblock=true, $blockdir='ltr')
  3953. {
  3954. if (!$a) {
  3955. if ($blockdir=='rtl') { $a = 'R'; }
  3956. else { $a = 'L'; }
  3957. }
  3958. $this->flowingBlockAttr[ 'width' ] = ($w * _MPDFK);
  3959. // line height in user units
  3960. $this->flowingBlockAttr[ 'is_table' ] = $is_table;
  3961. $this->flowingBlockAttr[ 'is_list' ] = $is_list;
  3962. $this->flowingBlockAttr[ 'height' ] = $h;
  3963. $this->flowingBlockAttr[ 'lineCount' ] = 0;
  3964. $this->flowingBlockAttr[ 'align' ] = $a;
  3965. $this->flowingBlockAttr[ 'font' ] = array();
  3966. $this->flowingBlockAttr[ 'content' ] = array();
  3967. $this->flowingBlockAttr[ 'contentB' ] = array();
  3968. $this->flowingBlockAttr[ 'contentWidth' ] = 0;
  3969. $this->flowingBlockAttr[ 'blockstate' ] = $blockstate;
  3970. $this->flowingBlockAttr[ 'newblock' ] = $newblock;
  3971. $this->flowingBlockAttr[ 'valign' ] = 'M';
  3972. $this->flowingBlockAttr['blockdir'] = $blockdir;
  3973. }
  3974. function finishFlowingBlock($endofblock=false, $next='') {
  3975. $currentx = $this->x;
  3976. //prints out the last chunk
  3977. $is_table = $this->flowingBlockAttr[ 'is_table' ];
  3978. $is_list = $this->flowingBlockAttr[ 'is_list' ];
  3979. $maxWidth =& $this->flowingBlockAttr[ 'width' ];
  3980. $lineHeight =& $this->flowingBlockAttr[ 'height' ];
  3981. $align =& $this->flowingBlockAttr[ 'align' ];
  3982. $content =& $this->flowingBlockAttr[ 'content' ];
  3983. $contentB =& $this->flowingBlockAttr[ 'contentB' ];
  3984. $font =& $this->flowingBlockAttr[ 'font' ];
  3985. $contentWidth =& $this->flowingBlockAttr[ 'contentWidth' ];
  3986. $lineCount =& $this->flowingBlockAttr[ 'lineCount' ];
  3987. $valign =& $this->flowingBlockAttr[ 'valign' ];
  3988. $blockstate = $this->flowingBlockAttr[ 'blockstate' ];
  3989. $newblock = $this->flowingBlockAttr[ 'newblock' ];
  3990. $blockdir = $this->flowingBlockAttr['blockdir'];
  3991. // *********** BLOCK BACKGROUND COLOR *****************//
  3992. if ($this->blk[$this->blklvl]['bgcolor'] && !$is_table) {
  3993. $fill = 0;
  3994. }
  3995. else {
  3996. $this->SetFColor($this->ConvertColor(255));
  3997. $fill = 0;
  3998. }
  3999. // Always right trim!
  4000. // Right trim content and adjust width if need to justify (later)
  4001. if (isset($content[count($content)-1]) && preg_match('/[ ]+$/',$content[count($content)-1], $m)) {
  4002. $strip = strlen($m[0]);
  4003. $content[count($content)-1] = substr($content[count($content)-1],0,(strlen($content[count($content)-1])-$strip));
  4004. $this->restoreFont( $font[ count($content)-1 ],false );
  4005. $contentWidth -= $this->GetStringWidth($m[0]) * _MPDFK;
  4006. }
  4007. // the amount of space taken up so far in user units
  4008. $usedWidth = 0;
  4009. // COLS
  4010. $oldcolumn = $this->CurrCol;
  4011. if ($this->ColActive && !$is_table) { $this->breakpoints[$this->CurrCol][] = $this->y; } // *COLUMNS*
  4012. // Print out each chunk
  4013. /*-- TABLES --*/
  4014. if ($is_table) {
  4015. $ipaddingL = 0;
  4016. $ipaddingR = 0;
  4017. $paddingL = 0;
  4018. $paddingR = 0;
  4019. }
  4020. else {
  4021. /*-- END TABLES --*/
  4022. $ipaddingL = $this->blk[$this->blklvl]['padding_left'];
  4023. $ipaddingR = $this->blk[$this->blklvl]['padding_right'];
  4024. $paddingL = ($ipaddingL * _MPDFK);
  4025. $paddingR = ($ipaddingR * _MPDFK);
  4026. $this->cMarginL = $this->blk[$this->blklvl]['border_left']['w'];
  4027. $this->cMarginR = $this->blk[$this->blklvl]['border_right']['w'];
  4028. // Added mPDF 3.0 Float DIV
  4029. $fpaddingR = 0;
  4030. $fpaddingL = 0;
  4031. /*-- CSS-FLOAT --*/
  4032. if (count($this->floatDivs)) {
  4033. list($l_exists, $r_exists, $l_max, $r_max, $l_width, $r_width) = $this->GetFloatDivInfo($this->blklvl);
  4034. if ($r_exists) { $fpaddingR = $r_width; }
  4035. if ($l_exists) { $fpaddingL = $l_width; }
  4036. }
  4037. /*-- END CSS-FLOAT --*/
  4038. $usey = $this->y + 0.002;
  4039. if (($newblock) && ($blockstate==1 || $blockstate==3) && ($lineCount == 0) ) {
  4040. $usey += $this->blk[$this->blklvl]['margin_top'] + $this->blk[$this->blklvl]['padding_top'] + $this->blk[$this->blklvl]['border_top']['w'];
  4041. }
  4042. /*-- CSS-IMAGE-FLOAT --*/
  4043. // If float exists at this level
  4044. if (isset($this->floatmargins['R']) && $usey <= $this->floatmargins['R']['y1'] && $usey >= $this->floatmargins['R']['y0'] && !$this->floatmargins['R']['skipline']) { $fpaddingR += $this->floatmargins['R']['w']; }
  4045. if (isset($this->floatmargins['L']) && $usey <= $this->floatmargins['L']['y1'] && $usey >= $this->floatmargins['L']['y0'] && !$this->floatmargins['L']['skipline']) { $fpaddingL += $this->floatmargins['L']['w']; }
  4046. /*-- END CSS-IMAGE-FLOAT --*/
  4047. } // *TABLES*
  4048. // Set Current lineheight (correction factor)
  4049. $lhfixed = false;
  4050. /*-- LISTS --*/
  4051. if ($is_list) {
  4052. if (preg_match('/([0-9.,]+)mm/',$this->list_lineheight[$this->listlvl][$this->listOcc],$am)) {
  4053. $lhfixed = true;
  4054. $def_fontsize = $this->InlineProperties['LISTITEM'][$this->listlvl][$this->listOcc][$this->listnum]['size'];
  4055. $this->lineheight_correction = $am[1] / $def_fontsize ;
  4056. }
  4057. else {
  4058. $this->lineheight_correction = $this->list_lineheight[$this->listlvl][$this->listOcc];
  4059. }
  4060. }
  4061. else
  4062. /*-- END LISTS --*/
  4063. /*-- TABLES --*/
  4064. if ($is_table) {
  4065. if (preg_match('/([0-9.,]+)mm/',$this->table_lineheight,$am)) {
  4066. $lhfixed = true;
  4067. $def_fontsize = $this->FontSize; // needs to be default font-size for block ****
  4068. $this->lineheight_correction = $lineHeight / $def_fontsize ;
  4069. }
  4070. else {
  4071. $this->lineheight_correction = $this->table_lineheight;
  4072. }
  4073. }
  4074. else
  4075. /*-- END TABLES --*/
  4076. if (isset($this->blk[$this->blklvl]['line_height']) && $this->blk[$this->blklvl]['line_height']) {
  4077. if (preg_match('/([0-9.,]+)mm/',$this->blk[$this->blklvl]['line_height'],$am)) {
  4078. $lhfixed = true;
  4079. $def_fontsize = $this->blk[$this->blklvl]['InlineProperties']['size']; // needs to be default font-size for block ****
  4080. $this->lineheight_correction = $am[1] / $def_fontsize ;
  4081. }
  4082. else {
  4083. $this->lineheight_correction = $this->blk[$this->blklvl]['line_height'];
  4084. }
  4085. }
  4086. else {
  4087. $this->lineheight_correction = $this->normalLineheight;
  4088. }
  4089. // correct lineheight to maximum fontsize
  4090. if ($lhfixed) { $maxlineHeight = $this->lineheight; }
  4091. else { $maxlineHeight = 0; }
  4092. $this->forceExactLineheight = true;
  4093. $maxfontsize = 0;
  4094. // While we're at it, check if contains cursive text
  4095. $checkCursive=false;
  4096. if ($this->biDirectional) { $checkCursive=true; } // *RTL*
  4097. foreach ( $content as $k => $chunk )
  4098. {
  4099. $this->restoreFont( $font[ $k ],false );
  4100. if (!isset($this->objectbuffer[$k])) {
  4101. // Soft Hyphens chr(173)
  4102. if (!$this->usingCoreFont) {
  4103. $content[$k] = $chunk = str_replace("\xc2\xad",'',$chunk );
  4104. if (isset($this->CurrentFont['indic']) && $this->CurrentFont['indic']) { $checkCursive=true; } // *INDIC*
  4105. }
  4106. else if ($this->FontFamily!='csymbol' && $this->FontFamily!='czapfdingbats') {
  4107. $content[$k] = $chunk = str_replace(chr(173),'',$chunk );
  4108. }
  4109. // Special case of sub/sup carried over on its own to last line
  4110. if (($this->SUB || $this->SUP) && count($content)==1) { $actfs = $this->FontSize*100/55; } // 55% is font change for sub/sup
  4111. else { $actfs = $this->FontSize; }
  4112. if (!$lhfixed) { $maxlineHeight = max($maxlineHeight,$actfs * $this->lineheight_correction ); }
  4113. if ($lhfixed && ($actfs > $def_fontsize || ($actfs > ($lineHeight * $this->lineheight_correction) && $is_list))) {
  4114. $this->forceExactLineheight = false;
  4115. }
  4116. $maxfontsize = max($maxfontsize,$actfs);
  4117. }
  4118. }
  4119. if(isset($font[count($font)-1])) {
  4120. $lastfontreqstyle = $font[count($font)-1]['ReqFontStyle'];
  4121. $lastfontstyle = $font[count($font)-1]['style'];
  4122. }
  4123. else {
  4124. $lastfontreqstyle=null;
  4125. $lastfontstyle=null;
  4126. }
  4127. if ($blockdir == 'ltr' && strpos($lastfontreqstyle,"I") !== false && strpos($lastfontstyle,"I") === false) { // Artificial italic
  4128. $lastitalic = $this->FontSize*0.15*_MPDFK;
  4129. }
  4130. else { $lastitalic = 0; }
  4131. /*-- LISTS --*/
  4132. if ($is_list && is_array($this->bulletarray) && count($this->bulletarray)) {
  4133. $actfs = $this->bulletarray['fontsize'];
  4134. if (!$lhfixed) { $maxlineHeight = max($maxlineHeight,$actfs * $this->lineheight_correction ); }
  4135. if ($lhfixed && $actfs > $def_fontsize) { $this->forceExactLineheight = false; }
  4136. $maxfontsize = max($maxfontsize,$actfs);
  4137. }
  4138. /*-- END LISTS --*/
  4139. // when every text item checked i.e. $maxfontsize is set properly
  4140. $af = 0; // Above font
  4141. $bf = 0; // Below font
  4142. $mta = 0; // Maximum top-aligned
  4143. $mba = 0; // Maximum bottom-aligned
  4144. foreach ( $content as $k => $chunk )
  4145. {
  4146. if (isset($this->objectbuffer[$k])) {
  4147. $oh = $this->objectbuffer[$k]['OUTER-HEIGHT'];
  4148. $va = $this->objectbuffer[$k]['vertical-align']; // = $objattr['vertical-align'] = set as M,T,B,S
  4149. if ($lhfixed && $oh > $def_fontsize) { $this->forceExactLineheight = false; }
  4150. if ($va == 'BS') { // (BASELINE default)
  4151. $af = max($af, ($oh - ($maxfontsize * (0.5 + $this->baselineC))));
  4152. }
  4153. else if ($va == 'M') {
  4154. $af = max($af, ($oh - $maxfontsize)/2);
  4155. $bf = max($bf, ($oh - $maxfontsize)/2);
  4156. }
  4157. else if ($va == 'TT') {
  4158. $bf = max($bf, ($oh - $maxfontsize));
  4159. }
  4160. else if ($va == 'TB') {
  4161. $af = max($af, ($oh - $maxfontsize));
  4162. }
  4163. else if ($va == 'T') {
  4164. $mta = max($mta, $oh);
  4165. }
  4166. else if ($va == 'B') {
  4167. $mba = max($mba, $oh);
  4168. }
  4169. }
  4170. }
  4171. if ((!$lhfixed || !$this->forceExactLineheight) && ($af > (($maxlineHeight - $maxfontsize)/2) || $bf > (($maxlineHeight - $maxfontsize)/2))) {
  4172. $maxlineHeight = $maxfontsize + $af + $bf;
  4173. }
  4174. else if (!$lhfixed) { $af = $bf = ($maxlineHeight - $maxfontsize)/2; }
  4175. if ($mta > $maxlineHeight) {
  4176. $bf += ($mta - $maxlineHeight);
  4177. $maxlineHeight = $mta;
  4178. }
  4179. if ($mba > $maxlineHeight) {
  4180. $af += ($mba - $maxlineHeight);
  4181. $maxlineHeight = $mba;
  4182. }
  4183. $lineHeight = $maxlineHeight;
  4184. // If NOT images, and maxfontsize NOT > lineHeight - this value determines text baseline positioning
  4185. if ($lhfixed && $af==0 && $bf==0 && $maxfontsize<=($def_fontsize * $this->lineheight_correction * 0.8 )) {
  4186. $this->linemaxfontsize = $def_fontsize;
  4187. }
  4188. else { $this->linemaxfontsize = $maxfontsize; }
  4189. // Get PAGEBREAK TO TEST for height including the bottom border/padding
  4190. $check_h = max($this->divheight,$lineHeight);
  4191. // This fixes a proven bug...
  4192. if ($endofblock && $newblock && $blockstate==0 && !$content) { $check_h = 0; }
  4193. // but ? needs to fix potentially more widespread...
  4194. // if (!$content) { $check_h = 0; }
  4195. if ($this->blklvl > 0 && !$is_table) {
  4196. if ($endofblock && $blockstate > 1) {
  4197. if ($this->blk[$this->blklvl]['page_break_after_avoid']) { $check_h += $lineHeight; }
  4198. $check_h += ($this->blk[$this->blklvl]['padding_bottom'] + $this->blk[$this->blklvl]['border_bottom']['w']);
  4199. }
  4200. // mPDF 5.4.03
  4201. if (($newblock && ($blockstate==1 || $blockstate==3) && $lineCount == 0) || ($endofblock && $blockstate ==3 && $lineCount == 0)) {
  4202. $check_h += ($this->blk[$this->blklvl]['padding_top'] + $this->blk[$this->blklvl]['margin_top'] + $this->blk[$this->blklvl]['border_top']['w']);
  4203. }
  4204. }
  4205. // Force PAGE break if column height cannot take check-height
  4206. if ($this->ColActive && $check_h > ($this->PageBreakTrigger - $this->y0)) {
  4207. $this->SetCol($this->NbCol-1);
  4208. }
  4209. // mPDF 5.4.04
  4210. // Avoid just border/background-color moved on to next page
  4211. if ($endofblock && $blockstate > 1 && !$content) { $buff = $this->margBuffer; }
  4212. else { $buff = 0; }
  4213. // PAGEBREAK
  4214. // mPDF 5.4.04
  4215. if(!$is_table && ($this->y+$check_h) > ($this->PageBreakTrigger + $buff) and !$this->InFooter and $this->AcceptPageBreak()) {
  4216. $bak_x=$this->x;//Current X position
  4217. // WORD SPACING
  4218. $ws=$this->ws;//Word Spacing
  4219. $charspacing=$this->charspacing;//Character Spacing
  4220. $this->ResetSpacing();
  4221. $this->AddPage($this->CurOrientation);
  4222. $this->x=$bak_x;
  4223. // Added to correct for OddEven Margins
  4224. $currentx += $this->MarginCorrection;
  4225. $this->x += $this->MarginCorrection;
  4226. // WORD SPACING
  4227. $this->SetSpacing($charspacing,$ws);
  4228. }
  4229. if ($this->keep_block_together && !$is_table && $this->kt_p00 < $this->page && ($this->y+$check_h) > $this->kt_y00) {
  4230. $this->printdivbuffer();
  4231. $this->keep_block_together = 0;
  4232. }
  4233. /*-- COLUMNS --*/
  4234. // COLS
  4235. // COLUMN CHANGE
  4236. if ($this->CurrCol != $oldcolumn) {
  4237. $currentx += $this->ChangeColumn * ($this->ColWidth+$this->ColGap);
  4238. $this->x += $this->ChangeColumn * ($this->ColWidth+$this->ColGap);
  4239. $oldcolumn = $this->CurrCol;
  4240. }
  4241. if ($this->ColActive && !$is_table) { $this->breakpoints[$this->CurrCol][] = $this->y; }
  4242. /*-- END COLUMNS --*/
  4243. // TOP MARGIN
  4244. if ($newblock && ($blockstate==1 || $blockstate==3) && ($this->blk[$this->blklvl]['margin_top']) && $lineCount == 0 && !$is_table && !$is_list) {
  4245. $this->DivLn($this->blk[$this->blklvl]['margin_top'],$this->blklvl-1,true,$this->blk[$this->blklvl]['margin_collapse']);
  4246. if ($this->ColActive) { $this->breakpoints[$this->CurrCol][] = $this->y; } // *COLUMNS*
  4247. }
  4248. if ($newblock && ($blockstate==1 || $blockstate==3) && $lineCount == 0 && !$is_table && !$is_list) {
  4249. $this->blk[$this->blklvl]['y0'] = $this->y;
  4250. $this->blk[$this->blklvl]['startpage'] = $this->page;
  4251. if ($this->ColActive) { $this->breakpoints[$this->CurrCol][] = $this->y; } // *COLUMNS*
  4252. }
  4253. // ADDED for Paragraph_indent
  4254. $WidthCorrection = 0;
  4255. if (($newblock) && ($blockstate==1 || $blockstate==3) && isset($this->blk[$this->blklvl]['text_indent']) && ($lineCount == 0) && (!$is_table) && (!$is_list) && ($align != 'C')) {
  4256. $ti = $this->ConvertSize($this->blk[$this->blklvl]['text_indent'],$this->blk[$this->blklvl]['inner_width'],$this->FontSize,false);
  4257. $WidthCorrection = ($ti*_MPDFK);
  4258. }
  4259. // PADDING and BORDER spacing/fill
  4260. if (($newblock) && ($blockstate==1 || $blockstate==3) && (($this->blk[$this->blklvl]['padding_top']) || ($this->blk[$this->blklvl]['border_top'])) && ($lineCount == 0) && (!$is_table) && (!$is_list)) {
  4261. // $state = 0 normal; 1 top; 2 bottom; 3 top and bottom
  4262. $this->DivLn($this->blk[$this->blklvl]['padding_top'] + $this->blk[$this->blklvl]['border_top']['w'],-3,true,false,1);
  4263. if ($this->ColActive) { $this->breakpoints[$this->CurrCol][] = $this->y; } // *COLUMNS*
  4264. $this->x = $currentx;
  4265. }
  4266. // Added mPDF 3.0 Float DIV
  4267. $fpaddingR = 0;
  4268. $fpaddingL = 0;
  4269. /*-- CSS-FLOAT --*/
  4270. if (count($this->floatDivs)) {
  4271. list($l_exists, $r_exists, $l_max, $r_max, $l_width, $r_width) = $this->GetFloatDivInfo($this->blklvl);
  4272. if ($r_exists) { $fpaddingR = $r_width; }
  4273. if ($l_exists) { $fpaddingL = $l_width; }
  4274. }
  4275. /*-- END CSS-FLOAT --*/
  4276. $usey = $this->y + 0.002;
  4277. if (($newblock) && ($blockstate==1 || $blockstate==3) && ($lineCount == 0) ) {
  4278. $usey += $this->blk[$this->blklvl]['margin_top'] + $this->blk[$this->blklvl]['padding_top'] + $this->blk[$this->blklvl]['border_top']['w'];
  4279. }
  4280. /*-- CSS-IMAGE-FLOAT --*/
  4281. // If float exists at this level
  4282. if (isset($this->floatmargins['R']) && $usey <= $this->floatmargins['R']['y1'] && $usey >= $this->floatmargins['R']['y0'] && !$this->floatmargins['R']['skipline']) { $fpaddingR += $this->floatmargins['R']['w']; }
  4283. if (isset($this->floatmargins['L']) && $usey <= $this->floatmargins['L']['y1'] && $usey >= $this->floatmargins['L']['y0'] && !$this->floatmargins['L']['skipline']) { $fpaddingL += $this->floatmargins['L']['w']; }
  4284. /*-- END CSS-IMAGE-FLOAT --*/
  4285. if ($content) {
  4286. // In FinishFlowing Block no lines are justified as it is always last line
  4287. // but if orphansAllowed have allowed content width to go over max width, use J charspacing to compress line
  4288. // JUSTIFICATION J - NOT!
  4289. $nb_carac = 0;
  4290. $nb_spaces = 0;
  4291. $jcharspacing = 0;
  4292. $jws = 0;
  4293. $inclCursive=false;
  4294. foreach ( $content as $k => $chunk ) {
  4295. if (!isset($this->objectbuffer[$k]) || (isset($this->objectbuffer[$k]) && !$this->objectbuffer[$k])) {
  4296. if ($this->usingCoreFont) {
  4297. $chunk = str_replace(chr(160),chr(32),$chunk );
  4298. }
  4299. else {
  4300. $chunk = str_replace(chr(194).chr(160),chr(32),$chunk );
  4301. }
  4302. $nb_carac += mb_strlen( $chunk, $this->mb_enc );
  4303. $nb_spaces += mb_substr_count( $chunk,' ', $this->mb_enc );
  4304. if ($checkCursive) {
  4305. if (preg_match("/([".$this->pregRTLchars."])/u", $chunk)) { $inclCursive = true; } // *RTL*
  4306. if (preg_match("/([".$this->pregHIchars.$this->pregBNchars.$this->pregPAchars."])/u", $chunk)) { $inclCursive = true; } // *INDIC*
  4307. }
  4308. }
  4309. }
  4310. // if it's justified, we need to find the char/word spacing (or if orphans have allowed length of line to go over the maxwidth)
  4311. // If "orphans" in fact is just a final space - ignore this
  4312. if (((($contentWidth + $lastitalic) > $maxWidth) && ($content[count($content)-1] != ' ') ) ||
  4313. (!$endofblock && $align=='J' && ($next=='image' || $next=='select' || $next=='input' || $next=='textarea' || ($next=='br' && $this->justifyB4br)))
  4314. ) {
  4315. // WORD SPACING
  4316. list($jcharspacing,$jws) = $this->GetJspacing($nb_carac,$nb_spaces,($maxWidth-$lastitalic-$contentWidth-$WidthCorrection-(($this->cMarginL+$this->cMarginR)*_MPDFK)-($paddingL+$paddingR +(($fpaddingL + $fpaddingR) * _MPDFK) )),$inclCursive);
  4317. }
  4318. // Check if will fit at word/char spacing of previous line - if so continue it
  4319. // but only allow a maximum of $this->jSmaxWordLast and $this->jSmaxCharLast
  4320. else if ($contentWidth < ($maxWidth - $lastitalic-$WidthCorrection - (($this->cMarginL+$this->cMarginR)* _MPDFK) - ($paddingL+$paddingR +(($fpaddingL + $fpaddingR) * _MPDFK))) && !$this->fixedlSpacing) {
  4321. if ($this->ws > $this->jSmaxWordLast) {
  4322. $jws = $this->jSmaxWordLast;
  4323. }
  4324. if ($this->charspacing > $this->jSmaxCharLast) {
  4325. $jcharspacing = $this->jSmaxCharLast;
  4326. }
  4327. $check = $maxWidth - $lastitalic-$WidthCorrection - $contentWidth - (($this->cMarginL+$this->cMarginR)* _MPDFK) - ($paddingL+$paddingR +(($fpaddingL + $fpaddingR) * _MPDFK) ) - ( $jcharspacing * $nb_carac) - ( $jws * $nb_spaces);
  4328. if ($check <= 0) {
  4329. $jcharspacing = 0;
  4330. $jws = 0;
  4331. }
  4332. }
  4333. $empty = $maxWidth - $lastitalic-$WidthCorrection - $contentWidth - (($this->cMarginL+$this->cMarginR)* _MPDFK) - ($paddingL+$paddingR +(($fpaddingL + $fpaddingR) * _MPDFK) );
  4334. $empty -= ($jcharspacing * $nb_carac);
  4335. $empty -= ($jws * $nb_spaces);
  4336. $empty /= _MPDFK;
  4337. if (!$is_table) {
  4338. $this->maxPosR = max($this->maxPosR , ($this->w - $this->rMargin - $this->blk[$this->blklvl]['outer_right_margin'] - $empty));
  4339. $this->maxPosL = min($this->maxPosL , ($this->lMargin + $this->blk[$this->blklvl]['outer_left_margin'] + $empty));
  4340. }
  4341. $arraysize = count($content);
  4342. $margins = ($this->cMarginL+$this->cMarginR) + ($ipaddingL+$ipaddingR + $fpaddingR + $fpaddingR );
  4343. if (!$is_table) { $this->DivLn($lineHeight,$this->blklvl,false); } // false -> don't advance y
  4344. // DIRECTIONALITY RTL
  4345. $all_rtl = false;
  4346. $contains_rtl = false;
  4347. /*-- RTL --*/
  4348. if ($blockdir == 'rtl' || $this->biDirectional) {
  4349. $all_rtl = true;
  4350. foreach ( $content as $k => $chunk ) {
  4351. $reversed = $this->magic_reverse_dir($chunk, false, $blockdir);
  4352. if ($reversed > 0) { $contains_rtl = true; }
  4353. if ($reversed < 2) { $all_rtl = false; }
  4354. $content[$k] = $chunk;
  4355. }
  4356. if (($blockdir =='rtl' && $contains_rtl) || $all_rtl) {
  4357. $content = array_reverse($content,false);
  4358. $contentB = array_reverse($contentB,false);
  4359. }
  4360. }
  4361. /*-- END RTL --*/
  4362. $this->x = $currentx + $this->cMarginL + $ipaddingL + $fpaddingL;
  4363. if ($align == 'R') { $this->x += $empty; }
  4364. else if ($align == 'J' && $blockdir == 'rtl') { $this->x += $empty; }
  4365. else if ($align == 'C') { $this->x += ($empty / 2); }
  4366. // Paragraph INDENT
  4367. $WidthCorrection = 0;
  4368. if (($newblock) && ($blockstate==1 || $blockstate==3) && isset($this->blk[$this->blklvl]['text_indent']) && ($lineCount == 0) && (!$is_table) && (!$is_list) && ($align !='C')) {
  4369. $ti = $this->ConvertSize($this->blk[$this->blklvl]['text_indent'],$this->blk[$this->blklvl]['inner_width'],$this->FontSize,false);
  4370. $this->x += $ti;
  4371. }
  4372. foreach ( $content as $k => $chunk )
  4373. {
  4374. // FOR IMAGES
  4375. if ((($blockdir == 'rtl') && ($contains_rtl )) || $all_rtl ) { $dirk = $arraysize-1 - $k; } else { $dirk = $k; }
  4376. $va = 'M'; // default for text
  4377. if (isset($this->objectbuffer[$dirk]) && $this->objectbuffer[$dirk]) {
  4378. $xadj = $this->x - $this->objectbuffer[$dirk]['OUTER-X'];
  4379. $this->objectbuffer[$dirk]['OUTER-X'] += $xadj;
  4380. $this->objectbuffer[$dirk]['BORDER-X'] += $xadj;
  4381. $this->objectbuffer[$dirk]['INNER-X'] += $xadj;
  4382. $va = $this->objectbuffer[$dirk]['vertical-align'];
  4383. $yadj = $this->y - $this->objectbuffer[$dirk]['OUTER-Y'];
  4384. if ($va == 'BS') {
  4385. $yadj += $af + ($this->linemaxfontsize * (0.5 + $this->baselineC)) - $this->objectbuffer[$dirk]['OUTER-HEIGHT'];
  4386. }
  4387. else if ($va == 'M' || $va == '') {
  4388. $yadj += $af + ($this->linemaxfontsize /2) - ($this->objectbuffer[$dirk]['OUTER-HEIGHT']/2);
  4389. }
  4390. else if ($va == 'TB') {
  4391. $yadj += $af + $this->linemaxfontsize - $this->objectbuffer[$dirk]['OUTER-HEIGHT'];
  4392. }
  4393. else if ($va == 'TT') {
  4394. $yadj += $af;
  4395. }
  4396. else if ($va == 'B') {
  4397. $yadj += $af + $this->linemaxfontsize + $bf - $this->objectbuffer[$dirk]['OUTER-HEIGHT'];
  4398. }
  4399. else if ($va == 'T') {
  4400. $yadj += 0;
  4401. }
  4402. $this->objectbuffer[$dirk]['OUTER-Y'] += $yadj;
  4403. $this->objectbuffer[$dirk]['BORDER-Y'] += $yadj;
  4404. $this->objectbuffer[$dirk]['INNER-Y'] += $yadj;
  4405. }
  4406. // DIRECTIONALITY RTL
  4407. if ((($blockdir == 'rtl') && ($contains_rtl )) || $all_rtl ) { $this->restoreFont( $font[ $arraysize-1 - $k ] ); }
  4408. else { $this->restoreFont( $font[ $k ] ); }
  4409. $this->SetSpacing(($this->fixedlSpacing*_MPDFK)+$jcharspacing,($this->fixedlSpacing+$this->minwSpacing)*_MPDFK+$jws);
  4410. $this->fixedlSpacing = false;
  4411. $this->minwSpacing = 0;
  4412. // *********** SPAN BACKGROUND COLOR ***************** //
  4413. if (isset($this->spanbgcolor) && $this->spanbgcolor) {
  4414. $cor = $this->spanbgcolorarray;
  4415. $this->SetFColor($cor);
  4416. $save_fill = $fill; $spanfill = 1; $fill = 1;
  4417. }
  4418. if (!empty($this->spanborddet)) {
  4419. if (strpos($contentB[$k],'L')!==false && isset($this->spanborddet['L'])) $this->x += $this->spanborddet['L']['w'];
  4420. if (strpos($contentB[$k],'L')===false) $this->spanborddet['L']['s'] = $this->spanborddet['L']['w'] = 0;
  4421. if (strpos($contentB[$k],'R')===false) $this->spanborddet['R']['s'] = $this->spanborddet['R']['w'] = 0;
  4422. }
  4423. // WORD SPACING
  4424. $stringWidth = $this->GetStringWidth($chunk ) + ( $this->charspacing * mb_strlen($chunk,$this->mb_enc ) / _MPDFK )
  4425. + ( $this->ws * mb_substr_count($chunk,' ',$this->mb_enc ) / _MPDFK );
  4426. if (isset($this->objectbuffer[$dirk])) {
  4427. if ($this->objectbuffer[$dirk]['type']=='dottab') {
  4428. $this->objectbuffer[$dirk]['OUTER-WIDTH'] +=$empty;
  4429. }
  4430. $stringWidth = $this->objectbuffer[$dirk]['OUTER-WIDTH'];
  4431. }
  4432. if ($stringWidth==0) { $stringWidth = 0.000001; }
  4433. if ($k == $arraysize-1) $this->Cell( $stringWidth, $lineHeight, $chunk, '', 1, '', $fill, $this->HREF , $currentx,0,0,'M', $fill, $af, $bf, true ); //mono-style line or last part (skips line)
  4434. else $this->Cell( $stringWidth, $lineHeight, $chunk, '', 0, '', $fill, $this->HREF, 0, 0,0,'M', $fill, $af, $bf, true );//first or middle part
  4435. if (!empty($this->spanborddet)) {
  4436. if (strpos($contentB[$k],'R')!==false && $k != $arraysize-1) $this->x += $this->spanborddet['R']['w'];
  4437. }
  4438. // *********** SPAN BACKGROUND COLOR OFF - RESET BLOCK BGCOLOR ***************** //
  4439. if (isset($spanfill) && $spanfill) {
  4440. $fill = $save_fill; $spanfill = 0;
  4441. if ($fill) { $this->SetFColor($bcor); }
  4442. }
  4443. }
  4444. $this->printobjectbuffer($is_table, $blockdir);
  4445. $this->objectbuffer = array();
  4446. $this->ResetSpacing();
  4447. /*-- LISTS --*/
  4448. // LIST BULLETS/NUMBERS
  4449. if ($is_list && is_array($this->bulletarray) && ($lineCount == 0) ) {
  4450. $savedFont = $this->saveFont();
  4451. $bull = $this->bulletarray;
  4452. if (isset($bull['level']) && isset($bull['occur']) && isset($this->InlineProperties['LIST'][$bull['level']][$bull['occur']])) {
  4453. $this->restoreInlineProperties($this->InlineProperties['LIST'][$bull['level']][$bull['occur']]);
  4454. }
  4455. if (isset($bull['level']) && isset($bull['occur']) && isset($bull['num']) && isset($this->InlineProperties['LISTITEM'][$bull['level']][$bull['occur']][$bull['num']]) && $this->InlineProperties['LISTITEM'][$bull['level']][$bull['occur']][$bull['num']]) { $this->restoreInlineProperties($this->InlineProperties['LISTITEM'][$bull['level']][$bull['occur']][$bull['num']]); }
  4456. if (isset($bull['font']) && $bull['font'] == 'czapfdingbats') {
  4457. $this->bullet = true;
  4458. $this->SetFont('czapfdingbats','',$this->FontSizePt/2.5);
  4459. }
  4460. else { $this->SetFont($this->FontFamily,$this->FontStyle,$this->FontSizePt,true,true); } // force output
  4461. //Output bullet
  4462. $this->x = $currentx;
  4463. if (isset($bull['x'])) { $this->x += $bull['x']; }
  4464. $this->y -= $lineHeight;
  4465. if (is_array($bull['col'])) { $this->SetTColor($bull['col']); }
  4466. if (isset($bull['txt'])) { $this->Cell($bull['w'], $lineHeight,$bull['txt'],'','',$bull['align'],0,'',0,-$this->cMarginL, -$this->cMarginR ); }
  4467. if (isset($bull['font']) && $bull['font'] == 'czapfdingbats') {
  4468. $this->bullet = false;
  4469. }
  4470. $this->x = $currentx; // Reset
  4471. $this->y += $lineHeight;
  4472. if ($this->ColActive && !$is_table) { $this->breakpoints[$this->CurrCol][] = $this->y; } // *COLUMNS*
  4473. $this->restoreFont( $savedFont );
  4474. // $font = array( $savedFont );
  4475. $this->bulletarray = array(); // prevents repeat of bullet/number if <li>....<br />.....</li>
  4476. }
  4477. /*-- END LISTS --*/
  4478. } // END IF CONTENT
  4479. /*-- CSS-IMAGE-FLOAT --*/
  4480. // Update values if set to skipline
  4481. if ($this->floatmargins) { $this->_advanceFloatMargins(); }
  4482. if ($endofblock && $blockstate>1) {
  4483. // If float exists at this level
  4484. if (isset($this->floatmargins['R']['y1'])) { $fry1 = $this->floatmargins['R']['y1']; }
  4485. else { $fry1 = 0; }
  4486. if (isset($this->floatmargins['L']['y1'])) { $fly1 = $this->floatmargins['L']['y1']; }
  4487. else { $fly1 = 0; }
  4488. if ($this->y < $fry1 || $this->y < $fly1) {
  4489. $drop = max($fry1,$fly1) - $this->y;
  4490. $this->DivLn($drop);
  4491. $this->x = $currentx;
  4492. }
  4493. }
  4494. /*-- END CSS-IMAGE-FLOAT --*/
  4495. // PADDING and BORDER spacing/fill
  4496. if ($endofblock && ($blockstate > 1) && ($this->blk[$this->blklvl]['padding_bottom'] || $this->blk[$this->blklvl]['border_bottom'] || $this->blk[$this->blklvl]['css_set_height']) && (!$is_table) && (!$is_list)) {
  4497. // If CSS height set, extend bottom - if on same page as block started, and CSS HEIGHT > actual height,
  4498. // and does not force pagebreak
  4499. $extra = 0;
  4500. if ($this->blk[$this->blklvl]['css_set_height'] && $this->blk[$this->blklvl]['startpage']==$this->page) {
  4501. // predicted height
  4502. $h1 = ($this->y-$this->blk[$this->blklvl]['y0']) + $this->blk[$this->blklvl]['padding_bottom'] + $this->blk[$this->blklvl]['border_bottom']['w'];
  4503. if ($h1 < ($this->blk[$this->blklvl]['css_set_height']+$this->blk[$this->blklvl]['padding_bottom']+$this->blk[$this->blklvl]['padding_top'])) { $extra = ($this->blk[$this->blklvl]['css_set_height']+$this->blk[$this->blklvl]['padding_bottom']+$this->blk[$this->blklvl]['padding_top']) - $h1; }
  4504. if($this->y + $this->blk[$this->blklvl]['padding_bottom'] + $this->blk[$this->blklvl]['border_bottom']['w'] + $extra > $this->PageBreakTrigger) {
  4505. $extra = $this->PageBreakTrigger - ($this->y + $this->blk[$this->blklvl]['padding_bottom'] + $this->blk[$this->blklvl]['border_bottom']['w']);
  4506. }
  4507. }
  4508. // $state = 0 normal; 1 top; 2 bottom; 3 top and bottom
  4509. $this->DivLn($this->blk[$this->blklvl]['padding_bottom'] + $this->blk[$this->blklvl]['border_bottom']['w'] + $extra,-3,true,false,2);
  4510. $this->x = $currentx;
  4511. if ($this->ColActive) { $this->breakpoints[$this->CurrCol][] = $this->y; } // *COLUMNS*
  4512. }
  4513. // SET Bottom y1 of block (used for painting borders)
  4514. if (($endofblock) && ($blockstate > 1) && (!$is_table) && (!$is_list)) {
  4515. $this->blk[$this->blklvl]['y1'] = $this->y;
  4516. }
  4517. // BOTTOM MARGIN
  4518. if (($endofblock) && ($blockstate > 1) && ($this->blk[$this->blklvl]['margin_bottom']) && (!$is_table) && (!$is_list)) {
  4519. if($this->y+$this->blk[$this->blklvl]['margin_bottom'] < $this->PageBreakTrigger and !$this->InFooter) {
  4520. $this->DivLn($this->blk[$this->blklvl]['margin_bottom'],$this->blklvl-1,true,$this->blk[$this->blklvl]['margin_collapse']);
  4521. if ($this->ColActive) { $this->breakpoints[$this->CurrCol][] = $this->y; } // *COLUMNS*
  4522. }
  4523. }
  4524. // Reset lineheight
  4525. $lineHeight = $this->divheight;
  4526. }
  4527. function printobjectbuffer($is_table=false, $blockdir=false) {
  4528. if (!$blockdir) { $blockdir = $this->directionality; }
  4529. if ($is_table && $this->shrin_k > 1) { $k = $this->shrin_k; }
  4530. else { $k = 1; }
  4531. $save_y = $this->y;
  4532. $save_x = $this->x;
  4533. $save_currentfontfamily = $this->FontFamily;
  4534. $save_currentfontsize = $this->FontSizePt;
  4535. $save_currentfontstyle = $this->FontStyle.($this->U ? 'U' : '').($this->S ? 'S' : '');
  4536. if ($blockdir == 'rtl') { $rtlalign = 'R'; } else { $rtlalign = 'L'; }
  4537. foreach ($this->objectbuffer AS $ib => $objattr) {
  4538. if ($objattr['type'] == 'bookmark' || $objattr['type'] == 'indexentry' || $objattr['type'] == 'toc') {
  4539. $x = $objattr['OUTER-X'];
  4540. $y = $objattr['OUTER-Y'];
  4541. $this->y = $y - $this->FontSize/2;
  4542. $this->x = $x;
  4543. if ($objattr['type'] == 'bookmark' ) { $this->Bookmark($objattr['CONTENT'],$objattr['bklevel'] ,$y - $this->FontSize); } // *BOOKMARKS*
  4544. if ($objattr['type'] == 'indexentry') { $this->IndexEntry($objattr['CONTENT']); } // *INDEX*
  4545. if ($objattr['type'] == 'toc') { $this->TOC_Entry($objattr['CONTENT'], $objattr['toclevel'], $objattr['toc_id']); } // *TOC*
  4546. }
  4547. /*-- ANNOTATIONS --*/
  4548. else if ($objattr['type'] == 'annot') {
  4549. if ($objattr['POS-X']) { $x = $objattr['POS-X']; }
  4550. else if ($this->annotMargin<>0) { $x = -$objattr['OUTER-X']; }
  4551. else { $x = $objattr['OUTER-X']; }
  4552. if ($objattr['POS-Y']) { $y = $objattr['POS-Y']; }
  4553. else { $y = $objattr['OUTER-Y'] - $this->FontSize/2; }
  4554. // Create a dummy entry in the _out/columnBuffer with position sensitive data,
  4555. // linking $y-1 in the Columnbuffer with entry in $this->columnAnnots
  4556. // and when columns are split in length will not break annotation from current line
  4557. $this->y = $y-1;
  4558. $this->x = $x-1;
  4559. $this->Line($x-1,$y-1,$x-1,$y-1);
  4560. $this->Annotation($objattr['CONTENT'], $x , $y , $objattr['ICON'], $objattr['AUTHOR'], $objattr['SUBJECT'], $objattr['OPACITY'], $objattr['COLOR'], $objattr['POPUP'], $objattr['FILE']);
  4561. }
  4562. /*-- END ANNOTATIONS --*/
  4563. else {
  4564. $y = $objattr['OUTER-Y'];
  4565. $x = $objattr['OUTER-X'];
  4566. $w = $objattr['OUTER-WIDTH'];
  4567. $h = $objattr['OUTER-HEIGHT'];
  4568. if (isset($objattr['text'])) { $texto = $objattr['text']; }
  4569. $this->y = $y;
  4570. $this->x = $x;
  4571. if (isset($objattr['fontfamily'])) { $this->SetFont($objattr['fontfamily'],'',$objattr['fontsize'] ); }
  4572. }
  4573. // HR
  4574. if ($objattr['type'] == 'hr') {
  4575. $this->SetDColor($objattr['color']);
  4576. switch($objattr['align']) {
  4577. case 'C':
  4578. $empty = $objattr['OUTER-WIDTH'] - $objattr['INNER-WIDTH'];
  4579. $empty /= 2;
  4580. $x += $empty;
  4581. break;
  4582. case 'R':
  4583. $empty = $objattr['OUTER-WIDTH'] - $objattr['INNER-WIDTH'];
  4584. $x += $empty;
  4585. break;
  4586. }
  4587. $oldlinewidth = $this->LineWidth;
  4588. $this->SetLineWidth($objattr['linewidth']/$k );
  4589. $this->y += ($objattr['linewidth']/2) + $objattr['margin_top']/$k;
  4590. $this->Line($x,$this->y,$x+$objattr['INNER-WIDTH'],$this->y);
  4591. $this->SetLineWidth($oldlinewidth);
  4592. $this->SetDColor($this->ConvertColor(0));
  4593. }
  4594. // IMAGE
  4595. if ($objattr['type'] == 'image') {
  4596. if(isset($objattr['visibility']) && $objattr['visibility']!='visible' && $objattr['visibility']) {
  4597. $this->SetVisibility($objattr['visibility']);
  4598. }
  4599. if (isset($objattr['opacity'])) { $this->SetAlpha($objattr['opacity']); }
  4600. $rotate = 0;
  4601. $obiw = $objattr['INNER-WIDTH'];
  4602. $obih = $objattr['INNER-HEIGHT'];
  4603. $sx = $objattr['INNER-WIDTH']*_MPDFK / $objattr['orig_w'];
  4604. $sy = abs($objattr['INNER-HEIGHT'])*_MPDFK / abs($objattr['orig_h']);
  4605. $sx = ($objattr['INNER-WIDTH']*_MPDFK / $objattr['orig_w']);
  4606. $sy = ($objattr['INNER-HEIGHT']*_MPDFK / $objattr['orig_h']);
  4607. if (isset($objattr['ROTATE'])) { $rotate = $objattr['ROTATE']; }
  4608. if ($rotate==90) {
  4609. // Clockwise
  4610. $obiw = $objattr['INNER-HEIGHT'];
  4611. $obih = $objattr['INNER-WIDTH'];
  4612. $tr = $this->transformTranslate(0, -$objattr['INNER-WIDTH'], true) ;
  4613. $tr .= ' '. $this->transformRotate(90, $objattr['INNER-X'],($objattr['INNER-Y'] +$objattr['INNER-WIDTH'] ),true) ;
  4614. $sx = $obiw*_MPDFK / $objattr['orig_h'];
  4615. $sy = $obih*_MPDFK / $objattr['orig_w'];
  4616. }
  4617. else if ($rotate==-90 || $rotate==270) {
  4618. // AntiClockwise
  4619. $obiw = $objattr['INNER-HEIGHT'];
  4620. $obih = $objattr['INNER-WIDTH'];
  4621. $tr = $this->transformTranslate($objattr['INNER-WIDTH'], ($objattr['INNER-HEIGHT']-$objattr['INNER-WIDTH']), true) ;
  4622. $tr .= ' '. $this->transformRotate(-90, $objattr['INNER-X'],($objattr['INNER-Y'] +$objattr['INNER-WIDTH'] ),true) ;
  4623. $sx = $obiw*_MPDFK / $objattr['orig_h'];
  4624. $sy = $obih*_MPDFK / $objattr['orig_w'];
  4625. }
  4626. else if ($rotate==180) {
  4627. // Mirror
  4628. $tr = $this->transformTranslate($objattr['INNER-WIDTH'], -$objattr['INNER-HEIGHT'], true) ;
  4629. $tr .= ' '. $this->transformRotate(180, $objattr['INNER-X'],($objattr['INNER-Y'] +$objattr['INNER-HEIGHT'] ),true) ;
  4630. }
  4631. else { $tr = ''; }
  4632. $tr = trim($tr);
  4633. if ($tr) { $tr .= ' '; }
  4634. $gradmask = '';
  4635. /*-- BACKGROUNDS --*/
  4636. if (isset($objattr['GRADIENT-MASK'])) {
  4637. $g = $this->grad->parseMozGradient( $objattr['GRADIENT-MASK'] );
  4638. if ($g) {
  4639. $dummy = $this->grad->Gradient($objattr['INNER-X'], $objattr['INNER-Y'], $obiw, $obih, $g['type'], $g['stops'], $g['colorspace'], $g['coords'], $g['extend'], true, true);
  4640. $gradmask = '/TGS'.count($this->gradients).' gs ';
  4641. // $this->_out("q ".$tr.$this->grad->Gradient($objattr['INNER-X'], $objattr['INNER-Y'], $obiw, $obih, $g['type'], $g['stops'], $g['colorspace'], $g['coords'], $g['extend'], true)." Q");
  4642. }
  4643. }
  4644. /*-- END BACKGROUNDS --*/
  4645. /*-- IMAGES-WMF --*/
  4646. if (isset($objattr['itype']) && $objattr['itype']=='wmf') {
  4647. $outstring = sprintf('q '.$tr.'%.3F 0 0 %.3F %.3F %.3F cm /FO%d Do Q', $sx, -$sy, $objattr['INNER-X']*_MPDFK-$sx*$objattr['wmf_x'], (($this->h-$objattr['INNER-Y'])*_MPDFK)+$sy*$objattr['wmf_y'], $objattr['ID']);
  4648. }
  4649. else
  4650. /*-- END IMAGES-WMF --*/
  4651. if (isset($objattr['itype']) && $objattr['itype']=='svg') {
  4652. $outstring = sprintf('q '.$tr.'%.3F 0 0 %.3F %.3F %.3F cm /FO%d Do Q', $sx, -$sy, $objattr['INNER-X']*_MPDFK-$sx*$objattr['wmf_x'], (($this->h-$objattr['INNER-Y'])*_MPDFK)+$sy*$objattr['wmf_y'], $objattr['ID']);
  4653. }
  4654. else {
  4655. $outstring = sprintf("q ".$tr."%.3F 0 0 %.3F %.3F %.3F cm ".$gradmask."/I%d Do Q",$obiw*_MPDFK, $obih*_MPDFK, $objattr['INNER-X'] *_MPDFK, ($this->h-($objattr['INNER-Y'] +$obih ))*_MPDFK,$objattr['ID'] );
  4656. }
  4657. $this->_out($outstring);
  4658. // LINK
  4659. if (isset($objattr['link'])) $this->Link($objattr['INNER-X'],$objattr['INNER-Y'],$objattr['INNER-WIDTH'],$objattr['INNER-HEIGHT'],$objattr['link']);
  4660. if (isset($objattr['opacity'])) { $this->SetAlpha(1); }
  4661. if ((isset($objattr['border_top']) && $objattr['border_top']>0) || (isset($objattr['border_left']) && $objattr['border_left']>0) || (isset($objattr['border_right']) && $objattr['border_right']>0) || (isset($objattr['border_bottom']) && $objattr['border_bottom']>0)) { $this->PaintImgBorder($objattr,$is_table); }
  4662. if(isset($objattr['visibility']) && $objattr['visibility']!='visible' && $objattr['visibility']) {
  4663. $this->SetVisibility('visible');
  4664. }
  4665. }
  4666. /*-- BARCODES --*/
  4667. // BARCODE
  4668. if ($objattr['type'] == 'barcode') {
  4669. $bgcol = $this->ConvertColor(255);
  4670. if (isset($objattr['bgcolor']) && $objattr['bgcolor']) {
  4671. $bgcol = $objattr['bgcolor'];
  4672. }
  4673. $col = $this->ConvertColor(0);
  4674. if (isset($objattr['color']) && $objattr['color']) {
  4675. $col = $objattr['color'];
  4676. }
  4677. $this->SetFColor($bgcol);
  4678. $this->Rect($objattr['BORDER-X'], $objattr['BORDER-Y'], $objattr['BORDER-WIDTH'], $objattr['BORDER-HEIGHT'], 'F');
  4679. $this->SetFColor($this->ConvertColor(255));
  4680. if (isset($objattr['BORDER-WIDTH'])) { $this->PaintImgBorder($objattr,$is_table); }
  4681. if ($objattr['btype'] == 'EAN13' || $objattr['btype'] == 'ISBN' || $objattr['btype'] == 'ISSN' || $objattr['btype'] == 'UPCA' || $objattr['btype'] == 'UPCE' || $objattr['btype'] == 'EAN8') {
  4682. $this->WriteBarcode($objattr['code'], $objattr['showtext'], $objattr['INNER-X'], $objattr['INNER-Y'], $objattr['bsize'], 0, 0, 0, 0, 0, $objattr['bheight'], $bgcol, $col, $objattr['btype'], $objattr['bsupp'], $objattr['bsupp_code'], $k);
  4683. }
  4684. // QR-code
  4685. else if ($objattr['btype']=='QR') {
  4686. if (!class_exists('QRcode', false)) {
  4687. include(_MPDF_PATH.'qrcode/qrcode.class.php');
  4688. }
  4689. $this->qrcode = new QRcode($objattr['code'], $objattr['errorlevel']);
  4690. $this->qrcode->displayFPDF($this, $objattr['INNER-X'], $objattr['INNER-Y'], $objattr['bsize']*25, array(255,255,255), array(0,0,0));
  4691. }
  4692. else {
  4693. $this->WriteBarcode2($objattr['code'], $objattr['INNER-X'], $objattr['INNER-Y'], $objattr['bsize'], $objattr['bheight'], $bgcol, $col, $objattr['btype'], $objattr['pr_ratio'], $k);
  4694. }
  4695. }
  4696. /*-- END BARCODES --*/
  4697. // TEXT CIRCLE
  4698. if ($objattr['type'] == 'textcircle') {
  4699. $bgcol = ''; // mPDF 5.5.14
  4700. if (isset($objattr['bgcolor']) && $objattr['bgcolor']) {
  4701. $bgcol = $objattr['bgcolor'];
  4702. }
  4703. $col = $this->ConvertColor(0);
  4704. if (isset($objattr['color']) && $objattr['color']) {
  4705. $col = $objattr['color'];
  4706. }
  4707. $this->SetTColor($col);
  4708. $this->SetFColor($bgcol);
  4709. if ($bgcol) $this->Rect($objattr['BORDER-X'], $objattr['BORDER-Y'], $objattr['BORDER-WIDTH'], $objattr['BORDER-HEIGHT'], 'F'); // mPDF 5.5.14
  4710. $this->SetFColor($this->ConvertColor(255));
  4711. if (isset($objattr['BORDER-WIDTH'])) { $this->PaintImgBorder($objattr,$is_table); }
  4712. if (!class_exists('directw', false)) { include(_MPDF_PATH.'classes/directw.php'); }
  4713. if (empty($this->directw)) { $this->directw = new directw($this); }
  4714. $save_lmfs = $this->linemaxfontsize;
  4715. $this->linemaxfontsize = 0;
  4716. if (isset($objattr['top-text'])) {
  4717. $this->directw->CircularText($objattr['INNER-X']+$objattr['INNER-WIDTH']/2, $objattr['INNER-Y']+$objattr['INNER-HEIGHT']/2, $objattr['r']/$k, $objattr['top-text'], 'top', $objattr['fontfamily'], $objattr['fontsize']/$k, $objattr['fontstyle'], $objattr['space-width'], $objattr['char-width'], $objattr['divider']); // mPDF 5.5.23
  4718. }
  4719. if (isset($objattr['bottom-text'])) {
  4720. $this->directw->CircularText($objattr['INNER-X']+$objattr['INNER-WIDTH']/2, $objattr['INNER-Y']+$objattr['INNER-HEIGHT']/2, $objattr['r']/$k, $objattr['bottom-text'], 'bottom', $objattr['fontfamily'], $objattr['fontsize']/$k, $objattr['fontstyle'], $objattr['space-width'], $objattr['char-width'], $objattr['divider']); // mPDF 5.5.23
  4721. }
  4722. $this->linemaxfontsize = $save_lmfs;
  4723. }
  4724. $this->ResetSpacing();
  4725. // DOT-TAB
  4726. if ($objattr['type'] == 'dottab') {
  4727. $sp = $this->GetStringWidth(' ');
  4728. $nb=floor(($w-2*$sp)/$this->GetStringWidth('.'));
  4729. if ($nb>0) { $dots=' '.str_repeat('.',$nb).' '; }
  4730. else { $dots=' '; }
  4731. $col = $this->ConvertColor(0);
  4732. if (isset($objattr['colorarray']) && is_array($objattr['colorarray'])) {
  4733. $col = $objattr['colorarray'];
  4734. }
  4735. $this->SetTColor($col);
  4736. $save_sbd = $this->spanborddet;
  4737. $save_u = $this->U;
  4738. $save_s = $this->strike;
  4739. $this->spanborddet = '';
  4740. $this->U = false;
  4741. $this->strike = false;
  4742. $this->Cell($w,$h,$dots,0,0,'C');
  4743. $this->spanborddet = $save_sbd;
  4744. $this->U = $save_u;
  4745. $this->strike = $save_s;
  4746. // mPDF 5.0
  4747. $this->SetTColor($this->ConvertColor(0));
  4748. }
  4749. /*-- FORMS --*/
  4750. // TEXT/PASSWORD INPUT
  4751. if ($objattr['type'] == 'input' && ($objattr['subtype'] == 'TEXT' || $objattr['subtype'] == 'PASSWORD')) {
  4752. $this->form->print_ob_text($objattr,$w,$h,$texto,$rtlalign,$k,$blockdir);
  4753. }
  4754. // TEXTAREA
  4755. if ($objattr['type'] == 'textarea') {
  4756. $this->form->print_ob_textarea($objattr,$w,$h,$texto,$rtlalign,$k,$blockdir);
  4757. }
  4758. // SELECT
  4759. if ($objattr['type'] == 'select') {
  4760. $this->form->print_ob_select($objattr,$w,$h,$texto,$rtlalign,$k,$blockdir);
  4761. }
  4762. // INPUT/BUTTON as IMAGE
  4763. if ($objattr['type'] == 'input' && $objattr['subtype'] == 'IMAGE') {
  4764. $this->form->print_ob_imageinput($objattr,$w,$h,$texto,$rtlalign,$k,$blockdir);
  4765. }
  4766. // BUTTON
  4767. if ($objattr['type'] == 'input' && ($objattr['subtype'] == 'SUBMIT' || $objattr['subtype'] == 'RESET' || $objattr['subtype'] == 'BUTTON')) {
  4768. $this->form->print_ob_button($objattr,$w,$h,$texto,$rtlalign,$k,$blockdir);
  4769. }
  4770. // CHECKBOX
  4771. if ($objattr['type'] == 'input' && ($objattr['subtype'] == 'CHECKBOX')) {
  4772. $this->form->print_ob_checkbox($objattr,$w,$h,$texto,$rtlalign,$k,$blockdir,$x,$y);
  4773. }
  4774. // RADIO
  4775. if ($objattr['type'] == 'input' && ($objattr['subtype'] == 'RADIO')) {
  4776. $this->form->print_ob_radio($objattr,$w,$h,$texto,$rtlalign,$k,$blockdir,$x,$y);
  4777. }
  4778. /*-- END FORMS --*/
  4779. }
  4780. $this->SetFont($save_currentfontfamily,$save_currentfontstyle,$save_currentfontsize);
  4781. $this->y = $save_y;
  4782. $this->x = $save_x;
  4783. unset($content);
  4784. }
  4785. function WriteFlowingBlock( $s)
  4786. {
  4787. $currentx = $this->x;
  4788. $is_table = $this->flowingBlockAttr[ 'is_table' ];
  4789. $is_list = $this->flowingBlockAttr[ 'is_list' ];
  4790. // width of all the content so far in points
  4791. $contentWidth =& $this->flowingBlockAttr[ 'contentWidth' ];
  4792. // cell width in points
  4793. $maxWidth =& $this->flowingBlockAttr[ 'width' ];
  4794. $lineCount =& $this->flowingBlockAttr[ 'lineCount' ];
  4795. // line height in user units
  4796. $lineHeight =& $this->flowingBlockAttr[ 'height' ];
  4797. $align =& $this->flowingBlockAttr[ 'align' ];
  4798. $content =& $this->flowingBlockAttr[ 'content' ];
  4799. $contentB =& $this->flowingBlockAttr[ 'contentB' ];
  4800. $font =& $this->flowingBlockAttr[ 'font' ];
  4801. $valign =& $this->flowingBlockAttr[ 'valign' ];
  4802. $blockstate = $this->flowingBlockAttr[ 'blockstate' ];
  4803. $newblock = $this->flowingBlockAttr[ 'newblock' ];
  4804. $blockdir = $this->flowingBlockAttr['blockdir'];
  4805. // *********** BLOCK BACKGROUND COLOR ***************** //
  4806. if ($this->blk[$this->blklvl]['bgcolor'] && !$is_table) {
  4807. $fill = 0;
  4808. }
  4809. else {
  4810. $this->SetFColor($this->ConvertColor(255));
  4811. $fill = 0;
  4812. }
  4813. $font[] = $this->saveFont();
  4814. $content[] = '';
  4815. $contentB[] = '';
  4816. $currContent =& $content[ count( $content ) - 1 ];
  4817. // where the line should be cutoff if it is to be justified
  4818. $cutoffWidth = $contentWidth;
  4819. $curlyquote = mb_convert_encoding("\xe2\x80\x9e",$this->mb_enc,'UTF-8');
  4820. $curlylowquote = mb_convert_encoding("\xe2\x80\x9d",$this->mb_enc,'UTF-8');
  4821. // mPDF 5.5.07
  4822. $raquote = mb_convert_encoding("\xc2\xbb",$this->mb_enc,'UTF-8'); //&#187; &raquo;
  4823. // mPDF 5.5.20
  4824. $rsquo = mb_convert_encoding("\xe2\x80\x99",$this->mb_enc,'UTF-8'); //&#8217; &rsquo;
  4825. $sbquo = mb_convert_encoding("\xe2\x80\x9a",$this->mb_enc,'UTF-8'); //&#8218; &sbquo;
  4826. $bdquo = mb_convert_encoding("\xe2\x80\xba",$this->mb_enc,'UTF-8'); //&#8222; &bdquo;
  4827. $CJKoverflow = false;
  4828. // COLS
  4829. $oldcolumn = $this->CurrCol;
  4830. if ($this->ColActive && !$is_table) { $this->breakpoints[$this->CurrCol][] = $this->y; } // *COLUMNS*
  4831. /*-- TABLES --*/
  4832. if ($is_table) {
  4833. $ipaddingL = 0;
  4834. $ipaddingR = 0;
  4835. $paddingL = 0;
  4836. $paddingR = 0;
  4837. $cpaddingadjustL = 0;
  4838. $cpaddingadjustR = 0;
  4839. // Added mPDF 3.0
  4840. $fpaddingR = 0;
  4841. $fpaddingL = 0;
  4842. }
  4843. else {
  4844. /*-- END TABLES --*/
  4845. $ipaddingL = $this->blk[$this->blklvl]['padding_left'];
  4846. $ipaddingR = $this->blk[$this->blklvl]['padding_right'];
  4847. $paddingL = ($ipaddingL * _MPDFK);
  4848. $paddingR = ($ipaddingR * _MPDFK);
  4849. $this->cMarginL = $this->blk[$this->blklvl]['border_left']['w'];
  4850. $cpaddingadjustL = -$this->cMarginL;
  4851. $this->cMarginR = $this->blk[$this->blklvl]['border_right']['w'];
  4852. $cpaddingadjustR = -$this->cMarginR;
  4853. // Added mPDF 3.0 Float DIV
  4854. $fpaddingR = 0;
  4855. $fpaddingL = 0;
  4856. /*-- CSS-FLOAT --*/
  4857. if (count($this->floatDivs)) {
  4858. list($l_exists, $r_exists, $l_max, $r_max, $l_width, $r_width) = $this->GetFloatDivInfo($this->blklvl);
  4859. if ($r_exists) { $fpaddingR = $r_width; }
  4860. if ($l_exists) { $fpaddingL = $l_width; }
  4861. }
  4862. /*-- END CSS-FLOAT --*/
  4863. $usey = $this->y + 0.002;
  4864. if (($newblock) && ($blockstate==1 || $blockstate==3) && ($lineCount == 0) ) {
  4865. $usey += $this->blk[$this->blklvl]['margin_top'] + $this->blk[$this->blklvl]['padding_top'] + $this->blk[$this->blklvl]['border_top']['w'];
  4866. }
  4867. /*-- CSS-IMAGE-FLOAT --*/
  4868. // If float exists at this level
  4869. if (isset($this->floatmargins['R']) && $usey <= $this->floatmargins['R']['y1'] && $usey >= $this->floatmargins['R']['y0'] && !$this->floatmargins['R']['skipline']) { $fpaddingR += $this->floatmargins['R']['w']; }
  4870. if (isset($this->floatmargins['L']) && $usey <= $this->floatmargins['L']['y1'] && $usey >= $this->floatmargins['L']['y0'] && !$this->floatmargins['L']['skipline']) { $fpaddingL += $this->floatmargins['L']['w']; }
  4871. /*-- END CSS-IMAGE-FLOAT --*/
  4872. } // *TABLES*
  4873. //OBJECTS - IMAGES & FORM Elements (NB has already skipped line/page if required - in printbuffer)
  4874. if (substr($s,0,3) == "\xbb\xa4\xac") { //identifier has been identified!
  4875. $objattr = $this->_getObjAttr($s);
  4876. $h_corr = 0;
  4877. if ($is_table) { // *TABLES*
  4878. $maximumW = ($maxWidth/_MPDFK) - ($this->cellPaddingL + $this->cMarginL + $this->cellPaddingR + $this->cMarginR); // *TABLES*
  4879. } // *TABLES*
  4880. else { // *TABLES*
  4881. if (($newblock) && ($blockstate==1 || $blockstate==3) && ($lineCount == 0) && (!$is_table)) { $h_corr = $this->blk[$this->blklvl]['padding_top'] + $this->blk[$this->blklvl]['border_top']['w']; }
  4882. $maximumW = ($maxWidth/_MPDFK) - ($this->blk[$this->blklvl]['padding_left'] + $this->blk[$this->blklvl]['border_left']['w'] + $this->blk[$this->blklvl]['padding_right'] + $this->blk[$this->blklvl]['border_right']['w'] + $fpaddingL + $fpaddingR );
  4883. } // *TABLES*
  4884. $objattr = $this->inlineObject($objattr['type'],$this->lMargin + $fpaddingL + ($contentWidth/_MPDFK),($this->y + $h_corr), $objattr, $this->lMargin,($contentWidth/_MPDFK),$maximumW,$lineHeight,true,$is_table);
  4885. // SET LINEHEIGHT for this line ================ RESET AT END
  4886. $lineHeight = MAX($lineHeight,$objattr['OUTER-HEIGHT']);
  4887. $this->objectbuffer[count($content)-1] = $objattr;
  4888. // if (isset($objattr['vertical-align'])) { $valign = $objattr['vertical-align']; }
  4889. // else { $valign = ''; }
  4890. $contentWidth += ($objattr['OUTER-WIDTH'] * _MPDFK);
  4891. return;
  4892. }
  4893. $lbw = $rbw = 0; // Border widths
  4894. if (!empty($this->spanborddet)) {
  4895. if (isset($this->spanborddet['L'])) $lbw = $this->spanborddet['L']['w'];
  4896. if (isset($this->spanborddet['R'])) $rbw = $this->spanborddet['R']['w'];
  4897. }
  4898. if ($this->usingCoreFont) {
  4899. $tmp = strlen( $s );
  4900. }
  4901. else {
  4902. $tmp = mb_strlen( $s, $this->mb_enc );
  4903. }
  4904. $orphs = 0;
  4905. $check = 0;
  4906. // for every character in the string
  4907. for ( $i = 0; $i < $tmp; $i++ ) {
  4908. // extract the current character
  4909. // get the width of the character in points
  4910. if ($this->usingCoreFont) {
  4911. $c = $s[$i];
  4912. // Soft Hyphens chr(173)
  4913. $cw = ($this->GetCharWidthCore($c) * _MPDFK);
  4914. if ($this->kerning && $this->useKerning && $i > 0) {
  4915. if (isset($this->CurrentFont['kerninfo'][$s[($i-1)]][$c])) {
  4916. $cw += ($this->CurrentFont['kerninfo'][$s[($i-1)]][$c] * $this->FontSizePt / 1000 );
  4917. }
  4918. }
  4919. }
  4920. else {
  4921. $c = mb_substr($s,$i,1,$this->mb_enc );
  4922. $cw = ($this->GetCharWidthNonCore($c, false) * _MPDFK);
  4923. if ($this->kerning && $this->useKerning && $i > 0) {
  4924. $lastc = mb_substr($s,($i-1),1,$this->mb_enc );
  4925. $ulastc = $this->UTF8StringToArray($lastc, false);
  4926. $uc = $this->UTF8StringToArray($c, false);
  4927. if (isset($this->CurrentFont['kerninfo'][$ulastc[0]][$uc[0]])) {
  4928. $cw += ($this->CurrentFont['kerninfo'][$ulastc[0]][$uc[0]] * $this->FontSizePt / 1000 );
  4929. }
  4930. }
  4931. }
  4932. if ($i==0) {
  4933. $cw += $lbw*_MPDFK;
  4934. $contentB[(count($contentB)-1)] .= 'L';
  4935. }
  4936. if ($i==($tmp-1)) {
  4937. $cw += $rbw*_MPDFK;
  4938. $contentB[(count($contentB)-1)] .= 'R';
  4939. }
  4940. if ($c==' ') { $check = 1; }
  4941. // CHECK for ORPHANS
  4942. else if ($c=='.' || $c==',' || $c==')' || $c==']' || $c==';' || $c==':' || $c=='!' || $c=='?'|| $c=='"' || $c==$curlyquote || $c==$curlylowquote || $c==$raquote || $c==$rsquo || $c==$sbquo || $c==$bdquo ) {$check++; } // mPDF 5.5.07 mPDF 5.5.20
  4943. /*-- CJK-FONTS --*/
  4944. else if ($this->checkCJK) {
  4945. if ((!$is_table && $this->CJKfollowing && preg_match("/[".$this->CJKfollowing."]/u", $c)) || ($is_table && preg_match("/[".$this->CJKoverflow ."]/u", $c))) { $check++; }
  4946. else { $check = 0; }
  4947. }
  4948. /*-- END CJK-FONTS --*/
  4949. else { $check = 0; }
  4950. // There's an orphan '. ' or ', ' or <sup>32</sup> about to be cut off at the end of line
  4951. if($check==1) {
  4952. $currContent .= $c;
  4953. $cutoffWidth = $contentWidth;
  4954. $contentWidth += $cw;
  4955. continue;
  4956. }
  4957. if(($this->SUP || $this->SUB) && ($orphs < $this->orphansAllowed)) { // ? disable orphans in table if borders used
  4958. $currContent .= $c;
  4959. $cutoffWidth = $contentWidth;
  4960. $contentWidth += $cw;
  4961. $orphs++;
  4962. continue;
  4963. }
  4964. else { $orphs = 0; }
  4965. // ADDED for Paragraph_indent
  4966. $WidthCorrection = 0;
  4967. if (($newblock) && ($blockstate==1 || $blockstate==3) && isset($this->blk[$this->blklvl]['text_indent']) && ($lineCount == 0) && (!$is_table) && (!$is_list) && ($align != 'C')) {
  4968. $ti = $this->ConvertSize($this->blk[$this->blklvl]['text_indent'],$this->blk[$this->blklvl]['inner_width'],$this->FontSize,false);
  4969. $WidthCorrection = ($ti*_MPDFK);
  4970. }
  4971. // Added mPDF 3.0 Float DIV
  4972. $fpaddingR = 0;
  4973. $fpaddingL = 0;
  4974. /*-- CSS-FLOAT --*/
  4975. if (count($this->floatDivs)) {
  4976. list($l_exists, $r_exists, $l_max, $r_max, $l_width, $r_width) = $this->GetFloatDivInfo($this->blklvl);
  4977. if ($r_exists) { $fpaddingR = $r_width; }
  4978. if ($l_exists) { $fpaddingL = $l_width; }
  4979. }
  4980. /*-- END CSS-FLOAT --*/
  4981. $usey = $this->y + 0.002;
  4982. if (($newblock) && ($blockstate==1 || $blockstate==3) && ($lineCount == 0) ) {
  4983. $usey += $this->blk[$this->blklvl]['margin_top'] + $this->blk[$this->blklvl]['padding_top'] + $this->blk[$this->blklvl]['border_top']['w'];
  4984. }
  4985. /*-- CSS-IMAGE-FLOAT --*/
  4986. // If float exists at this level
  4987. if (isset($this->floatmargins['R']) && $usey <= $this->floatmargins['R']['y1'] && $usey >= $this->floatmargins['R']['y0'] && !$this->floatmargins['R']['skipline']) { $fpaddingR += $this->floatmargins['R']['w']; }
  4988. if (isset($this->floatmargins['L']) && $usey <= $this->floatmargins['L']['y1'] && $usey >= $this->floatmargins['L']['y0'] && !$this->floatmargins['L']['skipline']) { $fpaddingL += $this->floatmargins['L']['w']; }
  4989. /*-- END CSS-IMAGE-FLOAT --*/
  4990. // try adding another char
  4991. if (( $contentWidth + $cw > $maxWidth - $WidthCorrection - (($this->cMarginL+$this->cMarginR)*_MPDFK) - ($paddingL+$paddingR +(($fpaddingL + $fpaddingR) * _MPDFK) ) + 0.001)) {// 0.001 is to correct for deviations converting mm=>pts
  4992. // it won't fit, output what we already have
  4993. $lineCount++;
  4994. // contains any content that didn't make it into this print
  4995. $savedContent = '';
  4996. $savedContentB = '';
  4997. $savedFont = array();
  4998. $savedObj = array();
  4999. // cut off and save any partial words at the end of the string
  5000. $words = explode( ' ', $currContent );
  5001. ///////////////////
  5002. // HYPHENATION
  5003. $currWord = $words[count($words)-1] ;
  5004. $success = false;
  5005. /*-- HYPHENATION --*/
  5006. // Soft Hyphens chr(173)
  5007. if ((!$this->usingCoreFont && preg_match("/\xc2\xad/",$currWord)) || ($this->usingCoreFont && preg_match("/".chr(173)."/",$currWord) && ($this->FontFamily!='csymbol' && $this->FontFamily!='czapfdingbats')) ) {
  5008. $rem = $maxWidth - $WidthCorrection - (($this->cMarginL+$this->cMarginR)*_MPDFK) - ($paddingL+$paddingR +(($fpaddingL + $fpaddingR) * _MPDFK) );
  5009. list($success,$pre,$post,$prelength) = $this->softHyphenate($currWord, (($rem-$cutoffWidth)/_MPDFK -$this->GetCharWidthNonCore(" ", false)) );
  5010. }
  5011. if (!$success && ($this->hyphenate || ($this->hyphenateTables && $is_table))) {
  5012. // Look ahead to get current word
  5013. for($ac = $i; $ac<(mb_strlen($s)-1); $ac++) {
  5014. $addc = mb_substr($s,$ac,1,$this->mb_enc );
  5015. if ($addc == ' ') { break; }
  5016. $currWord .= $addc;
  5017. }
  5018. $rem = $maxWidth - $WidthCorrection - (($this->cMarginL+$this->cMarginR)*_MPDFK) - ($paddingL+$paddingR +(($fpaddingL + $fpaddingR) * _MPDFK) );
  5019. list($success,$pre,$post,$prelength) = $this->hyphenateWord($currWord, (($rem-$cutoffWidth)/_MPDFK -$this->GetCharWidth(" ", false)) );
  5020. }
  5021. if ($success) {
  5022. $already = array_pop( $words );
  5023. $forward = mb_substr($already,$prelength,mb_strlen($already, $this->mb_enc), $this->mb_enc);
  5024. $words[] = $pre.'-';
  5025. $words[] = $forward;
  5026. $currContent = mb_substr($currContent,0,mb_strlen($currContent, $this->mb_enc)+1-mb_strlen($post, $this->mb_enc), $this->mb_enc) . '-';
  5027. }
  5028. /*-- END HYPHENATION --*/
  5029. /*-- CJK-FONTS --*/
  5030. // mPDF 5.5.10
  5031. // if current overflow character is CJK
  5032. if ($this->checkCJK && preg_match("/[".$this->pregCJKchars."]/u", $c)) {
  5033. $lastchar = mb_substr($words[(count($words)-1)],mb_strlen($words[(count($words)-1)], $this->mb_enc)-1, 1, $this->mb_enc);
  5034. if ($this->checkCJK) {
  5035. // Last character that fits is not allowed to end a line - move lastchar(s) to start of next line
  5036. if (!$is_table && preg_match("/[".$this->CJKleading."]/u", $lastchar)) {
  5037. //move lastchar(s) to next line
  5038. $m0 = $lastchar;
  5039. $m1 = $c;
  5040. while(preg_match("/[".$this->CJKleading."]/u", $m0) && mb_strlen($words[(count($words)-1)], $this->mb_enc)>2) {
  5041. // trim last letter off word[0]
  5042. $words[(count($words)-1)] = mb_substr($words[(count($words)-1)],0,mb_strlen($words[(count($words)-1)], $this->mb_enc)-1, $this->mb_enc);
  5043. // and add it to savedContent for next line
  5044. $savedContent = $m0.$savedContent;
  5045. $m1 = $lastchar;
  5046. $lastchar = mb_substr($words[(count($words)-1)],mb_strlen($words[(count($words)-1)], $this->mb_enc)-1, 1, $this->mb_enc);
  5047. $m0 = $lastchar;
  5048. }
  5049. }
  5050. // Next character is not allowed to start a new line - move lastchar(s) to next line
  5051. else if (!$is_table && preg_match("/[".$this->CJKfollowing."]/u", $c)) {
  5052. // try squeezing another character(s) onto this line = Oikomi
  5053. if ($this->allowCJKorphans) {
  5054. $lookahead = mb_substr($s,$i+1,1,$this->mb_enc );
  5055. //if lookahead is not another following char
  5056. if ($lookahead && !preg_match("/[".$this->CJKfollowing."]/u", $lookahead)) {
  5057. $currContent .= $c;
  5058. $cutoffWidth = $contentWidth;
  5059. $contentWidth += $cw;
  5060. if ($this->allowCJKoverflow && !$is_table && preg_match("/[".$this->CJKoverflow."]/u", $c)) { $CJKoverflow = true; }
  5061. continue;
  5062. }
  5063. }
  5064. // or move lastchar(s) to next line to keep $c company = Oidashi
  5065. $m0 = $lastchar;
  5066. $m1 = $c;
  5067. while(preg_match("/[".$this->CJKfollowing."]/u", $m1) && mb_strlen($words[(count($words)-1)], $this->mb_enc)>2) {
  5068. // trim last letter off word[0]
  5069. $words[(count($words)-1)] = mb_substr($words[(count($words)-1)],0,mb_strlen($words[(count($words)-1)], $this->mb_enc)-1, $this->mb_enc);
  5070. // and add it to savedContent for next line
  5071. $savedContent = $m0.$savedContent;
  5072. $m1 = $lastchar;
  5073. $lastchar = mb_substr($words[(count($words)-1)],mb_strlen($words[(count($words)-1)], $this->mb_enc)-1, 1, $this->mb_enc);
  5074. $m0 = $lastchar;
  5075. }
  5076. }
  5077. }
  5078. $lastContent = '';
  5079. for ( $w = 0; $w < count( $words ) ; $w++) { $lastContent .= $words[ $w ]." "; }
  5080. $savedFont = $this->saveFont();
  5081. // replace the current content with the cropped version
  5082. $currContent = rtrim( $lastContent );
  5083. }
  5084. else
  5085. /*-- END CJK-FONTS --*/
  5086. // if it looks like we didn't finish any words for this chunk
  5087. if ( count( $words ) == 1 ) {
  5088. // TO correct for error when word too wide for page - but only when one long word from left to right margin
  5089. if (count($content) == 1 && $currContent != ' ') {
  5090. // mPDF 5.5.10
  5091. $lastchar = mb_substr($words[0],mb_strlen($words[0], $this->mb_enc)-1, 1, $this->mb_enc);
  5092. $lastContent = $words[0];
  5093. $savedFont = $this->saveFont();
  5094. // replace the current content with the cropped version
  5095. $currContent = rtrim( $lastContent );
  5096. }
  5097. else {
  5098. // save and crop off the content currently on the stack
  5099. $savedContent = array_pop( $content );
  5100. $savedContentB = $contentB[(count($contentB)-1)];
  5101. $savedFont = array_pop( $font );
  5102. // trim any trailing spaces off the last bit of content
  5103. $currContent =& $content[ count( $content ) - 1 ];
  5104. $currContent = rtrim( $currContent );
  5105. }
  5106. }
  5107. else { // otherwise, we need to find which bit to cut off
  5108. $lastContent = '';
  5109. for ( $w = 0; $w < count( $words ) - 1; $w++) { $lastContent .= $words[ $w ]." "; }
  5110. $savedContent = $words[ count( $words ) - 1 ];
  5111. $savedFont = $this->saveFont();
  5112. // replace the current content with the cropped version
  5113. $currContent = rtrim( $lastContent );
  5114. }
  5115. // CJK - strip CJK space at end of line
  5116. // &#x3000; = \xe3\x80\x80 = CJK space
  5117. if ($this->checkCJK) { $currContent = preg_replace("/\xe3\x80\x80$/",'',$currContent) ; } // *CJK-FONTS*
  5118. if (isset($this->objectbuffer[(count($content)-1)]) && $this->objectbuffer[(count($content)-1)]['type']=='dottab') {
  5119. $savedObj = array_pop( $this->objectbuffer );
  5120. $contentWidth -= ($this->objectbuffer[(count($content)-1)]['OUTER-WIDTH'] * _MPDFK);
  5121. }
  5122. // Set Current lineheight (correction factor)
  5123. $lhfixed = false;
  5124. /*-- LISTS --*/
  5125. if ($is_list) {
  5126. if (preg_match('/([0-9.,]+)mm/',$this->list_lineheight[$this->listlvl][$this->listOcc],$am)) {
  5127. $lhfixed = true;
  5128. $def_fontsize = $this->InlineProperties['LISTITEM'][$this->listlvl][$this->listOcc][$this->listnum]['size'];
  5129. $this->lineheight_correction = $am[1] / $def_fontsize ;
  5130. }
  5131. else {
  5132. $this->lineheight_correction = $this->list_lineheight[$this->listlvl][$this->listOcc];
  5133. }
  5134. }
  5135. else
  5136. /*-- END LISTS --*/
  5137. /*-- TABLES --*/
  5138. if ($is_table) {
  5139. if (preg_match('/([0-9.,]+)mm/',$this->table_lineheight,$am)) {
  5140. $lhfixed = true;
  5141. $def_fontsize = $this->FontSize; // needs to be default font-size for block ****
  5142. $this->lineheight_correction = $lineHeight / $def_fontsize ;
  5143. }
  5144. else {
  5145. $this->lineheight_correction = $this->table_lineheight;
  5146. }
  5147. }
  5148. else
  5149. /*-- END TABLES --*/
  5150. if (isset($this->blk[$this->blklvl]['line_height']) && $this->blk[$this->blklvl]['line_height']) {
  5151. if (preg_match('/([0-9.,]+)mm/',$this->blk[$this->blklvl]['line_height'],$am)) {
  5152. $lhfixed = true;
  5153. $def_fontsize = $this->blk[$this->blklvl]['InlineProperties']['size']; // needs to be default font-size for block ****
  5154. $this->lineheight_correction = $am[1] / $def_fontsize ;
  5155. }
  5156. else {
  5157. $this->lineheight_correction = $this->blk[$this->blklvl]['line_height'];
  5158. }
  5159. }
  5160. else {
  5161. $this->lineheight_correction = $this->normalLineheight;
  5162. }
  5163. // update $contentWidth and $cutoffWidth since they changed with cropping
  5164. // Also correct lineheight to maximum fontsize (not for tables)
  5165. $contentWidth = 0;
  5166. // correct lineheight to maximum fontsize
  5167. if ($lhfixed) { $maxlineHeight = $this->lineheight; }
  5168. else { $maxlineHeight = 0; }
  5169. $this->forceExactLineheight = true;
  5170. $maxfontsize = 0;
  5171. // While we're at it, check for cursive text
  5172. $checkCursive=false;
  5173. if ($this->biDirectional) { $checkCursive=true; } // *RTL*
  5174. foreach ( $content as $k => $chunk )
  5175. {
  5176. $this->restoreFont( $font[ $k ]);
  5177. if (!isset($this->objectbuffer[$k])) {
  5178. if (!$this->usingCoreFont) {
  5179. $content[$k] = $chunk = str_replace("\xc2\xad",'',$chunk );
  5180. if (isset($this->CurrentFont['indic']) && $this->CurrentFont['indic']) { $checkCursive=true; } // *INDIC*
  5181. }
  5182. // Soft Hyphens chr(173)
  5183. else if ($this->FontFamily!='csymbol' && $this->FontFamily!='czapfdingbats') {
  5184. $content[$k] = $chunk = str_replace(chr(173),'',$chunk );
  5185. }
  5186. $contentWidth += $this->GetStringWidth( $chunk ) * _MPDFK;
  5187. if (!empty($this->spanborddet)) {
  5188. if (strpos($contentB[$k],'L')!==false) $contentWidth += $this->spanborddet['L']['w'] * _MPDFK;
  5189. if (strpos($contentB[$k],'R')!==false) $contentWidth += $this->spanborddet['R']['w'] * _MPDFK;
  5190. }
  5191. if (!$lhfixed) { $maxlineHeight = max($maxlineHeight,$this->FontSize * $this->lineheight_correction ); }
  5192. if ($lhfixed && ($this->FontSize > $def_fontsize || ($this->FontSize > ($lineHeight * $this->lineheight_correction) && $is_list))) {
  5193. $this->forceExactLineheight = false;
  5194. }
  5195. $maxfontsize = max($maxfontsize,$this->FontSize);
  5196. }
  5197. }
  5198. $lastfontreqstyle = $font[count($font)-1]['ReqFontStyle'];
  5199. $lastfontstyle = $font[count($font)-1]['style'];
  5200. if ($blockdir == 'ltr' && strpos($lastfontreqstyle,"I") !== false && strpos($lastfontstyle,"I") === false) { // Artificial italic
  5201. $lastitalic = $this->FontSize*0.15*_MPDFK;
  5202. }
  5203. else { $lastitalic = 0; }
  5204. /*-- LISTS --*/
  5205. if ($is_list && is_array($this->bulletarray) && $this->bulletarray) {
  5206. $actfs = $this->bulletarray['fontsize'];
  5207. if (!$lhfixed) { $maxlineHeight = max($maxlineHeight,$actfs * $this->lineheight_correction ); }
  5208. if ($lhfixed && $actfs > $def_fontsize) { $this->forceExactLineheight = false; }
  5209. $maxfontsize = max($maxfontsize,$actfs);
  5210. }
  5211. /*-- END LISTS --*/
  5212. // when every text item checked i.e. $maxfontsize is set properly
  5213. $af = 0; // Above font
  5214. $bf = 0; // Below font
  5215. $mta = 0; // Maximum top-aligned
  5216. $mba = 0; // Maximum bottom-aligned
  5217. foreach ( $content as $k => $chunk ) {
  5218. if (isset($this->objectbuffer[$k]) && $this->objectbuffer[$k]) {
  5219. $contentWidth += $this->objectbuffer[$k]['OUTER-WIDTH'] * _MPDFK;
  5220. $oh = $this->objectbuffer[$k]['OUTER-HEIGHT'];
  5221. $va = $this->objectbuffer[$k]['vertical-align']; // = $objattr['vertical-align'] = set as M,T,B,S
  5222. if ($lhfixed && $oh > $def_fontsize) { $this->forceExactLineheight = false; }
  5223. if ($va == 'BS') { // (BASELINE default)
  5224. $af = max($af, ($oh - ($maxfontsize * (0.5 + $this->baselineC))));
  5225. }
  5226. else if ($va == 'M') {
  5227. $af = max($af, ($oh - $maxfontsize)/2);
  5228. $bf = max($bf, ($oh - $maxfontsize)/2);
  5229. }
  5230. else if ($va == 'TT') {
  5231. $bf = max($bf, ($oh - $maxfontsize));
  5232. }
  5233. else if ($va == 'TB') {
  5234. $af = max($af, ($oh - $maxfontsize));
  5235. }
  5236. else if ($va == 'T') {
  5237. $mta = max($mta, $oh);
  5238. }
  5239. else if ($va == 'B') {
  5240. $mba = max($mba, $oh);
  5241. }
  5242. }
  5243. }
  5244. if ((!$lhfixed || !$this->forceExactLineheight) && ($af > (($maxlineHeight - $maxfontsize)/2) || $bf > (($maxlineHeight - $maxfontsize)/2))) {
  5245. $maxlineHeight = $maxfontsize + $af + $bf;
  5246. }
  5247. else if (!$lhfixed) { $af = $bf = ($maxlineHeight - $maxfontsize)/2; }
  5248. if ($mta > $maxlineHeight) {
  5249. $bf += ($mta - $maxlineHeight);
  5250. $maxlineHeight = $mta;
  5251. }
  5252. if ($mba > $maxlineHeight) {
  5253. $af += ($mba - $maxlineHeight);
  5254. $maxlineHeight = $mba;
  5255. }
  5256. $lineHeight = $maxlineHeight;
  5257. $cutoffWidth = $contentWidth;
  5258. // If NOT images, and maxfontsize NOT > lineHeight - this value determines text baseline positioning
  5259. if ($lhfixed && $af==0 && $bf==0 && $maxfontsize<=($def_fontsize * $this->lineheight_correction * 0.8 )) {
  5260. $this->linemaxfontsize = $def_fontsize;
  5261. }
  5262. else { $this->linemaxfontsize = $maxfontsize; }
  5263. $inclCursive=false;
  5264. foreach ( $content as $k => $chunk ) {
  5265. if (!isset($this->objectbuffer[$k]) || (isset($this->objectbuffer[$k]) && !$this->objectbuffer[$k])) {
  5266. if ($this->usingCoreFont) {
  5267. $content[$k] = str_replace(chr(160),chr(32),$chunk );
  5268. }
  5269. else {
  5270. $content[$k] = str_replace(chr(194).chr(160),chr(32),$chunk );
  5271. if ($checkCursive) {
  5272. if (preg_match("/([".$this->pregRTLchars."])/u", $chunk)) { $inclCursive = true; } // *RTL*
  5273. if (preg_match("/([".$this->pregHIchars.$this->pregBNchars.$this->pregPAchars."])/u", $chunk)) { $inclCursive = true; } // *INDIC*
  5274. }
  5275. }
  5276. }
  5277. }
  5278. // JUSTIFICATION J
  5279. $jcharspacing = 0;
  5280. $jws = 0;
  5281. $nb_carac = 0;
  5282. $nb_spaces = 0;
  5283. // if it's justified, we need to find the char/word spacing (or if orphans have allowed length of line to go over the maxwidth)
  5284. if(( $align == 'J' ) || (($cutoffWidth + $lastitalic > $maxWidth - $WidthCorrection - (($this->cMarginL+$this->cMarginR)*_MPDFK) - ($paddingL+$paddingR +(($fpaddingL + $fpaddingR) * _MPDFK) ) + 0.001) && !$CJKoverflow)) { // 0.001 is to correct for deviations converting mm=>pts
  5285. // JUSTIFY J (Use character spacing)
  5286. // WORD SPACING
  5287. foreach ( $content as $k => $chunk ) {
  5288. if (!isset($this->objectbuffer[$k]) || (isset($this->objectbuffer[$k]) && !$this->objectbuffer[$k])) {
  5289. $nb_carac += mb_strlen( $chunk, $this->mb_enc ) ;
  5290. $nb_spaces += mb_substr_count( $chunk,' ', $this->mb_enc ) ;
  5291. }
  5292. }
  5293. list($jcharspacing,$jws) = $this->GetJspacing($nb_carac,$nb_spaces,($maxWidth-$lastitalic-$cutoffWidth-$WidthCorrection-(($this->cMarginL+$this->cMarginR)*_MPDFK)-($paddingL+$paddingR +(($fpaddingL + $fpaddingR) * _MPDFK) )),$inclCursive);
  5294. }
  5295. // WORD SPACING
  5296. $empty = $maxWidth - $lastitalic-$WidthCorrection - $contentWidth - (($this->cMarginL+$this->cMarginR)* _MPDFK) - ($paddingL+$paddingR +(($fpaddingL + $fpaddingR) * _MPDFK) );
  5297. $empty -= ($jcharspacing * $nb_carac);
  5298. $empty -= ($jws * $nb_spaces);
  5299. $empty /= _MPDFK;
  5300. $b = ''; //do not use borders
  5301. // Get PAGEBREAK TO TEST for height including the top border/padding
  5302. $check_h = max($this->divheight,$lineHeight);
  5303. if (($newblock) && ($blockstate==1 || $blockstate==3) && ($this->blklvl > 0) && ($lineCount == 1) && (!$is_table) && (!$is_list)) {
  5304. $check_h += ($this->blk[$this->blklvl]['padding_top'] + $this->blk[$this->blklvl]['margin_top'] + $this->blk[$this->blklvl]['border_top']['w']);
  5305. }
  5306. if ($this->ColActive && $check_h > ($this->PageBreakTrigger - $this->y0)) {
  5307. $this->SetCol($this->NbCol-1);
  5308. }
  5309. // PAGEBREAK
  5310. // 'If' below used in order to fix "first-line of other page with justify on" bug
  5311. if(!$is_table && ($this->y+$check_h) > $this->PageBreakTrigger and !$this->InFooter and $this->AcceptPageBreak()) {
  5312. $bak_x=$this->x;//Current X position
  5313. // WORD SPACING
  5314. $ws=$this->ws;//Word Spacing
  5315. $charspacing=$this->charspacing;//Character Spacing
  5316. $this->ResetSpacing();
  5317. $this->AddPage($this->CurOrientation);
  5318. $this->x = $bak_x;
  5319. // Added to correct for OddEven Margins
  5320. $currentx += $this->MarginCorrection;
  5321. $this->x += $this->MarginCorrection;
  5322. // WORD SPACING
  5323. $this->SetSpacing($charspacing,$ws);
  5324. }
  5325. if ($this->keep_block_together && !$is_table && $this->kt_p00 < $this->page && ($this->y+$check_h) > $this->kt_y00) {
  5326. $this->printdivbuffer();
  5327. $this->keep_block_together = 0;
  5328. }
  5329. /*-- COLUMNS --*/
  5330. // COLS
  5331. // COLUMN CHANGE
  5332. if ($this->CurrCol != $oldcolumn) {
  5333. $currentx += $this->ChangeColumn * ($this->ColWidth+$this->ColGap);
  5334. $this->x += $this->ChangeColumn * ($this->ColWidth+$this->ColGap);
  5335. $oldcolumn = $this->CurrCol;
  5336. }
  5337. if ($this->ColActive && !$is_table) { $this->breakpoints[$this->CurrCol][] = $this->y; } // *COLUMNS*
  5338. /*-- END COLUMNS --*/
  5339. // TOP MARGIN
  5340. if (($newblock) && ($blockstate==1 || $blockstate==3) && ($this->blk[$this->blklvl]['margin_top']) && ($lineCount == 1) && (!$is_table) && (!$is_list)) {
  5341. $this->DivLn($this->blk[$this->blklvl]['margin_top'],$this->blklvl-1,true,$this->blk[$this->blklvl]['margin_collapse']);
  5342. if ($this->ColActive) { $this->breakpoints[$this->CurrCol][] = $this->y; } // *COLUMNS*
  5343. }
  5344. // Update y0 for top of block (used to paint border)
  5345. if (($newblock) && ($blockstate==1 || $blockstate==3) && ($lineCount == 1) && (!$is_table) && (!$is_list)) {
  5346. $this->blk[$this->blklvl]['y0'] = $this->y;
  5347. $this->blk[$this->blklvl]['startpage'] = $this->page;
  5348. }
  5349. // TOP PADDING and BORDER spacing/fill
  5350. if (($newblock) && ($blockstate==1 || $blockstate==3) && (($this->blk[$this->blklvl]['padding_top']) || ($this->blk[$this->blklvl]['border_top'])) && ($lineCount == 1) && (!$is_table) && (!$is_list)) {
  5351. // $state = 0 normal; 1 top; 2 bottom; 3 top and bottom
  5352. $this->DivLn($this->blk[$this->blklvl]['padding_top'] + $this->blk[$this->blklvl]['border_top']['w'],-3,true,false,1);
  5353. if ($this->ColActive) { $this->breakpoints[$this->CurrCol][] = $this->y; } // *COLUMNS*
  5354. }
  5355. $arraysize = count($content);
  5356. $margins = ($this->cMarginL+$this->cMarginR) + ($ipaddingL+$ipaddingR + $fpaddingR + $fpaddingR );
  5357. // PAINT BACKGROUND FOR THIS LINE
  5358. if (!$is_table) { $this->DivLn($lineHeight,$this->blklvl,false); } // false -> don't advance y
  5359. $this->x = $currentx + $this->cMarginL + $ipaddingL + $fpaddingL ;
  5360. if ($align == 'R') { $this->x += $empty; }
  5361. else if ($align == 'C') { $this->x += ($empty / 2); }
  5362. // Paragraph INDENT
  5363. if (isset($this->blk[$this->blklvl]['text_indent']) && ($newblock) && ($blockstate==1 || $blockstate==3) && ($lineCount == 1) && (!$is_table) && ($blockdir !='rtl') && ($align !='C')) {
  5364. $ti = $this->ConvertSize($this->blk[$this->blklvl]['text_indent'],$this->blk[$this->blklvl]['inner_width'],$this->FontSize,false);
  5365. $this->x += $ti;
  5366. }
  5367. // DIRECTIONALITY RTL
  5368. $all_rtl = false;
  5369. $contains_rtl = false;
  5370. /*-- RTL --*/
  5371. if ($blockdir == 'rtl' || $this->biDirectional) {
  5372. $all_rtl = true;
  5373. foreach ( $content as $k => $chunk ) {
  5374. $reversed = $this->magic_reverse_dir($chunk, false, $blockdir);
  5375. if ($reversed > 0) { $contains_rtl = true; }
  5376. if ($reversed < 2) { $all_rtl = false; }
  5377. $content[$k] = $chunk;
  5378. }
  5379. if (($blockdir =='rtl' && $contains_rtl) || $all_rtl) {
  5380. $content = array_reverse($content,false);
  5381. $contentB = array_reverse($contentB,false);
  5382. }
  5383. }
  5384. /*-- END RTL --*/
  5385. foreach ( $content as $k => $chunk ) {
  5386. // FOR IMAGES - UPDATE POSITION
  5387. if (($blockdir =='rtl' && $contains_rtl) || $all_rtl) { $dirk = $arraysize-1 - $k ; } else { $dirk = $k; }
  5388. $va = 'M'; // default for text
  5389. if (isset($this->objectbuffer[$dirk]) && $this->objectbuffer[$dirk]) {
  5390. $xadj = $this->x - $this->objectbuffer[$dirk]['OUTER-X'] ;
  5391. $this->objectbuffer[$dirk]['OUTER-X'] += $xadj;
  5392. $this->objectbuffer[$dirk]['BORDER-X'] += $xadj;
  5393. $this->objectbuffer[$dirk]['INNER-X'] += $xadj;
  5394. $va = $this->objectbuffer[$dirk]['vertical-align'];
  5395. $yadj = $this->y - $this->objectbuffer[$dirk]['OUTER-Y'];
  5396. if ($va == 'BS') {
  5397. $yadj += $af + ($this->linemaxfontsize * (0.5 + $this->baselineC)) - $this->objectbuffer[$dirk]['OUTER-HEIGHT'];
  5398. }
  5399. else if ($va == 'M' || $va == '') {
  5400. $yadj += $af + ($this->linemaxfontsize /2) - ($this->objectbuffer[$dirk]['OUTER-HEIGHT']/2);
  5401. }
  5402. else if ($va == 'TB') {
  5403. $yadj += $af + $this->linemaxfontsize - $this->objectbuffer[$dirk]['OUTER-HEIGHT'];
  5404. }
  5405. else if ($va == 'TT') {
  5406. $yadj += $af;
  5407. }
  5408. else if ($va == 'B') {
  5409. $yadj += $af + $this->linemaxfontsize + $bf - $this->objectbuffer[$dirk]['OUTER-HEIGHT'];
  5410. }
  5411. else if ($va == 'T') {
  5412. $yadj += 0;
  5413. }
  5414. $this->objectbuffer[$dirk]['OUTER-Y'] += $yadj;
  5415. $this->objectbuffer[$dirk]['BORDER-Y'] += $yadj;
  5416. $this->objectbuffer[$dirk]['INNER-Y'] += $yadj;
  5417. }
  5418. // DIRECTIONALITY RTL
  5419. if ((($blockdir == 'rtl') && ($contains_rtl )) || ($all_rtl )) { $this->restoreFont($font[$arraysize-1 - $k]); }
  5420. else { $this->restoreFont( $font[ $k ] ); }
  5421. $this->SetSpacing(($this->fixedlSpacing*_MPDFK)+$jcharspacing,($this->fixedlSpacing+$this->minwSpacing)*_MPDFK+$jws);
  5422. // Now unset these values so they don't influence GetStringwidth below or in fn. Cell
  5423. $this->fixedlSpacing = false;
  5424. $this->minwSpacing = 0;
  5425. // *********** SPAN BACKGROUND COLOR ***************** //
  5426. if ($this->spanbgcolor) {
  5427. $cor = $this->spanbgcolorarray;
  5428. $this->SetFColor($cor);
  5429. $save_fill = $fill; $spanfill = 1; $fill = 1;
  5430. }
  5431. if (!empty($this->spanborddet)) {
  5432. if (strpos($contentB[$k],'L')!==false) $this->x += $this->spanborddet['L']['w'];
  5433. if (strpos($contentB[$k],'L')===false) $this->spanborddet['L']['s'] = $this->spanborddet['L']['w'] = 0;
  5434. if (strpos($contentB[$k],'R')===false) $this->spanborddet['R']['s'] = $this->spanborddet['R']['w'] = 0;
  5435. }
  5436. // WORD SPACING
  5437. $stringWidth = $this->GetStringWidth($chunk );
  5438. $stringWidth += ( $this->charspacing * mb_strlen($chunk,$this->mb_enc ) / _MPDFK );
  5439. $stringWidth += ( $this->ws * mb_substr_count($chunk,' ',$this->mb_enc ) / _MPDFK );
  5440. if (isset($this->objectbuffer[$dirk])) { $stringWidth = $this->objectbuffer[$dirk]['OUTER-WIDTH']; }
  5441. if ($stringWidth==0) { $stringWidth = 0.000001; }
  5442. if ($k == $arraysize-1) {
  5443. $stringWidth -= ( $this->charspacing / _MPDFK );
  5444. $this->Cell( $stringWidth, $lineHeight, $chunk, '', 1, '', $fill, $this->HREF, $currentx,0,0,'M', $fill, $af, $bf, true ); //mono-style line or last part (skips line)
  5445. }
  5446. else $this->Cell( $stringWidth, $lineHeight, $chunk, '', 0, '', $fill, $this->HREF, 0, 0,0,'M', $fill, $af, $bf, true );//first or middle part
  5447. if (!empty($this->spanborddet)) {
  5448. if (strpos($contentB[$k],'R')!==false && $k != $arraysize-1) $this->x += $this->spanborddet['R']['w'];
  5449. }
  5450. // *********** SPAN BACKGROUND COLOR OFF - RESET BLOCK BGCOLOR ***************** //
  5451. if (isset($spanfill) && $spanfill) {
  5452. $fill = $save_fill; $spanfill = 0;
  5453. if ($fill) { $this->SetFColor($bcor); }
  5454. }
  5455. }
  5456. if (!$is_table) {
  5457. $this->maxPosR = max($this->maxPosR , ($this->w - $this->rMargin - $this->blk[$this->blklvl]['outer_right_margin']));
  5458. $this->maxPosL = min($this->maxPosL , ($this->lMargin + $this->blk[$this->blklvl]['outer_left_margin']));
  5459. }
  5460. // move on to the next line, reset variables, tack on saved content and current char
  5461. $this->printobjectbuffer($is_table, $blockdir);
  5462. $this->objectbuffer = array();
  5463. /*-- LISTS --*/
  5464. // LIST BULLETS/NUMBERS
  5465. if ($is_list && is_array($this->bulletarray) && ($lineCount == 1) ) {
  5466. $this->ResetSpacing();
  5467. $bull = $this->bulletarray;
  5468. if (isset($bull['level']) && isset($bull['occur']) && isset($this->InlineProperties['LIST'][$bull['level']][$bull['occur']])) {
  5469. $this->restoreInlineProperties($this->InlineProperties['LIST'][$bull['level']][$bull['occur']]);
  5470. }
  5471. if (isset($bull['level']) && isset($bull['occur']) && isset($bull['num']) && isset($this->InlineProperties['LISTITEM'][$bull['level']][$bull['occur']][$bull['num']]) && $this->InlineProperties['LISTITEM'][$bull['level']][$bull['occur']][$bull['num']]) { $this->restoreInlineProperties($this->InlineProperties['LISTITEM'][$bull['level']][$bull['occur']][$bull['num']]); }
  5472. if (isset($bull['font']) && $bull['font'] == 'czapfdingbats') {
  5473. $this->bullet = true;
  5474. $this->SetFont('czapfdingbats','',$this->FontSizePt/2.5);
  5475. }
  5476. else { $this->SetFont($this->FontFamily,$this->FontStyle,$this->FontSizePt,true,true); } // force output
  5477. //Output bullet
  5478. $this->x = $currentx;
  5479. if (isset($bull['x'])) { $this->x += $bull['x']; }
  5480. $this->y -= $lineHeight;
  5481. if (is_array($bull['col'])) { $this->SetTColor($bull['col']); }
  5482. if (isset($bull['txt'])) { $this->Cell($bull['w'], $lineHeight,$bull['txt'],'','',$bull['align'],0,'',0,-$this->cMarginL, -$this->cMarginR ); }
  5483. if (isset($bull['font']) && $bull['font'] == 'czapfdingbats') {
  5484. $this->bullet = false;
  5485. }
  5486. $this->x = $currentx; // Reset
  5487. $this->y += $lineHeight;
  5488. if ($this->ColActive && !$is_table) { $this->breakpoints[$this->CurrCol][] = $this->y; } // *COLUMNS*
  5489. $this->bulletarray = array(); // prevents repeat of bullet/number if <li>....<br />.....</li>
  5490. }
  5491. /*-- END LISTS --*/
  5492. /*-- CSS-IMAGE-FLOAT --*/
  5493. // Update values if set to skipline
  5494. if ($this->floatmargins) { $this->_advanceFloatMargins(); }
  5495. /*-- END CSS-IMAGE-FLOAT --*/
  5496. // Reset lineheight
  5497. $lineHeight = $this->divheight;
  5498. $valign = 'M';
  5499. $this->restoreFont( $savedFont );
  5500. $lbw = $rbw = 0; // Border widths
  5501. if (!empty($this->spanborddet)) {
  5502. $lbw = $this->spanborddet['L']['w'];
  5503. $rbw = $this->spanborddet['R']['w'];
  5504. }
  5505. $font = array();
  5506. $content = array();
  5507. $contentB = array();
  5508. $contentWidth = 0;
  5509. if (!empty($savedObj)) {
  5510. $this->objectbuffer[] = $savedObj;
  5511. $font[] = $savedFont;
  5512. $content[] = '';
  5513. $contentB[] = '';
  5514. $contentWidth += $savedObj['OUTER-WIDTH'] * _MPDFK;
  5515. }
  5516. $font[] = $savedFont;
  5517. $content[] = $savedContent . $c;
  5518. $contentB[] = $savedContentB ;
  5519. $currContent =& $content[ (count($content)-1) ];
  5520. // CJK - strip CJK space at end of line
  5521. // &#x3000; = \xe3\x80\x80 = CJK space
  5522. if ($this->checkCJK && $currContent == "\xe3\x80\x80") { $currContent = '' ; } // *CJK-FONTS*
  5523. $contentWidth += $this->GetStringWidth( $currContent ) * _MPDFK;
  5524. if (strpos($savedContentB,'L')!==false) $contentWidth += $lbw;
  5525. $cutoffWidth = $contentWidth;
  5526. $CJKoverflow = false;
  5527. }
  5528. // another character will fit, so add it on
  5529. else {
  5530. $contentWidth += $cw;
  5531. $currContent .= $c;
  5532. }
  5533. }
  5534. unset($content);
  5535. unset($contentB);
  5536. }
  5537. //----------------------END OF FLOWING BLOCK------------------------------------//
  5538. /*-- CSS-IMAGE-FLOAT --*/
  5539. // Update values if set to skipline
  5540. function _advanceFloatMargins() {
  5541. // Update floatmargins - L
  5542. if (isset($this->floatmargins['L']) && $this->floatmargins['L']['skipline'] && $this->floatmargins['L']['y0'] != $this->y) {
  5543. $yadj = $this->y - $this->floatmargins['L']['y0'];
  5544. $this->floatmargins['L']['y0'] = $this->y;
  5545. $this->floatmargins['L']['y1'] += $yadj;
  5546. // Update objattr in floatbuffer
  5547. if ($this->floatbuffer[$this->floatmargins['L']['id']]['border_left']['w']) {
  5548. $this->floatbuffer[$this->floatmargins['L']['id']]['BORDER-Y'] += $yadj;
  5549. }
  5550. $this->floatbuffer[$this->floatmargins['L']['id']]['INNER-Y'] += $yadj;
  5551. $this->floatbuffer[$this->floatmargins['L']['id']]['OUTER-Y'] += $yadj;
  5552. // Unset values
  5553. $this->floatbuffer[$this->floatmargins['L']['id']]['skipline'] = false;
  5554. $this->floatmargins['L']['skipline'] = false;
  5555. $this->floatmargins['L']['id'] = '';
  5556. }
  5557. // Update floatmargins - R
  5558. if (isset($this->floatmargins['R']) && $this->floatmargins['R']['skipline'] && $this->floatmargins['R']['y0'] != $this->y) {
  5559. $yadj = $this->y - $this->floatmargins['R']['y0'];
  5560. $this->floatmargins['R']['y0'] = $this->y;
  5561. $this->floatmargins['R']['y1'] += $yadj;
  5562. // Update objattr in floatbuffer
  5563. if ($this->floatbuffer[$this->floatmargins['R']['id']]['border_left']['w']) {
  5564. $this->floatbuffer[$this->floatmargins['R']['id']]['BORDER-Y'] += $yadj;
  5565. }
  5566. $this->floatbuffer[$this->floatmargins['R']['id']]['INNER-Y'] += $yadj;
  5567. $this->floatbuffer[$this->floatmargins['R']['id']]['OUTER-Y'] += $yadj;
  5568. // Unset values
  5569. $this->floatbuffer[$this->floatmargins['R']['id']]['skipline'] = false;
  5570. $this->floatmargins['R']['skipline'] = false;
  5571. $this->floatmargins['R']['id'] = '';
  5572. }
  5573. }
  5574. /*-- END CSS-IMAGE-FLOAT --*/
  5575. ////////////////////////////////////////////////////////////////////////////////
  5576. // ADDED forcewrap - to call from inline OBJECT functions to breakwords if necessary in cell
  5577. ////////////////////////////////////////////////////////////////////////////////
  5578. function WordWrap(&$text, $maxwidth, $forcewrap = 0) {
  5579. $biggestword=0;
  5580. $toonarrow=false;
  5581. $text = trim($text);
  5582. if ($text==='') return 0;
  5583. $space = $this->GetCharWidth(' ',false);
  5584. $lines = explode("\n", $text);
  5585. $text = '';
  5586. $count = 0;
  5587. foreach ($lines as $line) {
  5588. $words = explode(' ', $line);
  5589. $width = 0;
  5590. foreach ($words as $word) {
  5591. $word = trim($word);
  5592. $wordwidth = $this->GetStringWidth($word);
  5593. //Warn user that maxwidth is insufficient
  5594. if ($wordwidth > $maxwidth + 0.0001) {
  5595. if ($wordwidth > $biggestword) { $biggestword = $wordwidth; }
  5596. $toonarrow=true;
  5597. // ADDED
  5598. if ($forcewrap) {
  5599. while($wordwidth > $maxwidth) {
  5600. $chw = 0; // check width
  5601. for ( $i = 0; $i < mb_strlen($word, $this->mb_enc ); $i++ ) {
  5602. $chw = $this->GetStringWidth(mb_substr($word,0,$i+1,$this->mb_enc ));
  5603. if ($chw > $maxwidth ) {
  5604. if ($text) {
  5605. $text = rtrim($text)."\n".mb_substr($word,0,$i,$this->mb_enc );
  5606. $count++;
  5607. }
  5608. else {
  5609. $text = mb_substr($word,0,$i,$this->mb_enc );
  5610. }
  5611. $word = mb_substr($word,$i,mb_strlen($word, $this->mb_enc )-$i,$this->mb_enc );
  5612. $wordwidth = $this->GetStringWidth($word);
  5613. $width = $maxwidth;
  5614. break;
  5615. }
  5616. }
  5617. }
  5618. }
  5619. }
  5620. if ($width + $wordwidth < $maxwidth - 0.0001) {
  5621. $width += $wordwidth + $space;
  5622. $text .= $word.' ';
  5623. }
  5624. else {
  5625. $width = $wordwidth + $space;
  5626. $text = rtrim($text)."\n".$word.' ';
  5627. $count++;
  5628. }
  5629. }
  5630. $text .= "\n";
  5631. $count++;
  5632. }
  5633. $text = rtrim($text);
  5634. //Return -(wordsize) if word is bigger than maxwidth
  5635. // ADDED
  5636. if ($forcewrap) { return $count; }
  5637. if (($toonarrow) && ($this->table_error_report)) {
  5638. $this->Error("Word is too long to fit in table - ".$this->table_error_report_param);
  5639. }
  5640. if ($toonarrow) return -$biggestword;
  5641. else return $count;
  5642. }
  5643. /*-- END HTML-CSS --*/
  5644. function _SetTextRendering($mode) {
  5645. if (!(($mode == 0) || ($mode == 1) || ($mode == 2)))
  5646. $this->Error("Text rendering mode should be 0, 1 or 2 (value : $mode)");
  5647. $tr = ($mode.' Tr');
  5648. if($this->page>0 && ((isset($this->pageoutput[$this->page]['TextRendering']) && $this->pageoutput[$this->page]['TextRendering'] != $tr) || !isset($this->pageoutput[$this->page]['TextRendering']) || $this->keep_block_together)) { $this->_out($tr); }
  5649. $this->pageoutput[$this->page]['TextRendering'] = $tr;
  5650. }
  5651. function SetTextOutline($width, $col=0) {
  5652. if ($width == false) //Now resets all values
  5653. {
  5654. $this->outline_on = false;
  5655. $this->SetLineWidth(0.2);
  5656. $this->SetDColor($this->ConvertColor(0));
  5657. $this->_SetTextRendering(0);
  5658. $tr = ('0 Tr');
  5659. if($this->page>0 && ((isset($this->pageoutput[$this->page]['TextRendering']) && $this->pageoutput[$this->page]['TextRendering'] != $tr) || !isset($this->pageoutput[$this->page]['TextRendering']) || $this->keep_block_together)) { $this->_out($tr); }
  5660. $this->pageoutput[$this->page]['TextRendering'] = $tr;
  5661. }
  5662. else
  5663. {
  5664. $this->SetLineWidth($width);
  5665. $this->SetDColor($col);
  5666. $tr = ('2 Tr');
  5667. if($this->page>0 && ((isset($this->pageoutput[$this->page]['TextRendering']) && $this->pageoutput[$this->page]['TextRendering'] != $tr) || !isset($this->pageoutput[$this->page]['TextRendering']) || $this->keep_block_together)) { $this->_out($tr); }
  5668. $this->pageoutput[$this->page]['TextRendering'] = $tr;
  5669. }
  5670. }
  5671. function Image($file,$x,$y,$w=0,$h=0,$type='',$link='',$paint=true, $constrain=true, $watermark=false, $shownoimg=true, $allowvector=true) {
  5672. $orig_srcpath = $file;
  5673. $this->GetFullPath($file);
  5674. $info=$this->_getImage($file, true, $allowvector, $orig_srcpath );
  5675. if(!$info && $paint) {
  5676. $info = $this->_getImage($this->noImageFile);
  5677. if ($info) {
  5678. $file = $this->noImageFile;
  5679. $w = ($info['w'] * (25.4/$this->dpi)); // 14 x 16px
  5680. $h = ($info['h'] * (25.4/$this->dpi)); // 14 x 16px
  5681. }
  5682. }
  5683. if(!$info) return false;
  5684. //Automatic width and height calculation if needed
  5685. if($w==0 and $h==0) {
  5686. /*-- IMAGES-WMF --*/
  5687. if ($info['type']=='wmf') {
  5688. // WMF units are twips (1/20pt)
  5689. // divide by 20 to get points
  5690. // divide by k to get user units
  5691. $w = abs($info['w'])/(20*_MPDFK);
  5692. $h = abs($info['h']) / (20*_MPDFK);
  5693. }
  5694. else
  5695. /*-- END IMAGES-WMF --*/
  5696. if ($info['type']=='svg') {
  5697. // returned SVG units are pts
  5698. // divide by k to get user units (mm)
  5699. $w = abs($info['w'])/_MPDFK;
  5700. $h = abs($info['h']) /_MPDFK;
  5701. }
  5702. else {
  5703. //Put image at default image dpi
  5704. $w=($info['w']/_MPDFK) * (72/$this->img_dpi);
  5705. $h=($info['h']/_MPDFK) * (72/$this->img_dpi);
  5706. }
  5707. }
  5708. if($w==0) $w=abs($h*$info['w']/$info['h']);
  5709. if($h==0) $h=abs($w*$info['h']/$info['w']);
  5710. /*-- WATERMARK --*/
  5711. if ($watermark) {
  5712. $maxw = $this->w;
  5713. $maxh = $this->h;
  5714. // Size = D PF or array
  5715. if (is_array($this->watermark_size)) {
  5716. $w = $this->watermark_size[0];
  5717. $h = $this->watermark_size[1];
  5718. }
  5719. else if (!is_string($this->watermark_size)) {
  5720. $maxw -= $this->watermark_size*2;
  5721. $maxh -= $this->watermark_size*2;
  5722. $w = $maxw;
  5723. $h=abs($w*$info['h']/$info['w']);
  5724. if ($h > $maxh ) {
  5725. $h = $maxh ; $w=abs($h*$info['w']/$info['h']);
  5726. }
  5727. }
  5728. else if ($this->watermark_size == 'F') {
  5729. if ($this->ColActive) { $maxw = $this->w - ($this->DeflMargin + $this->DefrMargin); }
  5730. else { $maxw = $this->pgwidth; }
  5731. $maxh = $this->h - ($this->tMargin + $this->bMargin);
  5732. $w = $maxw;
  5733. $h=abs($w*$info['h']/$info['w']);
  5734. if ($h > $maxh ) {
  5735. $h = $maxh ; $w=abs($h*$info['w']/$info['h']);
  5736. }
  5737. }
  5738. else if ($this->watermark_size == 'P') { // Default P
  5739. $w = $maxw;
  5740. $h=abs($w*$info['h']/$info['w']);
  5741. if ($h > $maxh ) {
  5742. $h = $maxh ; $w=abs($h*$info['w']/$info['h']);
  5743. }
  5744. }
  5745. // Automatically resize to maximum dimensions of page if too large
  5746. if ($w > $maxw) {
  5747. $w = $maxw;
  5748. $h=abs($w*$info['h']/$info['w']);
  5749. }
  5750. if ($h > $maxh ) {
  5751. $h = $maxh ;
  5752. $w=abs($h*$info['w']/$info['h']);
  5753. }
  5754. // Position
  5755. if (is_array($this->watermark_pos)) {
  5756. $x = $this->watermark_pos[0];
  5757. $y = $this->watermark_pos[1];
  5758. }
  5759. else if ($this->watermark_pos == 'F') { // centred on printable area
  5760. if ($this->ColActive) { // *COLUMNS*
  5761. if (($this->mirrorMargins) && (($this->page)%2==0)) { $xadj = $this->DeflMargin-$this->DefrMargin; } // *COLUMNS*
  5762. else { $xadj = 0; } // *COLUMNS*
  5763. $x = ($this->DeflMargin - $xadj + ($this->w - ($this->DeflMargin + $this->DefrMargin))/2) - ($w/2); // *COLUMNS*
  5764. } // *COLUMNS*
  5765. else { // *COLUMNS*
  5766. $x = ($this->lMargin + ($this->pgwidth)/2) - ($w/2);
  5767. } // *COLUMNS*
  5768. $y = ($this->tMargin + ($this->h - ($this->tMargin + $this->bMargin))/2) - ($h/2);
  5769. }
  5770. else { // default P - centred on whole page
  5771. $x = ($this->w/2) - ($w/2);
  5772. $y = ($this->h/2) - ($h/2);
  5773. }
  5774. /*-- IMAGES-WMF --*/
  5775. if ($info['type']=='wmf') {
  5776. $sx = $w*_MPDFK / $info['w'];
  5777. $sy = -$h*_MPDFK / $info['h'];
  5778. $outstring = sprintf('q %.3F 0 0 %.3F %.3F %.3F cm /FO%d Do Q', $sx, $sy, $x*_MPDFK-$sx*$info['x'], (($this->h-$y)*_MPDFK)-$sy*$info['y'], $info['i']);
  5779. }
  5780. else
  5781. /*-- END IMAGES-WMF --*/
  5782. if ($info['type']=='svg') {
  5783. $sx = $w*_MPDFK / $info['w'];
  5784. $sy = -$h*_MPDFK / $info['h'];
  5785. $outstring = sprintf('q %.3F 0 0 %.3F %.3F %.3F cm /FO%d Do Q', $sx, $sy, $x*_MPDFK-$sx*$info['x'], (($this->h-$y)*_MPDFK)-$sy*$info['y'], $info['i']);
  5786. }
  5787. else {
  5788. $outstring = sprintf("q %.3F 0 0 %.3F %.3F %.3F cm /I%d Do Q",$w*_MPDFK,$h*_MPDFK,$x*_MPDFK,($this->h-($y+$h))*_MPDFK,$info['i']);
  5789. }
  5790. if ($this->watermarkImgBehind) {
  5791. $outstring = $this->watermarkImgAlpha . "\n" . $outstring . "\n" . $this->SetAlpha(1, 'Normal', true) . "\n";
  5792. $this->pages[$this->page] = preg_replace('/(___BACKGROUND___PATTERNS'.date('jY').')/', "\n".$outstring."\n".'\\1', $this->pages[$this->page]);
  5793. }
  5794. else { $this->_out($outstring); }
  5795. return 0;
  5796. } // end of IF watermark
  5797. /*-- END WATERMARK --*/
  5798. if ($constrain) {
  5799. // Automatically resize to maximum dimensions of page if too large
  5800. if (isset($this->blk[$this->blklvl]['inner_width']) && $this->blk[$this->blklvl]['inner_width']) { $maxw = $this->blk[$this->blklvl]['inner_width']; }
  5801. else { $maxw = $this->pgwidth; }
  5802. if ($w > $maxw) {
  5803. $w = $maxw;
  5804. $h=abs($w*$info['h']/$info['w']);
  5805. }
  5806. if ($h > $this->h - ($this->tMargin + $this->bMargin + 1)) { // see below - +10 to avoid drawing too close to border of page
  5807. $h = $this->h - ($this->tMargin + $this->bMargin + 1) ;
  5808. if ($this->fullImageHeight) { $h = $this->fullImageHeight; }
  5809. $w=abs($h*$info['w']/$info['h']);
  5810. }
  5811. //Avoid drawing out of the paper(exceeding width limits).
  5812. //if ( ($x + $w) > $this->fw ) {
  5813. if ( ($x + $w) > $this->w ) {
  5814. $x = $this->lMargin;
  5815. $y += 5;
  5816. }
  5817. $changedpage = false;
  5818. $oldcolumn = $this->CurrCol;
  5819. //Avoid drawing out of the page.
  5820. if($y+$h>$this->PageBreakTrigger and !$this->InFooter and $this->AcceptPageBreak()) {
  5821. $this->AddPage($this->CurOrientation);
  5822. // Added to correct for OddEven Margins
  5823. $x=$x +$this->MarginCorrection;
  5824. $y = $tMargin + $this->margin_header;
  5825. $changedpage = true;
  5826. }
  5827. /*-- COLUMNS --*/
  5828. // COLS
  5829. // COLUMN CHANGE
  5830. if ($this->CurrCol != $oldcolumn) {
  5831. $y = $this->y0;
  5832. $x += $this->ChangeColumn * ($this->ColWidth+$this->ColGap);
  5833. $this->x += $this->ChangeColumn * ($this->ColWidth+$this->ColGap);
  5834. }
  5835. /*-- END COLUMNS --*/
  5836. } // end of IF constrain
  5837. /*-- IMAGES-WMF --*/
  5838. if ($info['type']=='wmf') {
  5839. $sx = $w*_MPDFK / $info['w'];
  5840. $sy = -$h*_MPDFK / $info['h'];
  5841. $outstring = sprintf('q %.3F 0 0 %.3F %.3F %.3F cm /FO%d Do Q', $sx, $sy, $x*_MPDFK-$sx*$info['x'], (($this->h-$y)*_MPDFK)-$sy*$info['y'], $info['i']);
  5842. }
  5843. else
  5844. /*-- END IMAGES-WMF --*/
  5845. if ($info['type']=='svg') {
  5846. $sx = $w*_MPDFK / $info['w'];
  5847. $sy = -$h*_MPDFK / $info['h'];
  5848. $outstring = sprintf('q %.3F 0 0 %.3F %.3F %.3F cm /FO%d Do Q', $sx, $sy, $x*_MPDFK-$sx*$info['x'], (($this->h-$y)*_MPDFK)-$sy*$info['y'], $info['i']);
  5849. }
  5850. else {
  5851. $outstring = sprintf("q %.3F 0 0 %.3F %.3F %.3F cm /I%d Do Q",$w*_MPDFK,$h*_MPDFK,$x*_MPDFK,($this->h-($y+$h))*_MPDFK,$info['i']);
  5852. }
  5853. if($paint) {
  5854. $this->_out($outstring);
  5855. if($link) $this->Link($x,$y,$w,$h,$link);
  5856. // Avoid writing text on top of the image. // THIS WAS OUTSIDE THE if ($paint) bit!!!!!!!!!!!!!!!!
  5857. $this->y = $y + $h;
  5858. }
  5859. //Return width-height array
  5860. $sizesarray['WIDTH'] = $w;
  5861. $sizesarray['HEIGHT'] = $h;
  5862. $sizesarray['X'] = $x; //Position before painting image
  5863. $sizesarray['Y'] = $y; //Position before painting image
  5864. $sizesarray['OUTPUT'] = $outstring;
  5865. $sizesarray['IMAGE_ID'] = $info['i'];
  5866. $sizesarray['itype'] = $info['type'];
  5867. $sizesarray['set-dpi'] = $info['set-dpi'];
  5868. return $sizesarray;
  5869. }
  5870. //=============================================================
  5871. //=============================================================
  5872. //=============================================================
  5873. //=============================================================
  5874. //=============================================================
  5875. /*-- HTML-CSS --*/
  5876. function _getObjAttr($t) {
  5877. $c = explode("\xbb\xa4\xac",$t,2);
  5878. $c = explode(",",$c[1],2);
  5879. foreach($c as $v) {
  5880. $v = explode("=",$v,2);
  5881. $sp[$v[0]] = $v[1];
  5882. }
  5883. return (unserialize($sp['objattr']));
  5884. }
  5885. function inlineObject($type,$x,$y,$objattr,$Lmargin,$widthUsed,$maxWidth,$lineHeight,$paint=false,$is_table=false)
  5886. {
  5887. if ($is_table) { $k = $this->shrin_k; } else { $k = 1; }
  5888. // NB $x is only used when paint=true
  5889. // Lmargin not used
  5890. $w = 0;
  5891. if (isset($objattr['width'])) { $w = $objattr['width']/$k; }
  5892. $h = 0;
  5893. if (isset($objattr['height'])) { $h = abs($objattr['height']/$k); }
  5894. $widthLeft = $maxWidth - $widthUsed;
  5895. $maxHeight = $this->h - ($this->tMargin + $this->bMargin + 10) ;
  5896. if ($this->fullImageHeight) { $maxHeight = $this->fullImageHeight; }
  5897. // For Images
  5898. if (isset($objattr['border_left'])) {
  5899. $extraWidth = ($objattr['border_left']['w'] + $objattr['border_right']['w'] + $objattr['margin_left']+ $objattr['margin_right'])/$k;
  5900. $extraHeight = ($objattr['border_top']['w'] + $objattr['border_bottom']['w'] + $objattr['margin_top']+ $objattr['margin_bottom'])/$k;
  5901. if ($type == 'image' || $type == 'barcode' || $type == 'textcircle') {
  5902. $extraWidth += ($objattr['padding_left'] + $objattr['padding_right'])/$k;
  5903. $extraHeight += ($objattr['padding_top'] + $objattr['padding_bottom'])/$k;
  5904. }
  5905. }
  5906. if (!isset($objattr['vertical-align'])) { $objattr['vertical-align'] = 'M'; }
  5907. if ($type == 'image' || (isset($objattr['subtype']) && $objattr['subtype'] == 'IMAGE')) {
  5908. if (isset($objattr['itype']) && ($objattr['itype'] == 'wmf' || $objattr['itype'] == 'svg')) {
  5909. $file = $objattr['file'];
  5910. $info=$this->formobjects[$file];
  5911. }
  5912. else if (isset($objattr['file'])) {
  5913. $file = $objattr['file'];
  5914. $info=$this->images[$file];
  5915. }
  5916. }
  5917. if ($type == 'annot' || $type == 'bookmark' || $type == 'indexentry' || $type == 'toc') {
  5918. $w = 0.00001;
  5919. $h = 0.00001;
  5920. }
  5921. // TEST whether need to skipline
  5922. if (!$paint) {
  5923. if ($type == 'hr') { // always force new line
  5924. if (($y + $h + $lineHeight > $this->PageBreakTrigger) && !$this->InFooter && !$is_table) { return array(-2, $w ,$h ); } // New page + new line
  5925. else { return array(1, $w ,$h ); } // new line
  5926. }
  5927. else {
  5928. if ($widthUsed > 0 && $w > $widthLeft && (!$is_table || $type != 'image')) { // New line needed
  5929. if (($y + $h + $lineHeight > $this->PageBreakTrigger) && !$this->InFooter) { return array(-2,$w ,$h ); } // New page + new line
  5930. return array(1,$w ,$h ); // new line
  5931. }
  5932. else if ($widthUsed > 0 && $w > $widthLeft && $is_table) { // New line needed in TABLE
  5933. return array(1,$w ,$h ); // new line
  5934. }
  5935. // Will fit on line but NEW PAGE REQUIRED
  5936. else if (($y + $h > $this->PageBreakTrigger) && !$this->InFooter && !$is_table) { return array(-1,$w ,$h ); }
  5937. else { return array(0,$w ,$h ); }
  5938. }
  5939. }
  5940. if ($type == 'annot' || $type == 'bookmark' || $type == 'indexentry' || $type == 'toc') {
  5941. $w = 0.00001;
  5942. $h = 0.00001;
  5943. $objattr['BORDER-WIDTH'] = 0;
  5944. $objattr['BORDER-HEIGHT'] = 0;
  5945. $objattr['BORDER-X'] = $x;
  5946. $objattr['BORDER-Y'] = $y;
  5947. $objattr['INNER-WIDTH'] = 0;
  5948. $objattr['INNER-HEIGHT'] = 0;
  5949. $objattr['INNER-X'] = $x;
  5950. $objattr['INNER-Y'] = $y;
  5951. }
  5952. if ($type == 'image') {
  5953. // Automatically resize to width remaining
  5954. if ($w > $widthLeft && !$is_table) {
  5955. $w = $widthLeft ;
  5956. $h=abs($w*$info['h']/$info['w']);
  5957. }
  5958. $img_w = $w - $extraWidth ;
  5959. $img_h = $h - $extraHeight ;
  5960. $objattr['BORDER-WIDTH'] = $img_w + $objattr['padding_left']/$k + $objattr['padding_right']/$k + (($objattr['border_left']['w']/$k + $objattr['border_right']['w']/$k)/2) ;
  5961. $objattr['BORDER-HEIGHT'] = $img_h + $objattr['padding_top']/$k + $objattr['padding_bottom']/$k + (($objattr['border_top']['w']/$k + $objattr['border_bottom']['w']/$k)/2) ;
  5962. $objattr['BORDER-X'] = $x + $objattr['margin_left']/$k + (($objattr['border_left']['w']/$k)/2) ;
  5963. $objattr['BORDER-Y'] = $y + $objattr['margin_top']/$k + (($objattr['border_top']['w']/$k)/2) ;
  5964. $objattr['INNER-WIDTH'] = $img_w;
  5965. $objattr['INNER-HEIGHT'] = $img_h;
  5966. $objattr['INNER-X'] = $x + $objattr['padding_left']/$k + $objattr['margin_left']/$k + ($objattr['border_left']['w']/$k);
  5967. $objattr['INNER-Y'] = $y + $objattr['padding_top']/$k + $objattr['margin_top']/$k + ($objattr['border_top']['w']/$k) ;
  5968. $objattr['ID'] = $info['i'];
  5969. }
  5970. if ($type == 'input' && $objattr['subtype'] == 'IMAGE') {
  5971. $img_w = $w - $extraWidth ;
  5972. $img_h = $h - $extraHeight ;
  5973. $objattr['BORDER-WIDTH'] = $img_w + (($objattr['border_left']['w']/$k + $objattr['border_right']['w']/$k)/2) ;
  5974. $objattr['BORDER-HEIGHT'] = $img_h + (($objattr['border_top']['w']/$k + $objattr['border_bottom']['w']/$k)/2) ;
  5975. $objattr['BORDER-X'] = $x + $objattr['margin_left']/$k + (($objattr['border_left']['w']/$k)/2) ;
  5976. $objattr['BORDER-Y'] = $y + $objattr['margin_top']/$k + (($objattr['border_top']['w']/$k)/2) ;
  5977. $objattr['INNER-WIDTH'] = $img_w;
  5978. $objattr['INNER-HEIGHT'] = $img_h;
  5979. $objattr['INNER-X'] = $x + $objattr['margin_left']/$k + ($objattr['border_left']['w']/$k);
  5980. $objattr['INNER-Y'] = $y + $objattr['margin_top']/$k + ($objattr['border_top']['w']/$k) ;
  5981. $objattr['ID'] = $info['i'];
  5982. }
  5983. if ($type == 'barcode' || $type == 'textcircle') {
  5984. $b_w = $w - $extraWidth ;
  5985. $b_h = $h - $extraHeight ;
  5986. $objattr['BORDER-WIDTH'] = $b_w + $objattr['padding_left']/$k + $objattr['padding_right']/$k + (($objattr['border_left']['w']/$k + $objattr['border_right']['w']/$k)/2) ;
  5987. $objattr['BORDER-HEIGHT'] = $b_h + $objattr['padding_top']/$k + $objattr['padding_bottom']/$k + (($objattr['border_top']['w']/$k + $objattr['border_bottom']['w']/$k)/2) ;
  5988. $objattr['BORDER-X'] = $x + $objattr['margin_left']/$k + (($objattr['border_left']['w']/$k)/2) ;
  5989. $objattr['BORDER-Y'] = $y + $objattr['margin_top']/$k + (($objattr['border_top']['w']/$k)/2) ;
  5990. $objattr['INNER-X'] = $x + $objattr['padding_left']/$k + $objattr['margin_left']/$k + ($objattr['border_left']['w']/$k);
  5991. $objattr['INNER-Y'] = $y + $objattr['padding_top']/$k + $objattr['margin_top']/$k + ($objattr['border_top']['w']/$k) ;
  5992. $objattr['INNER-WIDTH'] = $b_w;
  5993. $objattr['INNER-HEIGHT'] = $b_h;
  5994. }
  5995. if ($type == 'textarea') {
  5996. // Automatically resize to width remaining
  5997. if ($w > $widthLeft && !$is_table) {
  5998. $w = $widthLeft ;
  5999. }
  6000. if (($y + $h > $this->PageBreakTrigger) && !$this->InFooter) {
  6001. $h=$this->h - $y - $this->bMargin;
  6002. }
  6003. }
  6004. if ($type == 'hr') {
  6005. if ($is_table) {
  6006. $objattr['INNER-WIDTH'] = $maxWidth * $objattr['W-PERCENT']/100;
  6007. $objattr['width'] = $objattr['INNER-WIDTH'];
  6008. $w = $maxWidth;
  6009. }
  6010. else {
  6011. if ($w>$maxWidth) { $w = $maxWidth; }
  6012. $objattr['INNER-WIDTH'] = $w;
  6013. $w = $maxWidth;
  6014. }
  6015. }
  6016. if (($type == 'select') || ($type == 'input' && ($objattr['subtype'] == 'TEXT' || $objattr['subtype'] == 'PASSWORD'))) {
  6017. // Automatically resize to width remaining
  6018. if ($w > $widthLeft && !$is_table) {
  6019. $w = $widthLeft;
  6020. }
  6021. }
  6022. if ($type == 'textarea' || $type == 'select' || $type == 'input') {
  6023. if (isset($objattr['fontsize'])) $objattr['fontsize'] /= $k;
  6024. if (isset($objattr['linewidth'])) $objattr['linewidth'] /= $k;
  6025. }
  6026. if (!isset($objattr['BORDER-Y'])) { $objattr['BORDER-Y'] = 0; }
  6027. if (!isset($objattr['BORDER-X'])) { $objattr['BORDER-X'] = 0; }
  6028. if (!isset($objattr['INNER-Y'])) { $objattr['INNER-Y'] = 0; }
  6029. if (!isset($objattr['INNER-X'])) { $objattr['INNER-X'] = 0; }
  6030. //Return width-height array
  6031. $objattr['OUTER-WIDTH'] = $w;
  6032. $objattr['OUTER-HEIGHT'] = $h;
  6033. $objattr['OUTER-X'] = $x;
  6034. $objattr['OUTER-Y'] = $y;
  6035. return $objattr;
  6036. }
  6037. /*-- END HTML-CSS --*/
  6038. //=============================================================
  6039. //=============================================================
  6040. //=============================================================
  6041. //=============================================================
  6042. //=============================================================
  6043. function SetLineJoin($mode=0)
  6044. {
  6045. $s=sprintf('%d j',$mode);
  6046. if($this->page>0 && ((isset($this->pageoutput[$this->page]['LineJoin']) && $this->pageoutput[$this->page]['LineJoin'] != $s) || !isset($this->pageoutput[$this->page]['LineJoin']) || $this->keep_block_together)) { $this->_out($s); }
  6047. $this->pageoutput[$this->page]['LineJoin'] = $s;
  6048. }
  6049. function SetLineCap($mode=2) {
  6050. $s=sprintf('%d J',$mode);
  6051. if($this->page>0 && ((isset($this->pageoutput[$this->page]['LineCap']) && $this->pageoutput[$this->page]['LineCap'] != $s) || !isset($this->pageoutput[$this->page]['LineCap']) || $this->keep_block_together)) { $this->_out($s); }
  6052. $this->pageoutput[$this->page]['LineCap'] = $s;
  6053. }
  6054. function SetDash($black=false,$white=false)
  6055. {
  6056. if($black and $white) $s=sprintf('[%.3F %.3F] 0 d',$black*_MPDFK,$white*_MPDFK);
  6057. else $s='[] 0 d';
  6058. if($this->page>0 && ((isset($this->pageoutput[$this->page]['Dash']) && $this->pageoutput[$this->page]['Dash'] != $s) || !isset($this->pageoutput[$this->page]['Dash']) || $this->keep_block_together)) { $this->_out($s); }
  6059. $this->pageoutput[$this->page]['Dash'] = $s;
  6060. }
  6061. function SetDisplayPreferences($preferences) {
  6062. // String containing any or none of /HideMenubar/HideToolbar/HideWindowUI/DisplayDocTitle/CenterWindow/FitWindow
  6063. $this->DisplayPreferences .= $preferences;
  6064. }
  6065. function Ln($h='',$collapsible=0)
  6066. {
  6067. // Added collapsible to allow collapsible top-margin on new page
  6068. //Line feed; default value is last cell height
  6069. $this->x = $this->lMargin + $this->blk[$this->blklvl]['outer_left_margin'];
  6070. if ($collapsible && ($this->y==$this->tMargin) && (!$this->ColActive)) { $h = 0; }
  6071. if(is_string($h)) $this->y+=$this->lasth;
  6072. else $this->y+=$h;
  6073. }
  6074. /*-- HTML-CSS --*/
  6075. // $state = 0 normal; 1 top; 2 bottom; 3 top and bottom
  6076. function DivLn($h,$level=-3,$move_y=true,$collapsible=false,$state=0) {
  6077. // this->x is returned as it was
  6078. // adds lines (y) where DIV bgcolors are filled in
  6079. // allows .00001 as nominal height used for bookmarks/annotations etc.
  6080. if ($collapsible && (sprintf("%0.4f", $this->y)==sprintf("%0.4f", $this->tMargin)) && (!$this->ColActive)) { return; }
  6081. if ($collapsible && (sprintf("%0.4f", $this->y)==sprintf("%0.4f", $this->y0)) && ($this->ColActive) && $this->CurrCol == 0) { return; } // *COLUMNS*
  6082. // Still use this method if columns or page-break-inside: avoid, as it allows repositioning later
  6083. // otherwise, now uses PaintDivBB()
  6084. if (!$this->ColActive && !$this->keep_block_together && !$this->kwt) {
  6085. if ($move_y && !$this->ColActive) { $this->y += $h; }
  6086. return;
  6087. }
  6088. if ($level == -3) { $level = $this->blklvl; }
  6089. $firstblockfill = $this->GetFirstBlockFill();
  6090. if ($firstblockfill && $this->blklvl > 0 && $this->blklvl >= $firstblockfill) {
  6091. $last_x = 0;
  6092. $last_w = 0;
  6093. $last_fc = $this->FillColor;
  6094. $bak_x = $this->x;
  6095. $bak_h = $this->divheight;
  6096. $this->divheight = 0; // Temporarily turn off divheight - as Cell() uses it to check for PageBreak
  6097. for ($blvl=$firstblockfill;$blvl<=$level;$blvl++) {
  6098. $this->SetBlockFill($blvl);
  6099. $this->x = $this->lMargin + $this->blk[$blvl]['outer_left_margin'];
  6100. if ($last_x != $this->lMargin + $this->blk[$blvl]['outer_left_margin'] || $last_w != $this->blk[$blvl]['width'] || $last_fc != $this->FillColor) {
  6101. $x = $this->x;
  6102. $this->Cell( ($this->blk[$blvl]['width']), $h, '', '', 0, '', 1);
  6103. if (!$this->keep_block_together && !$this->writingHTMLheader && !$this->writingHTMLfooter) {
  6104. $this->x = $x;
  6105. // $state = 0 normal; 1 top; 2 bottom; 3 top and bottom
  6106. if ($blvl == $this->blklvl) { $this->PaintDivLnBorder($state,$blvl,$h); }
  6107. else { $this->PaintDivLnBorder(0,$blvl,$h); }
  6108. }
  6109. }
  6110. $last_x = $this->lMargin + $this->blk[$blvl]['outer_left_margin'];
  6111. $last_w = $this->blk[$blvl]['width'];
  6112. $last_fc = $this->FillColor;
  6113. }
  6114. // Reset current block fill
  6115. if (isset($this->blk[$this->blklvl]['bgcolorarray'])) {
  6116. $bcor = $this->blk[$this->blklvl]['bgcolorarray'];
  6117. $this->SetFColor($bcor);
  6118. }
  6119. $this->x = $bak_x;
  6120. $this->divheight = $bak_h;
  6121. }
  6122. if ($move_y) { $this->y += $h; }
  6123. }
  6124. /*-- END HTML-CSS --*/
  6125. function SetX($x)
  6126. {
  6127. //Set x position
  6128. if($x >= 0) $this->x=$x;
  6129. else $this->x = $this->w + $x;
  6130. }
  6131. function SetY($y)
  6132. {
  6133. //Set y position and reset x
  6134. $this->x=$this->lMargin;
  6135. if($y>=0)
  6136. $this->y=$y;
  6137. else
  6138. $this->y=$this->h+$y;
  6139. }
  6140. function SetXY($x,$y)
  6141. {
  6142. //Set x and y positions
  6143. $this->SetY($y);
  6144. $this->SetX($x);
  6145. }
  6146. function Output($name='',$dest='')
  6147. {
  6148. //Output PDF to some destination
  6149. if ($this->showStats) {
  6150. echo '<div>Generated in '.sprintf('%.2F',(microtime(true) - $this->time0)).' seconds</div>';
  6151. }
  6152. //Finish document if necessary
  6153. if ($this->progressBar) { $this->UpdateProgressBar(1,'100','Finished'); } // *PROGRESS-BAR*
  6154. if($this->state < 3) $this->Close();
  6155. if ($this->progressBar) { $this->UpdateProgressBar(2,'100','Finished'); } // *PROGRESS-BAR*
  6156. // fn. error_get_last is only in PHP>=5.2
  6157. if ($this->debug && function_exists('error_get_last') && error_get_last()) {
  6158. $e = error_get_last();
  6159. if (($e['type'] < 2048 && $e['type'] != 8) || (intval($e['type']) & intval(ini_get("error_reporting")))) {
  6160. echo "<p>Error message detected - PDF file generation aborted.</p>";
  6161. echo $e['message'].'<br />';
  6162. echo 'File: '.$e['file'].'<br />';
  6163. echo 'Line: '.$e['line'].'<br />';
  6164. exit;
  6165. }
  6166. }
  6167. if (($this->PDFA || $this->PDFX) && $this->encrypted) { $this->Error("PDFA1-b or PDFX/1-a does not permit encryption of documents."); }
  6168. if (count($this->PDFAXwarnings) && (($this->PDFA && !$this->PDFAauto) || ($this->PDFX && !$this->PDFXauto))) {
  6169. if ($this->PDFA) {
  6170. echo '<div>WARNING - This file could not be generated as it stands as a PDFA1-b compliant file.</div>';
  6171. echo '<div>These issues can be automatically fixed by mPDF using <i>$mpdf-&gt;PDFAauto=true;</i></div>';
  6172. echo '<div>Action that mPDF will take to automatically force PDFA1-b compliance are shown in brackets.</div>';
  6173. }
  6174. else {
  6175. echo '<div>WARNING - This file could not be generated as it stands as a PDFX/1-a compliant file.</div>';
  6176. echo '<div>These issues can be automatically fixed by mPDF using <i>$mpdf-&gt;PDFXauto=true;</i></div>';
  6177. echo '<div>Action that mPDF will take to automatically force PDFX/1-a compliance are shown in brackets.</div>';
  6178. }
  6179. echo '<div>Warning(s) generated:</div><ul>';
  6180. $this->PDFAXwarnings = array_unique($this->PDFAXwarnings);
  6181. foreach($this->PDFAXwarnings AS $w) {
  6182. echo '<li>'.$w.'</li>';
  6183. }
  6184. echo '</ul>';
  6185. exit;
  6186. }
  6187. if ($this->showStats) {
  6188. echo '<div>Compiled in '.sprintf('%.2F',(microtime(true) - $this->time0)).' seconds (total)</div>';
  6189. echo '<div>Peak Memory usage '.number_format((memory_get_peak_usage(true)/(1024*1024)),2).' MB</div>';
  6190. echo '<div>PDF file size '.number_format((strlen($this->buffer)/1024)).' kB</div>';
  6191. echo '<div>Number of fonts '.count($this->fonts).'</div>';
  6192. exit;
  6193. }
  6194. if(is_bool($dest)) $dest=$dest ? 'D' : 'F';
  6195. $dest=strtoupper($dest);
  6196. if($dest=='') {
  6197. if($name=='') {
  6198. $name='mpdf.pdf';
  6199. $dest='I';
  6200. }
  6201. else { $dest='F'; }
  6202. }
  6203. /*-- PROGRESS-BAR --*/
  6204. if ($this->progressBar && ($dest=='D' || $dest=='I')) {
  6205. if($name=='') { $name='mpdf.pdf'; }
  6206. $tempfile = '_tempPDF'.RAND(1,10000);
  6207. //Save to local file
  6208. $f=fopen(_MPDF_TEMP_PATH.$tempfile.'.pdf','wb');
  6209. if(!$f) $this->Error('Unable to create temporary output file: '.$tempfile.'.pdf');
  6210. fwrite($f,$this->buffer,strlen($this->buffer));
  6211. fclose($f);
  6212. $this->UpdateProgressBar(3,'','Finished');
  6213. echo '<script type="text/javascript">
  6214. var form = document.createElement("form");
  6215. form.setAttribute("method", "post");
  6216. form.setAttribute("action", "'._MPDF_URI.'includes/out.php");
  6217. var hiddenField = document.createElement("input");
  6218. hiddenField.setAttribute("type", "hidden");
  6219. hiddenField.setAttribute("name", "filename");
  6220. hiddenField.setAttribute("value", "'.$tempfile.'");
  6221. form.appendChild(hiddenField);
  6222. var hiddenField = document.createElement("input");
  6223. hiddenField.setAttribute("type", "hidden");
  6224. hiddenField.setAttribute("name", "dest");
  6225. hiddenField.setAttribute("value", "'.$dest.'");
  6226. form.appendChild(hiddenField);
  6227. var hiddenField = document.createElement("input");
  6228. hiddenField.setAttribute("type", "hidden");
  6229. hiddenField.setAttribute("name", "opname");
  6230. hiddenField.setAttribute("value", "'.$name.'");
  6231. form.appendChild(hiddenField);
  6232. var hiddenField = document.createElement("input");
  6233. hiddenField.setAttribute("type", "hidden");
  6234. hiddenField.setAttribute("name", "path");
  6235. hiddenField.setAttribute("value", "'.urlencode(_MPDF_TEMP_PATH).'");
  6236. form.appendChild(hiddenField);
  6237. document.body.appendChild(form);
  6238. form.submit();
  6239. </script>
  6240. </div>
  6241. </body>
  6242. </html>';
  6243. exit;
  6244. }
  6245. else {
  6246. if ($this->progressBar) { $this->UpdateProgressBar(3,'','Finished'); }
  6247. /*-- END PROGRESS-BAR --*/
  6248. switch($dest) {
  6249. case 'I':
  6250. if ($this->debug && !$this->allow_output_buffering && ob_get_contents()) { echo "<p>Output has already been sent from the script - PDF file generation aborted.</p>"; exit; }
  6251. //Send to standard output
  6252. if(PHP_SAPI!='cli') {
  6253. //We send to a browser
  6254. header('Content-Type: application/pdf');
  6255. if(headers_sent())
  6256. $this->Error('Some data has already been output to browser, can\'t send PDF file');
  6257. if (!isset($_SERVER['HTTP_ACCEPT_ENCODING']) OR empty($_SERVER['HTTP_ACCEPT_ENCODING'])) {
  6258. // don't use length if server using compression
  6259. header('Content-Length: '.strlen($this->buffer));
  6260. }
  6261. header('Content-disposition: inline; filename="'.$name.'"');
  6262. header('Cache-Control: public, must-revalidate, max-age=0');
  6263. header('Pragma: public');
  6264. header('Expires: Sat, 26 Jul 1997 05:00:00 GMT');
  6265. header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
  6266. }
  6267. echo $this->buffer;
  6268. break;
  6269. case 'D':
  6270. //Download file
  6271. header('Content-Description: File Transfer');
  6272. if (headers_sent())
  6273. $this->Error('Some data has already been output to browser, can\'t send PDF file');
  6274. header('Content-Transfer-Encoding: binary');
  6275. header('Cache-Control: public, must-revalidate, max-age=0');
  6276. header('Pragma: public');
  6277. header('Expires: Sat, 26 Jul 1997 05:00:00 GMT');
  6278. header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
  6279. header('Content-Type: application/force-download');
  6280. header('Content-Type: application/octet-stream', false);
  6281. header('Content-Type: application/download', false);
  6282. header('Content-Type: application/pdf', false);
  6283. if (!isset($_SERVER['HTTP_ACCEPT_ENCODING']) OR empty($_SERVER['HTTP_ACCEPT_ENCODING'])) {
  6284. // don't use length if server using compression
  6285. header('Content-Length: '.strlen($this->buffer));
  6286. }
  6287. header('Content-disposition: attachment; filename="'.$name.'"');
  6288. echo $this->buffer;
  6289. break;
  6290. case 'F':
  6291. //Save to local file
  6292. $f=fopen($name,'wb');
  6293. if(!$f) $this->Error('Unable to create output file: '.$name);
  6294. fwrite($f,$this->buffer,strlen($this->buffer));
  6295. fclose($f);
  6296. break;
  6297. case 'S':
  6298. //Return as a string
  6299. return $this->buffer;
  6300. default:
  6301. $this->Error('Incorrect output destination: '.$dest);
  6302. }
  6303. } // *PROGRESS-BAR*
  6304. //======================================================================================================
  6305. // DELETE OLD TMP FILES - Housekeeping
  6306. // Delete any files in tmp/ directory that are >1 hrs old
  6307. $interval = 3600;
  6308. if ($handle = opendir(preg_replace('/\/$/','',_MPDF_TEMP_PATH))) {
  6309. while (false !== ($file = readdir($handle))) {
  6310. if (!is_dir($file) && ((filemtime(_MPDF_TEMP_PATH.$file)+$interval) < time()) && ($file != "..") && ($file != ".")) { // mPDF 5.4.19
  6311. unlink(_MPDF_TEMP_PATH.$file);
  6312. }
  6313. }
  6314. closedir($handle);
  6315. }
  6316. //==============================================================================================================
  6317. return '';
  6318. }
  6319. // *****************************************************************************
  6320. // *
  6321. // Protected methods *
  6322. // *
  6323. // *****************************************************************************
  6324. function _dochecks()
  6325. {
  6326. //Check for locale-related bug
  6327. if(1.1==1)
  6328. $this->Error('Don\'t alter the locale before including mPDF');
  6329. //Check for decimal separator
  6330. if(sprintf('%.1f',1.0)!='1.0')
  6331. setlocale(LC_NUMERIC,'C');
  6332. // mPDF 5.4.11
  6333. $mqr=ini_get("magic_quotes_runtime");
  6334. if ($mqr) { $this->Error('mPDF requires magic_quotes_runtime to be turned off e.g. by using ini_set("magic_quotes_runtime", 0);'); }
  6335. }
  6336. function _begindoc()
  6337. {
  6338. //Start document
  6339. $this->state=1;
  6340. $this->_out('%PDF-'.$this->pdf_version);
  6341. $this->_out('%'.chr(226).chr(227).chr(207).chr(211)); // 4 chars > 128 to show binary file
  6342. }
  6343. /*-- HTMLHEADERS-FOOTERS --*/
  6344. function _puthtmlheaders() {
  6345. $this->state=2;
  6346. $nb=$this->page;
  6347. for($n=1;$n<=$nb;$n++) {
  6348. if ($this->mirrorMargins && $n%2==0) { $OE = 'E'; } // EVEN
  6349. else { $OE = 'O'; }
  6350. $this->page = $n;
  6351. if (isset($this->saveHTMLHeader[$n][$OE])) {
  6352. $html = $this->saveHTMLHeader[$n][$OE]['html'];
  6353. $this->lMargin = $this->saveHTMLHeader[$n][$OE]['ml'];
  6354. $this->rMargin = $this->saveHTMLHeader[$n][$OE]['mr'];
  6355. $this->tMargin = $this->saveHTMLHeader[$n][$OE]['mh'];
  6356. $this->bMargin = $this->saveHTMLHeader[$n][$OE]['mf'];
  6357. $this->margin_header = $this->saveHTMLHeader[$n][$OE]['mh'];
  6358. $this->margin_footer = $this->saveHTMLHeader[$n][$OE]['mf'];
  6359. $this->w = $this->saveHTMLHeader[$n][$OE]['pw'];
  6360. $this->h = $this->saveHTMLHeader[$n][$OE]['ph'];
  6361. $rotate = (isset($this->saveHTMLHeader[$n][$OE]['rotate']) ? $this->saveHTMLHeader[$n][$OE]['rotate'] : null);
  6362. $this->Reset();
  6363. $this->pageoutput[$n] = array();
  6364. $this->pgwidth = $this->w - $this->lMargin - $this->rMargin;
  6365. $this->x = $this->lMargin;
  6366. $this->y = $this->margin_header;
  6367. $html = str_replace('{PAGENO}',$this->pagenumPrefix.$this->docPageNum($n).$this->pagenumSuffix,$html);
  6368. $html = str_replace($this->aliasNbPgGp,$this->nbpgPrefix.$this->docPageNumTotal($n).$this->nbpgSuffix,$html ); // {nbpg}
  6369. $html = str_replace($this->aliasNbPg,$nb,$html ); // {nb}
  6370. $html = preg_replace('/\{DATE\s+(.*?)\}/e',"date('\\1')",$html );
  6371. $this->HTMLheaderPageLinks = array();
  6372. $this->HTMLheaderPageAnnots = array();
  6373. $this->HTMLheaderPageForms = array();
  6374. $this->pageBackgrounds = array();
  6375. $this->writingHTMLheader = true;
  6376. $this->WriteHTML($html , 4); // parameter 4 saves output to $this->headerbuffer
  6377. $this->writingHTMLheader = false;
  6378. $this->Reset();
  6379. $this->pageoutput[$n] = array();
  6380. $s = $this->PrintPageBackgrounds();
  6381. $this->headerbuffer = $s . $this->headerbuffer;
  6382. $os = '';
  6383. if ($rotate) {
  6384. $os .= sprintf('q 0 -1 1 0 0 %.3F cm ',($this->w*_MPDFK));
  6385. }
  6386. $os .= $this->headerbuffer ;
  6387. if ($rotate) {
  6388. $os .= ' Q' . "\n";
  6389. }
  6390. // Writes over the page background but behind any other output on page
  6391. $os = preg_replace('/\\\\/','\\\\\\\\',$os);
  6392. $this->pages[$n] = preg_replace('/(___HEADER___MARKER'.date('jY').')/', "\n".$os."\n".'\\1', $this->pages[$n]);
  6393. $lks = $this->HTMLheaderPageLinks;
  6394. foreach($lks AS $lk) {
  6395. if ($rotate) {
  6396. $lw = $lk[2];
  6397. $lh = $lk[3];
  6398. $lk[2] = $lh;
  6399. $lk[3] = $lw; // swap width and height
  6400. $ax = $lk[0]/_MPDFK;
  6401. $ay = $lk[1]/_MPDFK;
  6402. $bx = $ay-($lh/_MPDFK);
  6403. $by = $this->w-$ax;
  6404. $lk[0] = $bx*_MPDFK;
  6405. $lk[1] = ($this->h-$by)*_MPDFK - $lw;
  6406. }
  6407. $this->PageLinks[$n][]=$lk;
  6408. }
  6409. /*-- FORMS --*/
  6410. foreach($this->HTMLheaderPageForms AS $f) {
  6411. $this->form->forms[$f['n']] = $f;
  6412. }
  6413. /*-- END FORMS --*/
  6414. }
  6415. if (isset($this->saveHTMLFooter[$n][$OE])) {
  6416. $html = $this->saveHTMLFooter[$this->page][$OE]['html'];
  6417. $this->lMargin = $this->saveHTMLFooter[$n][$OE]['ml'];
  6418. $this->rMargin = $this->saveHTMLFooter[$n][$OE]['mr'];
  6419. $this->tMargin = $this->saveHTMLFooter[$n][$OE]['mh'];
  6420. $this->bMargin = $this->saveHTMLFooter[$n][$OE]['mf'];
  6421. $this->margin_header = $this->saveHTMLFooter[$n][$OE]['mh'];
  6422. $this->margin_footer = $this->saveHTMLFooter[$n][$OE]['mf'];
  6423. $this->w = $this->saveHTMLFooter[$n][$OE]['pw'];
  6424. $this->h = $this->saveHTMLFooter[$n][$OE]['ph'];
  6425. $rotate = (isset($this->saveHTMLFooter[$n][$OE]['rotate']) ? $this->saveHTMLFooter[$n][$OE]['rotate'] : null);
  6426. $this->Reset();
  6427. $this->pageoutput[$n] = array();
  6428. $this->pgwidth = $this->w - $this->lMargin - $this->rMargin;
  6429. $this->x = $this->lMargin;
  6430. $top_y = $this->y = $this->h - $this->margin_footer;
  6431. // if bottom-margin==0, corrects to avoid division by zero
  6432. if ($this->y == $this->h) { $top_y = $this->y = ($this->h - 0.1); }
  6433. $html = str_replace('{PAGENO}',$this->pagenumPrefix.$this->docPageNum($n).$this->pagenumSuffix,$html);
  6434. $html = str_replace($this->aliasNbPgGp,$this->nbpgPrefix.$this->docPageNumTotal($n).$this->nbpgSuffix,$html ); // {nbpg}
  6435. $html = str_replace($this->aliasNbPg,$nb,$html ); // {nb}
  6436. $html = preg_replace('/\{DATE\s+(.*?)\}/e',"date('\\1')",$html );
  6437. $this->HTMLheaderPageLinks = array();
  6438. $this->HTMLheaderPageAnnots = array();
  6439. $this->HTMLheaderPageForms = array();
  6440. $this->pageBackgrounds = array();
  6441. $this->writingHTMLfooter = true;
  6442. $this->InFooter = true;
  6443. $this->WriteHTML($html , 4); // parameter 4 saves output to $this->headerbuffer
  6444. $this->writingHTMLfooter = false;
  6445. $this->InFooter = false;
  6446. $this->Reset();
  6447. $this->pageoutput[$n] = array();
  6448. $fheight = $this->y - $top_y;
  6449. $adj = -$fheight;
  6450. $s = $this->PrintPageBackgrounds(-$adj);
  6451. $this->headerbuffer = $s . $this->headerbuffer;
  6452. $os = '';
  6453. $os .= $this->StartTransform(true)."\n";
  6454. if ($rotate) {
  6455. $os .= sprintf('q 0 -1 1 0 0 %.3F cm ',($this->w*_MPDFK));
  6456. }
  6457. $os .= $this->transformTranslate(0, $adj, true)."\n";
  6458. $os .= $this->headerbuffer ;
  6459. if ($rotate) {
  6460. $os .= ' Q' . "\n";
  6461. }
  6462. $os .= $this->StopTransform(true)."\n";
  6463. // Writes over the page background but behind any other output on page
  6464. $os = preg_replace('/\\\\/','\\\\\\\\',$os);
  6465. $this->pages[$n] = preg_replace('/(___HEADER___MARKER'.date('jY').')/', "\n".$os."\n".'\\1', $this->pages[$n]);
  6466. $lks = $this->HTMLheaderPageLinks;
  6467. foreach($lks AS $lk) {
  6468. $lk[1] -= $adj*_MPDFK;
  6469. if ($rotate) {
  6470. $lw = $lk[2];
  6471. $lh = $lk[3];
  6472. $lk[2] = $lh;
  6473. $lk[3] = $lw; // swap width and height
  6474. $ax = $lk[0]/_MPDFK;
  6475. $ay = $lk[1]/_MPDFK;
  6476. $bx = $ay-($lh/_MPDFK);
  6477. $by = $this->w-$ax;
  6478. $lk[0] = $bx*_MPDFK;
  6479. $lk[1] = ($this->h-$by)*_MPDFK - $lw;
  6480. }
  6481. $this->PageLinks[$n][]=$lk;
  6482. }
  6483. /*-- FORMS --*/
  6484. foreach($this->HTMLheaderPageForms AS $f) {
  6485. $f['y'] += $adj;
  6486. $this->form->forms[$f['n']] = $f;
  6487. }
  6488. /*-- END FORMS --*/
  6489. }
  6490. }
  6491. $this->page=$nb;
  6492. $this->state=1;
  6493. }
  6494. /*-- END HTMLHEADERS-FOOTERS --*/
  6495. function _putpages()
  6496. {
  6497. $nb=$this->page;
  6498. $filter=($this->compress) ? '/Filter /FlateDecode ' : '';
  6499. if($this->DefOrientation=='P') {
  6500. $defwPt=$this->fwPt;
  6501. $defhPt=$this->fhPt;
  6502. }
  6503. else {
  6504. $defwPt=$this->fhPt;
  6505. $defhPt=$this->fwPt;
  6506. }
  6507. $annotid=(3+2*$nb);
  6508. // Active Forms
  6509. $totaladdnum = 0;
  6510. for($n=1;$n<=$nb;$n++) {
  6511. if (isset($this->PageLinks[$n])) { $totaladdnum += count($this->PageLinks[$n]); }
  6512. /*-- ANNOTATIONS --*/
  6513. if (isset($this->PageAnnots[$n])) {
  6514. foreach ($this->PageAnnots[$n] as $k => $pl) {
  6515. if (!empty($pl['opt']['popup']) || !empty($pl['opt']['file'])) { $totaladdnum += 2 ; }
  6516. else { $totaladdnum++; }
  6517. }
  6518. }
  6519. /*-- END ANNOTATIONS --*/
  6520. /*-- FORMS --*/
  6521. if ( count($this->form->forms) > 0 ) {
  6522. $this->form->countPageForms($n, $totaladdnum);
  6523. }
  6524. /*-- END FORMS --*/
  6525. }
  6526. /*-- FORMS --*/
  6527. // Make a note in the radio button group of the obj_id it will have
  6528. $ctr = 0;
  6529. if (count($this->form->form_radio_groups)) {
  6530. foreach($this->form->form_radio_groups AS $name=>$frg) {
  6531. $this->form->form_radio_groups[$name]['obj_id'] = $annotid + $totaladdnum + $ctr;
  6532. $ctr++;
  6533. }
  6534. }
  6535. /*-- END FORMS --*/
  6536. // Select unused fonts (usually default font)
  6537. $unused = array();
  6538. foreach($this->fonts as $fk=>$font) {
  6539. if (!$font['used'] && ($font['type']=='TTF')) {
  6540. $unused[] = $fk;
  6541. }
  6542. }
  6543. for($n=1;$n<=$nb;$n++)
  6544. {
  6545. $thispage = $this->pages[$n];
  6546. unset($this->pages[$n]);
  6547. if(isset($this->OrientationChanges[$n])) {
  6548. $hPt=$this->pageDim[$n]['w']*_MPDFK;
  6549. $wPt=$this->pageDim[$n]['h']*_MPDFK;
  6550. $owidthPt_LR = $this->pageDim[$n]['outer_width_TB']*_MPDFK;
  6551. $owidthPt_TB = $this->pageDim[$n]['outer_width_LR']*_MPDFK;
  6552. }
  6553. else {
  6554. $wPt=$this->pageDim[$n]['w']*_MPDFK;
  6555. $hPt=$this->pageDim[$n]['h']*_MPDFK;
  6556. $owidthPt_LR = $this->pageDim[$n]['outer_width_LR']*_MPDFK;
  6557. $owidthPt_TB = $this->pageDim[$n]['outer_width_TB']*_MPDFK;
  6558. }
  6559. // Remove references to unused fonts (usually default font)
  6560. foreach($unused as $fk) {
  6561. if ($this->fonts[$fk]['sip'] || $this->fonts[$fk]['smp']) {
  6562. foreach($this->fonts[$fk]['subsetfontids'] AS $k => $fid) {
  6563. $thispage = preg_replace('/\s\/F'.$fid.' \d[\d.]* Tf\s/is',' ',$thispage);
  6564. }
  6565. }
  6566. else {
  6567. $thispage = preg_replace('/\s\/F'.$this->fonts[$fk]['i'].' \d[\d.]* Tf\s/is',' ',$thispage);
  6568. }
  6569. }
  6570. //Replace number of pages
  6571. if(!empty($this->aliasNbPg)) {
  6572. if (!$this->onlyCoreFonts) { $s1 = $this->UTF8ToUTF16BE($this->aliasNbPg, false); }
  6573. $s2 = $this->aliasNbPg;
  6574. if (!$this->onlyCoreFonts) { $r1 = $this->UTF8ToUTF16BE($nb, false); }
  6575. $r2 = $nb;
  6576. if (preg_match_all('/{mpdfheadernbpg (C|R) ff=(\S*) fs=(\S*) fz=(.*?)}/',$thispage,$m)) {
  6577. for($hi=0;$hi<count($m[0]);$hi++) {
  6578. $pos = $m[1][$hi];
  6579. $hff = $m[2][$hi];
  6580. $hfst = $m[3][$hi];
  6581. $hfsz = $m[4][$hi];
  6582. $this->SetFont($hff,$hfst,$hfsz, false);
  6583. $x1 = $this->GetStringWidth($this->aliasNbPg);
  6584. $x2 = $this->GetStringWidth($nb);
  6585. $xadj = $x1 - $x2;
  6586. if ($pos=='C') { $xadj /= 2; }
  6587. $rep = sprintf(' q 1 0 0 1 %.3F 0 cm ', $xadj*_MPDFK);
  6588. $thispage = str_replace($m[0][$hi], $rep, $thispage);
  6589. }
  6590. }
  6591. if (!$this->onlyCoreFonts) { $thispage=str_replace($s1,$r1,$thispage); }
  6592. $thispage=str_replace($s2,$r2,$thispage);
  6593. // And now for any SMP/SIP fonts subset using <HH> format
  6594. $r = '';
  6595. $nstr = "$nb";
  6596. for($i=0;$i<strlen($nstr);$i++) {
  6597. $r .= sprintf("%02s", strtoupper(dechex(intval($nstr[$i])+48)));
  6598. }
  6599. $thispage=str_replace($this->aliasNbPgHex,$r,$thispage);
  6600. }
  6601. //Replace number of pages in group
  6602. if(!empty($this->aliasNbPgGp)) {
  6603. if (!$this->onlyCoreFonts) { $s1 = $this->UTF8ToUTF16BE($this->aliasNbPgGp, false); }
  6604. $s2 = $this->aliasNbPgGp;
  6605. $nbt = $this->docPageNumTotal($n);
  6606. if (!$this->onlyCoreFonts) { $r1 = $this->UTF8ToUTF16BE($nbt, false); }
  6607. $r2 = $nbt;
  6608. if (preg_match_all('/{mpdfheadernbpggp (C|R) ff=(\S*) fs=(\S*) fz=(.*?)}/',$thispage,$m)) {
  6609. for($hi=0;$hi<count($m[0]);$hi++) {
  6610. $pos = $m[1][$hi];
  6611. $hff = $m[2][$hi];
  6612. $hfst = $m[3][$hi];
  6613. $hfsz = $m[4][$hi];
  6614. $this->SetFont($hff,$hfst,$hfsz, false);
  6615. $x1 = $this->GetStringWidth($this->aliasNbPgGp);
  6616. $x2 = $this->GetStringWidth($nbt);
  6617. $xadj = $x1 - $x2;
  6618. if ($pos=='C') { $xadj /= 2; }
  6619. $rep = sprintf(' q 1 0 0 1 %.3F 0 cm ', $xadj*_MPDFK);
  6620. $thispage = str_replace($m[0][$hi], $rep, $thispage);
  6621. }
  6622. }
  6623. if (!$this->onlyCoreFonts) { $thispage=str_replace($s1,$r1,$thispage); }
  6624. $thispage=str_replace($s2,$r2,$thispage);
  6625. // And now for any SMP/SIP fonts subset using <HH> format
  6626. $r = '';
  6627. $nstr = "$nbt";
  6628. for($i=0;$i<strlen($nstr);$i++) {
  6629. $r .= sprintf("%02s", strtoupper(dechex(intval($nstr[$i])+48)));
  6630. }
  6631. $thispage=str_replace($this->aliasNbPgGpHex,$r,$thispage);
  6632. }
  6633. $thispage = preg_replace('/(\s*___BACKGROUND___PATTERNS'.date('jY').'\s*)/', " ", $thispage);
  6634. $thispage = preg_replace('/(\s*___HEADER___MARKER'.date('jY').'\s*)/', " ", $thispage);
  6635. $thispage = preg_replace('/(\s*___PAGE___START'.date('jY').'\s*)/', " ", $thispage);
  6636. $thispage = preg_replace('/(\s*___TABLE___BACKGROUNDS'.date('jY').'\s*)/', " ", $thispage);
  6637. //Page
  6638. $this->_newobj();
  6639. $this->_out('<</Type /Page');
  6640. $this->_out('/Parent 1 0 R');
  6641. if(isset($this->OrientationChanges[$n])) {
  6642. $this->_out(sprintf('/MediaBox [0 0 %.3F %.3F]',$hPt,$wPt));
  6643. //If BleedBox is defined, it must be larger than the TrimBox, but smaller than the MediaBox
  6644. $bleedMargin = $this->pageDim[$n]['bleedMargin']*_MPDFK;
  6645. if ($bleedMargin && ($owidthPt_TB || $owidthPt_LR)) {
  6646. $x0 = $owidthPt_TB-$bleedMargin;
  6647. $y0 = $owidthPt_LR-$bleedMargin;
  6648. $x1 = $hPt-$owidthPt_TB+$bleedMargin;
  6649. $y1 = $wPt-$owidthPt_LR+$bleedMargin;
  6650. $this->_out(sprintf('/BleedBox [%.3F %.3F %.3F %.3F]', $x0, $y0, $x1, $y1));
  6651. }
  6652. $this->_out(sprintf('/TrimBox [%.3F %.3F %.3F %.3F]', $owidthPt_TB, $owidthPt_LR, ($hPt-$owidthPt_TB), ($wPt-$owidthPt_LR)));
  6653. if (isset($this->OrientationChanges[$n]) && $this->displayDefaultOrientation) {
  6654. if ($this->DefOrientation=='P') { $this->_out('/Rotate 270'); }
  6655. else { $this->_out('/Rotate 90'); }
  6656. }
  6657. }
  6658. //else if($wPt != $defwPt || $hPt != $defhPt) {
  6659. else {
  6660. $this->_out(sprintf('/MediaBox [0 0 %.3F %.3F]',$wPt,$hPt));
  6661. $bleedMargin = $this->pageDim[$n]['bleedMargin']*_MPDFK;
  6662. if ($bleedMargin && ($owidthPt_TB || $owidthPt_LR)) {
  6663. $x0 = $owidthPt_LR-$bleedMargin;
  6664. $y0 = $owidthPt_TB-$bleedMargin;
  6665. $x1 = $wPt-$owidthPt_LR+$bleedMargin;
  6666. $y1 = $hPt-$owidthPt_TB+$bleedMargin;
  6667. $this->_out(sprintf('/BleedBox [%.3F %.3F %.3F %.3F]', $x0, $y0, $x1, $y1));
  6668. }
  6669. $this->_out(sprintf('/TrimBox [%.3F %.3F %.3F %.3F]', $owidthPt_LR, $owidthPt_TB, ($wPt-$owidthPt_LR), ($hPt-$owidthPt_TB)));
  6670. }
  6671. $this->_out('/Resources 2 0 R');
  6672. // Important to keep in RGB colorSpace when using transparency
  6673. if (!$this->PDFA && !$this->PDFX) {
  6674. if ($this->restrictColorSpace == 3)
  6675. $this->_out('/Group << /Type /Group /S /Transparency /CS /DeviceCMYK >> ');
  6676. else if ($this->restrictColorSpace == 1)
  6677. $this->_out('/Group << /Type /Group /S /Transparency /CS /DeviceGray >> ');
  6678. else
  6679. $this->_out('/Group << /Type /Group /S /Transparency /CS /DeviceRGB >> ');
  6680. }
  6681. $annotsnum = 0;
  6682. if (isset($this->PageLinks[$n])) { $annotsnum += count($this->PageLinks[$n]); }
  6683. /*-- ANNOTATIONS --*/
  6684. if (isset($this->PageAnnots[$n])) {
  6685. foreach ($this->PageAnnots[$n] as $k => $pl) {
  6686. if (!empty($pl['opt']['popup']) || !empty($pl['opt']['file'])) { $annotsnum += 2 ; }
  6687. else { $annotsnum++; }
  6688. $this->PageAnnots[$n][$k]['pageobj'] = $this->n;
  6689. }
  6690. }
  6691. /*-- END ANNOTATIONS --*/
  6692. /*-- FORMS --*/
  6693. // Active Forms
  6694. $formsnum = 0;
  6695. if ( count($this->form->forms) > 0 ) {
  6696. foreach( $this->form->forms as $val ) {
  6697. if ( $val['page'] == $n )
  6698. $formsnum++;
  6699. }
  6700. }
  6701. /*-- END FORMS --*/
  6702. if ($annotsnum || $formsnum) {
  6703. $s = '/Annots [ ';
  6704. for($i=0;$i<$annotsnum;$i++) {
  6705. $s .= ($annotid + $i) . ' 0 R ';
  6706. }
  6707. $annotid += $annotsnum;
  6708. /*-- FORMS --*/
  6709. if ( count($this->form->forms) > 0 ) {
  6710. $this->form->addFormIds($n, $s, $annotid);
  6711. }
  6712. /*-- END FORMS --*/
  6713. $s .= '] ';
  6714. $this->_out($s);
  6715. }
  6716. $this->_out('/Contents '.($this->n+1).' 0 R>>');
  6717. $this->_out('endobj');
  6718. //Page content
  6719. $this->_newobj();
  6720. $p=($this->compress) ? gzcompress($thispage) : $thispage;
  6721. $this->_out('<<'.$filter.'/Length '.strlen($p).'>>');
  6722. $this->_putstream($p);
  6723. $this->_out('endobj');
  6724. }
  6725. $this->_putannots($n);
  6726. //Pages root
  6727. $this->offsets[1]=strlen($this->buffer);
  6728. $this->_out('1 0 obj');
  6729. $this->_out('<</Type /Pages');
  6730. $kids='/Kids [';
  6731. for($i=0;$i<$nb;$i++)
  6732. $kids.=(3+2*$i).' 0 R ';
  6733. $this->_out($kids.']');
  6734. $this->_out('/Count '.$nb);
  6735. $this->_out(sprintf('/MediaBox [0 0 %.3F %.3F]',$defwPt,$defhPt));
  6736. $this->_out('>>');
  6737. $this->_out('endobj');
  6738. }
  6739. function _putannots($n) {
  6740. $filter=($this->compress) ? '/Filter /FlateDecode ' : '';
  6741. $nb=$this->page;
  6742. for($n=1;$n<=$nb;$n++)
  6743. {
  6744. $annotobjs = array();
  6745. if(isset($this->PageLinks[$n]) || isset($this->PageAnnots[$n]) || count($this->form->forms) > 0 ) {
  6746. $wPt=$this->pageDim[$n]['w']*_MPDFK;
  6747. $hPt=$this->pageDim[$n]['h']*_MPDFK;
  6748. //Links
  6749. if(isset($this->PageLinks[$n])) {
  6750. foreach($this->PageLinks[$n] as $key => $pl) {
  6751. $this->_newobj();
  6752. $annot='';
  6753. $rect=sprintf('%.3F %.3F %.3F %.3F',$pl[0],$pl[1],$pl[0]+$pl[2],$pl[1]-$pl[3]);
  6754. $annot .= '<</Type /Annot /Subtype /Link /Rect ['.$rect.']';
  6755. $annot .= ' /Contents '.$this->_UTF16BEtextstring($pl[4]);
  6756. $annot .= ' /NM '.$this->_textstring(sprintf('%04u-%04u', $n, $key));
  6757. $annot .= ' /M '.$this->_textstring('D:'.date('YmdHis'));
  6758. $annot .= ' /Border [0 0 0]';
  6759. // Use this (instead of /Border) to specify border around link
  6760. // $annot .= ' /BS <</W 1'; // Width on points; 0 = no line
  6761. // $annot .= ' /S /D'; // style - [S]olid, [D]ashed, [B]eveled, [I]nset, [U]nderline
  6762. // $annot .= ' /D [3 2]'; // Dash array - if dashed
  6763. // $annot .= ' >>';
  6764. // $annot .= ' /C [1 0 0]'; // Color RGB
  6765. if ($this->PDFA || $this->PDFX) { $annot .= ' /F 28'; }
  6766. if (strpos($pl[4],'@')===0) {
  6767. $p=substr($pl[4],1);
  6768. // $h=isset($this->OrientationChanges[$p]) ? $wPt : $hPt;
  6769. $htarg=$this->pageDim[$p]['h']*_MPDFK;
  6770. $annot.=sprintf(' /Dest [%d 0 R /XYZ 0 %.3F null]>>',1+2*$p,$htarg);
  6771. }
  6772. else if(is_string($pl[4])) {
  6773. $annot .= ' /A <</S /URI /URI '.$this->_textstring($pl[4]).'>> >>';
  6774. }
  6775. else {
  6776. $l=$this->links[$pl[4]];
  6777. // may not be set if #link points to non-existent target
  6778. if (isset($this->pageDim[$l[0]]['h'])) { $htarg=$this->pageDim[$l[0]]['h']*_MPDFK; }
  6779. else { $htarg=$this->h*_MPDFK; } // doesn't really matter
  6780. $annot.=sprintf(' /Dest [%d 0 R /XYZ 0 %.3F null]>>',1+2*$l[0],$htarg-$l[1]*_MPDFK);
  6781. }
  6782. $this->_out($annot);
  6783. $this->_out('endobj');
  6784. }
  6785. }
  6786. /*-- ANNOTATIONS --*/
  6787. if(isset($this->PageAnnots[$n])) {
  6788. foreach ($this->PageAnnots[$n] as $key => $pl) {
  6789. if ($pl['opt']['file']) { $FileAttachment=true; }
  6790. else { $FileAttachment=false; }
  6791. $this->_newobj();
  6792. $annot='';
  6793. $pl['opt'] = array_change_key_case($pl['opt'], CASE_LOWER);
  6794. $x = $pl['x'];
  6795. if ($this->annotMargin <> 0 || $x==0 || $x<0) { // Odd page
  6796. $x = ($wPt/_MPDFK) - $this->annotMargin;
  6797. }
  6798. $w = $h = 0;
  6799. $a = $x * _MPDFK;
  6800. $b = $hPt - ($pl['y'] * _MPDFK);
  6801. $annot .= '<</Type /Annot ';
  6802. if ($FileAttachment) {
  6803. $annot .= '/Subtype /FileAttachment';
  6804. // Need to set a size for FileAttachment icons
  6805. if ($pl['opt']['icon']=='Paperclip') { $w=8.235; $h=20; } // 7,17
  6806. else if ($pl['opt']['icon']=='Tag') { $w=20; $h=16; }
  6807. else if ($pl['opt']['icon']=='Graph') { $w=20; $h=20; }
  6808. else { $w=14; $h=20; } // PushPin
  6809. $f = $pl['opt']['file'];
  6810. $f = preg_replace('/^.*\//', '', $f);
  6811. $f = preg_replace('/[^a-zA-Z0-9._]/', '', $f);
  6812. $annot .= '/FS <</Type /Filespec /F ('.$f.')';
  6813. $annot .= '/EF <</F '.($this->n+1).' 0 R>>';
  6814. $annot .= '>>';
  6815. }
  6816. else {
  6817. $annot .= '/Subtype /Text';
  6818. }
  6819. $rect = sprintf('%.3F %.3F %.3F %.3F', $a, $b-$h, $a+$w, $b);
  6820. $annot .= '/Rect ['.$rect.']';
  6821. // contents = description of file in free text
  6822. $annot .= ' /Contents '.$this->_UTF16BEtextstring($pl['txt']);
  6823. $annot .= ' /NM '.$this->_textstring(sprintf('%04u-%04u', $n, (2000 + $key)));
  6824. $annot .= ' /M '.$this->_textstring('D:'.date('YmdHis'));
  6825. $annot .= ' /CreationDate '.$this->_textstring('D:'.date('YmdHis'));
  6826. $annot .= ' /Border [0 0 0]';
  6827. if ($this->PDFA || $this->PDFX) {
  6828. $annot .= ' /F 28';
  6829. $annot .= ' /CA 1';
  6830. }
  6831. else if ($pl['opt']['ca']>0) { $annot .= ' /CA '.$pl['opt']['ca']; }
  6832. $annotcolor = ' /C [';
  6833. if (isset($pl['opt']['c']) AND $pl['opt']['c']) {
  6834. $col = $pl['opt']['c'];
  6835. if ($col{0}==3 || $col{0}==5) { $annotcolor .= sprintf("%.3F %.3F %.3F", ord($col{1})/255,ord($col{2})/255,ord($col{3})/255); }
  6836. else if ($col{0}==1) { $annotcolor .= sprintf("%.3F", ord($col{1})/255); }
  6837. else if ($col{0}==4 || $col{0}==6) { $annotcolor .= sprintf("%.3F %.3F %.3F %.3F", ord($col{1})/100,ord($col{2})/100,ord($col{3})/100,ord($col{4})/100); }
  6838. else { $annotcolor .= '1 1 0'; }
  6839. }
  6840. else { $annotcolor .= '1 1 0'; }
  6841. $annotcolor .= ']';
  6842. $annot .= $annotcolor;
  6843. // Usually Author
  6844. // Use as Title for fileattachment
  6845. if (isset($pl['opt']['t']) AND is_string($pl['opt']['t'])) {
  6846. $annot .= ' /T '.$this->_UTF16BEtextstring($pl['opt']['t']);
  6847. }
  6848. if ($FileAttachment) {
  6849. $iconsapp = array('Paperclip', 'Graph', 'PushPin', 'Tag');
  6850. }
  6851. else { $iconsapp = array('Comment', 'Help', 'Insert', 'Key', 'NewParagraph', 'Note', 'Paragraph'); }
  6852. if (isset($pl['opt']['icon']) AND in_array($pl['opt']['icon'], $iconsapp)) {
  6853. $annot .= ' /Name /'.$pl['opt']['icon'];
  6854. }
  6855. else if ($FileAttachment) { $annot .= ' /Name /PushPin'; }
  6856. else { $annot .= ' /Name /Note'; }
  6857. if (!$FileAttachment) {
  6858. // /Subj is PDF 1.5 spec.
  6859. if (isset($pl['opt']['subj']) && !$this->PDFA && !$this->PDFX) {
  6860. $annot .= ' /Subj '.$this->_UTF16BEtextstring($pl['opt']['subj']);
  6861. }
  6862. if (!empty($pl['opt']['popup'])) {
  6863. $annot .= ' /Open true';
  6864. $annot .= ' /Popup '.($this->n+1).' 0 R';
  6865. }
  6866. else { $annot .= ' /Open false'; }
  6867. }
  6868. $annot .= ' /P '.$pl['pageobj'].' 0 R';
  6869. $annot .= '>>';
  6870. $this->_out($annot);
  6871. $this->_out('endobj');
  6872. if ($FileAttachment) {
  6873. $file = @file_get_contents($pl['opt']['file']) or die('mPDF Error: Cannot access file attachment - '.$pl['opt']['file']);
  6874. $filestream = gzcompress($file);
  6875. $this->_newobj();
  6876. $this->_out('<</Type /EmbeddedFile');
  6877. $this->_out('/Length '.strlen($filestream));
  6878. $this->_out('/Filter /FlateDecode');
  6879. $this->_out('>>');
  6880. $this->_putstream($filestream);
  6881. $this->_out('endobj');
  6882. }
  6883. else if (!empty($pl['opt']['popup'])) {
  6884. $this->_newobj();
  6885. $annot='';
  6886. if (is_array($pl['opt']['popup']) && isset($pl['opt']['popup'][0])) { $x = $pl['opt']['popup'][0] * _MPDFK; }
  6887. else { $x = $pl['x'] * _MPDFK; }
  6888. if (is_array($pl['opt']['popup']) && isset($pl['opt']['popup'][1])) { $y = $hPt - ($pl['opt']['popup'][1] * _MPDFK); }
  6889. else { $y = $hPt - ($pl['y'] * _MPDFK); }
  6890. if (is_array($pl['opt']['popup']) && isset($pl['opt']['popup'][2])) { $w = $pl['opt']['popup'][2] * _MPDFK; }
  6891. else { $w = 180; }
  6892. if (is_array($pl['opt']['popup']) && isset($pl['opt']['popup'][3])) { $h = $pl['opt']['popup'][3] * _MPDFK; }
  6893. else { $h = 120; }
  6894. $rect = sprintf('%.3F %.3F %.3F %.3F', $x, $y-$h, $x+$w, $y);
  6895. $annot .= '<</Type /Annot /Subtype /Popup /Rect ['.$rect.']';
  6896. $annot .= ' /M '.$this->_textstring('D:'.date('YmdHis'));
  6897. if ($this->PDFA || $this->PDFX) { $annot .= ' /F 28'; }
  6898. $annot .= ' /Parent '.($this->n-1).' 0 R';
  6899. $annot .= '>>';
  6900. $this->_out($annot);
  6901. $this->_out('endobj');
  6902. }
  6903. }
  6904. }
  6905. /*-- END ANNOTATIONS --*/
  6906. /*-- FORMS --*/
  6907. // Active Forms
  6908. if ( count($this->form->forms) > 0 ) {
  6909. $this->form->_putFormItems($n, $hPt);
  6910. }
  6911. /*-- END FORMS --*/
  6912. }
  6913. }
  6914. /*-- FORMS --*/
  6915. // Active Forms - Radio Button Group entries
  6916. // Output Radio Button Group form entries (radio_on_obj_id already determined)
  6917. if (count($this->form->form_radio_groups)) {
  6918. $this->form->_putRadioItems($n);
  6919. }
  6920. /*-- END FORMS --*/
  6921. }
  6922. /*-- ANNOTATIONS --*/
  6923. function Annotation($text, $x=0, $y=0, $icon='Note', $author='', $subject='', $opacity=0, $colarray=false, $popup='', $file='') {
  6924. if (is_array($colarray) && count($colarray)==3) { $colarray = $this->ConvertColor('rgb('.$colarray[0].','.$colarray[1].','.$colarray[2].')'); }
  6925. if ($colarray === false) { $colarray = $this->ConvertColor('yellow'); }
  6926. if ($x==0) { $x = $this->x; }
  6927. if ($y==0) { $y = $this->y; }
  6928. $page = $this->page;
  6929. if ($page < 1) { // Document has not been started - assume it's for first page
  6930. $page = 1;
  6931. if ($x==0) { $x = $this->lMargin; }
  6932. if ($y==0) { $y = $this->tMargin; }
  6933. }
  6934. if ($this->PDFA || $this->PDFX) {
  6935. if (($this->PDFA && !$this->PDFAauto) || ($this->PDFX && !$this->PDFXauto)) { $this->PDFAXwarnings[] = "Annotation markers cannot be semi-transparent in PDFA1-b or PDFX/1-a, so they may make underlying text unreadable. (Annotation markers moved to right margin)"; }
  6936. $x = ($this->w) - $this->rMargin*0.66;
  6937. }
  6938. if (!$this->annotMargin) { $y -= $this->FontSize / 2; }
  6939. if (!$opacity && $this->annotMargin) { $opacity = 1; }
  6940. else if (!$opacity) { $opacity = $this->annotOpacity; }
  6941. $an = array('txt' => $text, 'x' => $x, 'y' => $y, 'opt' => array('Icon'=>$icon, 'T'=>$author, 'Subj'=>$subject, 'C'=>$colarray, 'CA'=>$opacity, 'popup'=>$popup, 'file'=>$file));
  6942. if ($this->keep_block_together) { // Save to array - don't write yet
  6943. $this->ktAnnots[$this->page][]= $an;
  6944. return;
  6945. }
  6946. else if ($this->table_rotate) {
  6947. $this->tbrot_Annots[$this->page][]= $an;
  6948. return;
  6949. }
  6950. else if ($this->kwt) {
  6951. $this->kwt_Annots[$this->page][]= $an;
  6952. return;
  6953. }
  6954. // mPDF 5.0
  6955. if ($this->writingHTMLheader || $this->writingHTMLfooter) {
  6956. $this->HTMLheaderPageAnnots[]= $an;
  6957. return;
  6958. }
  6959. //Put an Annotation on the page
  6960. $this->PageAnnots[$page][] = $an;
  6961. /*-- COLUMNS --*/
  6962. // Save cross-reference to Column buffer
  6963. $ref = count($this->PageAnnots[$this->page])-1;
  6964. $this->columnAnnots[$this->CurrCol][INTVAL($this->x)][INTVAL($this->y)] = $ref;
  6965. /*-- END COLUMNS --*/
  6966. }
  6967. /*-- END ANNOTATIONS --*/
  6968. function _putfonts() {
  6969. $nf=$this->n;
  6970. foreach($this->FontFiles as $fontkey=>$info) {
  6971. // TrueType embedded
  6972. if (isset($info['type']) && $info['type']=='TTF' && !$info['sip'] && !$info['smp']) {
  6973. $used = true;
  6974. $asSubset = false;
  6975. foreach($this->fonts AS $k=>$f) {
  6976. if ($f['fontkey'] == $fontkey && $f['type']=='TTF') {
  6977. $used = $f['used'];
  6978. if ($used) {
  6979. $nChars = (ord($f['cw'][0]) << 8) + ord($f['cw'][1]);
  6980. $usage = intval(count($f['subset'])*100 / $nChars);
  6981. $fsize = $info['length1'];
  6982. // Always subset the very large TTF files
  6983. if ($fsize > ($this->maxTTFFilesize *1024)) { $asSubset = true; }
  6984. else if ($usage < $this->percentSubset) { $asSubset = true; }
  6985. }
  6986. if ($f['unAGlyphs']) $aaSubset = true; // mPDF 5.4.05
  6987. if ($this->PDFA || $this->PDFX) $asSubset = false;
  6988. $this->fonts[$k]['asSubset'] = $asSubset;
  6989. break;
  6990. }
  6991. }
  6992. if ($used && !$asSubset) {
  6993. //Font file embedding
  6994. $this->_newobj();
  6995. $this->FontFiles[$fontkey]['n']=$this->n;
  6996. $font='';
  6997. $originalsize = $info['length1'];
  6998. if ($this->repackageTTF || $this->fonts[$fontkey]['TTCfontID']>0) {
  6999. // First see if there is a cached compressed file
  7000. if (file_exists(_MPDF_TTFONTDATAPATH.$fontkey.'.ps.z')) {
  7001. $f=fopen(_MPDF_TTFONTDATAPATH.$fontkey.'.ps.z','rb');
  7002. if(!$f) { $this->Error('Font file .ps.z not found'); }
  7003. while(!feof($f)) { $font .= fread($f, 2048); }
  7004. fclose($f);
  7005. include(_MPDF_TTFONTDATAPATH.$fontkey.'.ps.php'); // sets $originalsize (of repackaged font)
  7006. }
  7007. else {
  7008. if (!class_exists('TTFontFile', false)) { include(_MPDF_PATH .'classes/ttfontsuni.php'); }
  7009. $ttf = new TTFontFile();
  7010. $font = $ttf->repackageTTF($this->FontFiles[$fontkey]['ttffile'], $this->fonts[$fontkey]['TTCfontID'], $this->debugfonts, $this->fonts[$fontkey]['unAGlyphs']); // mPDF 5.4.05
  7011. $originalsize = strlen($font);
  7012. $font = gzcompress($font);
  7013. unset($ttf);
  7014. if (is_writable(dirname(_MPDF_TTFONTDATAPATH.'x'))) {
  7015. $fh = fopen(_MPDF_TTFONTDATAPATH.$fontkey.'.ps.z',"wb");
  7016. fwrite($fh,$font,strlen($font));
  7017. fclose($fh);
  7018. $fh = fopen(_MPDF_TTFONTDATAPATH.$fontkey.'.ps.php',"wb");
  7019. $len = "<?php \n";
  7020. $len.='$originalsize='.$originalsize.";\n";
  7021. $len.="?>";
  7022. fwrite($fh,$len,strlen($len));
  7023. fclose($fh);
  7024. }
  7025. }
  7026. }
  7027. else {
  7028. // First see if there is a cached compressed file
  7029. if (file_exists(_MPDF_TTFONTDATAPATH.$fontkey.'.z')) {
  7030. $f=fopen(_MPDF_TTFONTDATAPATH.$fontkey.'.z','rb');
  7031. if(!$f) { $this->Error('Font file not found'); }
  7032. while(!feof($f)) { $font .= fread($f, 2048); }
  7033. fclose($f);
  7034. }
  7035. else {
  7036. $f=fopen($this->FontFiles[$fontkey]['ttffile'],'rb');
  7037. if(!$f) { $this->Error('Font file not found'); }
  7038. while(!feof($f)) { $font .= fread($f, 2048); }
  7039. fclose($f);
  7040. $font = gzcompress($font);
  7041. if (is_writable(dirname(_MPDF_TTFONTDATAPATH.'x'))) {
  7042. $fh = fopen(_MPDF_TTFONTDATAPATH.$fontkey.'.z',"wb");
  7043. fwrite($fh,$font,strlen($font));
  7044. fclose($fh);
  7045. }
  7046. }
  7047. }
  7048. $this->_out('<</Length '.strlen($font));
  7049. $this->_out('/Filter /FlateDecode');
  7050. $this->_out('/Length1 '.$originalsize);
  7051. $this->_out('>>');
  7052. $this->_putstream($font);
  7053. $this->_out('endobj');
  7054. }
  7055. }
  7056. }
  7057. $nfonts = count($this->fonts);
  7058. $fctr = 1;
  7059. foreach($this->fonts as $k=>$font) {
  7060. //Font objects
  7061. $type=$font['type'];
  7062. $name=$font['name'];
  7063. if ((!isset($font['used']) || !$font['used']) && $type=='TTF') { continue; }
  7064. if ($this->progressBar) { $this->UpdateProgressBar(2,intval($fctr*100/$nfonts),'Writing Fonts'); $fctr++; } // *PROGRESS-BAR*
  7065. if (isset($font['asSubset'])) { $asSubset = $font['asSubset']; }
  7066. else { $asSubset = ''; }
  7067. /*-- CJK-FONTS --*/
  7068. if($type=='Type0') { // = Adobe CJK Fonts
  7069. $this->fonts[$k]['n']=$this->n+1;
  7070. $this->_newobj();
  7071. $this->_out('<</Type /Font');
  7072. $this->_putType0($font);
  7073. }
  7074. else
  7075. /*-- END CJK-FONTS --*/
  7076. if($type=='core') {
  7077. //Standard font
  7078. $this->fonts[$k]['n']=$this->n+1;
  7079. if ($this->PDFA || $this->PDFX) { $this->Error('Core fonts are not allowed in PDF/A1-b or PDFX/1-a files (Times, Helvetica, Courier etc.)'); }
  7080. $this->_newobj();
  7081. $this->_out('<</Type /Font');
  7082. $this->_out('/BaseFont /'.$name);
  7083. $this->_out('/Subtype /Type1');
  7084. if($name!='Symbol' && $name!='ZapfDingbats') {
  7085. $this->_out('/Encoding /WinAnsiEncoding');
  7086. }
  7087. $this->_out('>>');
  7088. $this->_out('endobj');
  7089. }
  7090. // TrueType embedded SUBSETS for SIP (CJK extB containing Supplementary Ideographic Plane 2)
  7091. // Or Unicode Plane 1 - Supplementary Multilingual Plane
  7092. else if ($type=='TTF' && ($font['sip'] || $font['smp'])) {
  7093. if (!$font['used']) { continue; }
  7094. $ssfaid="AA";
  7095. if (!class_exists('TTFontFile', false)) { include(_MPDF_PATH .'classes/ttfontsuni.php'); }
  7096. $ttf = new TTFontFile();
  7097. for($sfid=0;$sfid<count($font['subsetfontids']);$sfid++) {
  7098. $this->fonts[$k]['n'][$sfid]=$this->n+1; // NB an array for subset
  7099. $subsetname = 'MPDF'.$ssfaid.'+'.$font['name'];
  7100. $ssfaid++;
  7101. $subset = $font['subsets'][$sfid];
  7102. unset($subset[0]);
  7103. $ttfontstream = $ttf->makeSubsetSIP($font['ttffile'], $subset, $font['TTCfontID'], $this->debugfonts);
  7104. $ttfontsize = strlen($ttfontstream);
  7105. $fontstream = gzcompress($ttfontstream);
  7106. $widthstring = '';
  7107. $toUnistring = '';
  7108. foreach($font['subsets'][$sfid] AS $cp=>$u) {
  7109. $w = $this->_getCharWidth($font['cw'], $u);
  7110. if ($w !== false) {
  7111. $widthstring .= $w.' ';
  7112. }
  7113. else {
  7114. $widthstring .= round($ttf->defaultWidth).' ';
  7115. }
  7116. if ($u > 65535) {
  7117. $utf8 = chr(($u>>18)+240).chr((($u>>12)&63)+128).chr((($u>>6)&63)+128) .chr(($u&63)+128);
  7118. $utf16 = mb_convert_encoding($utf8, 'UTF-16BE', 'UTF-8');
  7119. $l1 = ord($utf16[0]);
  7120. $h1 = ord($utf16[1]);
  7121. $l2 = ord($utf16[2]);
  7122. $h2 = ord($utf16[3]);
  7123. $toUnistring .= sprintf("<%02s> <%02s%02s%02s%02s>\n", strtoupper(dechex($cp)), strtoupper(dechex($l1)), strtoupper(dechex($h1)), strtoupper(dechex($l2)), strtoupper(dechex($h2)));
  7124. }
  7125. else {
  7126. $toUnistring .= sprintf("<%02s> <%04s>\n", strtoupper(dechex($cp)), strtoupper(dechex($u)));
  7127. }
  7128. }
  7129. //Additional Type1 or TrueType font
  7130. $this->_newobj();
  7131. $this->_out('<</Type /Font');
  7132. $this->_out('/BaseFont /'.$subsetname);
  7133. $this->_out('/Subtype /TrueType');
  7134. $this->_out('/FirstChar 0 /LastChar '.(count($font['subsets'][$sfid])-1));
  7135. $this->_out('/Widths '.($this->n+1).' 0 R');
  7136. $this->_out('/FontDescriptor '.($this->n+2).' 0 R');
  7137. $this->_out('/ToUnicode '.($this->n + 3).' 0 R');
  7138. $this->_out('>>');
  7139. $this->_out('endobj');
  7140. //Widths
  7141. $this->_newobj();
  7142. $this->_out('['.$widthstring.']');
  7143. $this->_out('endobj');
  7144. //Descriptor
  7145. $this->_newobj();
  7146. $s='<</Type /FontDescriptor /FontName /'.$subsetname."\n";
  7147. foreach($font['desc'] as $kd=>$v) {
  7148. if ($kd == 'Flags') { $v = $v | 4; $v = $v & ~32; } // SYMBOLIC font flag
  7149. $s.=' /'.$kd.' '.$v."\n";
  7150. }
  7151. $s.='/FontFile2 '.($this->n + 2).' 0 R';
  7152. $this->_out($s.'>>');
  7153. $this->_out('endobj');
  7154. // ToUnicode
  7155. $this->_newobj();
  7156. $toUni = "/CIDInit /ProcSet findresource begin\n";
  7157. $toUni .= "12 dict begin\n";
  7158. $toUni .= "begincmap\n";
  7159. $toUni .= "/CIDSystemInfo\n";
  7160. $toUni .= "<</Registry (Adobe)\n";
  7161. $toUni .= "/Ordering (UCS)\n";
  7162. $toUni .= "/Supplement 0\n";
  7163. $toUni .= ">> def\n";
  7164. $toUni .= "/CMapName /Adobe-Identity-UCS def\n";
  7165. $toUni .= "/CMapType 2 def\n";
  7166. $toUni .= "1 begincodespacerange\n";
  7167. $toUni .= "<00> <FF>\n";
  7168. $toUni .= "endcodespacerange\n";
  7169. $toUni .= count($font['subsets'][$sfid])." beginbfchar\n";
  7170. $toUni .= $toUnistring;
  7171. $toUni .= "endbfchar\n";
  7172. $toUni .= "endcmap\n";
  7173. $toUni .= "CMapName currentdict /CMap defineresource pop\n";
  7174. $toUni .= "end\n";
  7175. $toUni .= "end\n";
  7176. $this->_out('<</Length '.(strlen($toUni)).'>>');
  7177. $this->_putstream($toUni);
  7178. $this->_out('endobj');
  7179. //Font file
  7180. $this->_newobj();
  7181. $this->_out('<</Length '.strlen($fontstream));
  7182. $this->_out('/Filter /FlateDecode');
  7183. $this->_out('/Length1 '.$ttfontsize);
  7184. $this->_out('>>');
  7185. $this->_putstream($fontstream);
  7186. $this->_out('endobj');
  7187. } // foreach subset
  7188. unset($ttf);
  7189. }
  7190. // TrueType embedded SUBSETS or FULL
  7191. else if ($type=='TTF') {
  7192. $this->fonts[$k]['n']=$this->n+1;
  7193. if ($asSubset ) {
  7194. $ssfaid="A";
  7195. if (!class_exists('TTFontFile', false)) { include(_MPDF_PATH .'classes/ttfontsuni.php'); }
  7196. $ttf = new TTFontFile();
  7197. $fontname = 'MPDFA'.$ssfaid.'+'.$font['name'];
  7198. $subset = $font['subset'];
  7199. unset($subset[0]);
  7200. $ttfontstream = $ttf->makeSubset($font['ttffile'], $subset, $font['TTCfontID'], $this->debugfonts, $font['unAGlyphs']); // mPDF 5.4.05
  7201. $ttfontsize = strlen($ttfontstream);
  7202. $fontstream = gzcompress($ttfontstream);
  7203. $codeToGlyph = $ttf->codeToGlyph;
  7204. unset($codeToGlyph[0]);
  7205. }
  7206. else { $fontname = $font['name']; }
  7207. // Type0 Font
  7208. // A composite font - a font composed of other fonts, organized hierarchically
  7209. $this->_newobj();
  7210. $this->_out('<</Type /Font');
  7211. $this->_out('/Subtype /Type0');
  7212. $this->_out('/BaseFont /'.$fontname.'');
  7213. $this->_out('/Encoding /Identity-H');
  7214. $this->_out('/DescendantFonts ['.($this->n + 1).' 0 R]');
  7215. $this->_out('/ToUnicode '.($this->n + 2).' 0 R');
  7216. $this->_out('>>');
  7217. $this->_out('endobj');
  7218. // CIDFontType2
  7219. // A CIDFont whose glyph descriptions are based on TrueType font technology
  7220. $this->_newobj();
  7221. $this->_out('<</Type /Font');
  7222. $this->_out('/Subtype /CIDFontType2');
  7223. $this->_out('/BaseFont /'.$fontname.'');
  7224. $this->_out('/CIDSystemInfo '.($this->n + 2).' 0 R');
  7225. $this->_out('/FontDescriptor '.($this->n + 3).' 0 R');
  7226. if (isset($font['desc']['MissingWidth'])){
  7227. $this->_out('/DW '.$font['desc']['MissingWidth'].'');
  7228. }
  7229. if (!$asSubset && file_exists(_MPDF_TTFONTDATAPATH.$font['fontkey'].'.cw')) {
  7230. $w = '';
  7231. $w=file_get_contents(_MPDF_TTFONTDATAPATH.$font['fontkey'].'.cw');
  7232. $this->_out($w);
  7233. }
  7234. else {
  7235. $this->_putTTfontwidths($font, $asSubset, $ttf->maxUni);
  7236. }
  7237. $this->_out('/CIDToGIDMap '.($this->n + 4).' 0 R');
  7238. $this->_out('>>');
  7239. $this->_out('endobj');
  7240. // ToUnicode
  7241. $this->_newobj();
  7242. $toUni = "/CIDInit /ProcSet findresource begin\n";
  7243. $toUni .= "12 dict begin\n";
  7244. $toUni .= "begincmap\n";
  7245. $toUni .= "/CIDSystemInfo\n";
  7246. $toUni .= "<</Registry (Adobe)\n";
  7247. $toUni .= "/Ordering (UCS)\n";
  7248. $toUni .= "/Supplement 0\n";
  7249. $toUni .= ">> def\n";
  7250. $toUni .= "/CMapName /Adobe-Identity-UCS def\n";
  7251. $toUni .= "/CMapType 2 def\n";
  7252. $toUni .= "1 begincodespacerange\n";
  7253. $toUni .= "<0000> <FFFF>\n";
  7254. $toUni .= "endcodespacerange\n";
  7255. $toUni .= "1 beginbfrange\n";
  7256. $toUni .= "<0000> <FFFF> <0000>\n";
  7257. $toUni .= "endbfrange\n";
  7258. $toUni .= "endcmap\n";
  7259. $toUni .= "CMapName currentdict /CMap defineresource pop\n";
  7260. $toUni .= "end\n";
  7261. $toUni .= "end\n";
  7262. $this->_out('<</Length '.(strlen($toUni)).'>>');
  7263. $this->_putstream($toUni);
  7264. $this->_out('endobj');
  7265. // CIDSystemInfo dictionary
  7266. $this->_newobj();
  7267. $this->_out('<</Registry (Adobe)');
  7268. $this->_out('/Ordering (UCS)');
  7269. $this->_out('/Supplement 0');
  7270. $this->_out('>>');
  7271. $this->_out('endobj');
  7272. // Font descriptor
  7273. $this->_newobj();
  7274. $this->_out('<</Type /FontDescriptor');
  7275. $this->_out('/FontName /'.$fontname);
  7276. foreach($font['desc'] as $kd=>$v) {
  7277. if ($asSubset && $kd == 'Flags') { $v = $v | 4; $v = $v & ~32; } // SYMBOLIC font flag
  7278. $this->_out(' /'.$kd.' '.$v);
  7279. }
  7280. if ($font['panose']) {
  7281. $this->_out(' /Style << /Panose <'.$font['panose'].'> >>');
  7282. }
  7283. if ($asSubset ) {
  7284. $this->_out('/FontFile2 '.($this->n + 2).' 0 R');
  7285. }
  7286. else if ($font['fontkey']) {
  7287. // obj ID of a stream containing a TrueType font program
  7288. $this->_out('/FontFile2 '.$this->FontFiles[$font['fontkey']]['n'].' 0 R');
  7289. }
  7290. $this->_out('>>');
  7291. $this->_out('endobj');
  7292. // Embed CIDToGIDMap
  7293. // A specification of the mapping from CIDs to glyph indices
  7294. if ($asSubset ) {
  7295. $cidtogidmap = '';
  7296. $cidtogidmap = str_pad('', 256*256*2, "\x00");
  7297. foreach($codeToGlyph as $cc=>$glyph) {
  7298. $cidtogidmap[$cc*2] = chr($glyph >> 8);
  7299. $cidtogidmap[$cc*2 + 1] = chr($glyph & 0xFF);
  7300. }
  7301. $cidtogidmap = gzcompress($cidtogidmap);
  7302. }
  7303. else {
  7304. // First see if there is a cached CIDToGIDMapfile
  7305. $cidtogidmap = '';
  7306. if (file_exists(_MPDF_TTFONTDATAPATH.$font['fontkey'].'.cgm')) {
  7307. $f=fopen(_MPDF_TTFONTDATAPATH.$font['fontkey'].'.cgm','rb');
  7308. while(!feof($f)) { $cidtogidmap .= fread($f, 2048); }
  7309. fclose($f);
  7310. }
  7311. else {
  7312. if (!class_exists('TTFontFile', false)) { include(_MPDF_PATH .'classes/ttfontsuni.php'); }
  7313. $ttf = new TTFontFile();
  7314. $charToGlyph = $ttf->getCTG($font['ttffile'], $font['TTCfontID'], $this->debugfonts, $font['unAGlyphs']); // mPDF 5.4.05
  7315. $cidtogidmap = str_pad('', 256*256*2, "\x00");
  7316. foreach($charToGlyph as $cc=>$glyph) {
  7317. $cidtogidmap[$cc*2] = chr($glyph >> 8);
  7318. $cidtogidmap[$cc*2 + 1] = chr($glyph & 0xFF);
  7319. }
  7320. unset($ttf);
  7321. $cidtogidmap = gzcompress($cidtogidmap);
  7322. if (is_writable(dirname(_MPDF_TTFONTDATAPATH.'x'))) {
  7323. $fh = fopen(_MPDF_TTFONTDATAPATH.$font['fontkey'].'.cgm',"wb");
  7324. fwrite($fh,$cidtogidmap,strlen($cidtogidmap));
  7325. fclose($fh);
  7326. }
  7327. }
  7328. }
  7329. $this->_newobj();
  7330. $this->_out('<</Length '.strlen($cidtogidmap).'');
  7331. $this->_out('/Filter /FlateDecode');
  7332. $this->_out('>>');
  7333. $this->_putstream($cidtogidmap);
  7334. $this->_out('endobj');
  7335. //Font file
  7336. if ($asSubset ) {
  7337. $this->_newobj();
  7338. $this->_out('<</Length '.strlen($fontstream));
  7339. $this->_out('/Filter /FlateDecode');
  7340. $this->_out('/Length1 '.$ttfontsize);
  7341. $this->_out('>>');
  7342. $this->_putstream($fontstream);
  7343. $this->_out('endobj');
  7344. unset($ttf);
  7345. }
  7346. }
  7347. else { $this->Error('Unsupported font type: '.$type.' ('.$name.')'); }
  7348. }
  7349. }
  7350. function _putTTfontwidths(&$font, $asSubset, $maxUni) {
  7351. if ($asSubset && file_exists(_MPDF_TTFONTDATAPATH.$font['fontkey'].'.cw127.php')) {
  7352. include(_MPDF_TTFONTDATAPATH.$font['fontkey'].'.cw127.php') ;
  7353. $startcid = 128;
  7354. }
  7355. else {
  7356. $rangeid = 0;
  7357. $range = array();
  7358. $prevcid = -2;
  7359. $prevwidth = -1;
  7360. $interval = false;
  7361. $startcid = 1;
  7362. }
  7363. if ($asSubset) { $cwlen = $maxUni + 1; }
  7364. else { $cwlen = (strlen($font['cw'])/2); }
  7365. // for each character
  7366. for ($cid=$startcid; $cid<$cwlen; $cid++) {
  7367. if ($cid==128 && $asSubset && (!file_exists(_MPDF_TTFONTDATAPATH.$font['fontkey'].'.cw127.php'))) {
  7368. if (is_writable(dirname(_MPDF_TTFONTDATAPATH.'x'))) {
  7369. $fh = fopen(_MPDF_TTFONTDATAPATH.$font['fontkey'].'.cw127.php',"wb");
  7370. $cw127='<?php'."\n";
  7371. $cw127.='$rangeid='.$rangeid.";\n";
  7372. $cw127.='$prevcid='.$prevcid.";\n";
  7373. $cw127.='$prevwidth='.$prevwidth.";\n";
  7374. if ($interval) { $cw127.='$interval=true'.";\n"; }
  7375. else { $cw127.='$interval=false'.";\n"; }
  7376. $cw127.='$range='.var_export($range,true).";\n";
  7377. $cw127.="?>";
  7378. fwrite($fh,$cw127,strlen($cw127));
  7379. fclose($fh);
  7380. }
  7381. }
  7382. if ($font['cw'][$cid*2] == "\00" && $font['cw'][$cid*2+1] == "\00") { continue; }
  7383. $width = (ord($font['cw'][$cid*2]) << 8) + ord($font['cw'][$cid*2+1]);
  7384. if ($width == 65535) { $width = 0; }
  7385. if ($asSubset && $cid > 255 && (!isset($font['subset'][$cid]) || !$font['subset'][$cid])) {
  7386. continue;
  7387. }
  7388. if (!isset($font['dw']) || (isset($font['dw']) && $width != $font['dw'])) {
  7389. if ($cid == ($prevcid + 1)) {
  7390. // consecutive CID
  7391. if ($width == $prevwidth) {
  7392. if ($width == $range[$rangeid][0]) {
  7393. $range[$rangeid][] = $width;
  7394. } else {
  7395. array_pop($range[$rangeid]);
  7396. // new range
  7397. $rangeid = $prevcid;
  7398. $range[$rangeid] = array();
  7399. $range[$rangeid][] = $prevwidth;
  7400. $range[$rangeid][] = $width;
  7401. }
  7402. $interval = true;
  7403. $range[$rangeid]['interval'] = true;
  7404. } else {
  7405. if ($interval) {
  7406. // new range
  7407. $rangeid = $cid;
  7408. $range[$rangeid] = array();
  7409. $range[$rangeid][] = $width;
  7410. } else {
  7411. $range[$rangeid][] = $width;
  7412. }
  7413. $interval = false;
  7414. }
  7415. } else {
  7416. // new range
  7417. $rangeid = $cid;
  7418. $range[$rangeid] = array();
  7419. $range[$rangeid][] = $width;
  7420. $interval = false;
  7421. }
  7422. $prevcid = $cid;
  7423. $prevwidth = $width;
  7424. }
  7425. }
  7426. $w = $this->_putfontranges($range);
  7427. $this->_out($w);
  7428. if (!$asSubset) {
  7429. if (is_writable(dirname(_MPDF_TTFONTDATAPATH.'x'))) {
  7430. $fh = fopen(_MPDF_TTFONTDATAPATH.$font['fontkey'].'.cw',"wb");
  7431. fwrite($fh,$w,strlen($w));
  7432. fclose($fh);
  7433. }
  7434. }
  7435. }
  7436. function _putfontranges(&$range) {
  7437. // optimize ranges
  7438. $prevk = -1;
  7439. $nextk = -1;
  7440. $prevint = false;
  7441. foreach ($range as $k => $ws) {
  7442. $cws = count($ws);
  7443. if (($k == $nextk) AND (!$prevint) AND ((!isset($ws['interval'])) OR ($cws < 4))) {
  7444. if (isset($range[$k]['interval'])) {
  7445. unset($range[$k]['interval']);
  7446. }
  7447. $range[$prevk] = array_merge($range[$prevk], $range[$k]);
  7448. unset($range[$k]);
  7449. } else {
  7450. $prevk = $k;
  7451. }
  7452. $nextk = $k + $cws;
  7453. if (isset($ws['interval'])) {
  7454. if ($cws > 3) {
  7455. $prevint = true;
  7456. } else {
  7457. $prevint = false;
  7458. }
  7459. unset($range[$k]['interval']);
  7460. --$nextk;
  7461. } else {
  7462. $prevint = false;
  7463. }
  7464. }
  7465. // output data
  7466. $w = '';
  7467. foreach ($range as $k => $ws) {
  7468. if (count(array_count_values($ws)) == 1) {
  7469. // interval mode is more compact
  7470. $w .= ' '.$k.' '.($k + count($ws) - 1).' '.$ws[0];
  7471. } else {
  7472. // range mode
  7473. $w .= ' '.$k.' [ '.implode(' ', $ws).' ]' . "\n";
  7474. }
  7475. }
  7476. return '/W ['.$w.' ]';
  7477. }
  7478. function _putfontwidths(&$font, $cidoffset=0) {
  7479. ksort($font['cw']);
  7480. unset($font['cw'][65535]);
  7481. $rangeid = 0;
  7482. $range = array();
  7483. $prevcid = -2;
  7484. $prevwidth = -1;
  7485. $interval = false;
  7486. // for each character
  7487. foreach ($font['cw'] as $cid => $width) {
  7488. $cid -= $cidoffset;
  7489. if (!isset($font['dw']) || (isset($font['dw']) && $width != $font['dw'])) {
  7490. if ($cid == ($prevcid + 1)) {
  7491. // consecutive CID
  7492. if ($width == $prevwidth) {
  7493. if ($width == $range[$rangeid][0]) {
  7494. $range[$rangeid][] = $width;
  7495. } else {
  7496. array_pop($range[$rangeid]);
  7497. // new range
  7498. $rangeid = $prevcid;
  7499. $range[$rangeid] = array();
  7500. $range[$rangeid][] = $prevwidth;
  7501. $range[$rangeid][] = $width;
  7502. }
  7503. $interval = true;
  7504. $range[$rangeid]['interval'] = true;
  7505. } else {
  7506. if ($interval) {
  7507. // new range
  7508. $rangeid = $cid;
  7509. $range[$rangeid] = array();
  7510. $range[$rangeid][] = $width;
  7511. } else {
  7512. $range[$rangeid][] = $width;
  7513. }
  7514. $interval = false;
  7515. }
  7516. } else {
  7517. // new range
  7518. $rangeid = $cid;
  7519. $range[$rangeid] = array();
  7520. $range[$rangeid][] = $width;
  7521. $interval = false;
  7522. }
  7523. $prevcid = $cid;
  7524. $prevwidth = $width;
  7525. }
  7526. }
  7527. $this->_out($this->_putfontranges($range));
  7528. }
  7529. /*-- CJK-FONTS --*/
  7530. // from class PDF_Chinese CJK EXTENSIONS
  7531. function _putType0(&$font)
  7532. {
  7533. //Type0
  7534. $this->_out('/Subtype /Type0');
  7535. $this->_out('/BaseFont /'.$font['name'].'-'.$font['CMap']);
  7536. $this->_out('/Encoding /'.$font['CMap']);
  7537. $this->_out('/DescendantFonts ['.($this->n+1).' 0 R]');
  7538. $this->_out('>>');
  7539. $this->_out('endobj');
  7540. //CIDFont
  7541. $this->_newobj();
  7542. $this->_out('<</Type /Font');
  7543. $this->_out('/Subtype /CIDFontType0');
  7544. $this->_out('/BaseFont /'.$font['name']);
  7545. $cidinfo = '/Registry '.$this->_textstring('Adobe');
  7546. $cidinfo .= ' /Ordering '.$this->_textstring($font['registry']['ordering']);
  7547. $cidinfo .= ' /Supplement '.$font['registry']['supplement'];
  7548. $this->_out('/CIDSystemInfo <<'.$cidinfo.'>>');
  7549. $this->_out('/FontDescriptor '.($this->n+1).' 0 R');
  7550. if (isset($font['MissingWidth'])){
  7551. $this->_out('/DW '.$font['MissingWidth'].'');
  7552. }
  7553. $this->_putfontwidths($font, 31);
  7554. $this->_out('>>');
  7555. $this->_out('endobj');
  7556. //Font descriptor
  7557. $this->_newobj();
  7558. $s = '<</Type /FontDescriptor /FontName /'.$font['name'];
  7559. foreach ($font['desc'] as $k => $v) {
  7560. if ($k != 'Style') {
  7561. $s .= ' /'.$k.' '.$v.'';
  7562. }
  7563. }
  7564. $this->_out($s.'>>');
  7565. $this->_out('endobj');
  7566. }
  7567. /*-- END CJK-FONTS --*/
  7568. function _putimages()
  7569. {
  7570. $filter=($this->compress) ? '/Filter /FlateDecode ' : '';
  7571. reset($this->images);
  7572. while(list($file,$info)=each($this->images)) {
  7573. $this->_newobj();
  7574. $this->images[$file]['n']=$this->n;
  7575. $this->_out('<</Type /XObject');
  7576. $this->_out('/Subtype /Image');
  7577. $this->_out('/Width '.$info['w']);
  7578. $this->_out('/Height '.$info['h']);
  7579. if (isset($info['masked'])) {
  7580. $this->_out('/SMask '.($this->n - 1).' 0 R');
  7581. }
  7582. if($info['cs']=='Indexed') {
  7583. if ($this->PDFX || ($this->PDFA && $this->restrictColorSpace==3)) { $this->Error("PDFA1-b and PDFX/1-a files do not permit using mixed colour space (".$file.")."); }
  7584. $this->_out('/ColorSpace [/Indexed /DeviceRGB '.(strlen($info['pal'])/3-1).' '.($this->n+1).' 0 R]');
  7585. }
  7586. else {
  7587. $this->_out('/ColorSpace /'.$info['cs']);
  7588. if($info['cs']=='DeviceCMYK') {
  7589. if ($this->PDFA && $this->restrictColorSpace!=3) { $this->Error("PDFA1-b does not permit Images using mixed colour space (".$file.")."); }
  7590. if($info['type']=='jpg') { $this->_out('/Decode [1 0 1 0 1 0 1 0]'); }
  7591. }
  7592. else if ($info['cs']=='DeviceRGB' && ($this->PDFX || ($this->PDFA && $this->restrictColorSpace==3))) { $this->Error("PDFA1-b and PDFX/1-a files do not permit using mixed colour space (".$file.")."); }
  7593. }
  7594. $this->_out('/BitsPerComponent '.$info['bpc']);
  7595. if (isset($info['f']) && $info['f']) { $this->_out('/Filter /'.$info['f']); }
  7596. if(isset($info['parms'])) { $this->_out($info['parms']); }
  7597. if(isset($info['trns']) and is_array($info['trns'])) {
  7598. $trns='';
  7599. for($i=0;$i<count($info['trns']);$i++)
  7600. $trns.=$info['trns'][$i].' '.$info['trns'][$i].' ';
  7601. $this->_out('/Mask ['.$trns.']');
  7602. }
  7603. $this->_out('/Length '.strlen($info['data']).'>>');
  7604. $this->_putstream($info['data']);
  7605. unset($this->images[$file]['data']);
  7606. $this->_out('endobj');
  7607. //Palette
  7608. if($info['cs']=='Indexed') {
  7609. $this->_newobj();
  7610. $pal=($this->compress) ? gzcompress($info['pal']) : $info['pal'];
  7611. $this->_out('<<'.$filter.'/Length '.strlen($pal).'>>');
  7612. $this->_putstream($pal);
  7613. $this->_out('endobj');
  7614. }
  7615. }
  7616. }
  7617. function _putinfo()
  7618. {
  7619. $this->_out('/Producer '.$this->_UTF16BEtextstring('mPDF '.mPDF_VERSION));
  7620. if(!empty($this->title))
  7621. $this->_out('/Title '.$this->_UTF16BEtextstring($this->title));
  7622. if(!empty($this->subject))
  7623. $this->_out('/Subject '.$this->_UTF16BEtextstring($this->subject));
  7624. if(!empty($this->author))
  7625. $this->_out('/Author '.$this->_UTF16BEtextstring($this->author));
  7626. if(!empty($this->keywords))
  7627. $this->_out('/Keywords '.$this->_UTF16BEtextstring($this->keywords));
  7628. if(!empty($this->creator))
  7629. $this->_out('/Creator '.$this->_UTF16BEtextstring($this->creator));
  7630. $z = date('O'); // +0200
  7631. $offset = substr($z,0,3)."'".substr($z,3,2)."'";
  7632. $this->_out('/CreationDate '.$this->_textstring(date('YmdHis').$offset));
  7633. $this->_out('/ModDate '.$this->_textstring(date('YmdHis').$offset));
  7634. if ($this->PDFX) {
  7635. $this->_out('/Trapped/False');
  7636. $this->_out('/GTS_PDFXVersion(PDF/X-1a:2003)');
  7637. }
  7638. }
  7639. function _putmetadata() {
  7640. $this->_newobj();
  7641. $this->MetadataRoot = $this->n;
  7642. $Producer = 'mPDF '.mPDF_VERSION;
  7643. $z = date('O'); // +0200
  7644. $offset = substr($z,0,3).':'.substr($z,3,2);
  7645. $CreationDate = date('Y-m-d\TH:i:s').$offset; // 2006-03-10T10:47:26-05:00 2006-06-19T09:05:17Z
  7646. $uuid = sprintf('%04x%04x-%04x-%04x-%04x-%04x%04x%04x', mt_rand(0, 0xffff), mt_rand(0, 0xffff),
  7647. mt_rand(0, 0xffff), mt_rand(0, 0x0fff) | 0x4000, mt_rand(0, 0x3fff) | 0x8000,
  7648. mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff) );
  7649. $m = '<?xpacket begin="'.chr(239).chr(187).chr(191).'" id="W5M0MpCehiHzreSzNTczkc9d"?>'."\n"; // begin = FEFF BOM
  7650. $m .= ' <x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="3.1-701">'."\n";
  7651. $m .= ' <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">'."\n";
  7652. $m .= ' <rdf:Description rdf:about="uuid:'.$uuid.'" xmlns:pdf="http://ns.adobe.com/pdf/1.3/">'."\n";
  7653. $m .= ' <pdf:Producer>'.$Producer.'</pdf:Producer>'."\n";
  7654. if(!empty($this->keywords)) { $m .= ' <pdf:Keywords>'.$this->keywords.'</pdf:Keywords>'."\n"; }
  7655. $m .= ' </rdf:Description>'."\n";
  7656. $m .= ' <rdf:Description rdf:about="uuid:'.$uuid.'" xmlns:xmp="http://ns.adobe.com/xap/1.0/">'."\n";
  7657. $m .= ' <xmp:CreateDate>'.$CreationDate.'</xmp:CreateDate>'."\n";
  7658. $m .= ' <xmp:ModifyDate>'.$CreationDate.'</xmp:ModifyDate>'."\n";
  7659. $m .= ' <xmp:MetadataDate>'.$CreationDate.'</xmp:MetadataDate>'."\n";
  7660. if(!empty($this->creator)) { $m .= ' <xmp:CreatorTool>'.$this->creator.'</xmp:CreatorTool>'."\n"; }
  7661. $m .= ' </rdf:Description>'."\n";
  7662. // DC elements
  7663. $m .= ' <rdf:Description rdf:about="uuid:'.$uuid.'" xmlns:dc="http://purl.org/dc/elements/1.1/">'."\n";
  7664. $m .= ' <dc:format>application/pdf</dc:format>'."\n";
  7665. if(!empty($this->title)) {
  7666. $m .= ' <dc:title>
  7667. <rdf:Alt>
  7668. <rdf:li xml:lang="x-default">'.$this->title.'</rdf:li>
  7669. </rdf:Alt>
  7670. </dc:title>'."\n";
  7671. }
  7672. if(!empty($this->keywords)) {
  7673. $m .= ' <dc:subject>
  7674. <rdf:Bag>
  7675. <rdf:li>'.$this->keywords.'</rdf:li>
  7676. </rdf:Bag>
  7677. </dc:subject>'."\n";
  7678. }
  7679. if(!empty($this->subject)) {
  7680. $m .= ' <dc:description>
  7681. <rdf:Alt>
  7682. <rdf:li xml:lang="x-default">'.$this->subject.'</rdf:li>
  7683. </rdf:Alt>
  7684. </dc:description>'."\n";
  7685. }
  7686. if(!empty($this->author)) {
  7687. $m .= ' <dc:creator>
  7688. <rdf:Seq>
  7689. <rdf:li>'.$this->author.'</rdf:li>
  7690. </rdf:Seq>
  7691. </dc:creator>'."\n";
  7692. }
  7693. $m .= ' </rdf:Description>'."\n";
  7694. // This bit is specific to PDFX-1a
  7695. if ($this->PDFX) {
  7696. $m .= ' <rdf:Description rdf:about="uuid:'.$uuid.'" xmlns:pdfx="http://ns.adobe.com/pdfx/1.3/" pdfx:Apag_PDFX_Checkup="1.3" pdfx:GTS_PDFXConformance="PDF/X-1a:2003" pdfx:GTS_PDFXVersion="PDF/X-1:2003"/>'."\n";
  7697. }
  7698. // This bit is specific to PDFA-1b
  7699. else if ($this->PDFA) {
  7700. $m .= ' <rdf:Description rdf:about="uuid:'.$uuid.'" xmlns:pdfaid="http://www.aiim.org/pdfa/ns/id/" >'."\n";
  7701. $m .= ' <pdfaid:part>1</pdfaid:part>'."\n";
  7702. $m .= ' <pdfaid:conformance>B</pdfaid:conformance>'."\n";
  7703. $m .= ' <pdfaid:amd>2005</pdfaid:amd>'."\n";
  7704. $m .= ' </rdf:Description>'."\n";
  7705. }
  7706. $m .= ' <rdf:Description rdf:about="uuid:'.$uuid.'" xmlns:xmpMM="http://ns.adobe.com/xap/1.0/mm/">'."\n";
  7707. $m .= ' <xmpMM:DocumentID>uuid:'.$uuid.'</xmpMM:DocumentID>'."\n";
  7708. $m .= ' </rdf:Description>'."\n";
  7709. $m .= ' </rdf:RDF>'."\n";
  7710. $m .= ' </x:xmpmeta>'."\n";
  7711. $m .= str_repeat(str_repeat(' ',100)."\n",20); // 2-4kB whitespace padding required
  7712. $m .= '<?xpacket end="w"?>'; // "r" read only
  7713. $this->_out('<</Type/Metadata/Subtype/XML/Length '.strlen($m).'>>');
  7714. $this->_putstream($m);
  7715. $this->_out('endobj');
  7716. }
  7717. function _putoutputintent() {
  7718. $this->_newobj();
  7719. $this->OutputIntentRoot = $this->n;
  7720. $this->_out('<</Type /OutputIntent');
  7721. if ($this->PDFA) {
  7722. $this->_out('/S /GTS_PDFA1');
  7723. if ($this->ICCProfile) {
  7724. $this->_out('/Info ('.preg_replace('/_/',' ',$this->ICCProfile).')');
  7725. $this->_out('/OutputConditionIdentifier (Custom)');
  7726. $this->_out('/OutputCondition ()');
  7727. }
  7728. else {
  7729. $this->_out('/Info (sRGB IEC61966-2.1)');
  7730. $this->_out('/OutputConditionIdentifier (sRGB IEC61966-2.1)');
  7731. $this->_out('/OutputCondition ()');
  7732. }
  7733. $this->_out('/DestOutputProfile '.($this->n+1).' 0 R');
  7734. }
  7735. else if ($this->PDFX) { // always a CMYK profile
  7736. $this->_out('/S /GTS_PDFX');
  7737. if ($this->ICCProfile) {
  7738. $this->_out('/Info ('.preg_replace('/_/',' ',$this->ICCProfile).')');
  7739. $this->_out('/OutputConditionIdentifier (Custom)');
  7740. $this->_out('/OutputCondition ()');
  7741. $this->_out('/DestOutputProfile '.($this->n+1).' 0 R');
  7742. }
  7743. else {
  7744. $this->_out('/Info (CGATS TR 001)');
  7745. $this->_out('/OutputConditionIdentifier (CGATS TR 001)');
  7746. $this->_out('/OutputCondition (CGATS TR 001 (SWOP))');
  7747. $this->_out('/RegistryName (http://www.color.org)');
  7748. }
  7749. }
  7750. $this->_out('>>');
  7751. $this->_out('endobj');
  7752. if ($this->PDFX && !$this->ICCProfile) { return; } // no ICCProfile embedded
  7753. $this->_newobj();
  7754. if ($this->ICCProfile)
  7755. $s = file_get_contents(_MPDF_PATH.'iccprofiles/'.$this->ICCProfile.'.icc');
  7756. else
  7757. $s = file_get_contents(_MPDF_PATH.'iccprofiles/sRGB_IEC61966-2-1.icc');
  7758. if ($this->compress) { $s = gzcompress($s); }
  7759. $this->_out('<<');
  7760. if ($this->PDFX || ($this->PDFA && $this->restrictColorSpace == 3)) { $this->_out('/N 4'); }
  7761. else { $this->_out('/N 3'); }
  7762. if ($this->compress)
  7763. $this->_out('/Filter /FlateDecode ');
  7764. $this->_out('/Length '.strlen($s).'>>');
  7765. $this->_putstream($s);
  7766. $this->_out('endobj');
  7767. }
  7768. function _putcatalog() {
  7769. $this->_out('/Type /Catalog');
  7770. $this->_out('/Pages 1 0 R');
  7771. if($this->ZoomMode=='fullpage') $this->_out('/OpenAction [3 0 R /Fit]');
  7772. elseif($this->ZoomMode=='fullwidth') $this->_out('/OpenAction [3 0 R /FitH null]');
  7773. elseif($this->ZoomMode=='real') $this->_out('/OpenAction [3 0 R /XYZ null null 1]');
  7774. elseif(!is_string($this->ZoomMode)) $this->_out('/OpenAction [3 0 R /XYZ null null '.($this->ZoomMode/100).']');
  7775. else $this->_out('/OpenAction [3 0 R /XYZ null null null]');
  7776. if($this->LayoutMode=='single') $this->_out('/PageLayout /SinglePage');
  7777. elseif($this->LayoutMode=='continuous') $this->_out('/PageLayout /OneColumn');
  7778. elseif($this->LayoutMode=='twoleft') $this->_out('/PageLayout /TwoColumnLeft');
  7779. elseif($this->LayoutMode=='tworight') $this->_out('/PageLayout /TwoColumnRight');
  7780. elseif($this->LayoutMode=='two') {
  7781. if ($this->mirrorMargins) { $this->_out('/PageLayout /TwoColumnRight'); }
  7782. else { $this->_out('/PageLayout /TwoColumnLeft'); }
  7783. }
  7784. /*-- BOOKMARKS --*/
  7785. if(count($this->BMoutlines)>0) {
  7786. $this->_out('/Outlines '.$this->OutlineRoot.' 0 R');
  7787. $this->_out('/PageMode /UseOutlines');
  7788. }
  7789. /*-- END BOOKMARKS --*/
  7790. if(is_int(strpos($this->DisplayPreferences,'FullScreen'))) $this->_out('/PageMode /FullScreen');
  7791. // Metadata
  7792. if ($this->PDFA || $this->PDFX) {
  7793. $this->_out('/Metadata '.$this->MetadataRoot.' 0 R');
  7794. }
  7795. // OutputIntents
  7796. if ($this->PDFA || $this->PDFX || $this->ICCProfile) {
  7797. $this->_out('/OutputIntents ['.$this->OutputIntentRoot.' 0 R]');
  7798. }
  7799. /*-- FORMS --*/
  7800. if (count($this->form->forms)>0) {
  7801. $this->form->_putFormsCatalog();
  7802. }
  7803. /*-- END FORMS --*/
  7804. if ( isset($this->js) ) {
  7805. $this->_out('/Names << /JavaScript '.($this->n_js).' 0 R >> ');
  7806. }
  7807. if($this->DisplayPreferences || $this->directionality == 'rtl' || $this->mirrorMargins) {
  7808. $this->_out('/ViewerPreferences<<');
  7809. if(is_int(strpos($this->DisplayPreferences,'HideMenubar'))) $this->_out('/HideMenubar true');
  7810. if(is_int(strpos($this->DisplayPreferences,'HideToolbar'))) $this->_out('/HideToolbar true');
  7811. if(is_int(strpos($this->DisplayPreferences,'HideWindowUI'))) $this->_out('/HideWindowUI true');
  7812. if(is_int(strpos($this->DisplayPreferences,'DisplayDocTitle'))) $this->_out('/DisplayDocTitle true');
  7813. if(is_int(strpos($this->DisplayPreferences,'CenterWindow'))) $this->_out('/CenterWindow true');
  7814. if(is_int(strpos($this->DisplayPreferences,'FitWindow'))) $this->_out('/FitWindow true');
  7815. // /PrintScaling is PDF 1.6 spec.
  7816. if(is_int(strpos($this->DisplayPreferences,'NoPrintScaling')) && !$this->PDFA && !$this->PDFX)
  7817. $this->_out('/PrintScaling /None');
  7818. if($this->directionality == 'rtl') $this->_out('/Direction /R2L');
  7819. // /Duplex is PDF 1.7 spec.
  7820. if($this->mirrorMargins && !$this->PDFA && !$this->PDFX) {
  7821. // if ($this->DefOrientation=='P') $this->_out('/Duplex /DuplexFlipShortEdge');
  7822. $this->_out('/Duplex /DuplexFlipLongEdge'); // PDF v1.7+
  7823. }
  7824. $this->_out('>>');
  7825. }
  7826. if ($this->hasOC) {
  7827. $p=$this->n_ocg_print.' 0 R';
  7828. $v=$this->n_ocg_view.' 0 R';
  7829. $h=$this->n_ocg_hidden.' 0 R';
  7830. $as="<</Event /Print /OCGs [$p $v $h] /Category [/Print]>> <</Event /View /OCGs [$p $v $h] /Category [/View]>>";
  7831. $this->_out("/OCProperties <</OCGs [$p $v $h] /D <</ON [$p] /OFF [$v] /OFF [$h] /AS [$as]>>>>");
  7832. }
  7833. }
  7834. // Inactive function left for backwards compatability
  7835. function SetUserRights($enable=true, $annots="", $form="", $signature="") {
  7836. // Does nothing
  7837. }
  7838. function _enddoc() {
  7839. if ($this->progressBar) { $this->UpdateProgressBar(2,'10','Writing Headers & Footers'); } // *PROGRESS-BAR*
  7840. $this->_puthtmlheaders(); // *HTMLHEADERS-FOOTERS*
  7841. if ($this->progressBar) { $this->UpdateProgressBar(2,'20','Writing Pages'); } // *PROGRESS-BAR*
  7842. // Remove references to unused fonts (usually default font)
  7843. foreach($this->fonts as $fk=>$font) {
  7844. if (!$font['used'] && ($font['type']=='TTF')) {
  7845. if ($font['sip'] || $font['smp']) {
  7846. foreach($font['subsetfontids'] AS $k => $fid) {
  7847. foreach($this->pages AS $pn=>$page) {
  7848. $this->pages[$pn] = preg_replace('/\s\/F'.$fid.' \d[\d.]* Tf\s/is',' ',$this->pages[$pn]);
  7849. }
  7850. }
  7851. }
  7852. else {
  7853. foreach($this->pages AS $pn=>$page) {
  7854. $this->pages[$pn] = preg_replace('/\s\/F'.$font['i'].' \d[\d.]* Tf\s/is',' ',$this->pages[$pn]);
  7855. }
  7856. }
  7857. }
  7858. }
  7859. $this->_putpages();
  7860. if ($this->progressBar) { $this->UpdateProgressBar(2,'30','Writing document resources'); } // *PROGRESS-BAR*
  7861. $this->_putresources();
  7862. //Info
  7863. $this->_newobj();
  7864. $this->InfoRoot = $this->n;
  7865. $this->_out('<<');
  7866. if ($this->progressBar) { $this->UpdateProgressBar(2,'80','Writing document info'); } // *PROGRESS-BAR*
  7867. $this->_putinfo();
  7868. $this->_out('>>');
  7869. $this->_out('endobj');
  7870. // METADATA
  7871. if ($this->PDFA || $this->PDFX) { $this->_putmetadata(); }
  7872. // OUTPUTINTENT
  7873. if ($this->PDFA || $this->PDFX || $this->ICCProfile) { $this->_putoutputintent(); }
  7874. //Catalog
  7875. $this->_newobj();
  7876. $this->_out('<<');
  7877. if ($this->progressBar) { $this->UpdateProgressBar(2,'90','Writing document catalog'); } // *PROGRESS-BAR*
  7878. $this->_putcatalog();
  7879. $this->_out('>>');
  7880. $this->_out('endobj');
  7881. //Cross-ref
  7882. $o=strlen($this->buffer);
  7883. $this->_out('xref');
  7884. $this->_out('0 '.($this->n+1));
  7885. $this->_out('0000000000 65535 f ');
  7886. for($i=1; $i <= $this->n ; $i++)
  7887. $this->_out(sprintf('%010d 00000 n ',$this->offsets[$i]));
  7888. //Trailer
  7889. $this->_out('trailer');
  7890. $this->_out('<<');
  7891. $this->_puttrailer();
  7892. $this->_out('>>');
  7893. $this->_out('startxref');
  7894. $this->_out($o);
  7895. $this->buffer .= '%%EOF';
  7896. $this->state=3;
  7897. /*-- IMPORTS --*/
  7898. if ($this->enableImports && count($this->parsers) > 0) {
  7899. foreach ($this->parsers as $k => $_){
  7900. $this->parsers[$k]->closeFile();
  7901. $this->parsers[$k] = null;
  7902. unset($this->parsers[$k]);
  7903. }
  7904. }
  7905. /*-- END IMPORTS --*/
  7906. }
  7907. function _beginpage($orientation,$mgl='',$mgr='',$mgt='',$mgb='',$mgh='',$mgf='',$ohname='',$ehname='',$ofname='',$efname='',$ohvalue=0,$ehvalue=0,$ofvalue=0,$efvalue=0,$pagesel='',$newformat='') {
  7908. if (!($pagesel && $this->page==1 && (sprintf("%0.4f", $this->y)==sprintf("%0.4f", $this->tMargin)))) {
  7909. $this->page++;
  7910. $this->pages[$this->page]='';
  7911. }
  7912. $this->state=2;
  7913. $resetHTMLHeadersrequired = false;
  7914. if ($newformat) { $this->_setPageSize($newformat, $orientation); }
  7915. /*-- CSS-PAGE --*/
  7916. // Paged media (page-box)
  7917. if ($pagesel || (isset($this->page_box['using']) && $this->page_box['using'])) {
  7918. if ($pagesel || $this->page==1) { $first = true; }
  7919. else { $first = false; }
  7920. if ($this->mirrorMargins && ($this->page % 2==0)) { $oddEven = 'E'; }
  7921. else { $oddEven = 'O'; }
  7922. if ($pagesel) { $psel = $pagesel; }
  7923. else if ($this->page_box['current']) { $psel = $this->page_box['current']; }
  7924. else { $psel = ''; }
  7925. list($orientation,$mgl,$mgr,$mgt,$mgb,$mgh,$mgf,$hname,$fname,$bg,$resetpagenum,$pagenumstyle,$suppress,$marks,$newformat) = $this->SetPagedMediaCSS($psel, $first, $oddEven);
  7926. if ($this->mirrorMargins && ($this->page % 2==0)) {
  7927. if ($hname) { $ehvalue = 1; $ehname = $hname; } else { $ehvalue = -1; }
  7928. if ($fname) { $efvalue = 1; $efname = $fname; } else { $efvalue = -1; }
  7929. }
  7930. else {
  7931. if ($hname) { $ohvalue = 1; $ohname = $hname; } else { $ohvalue = -1; }
  7932. if ($fname) { $ofvalue = 1; $ofname = $fname; } else { $ofvalue = -1; }
  7933. }
  7934. if ($resetpagenum || $pagenumstyle || $suppress) {
  7935. $this->PageNumSubstitutions[] = array('from'=>($this->page), 'reset'=> $resetpagenum, 'type'=>$pagenumstyle, 'suppress'=>$suppress);
  7936. }
  7937. // PAGED MEDIA - CROP / CROSS MARKS from @PAGE
  7938. $this->show_marks = $marks;
  7939. // Background color
  7940. if (isset($bg['BACKGROUND-COLOR'])) {
  7941. $cor = $this->ConvertColor($bg['BACKGROUND-COLOR']);
  7942. if ($cor) {
  7943. $this->bodyBackgroundColor = $cor;
  7944. }
  7945. }
  7946. else { $this->bodyBackgroundColor = false; }
  7947. /*-- BACKGROUNDS --*/
  7948. if (isset($bg['BACKGROUND-GRADIENT'])) {
  7949. $this->bodyBackgroundGradient = $bg['BACKGROUND-GRADIENT'];
  7950. }
  7951. else { $this->bodyBackgroundGradient = false; }
  7952. // Tiling Patterns
  7953. if (isset($bg['BACKGROUND-IMAGE']) && $bg['BACKGROUND-IMAGE']) {
  7954. $ret = $this->SetBackground($bg, $this->pgwidth);
  7955. if ($ret) { $this->bodyBackgroundImage = $ret; }
  7956. }
  7957. else { $this->bodyBackgroundImage = false; }
  7958. /*-- END BACKGROUNDS --*/
  7959. $this->page_box['current'] = $psel;
  7960. $this->page_box['using'] = true;
  7961. }
  7962. /*-- END CSS-PAGE --*/
  7963. //Page orientation
  7964. if(!$orientation)
  7965. $orientation=$this->DefOrientation;
  7966. else {
  7967. $orientation=strtoupper(substr($orientation,0,1));
  7968. if($orientation!=$this->DefOrientation)
  7969. $this->OrientationChanges[$this->page]=true;
  7970. }
  7971. if($orientation!=$this->CurOrientation || $newformat) {
  7972. //Change orientation
  7973. if($orientation=='P') {
  7974. $this->wPt=$this->fwPt;
  7975. $this->hPt=$this->fhPt;
  7976. $this->w=$this->fw;
  7977. $this->h=$this->fh;
  7978. if (($this->forcePortraitHeaders || $this->forcePortraitMargins) && $this->DefOrientation=='P') {
  7979. $this->tMargin = $this->orig_tMargin;
  7980. $this->bMargin = $this->orig_bMargin;
  7981. $this->DeflMargin = $this->orig_lMargin;
  7982. $this->DefrMargin = $this->orig_rMargin;
  7983. $this->margin_header = $this->orig_hMargin;
  7984. $this->margin_footer = $this->orig_fMargin;
  7985. }
  7986. else { $resetHTMLHeadersrequired = true; } // *HTMLHEADERS-FOOTERS*
  7987. }
  7988. else {
  7989. $this->wPt=$this->fhPt;
  7990. $this->hPt=$this->fwPt;
  7991. $this->w=$this->fh;
  7992. $this->h=$this->fw;
  7993. if (($this->forcePortraitHeaders || $this->forcePortraitMargins) && $this->DefOrientation=='P') {
  7994. $this->tMargin = $this->orig_lMargin;
  7995. $this->bMargin = $this->orig_rMargin;
  7996. $this->DeflMargin = $this->orig_bMargin;
  7997. $this->DefrMargin = $this->orig_tMargin;
  7998. $this->margin_header = $this->orig_hMargin;
  7999. $this->margin_footer = $this->orig_fMargin;
  8000. }
  8001. else { $resetHTMLHeadersrequired = true; } // *HTMLHEADERS-FOOTERS*
  8002. }
  8003. $this->CurOrientation=$orientation;
  8004. $this->ResetMargins();
  8005. $this->pgwidth = $this->w - $this->lMargin - $this->rMargin;
  8006. $this->PageBreakTrigger=$this->h-$this->bMargin;
  8007. }
  8008. $this->pageDim[$this->page]['w']=$this->w ;
  8009. $this->pageDim[$this->page]['h']=$this->h ;
  8010. $this->pageDim[$this->page]['outer_width_LR'] = isset($this->page_box['outer_width_LR']) ? $this->page_box['outer_width_LR'] : 0;
  8011. $this->pageDim[$this->page]['outer_width_TB'] = isset($this->page_box['outer_width_TB']) ? $this->page_box['outer_width_TB'] : 0;
  8012. if (!isset($this->page_box['outer_width_LR']) && !isset($this->page_box['outer_width_TB'])) {
  8013. $this->pageDim[$this->page]['bleedMargin'] = 0;
  8014. }
  8015. else if ($this->bleedMargin <= $this->page_box['outer_width_LR'] && $this->bleedMargin <= $this->page_box['outer_width_TB']) {
  8016. $this->pageDim[$this->page]['bleedMargin'] = $this->bleedMargin;
  8017. }
  8018. else {
  8019. $this->pageDim[$this->page]['bleedMargin'] = min($this->page_box['outer_width_LR'], $this->page_box['outer_width_TB'])-0.01;
  8020. }
  8021. // If Page Margins are re-defined
  8022. // strlen()>0 is used to pick up (integer) 0, (string) '0', or set value
  8023. if ((strlen($mgl)>0 && $this->DeflMargin != $mgl) || (strlen($mgr)>0 && $this->DefrMargin != $mgr) || (strlen($mgt)>0 && $this->tMargin != $mgt) || (strlen($mgb)>0 && $this->bMargin != $mgb) || (strlen($mgh)>0 && $this->margin_header!=$mgh) || (strlen($mgf)>0 && $this->margin_footer!=$mgf)) {
  8024. if (strlen($mgl)>0) $this->DeflMargin = $mgl;
  8025. if (strlen($mgr)>0) $this->DefrMargin = $mgr;
  8026. if (strlen($mgt)>0) $this->tMargin = $mgt;
  8027. if (strlen($mgb)>0) $this->bMargin = $mgb;
  8028. if (strlen($mgh)>0) $this->margin_header=$mgh;
  8029. if (strlen($mgf)>0) $this->margin_footer=$mgf;
  8030. $this->ResetMargins();
  8031. $this->SetAutoPageBreak($this->autoPageBreak,$this->bMargin);
  8032. $this->pgwidth = $this->w - $this->lMargin - $this->rMargin;
  8033. $resetHTMLHeadersrequired = true; // *HTMLHEADERS-FOOTERS*
  8034. }
  8035. $this->ResetMargins();
  8036. $this->pgwidth = $this->w - $this->lMargin - $this->rMargin;
  8037. $this->SetAutoPageBreak($this->autoPageBreak,$this->bMargin);
  8038. // Reset column top margin
  8039. $this->y0 = $this->tMargin;
  8040. $this->x=$this->lMargin;
  8041. $this->y=$this->tMargin;
  8042. $this->FontFamily='';
  8043. // HEADERS AND FOOTERS
  8044. if ($ohvalue<0 || strtoupper($ohvalue)=='OFF') {
  8045. $this->HTMLHeader = '';
  8046. $this->headerDetails['odd'] = array();
  8047. $resetHTMLHeadersrequired = true; // *HTMLHEADERS-FOOTERS*
  8048. }
  8049. else if ($ohname && $ohvalue>0) {
  8050. /*-- HTMLHEADERS-FOOTERS --*/
  8051. if (preg_match('/^html_(.*)$/i',$ohname,$n)) {
  8052. if (isset($this->pageHTMLheaders[$n[1]])) { $this->HTMLHeader = $this->pageHTMLheaders[$n[1]]; }
  8053. else { $this->HTMLHeader = ''; }
  8054. $this->headerDetails['odd'] = array();
  8055. $resetHTMLHeadersrequired = true;
  8056. }
  8057. else {
  8058. /*-- END HTMLHEADERS-FOOTERS --*/
  8059. if (isset($this->pageheaders[$ohname])) { $this->headerDetails['odd'] = $this->pageheaders[$ohname]; }
  8060. else if ($ohname!='_default') { $this->headerDetails['odd'] = array(); }
  8061. $this->HTMLHeader = '';
  8062. /*-- HTMLHEADERS-FOOTERS --*/
  8063. $resetHTMLHeadersrequired = false;
  8064. }
  8065. /*-- END HTMLHEADERS-FOOTERS --*/
  8066. }
  8067. if ($ehvalue<0 || strtoupper($ehvalue)=='OFF') {
  8068. $this->HTMLHeaderE = '';
  8069. $this->headerDetails['even'] = array();
  8070. $resetHTMLHeadersrequired = true; // *HTMLHEADERS-FOOTERS*
  8071. }
  8072. else if ($ehname && $ehvalue>0) {
  8073. /*-- HTMLHEADERS-FOOTERS --*/
  8074. if (preg_match('/^html_(.*)$/i',$ehname,$n)) {
  8075. if (isset($this->pageHTMLheaders[$n[1]])) { $this->HTMLHeaderE = $this->pageHTMLheaders[$n[1]]; }
  8076. else { $this->HTMLHeaderE = ''; }
  8077. $this->headerDetails['even'] = array();
  8078. $resetHTMLHeadersrequired = true;
  8079. }
  8080. else {
  8081. /*-- END HTMLHEADERS-FOOTERS --*/
  8082. if (isset($this->pageheaders[$ehname])) { $this->headerDetails['even'] = $this->pageheaders[$ehname]; }
  8083. else if ($ehname!='_default') { $this->headerDetails['even'] = array(); }
  8084. $this->HTMLHeaderE = '';
  8085. /*-- HTMLHEADERS-FOOTERS --*/
  8086. $resetHTMLHeadersrequired = false;
  8087. }
  8088. /*-- END HTMLHEADERS-FOOTERS --*/
  8089. }
  8090. if ($ofvalue<0 || strtoupper($ofvalue)=='OFF') {
  8091. $this->HTMLFooter = '';
  8092. $this->footerDetails['odd'] = array();
  8093. $resetHTMLHeadersrequired = true; // *HTMLHEADERS-FOOTERS*
  8094. }
  8095. else if ($ofname && $ofvalue>0) {
  8096. /*-- HTMLHEADERS-FOOTERS --*/
  8097. if (preg_match('/^html_(.*)$/i',$ofname,$n)) {
  8098. if (isset($this->pageHTMLfooters[$n[1]])) { $this->HTMLFooter = $this->pageHTMLfooters[$n[1]]; }
  8099. else { $this->HTMLFooter = ''; }
  8100. $this->footerDetails['odd'] = array();
  8101. $resetHTMLHeadersrequired = true;
  8102. }
  8103. else {
  8104. /*-- END HTMLHEADERS-FOOTERS --*/
  8105. if (isset($this->pagefooters[$ofname])) { $this->footerDetails['odd'] = $this->pagefooters[$ofname]; }
  8106. else if ($ofname!='_default') { $this->footerDetails['odd'] = array(); }
  8107. $this->HTMLFooter = '';
  8108. /*-- HTMLHEADERS-FOOTERS --*/
  8109. $resetHTMLHeadersrequired = true;
  8110. }
  8111. /*-- END HTMLHEADERS-FOOTERS --*/
  8112. }
  8113. if ($efvalue<0 || strtoupper($efvalue)=='OFF') {
  8114. $this->HTMLFooterE = '';
  8115. $this->footerDetails['even'] = array();
  8116. $resetHTMLHeadersrequired = true; // *HTMLHEADERS-FOOTERS*
  8117. }
  8118. else if ($efname && $efvalue>0) {
  8119. /*-- HTMLHEADERS-FOOTERS --*/
  8120. if (preg_match('/^html_(.*)$/i',$efname,$n)) {
  8121. if (isset($this->pageHTMLfooters[$n[1]])) { $this->HTMLFooterE = $this->pageHTMLfooters[$n[1]]; }
  8122. else { $this->HTMLFooterE = ''; }
  8123. $this->footerDetails['even'] = array();
  8124. $resetHTMLHeadersrequired = true;
  8125. }
  8126. else {
  8127. /*-- END HTMLHEADERS-FOOTERS --*/
  8128. if (isset($this->pagefooters[$efname])) { $this->footerDetails['even'] = $this->pagefooters[$efname]; }
  8129. else if ($efname!='_default') { $this->footerDetails['even'] = array(); }
  8130. $this->HTMLFooterE = '';
  8131. /*-- HTMLHEADERS-FOOTERS --*/
  8132. $resetHTMLHeadersrequired = true;
  8133. }
  8134. /*-- END HTMLHEADERS-FOOTERS --*/
  8135. }
  8136. /*-- HTMLHEADERS-FOOTERS --*/
  8137. if ($resetHTMLHeadersrequired) {
  8138. $this->SetHTMLHeader($this->HTMLHeader );
  8139. $this->SetHTMLHeader($this->HTMLHeaderE ,'E');
  8140. $this->SetHTMLFooter($this->HTMLFooter );
  8141. $this->SetHTMLFooter($this->HTMLFooterE ,'E');
  8142. }
  8143. /*-- END HTMLHEADERS-FOOTERS --*/
  8144. if (($this->mirrorMargins) && (($this->page)%2==0)) { // EVEN
  8145. $this->_setAutoHeaderHeight($this->headerDetails['even'], $this->HTMLHeaderE);
  8146. $this->_setAutoFooterHeight($this->footerDetails['even'], $this->HTMLFooterE);
  8147. }
  8148. else { // ODD or DEFAULT
  8149. $this->_setAutoHeaderHeight($this->headerDetails['odd'], $this->HTMLHeader);
  8150. $this->_setAutoFooterHeight($this->footerDetails['odd'], $this->HTMLFooter);
  8151. }
  8152. // Reset column top margin
  8153. $this->y0 = $this->tMargin;
  8154. $this->x=$this->lMargin;
  8155. $this->y=$this->tMargin;
  8156. }
  8157. function _setAutoHeaderHeight(&$det, &$htmlh) {
  8158. if ($this->setAutoTopMargin=='pad') {
  8159. if ($htmlh['h']) { $h = $htmlh['h']; }
  8160. else if ($det) { $h = $this->_getHFHeight($det,'H'); }
  8161. else { $h = 0; }
  8162. $this->tMargin = $this->margin_header + $h + $this->orig_tMargin;
  8163. }
  8164. else if ($this->setAutoTopMargin=='stretch') {
  8165. if ($htmlh['h']) { $h = $htmlh['h']; }
  8166. else if ($det) { $h = $this->_getHFHeight($det,'H'); }
  8167. else { $h = 0; }
  8168. $this->tMargin = max($this->orig_tMargin, $this->margin_header + $h + $this->autoMarginPadding);
  8169. }
  8170. }
  8171. function _setAutoFooterHeight(&$det, &$htmlf) {
  8172. if ($this->setAutoBottomMargin=='pad') {
  8173. if ($htmlf['h']) { $h = $htmlf['h']; }
  8174. else if ($det) { $h = $this->_getHFHeight($det,'F'); }
  8175. else { $h = 0; }
  8176. $this->bMargin = $this->margin_footer + $h + $this->orig_bMargin;
  8177. $this->PageBreakTrigger=$this->h-$this->bMargin ;
  8178. }
  8179. else if ($this->setAutoBottomMargin=='stretch') {
  8180. if ($htmlf['h']) { $h = $htmlf['h']; }
  8181. else if ($det) { $h = $this->_getHFHeight($det,'F'); }
  8182. else { $h = 0; }
  8183. $this->bMargin = max($this->orig_bMargin, $this->margin_footer + $h + $this->autoMarginPadding);
  8184. $this->PageBreakTrigger=$this->h-$this->bMargin ;
  8185. }
  8186. }
  8187. function _getHFHeight(&$det,$end) {
  8188. $h = 0;
  8189. if(count($det)) {
  8190. foreach(array('L','C','R') AS $pos) {
  8191. if (isset($det[$pos]['content']) && $det[$pos]['content']) {
  8192. if (isset($det[$pos]['font-size']) && $det[$pos]['font-size']) { $hfsz = $det[$pos]['font-size']; }
  8193. else { $hfsz = $this->default_font_size; }
  8194. $h = max($h,$hfsz/_MPDFK);
  8195. }
  8196. }
  8197. if ($det['line'] && $end=='H') { $h += $h/_MPDFK*$this->header_line_spacing; }
  8198. else if ($det['line'] && $end=='F') { $h += $h/_MPDFK*$this->footer_line_spacing; }
  8199. }
  8200. return $h;
  8201. }
  8202. function _endpage() {
  8203. /*-- CSS-IMAGE-FLOAT --*/
  8204. $this->printfloatbuffer();
  8205. /*-- END CSS-IMAGE-FLOAT --*/
  8206. if($this->visibility!='visible')
  8207. $this->SetVisibility('visible');
  8208. //End of page contents
  8209. $this->state=1;
  8210. }
  8211. function _newobj($obj_id=false,$onlynewobj=false) {
  8212. if (!$obj_id) {
  8213. $obj_id = ++$this->n;
  8214. }
  8215. //Begin a new object
  8216. if (!$onlynewobj) {
  8217. $this->offsets[$obj_id] = strlen($this->buffer);
  8218. $this->_out($obj_id.' 0 obj');
  8219. $this->_current_obj_id = $obj_id; // for later use with encryption
  8220. }
  8221. }
  8222. function _dounderline($x,$y,$txt) {
  8223. // Now print line exactly where $y secifies - called from Text() and Cell() - adjust position there
  8224. // WORD SPACING
  8225. $w =($this->GetStringWidth($txt)*_MPDFK) + ($this->charspacing * mb_strlen( $txt, $this->mb_enc ))
  8226. + ( $this->ws * mb_substr_count( $txt, ' ', $this->mb_enc ));
  8227. //Draw a line
  8228. return sprintf('%.3F %.3F m %.3F %.3F l S',$x*_MPDFK,($this->h-$y)*_MPDFK,($x*_MPDFK)+$w,($this->h-$y)*_MPDFK);
  8229. }
  8230. function _imageError($file, $firsttime, $msg) {
  8231. // Save re-trying image URL's which have already failed
  8232. $this->failedimages[$file] = true;
  8233. if ($firsttime && ($this->showImageErrors || $this->debug)) {
  8234. $this->Error("IMAGE Error (".$file."): ".$msg);
  8235. }
  8236. return false;
  8237. }
  8238. function _getImage(&$file, $firsttime=true, $allowvector=true, $orig_srcpath=false) {
  8239. // firsttime i.e. whether to add to this->images - use false when calling iteratively
  8240. // Image Data passed directly as var:varname
  8241. if (preg_match('/var:\s*(.*)/',$file, $v)) {
  8242. $data = $this->$v[1];
  8243. $file = md5($data);
  8244. }
  8245. // mPDF 5.5.13
  8246. if (preg_match('/data:image\/(gif|jpeg|png);base64,(.*)/',$file, $v)) {
  8247. $type = $v[1];
  8248. $data = base64_decode($v[2]);
  8249. $file = md5($data);
  8250. }
  8251. $file = urldecode_pathonly($file); // mPDF 5.5.03 // mPDF 5.5.12
  8252. if ($orig_srcpath && substr($orig_srcpath,0,5)!='data:') { $orig_srcpath = urldecode_pathonly($orig_srcpath); } // mPDF 5.5.03 5.4.21
  8253. $ppUx = 0;
  8254. if ($firsttime && preg_match('/(.*\/)([^\/]*)/',$file,$fm)) {
  8255. if (strlen($fm[2])) { $file = $fm[1].preg_replace('/ /','%20',$fm[2]); }
  8256. }
  8257. if ($orig_srcpath && isset($this->images[$orig_srcpath])) { $file=$orig_srcpath; return $this->images[$orig_srcpath]; }
  8258. if (isset($this->images[$file])) { return $this->images[$file]; }
  8259. else if ($orig_srcpath && isset($this->formobjects[$orig_srcpath])) { $file=$orig_srcpath; return $this->formobjects[$file]; }
  8260. else if (isset($this->formobjects[$file])) { return $this->formobjects[$file]; }
  8261. // Save re-trying image URL's which have already failed
  8262. else if ($firsttime && isset($this->failedimages[$file])) { return $this->_imageError($file, $firsttime, ''); }
  8263. if (empty($data)) {
  8264. $type = '';
  8265. $data = '';
  8266. if ($orig_srcpath && $this->basepathIsLocal && $check = @fopen($orig_srcpath,"rb")) {
  8267. fclose($check);
  8268. $file=$orig_srcpath;
  8269. $data = file_get_contents($file);
  8270. $type = $this->_imageTypeFromString($data);
  8271. }
  8272. if (!$data && $check = @fopen($file,"rb")) {
  8273. fclose($check);
  8274. $data = file_get_contents($file);
  8275. $type = $this->_imageTypeFromString($data);
  8276. }
  8277. if ((!$data || !$type) && !ini_get('allow_url_fopen')) { // only worth trying if remote file and !ini_get('allow_url_fopen')
  8278. $this->file_get_contents_by_socket($file, $data); // needs full url?? even on local (never needed for local)
  8279. if ($data) { $type = $this->_imageTypeFromString($data); }
  8280. }
  8281. if ((!$data || !$type) && !ini_get('allow_url_fopen') && function_exists("curl_init")) {
  8282. $this->file_get_contents_by_curl($file, $data); // needs full url?? even on local (never needed for local)
  8283. if ($data) { $type = $this->_imageTypeFromString($data); }
  8284. }
  8285. }
  8286. if (!$data) { return $this->_imageError($file, $firsttime, 'Could not find image file'); }
  8287. if (empty($type)) { $type = $this->_imageTypeFromString($data); }
  8288. if (($type == 'wmf' || $type == 'svg') && !$allowvector) { return $this->_imageError($file, $firsttime, 'WMF or SVG image file not supported in this context'); }
  8289. // SVG
  8290. if ($type == 'svg') {
  8291. if (!class_exists('SVG', false)) { include(_MPDF_PATH .'classes/svg.php'); }
  8292. $svg = new SVG($this);
  8293. $family=$this->FontFamily;
  8294. $style=$this->FontStyle;
  8295. $size=$this->FontSizePt;
  8296. $info = $svg->ImageSVG($data);
  8297. //Restore font
  8298. if($family) $this->SetFont($family,$style,$size,false);
  8299. if (!$info) { return $this->_imageError($file, $firsttime, 'Error parsing SVG file'); }
  8300. $info['type']='svg';
  8301. $info['i']=count($this->formobjects)+1;
  8302. $this->formobjects[$file]=$info;
  8303. return $info;
  8304. }
  8305. // JPEG
  8306. if ($type == 'jpeg' || $type == 'jpg') {
  8307. $hdr = $this->_jpgHeaderFromString($data);
  8308. if (!$hdr) { return $this->_imageError($file, $firsttime, 'Error parsing JPG header'); }
  8309. $a = $this->_jpgDataFromHeader($hdr);
  8310. $j = strpos($data,'JFIF');
  8311. if ($j) {
  8312. //Read resolution
  8313. $unitSp=ord(substr($data,($j+7),1));
  8314. if ($unitSp > 0) {
  8315. $ppUx=$this->_twobytes2int(substr($data,($j+8),2)); // horizontal pixels per meter, usually set to zero
  8316. if ($unitSp == 2) { // = dots per cm (if == 1 set as dpi)
  8317. $ppUx=round($ppUx/10 *25.4);
  8318. }
  8319. }
  8320. }
  8321. if ($a[2] == 'DeviceCMYK' && (($this->PDFA && $this->restrictColorSpace!=3) || $this->restrictColorSpace==2)) {
  8322. // convert to RGB image
  8323. if (!function_exists("gd_info")) { $this->Error("JPG image may not use CMYK color space (".$file.")."); }
  8324. if ($this->PDFA && !$this->PDFAauto) { $this->PDFAXwarnings[] = "JPG image may not use CMYK color space - ".$file." - (Image converted to RGB. NB This will alter the colour profile of the image.)"; }
  8325. $im = @imagecreatefromstring($data);
  8326. if ($im) {
  8327. $tempfile = _MPDF_TEMP_PATH.'_tempImgPNG'.RAND(1,10000).'.png';
  8328. imageinterlace($im, false);
  8329. $check = @imagepng($im, $tempfile);
  8330. if (!$check) { return $this->_imageError($file, $firsttime, 'Error creating temporary file ('.$tempfile.') whilst using GD library to parse JPG(CMYK) image'); }
  8331. $info = $this->_getImage($tempfile, false);
  8332. if (!$info) { return $this->_imageError($file, $firsttime, 'Error parsing temporary file ('.$tempfile.') created with GD library to parse JPG(CMYK) image'); }
  8333. imagedestroy($im);
  8334. unlink($tempfile);
  8335. $info['type']='jpg';
  8336. if ($firsttime) {
  8337. $info['i']=count($this->images)+1;
  8338. $this->images[$file]=$info;
  8339. }
  8340. return $info;
  8341. }
  8342. else { return $this->_imageError($file, $firsttime, 'Error creating GD image file from JPG(CMYK) image'); }
  8343. }
  8344. else if ($a[2] == 'DeviceRGB' && ($this->PDFX || $this->restrictColorSpace==3)) {
  8345. // Convert to CMYK image stream - nominally returned as type='png'
  8346. $info = $this->_convImage($data, $a[2], 'DeviceCMYK', $a[0], $a[1], $ppUx, false);
  8347. if (($this->PDFA && !$this->PDFAauto) || ($this->PDFX && !$this->PDFXauto)) { $this->PDFAXwarnings[] = "JPG image may not use RGB color space - ".$file." - (Image converted to CMYK. NB This will alter the colour profile of the image.)"; }
  8348. }
  8349. else if (($a[2] == 'DeviceRGB' || $a[2] == 'DeviceCMYK') && $this->restrictColorSpace==1) {
  8350. // Convert to Grayscale image stream - nominally returned as type='png'
  8351. $info = $this->_convImage($data, $a[2], 'DeviceGray', $a[0], $a[1], $ppUx, false);
  8352. }
  8353. else {
  8354. $info = array('w'=>$a[0],'h'=>$a[1],'cs'=>$a[2],'bpc'=>$a[3],'f'=>'DCTDecode','data'=>$data, 'type'=>'jpg');
  8355. if ($ppUx) { $info['set-dpi'] = $ppUx; }
  8356. }
  8357. if (!$info) { return $this->_imageError($file, $firsttime, 'Error parsing or converting JPG image'); }
  8358. if ($firsttime) {
  8359. $info['i']=count($this->images)+1;
  8360. $this->images[$file]=$info;
  8361. }
  8362. return $info;
  8363. }
  8364. // PNG
  8365. else if ($type == 'png') {
  8366. //Check signature
  8367. if(substr($data,0,8)!=chr(137).'PNG'.chr(13).chr(10).chr(26).chr(10)) {
  8368. return $this->_imageError($file, $firsttime, 'Error parsing PNG identifier');
  8369. }
  8370. //Read header chunk
  8371. if(substr($data,12,4)!='IHDR') {
  8372. return $this->_imageError($file, $firsttime, 'Incorrect PNG file (no IHDR block found)');
  8373. }
  8374. $w=$this->_fourbytes2int(substr($data,16,4));
  8375. $h=$this->_fourbytes2int(substr($data,20,4));
  8376. $bpc=ord(substr($data,24,1));
  8377. $errpng = false;
  8378. $pngalpha = false;
  8379. if($bpc>8) { $errpng = 'not 8-bit depth'; }
  8380. $ct=ord(substr($data,25,1));
  8381. if($ct==0) { $colspace='DeviceGray'; }
  8382. elseif($ct==2) { $colspace='DeviceRGB'; }
  8383. elseif($ct==3) { $colspace='Indexed'; }
  8384. elseif($ct==4) { $colspace='DeviceGray'; $errpng = 'alpha channel'; $pngalpha = true; }
  8385. else { $colspace='DeviceRGB'; $errpng = 'alpha channel'; $pngalpha = true; }
  8386. if(ord(substr($data,26,1))!=0) { $errpng = 'compression method'; }
  8387. if(ord(substr($data,27,1))!=0) { $errpng = 'filter method'; }
  8388. if(ord(substr($data,28,1))!=0) { $errpng = 'interlaced file'; }
  8389. $j = strpos($data,'pHYs');
  8390. if ($j) {
  8391. //Read resolution
  8392. $unitSp=ord(substr($data,($j+12),1));
  8393. if ($unitSp == 1) {
  8394. $ppUx=$this->_fourbytes2int(substr($data,($j+4),4)); // horizontal pixels per meter, usually set to zero
  8395. $ppUx=round($ppUx/1000 *25.4);
  8396. }
  8397. }
  8398. if (($colspace == 'DeviceRGB' || $colspace == 'Indexed') && ($this->PDFX || $this->restrictColorSpace==3)) {
  8399. // Convert to CMYK image stream - nominally returned as type='png'
  8400. $info = $this->_convImage($data, $colspace, 'DeviceCMYK', $w, $h, $ppUx, $pngalpha);
  8401. if (($this->PDFA && !$this->PDFAauto) || ($this->PDFX && !$this->PDFXauto)) { $this->PDFAXwarnings[] = "PNG image may not use RGB color space - ".$file." - (Image converted to CMYK. NB This will alter the colour profile of the image.)"; }
  8402. }
  8403. else if (($colspace == 'DeviceRGB' || $colspace == 'Indexed') && $this->restrictColorSpace==1) {
  8404. // Convert to Grayscale image stream - nominally returned as type='png'
  8405. $info = $this->_convImage($data, $colspace, 'DeviceGray', $w, $h, $ppUx, $pngalpha);
  8406. }
  8407. else if (($this->PDFA || $this->PDFX) && $pngalpha) {
  8408. // Remove alpha channel
  8409. if ($this->restrictColorSpace==1) { // Grayscale
  8410. $info = $this->_convImage($data, $colspace, 'DeviceGray', $w, $h, $ppUx, $pngalpha);
  8411. }
  8412. else if ($this->restrictColorSpace==3) { // CMYK
  8413. $info = $this->_convImage($data, $colspace, 'DeviceCMYK', $w, $h, $ppUx, $pngalpha);
  8414. }
  8415. else if ($this->PDFA ) { // RGB
  8416. $info = $this->_convImage($data, $colspace, 'DeviceRGB', $w, $h, $ppUx, $pngalpha);
  8417. }
  8418. if (($this->PDFA && !$this->PDFAauto) || ($this->PDFX && !$this->PDFXauto)) { $this->PDFAXwarnings[] = "Transparency (alpha channel) not permitted in PDFA or PDFX files - ".$file." - (Image converted to one without transparency.)"; }
  8419. }
  8420. else if ($errpng || $pngalpha) {
  8421. if (function_exists('gd_info')) { $gd = gd_info(); }
  8422. else {$gd = array(); }
  8423. if (!isset($gd['PNG Support'])) { return $this->_imageError($file, $firsttime, 'GD library required for PNG image ('.$errpng.')'); }
  8424. $im = imagecreatefromstring($data);
  8425. if (!$im) { return $this->_imageError($file, $firsttime, 'Error creating GD image from PNG file ('.$errpng.')'); }
  8426. $w = imagesx($im);
  8427. $h = imagesy($im);
  8428. if ($im) {
  8429. $tempfile = _MPDF_TEMP_PATH.'_tempImgPNG'.RAND(1,10000).'.png';
  8430. // Alpha channel set
  8431. if ($pngalpha) {
  8432. if ($this->PDFA) { $this->Error("PDFA1-b does not permit images with alpha channel transparency (".$file.")."); }
  8433. $imgalpha = imagecreate($w, $h);
  8434. // generate gray scale pallete
  8435. for ($c = 0; $c < 256; ++$c) { ImageColorAllocate($imgalpha, $c, $c, $c); }
  8436. // extract alpha channel
  8437. $gammacorr = 2.2; // gamma correction
  8438. for ($xpx = 0; $xpx < $w; ++$xpx) {
  8439. for ($ypx = 0; $ypx < $h; ++$ypx) {
  8440. //$colorindex = imagecolorat($im, $xpx, $ypx);
  8441. //$col = imagecolorsforindex($im, $colorindex);
  8442. //$gamma2 = (pow((((127 - $col['alpha']) * 255 / 127) / 255), $gammacorr) * 255);
  8443. $alpha = (imagecolorat($im, $xpx, $ypx) & 0x7F000000) >> 24;
  8444. if ($alpha < 127) {
  8445. if ($alpha==0) { $gamma = 255; }
  8446. else
  8447. $gamma = (pow((((127 - $alpha) * 255 / 127) / 255), $gammacorr) * 255);
  8448. imagesetpixel($imgalpha, $xpx, $ypx, $gamma);
  8449. }
  8450. }
  8451. }
  8452. // create temp alpha file
  8453. $tempfile_alpha = _MPDF_TEMP_PATH.'_tempMskPNG'.RAND(1,10000).'.png';
  8454. if (!is_writable($tempfile_alpha)) {
  8455. ob_start();
  8456. $check = @imagepng($imgalpha);
  8457. if (!$check) { return $this->_imageError($file, $firsttime, 'Error creating temporary image object whilst using GD library to parse PNG image'); }
  8458. imagedestroy($imgalpha);
  8459. $this->_tempimg = ob_get_contents();
  8460. $this->_tempimglnk = 'var:_tempimg';
  8461. ob_end_clean();
  8462. // extract image without alpha channel
  8463. $imgplain = imagecreatetruecolor($w, $h);
  8464. imagecopy($imgplain, $im, 0, 0, 0, 0, $w, $h);
  8465. // create temp image file
  8466. $minfo = $this->_getImage($this->_tempimglnk, false);
  8467. if (!$minfo) { return $this->_imageError($file, $firsttime, 'Error parsing temporary file image object created with GD library to parse PNG image'); }
  8468. ob_start();
  8469. $check = @imagepng($imgplain);
  8470. if (!$check) { return $this->_imageError($file, $firsttime, 'Error creating temporary image object whilst using GD library to parse PNG image'); }
  8471. $this->_tempimg = ob_get_contents();
  8472. $this->_tempimglnk = 'var:_tempimg';
  8473. ob_end_clean();
  8474. $info = $this->_getImage($this->_tempimglnk, false);
  8475. if (!$info) { return $this->_imageError($file, $firsttime, 'Error parsing temporary file image object created with GD library to parse PNG image'); }
  8476. imagedestroy($imgplain);
  8477. $imgmask = count($this->images)+1;
  8478. $minfo['cs'] = 'DeviceGray';
  8479. $minfo['i']=$imgmask ;
  8480. $this->images[$tempfile_alpha] = $minfo;
  8481. }
  8482. else {
  8483. $check = @imagepng($imgalpha, $tempfile_alpha);
  8484. if (!$check) { return $this->_imageError($file, $firsttime, 'Failed to create temporary image file ('.$tempfile_alpha.') parsing PNG image with alpha channel ('.$errpng.')'); }
  8485. imagedestroy($imgalpha);
  8486. // extract image without alpha channel
  8487. $imgplain = imagecreatetruecolor($w, $h);
  8488. imagecopy($imgplain, $im, 0, 0, 0, 0, $w, $h);
  8489. // create temp image file
  8490. $check = @imagepng($imgplain, $tempfile);
  8491. if (!$check) { return $this->_imageError($file, $firsttime, 'Failed to create temporary image file ('.$tempfile.') parsing PNG image with alpha channel ('.$errpng.')'); }
  8492. imagedestroy($imgplain);
  8493. // embed mask image
  8494. $minfo = $this->_getImage($tempfile_alpha, false);
  8495. unlink($tempfile_alpha);
  8496. if (!$minfo) { return $this->_imageError($file, $firsttime, 'Error parsing temporary file ('.$tempfile_alpha.') created with GD library to parse PNG image'); }
  8497. $imgmask = count($this->images)+1;
  8498. $minfo['cs'] = 'DeviceGray';
  8499. $minfo['i']=$imgmask ;
  8500. $this->images[$tempfile_alpha] = $minfo;
  8501. // embed image, masked with previously embedded mask
  8502. $info = $this->_getImage($tempfile, false);
  8503. unlink($tempfile);
  8504. if (!$info) { return $this->_imageError($file, $firsttime, 'Error parsing temporary file ('.$tempfile.') created with GD library to parse PNG image'); }
  8505. }
  8506. $info['masked'] = $imgmask;
  8507. if ($ppUx) { $info['set-dpi'] = $ppUx; }
  8508. $info['type']='png';
  8509. if ($firsttime) {
  8510. $info['i']=count($this->images)+1;
  8511. $this->images[$file]=$info;
  8512. }
  8513. return $info;
  8514. }
  8515. else { // No alpha/transparency set
  8516. imagealphablending($im, false);
  8517. imagesavealpha($im, false);
  8518. imageinterlace($im, false);
  8519. if (!is_writable($tempfile)) {
  8520. ob_start();
  8521. $check = @imagepng($im);
  8522. if (!$check) { return $this->_imageError($file, $firsttime, 'Error creating temporary image object whilst using GD library to parse PNG image'); }
  8523. $this->_tempimg = ob_get_contents();
  8524. $this->_tempimglnk = 'var:_tempimg';
  8525. ob_end_clean();
  8526. $info = $this->_getImage($this->_tempimglnk, false);
  8527. if (!$info) { return $this->_imageError($file, $firsttime, 'Error parsing temporary file image object created with GD library to parse PNG image'); }
  8528. imagedestroy($im);
  8529. }
  8530. else {
  8531. $check = @imagepng($im, $tempfile );
  8532. if (!$check) { return $this->_imageError($file, $firsttime, 'Failed to create temporary image file ('.$tempfile.') parsing PNG image ('.$errpng.')'); }
  8533. imagedestroy($im);
  8534. $info = $this->_getImage($tempfile, false) ;
  8535. unlink($tempfile );
  8536. if (!$info) { return $this->_imageError($file, $firsttime, 'Error parsing temporary file ('.$tempfile.') created with GD library to parse PNG image'); }
  8537. }
  8538. if ($ppUx) { $info['set-dpi'] = $ppUx; }
  8539. $info['type']='png';
  8540. if ($firsttime) {
  8541. $info['i']=count($this->images)+1;
  8542. $this->images[$file]=$info;
  8543. }
  8544. return $info;
  8545. }
  8546. }
  8547. }
  8548. else {
  8549. $parms='/DecodeParms <</Predictor 15 /Colors '.($ct==2 ? 3 : 1).' /BitsPerComponent '.$bpc.' /Columns '.$w.'>>';
  8550. //Scan chunks looking for palette, transparency and image data
  8551. $pal='';
  8552. $trns='';
  8553. $pngdata='';
  8554. $p = 33;
  8555. do {
  8556. $n=$this->_fourbytes2int(substr($data,$p,4)); $p += 4;
  8557. $type=substr($data,$p,4); $p += 4;
  8558. if($type=='PLTE') {
  8559. //Read palette
  8560. $pal=substr($data,$p,$n); $p += $n;
  8561. $p += 4;
  8562. }
  8563. elseif($type=='tRNS') {
  8564. //Read transparency info
  8565. $t=substr($data,$p,$n); $p += $n;
  8566. if($ct==0) $trns=array(ord(substr($t,1,1)));
  8567. elseif($ct==2) $trns=array(ord(substr($t,1,1)),ord(substr($t,3,1)),ord(substr($t,5,1)));
  8568. else
  8569. {
  8570. $pos=strpos($t,chr(0));
  8571. if(is_int($pos)) $trns=array($pos);
  8572. }
  8573. $p += 4;
  8574. }
  8575. elseif($type=='IDAT') {
  8576. $pngdata.=substr($data,$p,$n); $p += $n;
  8577. $p += 4;
  8578. }
  8579. elseif($type=='IEND') { break; }
  8580. else if (preg_match('/[a-zA-Z]{4}/',$type)) { $p += $n+4; }
  8581. else { return $this->_imageError($file, $firsttime, 'Error parsing PNG image data'); }
  8582. }
  8583. while($n);
  8584. if (!$pngdata) { return $this->_imageError($file, $firsttime, 'Error parsing PNG image data - no IDAT data found'); }
  8585. if($colspace=='Indexed' and empty($pal)) { return $this->_imageError($file, $firsttime, 'Error parsing PNG image data - missing colour palette'); }
  8586. $info = array('w'=>$w,'h'=>$h,'cs'=>$colspace,'bpc'=>$bpc,'f'=>'FlateDecode','parms'=>$parms,'pal'=>$pal,'trns'=>$trns,'data'=>$pngdata);
  8587. $info['type']='png';
  8588. if ($ppUx) { $info['set-dpi'] = $ppUx; }
  8589. }
  8590. if (!$info) { return $this->_imageError($file, $firsttime, 'Error parsing or converting PNG image'); }
  8591. if ($firsttime) {
  8592. $info['i']=count($this->images)+1;
  8593. $this->images[$file]=$info;
  8594. }
  8595. return $info;
  8596. }
  8597. // GIF
  8598. else if ($type == 'gif') {
  8599. if (function_exists('gd_info')) { $gd = gd_info(); }
  8600. else {$gd = array(); }
  8601. if (isset($gd['GIF Read Support']) && $gd['GIF Read Support']) {
  8602. $im = @imagecreatefromstring($data);
  8603. if ($im) {
  8604. $tempfile = _MPDF_TEMP_PATH.'_tempImgPNG'.RAND(1,10000).'.png';
  8605. imagealphablending($im, false);
  8606. imagesavealpha($im, false);
  8607. imageinterlace($im, false);
  8608. if (!is_writable($tempfile)) {
  8609. ob_start();
  8610. $check = @imagepng($im);
  8611. if (!$check) { return $this->_imageError($file, $firsttime, 'Error creating temporary image object whilst using GD library to parse GIF image'); }
  8612. $this->_tempimg = ob_get_contents();
  8613. $this->_tempimglnk = 'var:_tempimg';
  8614. ob_end_clean();
  8615. $info = $this->_getImage($this->_tempimglnk, false);
  8616. if (!$info) { return $this->_imageError($file, $firsttime, 'Error parsing temporary file image object created with GD library to parse GIF image'); }
  8617. imagedestroy($im);
  8618. }
  8619. else {
  8620. $check = @imagepng($im, $tempfile);
  8621. if (!$check) { return $this->_imageError($file, $firsttime, 'Error creating temporary file ('.$tempfile.') whilst using GD library to parse GIF image'); }
  8622. $info = $this->_getImage($tempfile, false);
  8623. if (!$info) { return $this->_imageError($file, $firsttime, 'Error parsing temporary file ('.$tempfile.') created with GD library to parse GIF image'); }
  8624. imagedestroy($im);
  8625. unlink($tempfile);
  8626. }
  8627. $info['type']='gif';
  8628. if ($firsttime) {
  8629. $info['i']=count($this->images)+1;
  8630. $this->images[$file]=$info;
  8631. }
  8632. return $info;
  8633. }
  8634. else { return $this->_imageError($file, $firsttime, 'Error creating GD image file from GIF image'); }
  8635. }
  8636. if (!class_exists('gif', false)) {
  8637. include_once(_MPDF_PATH.'classes/gif.php');
  8638. }
  8639. $gif=new CGIF();
  8640. $h=0;
  8641. $w=0;
  8642. $gif->loadFile($data, 0);
  8643. if(isset($gif->m_img->m_gih->m_bLocalClr) && $gif->m_img->m_gih->m_bLocalClr) {
  8644. $nColors = $gif->m_img->m_gih->m_nTableSize;
  8645. $pal = $gif->m_img->m_gih->m_colorTable->toString();
  8646. if($bgColor != -1) {
  8647. $bgColor = $gif->m_img->m_gih->m_colorTable->colorIndex($bgColor);
  8648. }
  8649. $colspace='Indexed';
  8650. } elseif(isset($gif->m_gfh->m_bGlobalClr) && $gif->m_gfh->m_bGlobalClr) {
  8651. $nColors = $gif->m_gfh->m_nTableSize;
  8652. $pal = $gif->m_gfh->m_colorTable->toString();
  8653. if((isset($bgColor)) and $bgColor != -1) {
  8654. $bgColor = $gif->m_gfh->m_colorTable->colorIndex($bgColor);
  8655. }
  8656. $colspace='Indexed';
  8657. } else {
  8658. $nColors = 0;
  8659. $bgColor = -1;
  8660. $colspace='DeviceGray';
  8661. $pal='';
  8662. }
  8663. $trns='';
  8664. if(isset($gif->m_img->m_bTrans) && $gif->m_img->m_bTrans && ($nColors > 0)) {
  8665. $trns=array($gif->m_img->m_nTrans);
  8666. }
  8667. $gifdata=$gif->m_img->m_data;
  8668. $w=$gif->m_gfh->m_nWidth;
  8669. $h=$gif->m_gfh->m_nHeight;
  8670. $gif->ClearData();
  8671. if($colspace=='Indexed' and empty($pal)) {
  8672. return $this->_imageError($file, $firsttime, 'Error parsing GIF image - missing colour palette');
  8673. }
  8674. if ($this->compress) {
  8675. $gifdata=gzcompress($gifdata);
  8676. $info = array( 'w'=>$w, 'h'=>$h, 'cs'=>$colspace, 'bpc'=>8, 'f'=>'FlateDecode', 'pal'=>$pal, 'trns'=>$trns, 'data'=>$gifdata);
  8677. }
  8678. else {
  8679. $info = array( 'w'=>$w, 'h'=>$h, 'cs'=>$colspace, 'bpc'=>8, 'pal'=>$pal, 'trns'=>$trns, 'data'=>$gifdata);
  8680. }
  8681. $info['type']='gif';
  8682. if ($firsttime) {
  8683. $info['i']=count($this->images)+1;
  8684. $this->images[$file]=$info;
  8685. }
  8686. return $info;
  8687. }
  8688. /*-- IMAGES-BMP --*/
  8689. // BMP (Windows Bitmap)
  8690. else if ($type == 'bmp') {
  8691. if (!class_exists('bmp', false)) { include(_MPDF_PATH.'classes/bmp.php'); }
  8692. if (empty($this->bmp)) { $this->bmp = new bmp($this); }
  8693. $info = $this->bmp->_getBMPimage($data, $file);
  8694. if (isset($info['error'])) {
  8695. return $this->_imageError($file, $firsttime, $info['error']);
  8696. }
  8697. if ($firsttime) {
  8698. $info['i']=count($this->images)+1;
  8699. $this->images[$file]=$info;
  8700. }
  8701. return $info;
  8702. }
  8703. /*-- END IMAGES-BMP --*/
  8704. /*-- IMAGES-WMF --*/
  8705. // WMF
  8706. else if ($type == 'wmf') {
  8707. if (!class_exists('wmf', false)) { include(_MPDF_PATH.'classes/wmf.php'); }
  8708. if (empty($this->wmf)) { $this->wmf = new wmf($this); }
  8709. $wmfres = $this->wmf->_getWMFimage($data);
  8710. if ($wmfres[0]==0) {
  8711. if ($wmfres[1]) { return $this->_imageError($file, $firsttime, $wmfres[1]); }
  8712. return $this->_imageError($file, $firsttime, 'Error parsing WMF image');
  8713. }
  8714. $info = array('x'=>$wmfres[2][0],'y'=>$wmfres[2][1],'w'=>$wmfres[3][0],'h'=>$wmfres[3][1],'data'=>$wmfres[1]);
  8715. $info['i']=count($this->formobjects)+1;
  8716. $info['type']='wmf';
  8717. $this->formobjects[$file]=$info;
  8718. return $info;
  8719. }
  8720. /*-- END IMAGES-WMF --*/
  8721. // UNKNOWN TYPE - try GD imagecreatefromstring
  8722. else {
  8723. if (function_exists('gd_info')) { $gd = gd_info(); }
  8724. else {$gd = array(); }
  8725. if (isset($gd['PNG Support']) && $gd['PNG Support']) {
  8726. $im = @imagecreatefromstring($data);
  8727. if (!$im) { return $this->_imageError($file, $firsttime, 'Error parsing image file - image type not recognised, and not supported by GD imagecreate'); }
  8728. $tempfile = _MPDF_TEMP_PATH.'_tempImgPNG'.RAND(1,10000).'.png';
  8729. imagealphablending($im, false);
  8730. imagesavealpha($im, false);
  8731. imageinterlace($im, false);
  8732. $check = @imagepng($im, $tempfile);
  8733. if (!$check) { return $this->_imageError($file, $firsttime, 'Error creating temporary file ('.$tempfile.') whilst using GD library to parse unknown image type'); }
  8734. $info = $this->_getImage($tempfile, false);
  8735. imagedestroy($im);
  8736. unlink($tempfile);
  8737. if (!$info) { return $this->_imageError($file, $firsttime, 'Error parsing temporary file ('.$tempfile.') created with GD library to parse unknown image type'); }
  8738. $info['type']='png';
  8739. if ($firsttime) {
  8740. $info['i']=count($this->images)+1;
  8741. $this->images[$file]=$info;
  8742. }
  8743. return $info;
  8744. }
  8745. }
  8746. return $this->_imageError($file, $firsttime, 'Error parsing image file - image type not recognised');
  8747. }
  8748. //==============================================================
  8749. function _convImage(&$data, $colspace, $targetcs, $w, $h, $dpi, $mask) {
  8750. if ($this->PDFA || $this->PDFX) { $mask=false; }
  8751. $im = @imagecreatefromstring($data);
  8752. $info = array();
  8753. if ($im) {
  8754. $imgdata = '';
  8755. $mimgdata = '';
  8756. $minfo = array();
  8757. //Read transparency info
  8758. $trns=array();
  8759. $trnsrgb = false;
  8760. if (!$this->PDFA && !$this->PDFX) {
  8761. $p = strpos($data,'tRNS');
  8762. if ($p) {
  8763. $n=$this->_fourbytes2int(substr($data,($p-4),4));
  8764. $t = substr($data,($p+4),$n);
  8765. if ($colspace=='DeviceGray') {
  8766. $trns=array(ord(substr($t,1,1)));
  8767. $trnsrgb = array($trns[0],$trns[0],$trns[0]);
  8768. }
  8769. else if ($colspace=='DeviceRGB') {
  8770. $trns=array(ord(substr($t,1,1)),ord(substr($t,3,1)),ord(substr($t,5,1)));
  8771. $trnsrgb = $trns;
  8772. if ($targetcs=='DeviceCMYK') {
  8773. $col = $this->rgb2cmyk(array(3,$trns[0],$trns[1],$trns[2]));
  8774. $c1 = intval($col[1]*2.55);
  8775. $c2 = intval($col[2]*2.55);
  8776. $c3 = intval($col[3]*2.55);
  8777. $c4 = intval($col[4]*2.55);
  8778. $trns = array($c1,$c2,$c3,$c4);
  8779. }
  8780. else if ($targetcs=='DeviceGray') {
  8781. $c = intval(($trns[0] * .21) + ($trns[1] * .71) + ($trns[2] * .07));
  8782. $trns = array($c);
  8783. }
  8784. }
  8785. else { // Indexed
  8786. $pos = strpos($t,chr(0));
  8787. if (is_int($pos)) {
  8788. $pal = imagecolorsforindex($im, $pos);
  8789. $r = $pal['red'];
  8790. $g = $pal['green'];
  8791. $b = $pal['blue'];
  8792. $trns=array($r,$g,$b); // ****
  8793. $trnsrgb = $trns;
  8794. if ($targetcs=='DeviceCMYK') {
  8795. $col = $this->rgb2cmyk(array(3,$r,$g,$b));
  8796. $c1 = intval($col[1]*2.55);
  8797. $c2 = intval($col[2]*2.55);
  8798. $c3 = intval($col[3]*2.55);
  8799. $c4 = intval($col[4]*2.55);
  8800. $trns = array($c1,$c2,$c3,$c4);
  8801. }
  8802. else if ($targetcs=='DeviceGray') {
  8803. $c = intval(($r * .21) + ($g * .71) + ($b * .07));
  8804. $trns = array($c);
  8805. }
  8806. }
  8807. }
  8808. }
  8809. }
  8810. for ($i = 0; $i < $h; $i++) {
  8811. for ($j = 0; $j < $w; $j++) {
  8812. $rgb = imagecolorat($im, $j, $i);
  8813. $r = ($rgb >> 16) & 0xFF;
  8814. $g = ($rgb >> 8) & 0xFF;
  8815. $b = $rgb & 0xFF;
  8816. if ($colspace=='Indexed') {
  8817. $pal = imagecolorsforindex($im, $rgb);
  8818. $r = $pal['red'];
  8819. $g = $pal['green'];
  8820. $b = $pal['blue'];
  8821. }
  8822. if ($targetcs=='DeviceCMYK') {
  8823. $col = $this->rgb2cmyk(array(3,$r,$g,$b));
  8824. $c1 = intval($col[1]*2.55);
  8825. $c2 = intval($col[2]*2.55);
  8826. $c3 = intval($col[3]*2.55);
  8827. $c4 = intval($col[4]*2.55);
  8828. if ($trnsrgb) {
  8829. // original pixel was not set as transparent but processed color does match
  8830. if ($trnsrgb!=array($r,$g,$b) && $trns==array($c1,$c2,$c3,$c4)) {
  8831. if ($c4==0) { $c4=1; } else { $c4--; }
  8832. }
  8833. }
  8834. $imgdata .= chr($c1).chr($c2).chr($c3).chr($c4);
  8835. }
  8836. else if ($targetcs=='DeviceGray') {
  8837. $c = intval(($r * .21) + ($g * .71) + ($b * .07));
  8838. if ($trnsrgb) {
  8839. // original pixel was not set as transparent but processed color does match
  8840. if ($trnsrgb!=array($r,$g,$b) && $trns==array($c)) {
  8841. if ($c==0) { $c=1; } else { $c--; }
  8842. }
  8843. }
  8844. $imgdata .= chr($c);
  8845. }
  8846. else if ($targetcs=='DeviceRGB') {
  8847. $imgdata .= chr($r).chr($g).chr($b);
  8848. }
  8849. if ($mask) {
  8850. $col = imagecolorsforindex($im, $rgb);
  8851. $gammacorr = 2.2; // gamma correction
  8852. $gamma = intval((pow((((127 - $col['alpha']) * 255 / 127) / 255), $gammacorr) * 255));
  8853. $mimgdata .= chr($gamma);
  8854. }
  8855. }
  8856. }
  8857. if ($targetcs=='DeviceGray') { $ncols = 1; }
  8858. else if ($targetcs=='DeviceRGB') { $ncols = 3; }
  8859. else if ($targetcs=='DeviceCMYK') { $ncols = 4; }
  8860. $imgdata = gzcompress($imgdata);
  8861. $info = array('w'=>$w,'h'=>$h,'cs'=>$targetcs,'bpc'=>8,'f'=>'FlateDecode','data'=>$imgdata, 'type'=>'png',
  8862. 'parms'=>'/DecodeParms <</Colors '.$ncols.' /BitsPerComponent 8 /Columns '.$w.'>>');
  8863. if ($dpi) { $info['set-dpi'] = $dpi; }
  8864. if ($mask) {
  8865. $mimgdata = gzcompress($mimgdata);
  8866. $minfo = array('w'=>$w,'h'=>$h,'cs'=>'DeviceGray','bpc'=>8,'f'=>'FlateDecode','data'=>$mimgdata, 'type'=>'png',
  8867. 'parms'=>'/DecodeParms <</Colors '.$ncols.' /BitsPerComponent 8 /Columns '.$w.'>>');
  8868. if ($dpi) { $minfo['set-dpi'] = $dpi; }
  8869. $tempfile = '_tempImgPNG'.RAND(1,10000).'.png';
  8870. $imgmask = count($this->images)+1;
  8871. $minfo['i']=$imgmask ;
  8872. $this->images[$tempfile] = $minfo;
  8873. $info['masked'] = $imgmask;
  8874. }
  8875. else if ($trns) { $info['trns'] = $trns; }
  8876. imagedestroy($im);
  8877. }
  8878. return $info;
  8879. }
  8880. function _fourbytes2int($s) {
  8881. //Read a 4-byte integer from string
  8882. return (ord($s[0])<<24) + (ord($s[1])<<16) + (ord($s[2])<<8) + ord($s[3]);
  8883. }
  8884. function _twobytes2int($s) {
  8885. //Read a 2-byte integer from string
  8886. return (ord(substr($s, 0, 1))<<8) + ord(substr($s, 1, 1));
  8887. }
  8888. function _jpgHeaderFromString(&$data) {
  8889. $p = 4;
  8890. $p += $this->_twobytes2int(substr($data, $p, 2)); // Length of initial marker block
  8891. $marker = substr($data, $p, 2);
  8892. while($marker != chr(255).chr(192) && $marker != chr(255).chr(194) && $p<strlen($data)) {
  8893. // Start of frame marker (FFC0) or (FFC2) mPDF 4.4.004
  8894. $p += ($this->_twobytes2int(substr($data, $p+2, 2))) + 2; // Length of marker block
  8895. $marker = substr($data, $p, 2);
  8896. }
  8897. if ($marker != chr(255).chr(192) && $marker != chr(255).chr(194)) { return false; }
  8898. return substr($data, $p+2, 10);
  8899. }
  8900. function _jpgDataFromHeader($hdr) {
  8901. $bpc = ord(substr($hdr, 2, 1));
  8902. if (!$bpc) { $bpc = 8; }
  8903. $h = $this->_twobytes2int(substr($hdr, 3, 2));
  8904. $w = $this->_twobytes2int(substr($hdr, 5, 2));
  8905. $channels = ord(substr($hdr, 7, 1));
  8906. if ($channels==3) { $colspace='DeviceRGB'; }
  8907. elseif($channels==4) { $colspace='DeviceCMYK'; }
  8908. else { $colspace='DeviceGray'; }
  8909. return array($w, $h, $colspace, $bpc);
  8910. }
  8911. function file_get_contents_by_curl($url, &$data) {
  8912. $timeout = 5;
  8913. $ch = curl_init($url);
  8914. curl_setopt($ch, CURLOPT_HEADER, 0);
  8915. curl_setopt($ch, CURLOPT_NOBODY, 0);
  8916. curl_setopt ( $ch , CURLOPT_RETURNTRANSFER , 1 );
  8917. curl_setopt ( $ch , CURLOPT_CONNECTTIMEOUT , $timeout );
  8918. $data = curl_exec($ch);
  8919. curl_close($ch);
  8920. }
  8921. function file_get_contents_by_socket($url, &$data) {
  8922. $timeout = 1;
  8923. $p = parse_url($url);
  8924. $file = $p['path'];
  8925. if ($p['query']) { $file .= '?'.$p['query']; }
  8926. if(!($fh = @fsockopen($p['host'], 80, $errno, $errstr, $timeout))) { return false; }
  8927. $getstring =
  8928. "GET ".$file." HTTP/1.0 \r\n" .
  8929. "Host: ".$p['host']." \r\n" .
  8930. "Connection: close\r\n\r\n";
  8931. fwrite($fh, $getstring);
  8932. // Get rid of HTTP header
  8933. $s = fgets($fh, 1024);
  8934. if (!$s) { return false; }
  8935. $httpheader .= $s;
  8936. while (!feof($fh)) {
  8937. $s = fgets($fh, 1024);
  8938. if ( $s == "\r\n" ) { break; }
  8939. }
  8940. $data = '';
  8941. while (!feof($fh)) {
  8942. $data .= fgets($fh, 1024);
  8943. }
  8944. fclose($fh);
  8945. }
  8946. //==============================================================
  8947. function _imageTypeFromString(&$data) {
  8948. $type = '';
  8949. if (substr($data, 6, 4)== 'JFIF' || substr($data, 6, 4)== 'Exif') {
  8950. $type = 'jpeg';
  8951. }
  8952. else if (substr($data, 0, 6)== "GIF87a" || substr($data, 0, 6)== "GIF89a") {
  8953. $type = 'gif';
  8954. }
  8955. else if (substr($data, 0, 8)== chr(137).'PNG'.chr(13).chr(10).chr(26).chr(10)) {
  8956. $type = 'png';
  8957. }
  8958. /*-- IMAGES-WMF --*/
  8959. else if (substr($data, 0, 4)== chr(215).chr(205).chr(198).chr(154)) {
  8960. $type = 'wmf';
  8961. }
  8962. /*-- END IMAGES-WMF --*/
  8963. else if (preg_match('/<svg.*<\/svg>/is',$data)) {
  8964. $type = 'svg';
  8965. }
  8966. // BMP images
  8967. else if (substr($data, 0, 2)== "BM") {
  8968. $type = 'bmp';
  8969. }
  8970. return $type;
  8971. }
  8972. //==============================================================
  8973. // Moved outside WMF as also needed for SVG
  8974. function _putformobjects() {
  8975. reset($this->formobjects);
  8976. while(list($file,$info)=each($this->formobjects)) {
  8977. $this->_newobj();
  8978. $this->formobjects[$file]['n']=$this->n;
  8979. $this->_out('<</Type /XObject');
  8980. $this->_out('/Subtype /Form');
  8981. $this->_out('/Group '.($this->n+1).' 0 R');
  8982. $this->_out('/BBox ['.$info['x'].' '.$info['y'].' '.($info['w']+$info['x']).' '.($info['h']+$info['y']).']');
  8983. if ($this->compress)
  8984. $this->_out('/Filter /FlateDecode');
  8985. $data=($this->compress) ? gzcompress($info['data']) : $info['data'];
  8986. $this->_out('/Length '.strlen($data).'>>');
  8987. $this->_putstream($data);
  8988. unset($this->formobjects[$file]['data']);
  8989. $this->_out('endobj');
  8990. // Required for SVG transparency (opacity) to work
  8991. $this->_newobj();
  8992. $this->_out('<</Type /Group');
  8993. $this->_out('/S /Transparency');
  8994. $this->_out('>>');
  8995. $this->_out('endobj');
  8996. }
  8997. }
  8998. function _freadint($f)
  8999. {
  9000. //Read a 4-byte integer from file
  9001. $i=ord(fread($f,1))<<24;
  9002. $i+=ord(fread($f,1))<<16;
  9003. $i+=ord(fread($f,1))<<8;
  9004. $i+=ord(fread($f,1));
  9005. return $i;
  9006. }
  9007. function _UTF16BEtextstring($s) {
  9008. $s = $this->UTF8ToUTF16BE($s, true);
  9009. /*-- ENCRYPTION --*/
  9010. if ($this->encrypted) {
  9011. $s = $this->_RC4($this->_objectkey($this->_current_obj_id), $s);
  9012. }
  9013. /*-- END ENCRYPTION --*/
  9014. return '('. $this->_escape($s).')';
  9015. }
  9016. function _textstring($s) {
  9017. /*-- ENCRYPTION --*/
  9018. if ($this->encrypted) {
  9019. $s = $this->_RC4($this->_objectkey($this->_current_obj_id), $s);
  9020. }
  9021. /*-- END ENCRYPTION --*/
  9022. return '('. $this->_escape($s).')';
  9023. }
  9024. function _escape($s)
  9025. {
  9026. // the chr(13) substitution fixes the Bugs item #1421290.
  9027. return strtr($s, array(')' => '\\)', '(' => '\\(', '\\' => '\\\\', chr(13) => '\r'));
  9028. }
  9029. function _putstream($s) {
  9030. /*-- ENCRYPTION --*/
  9031. if ($this->encrypted) {
  9032. $s = $this->_RC4($this->_objectkey($this->_current_obj_id), $s);
  9033. }
  9034. /*-- END ENCRYPTION --*/
  9035. $this->_out('stream');
  9036. $this->_out($s);
  9037. $this->_out('endstream');
  9038. }
  9039. function _out($s,$ln=true) {
  9040. if($this->state==2) {
  9041. if ($this->bufferoutput) {
  9042. $this->headerbuffer.= $s."\n";
  9043. }
  9044. /*-- COLUMNS --*/
  9045. else if (($this->ColActive) && !$this->processingHeader && !$this->processingFooter) {
  9046. // Captures everything in buffer for columns; Almost everything is sent from fn. Cell() except:
  9047. // Images sent from Image() or
  9048. // later sent as _out($textto) in printbuffer
  9049. // Line()
  9050. if (preg_match('/q \d+\.\d\d+ 0 0 (\d+\.\d\d+) \d+\.\d\d+ \d+\.\d\d+ cm \/(I|FO)\d+ Do Q/',$s,$m)) { // Image data
  9051. $h = ($m[1]/_MPDFK);
  9052. // Update/overwrite the lowest bottom of printing y value for a column
  9053. $this->ColDetails[$this->CurrCol]['bottom_margin'] = $this->y+$h;
  9054. }
  9055. /*-- TABLES --*/
  9056. else if (preg_match('/\d+\.\d\d+ \d+\.\d\d+ \d+\.\d\d+ ([\-]{0,1}\d+\.\d\d+) re/',$s,$m) && $this->tableLevel>0) { // Rect in table
  9057. $h = ($m[1]/_MPDFK);
  9058. // Update/overwrite the lowest bottom of printing y value for a column
  9059. $this->ColDetails[$this->CurrCol]['bottom_margin'] = max($this->ColDetails[$this->CurrCol]['bottom_margin'],($this->y+$h));
  9060. }
  9061. /*-- END TABLES --*/
  9062. else { // Td Text Set in Cell()
  9063. if (isset($this->ColDetails[$this->CurrCol]['bottom_margin'])) { $h = $this->ColDetails[$this->CurrCol]['bottom_margin'] - $this->y; }
  9064. else { $h = 0; }
  9065. }
  9066. if ($h < 0) { $h = -$h; }
  9067. $this->columnbuffer[] = array(
  9068. 's' => $s, // Text string to output
  9069. 'col' => $this->CurrCol, // Column when printed
  9070. 'x' => $this->x, // x when printed
  9071. 'y' => $this->y, // this->y when printed (after column break)
  9072. 'h' => $h // actual y at bottom when printed = y+h
  9073. );
  9074. }
  9075. /*-- END COLUMNS --*/
  9076. /*-- TABLES --*/
  9077. else if ($this->table_rotate && !$this->processingHeader && !$this->processingFooter) {
  9078. // Captures eveything in buffer for rotated tables;
  9079. $this->tablebuffer .= $s . "\n";
  9080. }
  9081. /*-- END TABLES --*/
  9082. else if ($this->kwt && !$this->processingHeader && !$this->processingFooter) {
  9083. // Captures eveything in buffer for keep-with-table (h1-6);
  9084. $this->kwt_buffer[] = array(
  9085. 's' => $s, // Text string to output
  9086. 'x' => $this->x, // x when printed
  9087. 'y' => $this->y, // y when printed
  9088. );
  9089. }
  9090. else if (($this->keep_block_together) && !$this->processingHeader && !$this->processingFooter) {
  9091. if (!isset($this->ktBlock[$this->page]['bottom_margin'])) {
  9092. $this->ktBlock[$this->page]['bottom_margin'] = $this->y;
  9093. }
  9094. // Captures eveything in buffer;
  9095. if (preg_match('/q \d+\.\d\d+ 0 0 (\d+\.\d\d+) \d+\.\d\d+ \d+\.\d\d+ cm \/(I|FO)\d+ Do Q/',$s,$m)) { // Image data
  9096. $h = ($m[1]/_MPDFK);
  9097. // Update/overwrite the lowest bottom of printing y value for Keep together block
  9098. $this->ktBlock[$this->page]['bottom_margin'] = $this->y+$h;
  9099. }
  9100. else { // Td Text Set in Cell()
  9101. if (isset($this->ktBlock[$this->page]['bottom_margin'])) { $h = $this->ktBlock[$this->page]['bottom_margin'] - $this->y; }
  9102. else { $h = 0; }
  9103. }
  9104. if ($h < 0) { $h = -$h; }
  9105. $this->divbuffer[] = array(
  9106. 'page' => $this->page,
  9107. 's' => $s, // Text string to output
  9108. 'x' => $this->x, // x when printed
  9109. 'y' => $this->y, // y when printed (after column break)
  9110. 'h' => $h // actual y at bottom when printed = y+h
  9111. );
  9112. }
  9113. else {
  9114. $this->pages[$this->page] .= $s.($ln == true ? "\n" : '');
  9115. }
  9116. }
  9117. else {
  9118. $this->buffer .= $s.($ln == true ? "\n" : '');
  9119. }
  9120. }
  9121. /*-- WATERMARK --*/
  9122. // add a watermark
  9123. function watermark( $texte, $angle=45, $fontsize=96, $alpha=0.2 ) {
  9124. if ($this->PDFA || $this->PDFX) { $this->Error('PDFA and PDFX do not permit transparency, so mPDF does not allow Watermarks!'); }
  9125. if (!$this->watermark_font) { $this->watermark_font = $this->default_font; }
  9126. $this->SetFont( $this->watermark_font, "B", $fontsize, false ); // Don't output
  9127. $texte= $this->purify_utf8_text($texte);
  9128. if ($this->text_input_as_HTML) {
  9129. $texte= $this->all_entities_to_utf8($texte);
  9130. }
  9131. if ($this->usingCoreFont) { $texte = mb_convert_encoding($texte,$this->mb_enc,'UTF-8'); }
  9132. // DIRECTIONALITY
  9133. $this->magic_reverse_dir($texte, true, $this->directionality); // *RTL*
  9134. // Font-specific ligature substitution for Indic fonts
  9135. if (isset($this->CurrentFont['indic']) && $this->CurrentFont['indic']) $this->ConvertIndic($texte); // *INDIC*
  9136. $this->SetAlpha($alpha);
  9137. $this->SetTColor($this->ConvertColor(0));
  9138. $szfont = $fontsize;
  9139. $loop = 0;
  9140. $maxlen = (min($this->w,$this->h) ); // sets max length of text as 7/8 width/height of page
  9141. while ( $loop == 0 )
  9142. {
  9143. $this->SetFont( $this->watermark_font, "B", $szfont, false ); // Don't output
  9144. $offset = ((sin(deg2rad($angle))) * ($szfont/_MPDFK));
  9145. $strlen = $this->GetStringWidth($texte);
  9146. if ( $strlen > $maxlen - $offset )
  9147. $szfont --;
  9148. else
  9149. $loop ++;
  9150. }
  9151. $this->SetFont( $this->watermark_font, "B", $szfont-0.1, true, true); // Output The -0.1 is because SetFont above is not written to PDF
  9152. // Repeating it will not output anything as mPDF thinks it is set
  9153. $adj = ((cos(deg2rad($angle))) * ($strlen/2));
  9154. $opp = ((sin(deg2rad($angle))) * ($strlen/2));
  9155. $wx = ($this->w/2) - $adj + $offset/3;
  9156. $wy = ($this->h/2) + $opp;
  9157. $this->Rotate($angle,$wx,$wy);
  9158. $this->Text($wx,$wy,$texte);
  9159. $this->Rotate(0);
  9160. $this->SetTColor($this->ConvertColor(0));
  9161. $this->SetAlpha(1);
  9162. }
  9163. function watermarkImg( $src, $alpha=0.2 ) {
  9164. if ($this->PDFA || $this->PDFX) { $this->Error('PDFA and PDFX do not permit transparency, so mPDF does not allow Watermarks!'); }
  9165. if ($this->watermarkImgBehind) { $this->watermarkImgAlpha = $this->SetAlpha($alpha, 'Normal', true); }
  9166. else { $this->SetAlpha($alpha, $this->watermarkImgAlphaBlend); }
  9167. $this->Image($src,0,0,0,0,'','', true, true, true);
  9168. if (!$this->watermarkImgBehind) { $this->SetAlpha(1); }
  9169. }
  9170. /*-- END WATERMARK --*/
  9171. function Rotate($angle,$x=-1,$y=-1)
  9172. {
  9173. if($x==-1)
  9174. $x=$this->x;
  9175. if($y==-1)
  9176. $y=$this->y;
  9177. if($this->angle!=0)
  9178. $this->_out('Q');
  9179. $this->angle=$angle;
  9180. if($angle!=0)
  9181. {
  9182. $angle*=M_PI/180;
  9183. $c=cos($angle);
  9184. $s=sin($angle);
  9185. $cx=$x*_MPDFK;
  9186. $cy=($this->h-$y)*_MPDFK;
  9187. $this->_out(sprintf('q %.5F %.5F %.5F %.5F %.3F %.3F cm 1 0 0 1 %.3F %.3F cm',$c,$s,-$s,$c,$cx,$cy,-$cx,-$cy));
  9188. }
  9189. }
  9190. function CircularText($x, $y, $r, $text, $align='top', $fontfamily='', $fontsize=0, $fontstyle='', $kerning=120, $fontwidth=100, $divider) { // mPDF 5.5.23
  9191. if (!class_exists('directw', false)) { include(_MPDF_PATH.'classes/directw.php'); }
  9192. if (empty($this->directw)) { $this->directw = new directw($this); }
  9193. $this->directw->CircularText($x, $y, $r, $text, $align, $fontfamily, $fontsize, $fontstyle, $kerning, $fontwidth, $divider); // mPDF 5.5.23
  9194. }
  9195. // From Invoice
  9196. function RoundedRect($x, $y, $w, $h, $r, $style = '')
  9197. {
  9198. $hp = $this->h;
  9199. if($style=='F')
  9200. $op='f';
  9201. elseif($style=='FD' or $style=='DF')
  9202. $op='B';
  9203. else
  9204. $op='S';
  9205. $MyArc = 4/3 * (sqrt(2) - 1);
  9206. $this->_out(sprintf('%.3F %.3F m',($x+$r)*_MPDFK,($hp-$y)*_MPDFK ));
  9207. $xc = $x+$w-$r ;
  9208. $yc = $y+$r;
  9209. $this->_out(sprintf('%.3F %.3F l', $xc*_MPDFK,($hp-$y)*_MPDFK ));
  9210. $this->_Arc($xc + $r*$MyArc, $yc - $r, $xc + $r, $yc - $r*$MyArc, $xc + $r, $yc);
  9211. $xc = $x+$w-$r ;
  9212. $yc = $y+$h-$r;
  9213. $this->_out(sprintf('%.3F %.3F l',($x+$w)*_MPDFK,($hp-$yc)*_MPDFK));
  9214. $this->_Arc($xc + $r, $yc + $r*$MyArc, $xc + $r*$MyArc, $yc + $r, $xc, $yc + $r);
  9215. $xc = $x+$r ;
  9216. $yc = $y+$h-$r;
  9217. $this->_out(sprintf('%.3F %.3F l',$xc*_MPDFK,($hp-($y+$h))*_MPDFK));
  9218. $this->_Arc($xc - $r*$MyArc, $yc + $r, $xc - $r, $yc + $r*$MyArc, $xc - $r, $yc);
  9219. $xc = $x+$r ;
  9220. $yc = $y+$r;
  9221. $this->_out(sprintf('%.3F %.3F l',($x)*_MPDFK,($hp-$yc)*_MPDFK ));
  9222. $this->_Arc($xc - $r, $yc - $r*$MyArc, $xc - $r*$MyArc, $yc - $r, $xc, $yc - $r);
  9223. $this->_out($op);
  9224. }
  9225. function _Arc($x1, $y1, $x2, $y2, $x3, $y3)
  9226. {
  9227. $h = $this->h;
  9228. $this->_out(sprintf('%.3F %.3F %.3F %.3F %.3F %.3F c ', $x1*_MPDFK, ($h-$y1)*_MPDFK,
  9229. $x2*_MPDFK, ($h-$y2)*_MPDFK, $x3*_MPDFK, ($h-$y3)*_MPDFK));
  9230. }
  9231. //====================================================
  9232. /*-- DIRECTW --*/
  9233. function Shaded_box( $text,$font='',$fontstyle='B',$szfont='',$width='70%',$style='DF',$radius=2.5,$fill='#FFFFFF',$color='#000000',$pad=2 ) {
  9234. // F (shading - no line),S (line, no shading),DF (both)
  9235. if (!class_exists('directw', false)) { include(_MPDF_PATH.'classes/directw.php'); }
  9236. if (empty($this->directw)) { $this->directw = new directw($this); }
  9237. $this->directw->Shaded_box( $text,$font,$fontstyle,$szfont,$width,$style,$radius,$fill,$color,$pad);
  9238. }
  9239. /*-- END DIRECTW --*/
  9240. function UTF8StringToArray($str, $addSubset=true) {
  9241. $out = array();
  9242. $len = strlen($str);
  9243. for ($i = 0; $i < $len; $i++) {
  9244. $uni = -1;
  9245. $h = ord($str[$i]);
  9246. if ( $h <= 0x7F )
  9247. $uni = $h;
  9248. elseif ( $h >= 0xC2 ) {
  9249. if ( ($h <= 0xDF) && ($i < $len -1) )
  9250. $uni = ($h & 0x1F) << 6 | (ord($str[++$i]) & 0x3F);
  9251. elseif ( ($h <= 0xEF) && ($i < $len -2) )
  9252. $uni = ($h & 0x0F) << 12 | (ord($str[++$i]) & 0x3F) << 6 | (ord($str[++$i]) & 0x3F);
  9253. elseif ( ($h <= 0xF4) && ($i < $len -3) )
  9254. $uni = ($h & 0x0F) << 18 | (ord($str[++$i]) & 0x3F) << 12 | (ord($str[++$i]) & 0x3F) << 6 | (ord($str[++$i]) & 0x3F);
  9255. }
  9256. if ($uni >= 0) {
  9257. $out[] = $uni;
  9258. if ($addSubset && isset($this->CurrentFont['subset'])) {
  9259. $this->CurrentFont['subset'][$uni] = $uni;
  9260. }
  9261. }
  9262. }
  9263. return $out;
  9264. }
  9265. //Convert utf-8 string to <HHHHHH> for Font Subsets
  9266. function UTF8toSubset($str) {
  9267. $ret = '<';
  9268. $str = preg_replace('/'.preg_quote($this->aliasNbPg,'/').'/', chr(7), $str );
  9269. $str = preg_replace('/'.preg_quote($this->aliasNbPgGp,'/').'/', chr(8), $str );
  9270. $unicode = $this->UTF8StringToArray($str);
  9271. $orig_fid = $this->CurrentFont['subsetfontids'][0];
  9272. $last_fid = $this->CurrentFont['subsetfontids'][0];
  9273. foreach($unicode as $c) {
  9274. if ($c == 7 || $c == 8) {
  9275. if ($orig_fid != $last_fid) {
  9276. $ret .= '> Tj /F'.$orig_fid.' '.$this->FontSizePt.' Tf <';
  9277. $last_fid = $orig_fid;
  9278. }
  9279. if ($c == 7) { $ret .= $this->aliasNbPgHex; }
  9280. else { $ret .= $this->aliasNbPgGpHex; }
  9281. continue;
  9282. }
  9283. for ($i=0; $i<99; $i++) {
  9284. // return c as decimal char
  9285. $init = array_search($c, $this->CurrentFont['subsets'][$i]);
  9286. if ($init!==false) {
  9287. if ($this->CurrentFont['subsetfontids'][$i] != $last_fid) {
  9288. $ret .= '> Tj /F'.$this->CurrentFont['subsetfontids'][$i].' '.$this->FontSizePt.' Tf <';
  9289. $last_fid = $this->CurrentFont['subsetfontids'][$i];
  9290. }
  9291. $ret .= sprintf("%02s", strtoupper(dechex($init)));
  9292. break;
  9293. }
  9294. // TrueType embedded SUBSETS
  9295. else if (count($this->CurrentFont['subsets'][$i]) < 255) {
  9296. $n = count($this->CurrentFont['subsets'][$i]);
  9297. $this->CurrentFont['subsets'][$i][$n] = $c;
  9298. if ($this->CurrentFont['subsetfontids'][$i] != $last_fid) {
  9299. $ret .= '> Tj /F'.$this->CurrentFont['subsetfontids'][$i].' '.$this->FontSizePt.' Tf <';
  9300. $last_fid = $this->CurrentFont['subsetfontids'][$i];
  9301. }
  9302. $ret .= sprintf("%02s", strtoupper(dechex($n)));
  9303. break;
  9304. }
  9305. else if (!isset($this->CurrentFont['subsets'][($i+1)])) {
  9306. // TrueType embedded SUBSETS
  9307. $this->CurrentFont['subsets'][($i+1)] = array(0=>0);
  9308. $new_fid = count($this->fonts)+$this->extraFontSubsets+1;
  9309. $this->CurrentFont['subsetfontids'][($i+1)] = $new_fid;
  9310. $this->extraFontSubsets++;
  9311. }
  9312. }
  9313. }
  9314. $ret .= '>';
  9315. if ($last_fid != $orig_fid) {
  9316. $ret .= ' Tj /F'.$orig_fid.' '.$this->FontSizePt.' Tf <> ';
  9317. }
  9318. return $ret;
  9319. }
  9320. // Converts UTF-8 strings to UTF16-BE.
  9321. function UTF8ToUTF16BE($str, $setbom=true) {
  9322. if ($this->checkSIP && preg_match("/([\x{20000}-\x{2FFFF}])/u", $str)) {
  9323. if (!in_array($this->currentfontfamily, array('gb','big5','sjis','uhc','gbB','big5B','sjisB','uhcB','gbI','big5I','sjisI','uhcI',
  9324. 'gbBI','big5BI','sjisBI','uhcBI'))) {
  9325. $str = preg_replace("/[\x{20000}-\x{2FFFF}]/u", chr(0), $str);
  9326. }
  9327. }
  9328. if ($this->checkSMP && preg_match("/([\x{10000}-\x{1FFFF}])/u", $str )) {
  9329. $str = preg_replace("/[\x{10000}-\x{1FFFF}]/u", chr(0), $str );
  9330. }
  9331. $outstr = ""; // string to be returned
  9332. if ($setbom) {
  9333. $outstr .= "\xFE\xFF"; // Byte Order Mark (BOM)
  9334. }
  9335. $outstr .= mb_convert_encoding($str, 'UTF-16BE', 'UTF-8');
  9336. return $outstr;
  9337. }
  9338. // ====================================================
  9339. // ====================================================
  9340. /*-- CJK-FONTS --*/
  9341. // from class PDF_Chinese CJK EXTENSIONS
  9342. function AddCIDFont($family,$style,$name,&$cw,$CMap,$registry,$desc)
  9343. {
  9344. $fontkey=strtolower($family).strtoupper($style);
  9345. if(isset($this->fonts[$fontkey]))
  9346. $this->Error("Font already added: $family $style");
  9347. $i=count($this->fonts)+$this->extraFontSubsets+1;
  9348. $name=str_replace(' ','',$name);
  9349. if ($family == 'sjis') { $up = -120; } else { $up = -130; }
  9350. // ? 'up' and 'ut' do not seem to be referenced anywhere
  9351. $this->fonts[$fontkey]=array('i'=>$i,'type'=>'Type0','name'=>$name,'up'=>$up,'ut'=>40,'cw'=>$cw,'CMap'=>$CMap,'registry'=>$registry,'MissingWidth'=>1000,'desc'=>$desc);
  9352. }
  9353. function AddCJKFont($family) {
  9354. if ($this->PDFA || $this->PDFX) {
  9355. $this->Error("Adobe CJK fonts cannot be embedded in mPDF (required for PDFA1-b and PDFX/1-a).");
  9356. }
  9357. if ($family == 'big5') { $this->AddBig5Font(); }
  9358. else if ($family == 'gb') { $this->AddGBFont(); }
  9359. else if ($family == 'sjis') { $this->AddSJISFont(); }
  9360. else if ($family == 'uhc') { $this->AddUHCFont(); }
  9361. }
  9362. function AddBig5Font()
  9363. {
  9364. //Add Big5 font with proportional Latin
  9365. $family='big5';
  9366. $name='MSungStd-Light-Acro';
  9367. $cw=$this->Big5_widths;
  9368. $CMap='UniCNS-UTF16-H';
  9369. $registry=array('ordering'=>'CNS1','supplement'=>4);
  9370. $desc = array(
  9371. 'Ascent' => 880,
  9372. 'Descent' => -120,
  9373. 'CapHeight' => 880,
  9374. 'Flags' => 6,
  9375. 'FontBBox' => '[-160 -249 1015 1071]',
  9376. 'ItalicAngle' => 0,
  9377. 'StemV' => 93,
  9378. );
  9379. $this->AddCIDFont($family,'',$name,$cw,$CMap,$registry,$desc);
  9380. $this->AddCIDFont($family,'B',$name.',Bold',$cw,$CMap,$registry,$desc);
  9381. $this->AddCIDFont($family,'I',$name.',Italic',$cw,$CMap,$registry,$desc);
  9382. $this->AddCIDFont($family,'BI',$name.',BoldItalic',$cw,$CMap,$registry,$desc);
  9383. }
  9384. function AddGBFont()
  9385. {
  9386. //Add GB font with proportional Latin
  9387. $family='gb';
  9388. $name='STSongStd-Light-Acro';
  9389. $cw=$this->GB_widths;
  9390. $CMap='UniGB-UTF16-H';
  9391. $registry=array('ordering'=>'GB1','supplement'=>4);
  9392. $desc = array(
  9393. 'Ascent' => 752,
  9394. 'Descent' => -271,
  9395. 'CapHeight' => 737,
  9396. 'Flags' => 6,
  9397. 'FontBBox' => '[-25 -254 1000 880]',
  9398. 'ItalicAngle' => 0,
  9399. 'StemV' => 58,
  9400. 'Style' => '<< /Panose <000000000400000000000000> >>',
  9401. );
  9402. $this->AddCIDFont($family,'',$name,$cw,$CMap,$registry,$desc);
  9403. $this->AddCIDFont($family,'B',$name.',Bold',$cw,$CMap,$registry,$desc);
  9404. $this->AddCIDFont($family,'I',$name.',Italic',$cw,$CMap,$registry,$desc);
  9405. $this->AddCIDFont($family,'BI',$name.',BoldItalic',$cw,$CMap,$registry,$desc);
  9406. }
  9407. function AddSJISFont()
  9408. {
  9409. //Add SJIS font with proportional Latin
  9410. $family='sjis';
  9411. $name='KozMinPro-Regular-Acro';
  9412. $cw=$this->SJIS_widths;
  9413. $CMap='UniJIS-UTF16-H';
  9414. $registry=array('ordering'=>'Japan1','supplement'=>5);
  9415. $desc = array(
  9416. 'Ascent' => 880,
  9417. 'Descent' => -120,
  9418. 'CapHeight' => 740,
  9419. 'Flags' => 6,
  9420. 'FontBBox' => '[-195 -272 1110 1075]',
  9421. 'ItalicAngle' => 0,
  9422. 'StemV' => 86,
  9423. 'XHeight' => 502,
  9424. );
  9425. $this->AddCIDFont($family,'',$name,$cw,$CMap,$registry,$desc);
  9426. $this->AddCIDFont($family,'B',$name.',Bold',$cw,$CMap,$registry,$desc);
  9427. $this->AddCIDFont($family,'I',$name.',Italic',$cw,$CMap,$registry,$desc);
  9428. $this->AddCIDFont($family,'BI',$name.',BoldItalic',$cw,$CMap,$registry,$desc);
  9429. }
  9430. function AddUHCFont()
  9431. {
  9432. //Add UHC font with proportional Latin
  9433. $family='uhc';
  9434. $name='HYSMyeongJoStd-Medium-Acro';
  9435. $cw=$this->UHC_widths;
  9436. $CMap='UniKS-UTF16-H';
  9437. $registry=array('ordering'=>'Korea1','supplement'=>2);
  9438. $desc = array(
  9439. 'Ascent' => 880,
  9440. 'Descent' => -120,
  9441. 'CapHeight' => 720,
  9442. 'Flags' => 6,
  9443. 'FontBBox' => '[-28 -148 1001 880]',
  9444. 'ItalicAngle' => 0,
  9445. 'StemV' => 60,
  9446. 'Style' => '<< /Panose <000000000600000000000000> >>',
  9447. );
  9448. $this->AddCIDFont($family,'',$name,$cw,$CMap,$registry,$desc);
  9449. $this->AddCIDFont($family,'B',$name.',Bold',$cw,$CMap,$registry,$desc);
  9450. $this->AddCIDFont($family,'I',$name.',Italic',$cw,$CMap,$registry,$desc);
  9451. $this->AddCIDFont($family,'BI',$name.',BoldItalic',$cw,$CMap,$registry,$desc);
  9452. }
  9453. /*-- END CJK-FONTS --*/
  9454. //////////////////////////////////////////////////////////////////////////////
  9455. //////////////////////////////////////////////////////////////////////////////
  9456. //////////////////////////////////////////////////////////////////////////////
  9457. //////////////////////////////////////////////////////////////////////////////
  9458. //////////////////////////////////////////////////////////////////////////////
  9459. //////////////////////////////////////////////////////////////////////////////
  9460. //////////////////////////////////////////////////////////////////////////////
  9461. function SetAutoFont($af = AUTOFONT_ALL) {
  9462. if ($this->onlyCoreFonts) { return false; }
  9463. if (!$af && $af !== 0) { $af = AUTOFONT_ALL; }
  9464. $this->autoFontGroups = $af;
  9465. if ($this->autoFontGroups ) {
  9466. $this->useLang = true;
  9467. }
  9468. }
  9469. function SetDefaultFont($font) {
  9470. // Disallow embedded fonts to be used as defaults in PDFA
  9471. if ($this->PDFA || $this->PDFX) {
  9472. if (strtolower($font) == 'ctimes') { $font = 'serif'; }
  9473. if (strtolower($font) == 'ccourier') { $font = 'monospace'; }
  9474. if (strtolower($font) == 'chelvetica') { $font = 'sans-serif'; }
  9475. }
  9476. $font = $this->SetFont($font); // returns substituted font if necessary
  9477. $this->default_font = $font;
  9478. $this->original_default_font = $font;
  9479. if (!$this->watermark_font ) { $this->watermark_font = $font; } // *WATERMARK*
  9480. $this->defaultCSS['BODY']['FONT-FAMILY'] = $font;
  9481. $this->CSS['BODY']['FONT-FAMILY'] = $font;
  9482. }
  9483. function SetDefaultFontSize($fontsize) {
  9484. $this->default_font_size = $fontsize;
  9485. $this->original_default_font_size = $fontsize;
  9486. $this->SetFontSize($fontsize);
  9487. $this->defaultCSS['BODY']['FONT-SIZE'] = $fontsize . 'pt';
  9488. $this->CSS['BODY']['FONT-SIZE'] = $fontsize . 'pt';
  9489. }
  9490. function SetDefaultBodyCSS($prop, $val) {
  9491. if ($prop) {
  9492. $this->defaultCSS['BODY'][strtoupper($prop)] = $val;
  9493. $this->CSS['BODY'][strtoupper($prop)] = $val;
  9494. }
  9495. }
  9496. function SetDirectionality($dir='ltr') {
  9497. /*-- RTL --*/
  9498. if (strtolower($dir) == 'rtl') {
  9499. if ($this->directionality != 'rtl') {
  9500. // Swop L/R Margins so page 1 RTL is an 'even' page
  9501. $tmp = $this->DeflMargin;
  9502. $this->DeflMargin = $this->DefrMargin;
  9503. $this->DefrMargin = $tmp;
  9504. $this->orig_lMargin = $this->DeflMargin;
  9505. $this->orig_rMargin = $this->DefrMargin;
  9506. $this->SetMargins($this->DeflMargin,$this->DefrMargin,$this->tMargin);
  9507. }
  9508. $this->directionality = 'rtl';
  9509. $this->defaultAlign = 'R';
  9510. $this->defaultTableAlign = 'R';
  9511. }
  9512. else {
  9513. /*-- END RTL --*/
  9514. $this->directionality = 'ltr';
  9515. $this->defaultAlign = 'L';
  9516. $this->defaultTableAlign = 'L';
  9517. } // *RTL*
  9518. $this->CSS['BODY']['DIRECTION'] = $this->directionality;
  9519. }
  9520. // Added to set line-height-correction
  9521. function SetLineHeightCorrection($val) {
  9522. if ($val > 0) { $this->default_lineheight_correction = $val; }
  9523. else { $this->default_lineheight_correction = 1.2; }
  9524. }
  9525. // Set a (fixed) lineheight to an actual value - either to named fontsize(pts) or default
  9526. function SetLineHeight($FontPt='',$spacing = '') {
  9527. if ($this->shrin_k > 1) { $k = $this->shrin_k; }
  9528. else { $k = 1; }
  9529. if ($spacing > 0) {
  9530. if (preg_match('/mm/',$spacing)) {
  9531. $this->lineheight = ($spacing + 0.0) / $k; // convert to number
  9532. }
  9533. else {
  9534. if ($FontPt) { $this->lineheight = (($FontPt/_MPDFK) *$spacing); }
  9535. else { $this->lineheight = (($this->FontSizePt/_MPDFK) *$spacing); }
  9536. }
  9537. }
  9538. else {
  9539. if ($FontPt) { $this->lineheight = (($FontPt/_MPDFK) *$this->normalLineheight); }
  9540. else { $this->lineheight = (($this->FontSizePt/_MPDFK) *$this->normalLineheight); }
  9541. }
  9542. }
  9543. function _computeLineheight($lh, $fs='') {
  9544. if ($this->shrin_k > 1) { $k = $this->shrin_k; }
  9545. else { $k = 1; }
  9546. if (!$fs) { $fs = $this->FontSize; }
  9547. if (preg_match('/mm/',$lh)) {
  9548. return (($lh + 0.0) / $k); // convert to number
  9549. }
  9550. else if ($lh > 0) {
  9551. return ($fs * $lh);
  9552. }
  9553. else if (isset($this->normalLineheight)) { return ($fs * $this->normalLineheight); }
  9554. else return ($fs * $this->default_lineheight_correction);
  9555. }
  9556. function SetBasePath($str='') {
  9557. if ( isset($_SERVER['HTTP_HOST']) ) { $host = $_SERVER['HTTP_HOST']; }
  9558. else if ( isset($_SERVER['SERVER_NAME']) ) { $host = $_SERVER['SERVER_NAME']; }
  9559. else { $host = ''; }
  9560. if (!$str) {
  9561. if ($_SERVER['SCRIPT_NAME']) { $currentPath = dirname($_SERVER['SCRIPT_NAME']); }
  9562. else { $currentPath = dirname($_SERVER['PHP_SELF']); }
  9563. $currentPath = str_replace("\\","/",$currentPath);
  9564. if ($currentPath == '/') { $currentPath = ''; }
  9565. if ($host) { $currpath = 'http://' . $host . $currentPath .'/'; }
  9566. else { $currpath = ''; }
  9567. $this->basepath = $currpath;
  9568. $this->basepathIsLocal = true;
  9569. return;
  9570. }
  9571. $str = preg_replace('/\?.*/','',$str);
  9572. if (!preg_match('/(http|https|ftp):\/\/.*\//i',$str)) { $str .= '/'; }
  9573. $str .= 'xxx'; // in case $str ends in / e.g. http://www.bbc.co.uk/
  9574. $this->basepath = dirname($str) . "/"; // returns e.g. e.g. http://www.google.com/dir1/dir2/dir3/
  9575. $this->basepath = str_replace("\\","/",$this->basepath); //If on Windows
  9576. $tr = parse_url($this->basepath);
  9577. if (isset($tr['host']) && ($tr['host'] == $host)) { $this->basepathIsLocal = true; }
  9578. else { $this->basepathIsLocal = false; }
  9579. }
  9580. function GetFullPath(&$path,$basepath='') {
  9581. // When parsing CSS need to pass temporary basepath - so links are relative to current stylesheet
  9582. if (!$basepath) { $basepath = $this->basepath; }
  9583. //Fix path value
  9584. $path = str_replace("\\","/",$path); //If on Windows
  9585. //Get link info and obtain its absolute path
  9586. $regexp = '|^./|'; // Inadvertently corrects "./path/etc" and "//www.domain.com/etc"
  9587. $path = preg_replace($regexp,'',$path);
  9588. if(substr($path,0,1) == '#') { return; }
  9589. if (stristr($path,"mailto:") !== false) { return; }
  9590. if (strpos($path,"../") !== false ) { //It is a Relative Link
  9591. $backtrackamount = substr_count($path,"../");
  9592. $maxbacktrack = substr_count($basepath,"/") - 1;
  9593. $filepath = str_replace("../",'',$path);
  9594. $path = $basepath;
  9595. //If it is an invalid relative link, then make it go to directory root
  9596. if ($backtrackamount > $maxbacktrack) $backtrackamount = $maxbacktrack;
  9597. //Backtrack some directories
  9598. for( $i = 0 ; $i < $backtrackamount + 1 ; $i++ ) $path = substr( $path, 0 , strrpos($path,"/") );
  9599. $path = $path . "/" . $filepath; //Make it an absolute path
  9600. }
  9601. else if( strpos($path,":/") === false || strpos($path,":/") > 10) { //It is a Local Link
  9602. if (substr($path,0,1) == "/") {
  9603. $tr = parse_url($basepath);
  9604. $root = $tr['scheme'].'://'.$tr['host'];
  9605. $path = $root . $path;
  9606. }
  9607. else { $path = $basepath . $path; }
  9608. }
  9609. //Do nothing if it is an Absolute Link
  9610. }
  9611. // Used for external CSS files
  9612. function _get_file($path) {
  9613. // If local file try using local path (? quicker, but also allowed even if allow_url_fopen false)
  9614. $contents = '';
  9615. $contents = @file_get_contents($path);
  9616. if ($contents) { return $contents; }
  9617. if ($this->basepathIsLocal) {
  9618. $tr = parse_url($path);
  9619. $lp=getenv("SCRIPT_NAME");
  9620. $ap=realpath($lp);
  9621. $ap=str_replace("\\","/",$ap);
  9622. $docroot=substr($ap,0,strpos($ap,$lp));
  9623. // WriteHTML parses all paths to full URLs; may be local file name
  9624. if ($tr['scheme'] && $tr['host'] && $_SERVER["DOCUMENT_ROOT"] ) {
  9625. $localpath = $_SERVER["DOCUMENT_ROOT"] . $tr['path'];
  9626. }
  9627. // DOCUMENT_ROOT is not returned on IIS
  9628. else if ($docroot) {
  9629. $localpath = $docroot . $tr['path'];
  9630. }
  9631. else { $localpath = $path; }
  9632. $contents = @file_get_contents($localpath);
  9633. }
  9634. // if not use full URL
  9635. else if (!$contents && !ini_get('allow_url_fopen') && function_exists("curl_init")) {
  9636. $ch = curl_init($path);
  9637. curl_setopt($ch, CURLOPT_HEADER, 0);
  9638. curl_setopt ( $ch , CURLOPT_RETURNTRANSFER , 1 );
  9639. $contents = curl_exec($ch);
  9640. curl_close($ch);
  9641. }
  9642. return $contents;
  9643. }
  9644. function docPageNum($num = 0, $extras = false) {
  9645. if ($num < 1) { $num = $this->page; }
  9646. $type = '1'; // set default decimal
  9647. $ppgno = $num;
  9648. $suppress = 0;
  9649. $offset = 0;
  9650. $lastreset = 0;
  9651. foreach($this->PageNumSubstitutions AS $psarr) {
  9652. if ($num >= $psarr['from']) {
  9653. if ($psarr['reset']) {
  9654. if ($psarr['reset']>1) { $offset = $psarr['reset']-1; }
  9655. $ppgno = $num - $psarr['from'] + 1 + $offset;
  9656. $lastreset = $psarr['from'];
  9657. }
  9658. if ($psarr['type']) { $type = $psarr['type']; }
  9659. if (strtoupper($psarr['suppress'])=='ON' || $psarr['suppress']==1) { $suppress = 1; }
  9660. else if (strtoupper($psarr['suppress'])=='OFF') { $suppress = 0; }
  9661. }
  9662. }
  9663. if ($suppress) { return ''; }
  9664. foreach($this->pgsIns AS $k=>$v) {
  9665. if ($k>$lastreset && $k<$num) {
  9666. $ppgno -= $v;
  9667. }
  9668. }
  9669. if ($type=='A') { $ppgno = $this->dec2alpha($ppgno,true); }
  9670. else if ($type=='a') { $ppgno = $this->dec2alpha($ppgno,false);}
  9671. else if ($type=='I') { $ppgno = $this->dec2roman($ppgno,true); }
  9672. else if ($type=='i') { $ppgno = $this->dec2roman($ppgno,false); }
  9673. if ($extras) { $ppgno = $this->pagenumPrefix . $ppgno . $this->pagenumSuffix; }
  9674. return $ppgno;
  9675. }
  9676. function docPageSettings($num = 0) {
  9677. // Returns current type (numberstyle), suppression state for this page number;
  9678. // reset is only returned if set for this page number
  9679. if ($num < 1) { $num = $this->page; }
  9680. $type = '1'; // set default decimal
  9681. $ppgno = $num;
  9682. $suppress = 0;
  9683. $offset = 0;
  9684. $reset = '';
  9685. foreach($this->PageNumSubstitutions AS $psarr) {
  9686. if ($num >= $psarr['from']) {
  9687. if ($psarr['reset']) {
  9688. if ($psarr['reset']>1) { $offset = $psarr['reset']-1; }
  9689. $ppgno = $num - $psarr['from'] + 1 + $offset;
  9690. }
  9691. if ($psarr['type']) { $type = $psarr['type']; }
  9692. if (strtoupper($psarr['suppress'])=='ON' || $psarr['suppress']==1) { $suppress = 1; }
  9693. else if (strtoupper($psarr['suppress'])=='OFF') { $suppress = 0; }
  9694. }
  9695. if ($num == $psarr['from']) { $reset = $psarr['reset']; }
  9696. }
  9697. if ($suppress) { $suppress = 'on'; }
  9698. else { $suppress = 'off'; }
  9699. return array($type, $suppress, $reset);
  9700. }
  9701. function docPageNumTotal($num = 0, $extras = false) {
  9702. if ($num < 1) { $num = $this->page; }
  9703. $type = '1'; // set default decimal
  9704. $ppgstart = 1;
  9705. $ppgend = count($this->pages)+1;
  9706. $suppress = 0;
  9707. $offset = 0;
  9708. foreach($this->PageNumSubstitutions AS $psarr) {
  9709. if ($num >= $psarr['from']) {
  9710. if ($psarr['reset']) {
  9711. if ($psarr['reset']>1) { $offset = $psarr['reset']-1; }
  9712. $ppgstart = $psarr['from'] + $offset;
  9713. $ppgend = count($this->pages)+1 + $offset;
  9714. }
  9715. if ($psarr['type']) { $type = $psarr['type']; }
  9716. if (strtoupper($psarr['suppress'])=='ON' || $psarr['suppress']==1) { $suppress = 1; }
  9717. else if (strtoupper($psarr['suppress'])=='OFF') { $suppress = 0; }
  9718. }
  9719. if ($num < $psarr['from']) {
  9720. if ($psarr['reset']) {
  9721. $ppgend = $psarr['from'] + $offset;
  9722. break;
  9723. }
  9724. }
  9725. }
  9726. if ($suppress) { return ''; }
  9727. $ppgno = $ppgend-$ppgstart+$offset;
  9728. if ($extras) { $ppgno = $this->nbpgPrefix . $ppgno . $this->nbpgSuffix; }
  9729. return $ppgno;
  9730. }
  9731. function RestartDocTemplate() {
  9732. $this->docTemplateStart = $this->page;
  9733. }
  9734. //Page header
  9735. function Header($content='') {
  9736. $this->cMarginL = 0;
  9737. $this->cMarginR = 0;
  9738. /*-- HTMLHEADERS-FOOTERS --*/
  9739. if (($this->mirrorMargins && ($this->page%2==0) && $this->HTMLHeaderE) || ($this->mirrorMargins && ($this->page%2==1) && $this->HTMLHeader) || (!$this->mirrorMargins && $this->HTMLHeader)) {
  9740. $this->writeHTMLHeaders();
  9741. return;
  9742. }
  9743. /*-- END HTMLHEADERS-FOOTERS --*/
  9744. $this->processingHeader=true;
  9745. $h = $this->headerDetails;
  9746. if(count($h)) {
  9747. if ($this->forcePortraitHeaders && $this->CurOrientation=='L' && $this->CurOrientation!=$this->DefOrientation) {
  9748. $this->_out(sprintf('q 0 -1 1 0 0 %.3F cm ',($this->h*_MPDFK)));
  9749. $yadj = $this->w - $this->h;
  9750. $headerpgwidth = $this->h - $this->orig_lMargin - $this->orig_rMargin;
  9751. if (($this->mirrorMargins) && (($this->page)%2==0)) { // EVEN
  9752. $headerlmargin = $this->orig_rMargin;
  9753. }
  9754. else {
  9755. $headerlmargin = $this->orig_lMargin;
  9756. }
  9757. }
  9758. else {
  9759. $yadj = 0;
  9760. $headerpgwidth = $this->pgwidth;
  9761. $headerlmargin = $this->lMargin;
  9762. }
  9763. $this->y = $this->margin_header - $yadj ;
  9764. $this->SetTColor($this->ConvertColor(0));
  9765. $this->SUP = false;
  9766. $this->SUB = false;
  9767. $this->bullet = false;
  9768. // only show pagenumber if numbering on
  9769. $pgno = $this->docPageNum($this->page, true);
  9770. if (($this->mirrorMargins) && (($this->page)%2==0)) { // EVEN
  9771. $side = 'even';
  9772. }
  9773. else { // ODD // OR NOT MIRRORING MARGINS/FOOTERS = DEFAULT
  9774. $side = 'odd';
  9775. }
  9776. $maxfontheight = 0;
  9777. foreach(array('L','C','R') AS $pos) {
  9778. if (isset($h[$side][$pos]['content']) && $h[$side][$pos]['content']) {
  9779. if (isset($h[$side][$pos]['font-size']) && $h[$side][$pos]['font-size']) { $hfsz = $h[$side][$pos]['font-size']; }
  9780. else { $hfsz = $this->default_font_size; }
  9781. $maxfontheight = max($maxfontheight,$hfsz);
  9782. }
  9783. }
  9784. // LEFT-CENTER-RIGHT
  9785. foreach(array('L','C','R') AS $pos) {
  9786. if (isset($h[$side][$pos]['content']) && $h[$side][$pos]['content']) {
  9787. $hd = str_replace('{PAGENO}',$pgno,$h[$side][$pos]['content']);
  9788. $hd = str_replace($this->aliasNbPgGp,$this->nbpgPrefix.$this->aliasNbPgGp.$this->nbpgSuffix,$hd);
  9789. $hd = preg_replace('/\{DATE\s+(.*?)\}/e',"date('\\1')",$hd);
  9790. if (isset($h[$side][$pos]['font-family']) && $h[$side][$pos]['font-family']) { $hff = $h[$side][$pos]['font-family']; }
  9791. else { $hff = $this->original_default_font; }
  9792. if (isset($h[$side][$pos]['font-size']) && $h[$side][$pos]['font-size']) { $hfsz = $h[$side][$pos]['font-size']; }
  9793. else { $hfsz = $this->original_default_font_size; } // pts
  9794. $maxfontheight = max($maxfontheight,$hfsz);
  9795. $hfst = '';
  9796. if (isset($h[$side][$pos]['font-style']) && $h[$side][$pos]['font-style']) {
  9797. $hfst = $h[$side][$pos]['font-style'];
  9798. }
  9799. if (isset($h[$side][$pos]['color']) && $h[$side][$pos]['color']) {
  9800. $hfcol = $h[$side][$pos]['color'];
  9801. $cor = $this->ConvertColor($hfcol);
  9802. if ($cor) { $this->SetTColor($cor); }
  9803. }
  9804. else { $hfcol = ''; }
  9805. $this->SetFont($hff,$hfst,$hfsz,true,true);
  9806. $this->x = $headerlmargin ;
  9807. $this->y = $this->margin_header - $yadj ;
  9808. $hd = $this->purify_utf8_text($hd);
  9809. if ($this->text_input_as_HTML) {
  9810. $hd = $this->all_entities_to_utf8($hd);
  9811. }
  9812. // CONVERT CODEPAGE
  9813. if ($this->usingCoreFont) { $hd = mb_convert_encoding($hd,$this->mb_enc,'UTF-8'); }
  9814. // DIRECTIONALITY RTL
  9815. $this->magic_reverse_dir($hd, true, $this->directionality); // *RTL*
  9816. // Font-specific ligature substitution for Indic fonts
  9817. if (isset($this->CurrentFont['indic']) && $this->CurrentFont['indic']) $this->ConvertIndic($hd); // *INDIC*
  9818. $align = $pos;
  9819. /*-- RTL --*/
  9820. if ($this->directionality == 'rtl') {
  9821. if ($pos == 'L') { $align = 'R'; }
  9822. else if ($pos == 'R') { $align = 'L'; }
  9823. }
  9824. /*-- END RTL --*/
  9825. if ($pos!='L' && (strpos($hd,$this->aliasNbPg)!==false || strpos($hd,$this->aliasNbPgGp)!==false)) {
  9826. if (strpos($hd,$this->aliasNbPgGp)!==false) { $type= 'nbpggp'; } else { $type= 'nbpg'; }
  9827. $this->_out('{mpdfheader'.$type.' '.$pos.' ff='.$hff.' fs='.$hfst.' fz='.$hfsz.'}');
  9828. $this->Cell($headerpgwidth ,$maxfontheight/_MPDFK ,$hd,0,0,$align,0,'',0,0,0,'M');
  9829. $this->_out('Q');
  9830. }
  9831. else {
  9832. $this->Cell($headerpgwidth ,$maxfontheight/_MPDFK ,$hd,0,0,$align,0,'',0,0,0,'M');
  9833. }
  9834. if ($hfcol) { $this->SetTColor($this->ConvertColor(0)); }
  9835. }
  9836. }
  9837. //Return Font to normal
  9838. $this->SetFont($this->default_font,'',$this->original_default_font_size);
  9839. // LINE
  9840. if (isset($h[$side]['line']) && $h[$side]['line']) {
  9841. $this->SetLineWidth(0.1);
  9842. $this->SetDColor($this->ConvertColor(0));
  9843. $this->Line($headerlmargin , $this->margin_header + ($maxfontheight*(1+$this->header_line_spacing)/_MPDFK) - $yadj , $headerlmargin + $headerpgwidth, $this->margin_header + ($maxfontheight*(1+$this->header_line_spacing)/_MPDFK) - $yadj );
  9844. }
  9845. if ($this->forcePortraitHeaders && $this->CurOrientation=='L' && $this->CurOrientation!=$this->DefOrientation) {
  9846. $this->_out('Q');
  9847. }
  9848. }
  9849. $this->SetY($this->tMargin);
  9850. if ($this->ColActive) { $this->pgwidth = $this->ColWidth; } // *COLUMNS*
  9851. $this->processingHeader=false;
  9852. }
  9853. /*-- TABLES --*/
  9854. function TableHeaderFooter($content='',$tablestartpage='',$tablestartcolumn ='',$horf = 'H',$level, $firstSpread=true, $finalSpread=true) {
  9855. if(($horf=='H' || $horf=='F') && !empty($content)) {
  9856. $table = &$this->table[1][1];
  9857. // Advance down page by half width of top border
  9858. if ($horf=='H') { // Only if header
  9859. if ($table['borders_separate']) { $adv = $table['border_spacing_V']/2 + $table['border_details']['T']['w'] + $table['padding']['T']; }
  9860. else { $adv = $table['max_cell_border_width']['T'] /2 ; }
  9861. if ($adv) {
  9862. if ($this->table_rotate) {
  9863. $this->y += ($adv);
  9864. }
  9865. else {
  9866. $this->DivLn($adv,$this->blklvl,true);
  9867. }
  9868. }
  9869. }
  9870. if ($horf=='F') { // Table Footer
  9871. $firstrow = count($table['cells']) - $table['footernrows'];
  9872. $lastrow = count($table['cells']) - 1;
  9873. }
  9874. else { // Table Header
  9875. $firstrow = 0;
  9876. $lastrow = $table['headernrows'] - 1;
  9877. }
  9878. $topy = $content[$firstrow][0]['y']-$this->y;
  9879. for ($i=$firstrow ; $i<=$lastrow; $i++) {
  9880. $y = $this->y;
  9881. /*-- COLUMNS --*/
  9882. // If outside columns, this is done in PaintDivBB
  9883. if ($this->ColActive) {
  9884. //OUTER FILL BGCOLOR of DIVS
  9885. if ($this->blklvl > 0) {
  9886. $firstblockfill = $this->GetFirstBlockFill();
  9887. if ($firstblockfill && $this->blklvl >= $firstblockfill) {
  9888. $divh = $content[$i][0]['h'];
  9889. $bak_x = $this->x;
  9890. $this->DivLn($divh,-3,false);
  9891. // Reset current block fill
  9892. $bcor = $this->blk[$this->blklvl]['bgcolorarray'];
  9893. $this->SetFColor($bcor);
  9894. $this->x = $bak_x;
  9895. }
  9896. }
  9897. }
  9898. /*-- END COLUMNS --*/
  9899. $colctr = 0;
  9900. foreach($content[$i] as $tablehf) {
  9901. $colctr++;
  9902. $y = $tablehf['y'] - $topy;
  9903. $this->y = $y;
  9904. //Set some cell values
  9905. $x = $tablehf['x'];
  9906. if (($this->mirrorMargins) && ($tablestartpage == 'ODD') && (($this->page)%2==0)) { // EVEN
  9907. $x = $x +$this->MarginCorrection;
  9908. }
  9909. else if (($this->mirrorMargins) && ($tablestartpage == 'EVEN') && (($this->page)%2==1)) { // ODD
  9910. $x = $x +$this->MarginCorrection;
  9911. }
  9912. /*-- COLUMNS --*/
  9913. // Added to correct for Columns
  9914. if ($this->ColActive) {
  9915. if ($this->directionality == 'rtl') { // *RTL*
  9916. $x -= ($this->CurrCol - $tablestartcolumn) * ($this->ColWidth+$this->ColGap); // *RTL*
  9917. } // *RTL*
  9918. else { // *RTL*
  9919. $x += ($this->CurrCol - $tablestartcolumn) * ($this->ColWidth+$this->ColGap);
  9920. } // *RTL*
  9921. }
  9922. /*-- END COLUMNS --*/
  9923. if ($colctr==1) { $x0 = $x; }
  9924. // mPDF ITERATION
  9925. if ($this->iterationCounter) {
  9926. foreach($tablehf['textbuffer'] AS $k=>$t) {
  9927. if (!is_array($t[0]) && preg_match('/{iteration ([a-zA-Z0-9_]+)}/',$t[0], $m)) { // mPDF 5.5.06
  9928. $vname = '__'.$m[1].'_';
  9929. if (!isset($this->$vname)) { $this->$vname = 1; }
  9930. else { $this->$vname++; }
  9931. $tablehf['textbuffer'][$k][0] = preg_replace('/{iteration '.$m[1].'}/', $this->$vname, $tablehf['textbuffer'][$k][0]);
  9932. }
  9933. }
  9934. }
  9935. $w = $tablehf['w'];
  9936. $h = $tablehf['h'];
  9937. $va = $tablehf['va'];
  9938. $R = $tablehf['R'];
  9939. $mih = $tablehf['mih'];
  9940. $border = $tablehf['border'];
  9941. $border_details = $tablehf['border_details'];
  9942. $padding = $tablehf['padding'];
  9943. $this->tabletheadjustfinished = true;
  9944. $textbuffer = $tablehf['textbuffer'];
  9945. $align = $tablehf['a'];
  9946. //Align
  9947. $this->divalign=$align;
  9948. $this->x = $x;
  9949. if ($this->ColActive) {
  9950. if ($table['borders_separate']) {
  9951. $tablefill = isset($table['bgcolor'][-1]) ? $table['bgcolor'][-1] : 0;
  9952. if ($tablefill) {
  9953. $color = $this->ConvertColor($tablefill);
  9954. if ($color) {
  9955. $xadj = ($table['border_spacing_H']/2);
  9956. $yadj = ($table['border_spacing_V']/2);
  9957. $wadj = $table['border_spacing_H'];
  9958. $hadj = $table['border_spacing_V'];
  9959. if ($i == $firstrow && $horf=='H') { // Top
  9960. $yadj += $table['padding']['T'] + $table['border_details']['T']['w'] ;
  9961. $hadj += $table['padding']['T'] + $table['border_details']['T']['w'] ;
  9962. }
  9963. if (($i == ($lastrow) || (isset($tablehf['rowspan']) && ($i+$tablehf['rowspan']) == ($lastrow+1)) || (!isset($tablehf['rowspan']) && ($i+1) == ($lastrow+1))) && $horf=='F') { // Bottom
  9964. $hadj += $table['padding']['B'] + $table['border_details']['B']['w'] ;
  9965. }
  9966. if ($colctr == 1) { // Left
  9967. $xadj += $table['padding']['L'] + $table['border_details']['L']['w'] ;
  9968. $wadj += $table['padding']['L'] + $table['border_details']['L']['w'] ;
  9969. }
  9970. if ($colctr == count($content[$i]) ) { // Right
  9971. $wadj += $table['padding']['R'] + $table['border_details']['R']['w'] ;
  9972. }
  9973. $this->SetFColor($color);
  9974. $this->Rect($x - $xadj, $y - $yadj, $w + $wadj, $h + $hadj, 'F');
  9975. }
  9976. }
  9977. }
  9978. }
  9979. if ($table['empty_cells']!='hide' || !empty($textbuffer) || !$table['borders_separate']) { $paintcell = true; }
  9980. else { $paintcell = false; }
  9981. //Vertical align
  9982. if ($R && INTVAL($R) > 0 && isset($va) && $va!='B') { $va='B';}
  9983. if (!isset($va) || empty($va) || $va=='M') $this->y += ($h-$mih)/2;
  9984. elseif (isset($va) && $va=='B') $this->y += $h-$mih;
  9985. //TABLE ROW OR CELL FILL BGCOLOR
  9986. $fill = 0;
  9987. if (isset($tablehf['bgcolor']) && $tablehf['bgcolor'] && $tablehf['bgcolor']!='transparent') {
  9988. $fill = $tablehf['bgcolor'];
  9989. $leveladj = 6;
  9990. }
  9991. else if (isset($content[$i][0]['trbgcolor']) && $content[$i][0]['trbgcolor'] && $content[$i][0]['trbgcolor']!='transparent') { // Row color
  9992. $fill = $content[$i][0]['trbgcolor'];
  9993. $leveladj = 3;
  9994. }
  9995. if ($fill && $paintcell) {
  9996. $color = $this->ConvertColor($fill);
  9997. if ($color) {
  9998. if ($table['borders_separate']) {
  9999. if ($this->ColActive) {
  10000. $this->SetFColor($color);
  10001. $this->Rect($x+ ($table['border_spacing_H']/2), $y+ ($table['border_spacing_V']/2), $w- $table['border_spacing_H'], $h- $table['border_spacing_V'], 'F');
  10002. }
  10003. else {
  10004. $this->tableBackgrounds[$level*9+$leveladj][] = array('gradient'=>false, 'x'=>($x + ($table['border_spacing_H']/2)), 'y'=>($y + ($table['border_spacing_V']/2)), 'w'=>($w - $table['border_spacing_H']), 'h'=>($h - $table['border_spacing_V']), 'col'=>$color);
  10005. }
  10006. }
  10007. else {
  10008. if ($this->ColActive) {
  10009. $this->SetFColor($color);
  10010. $this->Rect($x, $y, $w, $h, 'F');
  10011. }
  10012. else {
  10013. $this->tableBackgrounds[$level*9+$leveladj][] = array('gradient'=>false, 'x'=>$x, 'y'=>$y, 'w'=>$w, 'h'=>$h, 'col'=>$color);
  10014. }
  10015. }
  10016. }
  10017. }
  10018. /*-- BACKGROUNDS --*/
  10019. if (isset($tablehf['gradient']) && $tablehf['gradient'] && $paintcell){
  10020. $g = $this->grad->parseBackgroundGradient($tablehf['gradient']);
  10021. if ($g) {
  10022. if ($table['borders_separate']) {
  10023. $px = $x+ ($table['border_spacing_H']/2);
  10024. $py = $y+ ($table['border_spacing_V']/2);
  10025. $pw = $w- $table['border_spacing_H'];
  10026. $ph = $h- $table['border_spacing_V'];
  10027. }
  10028. else {
  10029. $px = $x;
  10030. $py = $y;
  10031. $pw = $w;
  10032. $ph = $h;
  10033. }
  10034. if ($this->ColActive) {
  10035. $this->grad->Gradient($px, $py, $pw, $ph, $g['type'], $g['stops'], $g['colorspace'], $g['coords'], $g['extend']);
  10036. }
  10037. else {
  10038. $this->tableBackgrounds[$level*9+7][] = array('gradient'=>true, 'x'=>$px, 'y'=>$py, 'w'=>$pw, 'h'=>$ph, 'gradtype'=>$g['type'], 'stops'=>$g['stops'], 'colorspace'=>$g['colorspace'], 'coords'=>$g['coords'], 'extend'=>$g['extend'], 'clippath'=>'');
  10039. }
  10040. }
  10041. }
  10042. if (isset($tablehf['background-image']) && $paintcell){
  10043. if ($tablehf['background-image']['gradient'] && preg_match('/(-moz-)*(repeating-)*(linear|radial)-gradient/', $tablehf['background-image']['gradient'] )) {
  10044. $g = $this->grad->parseMozGradient( $tablehf['background-image']['gradient'] );
  10045. if ($g) {
  10046. if ($table['borders_separate']) {
  10047. $px = $x+ ($table['border_spacing_H']/2);
  10048. $py = $y+ ($table['border_spacing_V']/2);
  10049. $pw = $w- $table['border_spacing_H'];
  10050. $ph = $h- $table['border_spacing_V'];
  10051. }
  10052. else {
  10053. $px = $x;
  10054. $py = $y;
  10055. $pw = $w;
  10056. $ph = $h;
  10057. }
  10058. if ($this->ColActive) {
  10059. $this->grad->Gradient($px, $py, $pw, $ph, $g['type'], $g['stops'], $g['colorspace'], $g['coords'], $g['extend']);
  10060. }
  10061. else {
  10062. $this->tableBackgrounds[$level*9+7][] = array('gradient'=>true, 'x'=>$px, 'y'=>$py, 'w'=>$pw, 'h'=>$ph, 'gradtype'=>$g['type'], 'stops'=>$g['stops'], 'colorspace'=>$g['colorspace'], 'coords'=>$g['coords'], 'extend'=>$g['extend'], 'clippath'=>'');
  10063. }
  10064. }
  10065. }
  10066. else if ($tablehf['background-image']['image_id']) { // Background pattern
  10067. $n = count($this->patterns)+1;
  10068. if ($table['borders_separate']) {
  10069. $px = $x+ ($table['border_spacing_H']/2);
  10070. $py = $y+ ($table['border_spacing_V']/2);
  10071. $pw = $w- $table['border_spacing_H'];
  10072. $ph = $h- $table['border_spacing_V'];
  10073. }
  10074. else {
  10075. $px = $x;
  10076. $py = $y;
  10077. $pw = $w;
  10078. $ph = $h;
  10079. }
  10080. if ($this->ColActive) {
  10081. list($orig_w, $orig_h, $x_repeat, $y_repeat) = $this->_resizeBackgroundImage($tablehf['background-image']['orig_w'], $tablehf['background-image']['orig_h'], $pw, $ph, $tablehf['background-image']['resize'], $tablehf['background-image']['x_repeat'] , $tablehf['background-image']['y_repeat']);
  10082. $this->patterns[$n] = array('x'=>$px, 'y'=>$py, 'w'=>$pw, 'h'=>$ph, 'pgh'=>$this->h, 'image_id'=>$tablehf['background-image']['image_id'], 'orig_w'=>$orig_w, 'orig_h'=>$orig_h, 'x_pos'=>$tablehf['background-image']['x_pos'] , 'y_pos'=>$tablehf['background-image']['y_pos'] , 'x_repeat'=>$x_repeat, 'y_repeat'=>$y_repeat, 'itype'=>$tablehf['background-image']['itype']);
  10083. if ($tablehf['background-image']['opacity']>0 && $tablehf['background-image']['opacity']<1) { $opac = $this->SetAlpha($tablehf['background-image']['opacity'],'Normal',true); }
  10084. else { $opac = ''; }
  10085. $this->_out(sprintf('q /Pattern cs /P%d scn %s %.3F %.3F %.3F %.3F re f Q', $n, $opac, $px*_MPDFK, ($this->h-$py)*_MPDFK, $pw*_MPDFK, -$ph*_MPDFK));
  10086. }
  10087. else {
  10088. $this->tableBackgrounds[$level*9+8][] = array('x'=>$px, 'y'=>$py, 'w'=>$pw, 'h'=>$ph, 'image_id'=>$tablehf['background-image']['image_id'], 'orig_w'=>$tablehf['background-image']['orig_w'], 'orig_h'=>$tablehf['background-image']['orig_h'], 'x_pos'=>$tablehf['background-image']['x_pos'], 'y_pos'=>$tablehf['background-image']['y_pos'], 'x_repeat'=>$tablehf['background-image']['x_repeat'], 'y_repeat'=>$tablehf['background-image']['y_repeat'], 'clippath'=>'', 'resize'=>$tablehf['background-image']['resize'], 'opacity'=>$tablehf['background-image']['opacity'], 'itype'=>$tablehf['background-image']['itype']);
  10089. }
  10090. }
  10091. }
  10092. /*-- END BACKGROUNDS --*/
  10093. //Cell Border
  10094. if ($table['borders_separate'] && $paintcell && $border) {
  10095. $this->_tableRect($x+ ($table['border_spacing_H']/2)+($border_details['L']['w'] /2), $y+ ($table['border_spacing_V']/2)+($border_details['T']['w'] /2), $w-$table['border_spacing_H']-($border_details['L']['w'] /2)-($border_details['R']['w'] /2), $h- $table['border_spacing_V']-($border_details['T']['w'] /2)-($border_details['B']['w']/2), $border, $border_details, false, $table['borders_separate']);
  10096. }
  10097. else if ($paintcell && $border) {
  10098. $this->_tableRect($x, $y, $w, $h, $border, $border_details, true, $table['borders_separate']); // true causes buffer
  10099. }
  10100. //Print cell content
  10101. //$this->divheight = $this->table_lineheight*$this->lineheight;
  10102. if (!empty($textbuffer)) {
  10103. if ($horf=='F' && preg_match('/{colsum([0-9]*)[_]*}/', $textbuffer[0][0], $m)) {
  10104. $rep = sprintf("%01.".intval($m[1])."f", $this->colsums[$colctr-1]);
  10105. $textbuffer[0][0] = preg_replace('/{colsum[0-9_]*}/', $rep ,$textbuffer[0][0]);
  10106. }
  10107. if ($R) {
  10108. $cellPtSize = $textbuffer[0][11] / $this->shrin_k;
  10109. if (!$cellPtSize) { $cellPtSize = $this->default_font_size; }
  10110. $cellFontHeight = ($cellPtSize/_MPDFK);
  10111. $opx = $this->x;
  10112. $opy = $this->y;
  10113. $angle = INTVAL($R);
  10114. // Only allow 45 - 90 degrees (when bottom-aligned) or -90
  10115. if ($angle > 90) { $angle = 90; }
  10116. else if ($angle > 0 && (isset($va) && $va!='B')) { $angle = 90; }
  10117. else if ($angle > 0 && $angle <45) { $angle = 45; }
  10118. else if ($angle < 0) { $angle = -90; }
  10119. $offset = ((sin(deg2rad($angle))) * 0.37 * $cellFontHeight);
  10120. if (isset($align) && $align =='R') {
  10121. $this->x += ($w) + ($offset) - ($cellFontHeight/3) - ($padding['R'] + $border_details['R']['w']);
  10122. }
  10123. else if (!isset($align ) || $align =='C') {
  10124. $this->x += ($w/2) + ($offset);
  10125. }
  10126. else {
  10127. $this->x += ($offset) + ($cellFontHeight/3)+($padding['L'] + $border_details['L']['w']);
  10128. }
  10129. $str = '';
  10130. foreach($tablehf['textbuffer'] AS $t) { $str .= $t[0].' '; }
  10131. $str = trim($str);
  10132. if (!isset($va) || $va=='M') {
  10133. $this->y -= ($h-$mih)/2; //Undo what was added earlier VERTICAL ALIGN
  10134. if ($angle > 0) { $this->y += (($h-$mih)/2)+($padding['T'] + $border_details['T']['w']) + ($mih-($padding['T'] + $border_details['T']['w']+$border_details['B']['w']+$padding['B'])); }
  10135. else if ($angle < 0) { $this->y += (($h-$mih)/2)+($padding['T'] + $border_details['T']['w']); }
  10136. }
  10137. else if (isset($va) && $va=='B') {
  10138. $this->y -= $h-$mih; //Undo what was added earlier VERTICAL ALIGN
  10139. if ($angle > 0) { $this->y += $h-($border_details['B']['w']+$padding['B']); }
  10140. else if ($angle < 0) { $this->y += $h-$mih+($padding['T'] + $border_details['T']['w']); }
  10141. }
  10142. else if (isset($va) && $va=='T') {
  10143. if ($angle > 0) { $this->y += $mih-($border_details['B']['w']+$padding['B']); }
  10144. else if ($angle < 0) { $this->y += ($padding['T'] + $border_details['T']['w']); }
  10145. }
  10146. $this->Rotate($angle,$this->x,$this->y);
  10147. $s_fs = $this->FontSizePt;
  10148. $s_f = $this->FontFamily;
  10149. $s_st = $this->FontStyle;
  10150. if (!empty($textbuffer[0][3])) { //Font Color
  10151. $cor = $textbuffer[0][3];
  10152. $this->SetTColor($cor);
  10153. }
  10154. $s_str = $this->strike;
  10155. $this->strike = $textbuffer[0][8]; //Strikethrough
  10156. $this->SetFont($textbuffer[0][4],$textbuffer[0][2],$cellPtSize,true,true);
  10157. $this->Text($this->x,$this->y,$str);
  10158. $this->Rotate(0);
  10159. $this->SetFont($s_f,$s_st,$s_fs,true,true);
  10160. $this->SetTColor(0);
  10161. $this->strike = $s_str;
  10162. $this->x = $opx;
  10163. $this->y = $opy;
  10164. }
  10165. else {
  10166. if ($table['borders_separate']) { // NB twice border width
  10167. $xadj = $border_details['L']['w'] + $padding['L'] +($table['border_spacing_H']/2);
  10168. $wadj = $border_details['L']['w'] + $border_details['R']['w'] + $padding['L'] +$padding['R'] + $table['border_spacing_H'];
  10169. $yadj = $border_details['T']['w'] + $padding['T'] + ($table['border_spacing_H']/2);
  10170. }
  10171. else {
  10172. $xadj = $border_details['L']['w']/2 + $padding['L'];
  10173. $wadj = ($border_details['L']['w'] + $border_details['R']['w'])/2 + $padding['L'] + $padding['R'];
  10174. $yadj = $border_details['T']['w']/2 + $padding['T'];
  10175. }
  10176. $this->divwidth=$w-($wadj);
  10177. $this->x += $xadj;
  10178. $this->y += $yadj;
  10179. $this->printbuffer($textbuffer,'',true);
  10180. }
  10181. }
  10182. $textbuffer = array();
  10183. /*-- BACKGROUNDS --*/
  10184. if (!$this->ColActive) {
  10185. if (isset($content[$i][0]['trgradients']) && ($colctr==1 || $table['borders_separate'])) {
  10186. $g = $this->grad->parseBackgroundGradient($content[$i][0]['trgradients']);
  10187. if ($g) {
  10188. $gx = $x0;
  10189. $gy = $y;
  10190. $gh = $h;
  10191. $gw = $table['w'] - ($table['max_cell_border_width']['L']/2) - ($table['max_cell_border_width']['R']/2) - $table['margin']['L'] - $table['margin']['R'];
  10192. if ($table['borders_separate']) {
  10193. $gw -= ($table['padding']['L'] + $table['border_details']['L']['w'] + $table['padding']['R'] + $table['border_details']['R']['w'] + $table['border_spacing_H']);
  10194. $s = '';
  10195. $clx = $x+ ($table['border_spacing_H']/2);
  10196. $cly = $y+ ($table['border_spacing_V']/2);
  10197. $clw = $w- $table['border_spacing_H'];
  10198. $clh = $h- $table['border_spacing_V'];
  10199. // Set clipping path
  10200. $s = ' q 0 w '; // Line width=0
  10201. $s .= sprintf('%.3F %.3F m ', ($clx)*_MPDFK, ($this->h-($cly))*_MPDFK); // start point TL before the arc
  10202. $s .= sprintf('%.3F %.3F l ', ($clx)*_MPDFK, ($this->h-($cly+$clh))*_MPDFK); // line to BL
  10203. $s .= sprintf('%.3F %.3F l ', ($clx+$clw)*_MPDFK, ($this->h-($cly+$clh))*_MPDFK); // line to BR
  10204. $s .= sprintf('%.3F %.3F l ', ($clx+$clw)*_MPDFK, ($this->h-($cly))*_MPDFK); // line to TR
  10205. $s .= sprintf('%.3F %.3F l ', ($clx)*_MPDFK, ($this->h-($cly))*_MPDFK); // line to TL
  10206. $s .= ' W n '; // Ends path no-op & Sets the clipping path
  10207. $this->tableBackgrounds[$level*9+4][] = array('gradient'=>true, 'x'=>$gx + ($table['border_spacing_H']/2), 'y'=>$gy + ($table['border_spacing_V']/2), 'w'=>$gw - $table['border_spacing_V'], 'h'=>$gh - $table['border_spacing_H'], 'gradtype'=>$g['type'], 'stops'=>$g['stops'], 'colorspace'=>$g['colorspace'], 'coords'=>$g['coords'], 'extend'=>$g['extend'], 'clippath'=>$s);
  10208. }
  10209. else {
  10210. $this->tableBackgrounds[$level*9+4][] = array('gradient'=>true, 'x'=>$gx, 'y'=>$gy, 'w'=>$gw, 'h'=>$gh, 'gradtype'=>$g['type'], 'stops'=>$g['stops'], 'colorspace'=>$g['colorspace'], 'coords'=>$g['coords'], 'extend'=>$g['extend'], 'clippath'=>'');
  10211. }
  10212. }
  10213. }
  10214. if (isset($content[$i][0]['trbackground-images']) && ($colctr==1 || $table['borders_separate'])) {
  10215. if ($content[$i][0]['trbackground-images']['gradient'] && preg_match('/(-moz-)*(repeating-)*(linear|radial)-gradient/', $content[$i][0]['trbackground-images']['gradient'] )) {
  10216. $g = $this->grad->parseMozGradient( $content[$i][0]['trbackground-images']['gradient'] );
  10217. if ($g) {
  10218. $gx = $x0;
  10219. $gy = $y;
  10220. $gh = $h;
  10221. $gw = $table['w'] - ($table['max_cell_border_width']['L']/2) - ($table['max_cell_border_width']['R']/2) - $table['margin']['L'] - $table['margin']['R'];
  10222. if ($table['borders_separate']) {
  10223. $gw -= ($table['padding']['L'] + $table['border_details']['L']['w'] + $table['padding']['R'] + $table['border_details']['R']['w'] + $table['border_spacing_H']);
  10224. $s = '';
  10225. $clx = $x+ ($table['border_spacing_H']/2);
  10226. $cly = $y+ ($table['border_spacing_V']/2);
  10227. $clw = $w- $table['border_spacing_H'];
  10228. $clh = $h- $table['border_spacing_V'];
  10229. // Set clipping path
  10230. $s = ' q 0 w '; // Line width=0
  10231. $s .= sprintf('%.3F %.3F m ', ($clx)*_MPDFK, ($this->h-($cly))*_MPDFK); // start point TL before the arc
  10232. $s .= sprintf('%.3F %.3F l ', ($clx)*_MPDFK, ($this->h-($cly+$clh))*_MPDFK); // line to BL
  10233. $s .= sprintf('%.3F %.3F l ', ($clx+$clw)*_MPDFK, ($this->h-($cly+$clh))*_MPDFK); // line to BR
  10234. $s .= sprintf('%.3F %.3F l ', ($clx+$clw)*_MPDFK, ($this->h-($cly))*_MPDFK); // line to TR
  10235. $s .= sprintf('%.3F %.3F l ', ($clx)*_MPDFK, ($this->h-($cly))*_MPDFK); // line to TL
  10236. $s .= ' W n '; // Ends path no-op & Sets the clipping path
  10237. $this->tableBackgrounds[$level*9+4][] = array('gradient'=>true, 'x'=>$gx + ($table['border_spacing_H']/2), 'y'=>$gy + ($table['border_spacing_V']/2), 'w'=>$gw - $table['border_spacing_V'], 'h'=>$gh - $table['border_spacing_H'], 'gradtype'=>$g['type'], 'stops'=>$g['stops'], 'colorspace'=>$g['colorspace'], 'coords'=>$g['coords'], 'extend'=>$g['extend'], 'clippath'=>$s);
  10238. }
  10239. else {
  10240. $this->tableBackgrounds[$level*9+4][] = array('gradient'=>true, 'x'=>$gx, 'y'=>$gy, 'w'=>$gw, 'h'=>$gh, 'gradtype'=>$g['type'], 'stops'=>$g['stops'], 'colorspace'=>$g['colorspace'], 'coords'=>$g['coords'], 'extend'=>$g['extend'], 'clippath'=>'');
  10241. }
  10242. }
  10243. }
  10244. else {
  10245. $image_id = $content[$i][0]['trbackground-images']['image_id'];
  10246. $orig_w = $content[$i][0]['trbackground-images']['orig_w'];
  10247. $orig_h = $content[$i][0]['trbackground-images']['orig_h'];
  10248. $x_pos = $content[$i][0]['trbackground-images']['x_pos'];
  10249. $y_pos = $content[$i][0]['trbackground-images']['y_pos'];
  10250. $x_repeat = $content[$i][0]['trbackground-images']['x_repeat'];
  10251. $y_repeat = $content[$i][0]['trbackground-images']['y_repeat'];
  10252. $resize = $content[$i][0]['trbackground-images']['resize'];
  10253. $opacity = $content[$i][0]['trbackground-images']['opacity'];
  10254. $itype = $content[$i][0]['trbackground-images']['itype'];
  10255. $clippath = '';
  10256. $gx = $x0;
  10257. $gy = $y;
  10258. $gh = $h;
  10259. $gw = $table['w'] - ($table['max_cell_border_width']['L']/2) - ($table['max_cell_border_width']['R']/2) - $table['margin']['L'] - $table['margin']['R'];
  10260. if ($table['borders_separate']) {
  10261. $gw -= ($table['padding']['L'] + $table['border_details']['L']['w'] + $table['padding']['R'] + $table['border_details']['R']['w'] + $table['border_spacing_H']);
  10262. $s = '';
  10263. $clx = $x+ ($table['border_spacing_H']/2);
  10264. $cly = $y+ ($table['border_spacing_V']/2);
  10265. $clw = $w- $table['border_spacing_H'];
  10266. $clh = $h- $table['border_spacing_V'];
  10267. // Set clipping path
  10268. $s = ' q 0 w '; // Line width=0
  10269. $s .= sprintf('%.3F %.3F m ', ($clx)*_MPDFK, ($this->h-($cly))*_MPDFK); // start point TL before the arc
  10270. $s .= sprintf('%.3F %.3F l ', ($clx)*_MPDFK, ($this->h-($cly+$clh))*_MPDFK); // line to BL
  10271. $s .= sprintf('%.3F %.3F l ', ($clx+$clw)*_MPDFK, ($this->h-($cly+$clh))*_MPDFK); // line to BR
  10272. $s .= sprintf('%.3F %.3F l ', ($clx+$clw)*_MPDFK, ($this->h-($cly))*_MPDFK); // line to TR
  10273. $s .= sprintf('%.3F %.3F l ', ($clx)*_MPDFK, ($this->h-($cly))*_MPDFK); // line to TL
  10274. $s .= ' W n '; // Ends path no-op & Sets the clipping path
  10275. $this->tableBackgrounds[$level*9+5][] = array('x'=>$gx + ($table['border_spacing_H']/2), 'y'=>$gy + ($table['border_spacing_V']/2), 'w'=>$gw - $table['border_spacing_V'], 'h'=>$gh - $table['border_spacing_H'], '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, 'clippath'=>$s, 'resize'=>$resize, 'opacity'=>$opacity, 'itype'=>$itype);
  10276. }
  10277. else {
  10278. $this->tableBackgrounds[$level*9+5][] = array('x'=>$gx, 'y'=>$gy, 'w'=>$gw, 'h'=>$gh, '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, 'clippath'=>'', 'resize'=>$resize, 'opacity'=>$opacity, 'itype'=>$itype);
  10279. }
  10280. }
  10281. }
  10282. }
  10283. /*-- END BACKGROUNDS --*/
  10284. // TABLE BORDER - if separate OR collapsed and only table border
  10285. if (($table['borders_separate'] || ($this->simpleTables && !$table['simple']['border'])) && $table['border']) {
  10286. $halfspaceL = $table['padding']['L'] + ($table['border_spacing_H']/2);
  10287. $halfspaceR = $table['padding']['R'] + ($table['border_spacing_H']/2);
  10288. $halfspaceT = $table['padding']['T'] + ($table['border_spacing_V']/2);
  10289. $halfspaceB = $table['padding']['B'] + ($table['border_spacing_V']/2);
  10290. $tbx = $x;
  10291. $tby = $y;
  10292. $tbw = $w;
  10293. $tbh = $h;
  10294. $tab_bord = 0;
  10295. $corner = '';
  10296. if ($i == $firstrow && $horf=='H') { // Top
  10297. $tby -= $halfspaceT + ($table['border_details']['T']['w']/2);
  10298. $tbh += $halfspaceT + ($table['border_details']['T']['w']/2);
  10299. $this->setBorder($tab_bord , _BORDER_TOP);
  10300. $corner .= 'T';
  10301. }
  10302. if (($i == ($lastrow) || (isset($tablehf['rowspan']) && ($i+$tablehf['rowspan']) == ($lastrow+1))) && $horf=='F') { // Bottom
  10303. $tbh += $halfspaceB + ($table['border_details']['B']['w']/2);
  10304. $this->setBorder($tab_bord , _BORDER_BOTTOM);
  10305. $corner .= 'B';
  10306. }
  10307. if ($colctr == 1 && $firstSpread) { // Left
  10308. $tbx -= $halfspaceL + ($table['border_details']['L']['w']/2);
  10309. $tbw += $halfspaceL + ($table['border_details']['L']['w']/2);
  10310. $this->setBorder($tab_bord , _BORDER_LEFT);
  10311. $corner .= 'L';
  10312. }
  10313. if ($colctr == count($content[$i]) && $finalSpread) { // Right
  10314. $tbw += $halfspaceR + ($table['border_details']['R']['w']/2);
  10315. $this->setBorder($tab_bord , _BORDER_RIGHT);
  10316. $corner .= 'R';
  10317. }
  10318. $this->_tableRect($tbx, $tby, $tbw, $tbh, $tab_bord , $table['border_details'], false, $table['borders_separate'], 'table', $corner, $table['border_spacing_V'], $table['border_spacing_H'] );
  10319. }
  10320. }// end column $content
  10321. $this->y = $y + $h; //Update y coordinate
  10322. }// end row $i
  10323. unset($table );
  10324. $this->colsums = array();
  10325. }
  10326. }
  10327. /*-- END TABLES --*/
  10328. /*-- HTMLHEADERS-FOOTERS --*/
  10329. function SetHTMLHeader($header='',$OE='',$write=false) {
  10330. $height = 0;
  10331. if (is_array($header) && isset($header['html']) && $header['html']) {
  10332. $Hhtml = $header['html'];
  10333. if ($this->setAutoTopMargin) {
  10334. if (isset($header['h'])) { $height = $header['h']; }
  10335. else { $height = $this->_gethtmlheight($Hhtml); }
  10336. }
  10337. }
  10338. else if (!is_array($header) && $header) {
  10339. $Hhtml = $header;
  10340. if ($this->setAutoTopMargin) { $height = $this->_gethtmlheight($Hhtml); }
  10341. }
  10342. else { $Hhtml = ''; }
  10343. if ($OE != 'E') { $OE = 'O'; }
  10344. if ($OE == 'E') {
  10345. if ($Hhtml) {
  10346. $this->HTMLHeaderE['html'] = $Hhtml;
  10347. $this->HTMLHeaderE['h'] = $height;
  10348. }
  10349. else { $this->HTMLHeaderE = ''; }
  10350. }
  10351. else {
  10352. if ($Hhtml) {
  10353. $this->HTMLHeader['html'] = $Hhtml;
  10354. $this->HTMLHeader['h'] = $height;
  10355. }
  10356. else { $this->HTMLHeader = ''; }
  10357. }
  10358. if (!$this->mirrorMargins && $OE == 'E') { return; }
  10359. if ($Hhtml=='') { return; }
  10360. if ($OE == 'E') {
  10361. $this->headerDetails['even'] = array(); // override and clear any other non-HTML header/footer
  10362. }
  10363. else {
  10364. $this->headerDetails['odd'] = array(); // override and clear any non-HTML other header/footer
  10365. }
  10366. if ($this->setAutoTopMargin=='pad') {
  10367. $this->tMargin = $this->margin_header + $height + $this->orig_tMargin;
  10368. if (isset($this->saveHTMLHeader[$this->page][$OE]['mt'])) { $this->saveHTMLHeader[$this->page][$OE]['mt'] = $this->tMargin; }
  10369. }
  10370. else if ($this->setAutoTopMargin=='stretch') {
  10371. $this->tMargin = max($this->orig_tMargin, $this->margin_header + $height + $this->autoMarginPadding);
  10372. if (isset($this->saveHTMLHeader[$this->page][$OE]['mt'])) { $this->saveHTMLHeader[$this->page][$OE]['mt'] = $this->tMargin; }
  10373. }
  10374. if ($write && $this->state!=0 && (($this->mirrorMargins && $OE == 'E' && ($this->page)%2==0) || ($this->mirrorMargins && $OE != 'E' && ($this->page)%2==1) || !$this->mirrorMargins)) { $this->writeHTMLHeaders(); }
  10375. }
  10376. function SetHTMLFooter($footer='',$OE='') {
  10377. $height = 0;
  10378. if (is_array($footer) && isset($footer['html']) && $footer['html']) {
  10379. $Fhtml = $footer['html'];
  10380. if ($this->setAutoBottomMargin) {
  10381. if (isset($footer['h'])) { $height = $footer['h']; }
  10382. else { $height = $this->_gethtmlheight($Fhtml); }
  10383. }
  10384. }
  10385. else if (!is_array($footer) && $footer) {
  10386. $Fhtml = $footer;
  10387. if ($this->setAutoBottomMargin) { $height = $this->_gethtmlheight($Fhtml); }
  10388. }
  10389. else { $Fhtml = ''; }
  10390. if ($OE != 'E') { $OE = 'O'; }
  10391. if ($OE == 'E') {
  10392. if ($Fhtml) {
  10393. $this->HTMLFooterE['html'] = $Fhtml;
  10394. $this->HTMLFooterE['h'] = $height;
  10395. }
  10396. else { $this->HTMLFooterE = ''; }
  10397. }
  10398. else {
  10399. if ($Fhtml) {
  10400. $this->HTMLFooter['html'] = $Fhtml;
  10401. $this->HTMLFooter['h'] = $height;
  10402. }
  10403. else { $this->HTMLFooter = ''; }
  10404. }
  10405. if (!$this->mirrorMargins && $OE == 'E') { return; }
  10406. if ($Fhtml=='') { return false; }
  10407. if ($OE == 'E') {
  10408. $this->footerDetails['even'] = array(); // override and clear any other header/footer
  10409. }
  10410. else {
  10411. $this->footerDetails['odd'] = array(); // override and clear any other header/footer
  10412. }
  10413. if ($this->setAutoBottomMargin=='pad') {
  10414. $this->bMargin = $this->margin_footer + $height + $this->orig_bMargin;
  10415. $this->PageBreakTrigger=$this->h-$this->bMargin ;
  10416. if (isset($this->saveHTMLHeader[$this->page][$OE]['mb'])) { $this->saveHTMLHeader[$this->page][$OE]['mb'] = $this->bMargin; }
  10417. }
  10418. else if ($this->setAutoBottomMargin=='stretch') {
  10419. $this->bMargin = max($this->orig_bMargin, $this->margin_footer + $height + $this->autoMarginPadding);
  10420. $this->PageBreakTrigger=$this->h-$this->bMargin ;
  10421. if (isset($this->saveHTMLHeader[$this->page][$OE]['mb'])) { $this->saveHTMLHeader[$this->page][$OE]['mb'] = $this->bMargin; }
  10422. }
  10423. }
  10424. function _getHtmlHeight($html) {
  10425. $save_state = $this->state;
  10426. if($this->state==0) {
  10427. $this->AddPage($this->CurOrientation);
  10428. }
  10429. $this->state = 2;
  10430. $this->Reset();
  10431. $this->pageoutput[$this->page] = array();
  10432. $save_x = $this->x;
  10433. $save_y = $this->y;
  10434. $this->x = $this->lMargin;
  10435. $this->y = $this->margin_header;
  10436. $html = str_replace('{PAGENO}',$this->pagenumPrefix.$this->docPageNum($this->page).$this->pagenumSuffix,$html);
  10437. $html = str_replace($this->aliasNbPgGp,$this->nbpgPrefix.$this->docPageNumTotal($this->page).$this->nbpgSuffix,$html );
  10438. $html = str_replace($this->aliasNbPg,$this->page,$html );
  10439. $html = preg_replace('/\{DATE\s+(.*?)\}/e',"date('\\1')",$html );
  10440. $this->HTMLheaderPageLinks = array();
  10441. $this->HTMLheaderPageAnnots = array();
  10442. $this->HTMLheaderPageForms = array();
  10443. $savepb = $this->pageBackgrounds;
  10444. $this->writingHTMLheader = true;
  10445. $this->WriteHTML($html , 4); // parameter 4 saves output to $this->headerbuffer
  10446. $this->writingHTMLheader = false;
  10447. $h = ($this->y - $this->margin_header);
  10448. $this->Reset();
  10449. $this->pageoutput[$this->page] = array();
  10450. $this->headerbuffer = '';
  10451. $this->pageBackgrounds = $savepb;
  10452. $this->x = $save_x;
  10453. $this->y = $save_y;
  10454. $this->state = $save_state;
  10455. if($save_state==0) {
  10456. unset($this->pages[1]);
  10457. $this->page = 0;
  10458. }
  10459. return $h;
  10460. }
  10461. // Called internally from Header
  10462. function writeHTMLHeaders() {
  10463. if ($this->mirrorMargins && ($this->page)%2==0) { $OE = 'E'; } // EVEN
  10464. else { $OE = 'O'; }
  10465. if ($OE == 'E') {
  10466. $this->saveHTMLHeader[$this->page][$OE]['html'] = $this->HTMLHeaderE['html'] ;
  10467. }
  10468. else {
  10469. $this->saveHTMLHeader[$this->page][$OE]['html'] = $this->HTMLHeader['html'] ;
  10470. }
  10471. if ($this->forcePortraitHeaders && $this->CurOrientation=='L' && $this->CurOrientation!=$this->DefOrientation) {
  10472. $this->saveHTMLHeader[$this->page][$OE]['rotate'] = true;
  10473. $this->saveHTMLHeader[$this->page][$OE]['ml'] = $this->tMargin;
  10474. $this->saveHTMLHeader[$this->page][$OE]['mr'] = $this->bMargin;
  10475. $this->saveHTMLHeader[$this->page][$OE]['mh'] = $this->margin_header;
  10476. $this->saveHTMLHeader[$this->page][$OE]['mf'] = $this->margin_footer;
  10477. $this->saveHTMLHeader[$this->page][$OE]['pw'] = $this->h;
  10478. $this->saveHTMLHeader[$this->page][$OE]['ph'] = $this->w;
  10479. }
  10480. else {
  10481. $this->saveHTMLHeader[$this->page][$OE]['ml'] = $this->lMargin;
  10482. $this->saveHTMLHeader[$this->page][$OE]['mr'] = $this->rMargin;
  10483. $this->saveHTMLHeader[$this->page][$OE]['mh'] = $this->margin_header;
  10484. $this->saveHTMLHeader[$this->page][$OE]['mf'] = $this->margin_footer;
  10485. $this->saveHTMLHeader[$this->page][$OE]['pw'] = $this->w;
  10486. $this->saveHTMLHeader[$this->page][$OE]['ph'] = $this->h;
  10487. }
  10488. }
  10489. function writeHTMLFooters() {
  10490. if ($this->mirrorMargins && ($this->page)%2==0) { $OE = 'E'; } // EVEN
  10491. else { $OE = 'O'; }
  10492. if ($OE == 'E') {
  10493. $this->saveHTMLFooter[$this->page][$OE]['html'] = $this->HTMLFooterE['html'] ;
  10494. }
  10495. else {
  10496. $this->saveHTMLFooter[$this->page][$OE]['html'] = $this->HTMLFooter['html'] ;
  10497. }
  10498. if ($this->forcePortraitHeaders && $this->CurOrientation=='L' && $this->CurOrientation!=$this->DefOrientation) {
  10499. $this->saveHTMLFooter[$this->page][$OE]['rotate'] = true;
  10500. $this->saveHTMLFooter[$this->page][$OE]['ml'] = $this->tMargin;
  10501. $this->saveHTMLFooter[$this->page][$OE]['mr'] = $this->bMargin;
  10502. $this->saveHTMLFooter[$this->page][$OE]['mt'] = $this->rMargin;
  10503. $this->saveHTMLFooter[$this->page][$OE]['mb'] = $this->lMargin;
  10504. $this->saveHTMLFooter[$this->page][$OE]['mh'] = $this->margin_header;
  10505. $this->saveHTMLFooter[$this->page][$OE]['mf'] = $this->margin_footer;
  10506. $this->saveHTMLFooter[$this->page][$OE]['pw'] = $this->h;
  10507. $this->saveHTMLFooter[$this->page][$OE]['ph'] = $this->w;
  10508. }
  10509. else {
  10510. $this->saveHTMLFooter[$this->page][$OE]['ml'] = $this->lMargin;
  10511. $this->saveHTMLFooter[$this->page][$OE]['mr'] = $this->rMargin;
  10512. $this->saveHTMLFooter[$this->page][$OE]['mt'] = $this->tMargin;
  10513. $this->saveHTMLFooter[$this->page][$OE]['mb'] = $this->bMargin;
  10514. $this->saveHTMLFooter[$this->page][$OE]['mh'] = $this->margin_header;
  10515. $this->saveHTMLFooter[$this->page][$OE]['mf'] = $this->margin_footer;
  10516. $this->saveHTMLFooter[$this->page][$OE]['pw'] = $this->w;
  10517. $this->saveHTMLFooter[$this->page][$OE]['ph'] = $this->h;
  10518. }
  10519. }
  10520. /*-- END HTMLHEADERS-FOOTERS --*/
  10521. function DefHeaderByName($name,$arr) {
  10522. if (!$name) { $name = '_default'; }
  10523. $this->pageheaders[$name] = $arr;
  10524. }
  10525. function DefFooterByName($name,$arr) {
  10526. if (!$name) { $name = '_default'; }
  10527. $this->pagefooters[$name] = $arr;
  10528. }
  10529. function SetHeaderByName($name,$side='O',$write=false) {
  10530. if (!$name) { $name = '_default'; }
  10531. if ($side=='E') { $this->headerDetails['even'] = $this->pageheaders[$name]; }
  10532. else { $this->headerDetails['odd'] = $this->pageheaders[$name]; }
  10533. if ($write) { $this->Header(); }
  10534. }
  10535. function SetFooterByName($name,$side='O') {
  10536. if (!$name) { $name = '_default'; }
  10537. if ($side=='E') { $this->footerDetails['even'] = $this->pagefooters[$name]; }
  10538. else { $this->footerDetails['odd'] = $this->pagefooters[$name]; }
  10539. }
  10540. /*-- HTMLHEADERS-FOOTERS --*/
  10541. function DefHTMLHeaderByName($name,$html) {
  10542. if (!$name) { $name = '_default'; }
  10543. $this->pageHTMLheaders[$name]['html'] = $html;
  10544. $this->pageHTMLheaders[$name]['h'] = $this->_gethtmlheight($html);
  10545. }
  10546. function DefHTMLFooterByName($name,$html) {
  10547. if (!$name) { $name = '_default'; }
  10548. $this->pageHTMLfooters[$name]['html'] = $html;
  10549. $this->pageHTMLfooters[$name]['h'] = $this->_gethtmlheight($html);
  10550. }
  10551. function SetHTMLHeaderByName($name,$side='O',$write=false) {
  10552. if (!$name) { $name = '_default'; }
  10553. $this->SetHTMLHeader($this->pageHTMLheaders[$name],$side,$write);
  10554. }
  10555. function SetHTMLFooterByName($name,$side='O') {
  10556. if (!$name) { $name = '_default'; }
  10557. $this->SetHTMLFooter($this->pageHTMLfooters[$name],$side,$write);
  10558. }
  10559. /*-- END HTMLHEADERS-FOOTERS --*/
  10560. function SetHeader($Harray=array(),$side='',$write=false) {
  10561. if (is_string($Harray)) {
  10562. if (strlen($Harray)==0) {
  10563. if ($side=='O') { $this->headerDetails['odd'] = array(); }
  10564. else if ($side=='E') { $this->headerDetails['even'] = array(); }
  10565. else { $this->headerDetails = array(); }
  10566. }
  10567. else if (strpos($Harray,'|') || strpos($Harray,'|')===0) {
  10568. $hdet = explode('|',$Harray);
  10569. $this->headerDetails = array (
  10570. 'odd' => array (
  10571. 'L' => array ('content' => $hdet[0], 'font-size' => $this->defaultheaderfontsize, 'font-style' => $this->defaultheaderfontstyle),
  10572. 'C' => array ('content' => $hdet[1], 'font-size' => $this->defaultheaderfontsize, 'font-style' => $this->defaultheaderfontstyle),
  10573. 'R' => array ('content' => $hdet[2], 'font-size' => $this->defaultheaderfontsize, 'font-style' => $this->defaultheaderfontstyle),
  10574. 'line' => $this->defaultheaderline,
  10575. ),
  10576. 'even' => array (
  10577. 'R' => array ('content' => $hdet[0], 'font-size' => $this->defaultheaderfontsize, 'font-style' => $this->defaultheaderfontstyle),
  10578. 'C' => array ('content' => $hdet[1], 'font-size' => $this->defaultheaderfontsize, 'font-style' => $this->defaultheaderfontstyle),
  10579. 'L' => array ('content' => $hdet[2], 'font-size' => $this->defaultheaderfontsize, 'font-style' => $this->defaultheaderfontstyle),
  10580. 'line' => $this->defaultheaderline,
  10581. )
  10582. );
  10583. }
  10584. else {
  10585. $this->headerDetails = array (
  10586. 'odd' => array (
  10587. 'R' => array ('content' => $Harray, 'font-size' => $this->defaultheaderfontsize, 'font-style' => $this->defaultheaderfontstyle),
  10588. 'line' => $this->defaultheaderline,
  10589. ),
  10590. 'even' => array (
  10591. 'L' => array ('content' => $Harray, 'font-size' => $this->defaultheaderfontsize, 'font-style' => $this->defaultheaderfontstyle),
  10592. 'line' => $this->defaultheaderline,
  10593. )
  10594. );
  10595. }
  10596. }
  10597. else if (is_array($Harray)) {
  10598. if ($side=='O') { $this->headerDetails['odd'] = $Harray; }
  10599. else if ($side=='E') { $this->headerDetails['even'] = $Harray; }
  10600. else { $this->headerDetails = $Harray; }
  10601. }
  10602. /*-- HTMLHEADERS-FOOTERS --*/
  10603. // Overwrite any HTML Header previously set
  10604. if ($side=='E') { $this->SetHTMLHeader('','E'); }
  10605. else if ($side=='O') { $this->SetHTMLHeader(''); }
  10606. else {
  10607. $this->SetHTMLHeader('');
  10608. $this->SetHTMLHeader('','E');
  10609. }
  10610. /*-- END HTMLHEADERS-FOOTERS --*/
  10611. if ($write) {
  10612. $save_y = $this->y;
  10613. $this->Header();
  10614. $this->SetY($save_y) ;
  10615. }
  10616. }
  10617. function SetFooter($Farray=array(),$side='') {
  10618. if (is_string($Farray)) {
  10619. if (strlen($Farray)==0) {
  10620. if ($side=='O') { $this->footerDetails['odd'] = array(); }
  10621. else if ($side=='E') { $this->footerDetails['even'] = array(); }
  10622. else { $this->footerDetails = array(); }
  10623. }
  10624. else if (strpos($Farray,'|') || strpos($Farray,'|')===0) {
  10625. $fdet = explode('|',$Farray);
  10626. $this->footerDetails = array (
  10627. 'odd' => array (
  10628. 'L' => array ('content' => $fdet[0], 'font-size' => $this->defaultfooterfontsize, 'font-style' => $this->defaultfooterfontstyle),
  10629. 'C' => array ('content' => $fdet[1], 'font-size' => $this->defaultfooterfontsize, 'font-style' => $this->defaultfooterfontstyle),
  10630. 'R' => array ('content' => $fdet[2], 'font-size' => $this->defaultfooterfontsize, 'font-style' => $this->defaultfooterfontstyle),
  10631. 'line' => $this->defaultfooterline,
  10632. ),
  10633. 'even' => array (
  10634. 'R' => array ('content' => $fdet[0], 'font-size' => $this->defaultfooterfontsize, 'font-style' => $this->defaultfooterfontstyle),
  10635. 'C' => array ('content' => $fdet[1], 'font-size' => $this->defaultfooterfontsize, 'font-style' => $this->defaultfooterfontstyle),
  10636. 'L' => array ('content' => $fdet[2], 'font-size' => $this->defaultfooterfontsize, 'font-style' => $this->defaultfooterfontstyle),
  10637. 'line' => $this->defaultfooterline,
  10638. )
  10639. );
  10640. }
  10641. else {
  10642. $this->footerDetails = array (
  10643. 'odd' => array (
  10644. 'R' => array ('content' => $Farray, 'font-size' => $this->defaultfooterfontsize, 'font-style' => $this->defaultfooterfontstyle),
  10645. 'line' => $this->defaultfooterline,
  10646. ),
  10647. 'even' => array (
  10648. 'L' => array ('content' => $Farray, 'font-size' => $this->defaultfooterfontsize, 'font-style' => $this->defaultfooterfontstyle),
  10649. 'line' => $this->defaultfooterline,
  10650. )
  10651. );
  10652. }
  10653. }
  10654. else if (is_array($Farray)) {
  10655. if ($side=='O') { $this->footerDetails['odd'] = $Farray; }
  10656. else if ($side=='E') { $this->footerDetails['even'] = $Farray; }
  10657. else { $this->footerDetails = $Farray; }
  10658. }
  10659. /*-- HTMLHEADERS-FOOTERS --*/
  10660. // Overwrite any HTML Footer previously set
  10661. if ($side=='E') { $this->SetHTMLFooter('','E'); }
  10662. else if ($side=='O') { $this->SetHTMLFooter(''); }
  10663. else {
  10664. $this->SetHTMLFooter('');
  10665. $this->SetHTMLFooter('','E');
  10666. }
  10667. /*-- END HTMLHEADERS-FOOTERS --*/
  10668. }
  10669. /*-- WATERMARK --*/
  10670. function setUnvalidatedText($txt='', $alpha=-1) {
  10671. if ($alpha>=0) $this->watermarkTextAlpha = $alpha;
  10672. $this->watermarkText = $txt;
  10673. }
  10674. function SetWatermarkText($txt='', $alpha=-1) {
  10675. if ($alpha>=0) $this->watermarkTextAlpha = $alpha;
  10676. $this->watermarkText = $txt;
  10677. }
  10678. function SetWatermarkImage($src, $alpha=-1, $size='D', $pos='F') {
  10679. if ($alpha>=0) $this->watermarkImageAlpha = $alpha;
  10680. $this->watermarkImage = $src;
  10681. $this->watermark_size = $size;
  10682. $this->watermark_pos = $pos;
  10683. }
  10684. /*-- END WATERMARK --*/
  10685. //Page footer
  10686. function Footer() {
  10687. /*-- CSS-PAGE --*/
  10688. // PAGED MEDIA - CROP / CROSS MARKS from @PAGE
  10689. if ($this->show_marks == 'CROP' || $this->show_marks == 'CROPCROSS') {
  10690. // Show TICK MARKS
  10691. $this->SetLineWidth(0.1); // = 0.1 mm
  10692. $this->SetDColor($this->ConvertColor(0));
  10693. $l = $this->cropMarkLength;
  10694. $m = $this->cropMarkMargin; // Distance of crop mark from margin
  10695. $b = $this->nonPrintMargin; // Non-printable border at edge of paper sheet
  10696. $ax1 = $b;
  10697. $bx = $this->page_box['outer_width_LR'] - $m;
  10698. $ax = max($ax1, $bx-$l);
  10699. $cx1 = $this->w - $b;
  10700. $dx = $this->w - $this->page_box['outer_width_LR'] + $m;
  10701. $cx = min($cx1, $dx+$l);
  10702. $ay1 = $b;
  10703. $by = $this->page_box['outer_width_TB'] - $m;
  10704. $ay = max($ay1, $by-$l);
  10705. $cy1 = $this->h - $b;
  10706. $dy = $this->h - $this->page_box['outer_width_TB'] + $m;
  10707. $cy = min($cy1, $dy+$l);
  10708. $this->Line($ax, $this->page_box['outer_width_TB'], $bx, $this->page_box['outer_width_TB']);
  10709. $this->Line($cx, $this->page_box['outer_width_TB'], $dx, $this->page_box['outer_width_TB']);
  10710. $this->Line($ax, $this->h - $this->page_box['outer_width_TB'], $bx, $this->h - $this->page_box['outer_width_TB']);
  10711. $this->Line($cx, $this->h - $this->page_box['outer_width_TB'], $dx, $this->h - $this->page_box['outer_width_TB']);
  10712. $this->Line($this->page_box['outer_width_LR'], $ay, $this->page_box['outer_width_LR'], $by);
  10713. $this->Line($this->page_box['outer_width_LR'], $cy, $this->page_box['outer_width_LR'], $dy);
  10714. $this->Line($this->w - $this->page_box['outer_width_LR'], $ay, $this->w - $this->page_box['outer_width_LR'], $by);
  10715. $this->Line($this->w - $this->page_box['outer_width_LR'], $cy, $this->w - $this->page_box['outer_width_LR'], $dy);
  10716. if ($this->printers_info) {
  10717. $hd = date('Y-m-d H:i').' Page '.$this->page.' of {nb}';
  10718. $this->SetTColor($this->ConvertColor(0));
  10719. $this->SetFont('arial','',7.5,true,true);
  10720. $this->x = $this->page_box['outer_width_LR'] + 1.5;
  10721. $this->y = 1;
  10722. $this->Cell($headerpgwidth ,$this->FontSize,$hd,0,0,'L',0,'',0,0,0,'M');
  10723. $this->SetFont($this->default_font,'',$this->original_default_font_size);
  10724. }
  10725. }
  10726. if ($this->show_marks == 'CROSS' || $this->show_marks == 'CROPCROSS') {
  10727. $this->SetLineWidth(0.1); // = 0.1 mm
  10728. $this->SetDColor($this->ConvertColor(0));
  10729. $l = 14 /2; // longer length of the cross line (half)
  10730. $w = 6 /2; // shorter width of the cross line (half)
  10731. $r = 1.2; // radius of circle
  10732. $m = $this->crossMarkMargin; // Distance of cross mark from margin
  10733. $x1 = $this->page_box['outer_width_LR'] - $m;
  10734. $x2 = $this->w - $this->page_box['outer_width_LR'] + $m;
  10735. $y1 = $this->page_box['outer_width_TB'] - $m;
  10736. $y2 = $this->h - $this->page_box['outer_width_TB'] + $m;
  10737. // Left
  10738. $this->Circle($x1, $this->h/2, $r, 'S') ;
  10739. $this->Line($x1-$w, $this->h/2, $x1+$w, $this->h/2);
  10740. $this->Line($x1, $this->h/2-$l, $x1, $this->h/2+$l);
  10741. // Right
  10742. $this->Circle($x2, $this->h/2, $r, 'S') ;
  10743. $this->Line($x2-$w, $this->h/2, $x2+$w, $this->h/2);
  10744. $this->Line($x2, $this->h/2-$l, $x2, $this->h/2+$l);
  10745. // Top
  10746. $this->Circle($this->w/2, $y1, $r, 'S') ;
  10747. $this->Line($this->w/2, $y1-$w, $this->w/2, $y1+$w);
  10748. $this->Line($this->w/2-$l, $y1, $this->w/2+$l, $y1);
  10749. // Bottom
  10750. $this->Circle($this->w/2, $y2, $r, 'S') ;
  10751. $this->Line($this->w/2, $y2-$w, $this->w/2, $y2+$w);
  10752. $this->Line($this->w/2-$l, $y2, $this->w/2+$l, $y2);
  10753. }
  10754. // If @page set non-HTML headers/footers named, they were not read until later in the HTML code - so now set them
  10755. if ($this->page==1) {
  10756. if ($this->firstPageBoxHeader) {
  10757. $this->headerDetails['odd'] = $this->pageheaders[$this->firstPageBoxHeader];
  10758. $this->Header();
  10759. }
  10760. if ($this->firstPageBoxFooter) {
  10761. $this->footerDetails['odd'] = $this->pagefooters[$this->firstPageBoxFooter];
  10762. }
  10763. $this->firstPageBoxHeader='';
  10764. $this->firstPageBoxFooter='';
  10765. }
  10766. /*-- END CSS-PAGE --*/
  10767. /*-- HTMLHEADERS-FOOTERS --*/
  10768. if (($this->mirrorMargins && ($this->page%2==0) && $this->HTMLFooterE) || ($this->mirrorMargins && ($this->page%2==1) && $this->HTMLFooter) || (!$this->mirrorMargins && $this->HTMLFooter)) {
  10769. $this->writeHTMLFooters();
  10770. /*-- WATERMARK --*/
  10771. if (($this->watermarkText) && ($this->showWatermarkText)) {
  10772. $this->watermark( $this->watermarkText, 45, 120, $this->watermarkTextAlpha); // Watermark text
  10773. }
  10774. if (($this->watermarkImage) && ($this->showWatermarkImage)) {
  10775. $this->watermarkImg( $this->watermarkImage, $this->watermarkImageAlpha); // Watermark image
  10776. }
  10777. /*-- END WATERMARK --*/
  10778. return;
  10779. }
  10780. /*-- END HTMLHEADERS-FOOTERS --*/
  10781. $this->processingHeader=true;
  10782. $this->ResetMargins(); // necessary after columns
  10783. $this->pgwidth = $this->w - $this->lMargin - $this->rMargin;
  10784. /*-- WATERMARK --*/
  10785. if (($this->watermarkText) && ($this->showWatermarkText)) {
  10786. $this->watermark( $this->watermarkText, 45, 120, $this->watermarkTextAlpha); // Watermark text
  10787. }
  10788. if (($this->watermarkImage) && ($this->showWatermarkImage)) {
  10789. $this->watermarkImg( $this->watermarkImage, $this->watermarkImageAlpha); // Watermark image
  10790. }
  10791. /*-- END WATERMARK --*/
  10792. $h = $this->footerDetails;
  10793. if(count($h)) {
  10794. if ($this->forcePortraitHeaders && $this->CurOrientation=='L' && $this->CurOrientation!=$this->DefOrientation) {
  10795. $this->_out(sprintf('q 0 -1 1 0 0 %.3F cm ',($this->h*_MPDFK)));
  10796. $headerpgwidth = $this->h - $this->orig_lMargin - $this->orig_rMargin;
  10797. if (($this->mirrorMargins) && (($this->page)%2==0)) { // EVEN
  10798. $headerlmargin = $this->orig_rMargin;
  10799. }
  10800. else {
  10801. $headerlmargin = $this->orig_lMargin;
  10802. }
  10803. }
  10804. else {
  10805. $yadj = 0;
  10806. $headerpgwidth = $this->pgwidth;
  10807. $headerlmargin = $this->lMargin;
  10808. }
  10809. $this->SetY(-$this->margin_footer);
  10810. $this->SetTColor($this->ConvertColor(0));
  10811. $this->SUP = false;
  10812. $this->SUB = false;
  10813. $this->bullet = false;
  10814. // only show pagenumber if numbering on
  10815. $pgno = $this->docPageNum($this->page, true);
  10816. if (($this->mirrorMargins) && (($this->page)%2==0)) { // EVEN
  10817. $side = 'even';
  10818. }
  10819. else { // ODD // OR NOT MIRRORING MARGINS/FOOTERS = DEFAULT
  10820. $side = 'odd';
  10821. }
  10822. $maxfontheight = 0;
  10823. foreach(array('L','C','R') AS $pos) {
  10824. if (isset($h[$side][$pos]['content']) && $h[$side][$pos]['content']) {
  10825. if (isset($h[$side][$pos]['font-size']) && $h[$side][$pos]['font-size']) { $hfsz = $h[$side][$pos]['font-size']; }
  10826. else { $hfsz = $this->default_font_size; }
  10827. $maxfontheight = max($maxfontheight,$hfsz);
  10828. }
  10829. }
  10830. // LEFT-CENTER-RIGHT
  10831. foreach(array('L','C','R') AS $pos) {
  10832. if (isset($h[$side][$pos]['content']) && $h[$side][$pos]['content']) {
  10833. $hd = str_replace('{PAGENO}',$pgno,$h[$side][$pos]['content']);
  10834. $hd = str_replace($this->aliasNbPgGp,$this->nbpgPrefix.$this->aliasNbPgGp.$this->nbpgSuffix,$hd);
  10835. $hd = preg_replace('/\{DATE\s+(.*?)\}/e',"date('\\1')",$hd);
  10836. if (isset($h[$side][$pos]['font-family']) && $h[$side][$pos]['font-family']) { $hff = $h[$side][$pos]['font-family']; }
  10837. else { $hff = $this->original_default_font; }
  10838. if (isset($h[$side][$pos]['font-size']) && $h[$side][$pos]['font-size']) { $hfsz = $h[$side][$pos]['font-size']; }
  10839. else { $hfsz = $this->original_default_font_size; }
  10840. $maxfontheight = max($maxfontheight,$hfsz);
  10841. if (isset($h[$side][$pos]['font-style']) && $h[$side][$pos]['font-style']) { $hfst = $h[$side][$pos]['font-style']; }
  10842. else { $hfst = ''; }
  10843. if (isset($h[$side][$pos]['color']) && $h[$side][$pos]['color']) {
  10844. $hfcol = $h[$side][$pos]['color'];
  10845. $cor = $this->ConvertColor($hfcol);
  10846. if ($cor) { $this->SetTColor($cor); }
  10847. }
  10848. else { $hfcol = ''; }
  10849. $this->SetFont($hff,$hfst,$hfsz,true,true);
  10850. $this->x = $headerlmargin ;
  10851. $this->y = $this->h - $this->margin_footer - ($maxfontheight/_MPDFK);
  10852. $hd = $this->purify_utf8_text($hd);
  10853. if ($this->text_input_as_HTML) {
  10854. $hd = $this->all_entities_to_utf8($hd);
  10855. }
  10856. // CONVERT CODEPAGE
  10857. if ($this->usingCoreFont) { $hd = mb_convert_encoding($hd,$this->mb_enc,'UTF-8'); }
  10858. // DIRECTIONALITY RTL
  10859. $this->magic_reverse_dir($hd, true, $this->directionality); // *RTL*
  10860. // Font-specific ligature substitution for Indic fonts
  10861. if (isset($this->CurrentFont['indic']) && $this->CurrentFont['indic']) $this->ConvertIndic($hd); // *INDIC*
  10862. $align = $pos;
  10863. if ($this->directionality == 'rtl') {
  10864. if ($pos == 'L') { $align = 'R'; }
  10865. else if ($pos == 'R') { $align = 'L'; }
  10866. }
  10867. if ($pos!='L' && (strpos($hd,$this->aliasNbPg)!==false || strpos($hd,$this->aliasNbPgGp)!==false)) {
  10868. if (strpos($hd,$this->aliasNbPgGp)!==false) { $type= 'nbpggp'; } else { $type= 'nbpg'; }
  10869. $this->_out('{mpdfheader'.$type.' '.$pos.' ff='.$hff.' fs='.$hfst.' fz='.$hfsz.'}');
  10870. $this->Cell($headerpgwidth ,$maxfontheight/_MPDFK ,$hd,0,0,$align,0,'',0,0,0,'M');
  10871. $this->_out('Q');
  10872. }
  10873. else {
  10874. $this->Cell($headerpgwidth ,$maxfontheight/_MPDFK ,$hd,0,0,$align,0,'',0,0,0,'M');
  10875. }
  10876. if ($hfcol) { $this->SetTColor($this->ConvertColor(0)); }
  10877. }
  10878. }
  10879. // Return Font to normal
  10880. $this->SetFont($this->default_font,'',$this->original_default_font_size);
  10881. // LINE
  10882. if (isset($h[$side]['line']) && $h[$side]['line']) {
  10883. $this->SetLineWidth(0.1);
  10884. $this->SetDColor($this->ConvertColor(0));
  10885. $this->Line($headerlmargin , $this->y-($maxfontheight*($this->footer_line_spacing)/_MPDFK), $headerlmargin +$headerpgwidth, $this->y-($maxfontheight*($this->footer_line_spacing)/_MPDFK));
  10886. }
  10887. if ($this->forcePortraitHeaders && $this->CurOrientation=='L' && $this->CurOrientation!=$this->DefOrientation) {
  10888. $this->_out('Q');
  10889. }
  10890. }
  10891. $this->processingHeader=false;
  10892. }
  10893. /*-- HYPHENATION --*/
  10894. ///////////////////
  10895. ///////////////////
  10896. // HYPHENATION
  10897. ///////////////////
  10898. // Soft hyphs
  10899. function softHyphenate($word, $maxWidth) {
  10900. // Don't hyphenate web addresses
  10901. if (preg_match('/^(http:|www\.)/',$word)) { return array(false,'','',''); }
  10902. // Get dictionary
  10903. $poss = array();
  10904. $softhyphens = array();
  10905. $offset = 0;
  10906. $p = true;
  10907. if ($this->usingCoreFont) {
  10908. $wl = strlen($word);
  10909. }
  10910. else {
  10911. $wl = mb_strlen($word,'UTF-8');
  10912. }
  10913. while($offset < $wl) {
  10914. // Soft Hyphens chr(173)
  10915. if (!$this->usingCoreFont) {
  10916. $p = mb_strpos($word, "\xc2\xad", $offset, 'UTF-8');
  10917. }
  10918. else if ($this->FontFamily!='csymbol' && $this->FontFamily!='czapfdingbats') {
  10919. $p = strpos($word, chr(173), $offset);
  10920. }
  10921. if ($p !== false) { $poss[] = $p - count($poss); }
  10922. else { break; }
  10923. $offset = $p+1;
  10924. }
  10925. $success = false;
  10926. foreach($poss AS $i) {
  10927. if ($this->usingCoreFont) {
  10928. $a = substr($word,0,$i);
  10929. if ($this->GetStringWidth($a.'-') > $maxWidth) { break ; }
  10930. $pre = $a;
  10931. $post = substr($word,$i,strlen($word));
  10932. $prelength = strlen($pre);
  10933. }
  10934. else {
  10935. $a = mb_substr($word,0,$i,'UTF-8');
  10936. if ($this->GetStringWidth($a.'-') > $maxWidth) { break ; }
  10937. $pre = $a;
  10938. $post = mb_substr($word,$i,mb_strlen($word,'UTF-8'),'UTF-8');
  10939. $prelength = mb_strlen($pre, 'UTF-8');
  10940. }
  10941. $success = true;
  10942. }
  10943. return array($success,$pre,$post,$prelength);
  10944. }
  10945. ///////////////////
  10946. // Word hyphenation
  10947. function hyphenateWord($word, $maxWidth) {
  10948. // Do everything inside this function in utf-8
  10949. // Don't hyphenate web addresses
  10950. if (preg_match('/^(http:|www\.)/',$word)) { return array(false,'','',''); }
  10951. // Get dictionary
  10952. if (!$this->loadedSHYdictionary) {
  10953. if (file_exists(_MPDF_PATH.'patterns/dictionary.txt')) {
  10954. $this->SHYdictionary = file(_MPDF_PATH.'patterns/dictionary.txt',FILE_SKIP_EMPTY_LINES);
  10955. foreach($this->SHYdictionary as $entry) {
  10956. $entry = trim($entry);
  10957. $poss = array();
  10958. $offset = 0;
  10959. $p = true;
  10960. $wl = mb_strlen($entry ,'UTF-8');
  10961. while($offset < $wl) {
  10962. $p = mb_strpos($entry, '/', $offset, 'UTF-8');
  10963. if ($p !== false) { $poss[] = $p - count($poss); }
  10964. else { break; }
  10965. $offset = $p+1;
  10966. }
  10967. if (count($poss)) { $this->SHYdictionaryWords[str_replace('/', '', mb_strtolower($entry))] = $poss; }
  10968. }
  10969. }
  10970. $this->loadedSHYdictionary = true;
  10971. }
  10972. if (!in_array($this->SHYlang,$this->SHYlanguages)) { return array(false,'','',''); }
  10973. // If no pattern loaded or not the best one
  10974. if (count($this->SHYpatterns) < 1 || ($this->loadedSHYpatterns && $this->loadedSHYpatterns != $this->SHYlang)) {
  10975. include(_MPDF_PATH."patterns/" . $this->SHYlang . ".php");
  10976. $patterns = explode(' ', $patterns);
  10977. $new_patterns = array();
  10978. for($i = 0; $i < count($patterns); $i++) {
  10979. $value = $patterns[$i];
  10980. $new_patterns[preg_replace('/[0-9]/', '', $value)] = $value;
  10981. }
  10982. $this->SHYpatterns = $new_patterns;
  10983. $this->loadedSHYpatterns = $this->SHYlang;
  10984. }
  10985. if ($this->usingCoreFont) { $word = mb_convert_encoding($word,'UTF-8',$this->mb_enc); }
  10986. $prepre = '';
  10987. $postpost = '';
  10988. $startpunctuation = "\xc2\xab\xc2\xbf\xe2\x80\x98\xe2\x80\x9b\xe2\x80\x9c\xe2\x80\x9f";
  10989. $endpunctuation = "\xe2\x80\x9e\xe2\x80\x9d\xe2\x80\x9a\xe2\x80\x99\xc2\xbb";
  10990. $pre = '';
  10991. $post = '';
  10992. if (preg_match('/^(["\''.$startpunctuation .'])+(.{'.$this->SHYcharmin.',})$/u',$word,$m)) {
  10993. $prepre = $m[1];
  10994. $word = $m[2];
  10995. }
  10996. if (preg_match('/^(.{'.$this->SHYcharmin.',})([\'\.,;:!?"'.$endpunctuation .']+)$/u',$word,$m)) {
  10997. $word = $m[1];
  10998. $postpost = $m[2];
  10999. }
  11000. if(mb_strlen($word,'UTF-8') < $this->SHYcharmin) {
  11001. return array(false,'','','');
  11002. }
  11003. $success = false;
  11004. if(isset($this->SHYdictionaryWords[mb_strtolower($word)])) {
  11005. foreach($this->SHYdictionaryWords[mb_strtolower($word)] AS $i) {
  11006. $a = $prepre . mb_substr($word,0,$i,'UTF-8');
  11007. if ($this->usingCoreFont) { $testa = mb_convert_encoding($a,$this->mb_enc,'UTF-8'); }
  11008. else { $testa = $a; }
  11009. if ($this->GetStringWidth($testa.'-') > $maxWidth) { break ; }
  11010. $pre = $a;
  11011. $post = mb_substr($word,$i,mb_strlen($word,'UTF-8'),'UTF-8') . $postpost;
  11012. $success = true;
  11013. }
  11014. }
  11015. if (!$success) {
  11016. $text_word = '_' . $word . '_';
  11017. $word_length = mb_strlen($text_word,'UTF-8');
  11018. $single_character = preg_split('//u', $text_word);
  11019. $text_word = mb_strtolower($text_word,'UTF-8');
  11020. $hyphenated_word = array();
  11021. $numb3rs = array('0' => true, '1' => true, '2' => true, '3' => true, '4' => true, '5' => true, '6' => true, '7' => true, '8' => true, '9' => true);
  11022. for($position = 0; $position <= ($word_length - $this->SHYcharmin); $position++) {
  11023. $maxwins = min(($word_length - $position), $this->SHYcharmax);
  11024. for($win = $this->SHYcharmin; $win <= $maxwins; $win++) {
  11025. if(isset($this->SHYpatterns[mb_substr($text_word, $position, $win,'UTF-8')])) {
  11026. $pattern = $this->SHYpatterns[mb_substr($text_word, $position, $win,'UTF-8')];
  11027. $digits = 1;
  11028. $pattern_length = mb_strlen($pattern,'UTF-8');
  11029. for($i = 0; $i < $pattern_length; $i++) {
  11030. $char = $pattern[$i];
  11031. if(isset($numb3rs[$char])) {
  11032. $zero = ($i == 0) ? $position - 1 : $position + $i - $digits;
  11033. if(!isset($hyphenated_word[$zero]) || $hyphenated_word[$zero] != $char) $hyphenated_word[$zero] = $char;
  11034. $digits++;
  11035. }
  11036. }
  11037. }
  11038. }
  11039. }
  11040. for($i = $this->SHYleftmin; $i <= (mb_strlen($word,'UTF-8') - $this->SHYrightmin); $i++) {
  11041. if(isset($hyphenated_word[$i]) && $hyphenated_word[$i] % 2 != 0) {
  11042. $a = $prepre . mb_substr($word,0,$i,'UTF-8');
  11043. if ($this->usingCoreFont) { $testa = mb_convert_encoding($a,$this->mb_enc,'UTF-8'); }
  11044. else { $testa = $a; }
  11045. if ($this->GetStringWidth($testa.'-') > $maxWidth + 0.0001) { break ; }
  11046. $pre = $a;
  11047. $post = mb_substr($word,$i,mb_strlen($word,'UTF-8'),'UTF-8') . $postpost;
  11048. $success = true;
  11049. }
  11050. }
  11051. }
  11052. if ($this->usingCoreFont) {
  11053. $pre = mb_convert_encoding($pre,$this->mb_enc,'UTF-8');
  11054. $post = mb_convert_encoding($post,$this->mb_enc,'UTF-8');
  11055. $prelength = strlen($pre);
  11056. }
  11057. else {
  11058. $prelength = mb_strlen($pre);
  11059. }
  11060. return array($success,$pre,$post,$prelength);
  11061. }
  11062. /*-- END HYPHENATION --*/
  11063. /*-- HTML-CSS --*/
  11064. ///////////////////
  11065. /// HTML parser ///
  11066. ///////////////////
  11067. function WriteHTML($html,$sub=0,$init=true,$close=true) {
  11068. // $sub ADDED - 0 = default; 1=headerCSS only; 2=HTML body (parts) only; 3 - HTML parses only
  11069. // 4 - writes HTML headers
  11070. // $close Leaves buffers etc. in current state, so that it can continue a block etc.
  11071. // $init - Clears and sets buffers to Top level block etc.
  11072. if (empty($html)) { $html = ''; }
  11073. if ($this->progressBar) { $this->UpdateProgressBar(1,0,'Parsing CSS & Headers'); } // *PROGRESS-BAR*
  11074. if ($init) {
  11075. $this->headerbuffer='';
  11076. $this->textbuffer = array();
  11077. $this->fixedPosBlockSave = array();
  11078. }
  11079. if ($sub == 1) { $html = '<style> '.$html.' </style>'; } // stylesheet only
  11080. if ($this->allow_charset_conversion) {
  11081. if ($sub < 1) {
  11082. $this->ReadCharset($html);
  11083. }
  11084. if ($this->charset_in && $sub!=4) { // mPDF 5.4.14
  11085. $success = iconv($this->charset_in,'UTF-8//TRANSLIT',$html);
  11086. if ($success) { $html = $success; }
  11087. }
  11088. }
  11089. $html = $this->purify_utf8($html,false);
  11090. if ($init) {
  11091. $this->blklvl = 0;
  11092. $this->lastblocklevelchange = 0;
  11093. $this->blk = array();
  11094. $this->initialiseBlock($this->blk[0]);
  11095. $this->blk[0]['width'] =& $this->pgwidth;
  11096. $this->blk[0]['inner_width'] =& $this->pgwidth;
  11097. $this->blk[0]['blockContext'] = $this->blockContext;
  11098. }
  11099. $zproperties = array();
  11100. if ($sub < 2) {
  11101. $this->ReadMetaTags($html);
  11102. // NB default stylesheet now in mPDF.css - read on initialising class
  11103. $html = $this->ReadCSS($html);
  11104. if ($this->useLang && !$this->usingCoreFont && preg_match('/<html [^>]*lang=[\'\"](.*?)[\'\"]/ism',$html,$m)) {
  11105. $html_lang = $m[1];
  11106. }
  11107. if (preg_match('/<html [^>]*dir=[\'\"]\s*rtl\s*[\'\"]/ism',$html)) {
  11108. $zproperties['DIRECTION'] = 'rtl';
  11109. }
  11110. // allow in-line CSS for body tag to be parsed // Get <body> tag inline CSS
  11111. if (preg_match('/<body([^>]*)>(.*?)<\/body>/ism',$html,$m) || preg_match('/<body([^>]*)>(.*)$/ism',$html,$m)) {
  11112. $html = $m[2];
  11113. // Changed to allow style="background: url('bg.jpg')"
  11114. if (preg_match('/style=[\"](.*?)[\"]/ism',$m[1],$mm) || preg_match('/style=[\'](.*?)[\']/ism',$m[1],$mm)) {
  11115. $zproperties = $this->readInlineCSS($mm[1]);
  11116. }
  11117. if (preg_match('/dir=[\'\"]\s*rtl\s*[\'\"]/ism',$m[1])) {
  11118. $zproperties['DIRECTION'] = 'rtl';
  11119. }
  11120. if (isset($html_lang) && $html_lang) { $zproperties['LANG'] = $html_lang; }
  11121. if ($this->useLang && !$this->onlyCoreFonts && preg_match('/lang=[\'\"](.*?)[\'\"]/ism',$m[1],$mm)) {
  11122. $zproperties['LANG'] = $mm[1];
  11123. }
  11124. }
  11125. }
  11126. $properties = $this->MergeCSS('BLOCK','BODY','');
  11127. if ($zproperties) { $properties = $this->array_merge_recursive_unique($properties,$zproperties); }
  11128. if (isset($properties['DIRECTION']) && $properties['DIRECTION']) {
  11129. $this->CSS['BODY']['DIRECTION'] = $properties['DIRECTION'];
  11130. }
  11131. if (!isset($this->CSS['BODY']['DIRECTION'])) {
  11132. $this->CSS['BODY']['DIRECTION'] = $this->directionality;
  11133. }
  11134. else { $this->SetDirectionality($this->CSS['BODY']['DIRECTION']); }
  11135. $this->setCSS($properties,'','BODY');
  11136. $this->blk[0]['InlineProperties'] = $this->saveInlineProperties();
  11137. if ($sub == 1) { return ''; }
  11138. if (!isset($this->CSS['BODY'])) { $this->CSS['BODY'] = array(); }
  11139. /*-- BACKGROUNDS --*/
  11140. if (isset($properties['BACKGROUND-GRADIENT'])) {
  11141. $this->bodyBackgroundGradient = $properties['BACKGROUND-GRADIENT'];
  11142. }
  11143. if (isset($properties['BACKGROUND-IMAGE']) && $properties['BACKGROUND-IMAGE']) {
  11144. $ret = $this->SetBackground($properties, $this->pgwidth);
  11145. if ($ret) { $this->bodyBackgroundImage = $ret; }
  11146. }
  11147. /*-- END BACKGROUNDS --*/
  11148. /*-- CSS-PAGE --*/
  11149. // If page-box is set
  11150. if ($this->state==0 && isset($this->CSS['@PAGE']) && $this->CSS['@PAGE'] ) {
  11151. $this->page_box['current'] = '';
  11152. $this->page_box['using'] = true;
  11153. list($pborientation,$pbmgl,$pbmgr,$pbmgt,$pbmgb,$pbmgh,$pbmgf,$hname,$fname,$bg,$resetpagenum,$pagenumstyle,$suppress,$marks,$newformat) = $this->SetPagedMediaCSS('', false, 'O');
  11154. $this->DefOrientation = $this->CurOrientation = $pborientation;
  11155. $this->orig_lMargin = $this->DeflMargin = $pbmgl;
  11156. $this->orig_rMargin = $this->DefrMargin = $pbmgr;
  11157. $this->orig_tMargin = $this->tMargin = $pbmgt;
  11158. $this->orig_bMargin = $this->bMargin = $pbmgb;
  11159. $this->orig_hMargin = $this->margin_header = $pbmgh;
  11160. $this->orig_fMargin = $this->margin_footer = $pbmgf;
  11161. list($pborientation,$pbmgl,$pbmgr,$pbmgt,$pbmgb,$pbmgh,$pbmgf,$hname,$fname,$bg,$resetpagenum,$pagenumstyle,$suppress,$marks,$newformat) = $this->SetPagedMediaCSS('', true, 'O'); // first page
  11162. $this->show_marks = $marks;
  11163. if ($hname && !preg_match('/^html_(.*)$/i',$hname)) $this->firstPageBoxHeader = $hname;
  11164. if ($fname && !preg_match('/^html_(.*)$/i',$fname)) $this->firstPageBoxFooter = $fname;
  11165. }
  11166. /*-- END CSS-PAGE --*/
  11167. $parseonly = false;
  11168. $this->bufferoutput = false;
  11169. if ($sub == 3) {
  11170. $parseonly = true;
  11171. // Close any open block tags
  11172. for ($b= $this->blklvl;$b>0;$b--) { $this->CloseTag($this->blk[$b]['tag']); }
  11173. // Output any text left in buffer
  11174. if (count($this->textbuffer)) { $this->printbuffer($this->textbuffer); }
  11175. $this->textbuffer=array();
  11176. }
  11177. else if ($sub == 4) {
  11178. // Close any open block tags
  11179. for ($b= $this->blklvl;$b>0;$b--) { $this->CloseTag($this->blk[$b]['tag']); }
  11180. // Output any text left in buffer
  11181. if (count($this->textbuffer)) { $this->printbuffer($this->textbuffer); }
  11182. $this->bufferoutput = true;
  11183. $this->textbuffer=array();
  11184. $this->headerbuffer='';
  11185. $properties = $this->MergeCSS('BLOCK','BODY','');
  11186. $this->setCSS($properties,'','BODY');
  11187. }
  11188. mb_internal_encoding('UTF-8');
  11189. $html = $this->AdjustHTML($html, $this->tabSpaces); //Try to make HTML look more like XHTML
  11190. if ($this->autoFontGroups) { $html = $this->AutoFont($html); }
  11191. /*-- HTMLHEADERS-FOOTERS --*/
  11192. preg_match_all('/<htmlpageheader([^>]*)>(.*?)<\/htmlpageheader>/si',$html,$h);
  11193. for($i=0;$i<count($h[1]);$i++) {
  11194. if (preg_match('/name=[\'|\"](.*?)[\'|\"]/',$h[1][$i],$n)) {
  11195. $this->pageHTMLheaders[$n[1]]['html'] = $h[2][$i];
  11196. $this->pageHTMLheaders[$n[1]]['h'] = $this->_gethtmlheight($h[2][$i]);
  11197. }
  11198. }
  11199. preg_match_all('/<htmlpagefooter([^>]*)>(.*?)<\/htmlpagefooter>/si',$html,$f);
  11200. for($i=0;$i<count($f[1]);$i++) {
  11201. if (preg_match('/name=[\'|\"](.*?)[\'|\"]/',$f[1][$i],$n)) {
  11202. $this->pageHTMLfooters[$n[1]]['html'] = $f[2][$i];
  11203. $this->pageHTMLfooters[$n[1]]['h'] = $this->_gethtmlheight($f[2][$i]);
  11204. }
  11205. }
  11206. /*-- END HTMLHEADERS-FOOTERS --*/
  11207. $html = preg_replace('/<htmlpageheader.*?<\/htmlpageheader>/si','',$html);
  11208. $html = preg_replace('/<htmlpagefooter.*?<\/htmlpagefooter>/si','',$html);
  11209. if($this->state==0 && $sub!=1 && $sub!=3 && $sub!=4) {
  11210. $this->AddPage($this->CurOrientation);
  11211. }
  11212. /*-- HTMLHEADERS-FOOTERS --*/
  11213. if (isset($hname) && preg_match('/^html_(.*)$/i',$hname,$n)) $this->SetHTMLHeader($this->pageHTMLheaders[$n[1]],'O',true);
  11214. if (isset($fname) && preg_match('/^html_(.*)$/i',$fname,$n)) $this->SetHTMLFooter($this->pageHTMLfooters[$n[1]],'O');
  11215. /*-- END HTMLHEADERS-FOOTERS --*/
  11216. $html=str_replace('<?','< ',$html); //Fix '<?XML' bug from HTML code generated by MS Word
  11217. $this->checkSIP = false;
  11218. $this->checkSMP = false;
  11219. $this->checkCJK = false;
  11220. if ($this->onlyCoreFonts) { $html = $this->SubstituteChars($html); }
  11221. else {
  11222. if (preg_match("/([".$this->pregRTLchars."])/u", $html)) { $this->biDirectional = true; } // *RTL*
  11223. if (preg_match("/([\x{20000}-\x{2FFFF}])/u", $html)) { $this->checkSIP = true; }
  11224. if (preg_match("/([\x{10000}-\x{1FFFF}])/u", $html)) { $this->checkSMP = true; }
  11225. /*-- CJK-FONTS --*/
  11226. if (preg_match("/([".$this->pregCJKchars."])/u", $html)) { $this->checkCJK = true; }
  11227. /*-- END CJK-FONTS --*/
  11228. }
  11229. // Don't allow non-breaking spaces that are converted to substituted chars or will break anyway and mess up table width calc.
  11230. $html = str_replace('<tta>160</tta>',chr(32),$html);
  11231. $html = str_replace('</tta><tta>','|',$html);
  11232. $html = str_replace('</tts><tts>','|',$html);
  11233. $html = str_replace('</ttz><ttz>','|',$html);
  11234. //Add new supported tags in the DisableTags function
  11235. $html=strip_tags($html,$this->enabledtags); //remove all unsupported tags, but the ones inside the 'enabledtags' string
  11236. //Explode the string in order to parse the HTML code
  11237. $a=preg_split('/<(.*?)>/ms',$html,-1,PREG_SPLIT_DELIM_CAPTURE);
  11238. // ? more accurate regexp that allows e.g. <a name="Silly <name>">
  11239. // if changing - also change in fn.SubstituteChars()
  11240. // $a = preg_split ('/<((?:[^<>]+(?:"[^"]*"|\'[^\']*\')?)+)>/ms', $html, -1, PREG_SPLIT_DELIM_CAPTURE);
  11241. if ($this->mb_enc) {
  11242. mb_internal_encoding($this->mb_enc);
  11243. }
  11244. $pbc = 0;
  11245. if ($this->progressBar) { $this->UpdateProgressBar(1,0); } // *PROGRESS-BAR*
  11246. $this->subPos = -1;
  11247. $cnt = count($a);
  11248. for($i=0;$i<$cnt; $i++) {
  11249. $e = $a[$i];
  11250. if($i%2==0) {
  11251. //TEXT
  11252. if ($this->blk[$this->blklvl]['hide']) { continue; }
  11253. if ($this->inlineDisplayOff) { continue; }
  11254. if ($this->inMeter) { continue; } // mPDF 5.5.09
  11255. if ($this->inFixedPosBlock) { $this->fixedPosBlock .= $e; continue; } // *CSS-POSITION*
  11256. if (strlen($e) == 0) { continue; }
  11257. $e = strcode2utf($e);
  11258. $e = $this->lesser_entity_decode($e);
  11259. if ($this->usingCoreFont) {
  11260. // If core font is selected in document which is not onlyCoreFonts - substitute with non-core font
  11261. if ($this->useSubstitutions && !$this->onlyCoreFonts && $this->subPos<$i && !$this->specialcontent) {
  11262. $cnt += $this->SubstituteCharsNonCore($a, $i, $e);
  11263. }
  11264. // CONVERT ENCODING
  11265. $e = mb_convert_encoding($e,$this->mb_enc,'UTF-8');
  11266. if ($this->toupper) { $e = strtoupper($e); }
  11267. if ($this->tolower) { $e = strtolower($e); }
  11268. if ($this->capitalize) { $e = ucwords($e); }
  11269. }
  11270. else {
  11271. if ($this->checkSIP && $this->CurrentFont['sipext'] && $this->subPos<$i && !$this->specialcontent) {
  11272. $cnt += $this->SubstituteCharsSIP($a, $i, $e);
  11273. }
  11274. if ($this->useSubstitutions && !$this->onlyCoreFonts && $this->CurrentFont['type']!='Type0' && $this->subPos<$i && !$this->specialcontent) {
  11275. $cnt += $this->SubstituteCharsMB($a, $i, $e);
  11276. }
  11277. if ($this->biDirectional) { // *RTL*
  11278. $e = preg_replace("/([".$this->pregRTLchars."]+)/ue", '$this->ArabJoin(stripslashes(\'\\1\'))', $e); // *RTL*
  11279. // mPDF 5.4.05 removes U+200E/U+200F LTR and RTL mark
  11280. // mPDF 5.4.06 removes U+200C/U+200D Zero-width Joiner and Non-joiner
  11281. $e = preg_replace("/[\xe2\x80\x8c\xe2\x80\x8d\xe2\x80\x8e\xe2\x80\x8f]/u",'',$e);
  11282. } // *RTL*
  11283. // Font-specific ligature substitution for Indic fonts
  11284. if (isset($this->CurrentFont['indic']) && $this->CurrentFont['indic']) $this->ConvertIndic($e); // *INDIC*
  11285. if ($this->toupper) { $e = mb_strtoupper($e,$this->mb_enc); }
  11286. if ($this->tolower) { $e = mb_strtolower($e,$this->mb_enc); }
  11287. if ($this->capitalize) { $e = mb_convert_case($e, MB_CASE_TITLE, "UTF-8"); }
  11288. }
  11289. if (($this->tts) || ($this->ttz) || ($this->tta)) {
  11290. $es = explode('|',$e);
  11291. $e = '';
  11292. foreach($es AS $val) {
  11293. $e .= chr($val);
  11294. }
  11295. }
  11296. //Adjust lineheight
  11297. // FORM ELEMENTS
  11298. if ($this->specialcontent) {
  11299. /*-- FORMS --*/
  11300. //SELECT tag (form element)
  11301. if ($this->specialcontent == "type=select") {
  11302. $e = ltrim($e);
  11303. $stringwidth = $this->GetStringWidth($e);
  11304. if (!isset($this->selectoption['MAXWIDTH']) || $stringwidth > $this->selectoption['MAXWIDTH']) { $this->selectoption['MAXWIDTH'] = $stringwidth; }
  11305. if (!isset($this->selectoption['SELECTED']) || $this->selectoption['SELECTED'] == '') { $this->selectoption['SELECTED'] = $e; }
  11306. // mPDD 1.4 Active Forms
  11307. if (isset($this->selectoption['ACTIVE']) && $this->selectoption['ACTIVE']) {
  11308. $this->selectoption['ITEMS'][]=array('exportValue'=>$this->selectoption['currentVAL'], 'content'=>$e, 'selected'=>$this->selectoption['currentSEL']);
  11309. }
  11310. }
  11311. // TEXTAREA
  11312. else {
  11313. $objattr = unserialize($this->specialcontent);
  11314. $objattr['text'] = $e;
  11315. $te = "\xbb\xa4\xactype=textarea,objattr=".serialize($objattr)."\xbb\xa4\xac";
  11316. if ($this->tdbegin) {
  11317. $this->_saveCellTextBuffer($te, $this->HREF);
  11318. }
  11319. else {
  11320. $this->_saveTextBuffer($te, $this->HREF);
  11321. }
  11322. }
  11323. /*-- END FORMS --*/
  11324. }
  11325. // TABLE
  11326. else if ($this->tableLevel) {
  11327. /*-- TABLES --*/
  11328. if ($this->tdbegin) {
  11329. if (($this->ignorefollowingspaces) && !$this->ispre) { $e = ltrim($e); }
  11330. if ($e || $e==='0') {
  11331. if (($this->blockjustfinished || $this->listjustfinished) && $this->cell[$this->row][$this->col]['s']>0) {
  11332. $this->_saveCellTextBuffer("\n");
  11333. if (!isset($this->cell[$this->row][$this->col]['maxs'])) {
  11334. $this->cell[$this->row][$this->col]['maxs'] = $this->cell[$this->row][$this->col]['s'];
  11335. }
  11336. elseif($this->cell[$this->row][$this->col]['maxs'] < $this->cell[$this->row][$this->col]['s']) {
  11337. $this->cell[$this->row][$this->col]['maxs'] = $this->cell[$this->row][$this->col]['s'];
  11338. }
  11339. $this->cell[$this->row][$this->col]['s'] = 0;// reset
  11340. }
  11341. $this->blockjustfinished=false;
  11342. $this->listjustfinished=false;
  11343. $this->_saveCellTextBuffer($e, $this->HREF);
  11344. if (!isset($this->cell[$this->row][$this->col]['R']) || !$this->cell[$this->row][$this->col]['R']) {
  11345. if (isset($this->cell[$this->row][$this->col]['s'])) {
  11346. $this->cell[$this->row][$this->col]['s'] += $this->GetStringWidth($e, false);
  11347. }
  11348. else { $this->cell[$this->row][$this->col]['s'] = $this->GetStringWidth($e, false); }
  11349. if (!empty($this->spanborddet)) {
  11350. $this->cell[$this->row][$this->col]['s'] += $this->spanborddet['L']['w'] + $this->spanborddet['R']['w'];
  11351. }
  11352. }
  11353. if ($this->checkCJK && preg_match("/([".$this->pregCJKchars."])/u", $e)) { $this->tableCJK = true; } // *CJK-FONTS*
  11354. if ($this->tableLevel==1 && $this->useGraphs) {
  11355. $this->graphs[$this->currentGraphId]['data'][$this->row][$this->col] = $e;
  11356. }
  11357. $this->nestedtablejustfinished = false;
  11358. $this->linebreakjustfinished=false;
  11359. }
  11360. }
  11361. /*-- END TABLES --*/
  11362. }
  11363. // ALL ELSE
  11364. else {
  11365. if ($this->ignorefollowingspaces and !$this->ispre) { $e = ltrim($e); }
  11366. if ($e || $e==='0') $this->_saveTextBuffer($e, $this->HREF);
  11367. }
  11368. }
  11369. else { // TAG **
  11370. if($e[0]=='/') {
  11371. /*-- PROGRESS-BAR --*/
  11372. if ($this->progressBar) { // 10% increments
  11373. if (intval($i*10/$cnt) != $pbc) { $pbc = intval($i*10/$cnt); $this->UpdateProgressBar(1,$pbc*10,$tag); }
  11374. }
  11375. /*-- END PROGRESS-BAR --*/
  11376. // Check for tags where HTML specifies optional end tags,
  11377. // and/or does not allow nesting e.g. P inside P, or
  11378. $endtag = trim(strtoupper(substr($e,1))); // mPDF 5.4.20
  11379. if($this->blk[$this->blklvl]['hide']) {
  11380. if (in_array($endtag, $this->outerblocktags) || in_array($endtag, $this->innerblocktags)) {
  11381. unset($this->blk[$this->blklvl]);
  11382. $this->blklvl--;
  11383. }
  11384. continue;
  11385. }
  11386. /*-- CSS-POSITION --*/
  11387. if ($this->inFixedPosBlock) {
  11388. if (in_array($endtag, $this->outerblocktags) || in_array($endtag, $this->innerblocktags)) { $this->fixedPosBlockDepth--; }
  11389. if ($this->fixedPosBlockDepth == 0) {
  11390. $this->fixedPosBlockSave[] = array($this->fixedPosBlock, $this->fixedPosBlockBBox, $this->page);
  11391. $this->fixedPosBlock = '';
  11392. $this->inFixedPosBlock = false;
  11393. continue;
  11394. }
  11395. $this->fixedPosBlock .= '<'.$e.'>';
  11396. continue;
  11397. }
  11398. /*-- END CSS-POSITION --*/
  11399. if ($this->allow_html_optional_endtags && !$parseonly) {
  11400. if (($endtag == 'DIV' || $endtag =='FORM' || $endtag =='CENTER') && $this->lastoptionaltag == 'P') { $this->CloseTag($this->lastoptionaltag ); }
  11401. if ($this->lastoptionaltag == 'LI' && $endtag == 'OL') { $this->CloseTag($this->lastoptionaltag ); }
  11402. if ($this->lastoptionaltag == 'LI' && $endtag == 'UL') { $this->CloseTag($this->lastoptionaltag ); }
  11403. if ($this->lastoptionaltag == 'DD' && $endtag == 'DL') { $this->CloseTag($this->lastoptionaltag ); }
  11404. if ($this->lastoptionaltag == 'DT' && $endtag == 'DL') { $this->CloseTag($this->lastoptionaltag ); }
  11405. if ($this->lastoptionaltag == 'OPTION' && $endtag == 'SELECT') { $this->CloseTag($this->lastoptionaltag ); }
  11406. /*-- TABLES --*/
  11407. if ($endtag == 'TABLE') {
  11408. if ($this->lastoptionaltag == 'THEAD' || $this->lastoptionaltag == 'TBODY' || $this->lastoptionaltag == 'TFOOT') {
  11409. $this->CloseTag($this->lastoptionaltag);
  11410. }
  11411. if ($this->lastoptionaltag == 'TR') { $this->CloseTag('TR'); }
  11412. if ($this->lastoptionaltag == 'TD' || $this->lastoptionaltag == 'TH') { $this->CloseTag($this->lastoptionaltag ); $this->CloseTag('TR'); }
  11413. }
  11414. if ($endtag == 'THEAD' || $endtag == 'TBODY' || $endtag == 'TFOOT') {
  11415. if ($this->lastoptionaltag == 'TR') { $this->CloseTag('TR'); }
  11416. if ($this->lastoptionaltag == 'TD' || $this->lastoptionaltag == 'TH') { $this->CloseTag($this->lastoptionaltag ); $this->CloseTag('TR'); }
  11417. }
  11418. if ($endtag == 'TR') {
  11419. if ($this->lastoptionaltag == 'TD' || $this->lastoptionaltag == 'TH') { $this->CloseTag($this->lastoptionaltag ); }
  11420. }
  11421. /*-- END TABLES --*/
  11422. }
  11423. $this->CloseTag($endtag);
  11424. }
  11425. else { // OPENING TAG
  11426. if($this->blk[$this->blklvl]['hide']) {
  11427. if (strpos($e,' ')) { $te = strtoupper(substr($e,0,strpos($e,' '))); }
  11428. else { $te = strtoupper($e); }
  11429. if (in_array($te, $this->outerblocktags) || in_array($te, $this->innerblocktags)) {
  11430. $this->blklvl++;
  11431. $this->blk[$this->blklvl]['hide']=true;
  11432. }
  11433. continue;
  11434. }
  11435. /*-- CSS-POSITION --*/
  11436. if ($this->inFixedPosBlock) {
  11437. if (strpos($e,' ')) { $te = strtoupper(substr($e,0,strpos($e,' '))); }
  11438. else { $te = strtoupper($e); }
  11439. $this->fixedPosBlock .= '<'.$e.'>';
  11440. if (in_array($te, $this->outerblocktags) || in_array($te, $this->innerblocktags)) { $this->fixedPosBlockDepth++; }
  11441. continue;
  11442. }
  11443. /*-- END CSS-POSITION --*/
  11444. $regexp = '|=\'(.*?)\'|s'; // eliminate single quotes, if any
  11445. $e = preg_replace($regexp,"=\"\$1\"",$e);
  11446. // changes anykey=anyvalue to anykey="anyvalue" (only do this inside tags)
  11447. if (substr($e,0,10)!='pageheader' && substr($e,0,10)!='pagefooter') {
  11448. $regexp = '| (\\w+?)=([^\\s>"]+)|si';
  11449. $e = preg_replace($regexp," \$1=\"\$2\"",$e);
  11450. }
  11451. $e = preg_replace('/ (\\S+?)\s*=\s*"/i', " \\1=\"", $e);
  11452. //Fix path values, if needed
  11453. $orig_srcpath = '';
  11454. if ((stristr($e,"href=") !== false) or (stristr($e,"src=") !== false) ) {
  11455. $regexp = '/ (href|src)\s*=\s*"(.*?)"/i';
  11456. preg_match($regexp,$e,$auxiliararray);
  11457. if (isset($auxiliararray[2])) { $path = $auxiliararray[2]; }
  11458. else { $path = ''; }
  11459. if (trim($path) != '' && !(stristr($e,"src=") !== false && substr($path,0,4)=='var:')) {
  11460. $orig_srcpath = $path;
  11461. $this->GetFullPath($path);
  11462. $regexp = '/ (href|src)="(.*?)"/i';
  11463. $e = preg_replace($regexp,' \\1="'.$path.'"',$e);
  11464. }
  11465. }//END of Fix path values
  11466. //Extract attributes
  11467. $contents=array();
  11468. $contents1=array(); // mPDF 5.5.17
  11469. $contents2=array();
  11470. // Changed to allow style="background: url('bg.jpg')"
  11471. // mPDF 5.5.17 Changed to improve performance; maximum length of \S (attribute) = 16
  11472. preg_match_all('/\\S{1,16}=["][^"]*["]/',$e,$contents1);
  11473. preg_match_all('/\\S{1,16}=[\'][^\']*[\']/i',$e,$contents2);
  11474. $contents = array_merge($contents1, $contents2);
  11475. preg_match('/\\S+/',$e,$a2);
  11476. $tag=strtoupper($a2[0]);
  11477. $attr=array();
  11478. if ($orig_srcpath) { $attr['ORIG_SRC'] = $orig_srcpath; }
  11479. if (!empty($contents)) {
  11480. foreach($contents[0] as $v) {
  11481. // Changed to allow style="background: url('bg.jpg')"
  11482. if(preg_match('/^([^=]*)=["]?([^"]*)["]?$/',$v,$a3) || preg_match('/^([^=]*)=[\']?([^\']*)[\']?$/',$v,$a3)) {
  11483. if (strtoupper($a3[1])=='ID' || strtoupper($a3[1])=='CLASS') { // 4.2.013 Omits STYLE
  11484. $attr[strtoupper($a3[1])]=trim(strtoupper($a3[2]));
  11485. }
  11486. // includes header-style-right etc. used for <pageheader>
  11487. else if (preg_match('/^(HEADER|FOOTER)-STYLE/i',$a3[1])) {
  11488. $attr[strtoupper($a3[1])]=trim(strtoupper($a3[2]));
  11489. }
  11490. else {
  11491. $attr[strtoupper($a3[1])]=trim($a3[2]);
  11492. }
  11493. }
  11494. }
  11495. }
  11496. $this->OpenTag($tag,$attr);
  11497. /*-- CSS-POSITION --*/
  11498. if ($this->inFixedPosBlock) {
  11499. $this->fixedPosBlockBBox = array($tag,$attr, $this->x, $this->y);
  11500. $this->fixedPosBlock = '';
  11501. $this->fixedPosBlockDepth = 1;
  11502. }
  11503. /*-- END CSS-POSITION --*/
  11504. // mPDF 5.5.09
  11505. if (preg_match('/\/$/',$e)) { $this->closeTag($tag); }
  11506. }
  11507. } // end TAG
  11508. } //end of foreach($a as $i=>$e)
  11509. if ($close) {
  11510. // Close any open block tags
  11511. for ($b= $this->blklvl;$b>0;$b--) { $this->CloseTag($this->blk[$b]['tag']); }
  11512. // Output any text left in buffer
  11513. if (count($this->textbuffer) && !$parseonly) { $this->printbuffer($this->textbuffer); }
  11514. if (!$parseonly) $this->textbuffer=array();
  11515. /*-- CSS-FLOAT --*/
  11516. // If ended with a float, need to move to end page
  11517. $currpos = $this->page*1000 + $this->y;
  11518. if (isset($this->blk[$this->blklvl]['float_endpos']) && $this->blk[$this->blklvl]['float_endpos'] > $currpos) {
  11519. $old_page = $this->page;
  11520. $new_page = intval($this->blk[$this->blklvl]['float_endpos'] /1000);
  11521. if ($old_page != $new_page) {
  11522. $s = $this->PrintPageBackgrounds();
  11523. // Writes after the marker so not overwritten later by page background etc.
  11524. $this->pages[$this->page] = preg_replace('/(___BACKGROUND___PATTERNS'.date('jY').')/', '\\1'."\n".$s."\n", $this->pages[$this->page]);
  11525. $this->pageBackgrounds = array();
  11526. $this->page = $new_page;
  11527. $this->ResetMargins();
  11528. $this->Reset();
  11529. $this->pageoutput[$this->page] = array();
  11530. }
  11531. $this->y = (($this->blk[$this->blklvl]['float_endpos'] *1000) % 1000000)/1000; // mod changes operands to integers before processing
  11532. }
  11533. /*-- END CSS-FLOAT --*/
  11534. /*-- CSS-IMAGE-FLOAT --*/
  11535. $this->printfloatbuffer();
  11536. /*-- END CSS-IMAGE-FLOAT --*/
  11537. //Create Internal Links, if needed
  11538. if (!empty($this->internallink) ) {
  11539. foreach($this->internallink as $k=>$v) {
  11540. if (strpos($k,"#") !== false ) { continue; } //ignore
  11541. $ypos = $v['Y'];
  11542. $pagenum = $v['PAGE'];
  11543. $sharp = "#";
  11544. while (array_key_exists($sharp.$k,$this->internallink)) {
  11545. $internallink = $this->internallink[$sharp.$k];
  11546. $this->SetLink($internallink,$ypos,$pagenum);
  11547. $sharp .= "#";
  11548. }
  11549. }
  11550. }
  11551. $this->linemaxfontsize = '';
  11552. $this->lineheight_correction = $this->default_lineheight_correction;
  11553. $this->bufferoutput = false;
  11554. /*-- CSS-POSITION --*/
  11555. if (count($this->fixedPosBlockSave) && $sub != 4) {
  11556. foreach($this->fixedPosBlockSave AS $fpbs) {
  11557. $old_page = $this->page;
  11558. $this->page = $fpbs[2];
  11559. $this->WriteFixedPosHTML($fpbs[0], 0, 0, 100, 100,'auto', $fpbs[1]); // 0,0,10,10 are overwritten by bbox
  11560. $this->page = $old_page;
  11561. }
  11562. }
  11563. /*-- END CSS-POSITION --*/
  11564. }
  11565. }
  11566. /*-- CSS-POSITION --*/
  11567. function WriteFixedPosHTML($html='',$x, $y, $w, $h, $overflow='visible', $bounding=array()) {
  11568. // $overflow can be 'hidden', 'visible' or 'auto' - 'auto' causes autofit to size
  11569. // Annotations disabled - enabled in mPDF 5.0
  11570. // Links do work
  11571. // Will always go on current page (or start Page 1 if required)
  11572. // Probably INCOMPATIBLE WITH keep with table, columns etc.
  11573. // Called externally or interally via <div style="position: [fixed|absolute]">
  11574. // When used internally, $x $y $w $h and $overflow are all overridden by $bounding
  11575. $overflow = strtolower($overflow);
  11576. if($this->state==0) {
  11577. $this->AddPage($this->CurOrientation);
  11578. }
  11579. $save_y = $this->y;
  11580. $save_x = $this->x;
  11581. $this->fullImageHeight = $this->h;
  11582. $save_cols = false;
  11583. /*-- COLUMNS --*/
  11584. if ($this->ColActive) {
  11585. $save_cols = true;
  11586. $save_nbcol = $this->NbCol; // other values of gap and vAlign will not change by setting Columns off
  11587. $this->SetColumns(0);
  11588. }
  11589. /*-- END COLUMNS --*/
  11590. $save_annots = $this->title2annots; // *ANNOTATIONS*
  11591. $this->writingHTMLheader = true; // a FIX to stop pagebreaks etc.
  11592. $this->writingHTMLfooter = true;
  11593. $this->InFooter = true; // suppresses autopagebreaks
  11594. $save_bgs = $this->pageBackgrounds;
  11595. $checkinnerhtml = preg_replace('/\s/','',$html);
  11596. if ($w > $this->w) { $x = 0; $w = $this->w; }
  11597. if ($h > $this->h) { $y = 0; $h = $this->h; }
  11598. if ($x > $this->w) { $x = $this->w - $w; }
  11599. if ($y > $this->h) { $y = $this->h - $h; }
  11600. if (!empty($bounding)) {
  11601. // $cont_ containing block = full physical page (position: absolute) or page inside margins (position: fixed)
  11602. // $bbox_ Bounding box is the <div> which is positioned absolutely/fixed
  11603. // top/left/right/bottom/width/height/background*/border*/padding*/margin* are taken from bounding
  11604. // font*[family/size/style/weight]/line-height/text*[align/decoration/transform/indent]/color are transferred to $inner
  11605. // as an enclosing <div> (after having checked ID/CLASS)
  11606. // $x, $y, $w, $h are inside of $bbox_ = containing box for $inner_
  11607. // $inner_ InnerHTML is the contents of that block to be output
  11608. $tag = $bounding[0];
  11609. $attr = $bounding[1];
  11610. $orig_x0 = $bounding[2];
  11611. $orig_y0 = $bounding[3];
  11612. // As in WriteHTML() initialising
  11613. $this->blklvl = 0;
  11614. $this->lastblocklevelchange = 0;
  11615. $this->blk = array();
  11616. $this->initialiseBlock($this->blk[0]);
  11617. $this->blk[0]['width'] =& $this->pgwidth;
  11618. $this->blk[0]['inner_width'] =& $this->pgwidth;
  11619. $this->blk[0]['blockContext'] = $this->blockContext;
  11620. $properties = $this->MergeCSS('BLOCK','BODY','');
  11621. $this->setCSS($properties,'','BODY');
  11622. $this->blklvl = 1;
  11623. $this->initialiseBlock($this->blk[1]);
  11624. $this->blk[1]['tag'] = $tag;
  11625. $this->blk[1]['attr'] = $attr;
  11626. $this->Reset();
  11627. $p = $this->MergeCSS('BLOCK',$tag,$attr);
  11628. if (isset($p['ROTATE']) && ($p['ROTATE']==90 || $p['ROTATE']==-90)) { $rotate = $p['ROTATE']; }
  11629. else { $rotate = 0; }
  11630. if (isset($p['OVERFLOW'])) { $overflow = strtolower($p['OVERFLOW']); }
  11631. if (strtolower($p['POSITION']) == 'fixed') {
  11632. $cont_w = $this->pgwidth; // $this->blk[0]['inner_width'];
  11633. $cont_h = $this->h - $this->tMargin - $this->bMargin;
  11634. $cont_x = $this->lMargin;
  11635. $cont_y = $this->tMargin;
  11636. }
  11637. else {
  11638. $cont_w = $this->w; // ABSOLUTE;
  11639. $cont_h = $this->h;
  11640. $cont_x = 0;
  11641. $cont_y = 0;
  11642. }
  11643. // Pass on in-line properties to the innerhtml
  11644. $css = '';
  11645. if (isset($p['TEXT-ALIGN'])) { $css .= 'text-align: '.strtolower($p['TEXT-ALIGN']).'; '; }
  11646. if (isset($p['TEXT-TRANSFORM'])) { $css .= 'text-transform: '.strtolower($p['TEXT-TRANSFORM']).'; '; }
  11647. if (isset($p['TEXT-INDENT'])) { $css .= 'text-indent: '.strtolower($p['TEXT-INDENT']).'; '; }
  11648. if (isset($p['TEXT-DECORATION'])) { $css .= 'text-decoration: '.strtolower($p['TEXT-DECORATION']).'; '; }
  11649. if (isset($p['FONT-FAMILY'])) { $css .= 'font-family: '.strtolower($p['FONT-FAMILY']).'; '; }
  11650. if (isset($p['FONT-STYLE'])) { $css .= 'font-style: '.strtolower($p['FONT-STYLE']).'; '; }
  11651. if (isset($p['FONT-WEIGHT'])) { $css .= 'font-weight: '.strtolower($p['FONT-WEIGHT']).'; '; }
  11652. if (isset($p['FONT-SIZE'])) { $css .= 'font-size: '.strtolower($p['FONT-SIZE']).'; '; }
  11653. if (isset($p['LINE-HEIGHT'])) { $css .= 'line-height: '.strtolower($p['LINE-HEIGHT']).'; '; }
  11654. if (isset($p['TEXT-ALIGN'])) { $css .= 'text-align: '.strtolower($p['TEXT-ALIGN']).'; '; }
  11655. if (isset($p['TEXT-SHADOW'])) { $css .= 'text-shadow: '.strtolower($p['TEXT-SHADOW']).'; '; }
  11656. if (isset($p['LETTER-SPACING'])) { $css .= 'letter-spacing: '.strtolower($p['LETTER-SPACING']).'; '; }
  11657. if (isset($p['FONT-VARIANT'])) { $css .= 'font-variant: '.strtolower($p['FONT-VARIANT']).'; '; }
  11658. if (isset($p['COLOR'])) { $css .= 'color: '.strtolower($p['COLOR']).'; '; }
  11659. if ($css) {
  11660. $html = '<div style="'.$css.'">'.$html.'</div>';
  11661. }
  11662. // Copy over (only) the properties to set for border and background
  11663. $pb = array();
  11664. $pb['MARGIN-TOP'] = $p['MARGIN-TOP'];
  11665. $pb['MARGIN-RIGHT'] = $p['MARGIN-RIGHT'];
  11666. $pb['MARGIN-BOTTOM'] = $p['MARGIN-BOTTOM'];
  11667. $pb['MARGIN-LEFT'] = $p['MARGIN-LEFT'];
  11668. $pb['PADDING-TOP'] = $p['PADDING-TOP'];
  11669. $pb['PADDING-RIGHT'] = $p['PADDING-RIGHT'];
  11670. $pb['PADDING-BOTTOM'] = $p['PADDING-BOTTOM'];
  11671. $pb['PADDING-LEFT'] = $p['PADDING-LEFT'];
  11672. $pb['BORDER-TOP'] = $p['BORDER-TOP'];
  11673. $pb['BORDER-RIGHT'] = $p['BORDER-RIGHT'];
  11674. $pb['BORDER-BOTTOM'] = $p['BORDER-BOTTOM'];
  11675. $pb['BORDER-LEFT'] = $p['BORDER-LEFT'];
  11676. $pb['BORDER-TOP-LEFT-RADIUS-H'] = $p['BORDER-TOP-LEFT-RADIUS-H'];
  11677. $pb['BORDER-TOP-LEFT-RADIUS-V'] = $p['BORDER-TOP-LEFT-RADIUS-V'];
  11678. $pb['BORDER-TOP-RIGHT-RADIUS-H'] = $p['BORDER-TOP-RIGHT-RADIUS-H'];
  11679. $pb['BORDER-TOP-RIGHT-RADIUS-V'] = $p['BORDER-TOP-RIGHT-RADIUS-V'];
  11680. $pb['BORDER-BOTTOM-LEFT-RADIUS-H'] = $p['BORDER-BOTTOM-LEFT-RADIUS-H'];
  11681. $pb['BORDER-BOTTOM-LEFT-RADIUS-V'] = $p['BORDER-BOTTOM-LEFT-RADIUS-V'];
  11682. $pb['BORDER-BOTTOM-RIGHT-RADIUS-H'] = $p['BORDER-BOTTOM-RIGHT-RADIUS-H'];
  11683. $pb['BORDER-BOTTOM-RIGHT-RADIUS-V'] = $p['BORDER-BOTTOM-RIGHT-RADIUS-V'];
  11684. if (isset($p['BACKGROUND-COLOR'])) { $pb['BACKGROUND-COLOR'] = $p['BACKGROUND-COLOR']; }
  11685. if (isset($p['BOX-SHADOW'])) { $pb['BOX-SHADOW'] = $p['BOX-SHADOW']; }
  11686. /*-- BACKGROUNDS --*/
  11687. if (isset($p['BACKGROUND-IMAGE'])) { $pb['BACKGROUND-IMAGE'] = $p['BACKGROUND-IMAGE']; }
  11688. if (isset($p['BACKGROUND-IMAGE-RESIZE'])) { $pb['BACKGROUND-IMAGE-RESIZE'] = $p['BACKGROUND-IMAGE-RESIZE']; }
  11689. if (isset($p['BACKGROUND-IMAGE-OPACITY'])) { $pb['BACKGROUND-IMAGE-OPACITY'] = $p['BACKGROUND-IMAGE-OPACITY']; }
  11690. if (isset($p['BACKGROUND-REPEAT'])) { $pb['BACKGROUND-REPEAT'] = $p['BACKGROUND-REPEAT']; }
  11691. if (isset($p['BACKGROUND-POSITION'])) { $pb['BACKGROUND-POSITION'] = $p['BACKGROUND-POSITION']; }
  11692. if (isset($p['BACKGROUND-GRADIENT'])) { $pb['BACKGROUND-GRADIENT'] = $p['BACKGROUND-GRADIENT']; }
  11693. /*-- END BACKGROUNDS --*/
  11694. $this->setCSS($pb,'BLOCK',$tag);
  11695. //================================================================
  11696. $bbox_br = $this->blk[1]['border_right']['w'];
  11697. $bbox_bl = $this->blk[1]['border_left']['w'];
  11698. $bbox_bt = $this->blk[1]['border_top']['w'];
  11699. $bbox_bb = $this->blk[1]['border_bottom']['w'];
  11700. $bbox_pr = $this->blk[1]['padding_right'];
  11701. $bbox_pl = $this->blk[1]['padding_left'];
  11702. $bbox_pt = $this->blk[1]['padding_top'];
  11703. $bbox_pb = $this->blk[1]['padding_bottom'];
  11704. $bbox_mr = $this->blk[1]['margin_right'];
  11705. if (strtolower($p['MARGIN-RIGHT'])=='auto') { $bbox_mr = 'auto'; }
  11706. $bbox_ml = $this->blk[1]['margin_left'];
  11707. if (strtolower($p['MARGIN-LEFT'])=='auto') { $bbox_ml = 'auto'; }
  11708. $bbox_mt = $this->blk[1]['margin_top'];
  11709. if (strtolower($p['MARGIN-TOP'])=='auto') { $bbox_mt = 'auto'; }
  11710. $bbox_mb = $this->blk[1]['margin_bottom'];
  11711. if (strtolower($p['MARGIN-BOTTOM'])=='auto') { $bbox_mb = 'auto'; }
  11712. if (isset($p['LEFT']) && strtolower($p['LEFT'])!='auto') { $bbox_left = $this->ConvertSize($p['LEFT'], $cont_w, $this->FontSize,false); }
  11713. else { $bbox_left = 'auto'; }
  11714. if (isset($p['TOP']) && strtolower($p['TOP'])!='auto') { $bbox_top = $this->ConvertSize($p['TOP'], $cont_h, $this->FontSize,false); }
  11715. else { $bbox_top = 'auto'; }
  11716. if (isset($p['RIGHT']) && strtolower($p['RIGHT'])!='auto') { $bbox_right = $this->ConvertSize($p['RIGHT'], $cont_w, $this->FontSize,false); }
  11717. else { $bbox_right = 'auto'; }
  11718. if (isset($p['BOTTOM']) && strtolower($p['BOTTOM'])!='auto') { $bbox_bottom = $this->ConvertSize($p['BOTTOM'], $cont_h, $this->FontSize,false); }
  11719. else { $bbox_bottom = 'auto'; }
  11720. if (isset($p['WIDTH']) && strtolower($p['WIDTH'])!='auto') { $inner_w = $this->ConvertSize($p['WIDTH'], $cont_w, $this->FontSize,false); }
  11721. else { $inner_w = 'auto'; }
  11722. if (isset($p['HEIGHT']) && strtolower($p['HEIGHT'])!='auto') { $inner_h = $this->ConvertSize($p['HEIGHT'], $cont_h, $this->FontSize,false); }
  11723. else { $inner_h = 'auto'; }
  11724. // If bottom or right pos are set and not left / top - save this to adjust rotated block later
  11725. if ($rotate) {
  11726. if ($bbox_left === 'auto' && $bbox_right !== 'auto') { $rot_rpos = $bbox_right; }
  11727. else { $rot_rpos = false; }
  11728. if ($bbox_top === 'auto' && $bbox_bottom !== 'auto') { $rot_bpos = $bbox_bottom; }
  11729. else { $rot_bpos = false; }
  11730. }
  11731. //================================================================
  11732. if ($checkinnerhtml=='' && $inner_h==='auto') { $inner_h = 0.0001; }
  11733. if ($checkinnerhtml=='' && $inner_w==='auto') { $inner_w = 2*$this->GetCharWidth('W',false); }
  11734. //================================================================
  11735. // Algorithm from CSS2.1 See http://www.w3.org/TR/CSS21/visudet.html#abs-non-replaced-height
  11736. // mPD 5.3.14
  11737. // Special case (not CSS) if all not specified, centre vertically on page
  11738. if ($bbox_top==='auto' && $inner_h==='auto' && $bbox_bottom==='auto' && $bbox_mt==='auto' && $bbox_mb==='auto') {
  11739. $bbox_top_orig = $bbox_top;
  11740. if ($bbox_mt==='auto') { $bbox_mt = 0; }
  11741. if ($bbox_mb==='auto') { $bbox_mb = 0; }
  11742. $bbox_top = $orig_y0 - $bbox_mt - $cont_y;
  11743. // solve for $bbox_bottom when content_h known - $inner_h=='auto' && $bbox_bottom=='auto'
  11744. }
  11745. // mPD 5.3.14
  11746. else if ($bbox_top==='auto' && $inner_h==='auto' && $bbox_bottom==='auto') {
  11747. $bbox_top_orig = $bbox_top = $orig_y0 - $cont_y;
  11748. if ($bbox_mt==='auto') { $bbox_mt = 0; }
  11749. if ($bbox_mb==='auto') { $bbox_mb = 0; }
  11750. // solve for $bbox_bottom when content_h known - $inner_h=='auto' && $bbox_bottom=='auto'
  11751. }
  11752. else if ($bbox_top!=='auto' && $inner_h!=='auto' && $bbox_bottom!=='auto') {
  11753. if ($bbox_mt==='auto' && $bbox_mb==='auto') {
  11754. $x = $cont_h - $bbox_top - $bbox_bt - $bbox_pt - $inner_h - $bbox_pb - $bbox_bb - $bbox_bottom;
  11755. $bbox_mt = $bbox_mb = ($x/2);
  11756. }
  11757. else if ($bbox_mt==='auto') {
  11758. $bbox