| [ Index ] |
PHP Cross Reference of Joomla 1.5.26 DE |
[Summary view] [Print] [Text view]
1 <?php 2 //============================================================+ 3 // File name : tcpdf.php 4 // Begin : 2002-08-03 5 // Last Update : 2008-03-07 6 // Author : Nicola Asuni 7 // Version : 2.5.000_PHP4 8 // License : GNU LGPL (http://www.gnu.org/copyleft/lesser.html) 9 // 10 // Description : This is a PHP5 class for generating PDF files 11 // on-the-fly without requiring external 12 // extensions. 13 // 14 // NOTE: 15 // This class was originally derived in 2002 from the Public 16 // Domain FPDF class by Olivier Plathey (http://www.fpdf.org). 17 // 18 // Main features: 19 // - supports all ISO page formats; 20 // - supports UTF-8 Unicode and Right-To-Left languages; 21 // - supports document encryption; 22 // - includes methods to publish some xhtml code; 23 // - includes graphic and transformation methods; 24 // - includes bookmarks; 25 // - includes Javascript and forms support; 26 // - includes a method to print various barcode formats using an improved version of "Generic Barcode Render Class" by Karim Mribti (http://www.mribti.com/barcode/) (require GD library: http://www.boutell.com/gd/) 27 // - supports TrueTypeUnicode, TrueType, Type1 and encoding; 28 // - supports custom page formats, margins and units of measure; 29 // - includes methods for page header and footer management; 30 // - supports automatic page break; 31 // - supports automatic page numbering; 32 // - supports automatic line break and text justification; 33 // - supports JPEG, PNG anf GIF images; 34 // - supports colors; 35 // - supports links; 36 // - support page compression (require zlib extension: http://www.gzip.org/zlib/); 37 // - the source code is full documented in PhpDocumentor Style (http://www.phpdoc.org). 38 // 39 // ----------------------------------------------------------- 40 // THANKS TO: 41 // 42 // Olivier Plathey (http://www.fpdf.org) for original FPDF. 43 // Efthimios Mavrogeorgiadis (emavro@yahoo.com) for suggestions on RTL language support. 44 // Klemen Vodopivec (http://www.fpdf.de/downloads/addons/37/) for Encryption algorithm. 45 // Warren Sherliker (wsherliker@gmail.com) for better image handling. 46 // dullus for text Justification. 47 // Bob Vincent (pillarsdotnet@users.sourceforge.net) for <li> value attribute. 48 // Patrick Benny for text stretch suggestion on Cell(). 49 // Johannes G�ntert for JavaScript support. 50 // Denis Van Nuffelen for Dynamic Form. 51 // Jacek Czekaj for multibyte justification 52 // Anthony Ferrara for the reintroduction of legacy image methods. 53 // Anyone that has reported a bug or sent a suggestion. 54 //============================================================+ 55 56 57 58 /** 59 * This is a PHP5 class for generating PDF files on-the-fly without requiring external extensions.<br> 60 * TCPDF project (http://tcpdf.sourceforge.net) has been originally derived from the Public Domain FPDF class by Olivier Plathey (http://www.fpdf.org).<br> 61 * <h3>TCPDF main features are:</h3> 62 * <ul> 63 * <li>supports all ISO page formats;</li> 64 * <li>supports UTF-8 Unicode and Right-To-Left languages;</li> 65 * <li>supports document encryption;</li> 66 * <li>includes methods to publish some xhtml code, supporting the following elements: h1, h2, h3, h4, h5, h6, b, u, i, a, img, p, br, strong, em, font, blockquote, li, ul, ol, hr, td, th, tr, table, sup, sub, small;</li> 67 * <li>includes a method to print various barcode formats using an improved version of "Generic Barcode Render Class" by Karim Mribti (<a href="http://www.mribti.com/barcode/" target="_blank" title="Generic Barcode Render Class by Karim Mribti">http://www.mribti.com/barcode/</a>) (require GD library: <a href="http://www.boutell.com/gd/" target="_blank" title="GD library">http://www.boutell.com/gd/</a>)</li> 68 * <li>supports TrueTypeUnicode, TrueType, Type1 and encoding; </li> 69 * <li>supports custom page formats, margins and units of measure;</li> 70 * <li>includes methods for page header and footer management;</li> 71 * <li>supports automatic page break;</li> 72 * <li>supports automatic page numbering;</li> 73 * <li>supports automatic line break and text justification;</li> 74 * <li>supports JPEG, PNG anf GIF images;</li> 75 * <li>supports colors;</li> 76 * <li>supports links;</li> 77 * <li>support page compression (require zlib extension: <a href="http://www.gzip.org/zlib/" target="_blank" title="zlib">http://www.gzip.org/zlib/</a>);</li> 78 * <li>the source code is full documented in PhpDocumentor Style (<a href="http://www.phpdoc.org" target="_blank" title="phpDocumentor">http://www.phpdoc.org</a>).</li> 79 * </ul> 80 * Tools to encode your unicode fonts are on fonts/ttf2ufm directory.</p> 81 * @name TCPDF 82 * @package com.tecnick.tcpdf 83 * @abstract Class for generating PDF files on-the-fly without requiring external extensions. 84 * @author Nicola Asuni 85 * @copyright 2004-2008 Nicola Asuni - Tecnick.com S.r.l (www.tecnick.com) Via Della Pace, 11 - 09044 - Quartucciu (CA) - ITALY - www.tecnick.com - info@tecnick.com 86 * @link http://www.tcpdf.org 87 * @license http://www.gnu.org/copyleft/lesser.html LGPL 88 * @version 2.5.000_PHP4 89 */ 90 91 /** 92 * include configuration file 93 */ 94 require_once(dirname(__FILE__).'/config/tcpdf_config.php'); 95 96 if(!class_exists('TCPDF')) { 97 /** 98 * define default PDF document producer 99 */ 100 define('PDF_PRODUCER','TCPDF 2.5.000_PHP4 (http://www.tcpdf.org)'); 101 102 /** 103 * This is a PHP5 class for generating PDF files on-the-fly without requiring external extensions.<br> 104 * TCPDF project (http://tcpdf.sourceforge.net) has been originally derived from the Public Domain FPDF class by Olivier Plathey (http://www.fpdf.org).<br> 105 * To add your own TTF fonts please read /fonts/README.TXT 106 * @name TCPDF 107 * @package com.tecnick.tcpdf 108 * @version 2.5.000_PHP4 109 * @author Nicola Asuni 110 * @link http://www.tcpdf.org 111 * @license http://www.gnu.org/copyleft/lesser.html LGPL 112 */ 113 class TCPDF { 114 115 // Private or Protected properties 116 117 /** 118 * @var current page number 119 * @access protected 120 */ 121 var $page; 122 123 /** 124 * @var current object number 125 * @access protected 126 */ 127 var $n; 128 129 /** 130 * @var array of object offsets 131 * @access protected 132 */ 133 var $offsets; 134 135 /** 136 * @var buffer holding in-memory PDF 137 * @access protected 138 */ 139 var $buffer; 140 141 /** 142 * @var array containing pages 143 * @access protected 144 */ 145 var $pages; 146 147 /** 148 * @var current document state 149 * @access protected 150 */ 151 var $state; 152 153 /** 154 * @var compression flag 155 * @access protected 156 */ 157 var $compress; 158 159 /** 160 * @var default page orientation (P = Portrait, L = Landscape) 161 * @access protected 162 */ 163 var $DefOrientation; 164 165 /** 166 * @var current page orientation (P = Portrait, L = Landscape) 167 * @access protected 168 */ 169 var $CurOrientation; 170 171 /** 172 * @var array indicating page orientation changes 173 * @access protected 174 */ 175 var $OrientationChanges; 176 177 /** 178 * @var scale factor (number of points in user unit) 179 * @access protected 180 */ 181 var $k; 182 183 /** 184 * @var width of page format in points 185 * @access protected 186 */ 187 var $fwPt; 188 189 /** 190 * @var height of page format in points 191 * @access protected 192 */ 193 var $fhPt; 194 195 /** 196 * @var width of page format in user unit 197 * @access protected 198 */ 199 var $fw; 200 201 /** 202 * @var height of page format in user unit 203 * @access protected 204 */ 205 var $fh; 206 207 /** 208 * @var current width of page in points 209 * @access protected 210 */ 211 var $wPt; 212 213 /** 214 * @var current height of page in points 215 * @access protected 216 */ 217 var $hPt; 218 219 /** 220 * @var current width of page in user unit 221 * @access protected 222 */ 223 var $w; 224 225 /** 226 * @var current height of page in user unit 227 * @access protected 228 */ 229 var $h; 230 231 /** 232 * @var left margin 233 * @access protected 234 */ 235 var $lMargin; 236 237 /** 238 * @var top margin 239 * @access protected 240 */ 241 var $tMargin; 242 243 /** 244 * @var right margin 245 * @access protected 246 */ 247 var $rMargin; 248 249 /** 250 * @var page break margin 251 * @access protected 252 */ 253 var $bMargin; 254 255 /** 256 * @var cell internal padding 257 * @access protected 258 */ 259 var $cMargin; 260 261 /** 262 * @var current horizontal position in user unit for cell positioning 263 * @access protected 264 */ 265 var $x; 266 267 /** 268 * @var current vertical position in user unit for cell positioning 269 * @access protected 270 */ 271 var $y; 272 273 /** 274 * @var height of last cell printed 275 * @access protected 276 */ 277 var $lasth; 278 279 /** 280 * @var line width in user unit 281 * @access protected 282 */ 283 var $LineWidth; 284 285 /** 286 * @var array of standard font names 287 * @access protected 288 */ 289 var $CoreFonts; 290 291 /** 292 * @var array of used fonts 293 * @access protected 294 */ 295 var $fonts; 296 297 /** 298 * @var array of font files 299 * @access protected 300 */ 301 var $FontFiles; 302 303 /** 304 * @var array of encoding differences 305 * @access protected 306 */ 307 var $diffs; 308 309 /** 310 * @var array of used images 311 * @access protected 312 */ 313 var $images; 314 315 /** 316 * @var array of links in pages 317 * @access protected 318 */ 319 var $PageLinks; 320 321 /** 322 * @var array of internal links 323 * @access protected 324 */ 325 var $links; 326 327 /** 328 * @var current font family 329 * @access protected 330 */ 331 var $FontFamily; 332 333 /** 334 * @var current font style 335 * @access protected 336 */ 337 var $FontStyle; 338 339 /** 340 * @var underlining flag 341 * @access protected 342 */ 343 var $underline; 344 345 /** 346 * @var current font info 347 * @access protected 348 */ 349 var $CurrentFont; 350 351 /** 352 * @var current font size in points 353 * @access protected 354 */ 355 var $FontSizePt; 356 357 /** 358 * @var current font size in user unit 359 * @access protected 360 */ 361 var $FontSize; 362 363 /** 364 * @var commands for drawing color 365 * @access protected 366 */ 367 var $DrawColor; 368 369 /** 370 * @var commands for filling color 371 * @access protected 372 */ 373 var $FillColor; 374 375 /** 376 * @var commands for text color 377 * @access protected 378 */ 379 var $TextColor; 380 381 /** 382 * @var indicates whether fill and text colors are different 383 * @access protected 384 */ 385 var $ColorFlag; 386 387 /** 388 * @var word spacing 389 * @access protected 390 */ 391 var $ws; 392 393 /** 394 * @var automatic page breaking 395 * @access protected 396 */ 397 var $AutoPageBreak; 398 399 /** 400 * @var threshold used to trigger page breaks 401 * @access protected 402 */ 403 var $PageBreakTrigger; 404 405 /** 406 * @var flag set when processing footer 407 * @access protected 408 */ 409 var $InFooter; 410 411 /** 412 * @var zoom display mode 413 * @access protected 414 */ 415 var $ZoomMode; 416 417 /** 418 * @var layout display mode 419 * @access protected 420 */ 421 var $LayoutMode; 422 423 /** 424 * @var title 425 * @access protected 426 */ 427 var $title; 428 429 /** 430 * @var subject 431 * @access protected 432 */ 433 var $subject; 434 435 /** 436 * @var author 437 * @access protected 438 */ 439 var $author; 440 441 /** 442 * @var keywords 443 * @access protected 444 */ 445 var $keywords; 446 447 /** 448 * @var creator 449 * @access protected 450 */ 451 var $creator; 452 453 /** 454 * @var alias for total number of pages 455 * @access protected 456 */ 457 var $AliasNbPages; 458 459 /** 460 * @var right-bottom corner X coordinate of inserted image 461 * @since 2002-07-31 462 * @author Nicola Asuni 463 * @access protected 464 */ 465 var $img_rb_x; 466 467 /** 468 * @var right-bottom corner Y coordinate of inserted image 469 * @since 2002-07-31 470 * @author Nicola Asuni 471 * @access protected 472 */ 473 var $img_rb_y; 474 475 /** 476 * @var image scale factor 477 * @since 2004-06-14 478 * @author Nicola Asuni 479 * @access protected 480 */ 481 var $imgscale = 1; 482 483 /** 484 * @var boolean set to true when the input text is unicode (require unicode fonts) 485 * @since 2005-01-02 486 * @author Nicola Asuni 487 * @access protected 488 */ 489 var $isunicode = false; 490 491 /** 492 * @var PDF version 493 * @since 1.5.3 494 * @access protected 495 */ 496 var $PDFVersion = "1.5"; 497 498 499 // ---------------------- 500 501 /** 502 * @var Minimum distance between header and top page margin. 503 * @access private 504 */ 505 var $header_margin; 506 507 /** 508 * @var Minimum distance between footer and bottom page margin. 509 * @access private 510 */ 511 var $footer_margin; 512 513 /** 514 * @var original left margin value 515 * @access private 516 * @since 1.53.0.TC013 517 */ 518 var $original_lMargin; 519 520 /** 521 * @var original right margin value 522 * @access private 523 * @since 1.53.0.TC013 524 */ 525 var $original_rMargin; 526 527 /** 528 * @var Header font. 529 * @access private 530 */ 531 var $header_font; 532 533 /** 534 * @var Footer font. 535 * @access private 536 */ 537 var $footer_font; 538 539 /** 540 * @var Language templates. 541 * @access private 542 */ 543 var $l; 544 545 /** 546 * @var Barcode to print on page footer (only if set). 547 * @access private 548 */ 549 var $barcode = false; 550 551 /** 552 * @var If true prints header 553 * @access private 554 */ 555 var $print_header = true; 556 557 /** 558 * @var If true prints footer. 559 * @access private 560 */ 561 var $print_footer = true; 562 563 /** 564 * @var Header width (0 = full page width). 565 * @access private 566 */ 567 var $header_width = 0; 568 569 /** 570 * @var Header image logo. 571 * @access private 572 */ 573 var $header_logo = ""; 574 575 /** 576 * @var Header image logo width in mm. 577 * @access private 578 */ 579 var $header_logo_width = 30; 580 581 /** 582 * @var String to print as title on document header. 583 * @access private 584 */ 585 var $header_title = ""; 586 587 /** 588 * @var String to print on document header. 589 * @access private 590 */ 591 var $header_string = ""; 592 593 /** 594 * @var Default number of columns for html table. 595 * @access private 596 */ 597 var $default_table_columns = 4; 598 599 600 // variables for html parser 601 602 /** 603 * @var HTML PARSER: store current link. 604 * @access private 605 */ 606 var $HREF; 607 608 /** 609 * @var HTML PARSER: store font list. 610 * @access private 611 */ 612 var $fontList; 613 614 /** 615 * @var HTML PARSER: true when font attribute is set. 616 * @access private 617 */ 618 var $issetfont; 619 620 /** 621 * @var HTML PARSER: true when color attribute is set. 622 * @access private 623 */ 624 var $issetcolor; 625 626 /** 627 * @var HTML PARSER: true in case of ordered list (OL), false otherwise. 628 * @access private 629 */ 630 var $listordered = false; 631 632 /** 633 * @var HTML PARSER: count list items. 634 * @access private 635 */ 636 var $listcount = 0; 637 638 /** 639 * @var HTML PARSER: size of table border. 640 * @access private 641 */ 642 var $tableborder = 0; 643 644 /** 645 * @var HTML PARSER: true at the beginning of table. 646 * @access private 647 */ 648 var $tdbegin = false; 649 650 /** 651 * @var HTML PARSER: table width. 652 * @access private 653 */ 654 var $tdwidth = 0; 655 656 /** 657 * @var HTML PARSER: table height. 658 * @access private 659 */ 660 var $tdheight = 0; 661 662 /** 663 * @var HTML PARSER: table align. 664 * @access private 665 */ 666 var $tdalign = "L"; 667 668 /** 669 * @var HTML PARSER: table background color. 670 * @access private 671 */ 672 var $tdbgcolor = false; 673 674 /** 675 * @var Store temporary font size in points. 676 * @access private 677 */ 678 var $tempfontsize = 10; 679 680 /** 681 * @var Bold font style status. 682 * @access private 683 */ 684 var $b; 685 686 /** 687 * @var Underlined font style status. 688 * @access private 689 */ 690 var $u; 691 692 /** 693 * @var Italic font style status. 694 * @access private 695 */ 696 var $i; 697 698 /** 699 * @var spacer for LI tags. 700 * @access private 701 */ 702 var $lispacer = ""; 703 704 /** 705 * @var default encoding 706 * @access private 707 * @since 1.53.0.TC010 708 */ 709 var $encoding = "UTF-8"; 710 711 /** 712 * @var PHP internal encoding 713 * @access private 714 * @since 1.53.0.TC016 715 */ 716 var $internal_encoding; 717 718 /** 719 * @var store previous fill color as RGB array 720 * @access private 721 * @since 1.53.0.TC017 722 */ 723 var $prevFillColor = array(255,255,255); 724 725 /** 726 * @var store previous text color as RGB array 727 * @access private 728 * @since 1.53.0.TC017 729 */ 730 var $prevTextColor = array(0,0,0); 731 732 /** 733 * @var store previous font family 734 * @access private 735 * @since 1.53.0.TC017 736 */ 737 var $prevFontFamily; 738 739 /** 740 * @var store previous font style 741 * @access private 742 * @since 1.53.0.TC017 743 */ 744 var $prevFontStyle; 745 746 /** 747 * @var indicates if the document language is Right-To-Left 748 * @access private 749 * @since 2.0.000 750 */ 751 var $rtl = false; 752 753 /** 754 * @var used to force RTL or LTR string inversion 755 * @access private 756 * @since 2.0.000 757 */ 758 var $tmprtl = false; 759 760 // --- Variables used for document encryption: 761 762 /** 763 * Indicates whether document is protected 764 * @access private 765 * @since 2.0.000 (2008-01-02) 766 */ 767 var $encrypted; 768 769 /** 770 * U entry in pdf document 771 * @access private 772 * @since 2.0.000 (2008-01-02) 773 */ 774 var $Uvalue; 775 776 /** 777 * O entry in pdf document 778 * @access private 779 * @since 2.0.000 (2008-01-02) 780 */ 781 var $Ovalue; 782 783 /** 784 * P entry in pdf document 785 * @access private 786 * @since 2.0.000 (2008-01-02) 787 */ 788 var $Pvalue; 789 790 /** 791 * encryption object id 792 * @access private 793 * @since 2.0.000 (2008-01-02) 794 */ 795 var $enc_obj_id; 796 797 /** 798 * last RC4 key encrypted (cached for optimisation) 799 * @access private 800 * @since 2.0.000 (2008-01-02) 801 */ 802 var $last_rc4_key; 803 804 /** 805 * last RC4 computed key 806 * @access private 807 * @since 2.0.000 (2008-01-02) 808 */ 809 var $last_rc4_key_c; 810 811 // --- bookmark --- 812 813 /** 814 * Outlines for bookmark 815 * @access private 816 * @since 2.1.002 (2008-02-12) 817 */ 818 var $outlines = array(); 819 820 /** 821 * Outline root for bookmark 822 * @access private 823 * @since 2.1.002 (2008-02-12) 824 */ 825 var $OutlineRoot; 826 827 828 // --- javascript and form --- 829 830 /** 831 * javascript code 832 * @access private 833 * @since 2.1.002 (2008-02-12) 834 */ 835 var $javascript = ""; 836 837 /** 838 * javascript counter 839 * @access private 840 * @since 2.1.002 (2008-02-12) 841 */ 842 var $n_js; 843 844 //------------------------------------------------------------ 845 // Public methods 846 //------------------------------------------------------------ 847 848 /** 849 * This is the class constructor. 850 * It allows to set up the page format, the orientation and 851 * the measure unit used in all the methods (except for the font sizes). 852 * @since 1.0 853 * @param string $orientation page orientation. Possible values are (case insensitive):<ul><li>P or Portrait (default)</li><li>L or Landscape</li></ul> 854 * @param string $unit User measure unit. Possible values are:<ul><li>pt: point</li><li>mm: millimeter (default)</li><li>cm: centimeter</li><li>in: inch</li></ul><br />A point equals 1/72 of inch, that is to say about 0.35 mm (an inch being 2.54 cm). This is a very common unit in typography; font sizes are expressed in that unit. 855 * @param mixed $format The format used for pages. It can be either one of the following values (case insensitive) or a custom format in the form of a two-element array containing the width and the height (expressed in the unit given by unit).<ul><li>4A0</li><li>2A0</li><li>A0</li><li>A1</li><li>A2</li><li>A3</li><li>A4 (default)</li><li>A5</li><li>A6</li><li>A7</li><li>A8</li><li>A9</li><li>A10</li><li>B0</li><li>B1</li><li>B2</li><li>B3</li><li>B4</li><li>B5</li><li>B6</li><li>B7</li><li>B8</li><li>B9</li><li>B10</li><li>C0</li><li>C1</li><li>C2</li><li>C3</li><li>C4</li><li>C5</li><li>C6</li><li>C7</li><li>C8</li><li>C9</li><li>C10</li><li>RA0</li><li>RA1</li><li>RA2</li><li>RA3</li><li>RA4</li><li>SRA0</li><li>SRA1</li><li>SRA2</li><li>SRA3</li><li>SRA4</li><li>LETTER</li><li>LEGAL</li><li>EXECUTIVE</li><li>FOLIO</li></ul> 856 * @param boolean $unicode TRUE means that the input text is unicode (default = true) 857 * @param String $encoding charset encoding; default is UTF-8 858 */ 859 function TCPDF($orientation='P', $unit='mm', $format='A4', $unicode=true, $encoding="UTF-8") { 860 861 /* Set internal character encoding to ASCII */ 862 if (function_exists("mb_internal_encoding") AND mb_internal_encoding()) { 863 $this->internal_encoding = mb_internal_encoding(); 864 mb_internal_encoding("ASCII"); 865 } 866 867 // set language direction 868 $this->rtl = $this->l['a_meta_dir']=='rtl' ? true : false; 869 $this->tmprtl = false; 870 871 //Some checks 872 $this->_dochecks(); 873 874 //Initialization of properties 875 $this->isunicode=$unicode; 876 $this->page=0; 877 $this->n=2; 878 $this->buffer=''; 879 $this->pages=array(); 880 $this->OrientationChanges=array(); 881 $this->state=0; 882 $this->fonts=array(); 883 $this->FontFiles=array(); 884 $this->diffs=array(); 885 $this->images=array(); 886 $this->links=array(); 887 $this->InFooter=false; 888 $this->lasth=0; 889 $this->FontFamily=''; 890 $this->FontStyle=''; 891 $this->FontSizePt=12; 892 $this->underline=false; 893 $this->DrawColor='0 G'; 894 $this->FillColor='0 g'; 895 $this->TextColor='0 g'; 896 $this->ColorFlag=false; 897 $this->ws=0; 898 // encryption values 899 $this->encrypted=false; 900 $this->last_rc4_key=''; 901 $this->padding="\x28\xBF\x4E\x5E\x4E\x75\x8A\x41\x64\x00\x4E\x56\xFF\xFA\x01\x08\x2E\x2E\x00\xB6\xD0\x68\x3E\x80\x2F\x0C\xA9\xFE\x64\x53\x69\x7A"; 902 903 //Standard Unicode fonts 904 $this->CoreFonts=array( 905 'courier'=>'Courier', 906 'courierB'=>'Courier-Bold', 907 'courierI'=>'Courier-Oblique', 908 'courierBI'=>'Courier-BoldOblique', 909 'helvetica'=>'Helvetica', 910 'helveticaB'=>'Helvetica-Bold', 911 'helveticaI'=>'Helvetica-Oblique', 912 'helveticaBI'=>'Helvetica-BoldOblique', 913 'times'=>'Times-Roman', 914 'timesB'=>'Times-Bold', 915 'timesI'=>'Times-Italic', 916 'timesBI'=>'Times-BoldItalic', 917 'symbol'=>'Symbol', 918 'zapfdingbats'=>'ZapfDingbats' 919 ); 920 921 //Scale factor 922 switch (strtolower($unit)){ 923 case 'pt': {$this->k=1; break;} 924 case 'mm': {$this->k=72/25.4; break;} 925 case 'cm': {$this->k=72/2.54; break;} 926 case 'in': {$this->k=72; break;} 927 default : {$this->Error('Incorrect unit: '.$unit); break;} 928 } 929 930 //Page format 931 if(is_string($format)) { 932 // Page formats (45 standard ISO paper formats and 4 american common formats). 933 // Paper cordinates are calculated in this way: (inches * 72) where (1 inch = 2.54 cm) 934 switch (strtoupper($format)){ 935 case '4A0': {$format = array(4767.87,6740.79); break;} 936 case '2A0': {$format = array(3370.39,4767.87); break;} 937 case 'A0': {$format = array(2383.94,3370.39); break;} 938 case 'A1': {$format = array(1683.78,2383.94); break;} 939 case 'A2': {$format = array(1190.55,1683.78); break;} 940 case 'A3': {$format = array(841.89,1190.55); break;} 941 case 'A4': default: {$format = array(595.28,841.89); break;} 942 case 'A5': {$format = array(419.53,595.28); break;} 943 case 'A6': {$format = array(297.64,419.53); break;} 944 case 'A7': {$format = array(209.76,297.64); break;} 945 case 'A8': {$format = array(147.40,209.76); break;} 946 case 'A9': {$format = array(104.88,147.40); break;} 947 case 'A10': {$format = array(73.70,104.88); break;} 948 case 'B0': {$format = array(2834.65,4008.19); break;} 949 case 'B1': {$format = array(2004.09,2834.65); break;} 950 case 'B2': {$format = array(1417.32,2004.09); break;} 951 case 'B3': {$format = array(1000.63,1417.32); break;} 952 case 'B4': {$format = array(708.66,1000.63); break;} 953 case 'B5': {$format = array(498.90,708.66); break;} 954 case 'B6': {$format = array(354.33,498.90); break;} 955 case 'B7': {$format = array(249.45,354.33); break;} 956 case 'B8': {$format = array(175.75,249.45); break;} 957 case 'B9': {$format = array(124.72,175.75); break;} 958 case 'B10': {$format = array(87.87,124.72); break;} 959 case 'C0': {$format = array(2599.37,3676.54); break;} 960 case 'C1': {$format = array(1836.85,2599.37); break;} 961 case 'C2': {$format = array(1298.27,1836.85); break;} 962 case 'C3': {$format = array(918.43,1298.27); break;} 963 case 'C4': {$format = array(649.13,918.43); break;} 964 case 'C5': {$format = array(459.21,649.13); break;} 965 case 'C6': {$format = array(323.15,459.21); break;} 966 case 'C7': {$format = array(229.61,323.15); break;} 967 case 'C8': {$format = array(161.57,229.61); break;} 968 case 'C9': {$format = array(113.39,161.57); break;} 969 case 'C10': {$format = array(79.37,113.39); break;} 970 case 'RA0': {$format = array(2437.80,3458.27); break;} 971 case 'RA1': {$format = array(1729.13,2437.80); break;} 972 case 'RA2': {$format = array(1218.90,1729.13); break;} 973 case 'RA3': {$format = array(864.57,1218.90); break;} 974 case 'RA4': {$format = array(609.45,864.57); break;} 975 case 'SRA0': {$format = array(2551.18,3628.35); break;} 976 case 'SRA1': {$format = array(1814.17,2551.18); break;} 977 case 'SRA2': {$format = array(1275.59,1814.17); break;} 978 case 'SRA3': {$format = array(907.09,1275.59); break;} 979 case 'SRA4': {$format = array(637.80,907.09); break;} 980 case 'LETTER': {$format = array(612.00,792.00); break;} 981 case 'LEGAL': {$format = array(612.00,1008.00); break;} 982 case 'EXECUTIVE': {$format = array(521.86,756.00); break;} 983 case 'FOLIO': {$format = array(612.00,936.00); break;} 984 // default: {$this->Error('Unknown page format: '.$format); break;} 985 } 986 $this->fwPt=$format[0]; 987 $this->fhPt=$format[1]; 988 } 989 else { 990 $this->fwPt=$format[0]*$this->k; 991 $this->fhPt=$format[1]*$this->k; 992 } 993 994 $this->fw=$this->fwPt/$this->k; 995 $this->fh=$this->fhPt/$this->k; 996 997 //Page orientation 998 $orientation=strtolower($orientation); 999 if($orientation=='p' or $orientation=='portrait') { 1000 $this->DefOrientation='P'; 1001 $this->wPt=$this->fwPt; 1002 $this->hPt=$this->fhPt; 1003 } 1004 elseif($orientation=='l' or $orientation=='landscape') { 1005 $this->DefOrientation='L'; 1006 $this->wPt=$this->fhPt; 1007 $this->hPt=$this->fwPt; 1008 } 1009 else { 1010 $this->Error('Incorrect orientation: '.$orientation); 1011 } 1012 1013 $this->CurOrientation=$this->DefOrientation; 1014 $this->w=$this->wPt/$this->k; 1015 $this->h=$this->hPt/$this->k; 1016 //Page margins (1 cm) 1017 $margin=28.35/$this->k; 1018 $this->SetMargins($margin,$margin); 1019 //Interior cell margin (1 mm) 1020 $this->cMargin=$margin/10; 1021 //Line width (0.2 mm) 1022 $this->LineWidth=.567/$this->k; 1023 //Automatic page break 1024 $this->SetAutoPageBreak(true,2*$margin); 1025 //Full width display mode 1026 $this->SetDisplayMode('fullwidth'); 1027 //Compression 1028 $this->SetCompression(true); 1029 //Set default PDF version number 1030 $this->PDFVersion = "1.5"; 1031 1032 $this->encoding = $encoding; 1033 $this->b = 0; 1034 $this->i = 0; 1035 $this->u = 0; 1036 $this->HREF = ''; 1037 $this->fontlist = array("arial", "times", "courier", "helvetica", "symbol"); 1038 $this->issetfont = false; 1039 $this->issetcolor = false; 1040 $this->tableborder = 0; 1041 $this->tdbegin = false; 1042 $this->tdwidth= 0; 1043 $this->tdheight = 0; 1044 if($this->rtl) { 1045 $this->tdalign = "R"; 1046 } else { 1047 $this->tdalign = "L"; 1048 } 1049 $this->tdbgcolor = false; 1050 1051 $this->SetFillColor(200, 200, 200, true); 1052 $this->SetTextColor(0, 0, 0, true); 1053 } 1054 1055 /** 1056 * Enable or disable Right-To-Left language mode 1057 * @param Boolean $enable if true enable Right-To-Left language mode. 1058 * @since 2.0.000 (2008-01-03) 1059 */ 1060 function setRTL($enable) { 1061 $this->rtl = $enable ? true : false; 1062 $this->tmprtl = false; 1063 } 1064 1065 /** 1066 * Force temporary RTL language direction 1067 * @param mixed $mode can be false, 'L' for LTR or 'R' for RTL 1068 * @since 2.1.000 (2008-01-09) 1069 */ 1070 function setTempRTL($mode) { 1071 switch ($mode) { 1072 case false: 1073 case 'L': 1074 case 'R': { 1075 $this->tmprtl = $mode; 1076 } 1077 } 1078 } 1079 1080 /** 1081 * Set the last cell height. 1082 * @param float $h cell height. 1083 * @author Nicola Asuni 1084 * @since 1.53.0.TC034 1085 */ 1086 function setLastH($h) { 1087 $this->lasth=$h; 1088 } 1089 1090 /** 1091 * Set the image scale. 1092 * @param float $scale image scale. 1093 * @author Nicola Asuni 1094 * @since 1.5.2 1095 */ 1096 function setImageScale($scale) { 1097 $this->imgscale=$scale; 1098 } 1099 1100 /** 1101 * Returns the image scale. 1102 * @return float image scale. 1103 * @author Nicola Asuni 1104 * @since 1.5.2 1105 */ 1106 function getImageScale() { 1107 return $this->imgscale; 1108 } 1109 1110 /** 1111 * Returns the page width in units. 1112 * @return int page width. 1113 * @author Nicola Asuni 1114 * @since 1.5.2 1115 */ 1116 function getPageWidth() { 1117 return $this->w; 1118 } 1119 1120 /** 1121 * Returns the page height in units. 1122 * @return int page height. 1123 * @author Nicola Asuni 1124 * @since 1.5.2 1125 */ 1126 function getPageHeight() { 1127 return $this->h; 1128 } 1129 1130 /** 1131 * Returns the page break margin. 1132 * @return int page break margin. 1133 * @author Nicola Asuni 1134 * @since 1.5.2 1135 */ 1136 function getBreakMargin() { 1137 return $this->bMargin; 1138 } 1139 1140 /** 1141 * Returns the scale factor (number of points in user unit). 1142 * @return int scale factor. 1143 * @author Nicola Asuni 1144 * @since 1.5.2 1145 */ 1146 function getScaleFactor() { 1147 return $this->k; 1148 } 1149 1150 /** 1151 * Defines the left, top and right margins. By default, they equal 1 cm. Call this method to change them. 1152 * @param float $left Left margin. 1153 * @param float $top Top margin. 1154 * @param float $right Right margin. Default value is the left one. 1155 * @since 1.0 1156 * @see SetLeftMargin(), SetTopMargin(), SetRightMargin(), SetAutoPageBreak() 1157 */ 1158 function SetMargins($left, $top, $right=-1) { 1159 //Set left, top and right margins 1160 $this->lMargin=$left; 1161 $this->tMargin=$top; 1162 if($right==-1) { 1163 $right=$left; 1164 } 1165 $this->rMargin=$right; 1166 } 1167 1168 /** 1169 * Defines the left margin. The method can be called before creating the first page. If the current abscissa gets out of page, it is brought back to the margin. 1170 * @param float $margin The margin. 1171 * @since 1.4 1172 * @see SetTopMargin(), SetRightMargin(), SetAutoPageBreak(), SetMargins() 1173 */ 1174 function SetLeftMargin($margin) { 1175 //Set left margin 1176 $this->lMargin=$margin; 1177 if(($this->page > 0) AND ($this->x < $margin)) { 1178 $this->x = $margin; 1179 } 1180 } 1181 1182 /** 1183 * Defines the top margin. The method can be called before creating the first page. 1184 * @param float $margin The margin. 1185 * @since 1.5 1186 * @see SetLeftMargin(), SetRightMargin(), SetAutoPageBreak(), SetMargins() 1187 */ 1188 function SetTopMargin($margin) { 1189 //Set top margin 1190 $this->tMargin=$margin; 1191 if(($this->page > 0) AND ($this->y < $margin)) { 1192 $this->y = $margin; 1193 } 1194 } 1195 1196 /** 1197 * Defines the right margin. The method can be called before creating the first page. 1198 * @param float $margin The margin. 1199 * @since 1.5 1200 * @see SetLeftMargin(), SetTopMargin(), SetAutoPageBreak(), SetMargins() 1201 */ 1202 function SetRightMargin($margin) { 1203 $this->rMargin=$margin; 1204 if(($this->page > 0) AND ($this->x > ($this->w - $margin))) { 1205 $this->x = $this->w - $margin; 1206 } 1207 } 1208 1209 /** 1210 * Set the internal Cell padding. 1211 * @param float $pad internal padding. 1212 * @since 2.1.000 (2008-01-09) 1213 * @see Cell(), SetLeftMargin(), SetTopMargin(), SetAutoPageBreak(), SetMargins() 1214 */ 1215 function SetCellPadding($pad) { 1216 $this->cMargin=$pad; 1217 } 1218 1219 /** 1220 * Enables or disables the automatic page breaking mode. When enabling, the second parameter is the distance from the bottom of the page that defines the triggering limit. By default, the mode is on and the margin is 2 cm. 1221 * @param boolean $auto Boolean indicating if mode should be on or off. 1222 * @param float $margin Distance from the bottom of the page. 1223 * @since 1.0 1224 * @see Cell(), MultiCell(), AcceptPageBreak() 1225 */ 1226 function SetAutoPageBreak($auto, $margin=0) { 1227 //Set auto page break mode and triggering margin 1228 $this->AutoPageBreak = $auto; 1229 $this->bMargin = $margin; 1230 $this->PageBreakTrigger = $this->h - $margin; 1231 } 1232 1233 /** 1234 * Defines the way the document is to be displayed by the viewer. The zoom level can be set: pages can be displayed entirely on screen, occupy the full width of the window, use real size, be scaled by a specific zooming factor or use viewer default (configured in the Preferences menu of Acrobat). The page layout can be specified too: single at once, continuous display, two columns or viewer default. By default, documents use the full width mode with continuous display. 1235 * @param mixed $zoom The zoom to use. It can be one of the following string values or a number indicating the zooming factor to use. <ul><li>fullpage: displays the entire page on screen </li><li>fullwidth: uses maximum width of window</li><li>real: uses real size (equivalent to 100% zoom)</li><li>default: uses viewer default mode</li></ul> 1236 * @param string $layout The page layout. Possible values are:<ul><li>single: displays one page at once</li><li>continuous: displays pages continuously (default)</li><li>two: displays two pages on two columns</li><li>default: uses viewer default mode</li></ul> 1237 * @since 1.2 1238 */ 1239 function SetDisplayMode($zoom, $layout='continuous') { 1240 //Set display mode in viewer 1241 if($zoom=='fullpage' or $zoom=='fullwidth' or $zoom=='real' or $zoom=='default' or !is_string($zoom)) { 1242 $this->ZoomMode=$zoom; 1243 } 1244 else { 1245 $this->Error('Incorrect zoom display mode: '.$zoom); 1246 } 1247 if($layout=='single' or $layout=='continuous' or $layout=='two' or $layout=='default') { 1248 $this->LayoutMode=$layout; 1249 } 1250 else { 1251 $this->Error('Incorrect layout display mode: '.$layout); 1252 } 1253 } 1254 1255 /** 1256 * Activates or deactivates page compression. When activated, the internal representation of each page is compressed, which leads to a compression ratio of about 2 for the resulting document. Compression is on by default. 1257 * Note: the Zlib extension is required for this feature. If not present, compression will be turned off. 1258 * @param boolean $compress Boolean indicating if compression must be enabled. 1259 * @since 1.4 1260 */ 1261 function SetCompression($compress) { 1262 //Set page compression 1263 if(function_exists('gzcompress')) { 1264 $this->compress=$compress; 1265 } 1266 else { 1267 $this->compress=false; 1268 } 1269 } 1270 1271 /** 1272 * Defines the title of the document. 1273 * @param string $title The title. 1274 * @since 1.2 1275 * @see SetAuthor(), SetCreator(), SetKeywords(), SetSubject() 1276 */ 1277 function SetTitle($title) { 1278 //Title of document 1279 $this->title=$title; 1280 } 1281 1282 /** 1283 * Defines the subject of the document. 1284 * @param string $subject The subject. 1285 * @since 1.2 1286 * @see SetAuthor(), SetCreator(), SetKeywords(), SetTitle() 1287 */ 1288 function SetSubject($subject) { 1289 //Subject of document 1290 $this->subject=$subject; 1291 } 1292 1293 /** 1294 * Defines the author of the document. 1295 * @param string $author The name of the author. 1296 * @since 1.2 1297 * @see SetCreator(), SetKeywords(), SetSubject(), SetTitle() 1298 */ 1299 function SetAuthor($author) { 1300 //Author of document 1301 $this->author=$author; 1302 } 1303 1304 /** 1305 * Associates keywords with the document, generally in the form 'keyword1 keyword2 ...'. 1306 * @param string $keywords The list of keywords. 1307 * @since 1.2 1308 * @see SetAuthor(), SetCreator(), SetSubject(), SetTitle() 1309 */ 1310 function SetKeywords($keywords) { 1311 //Keywords of document 1312 $this->keywords=$keywords; 1313 } 1314 1315 /** 1316 * Defines the creator of the document. This is typically the name of the application that generates the PDF. 1317 * @param string $creator The name of the creator. 1318 * @since 1.2 1319 * @see SetAuthor(), SetKeywords(), SetSubject(), SetTitle() 1320 */ 1321 function SetCreator($creator) { 1322 //Creator of document 1323 $this->creator=$creator; 1324 } 1325 1326 /** 1327 * Defines an alias for the total number of pages. It will be substituted as the document is closed.<br /> 1328 * <b>Example:</b><br /> 1329 * <pre> 1330 * class PDF extends TCPDF { 1331 * function Footer() { 1332 * //Go to 1.5 cm from bottom 1333 * $this->SetY(-15); 1334 * //Select Arial italic 8 1335 * $this->SetFont('vera','I',8); 1336 * //Print current and total page numbers 1337 * $this->Cell(0,10,'Page '.$this->PageNo().'/{nb}',0,0,'C'); 1338 * } 1339 * } 1340 * $pdf=new PDF(); 1341 * $pdf->AliasNbPages(); 1342 * </pre> 1343 * @param string $alias The alias. Default value: {nb}. 1344 * @since 1.4 1345 * @see PageNo(), Footer() 1346 */ 1347 function AliasNbPages($alias='{nb}') { 1348 //Define an alias for total number of pages 1349 $this->AliasNbPages = $this->_escapetext($alias); 1350 } 1351 1352 /** 1353 * This method is automatically called in case of fatal error; it simply outputs the message and halts the execution. An inherited class may override it to customize the error handling but should always halt the script, or the resulting document would probably be invalid. 1354 * 2004-06-11 :: Nicola Asuni : changed bold tag with strong 1355 * @param string $msg The error message 1356 * @since 1.0 1357 */ 1358 function Error($msg) { 1359 //Fatal error 1360 die('<strong>TCPDF error: </strong>'.$msg); 1361 } 1362 1363 /** 1364 * This method begins the generation of the PDF document. It is not necessary to call it explicitly because AddPage() does it automatically. 1365 * Note: no page is created by this method 1366 * @since 1.0 1367 * @see AddPage(), Close() 1368 */ 1369 function Open() { 1370 //Begin document 1371 $this->state=1; 1372 } 1373 1374 /** 1375 * Terminates the PDF document. It is not necessary to call this method explicitly because Output() does it automatically. If the document contains no page, AddPage() is called to prevent from getting an invalid document. 1376 * @since 1.0 1377 * @see Open(), Output() 1378 */ 1379 function Close() { 1380 //Terminate document 1381 if($this->state==3) { 1382 return; 1383 } 1384 if($this->page==0) { 1385 $this->AddPage(); 1386 } 1387 //Page footer 1388 $this->InFooter=true; 1389 $this->Footer(); 1390 $this->InFooter=false; 1391 //Close page 1392 $this->_endpage(); 1393 //Close document 1394 $this->_enddoc(); 1395 } 1396 1397 /** 1398 * Reset pointer to the last document page. 1399 * @since 2.0.000 (2008-01-04) 1400 * @see setPage(), getPage(), getNumPages() 1401 */ 1402 function lastPage() { 1403 $this->page = count($this->pages); 1404 } 1405 1406 /** 1407 * Move pointer to the apecified document page. 1408 * @param int $pnum page number 1409 * @since 2.1.000 (2008-01-07) 1410 * @see getPage(), lastpage(), getNumPages() 1411 */ 1412 function setPage($pnum) { 1413 if(($pnum > 0) AND ($pnum <= count($this->pages))) { 1414 $this->page = $pnum; 1415 } 1416 } 1417 1418 /** 1419 * Get current document page number. 1420 * @return int page number 1421 * @since 2.1.000 (2008-01-07) 1422 * @see setPage(), lastpage(), getNumPages() 1423 */ 1424 function getPage() { 1425 return $this->page; 1426 } 1427 1428 1429 /** 1430 * Get the total number of insered pages. 1431 * @return int number of pages 1432 * @since 2.1.000 (2008-01-07) 1433 * @see setPage(), getPage(), lastpage() 1434 */ 1435 function getNumPages() { 1436 return count($this->pages); 1437 } 1438 1439 /** 1440 * Adds a new page to the document. If a page is already present, the Footer() method is called first to output the footer. Then the page is added, the current position set to the top-left corner according to the left and top margins, and Header() is called to display the header. 1441 * The font which was set before calling is automatically restored. There is no need to call SetFont() again if you want to continue with the same font. The same is true for colors and line width. 1442 * The origin of the coordinate system is at the top-left corner and increasing ordinates go downwards. 1443 * @param string $orientation Page orientation. Possible values are (case insensitive):<ul><li>P or Portrait</li><li>L or Landscape</li></ul> The default value is the one passed to the constructor. 1444 * @since 1.0 1445 * @see TCPDF(), Header(), Footer(), SetMargins() 1446 */ 1447 function AddPage($orientation='') { 1448 if (count($this->pages) > $this->page) { 1449 // this page has been already added 1450 $this->page++; 1451 $this->y = $this->tMargin; 1452 return; 1453 } 1454 //Start a new page 1455 if($this->state==0) { 1456 $this->Open(); 1457 } 1458 $family=$this->FontFamily; 1459 $style=$this->FontStyle.($this->underline ? 'U' : ''); 1460 $size=$this->FontSizePt; 1461 $lw=$this->LineWidth; 1462 $dc=$this->DrawColor; 1463 $fc=$this->FillColor; 1464 $tc=$this->TextColor; 1465 $cf=$this->ColorFlag; 1466 if($this->page>0) { 1467 //Page footer 1468 $this->InFooter=true; 1469 $this->Footer(); 1470 $this->InFooter=false; 1471 //Close page 1472 $this->_endpage(); 1473 } 1474 //Start new page 1475 $this->_beginpage($orientation); 1476 //Set line cap style to square 1477 $this->_out('2 J'); 1478 //Set line width 1479 $this->LineWidth=$lw; 1480 $this->_out(sprintf('%.2f w',$lw*$this->k)); 1481 //Set font 1482 if($family) { 1483 $this->SetFont($family,$style,$size); 1484 } 1485 //Set colors 1486 $this->DrawColor=$dc; 1487 if($dc!='0 G') { 1488 $this->_out($dc); 1489 } 1490 $this->FillColor=$fc; 1491 if($fc!='0 g') { 1492 $this->_out($fc); 1493 } 1494 $this->TextColor=$tc; 1495 $this->ColorFlag=$cf; 1496 //Page header 1497 $this->Header(); 1498 //Restore line width 1499 if($this->LineWidth!=$lw) { 1500 $this->LineWidth=$lw; 1501 $this->_out(sprintf('%.2f w',$lw*$this->k)); 1502 } 1503 //Restore font 1504 if($family) { 1505 $this->SetFont($family,$style,$size); 1506 } 1507 //Restore colors 1508 if($this->DrawColor!=$dc) { 1509 $this->DrawColor=$dc; 1510 $this->_out($dc); 1511 } 1512 if($this->FillColor!=$fc) { 1513 $this->FillColor=$fc; 1514 $this->_out($fc); 1515 } 1516 $this->TextColor=$tc; 1517 $this->ColorFlag=$cf; 1518 } 1519 1520 /** 1521 * Set header data. 1522 * @param string $ln header image logo 1523 * @param string $lw header image logo width in mm 1524 * @param string $ht string to print as title on document header 1525 * @param string $hs string to print on document header 1526 */ 1527 function setHeaderData($ln="", $lw=0, $ht="", $hs="") { 1528 $this->header_logo = $ln; 1529 $this->header_logo_width = $lw; 1530 $this->header_title = $ht; 1531 $this->header_string = $hs; 1532 } 1533 1534 /** 1535 * Set header margin. 1536 * (minimum distance between header and top page margin) 1537 * @param int $hm distance in millimeters 1538 */ 1539 function setHeaderMargin($hm=10) { 1540 $this->header_margin = $hm; 1541 } 1542 1543 /** 1544 * Set footer margin. 1545 * (minimum distance between footer and bottom page margin) 1546 * @param int $fm distance in millimeters 1547 */ 1548 function setFooterMargin($fm=10) { 1549 $this->footer_margin = $fm; 1550 } 1551 1552 /** 1553 * Set a flag to print page header. 1554 * @param boolean $val set to true to print the page header (default), false otherwise. 1555 */ 1556 function setPrintHeader($val=true) { 1557 $this->print_header = $val; 1558 } 1559 1560 /** 1561 * Set a flag to print page footer. 1562 * @param boolean $value set to true to print the page footer (default), false otherwise. 1563 */ 1564 function setPrintFooter($val=true) { 1565 $this->print_footer = $val; 1566 } 1567 1568 /** 1569 * This method is used to render the page header. 1570 * It is automatically called by AddPage() and could be overwritten in your own inherited class. 1571 */ 1572 function Header() { 1573 if ($this->print_header) { 1574 1575 if (!isset($this->original_lMargin)) { 1576 $this->original_lMargin = $this->lMargin; 1577 } 1578 if (!isset($this->original_rMargin)) { 1579 $this->original_rMargin = $this->rMargin; 1580 } 1581 1582 // reset original header margins 1583 $this->rMargin = $this->original_rMargin; 1584 $this->lMargin = $this->original_lMargin; 1585 1586 // save current font values 1587 $font_family = $this->FontFamily; 1588 $font_style = $this->FontStyle; 1589 $font_size = $this->FontSizePt; 1590 1591 //set current position 1592 if ($this->rtl) { 1593 $this->SetXY($this->original_rMargin, $this->header_margin); 1594 } else { 1595 $this->SetXY($this->original_lMargin, $this->header_margin); 1596 } 1597 1598 if (($this->header_logo) AND ($this->header_logo != K_BLANK_IMAGE)) { 1599 $this->Image(K_PATH_IMAGES.$this->header_logo, $this->GetX(), $this->header_margin, $this->header_logo_width); 1600 } else { 1601 $this->img_rb_x = $this->GetX(); 1602 $this->img_rb_y = $this->GetY(); 1603 } 1604 1605 $cell_height = round((K_CELL_HEIGHT_RATIO * $this->header_font[2]) / $this->k, 2); 1606 // set starting margin for text data cell 1607 if ($this->rtl) { 1608 $header_x = $this->original_rMargin + ($this->header_logo_width * 1.1); 1609 } else { 1610 $header_x = $this->original_lMargin + ($this->header_logo_width * 1.1); 1611 } 1612 1613 // header title 1614 $this->SetFont($this->header_font[0], 'B', $this->header_font[2] + 1); 1615 $this->SetX($header_x); 1616 $this->Cell($this->header_width, $cell_height, $this->header_title, 0, 1, ''); 1617 1618 // header string 1619 $this->SetFont($this->header_font[0], $this->header_font[1], $this->header_font[2]); 1620 $this->SetX($header_x); 1621 $this->MultiCell($this->header_width, $cell_height, $this->header_string, 0, '', 0, 1, 0, 0, true, 0); 1622 1623 // print an ending header line 1624 //set style for cell border 1625 $prevlinewidth = $this->GetLineWidth(); 1626 $line_width = 0.3; 1627 $this->SetLineWidth($line_width); 1628 $this->SetDrawColor(0, 0, 0); 1629 $this->SetY(1 + max($this->img_rb_y, $this->GetY())); 1630 if ($this->rtl) { 1631 $this->SetX($this->original_rMargin); 1632 } else { 1633 $this->SetX($this->original_lMargin); 1634 } 1635 $this->Cell(0, 0, '', 'T', 0, 'C'); 1636 $this->SetLineWidth($prevlinewidth); 1637 1638 //restore position 1639 if ($this->rtl) { 1640 $this->SetXY($this->original_rMargin, $this->tMargin); 1641 } else { 1642 $this->SetXY($this->original_lMargin, $this->tMargin); 1643 } 1644 1645 // restore font values 1646 $this->SetFont($font_family, $font_style, $font_size); 1647 } 1648 } 1649 1650 /** 1651 * This method is used to render the page footer. 1652 * It is automatically called by AddPage() and could be overwritten in your own inherited class. 1653 */ 1654 function Footer() { 1655 if ($this->print_footer) { 1656 1657 if (!isset($this->original_lMargin)) { 1658 $this->original_lMargin = $this->lMargin; 1659 } 1660 if (!isset($this->original_rMargin)) { 1661 $this->original_rMargin = $this->rMargin; 1662 } 1663 1664 // reset original header margins 1665 $this->rMargin = $this->original_rMargin; 1666 $this->lMargin = $this->original_lMargin; 1667 1668 // save current font values 1669 $font_family = $this->FontFamily; 1670 $font_style = $this->FontStyle; 1671 $font_size = $this->FontSizePt; 1672 1673 //set font 1674 $this->SetFont($this->footer_font[0], $this->footer_font[1] , $this->footer_font[2]); 1675 //set style for cell border 1676 $prevlinewidth = $this->GetLineWidth(); 1677 $line_width = 0.3; 1678 $this->SetLineWidth($line_width); 1679 $this->SetDrawColor(0, 0, 0); 1680 1681 $footer_height = round((K_CELL_HEIGHT_RATIO * $this->footer_font[2]) / $this->k, 2); //footer height 1682 //get footer y position 1683 $footer_y = $this->h - $this->footer_margin - $footer_height; 1684 //set current position 1685 if ($this->rtl) { 1686 $this->SetXY($this->original_rMargin, $footer_y); 1687 } else { 1688 $this->SetXY($this->original_lMargin, $footer_y); 1689 } 1690 1691 //print document barcode 1692 if ($this->barcode) { 1693 $this->Ln(); 1694 $barcode_width = round(($this->w - $this->original_lMargin - $this->original_rMargin)/3); //max width 1695 $this->writeBarcode($this->GetX(), $footer_y + $line_width, $barcode_width, $footer_height - $line_width, "C128B", false, false, 2, $this->barcode); 1696 } 1697 1698 $pagenumtxt = $this->l['w_page']." ".$this->PageNo().' / {nb}'; 1699 1700 $this->SetY($footer_y); 1701 1702 //Print page number 1703 if ($this->rtl) { 1704 $this->SetX($this->original_rMargin); 1705 $this->Cell(0, $footer_height, $pagenumtxt, 'T', 0, 'L'); 1706 } else { 1707 $this->SetX($this->original_lMargin); 1708 $this->Cell(0, $footer_height, $pagenumtxt, 'T', 0, 'R'); 1709 } 1710 // restore line width 1711 $this->SetLineWidth($prevlinewidth); 1712 1713 // restore font values 1714 $this->SetFont($font_family, $font_style, $font_size); 1715 } 1716 } 1717 1718 /** 1719 * Returns the current page number. 1720 * @return int page number 1721 * @since 1.0 1722 * @see AliasNbPages() 1723 */ 1724 function PageNo() { 1725 //Get current page number 1726 return $this->page; 1727 } 1728 1729 /** 1730 * Defines the color used for all drawing operations (lines, rectangles and cell borders). It can be expressed in RGB components or gray scale. The method can be called before the first page is created and the value is retained from page to page. 1731 * @param int $r If g et b are given, red component; if not, indicates the gray level. Value between 0 and 255 1732 * @param int $g Green component (between 0 and 255) 1733 * @param int $b Blue component (between 0 and 255) 1734 * @since 1.3 1735 * @see SetFillColor(), SetTextColor(), Line(), Rect(), Cell(), MultiCell() 1736 */ 1737 function SetDrawColor($r, $g=-1, $b=-1) { 1738 //Set color for all stroking operations 1739 if(($r==0 and $g==0 and $b==0) or $g==-1) { 1740 $this->DrawColor=sprintf('%.3f G',$r/255); 1741 } 1742 else { 1743 $this->DrawColor=sprintf('%.3f %.3f %.3f RG',$r/255,$g/255,$b/255); 1744 } 1745 if($this->page>0) { 1746 $this->_out($this->DrawColor); 1747 } 1748 } 1749 1750 /** 1751 * Defines the color used for all filling operations (filled rectangles and cell backgrounds). It can be expressed in RGB components or gray scale. The method can be called before the first page is created and the value is retained from page to page. 1752 * @param int $r If g et b are given, red component; if not, indicates the gray level. Value between 0 and 255 1753 * @param int $g Green component (between 0 and 255) 1754 * @param int $b Blue component (between 0 and 255) 1755 * @param boolean $storeprev if true stores the RGB array on $prevFillColor variable. 1756 * @since 1.3 1757 * @see SetDrawColor(), SetTextColor(), Rect(), Cell(), MultiCell() 1758 */ 1759 function SetFillColor($r, $g=-1, $b=-1, $storeprev=false) { 1760 //Set color for all filling operations 1761 if(($r==0 and $g==0 and $b==0) or $g==-1) { 1762 $this->FillColor=sprintf('%.3f g',$r/255); 1763 } 1764 else { 1765 $this->FillColor=sprintf('%.3f %.3f %.3f rg',$r/255,$g/255,$b/255); 1766 } 1767 $this->ColorFlag=($this->FillColor!=$this->TextColor); 1768 if($this->page>0) { 1769 $this->_out($this->FillColor); 1770 } 1771 if ($storeprev) { 1772 // store color as previous value 1773 $this->prevFillColor = array($r, $g, $b); 1774 } 1775 } 1776 1777 /** 1778 * Defines the color used for text. It can be expressed in RGB components or gray scale. The method can be called before the first page is created and the value is retained from page to page. 1779 * @param int $r If g et b are given, red component; if not, indicates the gray level. Value between 0 and 255 1780 * @param int $g Green component (between 0 and 255) 1781 * @param int $b Blue component (between 0 and 255) 1782 * @param boolean $storeprev if true stores the RGB array on $prevTextColor variable. 1783 * @since 1.3 1784 * @see SetDrawColor(), SetFillColor(), Text(), Cell(), MultiCell() 1785 */ 1786 function SetTextColor($r, $g=-1, $b=-1, $storeprev=false) { 1787 //Set color for text 1788 if(($r==0 and $g==0 and $b==0) or $g==-1) { 1789 $this->TextColor=sprintf('%.3f g',$r/255); 1790 } 1791 else { 1792 $this->TextColor=sprintf('%.3f %.3f %.3f rg',$r/255,$g/255,$b/255); 1793 } 1794 $this->ColorFlag=($this->FillColor!=$this->TextColor); 1795 if ($storeprev) { 1796 // store color as previous value 1797 $this->prevTextColor = array($r, $g, $b); 1798 } 1799 } 1800 1801 /** 1802 * Returns the length of a string in user unit. A font must be selected.<br> 1803 * @param string $s The string whose length is to be computed 1804 * @return int string length 1805 * @author Nicola Asuni 1806 * @since 1.2 1807 */ 1808 function GetStringWidth($s) { 1809 return $this->GetArrStringWidth($this->utf8Bidi($this->UTF8StringToArray($s), $this->tmprtl)); 1810 } 1811 1812 /** 1813 * Returns the string length of an array of chars in user unit. A font must be selected.<br> 1814 * @param string $arr The array of chars whose total length is to be computed 1815 * @return int string length 1816 * @author Nicola Asuni 1817 * @since 2.4.000 (2008-03-06) 1818 */ 1819 function GetArrStringWidth($sa) { 1820 $w = 0; 1821 foreach($sa as $char) { 1822 $w += $this->GetCharWidth($char); 1823 } 1824 return $w; 1825 } 1826 1827 /** 1828 * Returns the length of the char in user unit. A font must be selected.<br> 1829 * @param string $char The char whose length is to be returned 1830 * @return int char width 1831 * @author Nicola Asuni 1832 * @since 2.4.000 (2008-03-06) 1833 */ 1834 function GetCharWidth($char) { 1835 $cw = &$this->CurrentFont['cw']; 1836 if (isset($cw[$char])) { 1837 $w = $cw[$char]; 1838 } elseif(isset($cw[ord($char)])) { 1839 $w = $cw[ord($char)]; 1840 } elseif(isset($cw[chr($char)])) { 1841 $w = $cw[chr($char)]; 1842 } elseif(isset($this->CurrentFont['desc']['MissingWidth'])) { 1843 $w = $this->CurrentFont['desc']['MissingWidth']; // set default size 1844 } else { 1845 $w = 500; 1846 } 1847 return ($w * $this->FontSize / 1000); 1848 } 1849 1850 /** 1851 * Returns the numbero of characters in a string. 1852 * @param string $s The input string. 1853 * @return int number of characters 1854 * @since 2.0.0001 (2008-01-07) 1855 */ 1856 function GetNumChars($s) { 1857 if($this->isunicode) { 1858 return count($this->UTF8StringToArray($s)); 1859 } 1860 return strlen($s); 1861 } 1862 1863 /** 1864 * Imports a TrueType or Type1 font and makes it available. It is necessary to generate a font definition file first with the makefont.php utility. The definition file (and the font file itself when embedding) must be present either in the current directory or in the one indicated by K_PATH_FONTS if the constant is defined. If it could not be found, the error "Could not include font definition file" is generated. 1865 * Support UTF-8 Unicode [Nicola Asuni, 2005-01-02]. 1866 * <b>Example</b>:<br /> 1867 * <pre> 1868 * $pdf->AddFont('Comic','I'); 1869 * // is equivalent to: 1870 * $pdf->AddFont('Comic','I','comici.php'); 1871 * </pre> 1872 * @param string $family Font family. The name can be chosen arbitrarily. If it is a standard family name, it will override the corresponding font. 1873 * @param string $style Font style. Possible values are (case insensitive):<ul><li>empty string: regular (default)</li><li>B: bold</li><li>I: italic</li><li>BI or IB: bold italic</li></ul> 1874 * @param string $file The font definition file. By default, the name is built from the family and style, in lower case with no space. 1875 * @since 1.5 1876 * @see SetFont() 1877 */ 1878 function AddFont($family, $style='', $file='') { 1879 if(empty($family)) { 1880 return; 1881 } 1882 1883 //Add a TrueType or Type1 font 1884 $family = strtolower($family); 1885 if((!$this->isunicode) AND ($family == 'arial')) { 1886 $family = 'helvetica'; 1887 } 1888 1889 $style=strtoupper($style); 1890 $style=str_replace('U','',$style); 1891 if($style == 'IB') { 1892 $style = 'BI'; 1893 } 1894 1895 $fontkey = $family.$style; 1896 // check if the font has been already added 1897 if(isset($this->fonts[$fontkey])) { 1898 return; 1899 } 1900 1901 if($file=='') { 1902 $file = str_replace(' ', '', $family).strtolower($style).'.php'; 1903 } 1904 if(!file_exists($this->_getfontpath().$file)) { 1905 // try to load the basic file without styles 1906 $file = str_replace(' ', '', $family).'.php'; 1907 } 1908 1909 include($this->_getfontpath().$file); 1910 1911 if(!isset($name) AND !isset($fpdf_charwidths)) { 1912 $this->Error('Could not include font definition file'); 1913 } 1914 1915 $i = count($this->fonts)+1; 1916 1917 if($this->isunicode) { 1918 $this->fonts[$fontkey] = array('i'=>$i, 'type'=>$type, 'name'=>$name, 'desc'=>$desc, 'up'=>$up, 'ut'=>$ut, 'cw'=>$cw, 'enc'=>$enc, 'file'=>$file, 'ctg'=>$ctg); 1919 $fpdf_charwidths[$fontkey] = $cw; 1920 } else { 1921 $this->fonts[$fontkey]=array('i'=>$i, 'type'=>'core', 'name'=>$this->CoreFonts[$fontkey], 'up'=>-100, 'ut'=>50, 'cw'=>$fpdf_charwidths[$fontkey]); 1922 } 1923 1924 if(isset($diff) AND (!empty($diff))) { 1925 //Search existing encodings 1926 $d=0; 1927 $nb=count($this->diffs); 1928 for($i=1;$i<=$nb;$i++) { 1929 if($this->diffs[$i]==$diff) { 1930 $d=$i; 1931 break; 1932 } 1933 } 1934 if($d==0) { 1935 $d=$nb+1; 1936 $this->diffs[$d]=$diff; 1937 } 1938 $this->fonts[$fontkey]['diff']=$d; 1939 } 1940 if(!empty($file)) { 1941 if((strcasecmp($type,"TrueType") == 0) OR (strcasecmp($type,"TrueTypeUnicode") == 0)) { 1942 $this->FontFiles[$file]=array('length1'=>$originalsize); 1943 } 1944 else { 1945 $this->FontFiles[$file]=array('length1'=>$size1,'length2'=>$size2); 1946 } 1947 } 1948 } 1949 1950 /** 1951 * Sets the font used to print character strings. It is mandatory to call this method at least once before printing text or the resulting document would not be valid. 1952 * The font can be either a standard one or a font added via the AddFont() method. Standard fonts use Windows encoding cp1252 (Western Europe). 1953 * The method can be called before the first page is created and the font is retained from page to page. 1954 If you just wish to change the current font size, it is simpler to call SetFontSize(). 1955 * Note: for the standard fonts, the font metric files must be accessible. There are three possibilities for this:<ul><li>They are in the current directory (the one where the running script lies)</li><li>They are in one of the directories defined by the include_path parameter</li><li>They are in the directory defined by the K_PATH_FONTS constant</li></ul><br /> 1956 * Example for the last case (note the trailing slash):<br /> 1957 * <pre> 1958 * define('K_PATH_FONTS','/home/www/font/'); 1959 * require('tcpdf.php'); 1960 * 1961 * //Times regular 12 1962 * $pdf->SetFont('Times'); 1963 * //Arial bold 14 1964 * $pdf->SetFont('vera','B',14); 1965 * //Removes bold 1966 * $pdf->SetFont(''); 1967 * //Times bold, italic and underlined 14 1968 * $pdf->SetFont('Times','BIU'); 1969 * </pre><br /> 1970 * If the file corresponding to the requested font is not found, the error "Could not include font metric file" is generated. 1971 * @param string $family Family font. It can be either a name defined by AddFont() or one of the standard families (case insensitive):<ul><li>Courier (fixed-width)</li><li>Helvetica or Arial (synonymous; sans serif)</li><li>Times (serif)</li><li>Symbol (symbolic)</li><li>ZapfDingbats (symbolic)</li></ul>It is also possible to pass an empty string. In that case, the current family is retained. 1972 * @param string $style Font style. Possible values are (case insensitive):<ul><li>empty string: regular</li><li>B: bold</li><li>I: italic</li><li>U: underline</li></ul>or any combination. The default value is regular. Bold and italic styles do not apply to Symbol and ZapfDingbats 1973 * @param float $size Font size in points. The default value is the current size. If no size has been specified since the beginning of the document, the value taken is 12 1974 * @since 1.0 1975 * @see AddFont(), SetFontSize() 1976 */ 1977 function SetFont($family, $style='', $size=0) { 1978 // save previous values 1979 $this->prevFontFamily = $this->FontFamily; 1980 $this->prevFontStyle = $this->FontStyle; 1981 1982 //Select a font; size given in points 1983 global $fpdf_charwidths; 1984 1985 $family=strtolower($family); 1986 if($family=='') { 1987 $family=$this->FontFamily; 1988 } 1989 if((!$this->isunicode) AND ($family == 'arial')) { 1990 $family = 'helvetica'; 1991 } 1992 elseif(($family=="symbol") OR ($family=="zapfdingbats")) { 1993 $style=''; 1994 } 1995 $style=strtoupper($style); 1996 1997 if(strpos($style,'U')!==false) { 1998 $this->underline=true; 1999 $style=str_replace('U','',$style); 2000 } 2001 else { 2002 $this->underline=false; 2003 } 2004 if($style=='IB') { 2005 $style='BI'; 2006 } 2007 if($size==0) { 2008 $size=$this->FontSizePt; 2009 } 2010 2011 // try to add font (if not already added) 2012 if($this->isunicode) { 2013 $this->AddFont($family, $style); 2014 } 2015 2016 //Test if font is already selected 2017 if(($this->FontFamily == $family) AND ($this->FontStyle == $style) AND ($this->FontSizePt == $size)) { 2018 return; 2019 } 2020 2021 $fontkey = $family.$style; 2022 //if(!isset($this->fonts[$fontkey]) AND isset($this->fonts[$family])) { 2023 // $style=''; 2024 //} 2025 2026 //Test if used for the first time 2027 if(!isset($this->fonts[$fontkey])) { 2028 //Check if one of the standard fonts 2029 if(isset($this->CoreFonts[$fontkey])) { 2030 if(!isset($fpdf_charwidths[$fontkey])) { 2031 //Load metric file 2032 $file = $family; 2033 if(($family!='symbol') AND ($family!='zapfdingbats')) { 2034 $file .= strtolower($style); 2035 } 2036 if(!file_exists($this->_getfontpath().$file.'.php')) { 2037 // try to load the basic file without styles 2038 $file = $family; 2039 $fontkey = $family; 2040 } 2041 include($this->_getfontpath().$file.'.php'); 2042 if (($this->isunicode AND !isset($ctg)) OR ((!$this->isunicode) AND (!isset($fpdf_charwidths[$fontkey]))) ) { 2043 $this->Error("Could not include font metric file [".$fontkey."]: ".$this->_getfontpath().$file.".php"); 2044 } 2045 } 2046 $i = count($this->fonts) + 1; 2047 2048 if($this->isunicode) { 2049 $this->fonts[$fontkey] = array('i'=>$i, 'type'=>$type, 'name'=>$name, 'desc'=>$desc, 'up'=>$up, 'ut'=>$ut, 'cw'=>$cw, 'enc'=>$enc, 'file'=>$file, 'ctg'=>$ctg); 2050 $fpdf_charwidths[$fontkey] = $cw; 2051 } else { 2052 $this->fonts[$fontkey]=array('i'=>$i, 'type'=>'core', 'name'=>$this->CoreFonts[$fontkey], 'up'=>-100, 'ut'=>50, 'cw'=>$fpdf_charwidths[$fontkey]); 2053 } 2054 } 2055 else { 2056 $this->Error('Undefined font: '.$family.' '.$style); 2057 } 2058 } 2059 //Select it 2060 $this->FontFamily = $family; 2061 $this->FontStyle = $style; 2062 $this->FontSizePt = $size; 2063 $this->FontSize = $size / $this->k; 2064 $this->CurrentFont = &$this->fonts[$fontkey]; 2065 if($this->page>0) { 2066 $this->_out(sprintf('BT /F%d %.2f Tf ET', $this->CurrentFont['i'], $this->FontSizePt)); 2067 } 2068 } 2069 2070 /** 2071 * Defines the size of the current font. 2072 * @param float $size The size (in points) 2073 * @since 1.0 2074 * @see SetFont() 2075 */ 2076 function SetFontSize($size) { 2077 //Set font size in points 2078 if($this->FontSizePt==$size) { 2079 return; 2080 } 2081 $this->FontSizePt = $size; 2082 $this->FontSize = $size / $this->k; 2083 if($this->page > 0) { 2084 $this->_out(sprintf('BT /F%d %.2f Tf ET', $this->CurrentFont['i'], $this->FontSizePt)); 2085 } 2086 } 2087 2088 /** 2089 * Creates a new internal link and returns its identifier. An internal link is a clickable area which directs to another place within the document.<br /> 2090 * The identifier can then be passed to Cell(), Write(), Image() or Link(). The destination is defined with SetLink(). 2091 * @since 1.5 2092 * @see Cell(), Write(), Image(), Link(), SetLink() 2093 */ 2094 function AddLink() { 2095 //Create a new internal link 2096 $n=count($this->links)+1; 2097 $this->links[$n]=array(0,0); 2098 return $n; 2099 } 2100 2101 /** 2102 * Defines the page and position a link points to 2103 * @param int $link The link identifier returned by AddLink() 2104 * @param float $y Ordinate of target position; -1 indicates the current position. The default value is 0 (top of page) 2105 * @param int $page Number of target page; -1 indicates the current page. This is the default value 2106 * @since 1.5 2107 * @see AddLink() 2108 */ 2109 function SetLink($link, $y=0, $page=-1) { 2110 //Set destination of internal link 2111 if($y==-1) { 2112 $y=$this->y; 2113 } 2114 if($page==-1) { 2115 $page=$this->page; 2116 } 2117 $this->links[$link]=array($page,$y); 2118 } 2119 2120 /** 2121 * Puts a link on a rectangular area of the page. Text or image links are generally put via Cell(), Write() or Image(), but this method can be useful for instance to define a clickable area inside an image. 2122 * @param float $x Abscissa of the upper-left corner of the rectangle (or upper-right for RTL languages) 2123 * @param float $y Ordinate of the upper-left corner of the rectangle (or upper-right for RTL languages) 2124 * @param float $w Width of the rectangle 2125 * @param float $h Height of the rectangle 2126 * @param mixed $link URL or identifier returned by AddLink() 2127 * @since 1.5 2128 * @see AddLink(), Cell(), Write(), Image() 2129 */ 2130 function Link($x, $y, $w, $h, $link) { 2131 $this->PageLinks[$this->page][] = array($x * $this->k, $this->hPt - $y * $this->k, $w * $this->k, $h*$this->k, $link); 2132 } 2133 2134 /** 2135 * Prints a character string. The origin is on the left of the first charcter, on the baseline. This method allows to place a string precisely on the page, but it is usually easier to use Cell(), MultiCell() or Write() which are the standard methods to print text. 2136 * @param float $x Abscissa of the origin 2137 * @param float $y Ordinate of the origin 2138 * @param string $txt String to print 2139 * @since 1.0 2140 * @see SetFont(), SetTextColor(), Cell(), MultiCell(), Write() 2141 */ 2142 function Text($x, $y, $txt) { 2143 //Output a string 2144 if($this->rtl) { 2145 // bidirectional algorithm (some chars may be changed affecting the line length) 2146 $s = $this->utf8Bidi($this->UTF8StringToArray($txt), $this->tmprtl); 2147 $l = $this->GetArrStringWidth($s); 2148 $xr = $this->w - $x - $this->GetArrStringWidth($s); 2149 } else { 2150 $xr = $x; 2151 } 2152 $s = sprintf('BT %.2f %.2f Td (%s) Tj ET', $xr * $this->k, ($this->h-$y) * $this->k, $this->_escapetext($txt)); 2153 if($this->underline AND ($txt!='')) { 2154 $s .= ' '.$this->_dounderline($xr, $y, $txt); 2155 } 2156 if($this->ColorFlag) { 2157 $s='q '.$this->TextColor.' '.$s.' Q'; 2158 } 2159 $this->_out($s); 2160 } 2161 2162 /** 2163 * Whenever a page break condition is met, the method is called, and the break is issued or not depending on the returned value. The default implementation returns a value according to the mode selected by SetAutoPageBreak().<br /> 2164 * This method is called automatically and should not be called directly by the application.<br /> 2165 * <b>Example:</b><br /> 2166 * The method is overriden in an inherited class in order to obtain a 3 column layout:<br /> 2167 * <pre> 2168 * class PDF extends TCPDF { 2169 * var $col=0; 2170 * 2171 * function SetCol($col) { 2172 * //Move position to a column 2173 * $this->col=$col; 2174 * $x=10+$col*65; 2175 * $this->SetLeftMargin($x); 2176 * $this->SetX($x); 2177 * } 2178 * 2179 * function AcceptPageBreak() { 2180 * if($this->col<2) { 2181 * //Go to next column 2182 * $this->SetCol($this->col+1); 2183 * $this->SetY(10); 2184 * return false; 2185 * } 2186 * else { 2187 * //Go back to first column and issue page break 2188 * $this->SetCol(0); 2189 * return true; 2190 * } 2191 * } 2192 * } 2193 * 2194 * $pdf=new PDF(); 2195 * $pdf->Open(); 2196 * $pdf->AddPage(); 2197 * $pdf->SetFont('vera','',12); 2198 * for($i=1;$i<=300;$i++) { 2199 * $pdf->Cell(0,5,"Line $i",0,1); 2200 * } 2201 * $pdf->Output(); 2202 * </pre> 2203 * @return boolean 2204 * @since 1.4 2205 * @see SetAutoPageBreak() 2206 */ 2207 function AcceptPageBreak() { 2208 //Accept automatic page break or not 2209 return $this->AutoPageBreak; 2210 } 2211 2212 /** 2213 * Prints a cell (rectangular area) with optional borders, background color and character string. The upper-left corner of the cell corresponds to the current position. The text can be aligned or centered. After the call, the current position moves to the right or to the next line. It is possible to put a link on the text.<br /> 2214 * If automatic page breaking is enabled and the cell goes beyond the limit, a page break is done before outputting. 2215 * @param float $w Cell width. If 0, the cell extends up to the right margin. 2216 * @param float $h Cell height. Default value: 0. 2217 * @param string $txt String to print. Default value: empty string. 2218 * @param mixed $border Indicates if borders must be drawn around the cell. The value can be either a number:<ul><li>0: no border (default)</li><li>1: frame</li></ul>or a string containing some or all of the following characters (in any order):<ul><li>L: left</li><li>T: top</li><li>R: right</li><li>B: bottom</li></ul> 2219 * @param int $ln Indicates where the current position should go after the call. Possible values are:<ul><li>0: to the right (or left for RTL languages)</li><li>1: to the beginning of the next line</li><li>2: below</li></ul> 2220 Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: 0. 2221 * @param string $align Allows to center or align the text. Possible values are:<ul><li>L or empty string: left align (default value)</li><li>C: center</li><li>R: right align</li><li>J: justify</li></ul> 2222 * @param int $fill Indicates if the cell background must be painted (1) or transparent (0). Default value: 0. 2223 * @param mixed $link URL or identifier returned by AddLink(). 2224 * @param int $stretch stretch carachter mode: <ul><li>0 = disabled</li><li>1 = horizontal scaling only if necessary</li><li>2 = forced horizontal scaling</li><li>3 = character spacing only if necessary</li><li>4 = forced character spacing</li></ul> 2225 * @since 1.0 2226 * @see SetFont(), SetDrawColor(), SetFillColor(), SetTextColor(), SetLineWidth(), AddLink(), Ln(), MultiCell(), Write(), SetAutoPageBreak() 2227 */ 2228 function Cell($w, $h=0, $txt='', $border=0, $ln=0, $align='', $fill=0, $link='', $stretch=0) { 2229 2230 $k = $this->k; 2231 2232 if((($this->y + $h) > $this->PageBreakTrigger) AND empty($this->InFooter) AND $this->AcceptPageBreak()) { 2233 //Automatic page break 2234 $x = $this->x; 2235 $ws = $this->ws; 2236 if($ws > 0) { 2237 $this->ws = 0; 2238 $this->_out('0 Tw'); 2239 } 2240 $this->AddPage($this->CurOrientation); 2241 if($ws > 0) { 2242 $this->ws = $ws; 2243 $this->_out(sprintf('%.3f Tw',$ws * $k)); 2244 } 2245 $this->x = $x; 2246 } 2247 if($w == 0) { 2248 if ($this->rtl) { 2249 $w = $this->x - $this->lMargin; 2250 } else { 2251 $w = $this->w - $this->rMargin - $this->x; 2252 } 2253 } 2254 $s = ''; 2255 if(($fill == 1) OR ($border == 1)) { 2256 if($fill == 1) { 2257 $op = ($border == 1) ? 'B' : 'f'; 2258 } else { 2259 $op = 'S'; 2260 } 2261 if ($this->rtl) { 2262 $xk = ($this->x - $w) * $k; 2263 } else { 2264 $xk = $this->x * $k; 2265 } 2266 $s .= sprintf('%.2f %.2f %.2f %.2f re %s ', $xk, ($this->h - $this->y) * $k, $w * $k, -$h * $k, $op); 2267 } 2268 if(is_string($border)) { 2269 $x=$this->x; 2270 $y=$this->y; 2271 if(strpos($border,'L')!==false) { 2272 if ($this->rtl) { 2273 $xk = ($x - $w) * $k; 2274 } else { 2275 $xk = $x * $k; 2276 } 2277 $s.=sprintf('%.2f %.2f m %.2f %.2f l S ',$xk,($this->h-$y)*$k,$xk,($this->h-($y+$h))*$k); 2278 } 2279 if(strpos($border,'T')!==false) { 2280 if ($this->rtl) { 2281 $xk = ($x - $w) * $k; 2282 $xwk = $x * $k; 2283 } else { 2284 $xk = $x * $k; 2285 $xwk = ($x + $w) * $k; 2286 } 2287 $s.=sprintf('%.2f %.2f m %.2f %.2f l S ',$xk,($this->h-$y)*$k,$xwk,($this->h-$y)*$k); 2288 } 2289 if(strpos($border,'R')!==false) { 2290 if ($this->rtl) { 2291 $xk = $x * $k; 2292 } else { 2293 $xk = ($x + $w) * $k; 2294 } 2295 $s.=sprintf('%.2f %.2f m %.2f %.2f l S ',$xk,($this->h-$y)*$k,$xk,($this->h-($y+$h))*$k); 2296 } 2297 if(strpos($border,'B')!==false) { 2298 if ($this->rtl) { 2299 $xk = ($x - $w) * $k; 2300 $xwk = $x * $k; 2301 } else { 2302 $xk = $x * $k; 2303 $xwk = ($x + $w) * $k; 2304 } 2305 $s.=sprintf('%.2f %.2f m %.2f %.2f l S ',$xk,($this->h-($y+$h))*$k,$xwk,($this->h-($y+$h))*$k); 2306 } 2307 } 2308 if($txt != '') { 2309 // text lenght 2310 $width = $this->GetStringWidth($txt); 2311 // ratio between cell lenght and text lenght 2312 $ratio = ($w - (2 * $this->cMargin)) / $width; 2313 2314 // stretch text if required 2315 if (($stretch > 0) AND (($ratio < 1) OR (($ratio > 1) AND (($stretch % 2) == 0)))) { 2316 if ($stretch > 2) { 2317 // spacing 2318 //Calculate character spacing in points 2319 $char_space = ($w - $width - (2 * $this->cMargin)) / max($this->GetNumChars($s)-1,1) * $this->k; 2320 //Set character spacing 2321 $this->_out(sprintf('BT %.2f Tc ET', $char_space)); 2322 } else { 2323 // scaling 2324 //Calculate horizontal scaling 2325 $horiz_scale = $ratio*100.0; 2326 //Set horizontal scaling 2327 $this->_out(sprintf('BT %.2f Tz ET', $horiz_scale)); 2328 } 2329 $align = ''; 2330 $width = $w - (2 * $this->cMargin); 2331 } else { 2332 $stretch == 0; 2333 } 2334 2335 if($align == 'L') { 2336 if ($this->rtl) { 2337 $dx = $w - $width - $this->cMargin; 2338 } else { 2339 $dx = $this->cMargin; 2340 } 2341 } elseif($align == 'R') { 2342 if ($this->rtl) { 2343 $dx = $this->cMargin; 2344 } else { 2345 $dx = $w - $width - $this->cMargin; 2346 } 2347 } elseif($align=='C') { 2348 $dx = ($w - $width)/2; 2349 } elseif($align=='J') { 2350 if ($this->rtl) { 2351 $dx = $w - $width - $this->cMargin; 2352 } else { 2353 $dx = $this->cMargin; 2354 } 2355 } else { 2356 $dx = $this->cMargin; 2357 } 2358 if($this->ColorFlag) { 2359 $s .= 'q '.$this->TextColor.' '; 2360 } 2361 $txt2 = $this->_escapetext($txt); 2362 if ($this->rtl) { 2363 $xdk = ($this->x - $dx - $width) * $k; 2364 } else { 2365 $xdk = ($this->x + $dx) * $k; 2366 } 2367 // 2008-02-16 Jacek Czekaj - multibyte justification 2368 if ($align == 'J') { 2369 // count number of spaces 2370 $ns = substr_count($txt, ' '); 2371 // get string width without spaces 2372 $width = $this->GetStringWidth(str_replace(' ', '', $txt)); 2373 // set word position to be used with TJ operator 2374 $txt2 = str_replace(chr(0).' ', ') '. -2830*($w-$width-(2*$this->cMargin))/($ns?$ns:1)/$this->FontSize/$this->k . ' (', $txt2); 2375 } 2376 2377 $s.=sprintf('BT %.2f %.2f Td [(%s)] TJ ET', $xdk, ($this->h - ($this->y + 0.5 * $h + 0.3 * $this->FontSize)) * $k, $txt2); 2378 2379 if($this->underline) { 2380 if ($this->rtl) { 2381 $xdx = $this->x - $dx - $width; 2382 } else { 2383 $xdx = $this->x + $dx; 2384 } 2385 $s.=' '.$this->_dounderline($xdx, $this->y + 0.5 * $h + 0.3 * $this->FontSize, $txt); 2386 } 2387 if($this->ColorFlag) { 2388 $s.=' Q'; 2389 } 2390 if($link) { 2391 if ($this->rtl) { 2392 $xdx = $this->x - $dx - $width; 2393 } else { 2394 $xdx = $this->x + $dx; 2395 } 2396 $this->Link($xdx, $this->y + 0.5 * $h - 0.5 * $this->FontSize, $width, $this->FontSize, $link); 2397 } 2398 } 2399 2400 // output cell 2401 if($s) { 2402 // output cell 2403 $this->_out($s); 2404 // reset text stretching 2405 if($stretch > 2) { 2406 //Reset character horizontal spacing 2407 $this->_out('BT 0 Tc ET'); 2408 } elseif($stretch > 0) { 2409 //Reset character horizontal scaling 2410 $this->_out('BT 100 Tz ET'); 2411 } 2412 } 2413 2414 $this->lasth = $h; 2415 2416 if($ln>0) { 2417 //Go to the beginning of the next line 2418 $this->y += $h; 2419 if($ln == 1) { 2420 if ($this->rtl) { 2421 $this->x = $this->w - $this->rMargin; 2422 } else { 2423 $this->x = $this->lMargin; 2424 } 2425 } 2426 } else { 2427 // go left or right by case 2428 if ($this->rtl) { 2429 $this->x -= $w; 2430 } else { 2431 $this->x += $w; 2432 } 2433 } 2434 } 2435 2436 /** 2437 * This method allows printing text with line breaks. They can be automatic (as soon as the text reaches the right border of the cell) or explicit (via the \n character). As many cells as necessary are output, one below the other.<br /> 2438 * Text can be aligned, centered or justified. The cell block can be framed and the background painted. 2439 * @param float $w Width of cells. If 0, they extend up to the right margin of the page. 2440 * @param float $h Cell minimum height. The cell extends automatically if needed. 2441 * @param string $txt String to print 2442 * @param mixed $border Indicates if borders must be drawn around the cell block. The value can be either a number:<ul><li>0: no border (default)</li><li>1: frame</li></ul>or a string containing some or all of the following characters (in any order):<ul><li>L: left</li><li>T: top</li><li>R: right</li><li>B: bottom</li></ul> 2443 * @param string $align Allows to center or align the text. Possible values are:<ul><li>L or empty string: left align</li><li>C: center</li><li>R: right align</li><li>J: justification (default value)</li></ul> 2444 * @param int $fill Indicates if the cell background must be painted (1) or transparent (0). Default value: 0. 2445 * @param int $ln Indicates where the current position should go after the call. Possible values are:<ul><li>0: to the right</li><li>1: to the beginning of the next line [DEFAULT]</li><li>2: below</li></ul> 2446 * @param int $x x position in user units 2447 * @param int $y y position in user units 2448 * @param boolean $reseth if true reset the last cell height (default true). 2449 * @param int $stretch stretch carachter mode: <ul><li>0 = disabled</li><li>1 = horizontal scaling only if necessary</li><li>2 = forced horizontal scaling</li><li>3 = character spacing only if necessary</li><li>4 = forced character spacing</li></ul> 2450 * @return int Rerurn the number of lines. 2451 * @since 1.3 2452 * @see SetFont(), SetDrawColor(), SetFillColor(), SetTextColor(), SetLineWidth(), Cell(), Write(), SetAutoPageBreak() 2453 */ 2454 function MultiCell($w, $h, $txt, $border=0, $align='J', $fill=0, $ln=1, $x='', $y='', $reseth=true, $stretch=0) { 2455 if ((empty($this->lasth))OR ($reseth)) { 2456 //set row height 2457 $this->lasth = $this->FontSize * K_CELL_HEIGHT_RATIO; 2458 } 2459 2460 // get current page number 2461 $startpage = $this->page; 2462 2463 if (!empty($y)) { 2464 $this->SetY($y); 2465 } else { 2466 $y = $this->GetY(); 2467 } 2468 if (!empty($x)) { 2469 $this->SetX($x); 2470 } else { 2471 $x = $this->GetX(); 2472 } 2473 2474 if(empty($w)) { 2475 if ($this->rtl) { 2476 $w = $this->x - $this->lMargin; 2477 } else { 2478 $w = $this->w - $this->rMargin - $this->x; 2479 } 2480 } 2481 2482 // store original margin values 2483 $lMargin = $this->lMargin; 2484 $rMargin = $this->rMargin; 2485 2486 // set new margin values 2487 if ($this->rtl) { 2488 $this->SetLeftMargin($this->x - $w); 2489 $this->SetRightMargin($this->w - $this->x); 2490 } else { 2491 $this->SetLeftMargin($this->x); 2492 $this->SetRightMargin($this->w - $this->x - $w); 2493 } 2494 2495 // calculate remaining vertical space on first page ($startpage) 2496 $restspace = $this->getPageHeight() - $this->GetY() - $this->getBreakMargin(); 2497 2498 // Write text 2499 $nl = $this->Write($this->lasth, $txt, '', $fill, $align, true, $stretch); 2500 2501 // Get end-of-text Y position 2502 $currentY = $this->GetY(); 2503 // get latest page number 2504 $endpage = $this->page; 2505 2506 if (!empty($border)) { 2507 // check if a new page has been created 2508 if ($endpage > $startpage) { 2509 // design borders around HTML cells. 2510 for ($page=$startpage; $page<=$endpage; $page++) { 2511 $this->page = $page; 2512 if ($page==$startpage) { 2513 $this->SetY($this->getPageHeight() - $restspace - $this->getBreakMargin()); 2514 $h = $restspace - 1; 2515 } elseif ($page==$endpage) { 2516 $this->SetY($this->tMargin); // put cursor at the beginning of text 2517 $h = $currentY - $this->tMargin; 2518 } else { 2519 $this->SetY($this->tMargin); // put cursor at the beginning of text 2520 $h = $this->getPageHeight() - $this->tMargin - $this->getBreakMargin(); 2521 } 2522 $this->SetX($x); 2523 $this->Cell($w, $h, "", $border, 1, '', 0); 2524 } 2525 } else { 2526 $h = max($h, ($currentY - $y)); 2527 $this->SetY($y); // put cursor at the beginning of text 2528 $this->SetX($x); 2529 // design a cell around the text 2530 $this->Cell($w, $h, "", $border, 1, '', 0); 2531 } 2532 } 2533 2534 // restore original margin values 2535 $this->SetLeftMargin($lMargin); 2536 $this->SetRightMargin($rMargin); 2537 2538 if($ln>0) { 2539 //Go to the beginning of the next line 2540 $this->SetY($currentY); 2541 if($ln == 2) { 2542 $this->SetX($x + $w); 2543 } 2544 } else { 2545 // go left or right by case 2546 $this->page = $startpage; 2547 $this->y = $y; 2548 $this->SetX($x + $w); 2549 } 2550 2551 return $nl; 2552 } 2553 2554 /** 2555 * This method prints text from the current position.<br /> 2556 * @param float $h Line height 2557 * @param string $txt String to print 2558 * @param mixed $link URL or identifier returned by AddLink() 2559 * @param int $fill Indicates if the background must be painted (1) or transparent (0). Default value: 0. 2560 * @param string $align Allows to center or align the text. Possible values are:<ul><li>L or empty string: left align (default value)</li><li>C: center</li><li>R: right align</li><li>J: justify</li></ul> 2561 * @param boolean $ln if true set cursor at the bottom of the line, otherwise set cursor at the top of the line. 2562 * @param int $stretch stretch carachter mode: <ul><li>0 = disabled</li><li>1 = horizontal scaling only if necessary</li><li>2 = forced horizontal scaling</li><li>3 = character spacing only if necessary</li><li>4 = forced character spacing</li></ul> 2563 * @return int Rerurn the number of lines. 2564 * @since 1.5 2565 */ 2566 function Write($h, $txt, $link='', $fill=0, $align='', $ln=false, $stretch=0) { 2567 2568 // store current position 2569 $prevx = $this->x; 2570 $prevy = $this->y; 2571 2572 // Adjust internal padding 2573 if ($this->cMargin < ($this->LineWidth/2)) { 2574 $this->cMargin = ($this->LineWidth/2); 2575 } 2576 2577 // Add top space if needed 2578 if (($h - $this->FontSize) < $this->LineWidth) { 2579 $this->y += $this->LineWidth/2; 2580 } 2581 2582 //if ($h < ($this->LineWidth)) { 2583 // $h = ($this->LineWidth); 2584 //} 2585 2586 // calculating remaining line width ($w) 2587 if ($this->rtl) { 2588 $w = $this->x - $this->lMargin; 2589 } else { 2590 $w = $this->w - $this->rMargin - $this->x; 2591 } 2592 2593 // remove carriage returns 2594 $s = str_replace("\r", '', $txt); 2595 2596 // get array of chars 2597 $chars = $this->UTF8StringToArray($s); 2598 2599 // get the number of characters 2600 $nb = count($chars); 2601 2602 // handle single space character 2603 if(($nb==1) AND preg_match("/[\s]/u", $s)) { 2604 if ($this->rtl) { 2605 $this->x -= $this->GetStringWidth($s); 2606 } else { 2607 $this->x += $this->GetStringWidth($s); 2608 } 2609 return; 2610 } 2611 2612 // max column width 2613 $wmax = $w - (2 * $this->cMargin); 2614 2615 $i = 0; // character position 2616 $j = 0; // current srting starting position 2617 $sep = -1; // position of the last blank space 2618 $l = 0; // current string lenght 2619 $nl = 0; //number of lines 2620 2621 // for each character 2622 while($i < $nb) { 2623 //Get the current character 2624 $c = $chars[$i]; 2625 if ($c == 10) { 2626 // 10 = "\n" = new line 2627 //Explicit line break 2628 if ($align == "J") { 2629 if ($this->rtl) { 2630 $talign = "R"; 2631 } else { 2632 $talign = "L"; 2633 } 2634 } else { 2635 $talign = $align; 2636 } 2637 $this->Cell($w, $h, $this->UTF8ArrSubString($chars, $j, $i), 0, 2, $talign, $fill, $link, $stretch); 2638 $nl++; 2639 $j = $i + 1; 2640 $l = 0; 2641 $sep = -1; 2642 if($nl == 1) { 2643 // set the next line width and position 2644 if ($this->rtl) { 2645 $this->x = $this->w - $this->rMargin; 2646 $w = $this->x - $this->lMargin; 2647 } 2648 else { 2649 $this->x = $this->lMargin; 2650 $w = $this->w - $this->rMargin - $this->x; 2651 } 2652 $wmax = $w - (2 * $this->cMargin); 2653 } 2654 } else { 2655 if(preg_match("/[\s]/u", $this->unichr($c))) { 2656 // update last blank space position 2657 $sep = $i; 2658 } 2659 2660 // update string length 2661 if($this->isunicode) { 2662 // with bidirectional algorithm some chars may be changed affecting the line length 2663 // *** very slow 2664 $l = $this->GetArrStringWidth($this->utf8Bidi(array_slice($chars, $j, $i-$j+1), $this->tmprtl)); 2665 } else { 2666 $l += $this->GetCharWidth($c); 2667 } 2668 2669 if($l > $wmax) { 2670 // we have reached the end of column 2671 if($sep == -1) { 2672 // truncate the word because do not fit on column 2673 $this->Cell($w, $h, $this->UTF8ArrSubString($chars, $j, $i), 0, 2, $align, $fill, $link, $stretch); 2674 $nl++; 2675 if($nl == 1) { 2676 // set the next line width and position 2677 if ($this->rtl) { 2678 $this->x = $this->w - $this->rMargin; 2679 $w = $this->x - $this->lMargin; 2680 } 2681 else { 2682 $this->x = $this->lMargin; 2683 $w = $this->w - $this->rMargin - $this->x; 2684 } 2685 $wmax = $w - (2 * $this->cMargin); 2686 } 2687 } else { 2688 // word wrapping 2689 $this->Cell($w, $h, $this->UTF8ArrSubString($chars, $j, $sep), 0, 2, $align, $fill, $link, $stretch); 2690 $nl++; 2691 $i = $sep + 1; 2692 if($nl == 1) { 2693 // set the next line width and position 2694 if ($this->rtl) { 2695 $this->x = $this->w - $this->rMargin; 2696 $w = $this->x - $this->lMargin; 2697 } 2698 else { 2699 $this->x = $this->lMargin; 2700 $w = $this->w - $this->rMargin - $this->x; 2701 } 2702 $wmax = $w - (2 * $this->cMargin); 2703 } 2704 } 2705 $sep = -1; 2706 $j = $i; 2707 $l = 0; 2708 } 2709 } 2710 $i++; 2711 } // end while i < nb 2712 // print last row 2713 if($i != $j) { 2714 $this->Cell($w, $h, $this->UTF8ArrSubString($chars, $j, $nb), 0, $ln, $align, $fill, $link, $stretch); 2715 $nl++; 2716 } 2717 2718 $w = $this->GetStringWidth($this->UTF8ArrSubString($chars, $j, $nb)) + (2 * $this->cMargin); 2719 if ($this->rtl) { 2720 $this->x = $prevx - $w; 2721 } else { 2722 $this->x = $prevx + $w; 2723 } 2724 2725 // Add bottom space if needed 2726 if (($ln > 0) AND (($h - $this->FontSize) < $this->LineWidth)) { 2727 $this->y += $this->LineWidth/2; 2728 } 2729 2730 return $nl; 2731 } 2732 2733 /** 2734 * Extract a slice of the $strarr array and return it as string. 2735 * @param string $strarr The input array of characters. 2736 * @param int $start the starting element of $strarr. 2737 * @param int $end first element that will not be returned. 2738 * @return Return part of a string 2739 */ 2740 function UTF8ArrSubString($strarr, $start='', $end='') { 2741 if (strlen($start) == 0) { 2742 $start = 0; 2743 } 2744 if (strlen($end) == 0) { 2745 $end = count($strarr); 2746 } 2747 $string = ""; 2748 for ($i=$start; $i < $end; $i++) { 2749 $string .= $this->unichr($strarr[$i]); 2750 } 2751 return $string; 2752 } 2753 2754 /** 2755 * Returns the unicode caracter specified by UTF-8 code 2756 * @param int $c UTF-8 code 2757 * @return Returns the specified character. 2758 * @author Miguel Perez, Nicola Asuni 2759 * @since 2.3.000 (2008-03-05) 2760 */ 2761 function unichr($c) { 2762 if (!$this->isunicode) { 2763 return chr($c); 2764 } elseif ($c <= 0x7F) { 2765 // one byte 2766 return chr($c); 2767 } else if ($c <= 0x7FF) { 2768 // two bytes 2769 return chr(0xC0 | $c >> 6).chr(0x80 | $c & 0x3F); 2770 } else if ($c <= 0xFFFF) { 2771 // three bytes 2772 return chr(0xE0 | $c >> 12).chr(0x80 | $c >> 6 & 0x3F).chr(0x80 | $c & 0x3F); 2773 } else if ($c <= 0x10FFFF) { 2774 // four bytes 2775 return chr(0xF0 | $c >> 18).chr(0x80 | $c >> 12 & 0x3F).chr(0x80 | $c >> 6 & 0x3F).chr(0x80 | $c & 0x3F); 2776 } else { 2777 return ""; 2778 } 2779 } 2780 2781 /** 2782 * Puts an image in the page. The upper-left corner must be given. The dimensions can be specified in different ways:<ul><li>explicit width and height (expressed in user unit)</li><li>one explicit dimension, the other being calculated automatically in order to keep the original proportions</li><li>no explicit dimension, in which case the image is put at 72 dpi</li></ul> 2783 * Supported formats are JPEG and PNG. 2784 * For JPEG, all flavors are allowed:<ul><li>gray scales</li><li>true colors (24 bits)</li><li>CMYK (32 bits)</li></ul> 2785 * For PNG, are allowed:<ul><li>gray scales on at most 8 bits (256 levels)</li><li>indexed colors</li><li>true colors (24 bits)</li></ul> 2786 * If a transparent color is defined, it will be taken into account (but will be only interpreted by Acrobat 4 and above).<br /> 2787 * The format can be specified explicitly or inferred from the file extension.<br /> 2788 * It is possible to put a link on the image.<br /> 2789 * Remark: if an image is used several times, only one copy will be embedded in the file.<br /> 2790 * @param string $file Name of the file containing the image. 2791 * @param float $x Abscissa of the upper-left corner. 2792 * @param float $y Ordinate of the upper-left corner. 2793 * @param float $w Width of the image in the page. If not specified or equal to zero, it is automatically calculated. 2794 * @param float $h Height of the image in the page. If not specified or equal to zero, it is automatically calculated. 2795 * @param string $type Image format. Possible values are (case insensitive): JPG, JPEG, PNG. If not specified, the type is inferred from the file extension. 2796 * @param mixed $link URL or identifier returned by AddLink(). 2797 * @param string $align Indicates the alignment of the pointer next to image insertion relative to image height. The value can be:<ul><li>T: top-right for LTR or top-left for RTL</li><li>M: middle-right for LTR or middle-left for RTL</li><li>B: bottom-right for LTR or bottom-left for RTL</li><li>N: next line</li></ul> 2798 * @since 1.1 2799 * @see AddLink() 2800 */ 2801 function Image($file, $x, $y, $w=0, $h=0, $type='', $link='', $align='') { 2802 //Put an image on the page 2803 if(!isset($this->images[$file])) { 2804 //First use of image, get info 2805 if($type == '') { 2806 $pos = strrpos($file,'.'); 2807 if(empty($pos)) { 2808 $this->Error('Image file has no extension and no type was specified: '.$file); 2809 } 2810 $type = substr($file, $pos+1); 2811 } 2812 $type = strtolower($type); 2813 $mqr = get_magic_quotes_runtime(); 2814 set_magic_quotes_runtime(0); 2815 if($type == 'jpg' or $type == 'jpeg') { 2816 $info=$this->_parsejpg($file); 2817 } elseif($type == 'gif') { 2818 $info=$this->_parsegif($file); 2819 } elseif($type == 'png') { 2820 $info=$this->_parsepng($file); 2821 }else { 2822 //Allow for additional formats 2823 $mtd='_parse'.$type; 2824 if(!method_exists($this,$mtd)) { 2825 $this->Error('Unsupported image type: '.$type); 2826 } 2827 $info=$this->$mtd($file); 2828 } 2829 if($info === false) { 2830 //If false, we cannot process image 2831 return; 2832 } 2833 set_magic_quotes_runtime($mqr); 2834 $info['i']=count($this->images)+1; 2835 $this->images[$file]=$info; 2836 } 2837 else { 2838 $info=$this->images[$file]; 2839 } 2840 //Automatic width and height calculation if needed 2841 if(($w == 0) and ($h == 0)) { 2842 //Put image at 72 dpi 2843 // 2004-06-14 :: Nicola Asuni, scale factor where added 2844 $w = $info['w'] / ($this->imgscale * $this->k); 2845 $h = $info['h'] / ($this->imgscale * $this->k); 2846 } 2847 if($w == 0) { 2848 $w = $h * $info['w'] / $info['h']; 2849 } 2850 if($h == 0) { 2851 $h = $w * $info['h'] / $info['w']; 2852 } 2853 2854 // 2007-10-19 Warren Sherliker 2855 // Check whether we need a new page first as this does not fit 2856 // Copied from Cell() 2857 if((($this->y + $h) > $this->PageBreakTrigger) AND empty($this->InFooter) AND $this->AcceptPageBreak()) { 2858 // Automatic page break 2859 $this->AddPage($this->CurOrientation); 2860 // Reset coordinates to top fo next page 2861 $x = $this->GetX(); 2862 $y = $this->GetY(); 2863 } 2864 // 2007-10-19 Warren Sherliker: End Edit 2865 2866 // set bottomcoordinates 2867 $this->img_rb_y = $y + $h; 2868 if ($this->rtl) { 2869 $ximg = ($this->w - $x -$w); 2870 // set left side coordinate 2871 $this->img_rb_x = $ximg; 2872 } else { 2873 $ximg = $x; 2874 // set right side coordinate 2875 $this->img_rb_x = $ximg + $w; 2876 } 2877 $xkimg = $ximg * $this->k; 2878 $this->_out(sprintf('q %.2f 0 0 %.2f %.2f %.2f cm /I%d Do Q', $w*$this->k, $h*$this->k, $xkimg, ($this->h-($y+$h))*$this->k, $info['i'])); 2879 2880 if($link) { 2881 $this->Link($ximg, $y, $w, $h, $link); 2882 } 2883 2884 // set pointer to align the successive text/objects 2885 switch($align) { 2886 case 'T':{ 2887 $this->y = $y; 2888 $this->x = $this->img_rb_x; 2889 break; 2890 } 2891 case 'M':{ 2892 $this->y = $y + round($h/2); 2893 $this->x = $this->img_rb_x; 2894 break; 2895 } 2896 case 'B':{ 2897 $this->y = $this->img_rb_y; 2898 $this->x = $this->img_rb_x; 2899 break; 2900 } 2901 case 'N':{ 2902 $this->SetY($this->img_rb_y); 2903 break; 2904 } 2905 default:{ 2906 break; 2907 } 2908 } 2909 } 2910 2911 2912 /** 2913 * Performs a line break. The current abscissa goes back to the left margin and the ordinate increases by the amount passed in parameter. 2914 * @param float $h The height of the break. By default, the value equals the height of the last printed cell. 2915 * @since 1.0 2916 * @see Cell() 2917 */ 2918 function Ln($h='') { 2919 //Line feed; default value is last cell height 2920 if ($this->rtl) { 2921 $this->x = $this->w - $this->rMargin; 2922 } else { 2923 $this->x = $this->lMargin; 2924 } 2925 if(is_string($h)) { 2926 $this->y += $this->lasth; 2927 } else { 2928 $this->y += $h; 2929 } 2930 } 2931 2932 /** 2933 * Returns the relative X value of current position. 2934 * The value is relative to the left border for LTR languages and to the right border for RTL languages. 2935 * @return float 2936 * @since 1.2 2937 * @see SetX(), GetY(), SetY() 2938 */ 2939 function GetX() { 2940 //Get x position 2941 if ($this->rtl) { 2942 return ($this->w - $this->x); 2943 } else { 2944 return $this->x; 2945 } 2946 } 2947 2948 /** 2949 * Returns the absolute X value of current position. 2950 * @return float 2951 * @since 1.2 2952 * @see SetX(), GetY(), SetY() 2953 */ 2954 function GetAbsX() { 2955 return $this->x; 2956 } 2957 2958 /** 2959 * Returns the ordinate of the current position. 2960 * @return float 2961 * @since 1.0 2962 * @see SetY(), GetX(), SetX() 2963 */ 2964 function GetY() { 2965 //Get y position 2966 return $this->y; 2967 } 2968 2969 /** 2970 * Defines the abscissa of the current position. 2971 * If the passed value is negative, it is relative to the right of the page (or left if language is RTL). 2972 * @param float $x The value of the abscissa. 2973 * @since 1.2 2974 * @see GetX(), GetY(), SetY(), SetXY() 2975 */ 2976 function SetX($x) { 2977 //Set x position 2978 if ($this->rtl) { 2979 if($x >= 0) { 2980 $this->x = $this->w - $x; 2981 } else { 2982 $this->x = abs($x); 2983 } 2984 } else { 2985 if($x >= 0) { 2986 $this->x = $x; 2987 } else { 2988 $this->x = $this->w + $x; 2989 } 2990 } 2991 } 2992 2993 /** 2994 * Moves the current abscissa back to the left margin and sets the ordinate. 2995 * If the passed value is negative, it is relative to the bottom of the page. 2996 * @param float $y The value of the ordinate. 2997 * @since 1.0 2998 * @see GetX(), GetY(), SetY(), SetXY() 2999 */ 3000 function SetY($y) { 3001 //Set y position and reset x 3002 if ($this->rtl) { 3003 $this->x = $this->w - $this->rMargin; 3004 } else { 3005 $this->x = $this->lMargin; 3006 } 3007 if($y >= 0) { 3008 $this->y = $y; 3009 } else { 3010 $this->y = $this->h + $y; 3011 } 3012 } 3013 3014 3015 /** 3016 * Defines the abscissa and ordinate of the current position. If the passed values are negative, they are relative respectively to the right and bottom of the page. 3017 * @param float $x The value of the abscissa 3018 * @param float $y The value of the ordinate 3019 * @since 1.2 3020 * @see SetX(), SetY() 3021 */ 3022 function SetXY($x, $y) { 3023 //Set x and y positions 3024 $this->SetY($y); 3025 $this->SetX($x); 3026 } 3027 3028 /** 3029 * Send the document to a given destination: string, local file or browser. In the last case, the plug-in may be used (if present) or a download ("Save as" dialog box) may be forced.<br /> 3030 * The method first calls Close() if necessary to terminate the document. 3031 * @param string $name The name of the file. If not given, the document will be sent to the browser (destination I) with the name doc.pdf. 3032 * @param string $dest Destination where to send the document. It can take one of the following values:<ul><li>I: send the file inline to the browser. The plug-in is used if available. The name given by name is used when one selects the "Save as" option on the link generating the PDF.</li><li>D: send to the browser and force a file download with the name given by name.</li><li>F: save to a local file with the name given by name.</li><li>S: return the document as a string. name is ignored.</li></ul>If the parameter is not specified but a name is given, destination is F. If no parameter is specified at all, destination is I.<br />Note: for compatibility with previous versions, a boolean value is also accepted (false for F and true for D). 3033 * @since 1.0 3034 * @see Close() 3035 */ 3036 function Output($name='',$dest='') { 3037 //Output PDF to some destination 3038 //Finish document if necessary 3039 if($this->state < 3) { 3040 $this->Close(); 3041 } 3042 //Normalize parameters 3043 if(is_bool($dest)) { 3044 $dest=$dest ? 'D' : 'F'; 3045 } 3046 $dest=strtoupper($dest); 3047 if($dest=='') { 3048 if($name=='') { 3049 $name='doc.pdf'; 3050 $dest='I'; 3051 } else { 3052 $dest='F'; 3053 } 3054 } 3055 switch($dest) { 3056 case 'I': { 3057 //Send to standard output 3058 if(ob_get_contents()) { 3059 $this->Error('Some data has already been output, can\'t send PDF file'); 3060 } 3061 if(php_sapi_name()!='cli') { 3062 //We send to a browser 3063 header('Content-Type: application/pdf'); 3064 if(headers_sent()) { 3065 $this->Error('Some data has already been output to browser, can\'t send PDF file'); 3066 } 3067 header('Content-Length: '.strlen($this->buffer)); 3068 header('Content-disposition: inline; filename="'.$name.'"'); 3069 } 3070 echo $this->buffer; 3071 break; 3072 } 3073 case 'D': { 3074 //Download file 3075 if(ob_get_contents()) { 3076 $this->Error('Some data has already been output, can\'t send PDF file'); 3077 } 3078 if(isset($_SERVER['HTTP_USER_AGENT']) && strpos($_SERVER['HTTP_USER_AGENT'],'MSIE')) { 3079 header('Content-Type: application/force-download'); 3080 } else { 3081 header('Content-Type: application/octet-stream'); 3082 } 3083 if(headers_sent()) { 3084 $this->Error('Some data has already been output to browser, can\'t send PDF file'); 3085 } 3086 header('Content-Length: '.strlen($this->buffer)); 3087 header('Content-disposition: attachment; filename="'.$name.'"'); 3088 echo $this->buffer; 3089 break; 3090 } 3091 case 'F': { 3092 //Save to local file 3093 $f=fopen($name,'wb'); 3094 if(!$f) { 3095 $this->Error('Unable to create output file: '.$name); 3096 } 3097 fwrite($f,$this->buffer,strlen($this->buffer)); 3098 fclose($f); 3099 break; 3100 } 3101 case 'S': { 3102 //Return as a string 3103 return $this->buffer; 3104 } 3105 default: { 3106 $this->Error('Incorrect output destination: '.$dest); 3107 } 3108 } 3109 return ''; 3110 } 3111 3112 // Protected methods 3113 3114 /** 3115 * Check for locale-related bug 3116 * @access protected 3117 */ 3118 function _dochecks() { 3119 //Check for locale-related bug 3120 if(1.1==1) { 3121 $this->Error('Don\'t alter the locale before including class file'); 3122 } 3123 //Check for decimal separator 3124 if(sprintf('%.1f',1.0)!='1.0') { 3125 setlocale(LC_NUMERIC,'C'); 3126 } 3127 } 3128 3129 /** 3130 * Return fonts path 3131 * @access protected 3132 */ 3133 function _getfontpath() { 3134 if(!defined('K_PATH_FONTS') AND is_dir(dirname(__FILE__).'/font')) { 3135 define('K_PATH_FONTS', dirname(__FILE__).'/font/'); 3136 } 3137 return defined('K_PATH_FONTS') ? K_PATH_FONTS : ''; 3138 } 3139 3140 /** 3141 * Start document 3142 * @access protected 3143 */ 3144 function _begindoc() { 3145 //Start document 3146 $this->state=1; 3147 $this->_out('%PDF-'.$this->PDFVersion); 3148 } 3149 3150 /** 3151 * _putpages 3152 * @access protected 3153 */ 3154 function _putpages() { 3155 $nb = $this->page; 3156 if(!empty($this->AliasNbPages)) { 3157 $nbstr = $this->UTF8ToUTF16BE($nb, false); 3158 //Replace number of pages 3159 for($n=1;$n<=$nb;$n++) { 3160 $this->pages[$n]=str_replace($this->AliasNbPages, $nbstr, $this->pages[$n]); 3161 } 3162 } 3163 if($this->DefOrientation=='P') { 3164 $wPt=$this->fwPt; 3165 $hPt=$this->fhPt; 3166 } 3167 else { 3168 $wPt=$this->fhPt; 3169 $hPt=$this->fwPt; 3170 } 3171 $filter=($this->compress) ? '/Filter /FlateDecode ' : ''; 3172 for($n=1;$n<=$nb;$n++) { 3173 //Page 3174 $this->_newobj(); 3175 $this->_out('<</Type /Page'); 3176 $this->_out('/Parent 1 0 R'); 3177 if(isset($this->OrientationChanges[$n])) { 3178 $this->_out(sprintf('/MediaBox [0 0 %.2f %.2f]',$hPt,$wPt)); 3179 } 3180 $this->_out('/Resources 2 0 R'); 3181 if(isset($this->PageLinks[$n])) { 3182 //Links 3183 $annots='/Annots ['; 3184 foreach($this->PageLinks[$n] as $pl) { 3185 $rect=sprintf('%.2f %.2f %.2f %.2f',$pl[0],$pl[1],$pl[0]+$pl[2],$pl[1]-$pl[3]); 3186 $annots.='<</Type /Annot /Subtype /Link /Rect ['.$rect.'] /Border [0 0 0] '; 3187 if(is_string($pl[4])) { 3188 $annots.='/A <</S /URI /URI '.$this->_uristring($pl[4]).'>>>>'; 3189 } 3190 else { 3191 $l=$this->links[$pl[4]]; 3192 $h=isset($this->OrientationChanges[$l[0]]) ? $wPt : $hPt; 3193 $annots.=sprintf('/Dest [%d 0 R /XYZ 0 %.2f null]>>',1+2*$l[0],$h-$l[1]*$this->k); 3194 } 3195 } 3196 $this->_out($annots.']'); 3197 } 3198 $this->_out('/Contents '.($this->n+1).' 0 R>>'); 3199 $this->_out('endobj'); 3200 //Page content 3201 $p=($this->compress) ? gzcompress($this->pages[$n]) : $this->pages[$n]; 3202 $this->_newobj(); 3203 $this->_out('<<'.$filter.'/Length '.strlen($p).'>>'); 3204 $this->_putstream($p); 3205 $this->_out('endobj'); 3206 } 3207 //Pages root 3208 $this->offsets[1]=strlen($this->buffer); 3209 $this->_out('1 0 obj'); 3210 $this->_out('<</Type /Pages'); 3211 $kids='/Kids ['; 3212 for($i=0;$i<$nb;$i++) { 3213 $kids.=(3+2*$i).' 0 R '; 3214 } 3215 $this->_out($kids.']'); 3216 $this->_out('/Count '.$nb); 3217 $this->_out(sprintf('/MediaBox [0 0 %.2f %.2f]',$wPt,$hPt)); 3218 $this->_out('>>'); 3219 $this->_out('endobj'); 3220 } 3221 3222 /** 3223 * Adds fonts 3224 * _putfonts 3225 * @access protected 3226 */ 3227 function _putfonts() { 3228 $nf=$this->n; 3229 foreach($this->diffs as $diff) { 3230 //Encodings 3231 $this->_newobj(); 3232 $this->_out('<</Type /Encoding /BaseEncoding /WinAnsiEncoding /Differences ['.$diff.']>>'); 3233 $this->_out('endobj'); 3234 } 3235 $mqr=get_magic_quotes_runtime(); 3236 set_magic_quotes_runtime(0); 3237 foreach($this->FontFiles as $file=>$info) { 3238 //Font file embedding 3239 $this->_newobj(); 3240 $this->FontFiles[$file]['n']=$this->n; 3241 $font=''; 3242 $f=fopen($this->_getfontpath().strtolower($file),'rb',1); 3243 if(!$f) { 3244 $this->Error('Font file not found: '.$file); 3245 } 3246 while(!feof($f)) { 3247 $font .= fread($f, 8192); 3248 } 3249 fclose($f); 3250 $compressed=(substr($file,-2)=='.z'); 3251 if(!$compressed && isset($info['length2'])) { 3252 $header=(ord($font{0})==128); 3253 if($header) { 3254 //Strip first binary header 3255 $font=substr($font,6); 3256 } 3257 if($header && ord($font{$info['length1']})==128) { 3258 //Strip second binary header 3259 $font=substr($font,0,$info['length1']).substr($font,$info['length1']+6); 3260 } 3261 } 3262 $this->_out('<</Length '.strlen($font)); 3263 if($compressed) { 3264 $this->_out('/Filter /FlateDecode'); 3265 } 3266 $this->_out('/Length1 '.$info['length1']); 3267 if(isset($info['length2'])) { 3268 $this->_out('/Length2 '.$info['length2'].' /Length3 0'); 3269 } 3270 $this->_out('>>'); 3271 $this->_putstream($font); 3272 $this->_out('endobj'); 3273 } 3274 set_magic_quotes_runtime($mqr); 3275 foreach($this->fonts as $k=>$font) { 3276 //Font objects 3277 $this->fonts[$k]['n']=$this->n+1; 3278 $type=$font['type']; 3279 $name=$font['name']; 3280 if($type=='core') { 3281 //Standard font 3282 $this->_newobj(); 3283 $this->_out('<</Type /Font'); 3284 $this->_out('/BaseFont /'.$name); 3285 $this->_out('/Subtype /Type1'); 3286 if($name!='Symbol' && $name!='ZapfDingbats') { 3287 $this->_out('/Encoding /WinAnsiEncoding'); 3288 } 3289 $this->_out('>>'); 3290 $this->_out('endobj'); 3291 } elseif($type=='Type1' OR $type=='TrueType') { 3292 //Additional Type1 or TrueType font 3293 $this->_newobj(); 3294 $this->_out('<</Type /Font'); 3295 $this->_out('/BaseFont /'.$name); 3296 $this->_out('/Subtype /'.$type); 3297 $this->_out('/FirstChar 32 /LastChar 255'); 3298 $this->_out('/Widths '.($this->n+1).' 0 R'); 3299 $this->_out('/FontDescriptor '.($this->n+2).' 0 R'); 3300 if($font['enc']) { 3301 if(isset($font['diff'])) { 3302 $this->_out('/Encoding '.($nf+$font['diff']).' 0 R'); 3303 } else { 3304 $this->_out('/Encoding /WinAnsiEncoding'); 3305 } 3306 } 3307 $this->_out('>>'); 3308 $this->_out('endobj'); 3309 //Widths 3310 $this->_newobj(); 3311 $cw=&$font['cw']; 3312 $s='['; 3313 for($i=32;$i<=255;$i++) { 3314 $s.=$cw[chr($i)].' '; 3315 } 3316 $this->_out($s.']'); 3317 $this->_out('endobj'); 3318 //Descriptor 3319 $this->_newobj(); 3320 $s='<</Type /FontDescriptor /FontName /'.$name; 3321 foreach($font['desc'] as $k=>$v) { 3322 $s.=' /'.$k.' '.$v; 3323 } 3324 $file = $font['file']; 3325 if($file) { 3326 $s.=' /FontFile'.($type=='Type1' ? '' : '2').' '.$this->FontFiles[$file]['n'].' 0 R'; 3327 } 3328 $this->_out($s.'>>'); 3329 $this->_out('endobj'); 3330 } else { 3331 //Allow for additional types 3332 $mtd='_put'.strtolower($type); 3333 if(!method_exists($this, $mtd)) { 3334 $this->Error('Unsupported font type: '.$type); 3335 } 3336 $this->$mtd($font); 3337 } 3338 } 3339 } 3340 3341 /** 3342 * _putimages 3343 * @access protected 3344 */ 3345 function _putimages() { 3346 $filter=($this->compress) ? '/Filter /FlateDecode ' : ''; 3347 reset($this->images); 3348 while(list($file,$info)=each($this->images)) { 3349 $this->_newobj(); 3350 $this->images[$file]['n']=$this->n; 3351 $this->_out('<</Type /XObject'); 3352 $this->_out('/Subtype /Image'); 3353 $this->_out('/Width '.$info['w']); 3354 $this->_out('/Height '.$info['h']); 3355 3356 if (isset($info["masked"])) { 3357 $this->_out('/SMask '.($this->n-1).' 0 R'); 3358 } 3359 3360 if($info['cs']=='Indexed') { 3361 $this->_out('/ColorSpace [/Indexed /DeviceRGB '.(strlen($info['pal'])/3-1).' '.($this->n+1).' 0 R]'); 3362 } 3363 else { 3364 $this->_out('/ColorSpace /'.$info['cs']); 3365 if($info['cs']=='DeviceCMYK') { 3366 $this->_out('/Decode [1 0 1 0 1 0 1 0]'); 3367 } 3368 } 3369 $this->_out('/BitsPerComponent '.$info['bpc']); 3370 if(isset($info['f'])) { 3371 $this->_out('/Filter /'.$info['f']); 3372 } 3373 if(isset($info['parms'])) { 3374 $this->_out($info['parms']); 3375 } 3376 if(isset($info['trns']) and is_array($info['trns'])) { 3377 $trns=''; 3378 for($i=0;$i<count($info['trns']);$i++) { 3379 $trns.=$info['trns'][$i].' '.$info['trns'][$i].' '; 3380 } 3381 $this->_out('/Mask ['.$trns.']'); 3382 } 3383 $this->_out('/Length '.strlen($info['data']).'>>'); 3384 $this->_putstream($info['data']); 3385 unset($this->images[$file]['data']); 3386 $this->_out('endobj'); 3387 //Palette 3388 if($info['cs']=='Indexed') { 3389 $this->_newobj(); 3390 $pal=($this->compress) ? gzcompress($info['pal']) : $info['pal']; 3391 $this->_out('<<'.$filter.'/Length '.strlen($pal).'>>'); 3392 $this->_putstream($pal); 3393 $this->_out('endobj'); 3394 } 3395 } 3396 } 3397 3398 /** 3399 * _putxobjectdict 3400 * @access protected 3401 */ 3402 function _putxobjectdict() { 3403 foreach($this->images as $image) { 3404 $this->_out('/I'.$image['i'].' '.$image['n'].' 0 R'); 3405 } 3406 } 3407 3408 /** 3409 * _putresourcedict 3410 * @access protected 3411 */ 3412 function _putresourcedict(){ 3413 $this->_out('/ProcSet [/PDF /Text /ImageB /ImageC /ImageI]'); 3414 $this->_out('/Font <<'); 3415 foreach($this->fonts as $font) { 3416 $this->_out('/F'.$font['i'].' '.$font['n'].' 0 R'); 3417 } 3418 $this->_out('>>'); 3419 $this->_out('/XObject <<'); 3420 $this->_putxobjectdict(); 3421 $this->_out('>>'); 3422 } 3423 3424 /** 3425 * _putresources 3426 * @access protected 3427 */ 3428 function _putresources() { 3429 $this->_putfonts(); 3430 $this->_putimages(); 3431 //Resource dictionary 3432 $this->offsets[2]=strlen($this->buffer); 3433 $this->_out('2 0 obj'); 3434 $this->_out('<<'); 3435 $this->_putresourcedict(); 3436 $this->_out('>>'); 3437 $this->_out('endobj'); 3438 $this->_putjavascript(); 3439 $this->_putbookmarks(); 3440 // encryption 3441 if ($this->encrypted) { 3442 $this->_newobj(); 3443 $this->enc_obj_id = $this->n; 3444 $this->_out('<<'); 3445 $this->_putencryption(); 3446 $this->_out('>>'); 3447 $this->_out('endobj'); 3448 } 3449 } 3450 3451 /** 3452 * _putinfo 3453 * Adds some meta information 3454 * @access protected 3455 */ 3456 function _putinfo() { 3457 $this->_out('/CreationDate ('.$this->_escape('D:'.date('YmdHis')).')'); 3458 $this->_out('/ModDate ('.$this->_escape('D:'.date('YmdHis')).')'); 3459 $this->_out('/Producer '.$this->_textstring(PDF_PRODUCER)); 3460 if(!empty($this->title)) { 3461 $this->_out('/Title '.$this->_textstring($this->title)); 3462 } 3463 if(!empty($this->subject)) { 3464 $this->_out('/Subject '.$this->_textstring($this->subject)); 3465 } 3466 if(!empty($this->author)) { 3467 $this->_out('/Author '.$this->_textstring($this->author)); 3468 } 3469 if(!empty($this->keywords)) { 3470 $this->_out('/Keywords '.$this->_textstring($this->keywords)); 3471 } 3472 if(!empty($this->creator)) { 3473 $this->_out('/Creator '.$this->_textstring($this->creator)); 3474 } 3475 } 3476 3477 /** 3478 * _putcatalog 3479 * @access protected 3480 */ 3481 function _putcatalog() { 3482 $this->_out('/Type /Catalog'); 3483 $this->_out('/Pages 1 0 R'); 3484 if($this->ZoomMode=='fullpage') { 3485 $this->_out('/OpenAction [3 0 R /Fit]'); 3486 } 3487 elseif($this->ZoomMode=='fullwidth') { 3488 $this->_out('/OpenAction [3 0 R /FitH null]'); 3489 } 3490 elseif($this->ZoomMode=='real') { 3491 $this->_out('/OpenAction [3 0 R /XYZ null null 1]'); 3492 } 3493 elseif(!is_string($this->ZoomMode)) { 3494 $this->_out('/OpenAction [3 0 R /XYZ null null '.($this->ZoomMode/100).']'); 3495 } 3496 if($this->LayoutMode=='single') { 3497 $this->_out('/PageLayout /SinglePage'); 3498 } 3499 elseif($this->LayoutMode=='continuous') { 3500 $this->_out('/PageLayout /OneColumn'); 3501 } 3502 elseif($this->LayoutMode=='two') { 3503 $this->_out('/PageLayout /TwoColumnLeft'); 3504 } 3505 if (!empty($this->javascript)) { 3506 $this->_out('/Names <</JavaScript '.($this->n_js).' 0 R>>'); 3507 } 3508 if(count($this->outlines)>0) { 3509 $this->_out('/Outlines '.$this->OutlineRoot.' 0 R'); 3510 $this->_out('/PageMode /UseOutlines'); 3511 } 3512 if($this->rtl) { 3513 $this->_out('/ViewerPreferences << /Direction /R2L >>'); 3514 } 3515 } 3516 3517 /** 3518 * _puttrailer 3519 * @access protected 3520 */ 3521 function _puttrailer() { 3522 $this->_out('/Size '.($this->n+1)); 3523 $this->_out('/Root '.$this->n.' 0 R'); 3524 $this->_out('/Info '.($this->n-1).' 0 R'); 3525 if ($this->encrypted) { 3526 $this->_out('/Encrypt '.$this->enc_obj_id.' 0 R'); 3527 $this->_out('/ID [()()]'); 3528 } 3529 } 3530 3531 /** 3532 * _putheader 3533 * @access protected 3534 */ 3535 function _putheader() { 3536 $this->_out('%PDF-'.$this->PDFVersion); 3537 } 3538 3539 /** 3540 * _enddoc 3541 * @access protected 3542 */ 3543 function _enddoc() { 3544 $this->_putheader(); 3545 $this->_putpages(); 3546 $this->_putresources(); 3547 //Info 3548 $this->_newobj(); 3549 $this->_out('<<'); 3550 $this->_putinfo(); 3551 $this->_out('>>'); 3552 $this->_out('endobj'); 3553 //Catalog 3554 $this->_newobj(); 3555 $this->_out('<<'); 3556 $this->_putcatalog(); 3557 $this->_out('>>'); 3558 $this->_out('endobj'); 3559 //Cross-ref 3560 $o=strlen($this->buffer); 3561 $this->_out('xref'); 3562 $this->_out('0 '.($this->n+1)); 3563 $this->_out('0000000000 65535 f '); 3564 for($i=1;$i<=$this->n;$i++) { 3565 $this->_out(sprintf('%010d 00000 n ',$this->offsets[$i])); 3566 } 3567 //Trailer 3568 $this->_out('trailer'); 3569 $this->_out('<<'); 3570 $this->_puttrailer(); 3571 $this->_out('>>'); 3572 $this->_out('startxref'); 3573 $this->_out($o); 3574 $this->_out('%%EOF'); 3575 $this->state=3; 3576 } 3577 3578 /** 3579 * _beginpage 3580 * @access protected 3581 */ 3582 function _beginpage($orientation) { 3583 $this->page++; 3584 $this->pages[$this->page]=''; 3585 $this->state=2; 3586 if ($this->rtl) { 3587 $this->x = $this->w - $this->rMargin; 3588 } else { 3589 $this->x = $this->lMargin; 3590 } 3591 $this->y = $this->tMargin; 3592 $this->FontFamily=''; 3593 //Page orientation 3594 if(empty($orientation)) { 3595 $orientation=$this->DefOrientation; 3596 } 3597 else { 3598 $orientation=strtoupper($orientation{0}); 3599 if($orientation!=$this->DefOrientation) { 3600 $this->OrientationChanges[$this->page]=true; 3601 } 3602 } 3603 if($orientation!=$this->CurOrientation) { 3604 //Change orientation 3605 if($orientation=='P') { 3606 $this->wPt=$this->fwPt; 3607 $this->hPt=$this->fhPt; 3608 $this->w=$this->fw; 3609 $this->h=$this->fh; 3610 } 3611 else { 3612 $this->wPt=$this->fhPt; 3613 $this->hPt=$this->fwPt; 3614 $this->w=$this->fh; 3615 $this->h=$this->fw; 3616 } 3617 $this->PageBreakTrigger=$this->h-$this->bMargin; 3618 $this->CurOrientation=$orientation; 3619 } 3620 } 3621 3622 /** 3623 * End of page contents 3624 * @access protected 3625 */ 3626 function _endpage() { 3627 $this->state=1; 3628 } 3629 3630 /** 3631 * Begin a new object 3632 * @access protected 3633 */ 3634 function _newobj() { 3635 $this->n++; 3636 $this->offsets[$this->n]=strlen($this->buffer); 3637 $this->_out($this->n.' 0 obj'); 3638 } 3639 3640 /** 3641 * Underline text 3642 * @param int $x X coordinate 3643 * @param int $y Y coordinate 3644 * @param string $txt text to underline 3645 * @access protected 3646 */ 3647 function _dounderline($x, $y, $txt) { 3648 $up = $this->CurrentFont['up']; 3649 $ut = $this->CurrentFont['ut']; 3650 $w = $this->GetStringWidth($txt) + $this->ws * substr_count($txt,' '); 3651 return sprintf('%.2f %.2f %.2f %.2f re f', $x * $this->k, ($this->h - ($y - $up / 1000 * $this->FontSize)) * $this->k, $w * $this->k, -$ut / 1000 * $this->FontSizePt); 3652 } 3653 3654 3655 // REWRITTEN by Warren Sherliker wsherliker@gmail.com 3656 // altered to allow compatibility with all sorts of image formats including gif. 3657 // Can easily extend to work with others 3658 // such as gd xbm etc. which are all supported by php 5+ 3659 // (Requires GD library) 3660 3661 /** 3662 * Extract info from a JPEG file 3663 * @param string $file image file to parse 3664 * @return string 3665 * @access protected 3666 */ 3667 function _parsejpg($file) { 3668 if(!function_exists('imagecreatefromjpeg')) { 3669 // GD is not installed, try legacy method 3670 return $this->_legacyparsejpg($file); 3671 } 3672 $a=getimagesize($file); 3673 if(empty($a)) { 3674 $this->Error('Missing or incorrect image file: '.$file); 3675 } 3676 if($a[2]!=2) { 3677 $this->Error('Not a JPEG file: '.$file); 3678 } 3679 $jpeg = imagecreatefromjpeg($file); 3680 return $this->outputjpg($file, $jpeg); 3681 } 3682 3683 /** 3684 * Extract info from a GIF file 3685 * @param string $file image file to parse 3686 * @return string 3687 * @access protected 3688 */ 3689 function _parsegif($file) { 3690 if(!function_exists('imagecreatefromgif')) { 3691 // PDF doesn't support native GIF and GD is not installed 3692 return false; 3693 } 3694 $a=getimagesize($file); 3695 if(empty($a)) { 3696 $this->Error('Missing or incorrect image file: '.$file); 3697 } 3698 if($a[2]!=1) { 3699 $this->Error('Not a GIF file: '.$file); 3700 } 3701 // Temporary convert file to jpg and then delete this temp data file 3702 $gif = imagecreatefromgif($file); 3703 return $this->toJPEG($file, $gif); 3704 } 3705 3706 /** 3707 * Extract info from a PNG file 3708 * @param string $file image file to parse 3709 * @return string 3710 * @access protected 3711 */ 3712 function _parsepng($file) { 3713 if(!function_exists('imagecreatefrompng')) { 3714 // GD is not installed, try legacy method 3715 return $this->_legacyparsepng($file); 3716 } 3717 $f=fopen($file,'rb'); 3718 if(empty($f)) { 3719 $this->Error('Can\'t open image file: '.$file); 3720 } 3721 //Check signature 3722 if(fread($f,8)!=chr(137).'PNG'.chr(13).chr(10).chr(26).chr(10)) { 3723 $this->Error('Not a PNG file: '.$file); 3724 } 3725 //Read header chunk 3726 fread($f,4); 3727 if(fread($f,4)!='IHDR') { 3728 $this->Error('Incorrect PNG file: '.$file); 3729 } 3730 // Temporary convert file to jpg and then delete this temp data file 3731 $a=getimagesize($file); 3732 $png = imagecreatefrompng($file); 3733 return $this->toJPEG($file, $png); 3734 } 3735 3736 /** 3737 * Extract info from a JPEG file without using GD 3738 * @param string $file image file to parse 3739 * @return string 3740 * @access protected 3741 */ 3742 function _legacyparsejpg($file) { 3743 $a=GetImageSize($file); 3744 if(empty($a)) { 3745 $this->Error('Missing or incorrect image file: '.$file); 3746 } 3747 if($a[2]!=2) { 3748 $this->Error('Not a JPEG file: '.$file); 3749 } 3750 if(!isset($a['channels']) or $a['channels']==3) { 3751 $colspace='DeviceRGB'; 3752 } 3753 elseif($a['channels']==4) { 3754 $colspace='DeviceCMYK'; 3755 } 3756 else { 3757 $colspace='DeviceGray'; 3758 } 3759 $bpc=isset($a['bits']) ? $a['bits'] : 8; 3760 //Read whole file 3761 $f=fopen($file,'rb'); 3762 $data=''; 3763 while(!feof($f)) { 3764 $data.=fread($f,4096); 3765 } 3766 fclose($f); 3767 return array('w'=>$a[0],'h'=>$a[1],'cs'=>$colspace,'bpc'=>$bpc,'f'=>'DCTDecode','data'=>$data); 3768 } 3769 3770 /** 3771 * Extract info from a PNG file without using GD 3772 * @param string $file image file to parse 3773 * @return string 3774 * @access protected 3775 */ 3776 function _legacyparsepng($file) { 3777 $f=fopen($file,'rb'); 3778 if(empty($f)) { 3779 $this->Error('Can\'t open image file: '.$file); 3780 } 3781 //Check signature 3782 if(fread($f,8)!=chr(137).'PNG'.chr(13).chr(10).chr(26).chr(10)) { 3783 $this->Error('Not a PNG file: '.$file); 3784 } 3785 //Read header chunk 3786 fread($f,4); 3787 if(fread($f,4)!='IHDR') { 3788 $this->Error('Incorrect PNG file: '.$file); 3789 } 3790 $w=$this->_freadint($f); 3791 $h=$this->_freadint($f); 3792 $bpc=ord(fread($f,1)); 3793 if($bpc>8) { 3794 $this->Error('16-bit depth not supported: '.$file); 3795 } 3796 $ct=ord(fread($f,1)); 3797 if($ct==0) { 3798 $colspace='DeviceGray'; 3799 } 3800 elseif($ct==2) { 3801 $colspace='DeviceRGB'; 3802 } 3803 elseif($ct==3) { 3804 $colspace='Indexed'; 3805 } 3806 else { 3807 $this->Error('Alpha channel not supported: '.$file); 3808 } 3809 if(ord(fread($f,1))!=0) { 3810 $this->Error('Unknown compression method: '.$file); 3811 } 3812 if(ord(fread($f,1))!=0) { 3813 $this->Error('Unknown filter method: '.$file); 3814 } 3815 if(ord(fread($f,1))!=0) { 3816 $this->Error('Interlacing not supported: '.$file); 3817 } 3818 fread($f,4); 3819 $parms='/DecodeParms <</Predictor 15 /Colors '.($ct==2 ? 3 : 1).' /BitsPerComponent '.$bpc.' /Columns '.$w.'>>'; 3820 //Scan chunks looking for palette, transparency and image data 3821 $pal=''; 3822 $trns=''; 3823 $data=''; 3824 do { 3825 $n=$this->_freadint($f); 3826 $type=fread($f,4); 3827 if($type=='PLTE') { 3828 //Read palette 3829 $pal=fread($f,$n); 3830 fread($f,4); 3831 } 3832 elseif($type=='tRNS') { 3833 //Read transparency info 3834 $t=fread($f,$n); 3835 if($ct==0) { 3836 $trns=array(ord(substr($t,1,1))); 3837 } 3838 elseif($ct==2) { 3839 $trns=array(ord(substr($t,1,1)),ord(substr($t,3,1)),ord(substr($t,5,1))); 3840 } 3841 else { 3842 $pos=strpos($t,chr(0)); 3843 if($pos!==false) { 3844 $trns=array($pos); 3845 } 3846 } 3847 fread($f,4); 3848 } 3849 elseif($type=='IDAT') { 3850 //Read image data block 3851 $data.=fread($f,$n); 3852 fread($f,4); 3853 } 3854 elseif($type=='IEND') { 3855 break; 3856 } 3857 else { 3858 fread($f,$n+4); 3859 } 3860 } 3861 while($n); 3862 if($colspace=='Indexed' and empty($pal)) { 3863 $this->Error('Missing palette in '.$file); 3864 } 3865 fclose($f); 3866 return array('w'=>$w, 'h'=>$h, 'cs'=>$colspace, 'bpc'=>$bpc, 'f'=>'FlateDecode', 'parms'=>$parms, 'pal'=>$pal, 'trns'=>$trns, 'data'=>$data); 3867 } 3868 3869 /** 3870 * Convert the loaded php image to a JPEG and then return a structure for the PDF creator. 3871 * @param string $file Image file name. 3872 * @param image $image Image object. 3873 * return image JPEG image object. 3874 * @access protected 3875 */ 3876 function toJPEG($file, $image) { 3877 if ($image) { 3878 // output 3879 $tempname = tempnam(K_PATH_CACHE,'jpg'); 3880 imagejpeg($image, $tempname, 100); 3881 imagedestroy($image); 3882 $retvars = $this->outputjpg($tempname); 3883 // tidy up by removing temporary image 3884 unlink($tempname); 3885 return $retvars; 3886 } else { 3887 $this->Error('Can\'t open image file: '.$file); 3888 } 3889 } 3890 3891 /** 3892 * Get a JPEG filename and return a structure for the PDF creator. 3893 * @param string $filename JPEG file name. 3894 * @return array structure containing the image data 3895 * @access protected 3896 */ 3897 function outputjpg($filename) { 3898 $a=getimagesize($filename); 3899 3900 if(!isset($a['channels']) or $a['channels']==3) { 3901 $colspace='DeviceRGB'; 3902 } 3903 elseif($a['channels']==4) { 3904 $colspace='DeviceCMYK'; 3905 } 3906 else { 3907 $colspace='DeviceGray'; 3908 } 3909 $bpc=isset($a['bits']) ? $a['bits'] : 8; 3910 //Read whole file 3911 3912 $f=fopen($filename,'rb'); 3913 $data=''; 3914 while(!feof($f)) { 3915 $data.=fread($f,4096); 3916 } 3917 fclose($f); 3918 3919 return array('w'=>$a[0],'h'=>$a[1],'cs'=>$colspace,'bpc'=>$bpc,'f'=>'DCTDecode','data'=>$data); 3920 } 3921 3922 /// END OF REWRITE BY Warren Sherliker wsherliker@gmail.com 3923 3924 /** 3925 * Read a 4-byte integer from file 3926 * @param string $f file name. 3927 * @return 4-byte integer 3928 * @access protected 3929 */ 3930 function _freadint($f) { 3931 $a=unpack('Ni',fread($f,4)); 3932 return $a['i']; 3933 } 3934 3935 /** 3936 * Format a text string for meta information 3937 * @param string $s string to escape. 3938 * @return string escaped string. 3939 * @access protected 3940 */ 3941 function _textstring($s) { 3942 if($this->isunicode) { 3943 //Convert string to UTF-16BE 3944 $s = $this->UTF8ToUTF16BE($s, true); 3945 } 3946 if ($this->encrypted) { 3947 $s = $this->_RC4($this->_objectkey($this->n), $s); 3948 } 3949 return '('. $this->_escape($s).')'; 3950 } 3951 3952 /** 3953 * Format an URI string 3954 * @param string $s string to escape. 3955 * @return string escaped string. 3956 * @access protected 3957 */ 3958 function _uristring($s) { 3959 if ($this->encrypted) { 3960 $s = $this->_RC4($this->_objectkey($this->n), $s); 3961 } 3962 return '('.$this->_escape($s).')'; 3963 } 3964 3965 /** 3966 * Format a text string 3967 * @param string $s string to escape. 3968 * @return string escaped string. 3969 * @access protected 3970 */ 3971 function _escapetext($s) { 3972 if($this->isunicode) { 3973 //Convert string to UTF-16BE and reverse RTL language 3974 $s = $this->utf8StrRev($s, false, $this->tmprtl); 3975 } 3976 return $this->_escape($s); 3977 } 3978 3979 /** 3980 * Add \ before \, ( and ) 3981 * @param string $s string to escape. 3982 * @return string escaped string. 3983 * @access protected 3984 */ 3985 function _escape($s) { 3986 // the chr(13) substitution fixes the Bugs item #1421290. 3987 return strtr($s, array(')' => '\\)', '(' => '\\(', '\\' => '\\\\', chr(13) => '\r')); 3988 } 3989 3990 /** 3991 * Output a stream. 3992 * @param string $s string to output. 3993 * @access protected 3994 */ 3995 function _putstream($s) { 3996 if ($this->encrypted) { 3997 $s = $this->_RC4($this->_objectkey($this->n), $s); 3998 } 3999 $this->_out('stream'); 4000 $this->_out($s); 4001 $this->_out('endstream'); 4002 } 4003 4004 /** 4005 * Output a string to the document. 4006 * @param string $s string to output. 4007 * @access protected 4008 */ 4009 function _out($s) { 4010 if($this->state==2) { 4011 $this->pages[$this->page] .= $s."\n"; 4012 } 4013 else { 4014 $this->buffer .= $s."\n"; 4015 } 4016 } 4017 4018 /** 4019 * Adds unicode fonts.<br> 4020 * Based on PDF Reference 1.3 (section 5) 4021 * @access protected 4022 * @author Nicola Asuni 4023 * @since 1.52.0.TC005 (2005-01-05) 4024 */ 4025 function _puttruetypeunicode($font) { 4026 // Type0 Font 4027 // A composite font composed of other fonts, organized hierarchically 4028 $this->_newobj(); 4029 $this->_out('<</Type /Font'); 4030 $this->_out('/Subtype /Type0'); 4031 $this->_out('/BaseFont /'.$font['name'].''); 4032 $this->_out('/Encoding /Identity-H'); //The horizontal identity mapping for 2-byte CIDs; may be used with CIDFonts using any Registry, Ordering, and Supplement values. 4033 $this->_out('/DescendantFonts ['.($this->n + 1).' 0 R]'); 4034 $this->_out('/ToUnicode '.($this->n + 2).' 0 R'); 4035 $this->_out('>>'); 4036 $this->_out('endobj'); 4037 4038 // CIDFontType2 4039 // A CIDFont whose glyph descriptions are based on TrueType font technology 4040 $this->_newobj(); 4041 $this->_out('<</Type /Font'); 4042 $this->_out('/Subtype /CIDFontType2'); 4043 $this->_out('/BaseFont /'.$font['name'].''); 4044 $this->_out('/CIDSystemInfo '.($this->n + 2).' 0 R'); 4045 $this->_out('/FontDescriptor '.($this->n + 3).' 0 R'); 4046 if (isset($font['desc']['MissingWidth'])){ 4047 $this->_out('/DW '.$font['desc']['MissingWidth'].''); // The default width for glyphs in the CIDFont MissingWidth 4048 } 4049 $w = ""; 4050 foreach ($font['cw'] as $cid => $width) { 4051 $w .= ''.$cid.' ['.$width.'] '; // define a specific width for each individual CID 4052 } 4053 $this->_out('/W ['.$w.']'); // A description of the widths for the glyphs in the CIDFont 4054 $this->_out('/CIDToGIDMap '.($this->n + 4).' 0 R'); 4055 $this->_out('>>'); 4056 $this->_out('endobj'); 4057 4058 // ToUnicode 4059 // is a stream object that contains the definition of the CMap 4060 // (PDF Reference 1.3 chap. 5.9) 4061 $this->_newobj(); 4062 $this->_out('<</Length 345>>'); 4063 $this->_out('stream'); 4064 $this->_out('/CIDInit /ProcSet findresource begin'); 4065 $this->_out('12 dict begin'); 4066 $this->_out('begincmap'); 4067 $this->_out('/CIDSystemInfo'); 4068 $this->_out('<</Registry (Adobe)'); 4069 $this->_out('/Ordering (UCS)'); 4070 $this->_out('/Supplement 0'); 4071 $this->_out('>> def'); 4072 $this->_out('/CMapName /Adobe-Identity-UCS def'); 4073 $this->_out('/CMapType 2 def'); 4074 $this->_out('1 begincodespacerange'); 4075 $this->_out('<0000> <FFFF>'); 4076 $this->_out('endcodespacerange'); 4077 $this->_out('1 beginbfrange'); 4078 $this->_out('<0000> <FFFF> <0000>'); 4079 $this->_out('endbfrange'); 4080 $this->_out('endcmap'); 4081 $this->_out('CMapName currentdict /CMap defineresource pop'); 4082 $this->_out('end'); 4083 $this->_out('end'); 4084 $this->_out('endstream'); 4085 $this->_out('endobj'); 4086 4087 // CIDSystemInfo dictionary 4088 // A dictionary containing entries that define the character collection of the CIDFont. 4089 $this->_newobj(); 4090 $this->_out('<</Registry (Adobe)'); // A string identifying an issuer of character collections 4091 $this->_out('/Ordering (UCS)'); // A string that uniquely names a character collection issued by a specific registry 4092 $this->_out('/Supplement 0'); // The supplement number of the character collection. 4093 $this->_out('>>'); 4094 $this->_out('endobj'); 4095 4096 // Font descriptor 4097 // A font descriptor describing the CIDFont default metrics other than its glyph widths 4098 $this->_newobj(); 4099 $this->_out('<</Type /FontDescriptor'); 4100 $this->_out('/FontName /'.$font['name']); 4101 foreach ($font['desc'] as $key => $value) { 4102 $this->_out('/'.$key.' '.$value); 4103 } 4104 if ($font['file']) { 4105 // A stream containing a TrueType font program 4106 $this->_out('/FontFile2 '.$this->FontFiles[$font['file']]['n'].' 0 R'); 4107 } 4108 $this->_out('>>'); 4109 $this->_out('endobj'); 4110 4111 // Embed CIDToGIDMap 4112 // A specification of the mapping from CIDs to glyph indices 4113 $this->_newobj(); 4114 $ctgfile = $this->_getfontpath().strtolower($font['ctg']); 4115 if(!file_exists($ctgfile)) { 4116 $this->Error('Font file not found: '.$ctgfile); 4117 } 4118 $size = filesize($ctgfile); 4119 $this->_out('<</Length '.$size.''); 4120 if(substr($ctgfile, -2) == '.z') { // check file extension 4121 /* Decompresses data encoded using the public-domain 4122 zlib/deflate compression method, reproducing the 4123 original text or binary data */ 4124 $this->_out('/Filter /FlateDecode'); 4125 } 4126 $this->_out('>>'); 4127 $this->_putstream(file_get_contents($ctgfile)); 4128 $this->_out('endobj'); 4129 } 4130 4131 /** 4132 * Converts UTF-8 strings to codepoints array.<br> 4133 * Invalid byte sequences will be replaced with 0xFFFD (replacement character)<br> 4134 * Based on: http://www.faqs.org/rfcs/rfc3629.html 4135 * <pre> 4136 * Char. number range | UTF-8 octet sequence 4137 * (hexadecimal) | (binary) 4138 * --------------------+----------------------------------------------- 4139 * 0000 0000-0000 007F | 0xxxxxxx 4140 * 0000 0080-0000 07FF | 110xxxxx 10xxxxxx 4141 * 0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx 4142 * 0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx 4143 * --------------------------------------------------------------------- 4144 * 4145 * ABFN notation: 4146 * --------------------------------------------------------------------- 4147 * UTF8-octets = *( UTF8-char ) 4148 * UTF8-char = UTF8-1 / UTF8-2 / UTF8-3 / UTF8-4 4149 * UTF8-1 = %x00-7F 4150 * UTF8-2 = %xC2-DF UTF8-tail 4151 * 4152 * UTF8-3 = %xE0 %xA0-BF UTF8-tail / %xE1-EC 2( UTF8-tail ) / 4153 * %xED %x80-9F UTF8-tail / %xEE-EF 2( UTF8-tail ) 4154 * UTF8-4 = %xF0 %x90-BF 2( UTF8-tail ) / %xF1-F3 3( UTF8-tail ) / 4155 * %xF4 %x80-8F 2( UTF8-tail ) 4156 * UTF8-tail = %x80-BF 4157 * --------------------------------------------------------------------- 4158 * </pre> 4159 * @param string $str string to process. 4160 * @return array containing codepoints (UTF-8 characters values) 4161 * @access protected 4162 * @author Nicola Asuni 4163 * @since 1.53.0.TC005 (2005-01-05) 4164 */ 4165 function UTF8StringToArray($str) { 4166 if(!$this->isunicode) { 4167 // split string into array of chars 4168 $strarr = str_split($str); 4169 // convert chars to equivalent code 4170 while(list($pos,$char)=each($strarr)) { 4171 $strarr[$pos] = ord($char); 4172 } 4173 return $strarr; 4174 } 4175 $unicode = array(); // array containing unicode values 4176 $bytes = array(); // array containing single character byte sequences 4177 $numbytes = 1; // number of octetc needed to represent the UTF-8 character 4178 4179 $str .= ""; // force $str to be a string 4180 $length = strlen($str); 4181 4182 for($i = 0; $i < $length; $i++) { 4183 $char = ord($str{$i}); // get one string character at time 4184 if(count($bytes) == 0) { // get starting octect 4185 if ($char <= 0x7F) { 4186 $unicode[] = $char; // use the character "as is" because is ASCII 4187 $numbytes = 1; 4188 } elseif (($char >> 0x05) == 0x06) { // 2 bytes character (0x06 = 110 BIN) 4189 $bytes[] = ($char - 0xC0) << 0x06; 4190 $numbytes = 2; 4191 } elseif (($char >> 0x04) == 0x0E) { // 3 bytes character (0x0E = 1110 BIN) 4192 $bytes[] = ($char - 0xE0) << 0x0C; 4193 $numbytes = 3; 4194 } elseif (($char >> 0x03) == 0x1E) { // 4 bytes character (0x1E = 11110 BIN) 4195 $bytes[] = ($char - 0xF0) << 0x12; 4196 $numbytes = 4; 4197 } else { 4198 // use replacement character for other invalid sequences 4199 $unicode[] = 0xFFFD; 4200 $bytes = array(); 4201 $numbytes = 1; 4202 } 4203 } elseif (($char >> 0x06) == 0x02) { // bytes 2, 3 and 4 must start with 0x02 = 10 BIN 4204 $bytes[] = $char - 0x80; 4205 if (count($bytes) == $numbytes) { 4206 // compose UTF-8 bytes to a single unicode value 4207 $char = $bytes[0]; 4208 for($j = 1; $j < $numbytes; $j++) { 4209 $char += ($bytes[$j] << (($numbytes - $j - 1) * 0x06)); 4210 } 4211 if ((($char >= 0xD800) AND ($char <= 0xDFFF)) OR ($char >= 0x10FFFF)) { 4212 /* The definition of UTF-8 prohibits encoding character numbers between 4213 U+D800 and U+DFFF, which are reserved for use with the UTF-16 4214 encoding form (as surrogate pairs) and do not directly represent 4215 characters. */ 4216 $unicode[] = 0xFFFD; // use replacement character 4217 } 4218 else { 4219 $unicode[] = $char; // add char to array 4220 } 4221 // reset data for next char 4222 $bytes = array(); 4223 $numbytes = 1; 4224 } 4225 } else { 4226 // use replacement character for other invalid sequences 4227 $unicode[] = 0xFFFD; 4228 $bytes = array(); 4229 $numbytes = 1; 4230 } 4231 } 4232 return $unicode; 4233 } 4234 4235 /** 4236 * Converts UTF-8 strings to UTF16-BE.<br> 4237 * @param string $str string to process. 4238 * @param boolean $setbom if true set the Byte Order Mark (BOM = 0xFEFF) 4239 * @return string 4240 * @access protected 4241 * @author Nicola Asuni 4242 * @since 1.53.0.TC005 (2005-01-05) 4243 * @uses UTF8StringToArray(), arrUTF8ToUTF16BE() 4244 */ 4245 function UTF8ToUTF16BE($str, $setbom=true) { 4246 if(!$this->isunicode) { 4247 return $str; // string is not in unicode 4248 } 4249 $unicode = $this->UTF8StringToArray($str); // array containing UTF-8 unicode values 4250 return $this->arrUTF8ToUTF16BE($unicode, $setbom); 4251 } 4252 4253 /** 4254 * Converts array of UTF-8 characters to UTF16-BE string.<br> 4255 * Based on: http://www.faqs.org/rfcs/rfc2781.html 4256 * <pre> 4257 * Encoding UTF-16: 4258 * 4259 * Encoding of a single character from an ISO 10646 character value to 4260 * UTF-16 proceeds as follows. Let U be the character number, no greater 4261 * than 0x10FFFF. 4262 * 4263 * 1) If U < 0x10000, encode U as a 16-bit unsigned integer and 4264 * terminate. 4265 * 4266 * 2) Let U' = U - 0x10000. Because U is less than or equal to 0x10FFFF, 4267 * U' must be less than or equal to 0xFFFFF. That is, U' can be 4268 * represented in 20 bits. 4269 * 4270 * 3) Initialize two 16-bit unsigned integers, W1 and W2, to 0xD800 and 4271 * 0xDC00, respectively. These integers each have 10 bits free to 4272 * encode the character value, for a total of 20 bits. 4273 * 4274 * 4) Assign the 10 high-order bits of the 20-bit U' to the 10 low-order 4275 * bits of W1 and the 10 low-order bits of U' to the 10 low-order 4276 * bits of W2. Terminate. 4277 * 4278 * Graphically, steps 2 through 4 look like: 4279 * U' = yyyyyyyyyyxxxxxxxxxx 4280 * W1 = 110110yyyyyyyyyy 4281 * W2 = 110111xxxxxxxxxx 4282 * </pre> 4283 * @param array $unicode array containing UTF-8 unicode values 4284 * @param boolean $setbom if true set the Byte Order Mark (BOM = 0xFEFF) 4285 * @return string 4286 * @access protected 4287 * @author Nicola Asuni 4288 * @since 2.1.000 (2008-01-08) 4289 * @see UTF8ToUTF16BE() 4290 */ 4291 function arrUTF8ToUTF16BE($unicode, $setbom=true) { 4292 $outstr = ""; // string to be returned 4293 if ($setbom) { 4294 $outstr .= "\xFE\xFF"; // Byte Order Mark (BOM) 4295 } 4296 foreach($unicode as $char) { 4297 if($char == 0xFFFD) { 4298 $outstr .= "\xFF\xFD"; // replacement character 4299 } elseif ($char < 0x10000) { 4300 $outstr .= chr($char >> 0x08); 4301 $outstr .= chr($char & 0xFF); 4302 } else { 4303 $char -= 0x10000; 4304 $w1 = 0xD800 | ($char >> 0x10); 4305 $w2 = 0xDC00 | ($char & 0x3FF); 4306 $outstr .= chr($w1 >> 0x08); 4307 $outstr .= chr($w1 & 0xFF); 4308 $outstr .= chr($w2 >> 0x08); 4309 $outstr .= chr($w2 & 0xFF); 4310 } 4311 } 4312 return $outstr; 4313 } 4314 // ==================================================== 4315 4316 /** 4317 * Set header font. 4318 * @param array $font font 4319 * @since 1.1 4320 */ 4321 function setHeaderFont($font) { 4322 $this->header_font = $font; 4323 } 4324 4325 /** 4326 * Set footer font. 4327 * @param array $font font 4328 * @since 1.1 4329 */ 4330 function setFooterFont($font) { 4331 $this->footer_font = $font; 4332 } 4333 4334 /** 4335 * Set language array. 4336 * @param array $language 4337 * @since 1.1 4338 */ 4339 function setLanguageArray($language) { 4340 $this->l = $language; 4341 $this->rtl = $this->l['a_meta_dir']=='rtl' ? true : false; 4342 } 4343 4344 /** 4345 * Set document barcode. 4346 * @param string $bc barcode 4347 */ 4348 function setBarcode($bc="") { 4349 $this->barcode = $bc; 4350 } 4351 4352 /** 4353 * Print Barcode. 4354 * @param int $x x position in user units 4355 * @param int $y y position in user units 4356 * @param int $w width in user units 4357 * @param int $h height position in user units 4358 * @param string $type type of barcode (I25, C128A, C128B, C128C, C39) 4359 * @param string $style barcode style 4360 * @param string $font font for text 4361 * @param int $xres x resolution 4362 * @param string $code code to print 4363 */ 4364 function writeBarcode($x, $y, $w, $h, $type, $style, $font, $xres, $code) { 4365 require_once(dirname(__FILE__)."/barcode/barcode.php"); 4366 require_once(dirname(__FILE__)."/barcode/i25object.php"); 4367 require_once(dirname(__FILE__)."/barcode/c39object.php"); 4368 require_once(dirname(__FILE__)."/barcode/c128aobject.php"); 4369 require_once(dirname(__FILE__)."/barcode/c128bobject.php"); 4370 require_once(dirname(__FILE__)."/barcode/c128cobject.php"); 4371 4372 if (empty($code)) { 4373 return; 4374 } 4375 4376 if (empty($style)) { 4377 $style = BCS_ALIGN_LEFT; 4378 $style |= BCS_IMAGE_PNG; 4379 $style |= BCS_TRANSPARENT; 4380 //$style |= BCS_BORDER; 4381 //$style |= BCS_DRAW_TEXT; 4382 //$style |= BCS_STRETCH_TEXT; 4383 //$style |= BCS_REVERSE_COLOR; 4384 } 4385 if (empty($font)) {$font = BCD_DEFAULT_FONT;} 4386 if (empty($xres)) {$xres = BCD_DEFAULT_XRES;} 4387 4388 $scale_factor = 1.5 * $xres * $this->k; 4389 $bc_w = round($w * $scale_factor); //width in points 4390 $bc_h = round($h * $scale_factor); //height in points 4391 4392 switch (strtoupper($type)) { 4393 case "I25": { 4394 $obj = new I25Object($bc_w, $bc_h, $style, $code); 4395 break; 4396 } 4397 case "C128A": { 4398 $obj = new C128AObject($bc_w, $bc_h, $style, $code); 4399 break; 4400 } 4401 default: 4402 case "C128B": { 4403 $obj = new C128BObject($bc_w, $bc_h, $style, $code); 4404 break; 4405 } 4406 case "C128C": { 4407 $obj = new C128CObject($bc_w, $bc_h, $style, $code); 4408 break; 4409 } 4410 case "C39": { 4411 $obj = new C39Object($bc_w, $bc_h, $style, $code); 4412 break; 4413 } 4414 } 4415 4416 $obj->SetFont($font); 4417 $obj->DrawObject($xres); 4418 4419 //use a temporary file.... 4420 $tmpName = tempnam(K_PATH_CACHE,'img'); 4421 imagepng($obj->getImage(), $tmpName); 4422 $this->Image($tmpName, $x, $y, $w, $h, 'png'); 4423 $obj->DestroyObject(); 4424 unset($obj); 4425 unlink($tmpName); 4426 } 4427 4428 /** 4429 * Returns the PDF data. 4430 */ 4431 function getPDFData() { 4432 if($this->state < 3) { 4433 $this->Close(); 4434 } 4435 return $this->buffer; 4436 } 4437 4438 // --- HTML PARSER FUNCTIONS --- 4439 4440 /** 4441 * Allows to preserve some HTML formatting.<br /> 4442 * Supports: h1, h2, h3, h4, h5, h6, b, u, i, a, img, p, br, strong, em, font, blockquote, li, ul, ol, hr, td, th, tr, table, sup, sub, small 4443 * @param string $html text to display 4444 * @param boolean $ln if true add a new line after text (default = true) 4445 * @param int $fill Indicates if the background must be painted (1) or transparent (0). Default value: 0. 4446 * @param boolean $reseth if true reset the last cell height (default false). 4447 * @param boolean $cell if true add the default cMargin space to each Write (default false). 4448 */ 4449 function writeHTML($html, $ln=true, $fill=0, $reseth=false, $cell=false) { 4450 4451 // store some variables 4452 $html=strip_tags($html,"<h1><h2><h3><h4><h5><h6><b><u><i><a><img><p><br><br/><strong><em><font><blockquote><li><ul><ol><hr><td><th><tr><table><sup><sub><small><span><div>"); //remove all unsupported tags 4453 //replace carriage returns, newlines and tabs 4454 $repTable = array("\t" => " ", "\n" => " ", "\r" => " ", "\0" => " ", "\x0B" => " "); 4455 $html = strtr($html, $repTable); 4456 $pattern = '/(<[^>]+>)/Uu'; 4457 $a = preg_split($pattern, $html, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY); //explodes the string 4458 4459 if ((empty($this->lasth))OR ($reseth)) { 4460 //set row height 4461 $this->lasth = $this->FontSize * K_CELL_HEIGHT_RATIO; 4462 } 4463 4464 foreach($a as $key=>$element) { 4465 if (!preg_match($pattern, $element)) { 4466 //Text 4467 if($this->HREF) { 4468 $this->addHtmlLink($this->HREF, $element, $fill); 4469 } elseif($this->tdbegin) { 4470 if((strlen(trim($element)) > 0) AND ($element != " ")) { 4471 $this->Cell($this->tdwidth, $this->tdheight, $this->unhtmlentities($element), $this->tableborder, '', $this->tdalign, $this->tdbgcolor); 4472 } elseif($element == " ") { 4473 $this->Cell($this->tdwidth, $this->tdheight, '', $this->tableborder, '', $this->tdalign, $this->tdbgcolor); 4474 } 4475 } else { 4476 4477 $ctmpmargin = $this->cMargin; 4478 if(!$cell) { 4479 $this->cMargin = 0; 4480 } 4481 4482 $this->Write($this->lasth, stripslashes($this->unhtmlentities($element)), '', $fill, '', false, 0); 4483 4484 $this->cMargin = $ctmpmargin; 4485 } 4486 } else { 4487 $element = substr($element, 1, -1); 4488 //Tag 4489 if($element{0}=='/') { 4490 $this->closedHTMLTagHandler(strtolower(substr($element, 1))); 4491 } 4492 else { 4493 //Extract attributes 4494 // get tag name 4495 preg_match('/([a-zA-Z0-9]*)/', $element, $tag); 4496 $tag = strtolower($tag[0]); 4497 // get attributes 4498 preg_match_all('/([^=\s]*)=["\']?([^"\']*)["\']?/', $element, $attr_array, PREG_PATTERN_ORDER); 4499 $attr = array(); // reset attribute array 4500 while(list($id,$name)=each($attr_array[1])) { 4501 $attr[strtolower($name)] = $attr_array[2][$id]; 4502 } 4503 $this->openHTMLTagHandler($tag, $attr, $fill); 4504 } 4505 } 4506 } 4507 if ($ln) { 4508 $this->Ln($this->lasth); 4509 } 4510 } 4511 4512 /** 4513 * Prints a cell (rectangular area) with optional borders, background color and html text string. The upper-left corner of the cell corresponds to the current position. After the call, the current position moves to the right or to the next line.<br /> 4514 * If automatic page breaking is enabled and the cell goes beyond the limit, a page break is done before outputting. 4515 * @param float $w Cell width. If 0, the cell extends up to the right margin. 4516 * @param float $h Cell minimum height. The cell extends automatically if needed. 4517 * @param float $x upper-left corner X coordinate 4518 * @param float $y upper-left corner Y coordinate 4519 * @param string $html html text to print. Default value: empty string. 4520 * @param mixed $border Indicates if borders must be drawn around the cell. The value can be either a number:<ul><li>0: no border (default)</li><li>1: frame</li></ul>or a string containing some or all of the following characters (in any order):<ul><li>L: left</li><li>T: top</li><li>R: right</li><li>B: bottom</li></ul> 4521 * @param int $ln Indicates where the current position should go after the call. Possible values are:<ul><li>0: to the right (or left for RTL language)</li><li>1: to the beginning of the next line</li><li>2: below</li></ul> 4522 Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: 0. 4523 * @param int $fill Indicates if the cell background must be painted (1) or transparent (0). Default value: 0. 4524 * @param boolean $reseth if true reset the last cell height (default true). 4525 * @see Cell() 4526 */ 4527 function writeHTMLCell($w, $h, $x, $y, $html='', $border=0, $ln=0, $fill=0, $reseth=true) { 4528 4529 if ((empty($this->lasth))OR ($reseth)) { 4530 //set row height 4531 $this->lasth = $this->FontSize * K_CELL_HEIGHT_RATIO; 4532 } 4533 4534 // get current page number 4535 $startpage = $this->page; 4536 4537 if (!empty($y)) { 4538 $this->SetY($y); 4539 } else { 4540 $y = $this->GetY(); 4541 } 4542 if (!empty($x)) { 4543 $this->SetX($x); 4544 } else { 4545 $x = $this->GetX(); 4546 } 4547 4548 if(empty($w)) { 4549 if ($this->rtl) { 4550 $w = $this->x - $this->lMargin; 4551 } else { 4552 $w = $this->w - $this->rMargin - $this->x; 4553 } 4554 } 4555 4556 // store original margin values 4557 $lMargin = $this->lMargin; 4558 $rMargin = $this->rMargin; 4559 4560 // set new margin values 4561 if ($this->rtl) { 4562 $this->SetLeftMargin($this->x - $w); 4563 $this->SetRightMargin($this->w - $this->x); 4564 } else { 4565 $this->SetLeftMargin($this->x); 4566 $this->SetRightMargin($this->w - $this->x - $w); 4567 } 4568 4569 // calculate remaining vertical space on first page ($startpage) 4570 $restspace = $this->getPageHeight() - $this->GetY() - $this->getBreakMargin(); 4571 4572 // Write HTML text 4573 $this->writeHTML($html, true, $fill, $reseth, true); 4574 4575 // Get end-of-text Y position 4576 $currentY = $this->GetY(); 4577 // get latest page number 4578 $endpage = $this->page; 4579 4580 if (!empty($border)) { 4581 // check if a new page has been created 4582 if ($endpage > $startpage) { 4583 // design borders around HTML cells. 4584 for ($page=$startpage; $page<=$endpage; $page++) { 4585 $this->page = $page; 4586 if ($page==$startpage) { 4587 $this->SetY($this->getPageHeight() - $restspace - $this->getBreakMargin()); 4588 $h = $restspace - 1; 4589 } elseif ($page==$endpage) { 4590 $this->SetY($this->tMargin); // put cursor at the beginning of text 4591 $h = $currentY - $this->tMargin; 4592 } else { 4593 $this->SetY($this->tMargin); // put cursor at the beginning of text 4594 $h = $this->getPageHeight() - $this->tMargin - $this->getBreakMargin(); 4595 } 4596 $this->SetX($x); 4597 $this->Cell($w, $h, "", $border, 1, '', 0); 4598 } 4599 } else { 4600 $h = max($h, ($currentY - $y)); 4601 $this->SetY($y); // put cursor at the beginning of text 4602 $this->SetX($x); 4603 // design a cell around the text 4604 $this->Cell($w, $h, "", $border, 1, '', 0); 4605 } 4606 } 4607 4608 // restore original margin values 4609 $this->SetLeftMargin($lMargin); 4610 $this->SetRightMargin($rMargin); 4611 4612 if($ln>0) { 4613 //Go to the beginning of the next line 4614 $this->SetY($currentY); 4615 if($ln == 2) { 4616 $this->SetX($x + $w); 4617 } 4618 } else { 4619 // go left or right by case 4620 $this->page = $startpage; 4621 $this->y = $y; 4622 $this->SetX($x + $w); 4623 } 4624 } 4625 4626 /** 4627 * Process opening tags. 4628 * @param string $tag tag name (in uppercase) 4629 * @param string $attr tag attribute (in uppercase) 4630 * @param int $fill Indicates if the cell background must be painted (1) or transparent (0). Default value: 0. 4631 * @access private 4632 */ 4633 function openHTMLTagHandler($tag, $attr, $fill=0) { 4634 // check for text direction attribute 4635 if (isset($attr['dir'])) { 4636 $this->tmprtl = $attr['dir']=='rtl' ? 'R' : 'L'; 4637 } else { 4638 $this->tmprtl = false; 4639 } 4640 //Opening tag 4641 switch($tag) { 4642 case 'table': { 4643 if ((isset($attr['border'])) AND ($attr['border'] != '')) { 4644 $this->tableborder = $attr['border']; 4645 } 4646 else { 4647 $this->tableborder = 0; 4648 } 4649 break; 4650 } 4651 case 'tr': { 4652 break; 4653 } 4654 case 'td': 4655 case 'th': { 4656 if ((isset($attr['width'])) AND ($attr['width'] != '')) { 4657 $this->tdwidth = ($attr['width']/4); 4658 } 4659 else { 4660 $this->tdwidth = (($this->w - $this->lMargin - $this->rMargin) / $this->default_table_columns); 4661 } 4662 if ((isset($attr['height'])) AND ($attr['height'] != '')) { 4663 $this->tdheight=($attr['height'] / $this->k); 4664 } 4665 else { 4666 $this->tdheight = $this->lasth; 4667 } 4668 if ((isset($attr['align'])) AND ($attr['align'] != '')) { 4669 switch ($attr['align']) { 4670 case 'center': { 4671 $this->tdalign = "C"; 4672 break; 4673 } 4674 case 'right': { 4675 $this->tdalign = "R"; 4676 break; 4677 } 4678 default: 4679 case 'left': { 4680 $this->tdalign = "L"; 4681 break; 4682 } 4683 } 4684 } else { 4685 if($this->rtl) { 4686 $this->tdalign = "R"; 4687 } else { 4688 $this->tdalign = "L"; 4689 } 4690 } 4691 if ((isset($attr['bgcolor'])) AND ($attr['bgcolor'] != '')) { 4692 $coul = $this->convertColorHexToDec($attr['bgcolor']); 4693 $this->SetFillColor($coul['R'], $coul['G'], $coul['B']); 4694 $this->tdbgcolor=true; 4695 } 4696 $this->tdbegin=true; 4697 break; 4698 } 4699 case 'hr': { 4700 $this->Ln(); 4701 if ((isset($attr['width'])) AND ($attr['width'] != '')) { 4702 $hrWidth = $attr['width']; 4703 } 4704 else { 4705 $hrWidth = $this->w - $this->lMargin - $this->rMargin; 4706 } 4707 $x = $this->GetX(); 4708 $y = $this->GetY(); 4709 $this->GetLineWidth(); 4710 $prevlinewidth = $this->SetLineWidth(0.2); 4711 $this->Line($x, $y, $x + $hrWidth, $y); 4712 $this->SetLineWidth($prevlinewidth); 4713 $this->Ln(); 4714 break; 4715 } 4716 case 'strong': { 4717 $this->setStyle('b', true); 4718 break; 4719 } 4720 case 'em': { 4721 $this->setStyle('i', true); 4722 break; 4723 } 4724 case 'b': 4725 case 'i': 4726 case 'u': { 4727 $this->setStyle($tag, true); 4728 break; 4729 } 4730 case 'a': { 4731 $this->HREF = $attr['href']; 4732 break; 4733 } 4734 case 'img': { 4735 if(isset($attr['src'])) { 4736 // replace relative path with real server path 4737 if ($attr['src'][0] == '/') { 4738 $attr['src'] = $_SERVER['DOCUMENT_ROOT'].$attr['src']; 4739 } 4740 $attr['src'] = str_replace(K_PATH_URL, K_PATH_MAIN, $attr['src']); 4741 if(!isset($attr['width'])) { 4742 $attr['width'] = 0; 4743 } 4744 if(!isset($attr['height'])) { 4745 $attr['height'] = 0; 4746 } 4747 if(!isset($attr['align'])) { 4748 $align = 'N'; 4749 } else { 4750 switch($attr['align']) { 4751 case 'top':{ 4752 $align = 'T'; 4753 break; 4754 } 4755 case 'middle':{ 4756 $align = 'M'; 4757 break; 4758 } 4759 case 'bottom':{ 4760 $align = 'B'; 4761 break; 4762 } 4763 default:{ 4764 $align = 'N'; 4765 break; 4766 } 4767 } 4768 } 4769 $this->Image($attr['src'], $this->GetX(),$this->GetY(), $this->pixelsToMillimeters($attr['width']), $this->pixelsToMillimeters($attr['height']), '', '', $align); 4770 4771 } 4772 break; 4773 } 4774 case 'ul': { 4775 $this->listordered = false; 4776 $this->listcount = 0; 4777 break; 4778 } 4779 case 'ol': { 4780 $this->listordered = true; 4781 $this->listcount = 0; 4782 break; 4783 } 4784 case 'li': { 4785 $this->Ln(); 4786 if ($this->listordered) { 4787 if (isset($attr['value'])) { 4788 $this->listcount = intval($attr['value']); 4789 } 4790 $this->lispacer = " ".(++$this->listcount).". "; 4791 } else { 4792 //unordered list simbol 4793 $this->lispacer = " - "; 4794 } 4795 $rtldir = $this->tmprtl; 4796 $this->tmprtl = false; 4797 $this->Write($this->lasth, $this->lispacer, '', $fill, '', false, 0); 4798 $this->tmprtl = $rtldir; 4799 break; 4800 } 4801 case 'blockquote': 4802 case 'br': { 4803 $this->Ln(); 4804 if(strlen($this->lispacer) > 0) { 4805 if ($this->rtl) { 4806 $this->x -= $this->GetStringWidth($this->lispacer); 4807 } else { 4808 $this->x += $this->GetStringWidth($this->lispacer); 4809 } 4810 } 4811 break; 4812 } 4813 case 'p': { 4814 $this->Ln(); 4815 $this->Ln(); 4816 break; 4817 } 4818 case 'sup': { 4819 $currentFontSize = $this->FontSize; 4820 $this->tempfontsize = $this->FontSizePt; 4821 $this->SetFontSize($this->FontSizePt * K_SMALL_RATIO); 4822 $this->SetXY($this->GetX(), $this->GetY() - (($currentFontSize - $this->FontSize)*(K_SMALL_RATIO))); 4823 break; 4824 } 4825 case 'sub': { 4826 $currentFontSize = $this->FontSize; 4827 $this->tempfontsize = $this->FontSizePt; 4828 $this->SetFontSize($this->FontSizePt * K_SMALL_RATIO); 4829 $this->SetXY($this->GetX(), $this->GetY() + (($currentFontSize - $this->FontSize)*(K_SMALL_RATIO))); 4830 break; 4831 } 4832 case 'small': { 4833 $currentFontSize = $this->FontSize; 4834 $this->tempfontsize = $this->FontSizePt; 4835 $this->SetFontSize($this->FontSizePt * K_SMALL_RATIO); 4836 $this->SetXY($this->GetX(), $this->GetY() + (($currentFontSize - $this->FontSize)/3)); 4837 break; 4838 } 4839 case 'font': { 4840 if (isset($attr['color']) AND $attr['color']!='') { 4841 $coul = $this->convertColorHexToDec($attr['color']); 4842 $this->SetTextColor($coul['R'],$coul['G'],$coul['B']); 4843 $this->issetcolor=true; 4844 } 4845 if (isset($attr['face']) and in_array(strtolower($attr['face']), $this->fontlist)) { 4846 $this->SetFont(strtolower($attr['face'])); 4847 $this->issetfont=true; 4848 } 4849 if (isset($attr['size'])) { 4850 $headsize = intval($attr['size']); 4851 } else { 4852 $headsize = 0; 4853 } 4854 $currentFontSize = $this->FontSize; 4855 $this->tempfontsize = $this->FontSizePt; 4856 $this->SetFontSize($this->FontSizePt + $headsize); 4857 $this->lasth = $this->FontSize * K_CELL_HEIGHT_RATIO; 4858 break; 4859 } 4860 case 'h1': 4861 case 'h2': 4862 case 'h3': 4863 case 'h4': 4864 case 'h5': 4865 case 'h6': { 4866 $headsize = (4 - substr($tag, 1)) * 2; 4867 $currentFontSize = $this->FontSize; 4868 $this->tempfontsize = $this->FontSizePt; 4869 $this->SetFontSize($this->FontSizePt + $headsize); 4870 $this->setStyle('b', true); 4871 $this->lasth = $this->FontSize * K_CELL_HEIGHT_RATIO; 4872 break; 4873 } 4874 } 4875 } 4876 4877 /** 4878 * Process closing tags. 4879 * @param string $tag tag name (in uppercase) 4880 * @access private 4881 */ 4882 function closedHTMLTagHandler($tag) { 4883 //Closing tag 4884 switch($tag) { 4885 case 'td': 4886 case 'th': { 4887 $this->tdbegin = false; 4888 $this->tdwidth = 0; 4889 $this->tdheight = 0; 4890 if($this->rtl) { 4891 $this->tdalign = "R"; 4892 } else { 4893 $this->tdalign = "L"; 4894 } 4895 $this->tdbgcolor = false; 4896 $this->SetFillColor($this->prevFillColor[0], $this->prevFillColor[1], $this->prevFillColor[2]); 4897 break; 4898 } 4899 case 'tr': { 4900 $this->Ln(); 4901 break; 4902 } 4903 case 'table': { 4904 $this->tableborder=0; 4905 break; 4906 } 4907 case 'strong': { 4908 $this->setStyle('b', false); 4909 break; 4910 } 4911 case 'em': { 4912 $this->setStyle('i', false); 4913 break; 4914 } 4915 case 'b': 4916 case 'i': 4917 case 'u': { 4918 $this->setStyle($tag, false); 4919 break; 4920 } 4921 case 'a': { 4922 $this->HREF = ''; 4923 break; 4924 } 4925 case 'sup': { 4926 $currentFontSize = $this->FontSize; 4927 $this->SetFontSize($this->tempfontsize); 4928 $this->tempfontsize = $this->FontSizePt; 4929 $this->SetXY($this->GetX(), $this->GetY() - (($currentFontSize - $this->FontSize)*(K_SMALL_RATIO))); 4930 break; 4931 } 4932 case 'sub': { 4933 $currentFontSize = $this->FontSize; 4934 $this->SetFontSize($this->tempfontsize); 4935 $this->tempfontsize = $this->FontSizePt; 4936 $this->SetXY($this->GetX(), $this->GetY() + (($currentFontSize - $this->FontSize)*(K_SMALL_RATIO))); 4937 break; 4938 } 4939 case 'small': { 4940 $currentFontSize = $this->FontSize; 4941 $this->SetFontSize($this->tempfontsize); 4942 $this->tempfontsize = $this->FontSizePt; 4943 $this->SetXY($this->GetX(), $this->GetY() - (($this->FontSize - $currentFontSize)/3)); 4944 break; 4945 } 4946 case 'font': { 4947 if ($this->issetcolor == true) { 4948 $this->SetTextColor($this->prevTextColor[0], $this->prevTextColor[1], $this->prevTextColor[2]); 4949 } 4950 if ($this->issetfont) { 4951 $this->FontFamily = $this->prevFontFamily; 4952 $this->FontStyle = $this->prevFontStyle; 4953 $this->SetFont($this->FontFamily); 4954 $this->issetfont = false; 4955 } 4956 $currentFontSize = $this->FontSize; 4957 $this->SetFontSize($this->tempfontsize); 4958 $this->tempfontsize = $this->FontSizePt; 4959 //$this->TextColor = $this->prevTextColor; 4960 $this->lasth = $this->FontSize * K_CELL_HEIGHT_RATIO; 4961 break; 4962 } 4963 case 'p': { 4964 $this->Ln(); 4965 $this->Ln(); 4966 break; 4967 } 4968 case 'ul': 4969 case 'ol': { 4970 $this->Ln(); 4971 $this->Ln(); 4972 break; 4973 } 4974 case 'li': { 4975 $this->lispacer = ""; 4976 break; 4977 } 4978 case 'h1': 4979 case 'h2': 4980 case 'h3': 4981 case 'h4': 4982 case 'h5': 4983 case 'h6': { 4984 $currentFontSize = $this->FontSize; 4985 $this->SetFontSize($this->tempfontsize); 4986 $this->tempfontsize = $this->FontSizePt; 4987 $this->setStyle('b', false); 4988 $this->Ln(); 4989 $this->lasth = $this->FontSize * K_CELL_HEIGHT_RATIO; 4990 break; 4991 } 4992 default : { 4993 break; 4994 } 4995 } 4996 $this->tmprtl = false; 4997 } 4998 4999 /** 5000 * Sets font style. 5001 * @param string $tag tag name (in lowercase) 5002 * @param boolean $enable 5003 * @access private 5004 */ 5005 function setStyle($tag, $enable) { 5006 //Modify style and select corresponding font 5007 $this->$tag += ($enable ? 1 : -1); 5008 $style=''; 5009 foreach(array('b', 'i', 'u') as $s) { 5010 if($this->$s > 0) { 5011 $style .= $s; 5012 } 5013 } 5014 $this->SetFont('', $style); 5015 } 5016 5017 /** 5018 * Output anchor link. 5019 * @param string $url link URL 5020 * @param string $name link name 5021 * @param int $fill Indicates if the cell background must be painted (1) or transparent (0). Default value: 0. 5022 * @access public 5023 */ 5024 function addHtmlLink($url, $name, $fill=0) { 5025 //Put a hyperlink 5026 $this->SetTextColor(0, 0, 255); 5027 $this->setStyle('u', true); 5028 $this->Write($this->lasth, $name, $url, $fill, '', false, 0); 5029 $this->setStyle('u', false); 5030 $this->SetTextColor(0); 5031 } 5032 5033 /** 5034 * Returns an associative array (keys: R,G,B) from 5035 * a hex html code (e.g. #3FE5AA). 5036 * @param string $color hexadecimal html color [#rrggbb] 5037 * @return array 5038 * @access private 5039 */ 5040 function convertColorHexToDec($color = "#000000"){ 5041 $tbl_color = array(); 5042 $tbl_color['R'] = hexdec(substr($color, 1, 2)); 5043 $tbl_color['G'] = hexdec(substr($color, 3, 2)); 5044 $tbl_color['B'] = hexdec(substr($color, 5, 2)); 5045 return $tbl_color; 5046 } 5047 5048 /** 5049 * Converts pixels to millimeters in 72 dpi. 5050 * @param int $px pixels 5051 * @return float millimeters 5052 * @access private 5053 */ 5054 function pixelsToMillimeters($px){ 5055 return $px * 25.4 / 72; 5056 } 5057 5058 /** 5059 * Reverse function for htmlentities. 5060 * Convert entities in UTF-8. 5061 * 5062 * @param $text_to_convert Text to convert. 5063 * @return string converted 5064 */ 5065 function unhtmlentities($text_to_convert) { 5066 if (!$this->isunicode) { 5067 return html_entity_decode($text_to_convert); 5068 } 5069 require_once(dirname(__FILE__).'/html_entity_decode_php4.php'); 5070 return html_entity_decode_php4($text_to_convert); 5071 } 5072 5073 // ENCRYPTION METHODS ---------------------------------- 5074 // SINCE 2.0.000 (2008-01-02) 5075 /** 5076 * Compute encryption key depending on object number where the encrypted data is stored 5077 * @param int $n object number 5078 * @since 2.0.000 (2008-01-02) 5079 */ 5080 function _objectkey($n) { 5081 return substr($this->_md5_16($this->encryption_key.pack('VXxx',$n)),0,10); 5082 } 5083 5084 /** 5085 * Put encryption on PDF document 5086 * @since 2.0.000 (2008-01-02) 5087 */ 5088 function _putencryption() { 5089 $this->_out('/Filter /Standard'); 5090 $this->_out('/V 1'); 5091 $this->_out('/R 2'); 5092 $this->_out('/O ('.$this->_escape($this->Ovalue).')'); 5093 $this->_out('/U ('.$this->_escape($this->Uvalue).')'); 5094 $this->_out('/P '.$this->Pvalue); 5095 } 5096 5097 /** 5098 * Returns the input text exrypted using RC4 algorithm and the specified key. 5099 * RC4 is the standard encryption algorithm used in PDF format 5100 * @param string $key encryption key 5101 * @param String $text input text to be encrypted 5102 * @return String encrypted text 5103 * @since 2.0.000 (2008-01-02) 5104 * @author Klemen Vodopivec 5105 */ 5106 function _RC4($key, $text) { 5107 if ($this->last_rc4_key != $key) { 5108 $k = str_repeat($key, 256/strlen($key)+1); 5109 $rc4 = range(0,255); 5110 $j = 0; 5111 for ($i=0; $i<256; $i++) { 5112 $t = $rc4[$i]; 5113 $j = ($j + $t + ord($k{$i})) % 256; 5114 $rc4[$i] = $rc4[$j]; 5115 $rc4[$j] = $t; 5116 } 5117 $this->last_rc4_key = $key; 5118 $this->last_rc4_key_c = $rc4; 5119 } else { 5120 $rc4 = $this->last_rc4_key_c; 5121 } 5122 $len = strlen($text); 5123 $a = 0; 5124 $b = 0; 5125 $out = ''; 5126 for ($i=0; $i<$len; $i++) { 5127 $a = ($a+1)%256; 5128 $t= $rc4[$a]; 5129 $b = ($b+$t)%256; 5130 $rc4[$a] = $rc4[$b]; 5131 $rc4[$b] = $t; 5132 $k = $rc4[($rc4[$a]+$rc4[$b])%256]; 5133 $out.=chr(ord($text{$i}) ^ $k); 5134 } 5135 return $out; 5136 } 5137 5138 /** 5139 * Encrypts a string using MD5 and returns it's value as a binary string. 5140 * @param string $str input string 5141 * @return String MD5 encrypted binary string 5142 * @since 2.0.000 (2008-01-02) 5143 * @author Klemen Vodopivec 5144 */ 5145 function _md5_16($str) { 5146 return pack('H*',md5($str)); 5147 } 5148 5149 /** 5150 * Compute O value (used for RC4 encryption) 5151 * @param String $user_pass user password 5152 * @param String $owner_pass user password 5153 * @return String O value 5154 * @since 2.0.000 (2008-01-02) 5155 * @author Klemen Vodopivec 5156 */ 5157 function _Ovalue($user_pass, $owner_pass) { 5158 $tmp = $this->_md5_16($owner_pass); 5159 $owner_RC4_key = substr($tmp,0,5); 5160 return $this->_RC4($owner_RC4_key, $user_pass); 5161 } 5162 5163 /** 5164 * Compute U value (used for RC4 encryption) 5165 * @return String U value 5166 * @since 2.0.000 (2008-01-02) 5167 * @author Klemen Vodopivec 5168 */ 5169 function _Uvalue() { 5170 return $this->_RC4($this->encryption_key, $this->padding); 5171 } 5172 5173 /** 5174 * Compute encryption key 5175 * @param String $user_pass user password 5176 * @param String $owner_pass user password 5177 * @param String $protection protection type 5178 * @since 2.0.000 (2008-01-02) 5179 * @author Klemen Vodopivec 5180 */ 5181 function _generateencryptionkey($user_pass, $owner_pass, $protection) { 5182 // Pad passwords 5183 $user_pass = substr($user_pass.$this->padding,0,32); 5184 $owner_pass = substr($owner_pass.$this->padding,0,32); 5185 // Compute O value 5186 $this->Ovalue = $this->_Ovalue($user_pass,$owner_pass); 5187 // Compute encyption key 5188 $tmp = $this->_md5_16($user_pass.$this->Ovalue.chr($protection)."\xFF\xFF\xFF"); 5189 $this->encryption_key = substr($tmp,0,5); 5190 // Compute U value 5191 $this->Uvalue = $this->_Uvalue(); 5192 // Compute P value 5193 $this->Pvalue = -(($protection^255)+1); 5194 } 5195 5196 /** 5197 * Set document protection 5198 * The permission array is composed of values taken from the following ones: 5199 * - copy: copy text and images to the clipboard 5200 * - print: print the document 5201 * - modify: modify it (except for annotations and forms) 5202 * - annot-forms: add annotations and forms 5203 * Remark: the protection against modification is for people who have the full Acrobat product. 5204 * If you don't set any password, the document will open as usual. If you set a user password, the PDF viewer will ask for it before displaying the document. The master password, if different from the user one, can be used to get full access. 5205 * Note: protecting a document requires to encrypt it, which increases the processing time a lot. This can cause a PHP time-out in some cases, especially if the document contains images or fonts. 5206 * @param Array $permissions the set of permissions. Empty by default (only viewing is allowed). (print, modify, copy, annot-forms) 5207 * @param String $user_pass user password. Empty by default. 5208 * @param String $owner_pass owner password. If not specified, a random value is used. 5209 * @since 2.0.000 (2008-01-02) 5210 * @author Klemen Vodopivec 5211 */ 5212 function SetProtection($permissions=array(),$user_pass='',$owner_pass=null) { 5213 $options = array('print' => 4, 'modify' => 8, 'copy' => 16, 'annot-forms' => 32); 5214 $protection = 192; 5215 foreach($permissions as $permission) { 5216 if (!isset($options[$permission])) { 5217 $this->Error('Incorrect permission: '.$permission); 5218 } 5219 $protection += $options[$permission]; 5220 } 5221 if ($owner_pass === null) { 5222 $owner_pass = uniqid(rand()); 5223 } 5224 $this->encrypted = true; 5225 $this->_generateencryptionkey($user_pass, $owner_pass, $protection); 5226 } 5227 5228 // END OF ENCRYPTION FUNCTIONS ------------------------- 5229 5230 // START TRANSFORMATIONS SECTION ----------------------- 5231 // authors: Moritz Wagner, Andreas Wurmser, Nicola Asuni 5232 5233 /** 5234 * Starts a 2D tranformation saving current graphic state. 5235 * This function must be called before scaling, mirroring, translation, rotation and skewing. 5236 * Use StartTransform() before, and StopTransform() after the transformations to restore the normal behavior. 5237 * @since 2.1.000 (2008-01-07) 5238 * @see StartTransform(), StopTransform() 5239 */ 5240 function StartTransform() { 5241 $this->_out('q'); 5242 } 5243 5244 /** 5245 * Stops a 2D tranformation restoring previous graphic state. 5246 * This function must be called after scaling, mirroring, translation, rotation and skewing. 5247 * Use StartTransform() before, and StopTransform() after the transformations to restore the normal behavior. 5248 * @since 2.1.000 (2008-01-07) 5249 * @see StartTransform(), StopTransform() 5250 */ 5251 function StopTransform() { 5252 $this->_out('Q'); 5253 } 5254 /** 5255 * Horizontal Scaling. 5256 * @param float $s_x scaling factor for width as percent. 0 is not allowed. 5257 * @param int $x abscissa of the scaling center. Default is current x position 5258 * @param int $y ordinate of the scaling center. Default is current y position 5259 * @since 2.1.000 (2008-01-07) 5260 * @see StartTransform(), StopTransform() 5261 */ 5262 function ScaleX($s_x, $x='', $y=''){ 5263 $this->Scale($s_x, 100, $x, $y); 5264 } 5265 5266 /** 5267 * Vertical Scaling. 5268 * @param float $s_y scaling factor for height as percent. 0 is not allowed. 5269 * @param int $x abscissa of the scaling center. Default is current x position 5270 * @param int $y ordinate of the scaling center. Default is current y position 5271 * @since 2.1.000 (2008-01-07) 5272 * @see StartTransform(), StopTransform() 5273 */ 5274 function ScaleY($s_y, $x='', $y=''){ 5275 $this->Scale(100, $s_y, $x, $y); 5276 } 5277 5278 /** 5279 * Vertical and horizontal proportional Scaling. 5280 * @param float $s scaling factor for width and height as percent. 0 is not allowed. 5281 * @param int $x abscissa of the scaling center. Default is current x position 5282 * @param int $y ordinate of the scaling center. Default is current y position 5283 * @since 2.1.000 (2008-01-07) 5284 * @see StartTransform(), StopTransform() 5285 */ 5286 function ScaleXY($s, $x='', $y=''){ 5287 $this->Scale($s, $s, $x, $y); 5288 } 5289 5290 /** 5291 * Vertical and horizontal non-proportional Scaling. 5292 * @param float $s_x scaling factor for width as percent. 0 is not allowed. 5293 * @param float $s_y scaling factor for height as percent. 0 is not allowed. 5294 * @param int $x abscissa of the scaling center. Default is current x position 5295 * @param int $y ordinate of the scaling center. Default is current y position 5296 * @since 2.1.000 (2008-01-07) 5297 * @see StartTransform(), StopTransform() 5298 */ 5299 function Scale($s_x, $s_y, $x='', $y=''){ 5300 if($x === '') { 5301 $x=$this->x; 5302 } 5303 if($y === '') { 5304 $y=$this->y; 5305 } 5306 if($this->rtl) { 5307 $x = $this->w - $x; 5308 } 5309 if($s_x == 0 OR $s_y == 0) 5310 $this->Error('Please use values unequal to zero for Scaling'); 5311 $y=($this->h-$y)*$this->k; 5312 $x*=$this->k; 5313 //calculate elements of transformation matrix 5314 $s_x/=100; 5315 $s_y/=100; 5316 $tm[0]=$s_x; 5317 $tm[1]=0; 5318 $tm[2]=0; 5319 $tm[3]=$s_y; 5320 $tm[4]=$x*(1-$s_x); 5321 $tm[5]=$y*(1-$s_y); 5322 //scale the coordinate system 5323 $this->Transform($tm); 5324 } 5325 5326 /** 5327 * Horizontal Mirroring. 5328 * @param int $x abscissa of the point. Default is current x position 5329 * @since 2.1.000 (2008-01-07) 5330 * @see StartTransform(), StopTransform() 5331 */ 5332 function MirrorH($x=''){ 5333 $this->Scale(-100, 100, $x); 5334 } 5335 5336 /** 5337 * Verical Mirroring. 5338 * @param int $y ordinate of the point. Default is current y position 5339 * @since 2.1.000 (2008-01-07) 5340 * @see StartTransform(), StopTransform() 5341 */ 5342 function MirrorV($y=''){ 5343 $this->Scale(100, -100, '', $y); 5344 } 5345 5346 /** 5347 * Point reflection mirroring. 5348 * @param int $x abscissa of the point. Default is current x position 5349 * @param int $y ordinate of the point. Default is current y position 5350 * @since 2.1.000 (2008-01-07) 5351 * @see StartTransform(), StopTransform() 5352 */ 5353 function MirrorP($x='',$y=''){ 5354 $this->Scale(-100, -100, $x, $y); 5355 } 5356 5357 /** 5358 * Reflection against a straight line through point (x, y) with the gradient angle (angle). 5359 * @param float $angle gradient angle of the straight line. Default is 0 (horizontal line). 5360 * @param int $x abscissa of the point. Default is current x position 5361 * @param int $y ordinate of the point. Default is current y position 5362 * @since 2.1.000 (2008-01-07) 5363 * @see StartTransform(), StopTransform() 5364 */ 5365 function MirrorL($angle=0, $x='',$y=''){ 5366 $this->Scale(-100, 100, $x, $y); 5367 $this->Rotate(-2*($angle-90),$x,$y); 5368 } 5369 5370 /** 5371 * Translate graphic object horizontally. 5372 * @param int $t_x movement to the right 5373 * @since 2.1.000 (2008-01-07) 5374 * @see StartTransform(), StopTransform() 5375 */ 5376 function TranslateX($t_x){ 5377 $this->Translate($t_x, 0); 5378 } 5379 5380 /** 5381 * Translate graphic object vertically. 5382 * @param int $t_y movement to the bottom 5383 * @since 2.1.000 (2008-01-07) 5384 * @see StartTransform(), StopTransform() 5385 */ 5386 function TranslateY($t_y){ 5387 $this->Translate(0, $t_y, $x, $y); 5388 } 5389 5390 /** 5391 * Translate graphic object horizontally and vertically. 5392 * @param int $t_x movement to the right 5393 * @param int $t_y movement to the bottom 5394 * @since 2.1.000 (2008-01-07) 5395 * @see StartTransform(), StopTransform() 5396 */ 5397 function Translate($t_x, $t_y){ 5398 if($this->rtl) { 5399 $t_x = -$t_x; 5400 } 5401 //calculate elements of transformation matrix 5402 $tm[0]=1; 5403 $tm[1]=0; 5404 $tm[2]=0; 5405 $tm[3]=1; 5406 $tm[4]=$t_x*$this->k; 5407 $tm[5]=-$t_y*$this->k; 5408 //translate the coordinate system 5409 $this->Transform($tm); 5410 } 5411 5412 /** 5413 * Rotate object. 5414 * @param float $angle angle in degrees for counter-clockwise rotation 5415 * @param int $x abscissa of the rotation center. Default is current x position 5416 * @param int $y ordinate of the rotation center. Default is current y position 5417 * @since 2.1.000 (2008-01-07) 5418 * @see StartTransform(), StopTransform() 5419 */ 5420 function Rotate($angle, $x='', $y=''){ 5421 if($x === '') { 5422 $x=$this->x; 5423 } 5424 if($y === '') { 5425 $y=$this->y; 5426 } 5427 if($this->rtl) { 5428 $x = $this->w - $x; 5429 $angle = -$angle; 5430 } 5431 $y=($this->h-$y)*$this->k; 5432 $x*=$this->k; 5433 //calculate elements of transformation matrix 5434 $tm[0]=cos(deg2rad($angle)); 5435 $tm[1]=sin(deg2rad($angle)); 5436 $tm[2]=-$tm[1]; 5437 $tm[3]=$tm[0]; 5438 $tm[4]=$x+$tm[1]*$y-$tm[0]*$x; 5439 $tm[5]=$y-$tm[0]*$y-$tm[1]*$x; 5440 //rotate the coordinate system around ($x,$y) 5441 $this->Transform($tm); 5442 } 5443 5444 /** 5445 * Skew horizontally. 5446 * @param float $angle_x angle in degrees between -90 (skew to the left) and 90 (skew to the right) 5447 * @param int $x abscissa of the skewing center. default is current x position 5448 * @param int $y ordinate of the skewing center. default is current y position 5449 * @since 2.1.000 (2008-01-07) 5450 * @see StartTransform(), StopTransform() 5451 */ 5452 function SkewX($angle_x, $x='', $y=''){ 5453 $this->Skew($angle_x, 0, $x, $y); 5454 } 5455 5456 /** 5457 * Skew vertically. 5458 * @param float $angle_y angle in degrees between -90 (skew to the bottom) and 90 (skew to the top) 5459 * @param int $x abscissa of the skewing center. default is current x position 5460 * @param int $y ordinate of the skewing center. default is current y position 5461 * @since 2.1.000 (2008-01-07) 5462 * @see StartTransform(), StopTransform() 5463 */ 5464 function SkewY($angle_y, $x='', $y=''){ 5465 $this->Skew(0, $angle_y, $x, $y); 5466 } 5467 5468 /** 5469 * Skew. 5470 * @param float $angle_x angle in degrees between -90 (skew to the left) and 90 (skew to the right) 5471 * @param float $angle_y angle in degrees between -90 (skew to the bottom) and 90 (skew to the top) 5472 * @param int $x abscissa of the skewing center. default is current x position 5473 * @param int $y ordinate of the skewing center. default is current y position 5474 * @since 2.1.000 (2008-01-07) 5475 * @see StartTransform(), StopTransform() 5476 */ 5477 function Skew($angle_x, $angle_y, $x='', $y=''){ 5478 if($x === '') { 5479 $x=$this->x; 5480 } 5481 if($y === '') { 5482 $y=$this->y; 5483 } 5484 if($this->rtl) { 5485 $x = $this->w - $x; 5486 $angle_x = -$angle_x; 5487 } 5488 if($angle_x <= -90 OR $angle_x >= 90 OR $angle_y <= -90 OR $angle_y >= 90) 5489 $this->Error('Please use values between -90� and 90� for skewing'); 5490 $x*=$this->k; 5491 $y=($this->h-$y)*$this->k; 5492 //calculate elements of transformation matrix 5493 $tm[0]=1; 5494 $tm[1]=tan(deg2rad($angle_y)); 5495 $tm[2]=tan(deg2rad($angle_x)); 5496 $tm[3]=1; 5497 $tm[4]=-$tm[2]*$y; 5498 $tm[5]=-$tm[1]*$x; 5499 //skew the coordinate system 5500 $this->Transform($tm); 5501 } 5502 5503 /** 5504 * Apply graphic transformations. 5505 * @since 2.1.000 (2008-01-07) 5506 * @see StartTransform(), StopTransform() 5507 */ 5508 function Transform($tm){ 5509 $this->_out(sprintf('%.3f %.3f %.3f %.3f %.3f %.3f cm', $tm[0],$tm[1],$tm[2],$tm[3],$tm[4],$tm[5])); 5510 } 5511 5512 // END TRANSFORMATIONS SECTION ------------------------- 5513 5514 5515 // START GRAPHIC FUNCTIONS SECTION --------------------- 5516 // The following section is based on the code provided by David Hernandez Sanz 5517 5518 /** 5519 * Defines the line width. By default, the value equals 0.2 mm. The method can be called before the first page is created and the value is retained from page to page. 5520 * @param float $width The width. 5521 * @since 1.0 5522 * @see Line(), Rect(), Cell(), MultiCell() 5523 */ 5524 function SetLineWidth($width) { 5525 //Set line width 5526 $this->LineWidth=$width; 5527 if($this->page>0) { 5528 $this->_out(sprintf('%.2f w',$width*$this->k)); 5529 } 5530 } 5531 5532 /** 5533 * Returns the current the line width. 5534 * @return int Line width 5535 * @since 2.1.000 (2008-01-07) 5536 * @see Line(), SetLineWidth() 5537 */ 5538 function GetLineWidth() { 5539 return $this->LineWidth; 5540 } 5541 5542 /** 5543 * Set line style. 5544 * 5545 * @param array $style Line style. Array with keys among the following: 5546 * <ul> 5547 * <li>width (float): Width of the line in user units.</li> 5548 * <li>cap (string): Type of cap to put on the line. Possible values are: 5549 * butt, round, square. The difference between "square" and "butt" is that 5550 * "square" projects a flat end past the end of the line.</li> 5551 * <li>join (string): Type of join. Possible values are: miter, round, 5552 * bevel.</li> 5553 * <li>dash (mixed): Dash pattern. Is 0 (without dash) or string with 5554 * series of length values, which are the lengths of the on and off dashes. 5555 * For example: "2" represents 2 on, 2 off, 2 on, 2 off, ...; "2,1" is 2 on, 5556 * 1 off, 2 on, 1 off, ...</li> 5557 * <li>phase (integer): Modifier on the dash pattern which is used to shift 5558 * the point at which the pattern starts.</li> 5559 * <li>color (array): Draw color. Format: array(red, green, blue).</li> 5560 * </ul> 5561 * @access public 5562 * @since 2.1.000 (2008-01-08) 5563 */ 5564 function SetLineStyle($style) { 5565 extract($style); 5566 if (isset($width)) { 5567 $width_prev = $this->LineWidth; 5568 $this->SetLineWidth($width); 5569 $this->LineWidth = $width_prev; 5570 } 5571 if (isset($cap)) { 5572 $ca = array("butt" => 0, "round"=> 1, "square" => 2); 5573 if (isset($ca[$cap])) { 5574 $this->_out($ca[$cap] . " J"); 5575 } 5576 } 5577 if (isset($join)) { 5578 $ja = array("miter" => 0, "round" => 1, "bevel" => 2); 5579 if (isset($ja[$join])) { 5580 $this->_out($ja[$join] . " j"); 5581 } 5582 } 5583 if (isset($dash)) { 5584 $dash_string = ""; 5585 if ($dash) { 5586 if (ereg("^.+,", $dash)) { 5587 $tab = explode(",", $dash); 5588 } else { 5589 $tab = array($dash); 5590 } 5591 $dash_string = ""; 5592 foreach ($tab as $i => $v) { 5593 if ($i) { 5594 $dash_string .= " "; 5595 } 5596 $dash_string .= sprintf("%.2f", $v); 5597 } 5598 } 5599 if (!isset($phase) OR !$dash) { 5600 $phase = 0; 5601 } 5602 $this->_out(sprintf("[%s] %.2f d", $dash_string, $phase)); 5603 } 5604 if (isset($color)) { 5605 list($r, $g, $b) = $color; 5606 $this->SetDrawColor($r, $g, $b); 5607 } 5608 } 5609 5610 /* 5611 * Set a draw point. 5612 * @param float $x Abscissa of point. 5613 * @param float $y Ordinate of point. 5614 * @access private 5615 * @since 2.1.000 (2008-01-08) 5616 */ 5617 function _outPoint($x, $y) { 5618 if($this->rtl) { 5619 $x = $this->w - $x; 5620 } 5621 $this->_out(sprintf("%.2f %.2f m", $x * $this->k, ($this->h - $y) * $this->k)); 5622 } 5623 5624 /* 5625 * Draws a line from last draw point. 5626 * @param float $x Abscissa of end point. 5627 * @param float $y Ordinate of end point. 5628 * @access private 5629 * @since 2.1.000 (2008-01-08) 5630 */ 5631 function _outLine($x, $y) { 5632 if($this->rtl) { 5633 $x = $this->w - $x; 5634 } 5635 $this->_out(sprintf("%.2f %.2f l", $x * $this->k, ($this->h - $y) * $this->k)); 5636 } 5637 5638 /** 5639 * Draws a rectangle. 5640 * @param float $x Abscissa of upper-left corner (or upper-right corner for RTL language). 5641 * @param float $y Ordinate of upper-left corner (or upper-right corner for RTL language). 5642 * @param float $w Width. 5643 * @param float $h Height. 5644 * @param string $op options 5645 * @access protected 5646 * @since 2.1.000 (2008-01-08) 5647 */ 5648 function _outRect($x, $y, $w, $h, $op) { 5649 if($this->rtl) { 5650 $x = $this->w - $x - $w; 5651 } 5652 $this->_out(sprintf('%.2f %.2f %.2f %.2f re %s',$x*$this->k,($this->h-$y)*$this->k,$w*$this->k,-$h*$this->k,$op)); 5653 } 5654 5655 /* 5656 * Draws a Bezier curve from last draw point. 5657 * The Bezier curve is a tangent to the line between the control points at either end of the curve. 5658 * @param float $x1 Abscissa of control point 1. 5659 * @param float $y1 Ordinate of control point 1. 5660 * @param float $x2 Abscissa of control point 2. 5661 * @param float $y2 Ordinate of control point 2. 5662 * @param float $x3 Abscissa of end point. 5663 * @param float $y3 Ordinate of end point. 5664 * @access private 5665 * @since 2.1.000 (2008-01-08) 5666 */ 5667 function _outCurve($x1, $y1, $x2, $y2, $x3, $y3) { 5668 if($this->rtl) { 5669 $x1 = $this->w - $x1; 5670 $x2 = $this->w - $x2; 5671 $x3 = $this->w - $x3; 5672 } 5673 $this->_out(sprintf("%.2f %.2f %.2f %.2f %.2f %.2f c", $x1 * $this->k, ($this->h - $y1) * $this->k, $x2 * $this->k, ($this->h - $y2) * $this->k, $x3 * $this->k, ($this->h - $y3) * $this->k)); 5674 } 5675 5676 /** 5677 * Draws a line between two points. 5678 * @param float $x1 Abscissa of first point. 5679 * @param float $y1 Ordinate of first point. 5680 * @param float $x2 Abscissa of second point. 5681 * @param float $y2 Ordinate of second point. 5682 * @param array $style Line style. Array like for {@link SetLineStyle SetLineStyle}. Default value: default line style (empty array). 5683 * @access public 5684 * @since 1.0 5685 * @see SetLineWidth(), SetDrawColor(), SetLineStyle() 5686 */ 5687 function Line($x1, $y1, $x2, $y2, $style = array()) { 5688 if ($style) { 5689 $this->SetLineStyle($style); 5690 } 5691 $this->_outPoint($x1, $y1); 5692 $this->_outLine($x2, $y2); 5693 $this->_out(" S"); 5694 } 5695 5696 /** 5697 * Draws a rectangle. 5698 * @param float $x Abscissa of upper-left corner (or upper-right corner for RTL language). 5699 * @param float $y Ordinate of upper-left corner (or upper-right corner for RTL language). 5700 * @param float $w Width. 5701 * @param float $h Height. 5702 * @param string $style Style of rendering. Possible values are: 5703 * <ul> 5704 * <li>D or empty string: Draw (default).</li> 5705 * <li>F: Fill.</li> 5706 * <li>DF or FD: Draw and fill.</li> 5707 * </ul> 5708 * @param array $border_style Border style of rectangle. Array with keys among the following: 5709 * <ul> 5710 * <li>all: Line style of all borders. Array like for {@link SetLineStyle SetLineStyle}.</li> 5711 * <li>L, T, R, B or combinations: Line style of left, top, right or bottom border. Array like for {@link SetLineStyle SetLineStyle}.</li> 5712 * </ul> 5713 * If a key is not present or is null, not draws the border. Default value: default line style (empty array). 5714 * @param array $fill_color Fill color. Format: array(red, green, blue). Default value: default color (empty array). 5715 * @access public 5716 * @since 1.0 5717 * @see SetLineStyle() 5718 */ 5719 function Rect($x, $y, $w, $h, $style='', $border_style = array(), $fill_color = array()) { 5720 if (!(false === strpos($style, "F")) AND $fill_color) { 5721 list($r, $g, $b) = $fill_color; 5722 $this->SetFillColor($r, $g, $b); 5723 } 5724 switch ($style) { 5725 case "F": { 5726 $op='f'; 5727 $border_style = array(); 5728 $this->_outRect($x, $y, $w, $h, $op); 5729 break; 5730 } 5731 case "DF": 5732 case "FD": { 5733 if (!$border_style OR isset($border_style["all"])) { 5734 $op='B'; 5735 if (isset($border_style["all"])) { 5736 $this->SetLineStyle($border_style["all"]); 5737 $border_style = array(); 5738 } 5739 } else { 5740 $op='f'; 5741 } 5742 $this->_outRect($x, $y, $w, $h, $op); 5743 break; 5744 } 5745 default: { 5746 $op='S'; 5747 if (!$border_style OR isset($border_style["all"])) { 5748 if (isset($border_style["all"]) && $border_style["all"]) { 5749 $this->SetLineStyle($border_style["all"]); 5750 $border_style = array(); 5751 } 5752 $this->_outRect($x, $y, $w, $h, $op); 5753 } 5754 break; 5755 } 5756 } 5757 if ($border_style) { 5758 $border_style2 = array(); 5759 foreach ($border_style as $line => $value) { 5760 $lenght = strlen($line); 5761 for ($i = 0; $i < $lenght; $i++) { 5762 $border_style2[$line[$i]] = $value; 5763 } 5764 } 5765 $border_style = $border_style2; 5766 if (isset($border_style["L"]) && $border_style["L"]) { 5767 $this->Line($x, $y, $x, $y + $h, $border_style["L"]); 5768 } 5769 if (isset($border_style["T"]) && $border_style["T"]) { 5770 $this->Line($x, $y, $x + $w, $y, $border_style["T"]); 5771 } 5772 if (isset($border_style["R"]) && $border_style["R"]) { 5773 $this->Line($x + $w, $y, $x + $w, $y + $h, $border_style["R"]); 5774 } 5775 if (isset($border_style["B"]) && $border_style["B"]) { 5776 $this->Line($x, $y + $h, $x + $w, $y + $h, $border_style["B"]); 5777 } 5778 } 5779 } 5780 5781 5782 /** 5783 * Draws a Bezier curve. 5784 * The Bezier curve is a tangent to the line between the control points at 5785 * either end of the curve. 5786 * @param float $x0 Abscissa of start point. 5787 * @param float $y0 Ordinate of start point. 5788 * @param float $x1 Abscissa of control point 1. 5789 * @param float $y1 Ordinate of control point 1. 5790 * @param float $x2 Abscissa of control point 2. 5791 * @param float $y2 Ordinate of control point 2. 5792 * @param float $x3 Abscissa of end point. 5793 * @param float $y3 Ordinate of end point. 5794 * @param string $style Style of rendering. Possible values are: 5795 * <ul> 5796 * <li>D or empty string: Draw (default).</li> 5797 * <li>F: Fill.</li> 5798 * <li>DF or FD: Draw and fill.</li> 5799 * </ul> 5800 * @param array $line_style Line style of curve. Array like for {@link SetLineStyle SetLineStyle}. Default value: default line style (empty array). 5801 * @param array $fill_color Fill color. Format: array(red, green, blue). Default value: default color (empty array). 5802 * @access public 5803 * @see SetLineStyle() 5804 * @since 2.1.000 (2008-01-08) 5805 */ 5806 function Curve($x0, $y0, $x1, $y1, $x2, $y2, $x3, $y3, $style = "", $line_style = array(), $fill_color = array()) { 5807 if (!(false === strpos($style, "F")) AND $fill_color) { 5808 list($r, $g, $b) = $fill_color; 5809 $this->SetFillColor($r, $g, $b); 5810 } 5811 switch ($style) { 5812 case "F": { 5813 $op = "f"; 5814 $line_style = array(); 5815 break; 5816 } 5817 case "FD": 5818 case "DF": { 5819 $op = "B"; 5820 break; 5821 } 5822 default: { 5823 $op = "S"; 5824 break; 5825 } 5826 } 5827 if ($line_style) { 5828 $this->SetLineStyle($line_style); 5829 } 5830 $this->_outPoint($x0, $y0); 5831 $this->_outCurve($x1, $y1, $x2, $y2, $x3, $y3); 5832 $this->_out($op); 5833 } 5834 5835 /** 5836 * Draws an ellipse. 5837 * An ellipse is formed from n Bezier curves. 5838 * @param float $x0 Abscissa of center point. 5839 * @param float $y0 Ordinate of center point. 5840 * @param float $rx Horizontal radius. 5841 * @param float $ry Vertical radius (if ry = 0 then is a circle, see {@link Circle Circle}). Default value: 0. 5842 * @param float $angle: Angle oriented (anti-clockwise). Default value: 0. 5843 * @param float $astart: Angle start of draw line. Default value: 0. 5844 * @param float $afinish: Angle finish of draw line. Default value: 360. 5845 * @param string $style Style of rendering. Possible values are: 5846 * <ul> 5847 * <li>D or empty string: Draw (default).</li> 5848 * <li>F: Fill.</li> 5849 * <li>DF or FD: Draw and fill.</li> 5850 * <li>C: Draw close.</li> 5851 * </ul> 5852 * @param array $line_style Line style of ellipse. Array like for {@link SetLineStyle SetLineStyle}. Default value: default line style (empty array). 5853 * @param array $fill_color Fill color. Format: array(red, green, blue). Default value: default color (empty array). 5854 * @param integer $nc Number of curves used in ellipse. Default value: 8. 5855 * @access public 5856 * @since 2.1.000 (2008-01-08) 5857 */ 5858 function Ellipse($x0, $y0, $rx, $ry = 0, $angle = 0, $astart = 0, $afinish = 360, $style = "", $line_style = array(), $fill_color = array(), $nc = 8) { 5859 if ($angle) { 5860 $this->StartTransform(); 5861 $this->Rotate($angle, $x0, $y0); 5862 $this->Ellipse($x0, $y0, $rx, $ry, 0, $astart, $afinish, $style, $line_style, $fill_color, $nc); 5863 $this->StopTransform(); 5864 return; 5865 } 5866 if ($rx) { 5867 if (!(false === strpos($style, "F")) AND $fill_color) { 5868 list($r, $g, $b) = $fill_color; 5869 $this->SetFillColor($r, $g, $b); 5870 } 5871 switch ($style) { 5872 case "F": { 5873 $op = "f"; 5874 $line_style = array(); 5875 break; 5876 } 5877 case "FD": 5878 case "DF": { 5879 $op = "B"; 5880 break; 5881 } 5882 case "C": { 5883 $op = "s"; // Small "s" signifies closing the path as well 5884 break; 5885 } 5886 default: { 5887 $op = "S"; 5888 break; 5889 } 5890 } 5891 if ($line_style) { 5892 $this->SetLineStyle($line_style); 5893 } 5894 if (!$ry) { 5895 $ry = $rx; 5896 } 5897 $rx *= $this->k; 5898 $ry *= $this->k; 5899 if ($nc < 2){ 5900 $nc = 2; 5901 } 5902 $astart = deg2rad((float) $astart); 5903 $afinish = deg2rad((float) $afinish); 5904 $total_angle = $afinish - $astart; 5905 $dt = $total_angle / $nc; 5906 $dtm = $dt/3; 5907 $x0 *= $this->k; 5908 $y0 = ($this->h - $y0) * $this->k; 5909 $t1 = $astart; 5910 $a0 = $x0 + ($rx * cos($t1)); 5911 $b0 = $y0 + ($ry * sin($t1)); 5912 $c0 = -$rx * sin($t1); 5913 $d0 = $ry * cos($t1); 5914 $this->_outPoint($a0 / $this->k, $this->h - ($b0 / $this->k)); 5915 for ($i = 1; $i <= $nc; $i++) { 5916 // Draw this bit of the total curve 5917 $t1 = ($i * $dt) + $astart; 5918 $a1 = $x0 + ($rx * cos($t1)); 5919 $b1 = $y0 + ($ry * sin($t1)); 5920 $c1 = -$rx * sin($t1); 5921 $d1 = $ry * cos($t1); 5922 $this->_outCurve(($a0 + ($c0 * $dtm)) / $this->k, $this->h - (($b0 + ($d0 * $dtm)) / $this->k), ($a1 - ($c1 * $dtm)) / $this->k, $this->h - (($b1 - ($d1 * $dtm)) / $this->k), $a1 / $this->k, $this->h - ($b1 / $this->k)); 5923 $a0 = $a1; 5924 $b0 = $b1; 5925 $c0 = $c1; 5926 $d0 = $d1; 5927 } 5928 $this->_out($op); 5929 } 5930 } 5931 5932 /** 5933 * Draws a circle. 5934 * A circle is formed from n Bezier curves. 5935 * @param float $x0 Abscissa of center point. 5936 * @param float $y0 Ordinate of center point. 5937 * @param float $r Radius. 5938 * @param float $astart: Angle start of draw line. Default value: 0. 5939 * @param float $afinish: Angle finish of draw line. Default value: 360. 5940 * @param string $style Style of rendering. Possible values are: 5941 * <ul> 5942 * <li>D or empty string: Draw (default).</li> 5943 * <li>F: Fill.</li> 5944 * <li>DF or FD: Draw and fill.</li> 5945 * <li>C: Draw close.</li> 5946 * </ul> 5947 * @param array $line_style Line style of circle. Array like for {@link SetLineStyle SetLineStyle}. Default value: default line style (empty array). 5948 * @param array $fill_color Fill color. Format: array(red, green, blue). Default value: default color (empty array). 5949 * @param integer $nc Number of curves used in circle. Default value: 8. 5950 * @access public 5951 * @since 2.1.000 (2008-01-08) 5952 */ 5953 function Circle($x0, $y0, $r, $astart = 0, $afinish = 360, $style = "", $line_style = array(), $fill_color = array(), $nc = 8) { 5954 $this->Ellipse($x0, $y0, $r, 0, 0, $astart, $afinish, $style, $line_style, $fill_color, $nc); 5955 } 5956 5957 /** 5958 * Draws a polygon. 5959 * @param array $p Points 0 to ($np - 1). Array with values (x0, y0, x1, y1,..., x(np-1), y(np - 1)) 5960 * @param string $style Style of rendering. Possible values are: 5961 * <ul> 5962 * <li>D or empty string: Draw (default).</li> 5963 * <li>F: Fill.</li> 5964 * <li>DF or FD: Draw and fill.</li> 5965 * </ul> 5966 * @param array $line_style Line style of polygon. Array with keys among the following: 5967 * <ul> 5968 * <li>all: Line style of all lines. Array like for {@link SetLineStyle SetLineStyle}.</li> 5969 * <li>0 to ($np - 1): Line style of each line. Array like for {@link SetLineStyle SetLineStyle}.</li> 5970 * </ul> 5971 * If a key is not present or is null, not draws the line. Default value is default line style (empty array). 5972 * @param array $fill_color Fill color. Format: array(red, green, blue). Default value: default color (empty array). 5973 * @access public 5974 * @since 2.1.000 (2008-01-08) 5975 */ 5976 function Polygon($p, $style = "", $line_style = array(), $fill_color = array()) { 5977 $np = count($p) / 2; 5978 if (!(false === strpos($style, "F")) AND $fill_color) { 5979 list($r, $g, $b) = $fill_color; 5980 $this->SetFillColor($r, $g, $b); 5981 } 5982 switch ($style) { 5983 case "F": { 5984 $line_style = array(); 5985 $op = "f"; 5986 break; 5987 } 5988 case "FD": 5989 case "DF": { 5990 $op = "B"; 5991 break; 5992 } 5993 default: { 5994 $op = "S"; 5995 break; 5996 } 5997 } 5998 $draw = true; 5999 if ($line_style) { 6000 if (isset($line_style["all"])) { 6001 $this->SetLineStyle($line_style["all"]); 6002 } 6003 else { // 0 .. (np - 1), op = {B, S} 6004 $draw = false; 6005 if ("B" == $op) { 6006 $op = "f"; 6007 $this->_outPoint($p[0], $p[1]); 6008 for ($i = 2; $i < ($np * 2); $i = $i + 2) { 6009 $this->_outLine($p[$i], $p[$i + 1]); 6010 } 6011 $this->_outLine($p[0], $p[1]); 6012 $this->_out($op); 6013 } 6014 $p[$np * 2] = $p[0]; 6015 $p[($np * 2) + 1] = $p[1]; 6016 for ($i = 0; $i < $np; $i++) { 6017 if (isset($line_style[$i])) { 6018 $this->Line($p[$i * 2], $p[($i * 2) + 1], $p[($i * 2) + 2], $p[($i * 2) + 3], $line_style[$i]); 6019 } 6020 } 6021 } 6022 } 6023 if ($draw) { 6024 $this->_outPoint($p[0], $p[1]); 6025 for ($i = 2; $i < ($np * 2); $i = $i + 2) { 6026 $this->_outLine($p[$i], $p[$i + 1]); 6027 } 6028 $this->_outLine($p[0], $p[1]); 6029 $this->_out($op); 6030 } 6031 } 6032 6033 /** 6034 * Draws a regular polygon. 6035 * @param float $x0 Abscissa of center point. 6036 * @param float $y0 Ordinate of center point. 6037 * @param float $r: Radius of inscribed circle. 6038 * @param integer $ns Number of sides. 6039 * @param float $angle Angle oriented (anti-clockwise). Default value: 0. 6040 * @param boolean $draw_circle Draw inscribed circle or not. Default value: false. 6041 * @param string $style Style of rendering. Possible values are: 6042 * <ul> 6043 * <li>D or empty string: Draw (default).</li> 6044 * <li>F: Fill.</li> 6045 * <li>DF or FD: Draw and fill.</li> 6046 * </ul> 6047 * @param array $line_style Line style of polygon sides. Array with keys among the following: 6048 * <ul> 6049 * <li>all: Line style of all sides. Array like for {@link SetLineStyle SetLineStyle}.</li> 6050 * <li>0 to ($ns - 1): Line style of each side. Array like for {@link SetLineStyle SetLineStyle}.</li> 6051 * </ul> 6052 * If a key is not present or is null, not draws the side. Default value is default line style (empty array). 6053 * @param array $fill_color Fill color. Format: array(red, green, blue). Default value: default color (empty array). 6054 * @param string $circle_style Style of rendering of inscribed circle (if draws). Possible values are: 6055 * <ul> 6056 * <li>D or empty string: Draw (default).</li> 6057 * <li>F: Fill.</li> 6058 * <li>DF or FD: Draw and fill.</li> 6059 * </ul> 6060 * @param array $circle_outLine_style Line style of inscribed circle (if draws). Array like for {@link SetLineStyle SetLineStyle}. Default value: default line style (empty array). 6061 * @param array $circle_fill_color Fill color of inscribed circle (if draws). Format: array(red, green, blue). Default value: default color (empty array). 6062 * @access public 6063 * @since 2.1.000 (2008-01-08) 6064 */ 6065 function RegularPolygon($x0, $y0, $r, $ns, $angle = 0, $draw_circle = false, $style = "", $line_style = array(), $fill_color = array(), $circle_style = "", $circle_outLine_style = array(), $circle_fill_color = array()) { 6066 if (3 > $ns) { 6067 $ns = 3; 6068 } 6069 if ($draw_circle) { 6070 $this->Circle($x0, $y0, $r, 0, 360, $circle_style, $circle_outLine_style, $circle_fill_color); 6071 } 6072 $p = array(); 6073 for ($i = 0; $i < $ns; $i++) { 6074 $a = $angle + ($i * 360 / $ns); 6075 $a_rad = deg2rad((float) $a); 6076 $p[] = $x0 + ($r * sin($a_rad)); 6077 $p[] = $y0 + ($r * cos($a_rad)); 6078 } 6079 $this->Polygon($p, $style, $line_style, $fill_color); 6080 } 6081 6082 /** 6083 * Draws a star polygon 6084 * @param float $x0 Abscissa of center point. 6085 * @param float $y0 Ordinate of center point. 6086 * @param float $r Radius of inscribed circle. 6087 * @param integer $nv Number of vertices. 6088 * @param integer $ng Number of gap (if ($ng % $nv = 1) then is a regular polygon). 6089 * @param float $angle: Angle oriented (anti-clockwise). Default value: 0. 6090 * @param boolean $draw_circle: Draw inscribed circle or not. Default value is false. 6091 * @param string $style Style of rendering. Possible values are: 6092 * <ul> 6093 * <li>D or empty string: Draw (default).</li> 6094 * <li>F: Fill.</li> 6095 * <li>DF or FD: Draw and fill.</li> 6096 * </ul> 6097 * @param array $line_style Line style of polygon sides. Array with keys among the following: 6098 * <ul> 6099 * <li>all: Line style of all sides. Array like for 6100 * {@link SetLineStyle SetLineStyle}.</li> 6101 * <li>0 to (n - 1): Line style of each side. Array like for {@link SetLineStyle SetLineStyle}.</li> 6102 * </ul> 6103 * If a key is not present or is null, not draws the side. Default value is default line style (empty array). 6104 * @param array $fill_color Fill color. Format: array(red, green, blue). Default value: default color (empty array). 6105 * @param string $circle_style Style of rendering of inscribed circle (if draws). Possible values are: 6106 * <ul> 6107 * <li>D or empty string: Draw (default).</li> 6108 * <li>F: Fill.</li> 6109 * <li>DF or FD: Draw and fill.</li> 6110 * </ul> 6111 * @param array $circle_outLine_style Line style of inscribed circle (if draws). Array like for {@link SetLineStyle SetLineStyle}. Default value: default line style (empty array). 6112 * @param array $circle_fill_color Fill color of inscribed circle (if draws). Format: array(red, green, blue). Default value: default color (empty array). 6113 * @access public 6114 * @since 2.1.000 (2008-01-08) 6115 */ 6116 function StarPolygon($x0, $y0, $r, $nv, $ng, $angle = 0, $draw_circle = false, $style = "", $line_style = array(), $fill_color = array(), $circle_style = "", $circle_outLine_style = array(), $circle_fill_color = array()) { 6117 if (2 > $nv) { 6118 $nv = 2; 6119 } 6120 if ($draw_circle) { 6121 $this->Circle($x0, $y0, $r, 0, 360, $circle_style, $circle_outLine_style, $circle_fill_color); 6122 } 6123 $p2 = array(); 6124 $visited = array(); 6125 for ($i = 0; $i < $nv; $i++) { 6126 $a = $angle + ($i * 360 / $nv); 6127 $a_rad = deg2rad((float) $a); 6128 $p2[] = $x0 + ($r * sin($a_rad)); 6129 $p2[] = $y0 + ($r * cos($a_rad)); 6130 $visited[] = false; 6131 } 6132 $p = array(); 6133 $i = 0; 6134 do { 6135 $p[] = $p2[$i * 2]; 6136 $p[] = $p2[($i * 2) + 1]; 6137 $visited[$i] = true; 6138 $i += $ng; 6139 $i %= $nv; 6140 } while (!$visited[$i]); 6141 $this->Polygon($p, $style, $line_style, $fill_color); 6142 } 6143 6144 /** 6145 * Draws a rounded rectangle. 6146 * @param float $x Abscissa of upper-left corner. 6147 * @param float $y Ordinate of upper-left corner. 6148 * @param float $w Width. 6149 * @param float $h Height. 6150 * @param float $r Radius of the rounded corners. 6151 * @param string $round_corner Draws rounded corner or not. String with a 0 (not rounded i-corner) or 1 (rounded i-corner) in i-position. Positions are, in order and begin to 0: top left, top right, bottom right and bottom left. Default value: all rounded corner ("1111"). 6152 * @param string $style Style of rendering. Possible values are: 6153 * <ul> 6154 * <li>D or empty string: Draw (default).</li> 6155 * <li>F: Fill.</li> 6156 * <li>DF or FD: Draw and fill.</li> 6157 * </ul> 6158 * @param array $border_style Border style of rectangle. Array like for {@link SetLineStyle SetLineStyle}. Default value: default line style (empty array). 6159 * @param array $fill_color Fill color. Format: array(red, green, blue). Default value: default color (empty array). 6160 * @access public 6161 * @since 2.1.000 (2008-01-08) 6162 */ 6163 function RoundedRect($x, $y, $w, $h, $r, $round_corner = "1111", $style = "", $border_style = array(), $fill_color = array()) { 6164 if ("0000" == $round_corner) { // Not rounded 6165 $this->Rect($x, $y, $w, $h, $style, $border_style, $fill_color); 6166 } else { // Rounded 6167 if (!(false === strpos($style, "F")) AND $fill_color) { 6168 list($red, $g, $b) = $fill_color; 6169 $this->SetFillColor($red, $g, $b); 6170 } 6171 switch ($style) { 6172 case "F": { 6173 $border_style = array(); 6174 $op = "f"; 6175 break; 6176 } 6177 case "FD": 6178 case "DF": { 6179 $op = "B"; 6180 break; 6181 } 6182 default: { 6183 $op = "S"; 6184 break; 6185 } 6186 } 6187 if ($border_style) { 6188 $this->SetLineStyle($border_style); 6189 } 6190 $MyArc = 4 / 3 * (sqrt(2) - 1); 6191 $this->_outPoint($x + $r, $y); 6192 $xc = $x + $w - $r; 6193 $yc = $y + $r; 6194 $this->_outLine($xc, $y); 6195 if ($round_corner[0]) { 6196 $this->_outCurve($xc + ($r * $MyArc), $yc - $r, $xc + $r, $yc - ($r * $MyArc), $xc + $r, $yc); 6197 } else { 6198 $this->_outLine($x + $w, $y); 6199 } 6200 $xc = $x + $w - $r; 6201 $yc = $y + $h - $r; 6202 $this->_outLine($x + $w, $yc); 6203 if ($round_corner[1]) { 6204 $this->_outCurve($xc + $r, $yc + ($r * $MyArc), $xc + ($r * $MyArc), $yc + $r, $xc, $yc + $r); 6205 } else { 6206 $this->_outLine($x + $w, $y + $h); 6207 } 6208 $xc = $x + $r; 6209 $yc = $y + $h - $r; 6210 $this->_outLine($xc, $y + $h); 6211 if ($round_corner[2]) { 6212 $this->_outCurve($xc - ($r * $MyArc), $yc + $r, $xc - $r, $yc + ($r * $MyArc), $xc - $r, $yc); 6213 } else { 6214 $this->_outLine($x, $y + $h); 6215 } 6216 $xc = $x + $r; 6217 $yc = $y + $r; 6218 $this->_outLine($x, $yc); 6219 if ($round_corner[3]) { 6220 $this->_outCurve($xc - $r, $yc - ($r * $MyArc), $xc - ($r * $MyArc), $yc - $r, $xc, $yc - $r); 6221 } else { 6222 $this->_outLine($x, $y); 6223 $this->_outLine($x + $r, $y); 6224 } 6225 $this->_out($op); 6226 } 6227 } 6228 6229 // END GRAPHIC FUNCTIONS SECTION ----------------------- 6230 6231 // BIDIRECTIONAL TEXT SECTION -------------------------- 6232 /** 6233 * Reverse the RLT substrings using the Bidirectional Algorithm (http://unicode.org/reports/tr9/). 6234 * @param string $str string to manipulate. 6235 * @param bool $forcertl if 'R' forces RTL, if 'L' forces LTR 6236 * @return string 6237 * @author Nicola Asuni 6238 * @since 2.1.000 (2008-01-08) 6239 */ 6240 function utf8StrRev($str, $setbom=false, $forcertl=false) { 6241 return $this->arrUTF8ToUTF16BE($this->utf8Bidi($this->UTF8StringToArray($str), $forcertl=false), $setbom); 6242 } 6243 6244 /** 6245 * Reverse the RLT substrings using the Bidirectional Algorithm (http://unicode.org/reports/tr9/). 6246 * @param array $ta array of characters composing the string. 6247 * @param bool $forcertl if 'R' forces RTL, if 'L' forces LTR 6248 * @return string 6249 * @author Nicola Asuni 6250 * @since 2.4.000 (2008-03-06) 6251 */ 6252 function utf8Bidi($ta, $forcertl=false) { 6253 global $unicode,$unicode_mirror, $unicode_arlet; 6254 require_once(dirname(__FILE__).'/unicode_data.php'); 6255 6256 // paragraph embedding level 6257 $pel = 0; 6258 // max level 6259 $maxlevel = 0; 6260 6261 // create string from array 6262 $str = $this->UTF8ArrSubString($ta); 6263 6264 // check if string contains arabic text 6265 if (preg_match(K_RE_PATTERN_ARABIC, $str)) { 6266 $arabic = true; 6267 } else { 6268 $arabic = false; 6269 } 6270 6271 // check if string contains RTL text 6272 if (!($forcertl OR $arabic OR preg_match(K_RE_PATTERN_RTL, $str))) { 6273 return $ta; 6274 } 6275 6276 // get number of chars 6277 $numchars = count($ta); 6278 6279 if ($forcertl == 'R') { 6280 $pel = 1; 6281 } elseif ($forcertl == 'L') { 6282 $pel = 0; 6283 } else { 6284 // P2. In each paragraph, find the first character of type L, AL, or R. 6285 // P3. If a character is found in P2 and it is of type AL or R, then set the paragraph embedding level to one; otherwise, set it to zero. 6286 for ($i=0; $i < $numchars; $i++) { 6287 $type = $unicode[$ta[$i]]; 6288 if ($type == 'L') { 6289 $pel = 0; 6290 break; 6291 } elseif (($type == 'AL') OR ($type == 'R')) { 6292 $pel = 1; 6293 break; 6294 } 6295 } 6296 } 6297 6298 // Current Embedding Level 6299 $cel = $pel; 6300 // directional override status 6301 $dos = 'N'; 6302 $remember = array(); 6303 // start-of-level-run 6304 $sor = $pel % 2 ? 'R' : 'L'; 6305 $eor = $sor; 6306 6307 //$levels = array(array('level' => $cel, 'sor' => $sor, 'eor' => '', 'chars' => array())); 6308 //$current_level = &$levels[count( $levels )-1]; 6309 6310 // Array of characters data 6311 $chardata = Array(); 6312 6313 // X1. Begin by setting the current embedding level to the paragraph embedding level. Set the directional override status to neutral. Process each character iteratively, applying rules X2 through X9. Only embedding levels from 0 to 61 are valid in this phase. 6314 // In the resolution of levels in rules I1 and I2, the maximum embedding level of 62 can be reached. 6315 for ($i=0; $i < $numchars; $i++) { 6316 if ($ta[$i] == K_RLE) { 6317 // X2. With each RLE, compute the least greater odd embedding level. 6318 // a. If this new level would be valid, then this embedding code is valid. Remember (push) the current embedding level and override status. Reset the current level to this new level, and reset the override status to neutral. 6319 // b. If the new level would not be valid, then this code is invalid. Do not change the current level or override status. 6320 $next_level = $cel + ($cel % 2) + 1; 6321 if ($next_level < 62) { 6322 $remember[] = array('num' => K_RLE, 'cel' => $cel, 'dos' => $dos); 6323 $cel = $next_level; 6324 $dos = 'N'; 6325 $sor = $eor; 6326 $eor = $cel % 2 ? 'R' : 'L'; 6327 } 6328 } elseif ($ta[$i] == K_LRE) { 6329 // X3. With each LRE, compute the least greater even embedding level. 6330 // a. If this new level would be valid, then this embedding code is valid. Remember (push) the current embedding level and override status. Reset the current level to this new level, and reset the override status to neutral. 6331 // b. If the new level would not be valid, then this code is invalid. Do not change the current level or override status. 6332 $next_level = $cel + 2 - ($cel % 2); 6333 if ( $next_level < 62 ) { 6334 $remember[] = array('num' => K_LRE, 'cel' => $cel, 'dos' => $dos); 6335 $cel = $next_level; 6336 $dos = 'N'; 6337 $sor = $eor; 6338 $eor = $cel % 2 ? 'R' : 'L'; 6339 } 6340 } elseif ($ta[$i] == K_RLO) { 6341 // X4. With each RLO, compute the least greater odd embedding level. 6342 // a. If this new level would be valid, then this embedding code is valid. Remember (push) the current embedding level and override status. Reset the current level to this new level, and reset the override status to right-to-left. 6343 // b. If the new level would not be valid, then this code is invalid. Do not change the current level or override status. 6344 $next_level = $cel + ($cel % 2) + 1; 6345 if ($next_level < 62) { 6346 $remember[] = array('num' => K_RLO, 'cel' => $cel, 'dos' => $dos); 6347 $cel = $next_level; 6348 $dos = 'R'; 6349 $sor = $eor; 6350 $eor = $cel % 2 ? 'R' : 'L'; 6351 } 6352 } elseif ($ta[$i] == K_LRO) { 6353 // X5. With each LRO, compute the least greater even embedding level. 6354 // a. If this new level would be valid, then this embedding code is valid. Remember (push) the current embedding level and override status. Reset the current level to this new level, and reset the override status to left-to-right. 6355 // b. If the new level would not be valid, then this code is invalid. Do not change the current level or override status. 6356 $next_level = $cel + 2 - ($cel % 2); 6357 if ( $next_level < 62 ) { 6358 $remember[] = array('num' => K_LRO, 'cel' => $cel, 'dos' => $dos); 6359 $cel = $next_level; 6360 $dos = 'L'; 6361 $sor = $eor; 6362 $eor = $cel % 2 ? 'R' : 'L'; 6363 } 6364 } elseif ($ta[$i] == K_PDF) { 6365 // X7. With each PDF, determine the matching embedding or override code. If there was a valid matching code, restore (pop) the last remembered (pushed) embedding level and directional override. 6366 if (count($remember)) { 6367 $last = count($remember ) - 1; 6368 if (($remember[$last]['num'] == K_RLE) OR 6369 ($remember[$last]['num'] == K_LRE) OR 6370 ($remember[$last]['num'] == K_RLO) OR 6371 ($remember[$last]['num'] == K_LRO)) { 6372 $match = array_pop($remember); 6373 $cel = $match['cel']; 6374 $dos = $match['dos']; 6375 $sor = $eor; 6376 $eor = ($cel > $match['cel'] ? $cel : $match['cel']) % 2 ? 'R' : 'L'; 6377 } 6378 } 6379 } elseif (($ta[$i] != K_RLE) AND 6380 ($ta[$i] != K_LRE) AND 6381 ($ta[$i] != K_RLO) AND 6382 ($ta[$i] != K_LRO) AND 6383 ($ta[$i] != K_PDF)) { 6384 // X6. For all types besides RLE, LRE, RLO, LRO, and PDF: 6385 // a. Set the level of the current character to the current embedding level. 6386 // b. Whenever the directional override status is not neutral, reset the current character type to the directional override status. 6387 if ($dos != 'N') { 6388 $chardir = $dos; 6389 } else { 6390 $chardir = $unicode[$ta[$i]]; 6391 } 6392 // stores string characters and other information 6393 $chardata[] = array('char' => $ta[$i], 'level' => $cel, 'type' => $chardir, 'sor' => $sor, 'eor' => $eor); 6394 } 6395 } // end for each char 6396 6397 // X8. All explicit directional embeddings and overrides are completely terminated at the end of each paragraph. Paragraph separators are not included in the embedding. 6398 // X9. Remove all RLE, LRE, RLO, LRO, PDF, and BN codes. 6399 // X10. The remaining rules are applied to each run of characters at the same level. For each run, determine the start-of-level-run (sor) and end-of-level-run (eor) type, either L or R. This depends on the higher of the two levels on either side of the boundary (at the start or end of the paragraph, the level of the �other� run is the base embedding level). If the higher level is odd, the type is R; otherwise, it is L. 6400 6401 // 3.3.3 Resolving Weak Types 6402 // Weak types are now resolved one level run at a time. At level run boundaries where the type of the character on the other side of the boundary is required, the type assigned to sor or eor is used. 6403 // Nonspacing marks are now resolved based on the previous characters. 6404 $numchars = count($chardata); 6405 6406 // W1. Examine each nonspacing mark (NSM) in the level run, and change the type of the NSM to the type of the previous character. If the NSM is at the start of the level run, it will get the type of sor. 6407 $prevlevel = -1; // track level changes 6408 $levcount = 0; // counts consecutive chars at the same level 6409 for ($i=0; $i < $numchars; $i++) { 6410 if ($chardata[$i]['type'] == 'NSM') { 6411 if ($levcount) { 6412 $chardata[$i]['type'] = $chardata[$i]['sor']; 6413 } elseif ($i > 0) { 6414 $chardata[$i]['type'] = $chardata[($i-1)]['type']; 6415 } 6416 } 6417 if ($chardata[$i]['level'] != $prevlevel) { 6418 $levcount = 0; 6419 } else { 6420 $levcount++; 6421 } 6422 $prevlevel = $chardata[$i]['level']; 6423 } 6424 6425 // W2. Search backward from each instance of a European number until the first strong type (R, L, AL, or sor) is found. If an AL is found, change the type of the European number to Arabic number. 6426 $prevlevel = -1; 6427 $levcount = 0; 6428 for ($i=0; $i < $numchars; $i++) { 6429 if ($chardata[$i]['char'] == 'EN') { 6430 for ($j=$levcount; $j >= 0; $j--) { 6431 if ($chardata[$j]['type'] == 'AL') { 6432 $chardata[$i]['type'] = 'AN'; 6433 } elseif (($chardata[$j]['type'] == 'L') OR ($chardata[$j]['type'] == 'R')) { 6434 break; 6435 } 6436 } 6437 } 6438 if ($chardata[$i]['level'] != $prevlevel) { 6439 $levcount = 0; 6440 } else { 6441 $levcount++; 6442 } 6443 $prevlevel = $chardata[$i]['level']; 6444 } 6445 6446 // W3. Change all ALs to R. 6447 for ($i=0; $i < $numchars; $i++) { 6448 if ($chardata[$i]['type'] == 'AL') { 6449 $chardata[$i]['type'] = 'R'; 6450 } 6451 } 6452 6453 // W4. A single European separator between two European numbers changes to a European number. A single common separator between two numbers of the same type changes to that type. 6454 $prevlevel = -1; 6455 $levcount = 0; 6456 for ($i=0; $i < $numchars; $i++) { 6457 if (($levcount > 0) AND (($i+1) < $numchars) AND ($chardata[($i+1)]['level'] == $prevlevel)) { 6458 if (($chardata[$i]['type'] == 'ES') AND ($chardata[($i-1)]['type'] == 'EN') AND ($chardata[($i+1)]['type'] == 'EN')) { 6459 $chardata[$i]['type'] = 'EN'; 6460 } elseif (($chardata[$i]['type'] == 'CS') AND ($chardata[($i-1)]['type'] == 'EN') AND ($chardata[($i+1)]['type'] == 'EN')) { 6461 $chardata[$i]['type'] = 'EN'; 6462 } elseif (($chardata[$i]['type'] == 'CS') AND ($chardata[($i-1)]['type'] == 'AN') AND ($chardata[($i+1)]['type'] == 'AN')) { 6463 $chardata[$i]['type'] = 'AN'; 6464 } 6465 } 6466 if ($chardata[$i]['level'] != $prevlevel) { 6467 $levcount = 0; 6468 } else { 6469 $levcount++; 6470 } 6471 $prevlevel = $chardata[$i]['level']; 6472 } 6473 6474 // W5. A sequence of European terminators adjacent to European numbers changes to all European numbers. 6475 $prevlevel = -1; 6476 $levcount = 0; 6477 for ($i=0; $i < $numchars; $i++) { 6478 if($chardata[$i]['type'] == 'ET') { 6479 if (($levcount > 0) AND ($chardata[($i-1)]['type'] == 'EN')) { 6480 $chardata[$i]['type'] = 'EN'; 6481 } else { 6482 $j = $i+1; 6483 while (($j < $numchars) AND ($chardata[$j]['level'] == $prevlevel)) { 6484 if ($chardata[$j]['type'] == 'EN') { 6485 $chardata[$i]['type'] = 'EN'; 6486 break; 6487 } elseif ($chardata[$j]['type'] != 'ET') { 6488 break; 6489 } 6490 $j++; 6491 } 6492 } 6493 } 6494 if ($chardata[$i]['level'] != $prevlevel) { 6495 $levcount = 0; 6496 } else { 6497 $levcount++; 6498 } 6499 $prevlevel = $chardata[$i]['level']; 6500 } 6501 6502 // W6. Otherwise, separators and terminators change to Other Neutral. 6503 $prevlevel = -1; 6504 $levcount = 0; 6505 for ($i=0; $i < $numchars; $i++) { 6506 if (($chardata[$i]['type'] == 'ET') OR ($chardata[$i]['type'] == 'ES') OR ($chardata[$i]['type'] == 'CS')) { 6507 $chardata[$i]['type'] = 'ON'; 6508 } 6509 if ($chardata[$i]['level'] != $prevlevel) { 6510 $levcount = 0; 6511 } else { 6512 $levcount++; 6513 } 6514 $prevlevel = $chardata[$i]['level']; 6515 } 6516 6517 //W7. Search backward from each instance of a European number until the first strong type (R, L, or sor) is found. If an L is found, then change the type of the European number to L. 6518 $prevlevel = -1; 6519 $levcount = 0; 6520 for ($i=0; $i < $numchars; $i++) { 6521 if ($chardata[$i]['char'] == 'EN') { 6522 for ($j=$levcount; $j >= 0; $j--) { 6523 if ($chardata[$j]['type'] == 'L') { 6524 $chardata[$i]['type'] = 'L'; 6525 } elseif ($chardata[$j]['type'] == 'R') { 6526 break; 6527 } 6528 } 6529 } 6530 if ($chardata[$i]['level'] != $prevlevel) { 6531 $levcount = 0; 6532 } else { 6533 $levcount++; 6534 } 6535 $prevlevel = $chardata[$i]['level']; 6536 } 6537 6538 // N1. A sequence of neutrals takes the direction of the surrounding strong text if the text on both sides has the same direction. European and Arabic numbers act as if they were R in terms of their influence on neutrals. Start-of-level-run (sor) and end-of-level-run (eor) are used at level run boundaries. 6539 $prevlevel = -1; 6540 $levcount = 0; 6541 for ($i=0; $i < $numchars; $i++) { 6542 if (($levcount > 0) AND (($i+1) < $numchars) AND ($chardata[($i+1)]['level'] == $prevlevel)) { 6543 if (($chardata[$i]['type'] == 'N') AND ($chardata[($i-1)]['type'] == 'L') AND ($chardata[($i+1)]['type'] == 'L')) { 6544 $chardata[$i]['type'] = 'L'; 6545 } elseif (($chardata[$i]['type'] == 'N') AND 6546 (($chardata[($i-1)]['type'] == 'R') OR ($chardata[($i-1)]['type'] == 'EN') OR ($chardata[($i-1)]['type'] == 'AN')) AND 6547 (($chardata[($i+1)]['type'] == 'R') OR ($chardata[($i+1)]['type'] == 'EN') OR ($chardata[($i+1)]['type'] == 'AN'))) { 6548 $chardata[$i]['type'] = 'R'; 6549 } elseif ($chardata[$i]['type'] == 'N') { 6550 // N2. Any remaining neutrals take the embedding direction 6551 $chardata[$i]['type'] = $chardata[$i]['sor']; 6552 } 6553 } elseif (($levcount == 0) AND (($i+1) < $numchars) AND ($chardata[($i+1)]['level'] == $prevlevel)) { 6554 // first char 6555 if (($chardata[$i]['type'] == 'N') AND ($chardata[$i]['sor'] == 'L') AND ($chardata[($i+1)]['type'] == 'L')) { 6556 $chardata[$i]['type'] = 'L'; 6557 } elseif (($chardata[$i]['type'] == 'N') AND 6558 (($chardata[$i]['sor'] == 'R') OR ($chardata[$i]['sor'] == 'EN') OR ($chardata[$i]['sor'] == 'AN')) AND 6559 (($chardata[($i+1)]['type'] == 'R') OR ($chardata[($i+1)]['type'] == 'EN') OR ($chardata[($i+1)]['type'] == 'AN'))) { 6560 $chardata[$i]['type'] = 'R'; 6561 } elseif ($chardata[$i]['type'] == 'N') { 6562 // N2. Any remaining neutrals take the embedding direction 6563 $chardata[$i]['type'] = $chardata[$i]['sor']; 6564 } 6565 } elseif (($levcount > 0) AND ((($i+1) == $numchars) OR (($i+1) < $numchars) AND ($chardata[($i+1)]['level'] != $prevlevel))) { 6566 //last char 6567 if (($chardata[$i]['type'] == 'N') AND ($chardata[($i-1)]['type'] == 'L') AND ($chardata[$i]['eor'] == 'L')) { 6568 $chardata[$i]['type'] = 'L'; 6569 } elseif (($chardata[$i]['type'] == 'N') AND 6570 (($chardata[($i-1)]['type'] == 'R') OR ($chardata[($i-1)]['type'] == 'EN') OR ($chardata[($i-1)]['type'] == 'AN')) AND 6571 (($chardata[$i]['eor'] == 'R') OR ($chardata[$i]['eor'] == 'EN') OR ($chardata[$i]['eor'] == 'AN'))) { 6572 $chardata[$i]['type'] = 'R'; 6573 } elseif ($chardata[$i]['type'] == 'N') { 6574 // N2. Any remaining neutrals take the embedding direction 6575 $chardata[$i]['type'] = $chardata[$i]['sor']; 6576 } 6577 } elseif ($chardata[$i]['type'] == 'N') { 6578 // N2. Any remaining neutrals take the embedding direction 6579 $chardata[$i]['type'] = $chardata[$i]['sor']; 6580 } 6581 if ($chardata[$i]['level'] != $prevlevel) { 6582 $levcount = 0; 6583 } else { 6584 $levcount++; 6585 } 6586 $prevlevel = $chardata[$i]['level']; 6587 } 6588 6589 // I1. For all characters with an even (left-to-right) embedding direction, those of type R go up one level and those of type AN or EN go up two levels. 6590 // I2. For all characters with an odd (right-to-left) embedding direction, those of type L, EN or AN go up one level. 6591 for ($i=0; $i < $numchars; $i++) { 6592 $odd = $chardata[$i]['level'] % 2; 6593 if ($odd) { 6594 if (($chardata[$i]['type'] == 'L') OR ($chardata[$i]['type'] == 'AN') OR ($chardata[$i]['type'] == 'EN')){ 6595 $chardata[$i]['level'] += 1; 6596 } 6597 } else { 6598 if ($chardata[$i]['type'] == 'R') { 6599 $chardata[$i]['level'] += 1; 6600 } elseif (($chardata[$i]['type'] == 'AN') OR ($chardata[$i]['type'] == 'EN')){ 6601 $chardata[$i]['level'] += 2; 6602 } 6603 } 6604 $maxlevel = max($chardata[$i]['level'],$maxlevel); 6605 } 6606 6607 // L1. On each line, reset the embedding level of the following characters to the paragraph embedding level: 6608 // 1. Segment separators, 6609 // 2. Paragraph separators, 6610 // 3. Any sequence of whitespace characters preceding a segment separator or paragraph separator, and 6611 // 4. Any sequence of white space characters at the end of the line. 6612 for ($i=0; $i < $numchars; $i++) { 6613 if (($chardata[$i]['type'] == 'B') OR ($chardata[$i]['type'] == 'S')) { 6614 $chardata[$i]['level'] = $pel; 6615 } elseif ($chardata[$i]['type'] == 'WS') { 6616 $j = $i+1; 6617 while ($j < $numchars) { 6618 if ((($chardata[$j]['type'] == 'B') OR ($chardata[$j]['type'] == 'S')) OR 6619 (($j == ($numchars-1)) AND ($chardata[$j]['type'] == 'WS'))) { 6620 $chardata[$i]['level'] = $pel;; 6621 break; 6622 } elseif ($chardata[$j]['type'] != 'WS') { 6623 break; 6624 } 6625 $j++; 6626 } 6627 } 6628 } 6629 6630 // Arabic Shaping 6631 // Cursively connected scripts, such as Arabic or Syriac, require the selection of positional character shapes that depend on adjacent characters. Shaping is logically applied after the Bidirectional Algorithm is used and is limited to characters within the same directional run. 6632 if ($arabic) { 6633 for ($i=0; $i < $numchars; $i++) { 6634 if ($unicode[$chardata[$i]['char']] == 'AL') { 6635 if (($i > 0) AND (($i+1) < $numchars) AND 6636 ($unicode[$chardata[($i-1)]['char']] == 'AL') AND 6637 ($unicode[$chardata[($i+1)]['char']] == 'AL') AND 6638 ($chardata[($i-1)]['type'] == $chardata[$i]['type']) AND 6639 ($chardata[($i+1)]['type'] == $chardata[$i]['type'])) { 6640 // medial 6641 if (isset($unicode_arlet[$chardata[$i]['char']][3])) { 6642 $chardata[$i]['char'] = $unicode_arlet[$chardata[$i]['char']][3]; 6643 } 6644 } elseif ((($i+1) < $numchars) AND 6645 ($unicode[$chardata[($i+1)]['char']] == 'AL') AND 6646 ($chardata[($i+1)]['type'] == $chardata[$i]['type'])) { 6647 // initial 6648 if (isset($unicode_arlet[$chardata[$i]['char']][2])) { 6649 $chardata[$i]['char'] = $unicode_arlet[$chardata[$i]['char']][2]; 6650 } 6651 } elseif (($i > 0) AND 6652 ($unicode[$chardata[($i-1)]['char']] == 'AL') AND 6653 ($chardata[($i-1)]['type'] == $chardata[$i]['type'])) { 6654 // final 6655 if (isset($unicode_arlet[$chardata[$i]['char']][1])) { 6656 $chardata[$i]['char'] = $unicode_arlet[$chardata[$i]['char']][1]; 6657 } 6658 } elseif (isset($unicode_arlet[$chardata[$i]['char']][0])) { 6659 // isolated 6660 $chardata[$i]['char'] = $unicode_arlet[$chardata[$i]['char']][0]; 6661 } 6662 } 6663 } 6664 } 6665 6666 // L2. From the highest level found in the text to the lowest odd level on each line, including intermediate levels not actually present in the text, reverse any contiguous sequence of characters that are at that level or higher. 6667 for ($j=$maxlevel; $j > 0; $j--) { 6668 $ordarray = Array(); 6669 $revarr = Array(); 6670 $onlevel = false; 6671 for ($i=0; $i < $numchars; $i++) { 6672 if ($chardata[$i]['level'] >= $j) { 6673 $onlevel = true; 6674 if (isset($unicode_mirror[$chardata[$i]['char']])) { 6675 // L4. A character is depicted by a mirrored glyph if and only if (a) the resolved directionality of that character is R, and (b) the Bidi_Mirrored property value of that character is true. 6676 $chardata[$i]['char'] = $unicode_mirror[$chardata[$i]['char']]; 6677 } 6678 $revarr[] = $chardata[$i]; 6679 } else { 6680 if($onlevel) { 6681 $revarr = array_reverse($revarr); 6682 $ordarray = array_merge($ordarray, $revarr); 6683 $revarr = Array(); 6684 $onlevel = false; 6685 } 6686 $ordarray[] = $chardata[$i]; 6687 } 6688 } 6689 if($onlevel) { 6690 $revarr = array_reverse($revarr); 6691 $ordarray = array_merge($ordarray, $revarr); 6692 } 6693 $chardata = $ordarray; 6694 } 6695 6696 $ordarray = array(); 6697 for ($i=0; $i < $numchars; $i++) { 6698 $ordarray[] = $chardata[$i]['char']; 6699 } 6700 6701 return $ordarray; 6702 } 6703 6704 // END OF BIDIRECTIONAL TEXT SECTION ------------------- 6705 6706 /* 6707 * Adds a bookmark. 6708 * @param string $txt bookmark description. 6709 * @param int $level bookmark level. 6710 * @param float $y Ordinate of the boorkmark position (default = -1 = current position). 6711 * @access public 6712 * @author Olivier Plathey, Nicola Asuni 6713 * @since 2.1.002 (2008-02-12) 6714 */ 6715 function Bookmark($txt, $level=0, $y=-1) { 6716 if($y == -1) { 6717 $y = $this->GetY(); 6718 } 6719 $this->outlines[]=array('t'=>$txt,'l'=>$level,'y'=>$y,'p'=>$this->PageNo()); 6720 } 6721 6722 /* 6723 * Create a bookmark PDF string. 6724 * @access private 6725 * @author Olivier Plathey, Nicola Asuni 6726 * @since 2.1.002 (2008-02-12) 6727 */ 6728 function _putbookmarks() { 6729 $nb = count($this->outlines); 6730 if($nb == 0) { 6731 return; 6732 } 6733 $lru = array(); 6734 $level = 0; 6735 foreach($this->outlines as $i=>$o) { 6736 if($o['l'] > 0) { 6737 $parent = $lru[$o['l'] - 1]; 6738 //Set parent and last pointers 6739 $this->outlines[$i]['parent'] = $parent; 6740 $this->outlines[$parent]['last'] = $i; 6741 if($o['l'] > $level) { 6742 //Level increasing: set first pointer 6743 $this->outlines[$parent]['first'] = $i; 6744 } 6745 } else { 6746 $this->outlines[$i]['parent']=$nb; 6747 } 6748 if($o['l']<=$level and $i>0) { 6749 //Set prev and next pointers 6750 $prev = $lru[$o['l']]; 6751 $this->outlines[$prev]['next'] = $i; 6752 $this->outlines[$i]['prev'] = $prev; 6753 } 6754 $lru[$o['l']] = $i; 6755 $level = $o['l']; 6756 } 6757 //Outline items 6758 $n = $this->n+1; 6759 foreach($this->outlines as $i=>$o) { 6760 $this->_newobj(); 6761 $this->_out('<</Title '.$this->_textstring($o['t'])); 6762 $this->_out('/Parent '.($n+$o['parent']).' 0 R'); 6763 if(isset($o['prev'])) 6764 $this->_out('/Prev '.($n+$o['prev']).' 0 R'); 6765 if(isset($o['next'])) 6766 $this->_out('/Next '.($n+$o['next']).' 0 R'); 6767 if(isset($o['first'])) 6768 $this->_out('/First '.($n+$o['first']).' 0 R'); 6769 if(isset($o['last'])) 6770 $this->_out('/Last '.($n+$o['last']).' 0 R'); 6771 $this->_out(sprintf('/Dest [%d 0 R /XYZ 0 %.2f null]',1+2*$o['p'],($this->h-$o['y'])*$this->k)); 6772 $this->_out('/Count 0>>'); 6773 $this->_out('endobj'); 6774 } 6775 //Outline root 6776 $this->_newobj(); 6777 $this->OutlineRoot=$this->n; 6778 $this->_out('<</Type /Outlines /First '.$n.' 0 R'); 6779 $this->_out('/Last '.($n+$lru[0]).' 0 R>>'); 6780 $this->_out('endobj'); 6781 } 6782 6783 6784 // --- JAVASCRIPT - FORMS ------------------------------ 6785 6786 /* 6787 * Adds a javascript 6788 * @access public 6789 * @author Johannes G�ntert, Nicola Asuni 6790 * @since 2.1.002 (2008-02-12) 6791 */ 6792 function IncludeJS($script) { 6793 $this->javascript .= $script; 6794 } 6795 6796 /* 6797 * Create a javascript PDF string. 6798 * @access private 6799 * @author Johannes G�ntert, Nicola Asuni 6800 * @since 2.1.002 (2008-02-12) 6801 */ 6802 function _putjavascript() { 6803 if (empty($this->javascript)) { 6804 return; 6805 } 6806 $this->_newobj(); 6807 $this->n_js = $this->n; 6808 $this->_out('<<'); 6809 $this->_out('/Names [(EmbeddedJS) '.($this->n+1).' 0 R ]'); 6810 $this->_out('>>'); 6811 $this->_out('endobj'); 6812 $this->_newobj(); 6813 $this->_out('<<'); 6814 $this->_out('/S /JavaScript'); 6815 $this->_out('/JS '.$this->_textstring($this->javascript)); 6816 $this->_out('>>'); 6817 $this->_out('endobj'); 6818 } 6819 6820 /* 6821 * Convert color to javascript color. 6822 * @param string $color color name or #RRGGBB 6823 * @access private 6824 * @author Denis Van Nuffelen, Nicola Asuni 6825 * @since 2.1.002 (2008-02-12) 6826 */ 6827 function _JScolor($color) { 6828 static $aColors = array('transparent','black','white','red','green','blue','cyan','magenta','yellow','dkGray','gray','ltGray'); 6829 if(substr($color,0,1) == '#') { 6830 return sprintf("['RGB',%.3f,%.3f,%.3f]", hexdec(substr($color,1,2))/255, hexdec(substr($color,3,2))/255, hexdec(substr($color,5,2))/255); 6831 } 6832 if(!in_array($color,$aColors)) { 6833 $this->Error('Invalid color: '.$color); 6834 } 6835 return 'color.'.$color; 6836 } 6837 6838 /* 6839 * Adds a javascript form field. 6840 * @param string $type field type 6841 * @param string $name field name 6842 * @param int $x horizontal position 6843 * @param int $y vertical position 6844 * @param int $w width 6845 * @param int $h height 6846 * @param array $prop array of properties. Possible values are (http://www.adobe.com/devnet/acrobat/pdfs/js_developer_guide.pdf): <ul><li>rect: Position and size of field on page.</li><li>borderStyle: Rectangle border appearance.</li><li>strokeColor: Color of bounding rectangle.</li><li>lineWidth: Width of the edge of the surrounding rectangle.</li><li>rotation: Rotation of field in 90-degree increments.</li><li>fillColor: Background color of field (gray, transparent, RGB, or CMYK).</li><li>userName: Short description of field that appears on mouse-over.</li><li>readonly: Whether the user may change the field contents.</li><li>doNotScroll: Whether text fields may scroll.</li><li>display: Whether visible or hidden on screen or in print.</li><li>textFont: Text font.</li><li>textColor: Text color.</li><li>textSize: Text size.</li><li>richText: Rich text.</li><li>richValue: Text.</li><li>comb: Text comb format.</li><li>multiline: Text multiline.</li><li>charLimit: Text limit to number of characters.</li><li>fileSelect: Text file selection format.</li><li>password: Text password format.</li><li>alignment: Text layout in text fields.</li><li>buttonAlignX: X alignment of icon on button face.</li><li>buttonAlignY: Y alignment of icon on button face.</li><li>buttonFitBounds: Relative scaling of an icon to fit inside a button face.</li><li>buttonScaleHow: Relative scaling of an icon to fit inside a button face.</li><li>buttonScaleWhen: Relative scaling of an icon to fit inside a button face.</li><li>highlight: Appearance of a button when pushed.</li><li>style: Glyph style for checkbox and radio buttons.</li><li>numItems: Number of items in a combo box or list box.</li><li>editable: Whether the user can type in a combo box.</li><li>multipleSelection: Whether multiple list box items may be selected.</li></ul> 6847 * @access private 6848 * @author Denis Van Nuffelen, Nicola Asuni 6849 * @since 2.1.002 (2008-02-12) 6850 */ 6851 function _addfield($type, $name, $x, $y, $w, $h, $prop) { 6852 $k = $this->k; 6853 $this->javascript .= sprintf("f=addField('%s','%s',%d,[%.2f,%.2f,%.2f,%.2f]);",$name,$type,$this->PageNo()-1,$x*$k,($this->h-$y)*$k+1,($x+$w)*$k,($this->h-$y-$h)*$k+1); 6854 $this->javascript .= 'f.textSize='.$this->FontSizePt.';'; 6855 while(list($key, $val) = each($prop)) { 6856 if (strcmp(substr($key,-5),"Color") == 0) { 6857 $val = $this->_JScolor($val); 6858 } else { 6859 $val = "'".$val."'"; 6860 } 6861 $this->javascript .= "f.".$key."=".$val.";"; 6862 } 6863 $this->x+=$w; 6864 } 6865 6866 /* 6867 * Creates a text field 6868 * @param string $name field name 6869 * @param int $w width 6870 * @param int $h height 6871 * @param string $prop properties. The value property allows to set the initial value. The multiline property allows to define the field as multiline. Possible values are (http://www.adobe.com/devnet/acrobat/pdfs/js_developer_guide.pdf): <ul><li>rect: Position and size of field on page.</li><li>borderStyle: Rectangle border appearance.</li><li>strokeColor: Color of bounding rectangle.</li><li>lineWidth: Width of the edge of the surrounding rectangle.</li><li>rotation: Rotation of field in 90-degree increments.</li><li>fillColor: Background color of field (gray, transparent, RGB, or CMYK).</li><li>userName: Short description of field that appears on mouse-over.</li><li>readonly: Whether the user may change the field contents.</li><li>doNotScroll: Whether text fields may scroll.</li><li>display: Whether visible or hidden on screen or in print.</li><li>textFont: Text font.</li><li>textColor: Text color.</li><li>textSize: Text size.</li><li>richText: Rich text.</li><li>richValue: Text.</li><li>comb: Text comb format.</li><li>multiline: Text multiline.</li><li>charLimit: Text limit to number of characters.</li><li>fileSelect: Text file selection format.</li><li>password: Text password format.</li><li>alignment: Text layout in text fields.</li><li>buttonAlignX: X alignment of icon on button face.</li><li>buttonAlignY: Y alignment of icon on button face.</li><li>buttonFitBounds: Relative scaling of an icon to fit inside a button face.</li><li>buttonScaleHow: Relative scaling of an icon to fit inside a button face.</li><li>buttonScaleWhen: Relative scaling of an icon to fit inside a button face.</li><li>highlight: Appearance of a button when pushed.</li><li>style: Glyph style for checkbox and radio buttons.</li><li>numItems: Number of items in a combo box or list box.</li><li>editable: Whether the user can type in a combo box.</li><li>multipleSelection: Whether multiple list box items may be selected.</li></ul> 6872 * @access public 6873 * @author Denis Van Nuffelen, Nicola Asuni 6874 * @since 2.1.002 (2008-02-12) 6875 */ 6876 function TextField($name, $w, $h, $prop=array()) { 6877 $this->_addfield('text',$name,$this->x,$this->y,$w,$h,$prop); 6878 } 6879 6880 /* 6881 * Creates a RadioButton field 6882 * @param string $name field name 6883 * @param int $w width 6884 * @param string $prop properties. Possible values are (http://www.adobe.com/devnet/acrobat/pdfs/js_developer_guide.pdf): <ul><li>rect: Position and size of field on page.</li><li>borderStyle: Rectangle border appearance.</li><li>strokeColor: Color of bounding rectangle.</li><li>lineWidth: Width of the edge of the surrounding rectangle.</li><li>rotation: Rotation of field in 90-degree increments.</li><li>fillColor: Background color of field (gray, transparent, RGB, or CMYK).</li><li>userName: Short description of field that appears on mouse-over.</li><li>readonly: Whether the user may change the field contents.</li><li>doNotScroll: Whether text fields may scroll.</li><li>display: Whether visible or hidden on screen or in print.</li><li>textFont: Text font.</li><li>textColor: Text color.</li><li>textSize: Text size.</li><li>richText: Rich text.</li><li>richValue: Text.</li><li>comb: Text comb format.</li><li>multiline: Text multiline.</li><li>charLimit: Text limit to number of characters.</li><li>fileSelect: Text file selection format.</li><li>password: Text password format.</li><li>alignment: Text layout in text fields.</li><li>buttonAlignX: X alignment of icon on button face.</li><li>buttonAlignY: Y alignment of icon on button face.</li><li>buttonFitBounds: Relative scaling of an icon to fit inside a button face.</li><li>buttonScaleHow: Relative scaling of an icon to fit inside a button face.</li><li>buttonScaleWhen: Relative scaling of an icon to fit inside a button face.</li><li>highlight: Appearance of a button when pushed.</li><li>style: Glyph style for checkbox and radio buttons.</li><li>numItems: Number of items in a combo box or list box.</li><li>editable: Whether the user can type in a combo box.</li><li>multipleSelection: Whether multiple list box items may be selected.</li></ul> 6885 * @access public 6886 * @author Nicola Asuni 6887 * @since 2.2.003 (2008-03-03) 6888 */ 6889 function RadioButton($name, $w, $prop=array()) { 6890 if(!isset($prop['strokeColor'])) { 6891 $prop['strokeColor']='black'; 6892 } 6893 $this->_addfield('radiobutton',$name,$this->x,$this->y,$w,$w,$prop); 6894 } 6895 6896 /* 6897 * Creates a List-box field 6898 * @param string $name field name 6899 * @param int $w width 6900 * @param int $h height 6901 * @param array $values array containing the list of values. 6902 * @param string $prop properties. Possible values are (http://www.adobe.com/devnet/acrobat/pdfs/js_developer_guide.pdf): <ul><li>rect: Position and size of field on page.</li><li>borderStyle: Rectangle border appearance.</li><li>strokeColor: Color of bounding rectangle.</li><li>lineWidth: Width of the edge of the surrounding rectangle.</li><li>rotation: Rotation of field in 90-degree increments.</li><li>fillColor: Background color of field (gray, transparent, RGB, or CMYK).</li><li>userName: Short description of field that appears on mouse-over.</li><li>readonly: Whether the user may change the field contents.</li><li>doNotScroll: Whether text fields may scroll.</li><li>display: Whether visible or hidden on screen or in print.</li><li>textFont: Text font.</li><li>textColor: Text color.</li><li>textSize: Text size.</li><li>richText: Rich text.</li><li>richValue: Text.</li><li>comb: Text comb format.</li><li>multiline: Text multiline.</li><li>charLimit: Text limit to number of characters.</li><li>fileSelect: Text file selection format.</li><li>password: Text password format.</li><li>alignment: Text layout in text fields.</li><li>buttonAlignX: X alignment of icon on button face.</li><li>buttonAlignY: Y alignment of icon on button face.</li><li>buttonFitBounds: Relative scaling of an icon to fit inside a button face.</li><li>buttonScaleHow: Relative scaling of an icon to fit inside a button face.</li><li>buttonScaleWhen: Relative scaling of an icon to fit inside a button face.</li><li>highlight: Appearance of a button when pushed.</li><li>style: Glyph style for checkbox and radio buttons.</li><li>numItems: Number of items in a combo box or list box.</li><li>editable: Whether the user can type in a combo box.</li><li>multipleSelection: Whether multiple list box items may be selected.</li></ul> 6903 * @access public 6904 * @author Nicola Asuni 6905 * @since 2.2.003 (2008-03-03) 6906 */ 6907 function ListBox($name, $w, $h, $values, $prop=array()) { 6908 if(!isset($prop['strokeColor'])) { 6909 $prop['strokeColor']='ltGray'; 6910 } 6911 $this->_addfield('listbox',$name,$this->x,$this->y,$w,$h,$prop); 6912 $s = ''; 6913 foreach($values as $value) { 6914 $s .= "'".addslashes($value)."',"; 6915 } 6916 $this->javascript .= 'f.setItems(['.substr($s,0,-1).']);'; 6917 } 6918 6919 /* 6920 * Creates a Combo-box field 6921 * @param string $name field name 6922 * @param int $w width 6923 * @param int $h height 6924 * @param array $values array containing the list of values. 6925 * @param string $prop properties. Possible values are (http://www.adobe.com/devnet/acrobat/pdfs/js_developer_guide.pdf): <ul><li>rect: Position and size of field on page.</li><li>borderStyle: Rectangle border appearance.</li><li>strokeColor: Color of bounding rectangle.</li><li>lineWidth: Width of the edge of the surrounding rectangle.</li><li>rotation: Rotation of field in 90-degree increments.</li><li>fillColor: Background color of field (gray, transparent, RGB, or CMYK).</li><li>userName: Short description of field that appears on mouse-over.</li><li>readonly: Whether the user may change the field contents.</li><li>doNotScroll: Whether text fields may scroll.</li><li>display: Whether visible or hidden on screen or in print.</li><li>textFont: Text font.</li><li>textColor: Text color.</li><li>textSize: Text size.</li><li>richText: Rich text.</li><li>richValue: Text.</li><li>comb: Text comb format.</li><li>multiline: Text multiline.</li><li>charLimit: Text limit to number of characters.</li><li>fileSelect: Text file selection format.</li><li>password: Text password format.</li><li>alignment: Text layout in text fields.</li><li>buttonAlignX: X alignment of icon on button face.</li><li>buttonAlignY: Y alignment of icon on button face.</li><li>buttonFitBounds: Relative scaling of an icon to fit inside a button face.</li><li>buttonScaleHow: Relative scaling of an icon to fit inside a button face.</li><li>buttonScaleWhen: Relative scaling of an icon to fit inside a button face.</li><li>highlight: Appearance of a button when pushed.</li><li>style: Glyph style for checkbox and radio buttons.</li><li>numItems: Number of items in a combo box or list box.</li><li>editable: Whether the user can type in a combo box.</li><li>multipleSelection: Whether multiple list box items may be selected.</li></ul> 6926 * @access public 6927 * @author Denis Van Nuffelen, Nicola Asuni 6928 * @since 2.1.002 (2008-02-12) 6929 */ 6930 function ComboBox($name, $w, $h, $values, $prop=array()) { 6931 $this->_addfield('combobox',$name,$this->x,$this->y,$w,$h,$prop); 6932 $s = ''; 6933 foreach($values as $value) { 6934 $s .= "'".addslashes($value)."',"; 6935 } 6936 $this->javascript .= 'f.setItems(['.substr($s,0,-1).']);'; 6937 } 6938 6939 /* 6940 * Creates a CheckBox field 6941 * @param string $name field name 6942 * @param int $w width 6943 * @param boolean $checked define the initial state (default = false). 6944 * @param string $prop properties. Possible values are (http://www.adobe.com/devnet/acrobat/pdfs/js_developer_guide.pdf): <ul><li>rect: Position and size of field on page.</li><li>borderStyle: Rectangle border appearance.</li><li>strokeColor: Color of bounding rectangle.</li><li>lineWidth: Width of the edge of the surrounding rectangle.</li><li>rotation: Rotation of field in 90-degree increments.</li><li>fillColor: Background color of field (gray, transparent, RGB, or CMYK).</li><li>userName: Short description of field that appears on mouse-over.</li><li>readonly: Whether the user may change the field contents.</li><li>doNotScroll: Whether text fields may scroll.</li><li>display: Whether visible or hidden on screen or in print.</li><li>textFont: Text font.</li><li>textColor: Text color.</li><li>textSize: Text size.</li><li>richText: Rich text.</li><li>richValue: Text.</li><li>comb: Text comb format.</li><li>multiline: Text multiline.</li><li>charLimit: Text limit to number of characters.</li><li>fileSelect: Text file selection format.</li><li>password: Text password format.</li><li>alignment: Text layout in text fields.</li><li>buttonAlignX: X alignment of icon on button face.</li><li>buttonAlignY: Y alignment of icon on button face.</li><li>buttonFitBounds: Relative scaling of an icon to fit inside a button face.</li><li>buttonScaleHow: Relative scaling of an icon to fit inside a button face.</li><li>buttonScaleWhen: Relative scaling of an icon to fit inside a button face.</li><li>highlight: Appearance of a button when pushed.</li><li>style: Glyph style for checkbox and radio buttons.</li><li>numItems: Number of items in a combo box or list box.</li><li>editable: Whether the user can type in a combo box.</li><li>multipleSelection: Whether multiple list box items may be selected.</li></ul> 6945 * @access public 6946 * @author Denis Van Nuffelen, Nicola Asuni 6947 * @since 2.1.002 (2008-02-12) 6948 */ 6949 function CheckBox($name, $w, $checked=false, $prop=array()) { 6950 $prop['value'] = ($checked ? 'Yes' : 'Off'); 6951 if(!isset($prop['strokeColor'])) { 6952 $prop['strokeColor']='black'; 6953 } 6954 $this->_addfield('checkbox',$name,$this->x,$this->y,$w,$w,$prop); 6955 } 6956 6957 /* 6958 * Creates a button field 6959 * @param string $name field name 6960 * @param int $w width 6961 * @param int $h height 6962 * @param string $caption caption. 6963 * @param string $action action triggered by the button (JavaScript code). 6964 * @param string $prop properties. Possible values are (http://www.adobe.com/devnet/acrobat/pdfs/js_developer_guide.pdf): <ul><li>rect: Position and size of field on page.</li><li>borderStyle: Rectangle border appearance.</li><li>strokeColor: Color of bounding rectangle.</li><li>lineWidth: Width of the edge of the surrounding rectangle.</li><li>rotation: Rotation of field in 90-degree increments.</li><li>fillColor: Background color of field (gray, transparent, RGB, or CMYK).</li><li>userName: Short description of field that appears on mouse-over.</li><li>readonly: Whether the user may change the field contents.</li><li>doNotScroll: Whether text fields may scroll.</li><li>display: Whether visible or hidden on screen or in print.</li><li>textFont: Text font.</li><li>textColor: Text color.</li><li>textSize: Text size.</li><li>richText: Rich text.</li><li>richValue: Text.</li><li>comb: Text comb format.</li><li>multiline: Text multiline.</li><li>charLimit: Text limit to number of characters.</li><li>fileSelect: Text file selection format.</li><li>password: Text password format.</li><li>alignment: Text layout in text fields.</li><li>buttonAlignX: X alignment of icon on button face.</li><li>buttonAlignY: Y alignment of icon on button face.</li><li>buttonFitBounds: Relative scaling of an icon to fit inside a button face.</li><li>buttonScaleHow: Relative scaling of an icon to fit inside a button face.</li><li>buttonScaleWhen: Relative scaling of an icon to fit inside a button face.</li><li>highlight: Appearance of a button when pushed.</li><li>style: Glyph style for checkbox and radio buttons.</li><li>numItems: Number of items in a combo box or list box.</li><li>editable: Whether the user can type in a combo box.</li><li>multipleSelection: Whether multiple list box items may be selected.</li></ul> 6965 * @access public 6966 * @author Denis Van Nuffelen, Nicola Asuni 6967 * @since 2.1.002 (2008-02-12) 6968 */ 6969 function Button($name, $w, $h, $caption, $action, $prop=array()) { 6970 if(!isset($prop['strokeColor'])) { 6971 $prop['strokeColor']='black'; 6972 } 6973 if(!isset($prop['borderStyle'])) { 6974 $prop['borderStyle']='beveled'; 6975 } 6976 $this->_addfield('button',$name,$this->x,$this->y,$w,$h,$prop); 6977 $this->javascript .= "f.buttonSetCaption('".addslashes($caption)."');"; 6978 $this->javascript .= "f.setAction('MouseUp','".addslashes($action)."');"; 6979 $this->javascript .= "f.highlight='push';"; 6980 $this->javascript .= 'f.print=false;'; 6981 } 6982 6983 // END JAVASCRIPT - FORMS ------------------------------ 6984 6985 } // END OF TCPDF CLASS 6986 6987 //Handle special IE contype request 6988 if(isset($_SERVER['HTTP_USER_AGENT']) AND ($_SERVER['HTTP_USER_AGENT']=='contype')) { 6989 header('Content-Type: application/pdf'); 6990 exit; 6991 } 6992 6993 } 6994 //============================================================+ 6995 // END OF FILE 6996 //============================================================+ 6997 ?>
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated: Wed Mar 28 15:54:07 2012 | Cross-referenced by PHPXref 0.7.1 |