fpdf.php

Go to the documentation of this file.
00001 <?php
00002 /*******************************************************************************
00003 * FPDF                                                                         *
00004 *                                                                              *
00005 * Version: 1.6                                                                 *
00006 * Date:    2008-08-03                                                          *
00007 * Author:  Olivier PLATHEY                                                     *
00008 *******************************************************************************/
00009 
00010 define('FPDF_VERSION','1.6');
00011 
00012 class FPDF
00013 {
00014 var $page;               //current page number
00015 var $n;                  //current object number
00016 var $offsets;            //array of object offsets
00017 var $buffer;             //buffer holding in-memory PDF
00018 var $pages;              //array containing pages
00019 var $state;              //current document state
00020 var $compress;           //compression flag
00021 var $k;                  //scale factor (number of points in user unit)
00022 var $DefOrientation;     //default orientation
00023 var $CurOrientation;     //current orientation
00024 var $PageFormats;        //available page formats
00025 var $DefPageFormat;      //default page format
00026 var $CurPageFormat;      //current page format
00027 var $PageSizes;          //array storing non-default page sizes
00028 var $wPt,$hPt;           //dimensions of current page in points
00029 var $w,$h;               //dimensions of current page in user unit
00030 var $lMargin;            //left margin
00031 var $tMargin;            //top margin
00032 var $rMargin;            //right margin
00033 var $bMargin;            //page break margin
00034 var $cMargin;            //cell margin
00035 var $x,$y;               //current position in user unit
00036 var $lasth;              //height of last printed cell
00037 var $LineWidth;          //line width in user unit
00038 var $CoreFonts;          //array of standard font names
00039 var $fonts;              //array of used fonts
00040 var $FontFiles;          //array of font files
00041 var $diffs;              //array of encoding differences
00042 var $FontFamily;         //current font family
00043 var $FontStyle;          //current font style
00044 var $underline;          //underlining flag
00045 var $CurrentFont;        //current font info
00046 var $FontSizePt;         //current font size in points
00047 var $FontSize;           //current font size in user unit
00048 var $DrawColor;          //commands for drawing color
00049 var $FillColor;          //commands for filling color
00050 var $TextColor;          //commands for text color
00051 var $ColorFlag;          //indicates whether fill and text colors are different
00052 var $ws;                 //word spacing
00053 var $images;             //array of used images
00054 var $PageLinks;          //array of links in pages
00055 var $links;              //array of internal links
00056 var $AutoPageBreak;      //automatic page breaking
00057 var $PageBreakTrigger;   //threshold used to trigger page breaks
00058 var $InHeader;           //flag set when processing header
00059 var $InFooter;           //flag set when processing footer
00060 var $ZoomMode;           //zoom display mode
00061 var $LayoutMode;         //layout display mode
00062 var $title;              //title
00063 var $subject;            //subject
00064 var $author;             //author
00065 var $keywords;           //keywords
00066 var $creator;            //creator
00067 var $AliasNbPages;       //alias for total number of pages
00068 var $PDFVersion;         //PDF version number
00069 
00070 /*******************************************************************************
00071 *                                                                              *
00072 *                               Public methods                                 *
00073 *                                                                              *
00074 *******************************************************************************/
00075 function FPDF($orientation='P', $unit='mm', $format='A4')
00076 {
00077     //Some checks
00078     $this->_dochecks();
00079     //Initialization of properties
00080     $this->page=0;
00081     $this->n=2;
00082     $this->buffer='';
00083     $this->pages=array();
00084     $this->PageSizes=array();
00085     $this->state=0;
00086     $this->fonts=array();
00087     $this->FontFiles=array();
00088     $this->diffs=array();
00089     $this->images=array();
00090     $this->links=array();
00091     $this->InHeader=false;
00092     $this->InFooter=false;
00093     $this->lasth=0;
00094     $this->FontFamily='';
00095     $this->FontStyle='';
00096     $this->FontSizePt=12;
00097     $this->underline=false;
00098     $this->DrawColor='0 G';
00099     $this->FillColor='0 g';
00100     $this->TextColor='0 g';
00101     $this->ColorFlag=false;
00102     $this->ws=0;
00103     //Standard fonts
00104     $this->CoreFonts=array('courier'=>'Courier', 'courierB'=>'Courier-Bold', 'courierI'=>'Courier-Oblique', 'courierBI'=>'Courier-BoldOblique',
00105         'helvetica'=>'Helvetica', 'helveticaB'=>'Helvetica-Bold', 'helveticaI'=>'Helvetica-Oblique', 'helveticaBI'=>'Helvetica-BoldOblique',
00106         'times'=>'Times-Roman', 'timesB'=>'Times-Bold', 'timesI'=>'Times-Italic', 'timesBI'=>'Times-BoldItalic',
00107         'symbol'=>'Symbol', 'zapfdingbats'=>'ZapfDingbats');
00108     //Scale factor
00109     if($unit=='pt')
00110         $this->k=1;
00111     elseif($unit=='mm')
00112         $this->k=72/25.4;
00113     elseif($unit=='cm')
00114         $this->k=72/2.54;
00115     elseif($unit=='in')
00116         $this->k=72;
00117     else
00118         $this->Error('Incorrect unit: '.$unit);
00119     //Page format
00120     $this->PageFormats=array('a3'=>array(841.89,1190.55), 'a4'=>array(595.28,841.89), 'a5'=>array(420.94,595.28),
00121         'letter'=>array(612,792), 'legal'=>array(612,1008));
00122     if(is_string($format))
00123         $format=$this->_getpageformat($format);
00124     $this->DefPageFormat=$format;
00125     $this->CurPageFormat=$format;
00126     //Page orientation
00127     $orientation=strtolower($orientation);
00128     if($orientation=='p' || $orientation=='portrait')
00129     {
00130         $this->DefOrientation='P';
00131         $this->w=$this->DefPageFormat[0];
00132         $this->h=$this->DefPageFormat[1];
00133     }
00134     elseif($orientation=='l' || $orientation=='landscape')
00135     {
00136         $this->DefOrientation='L';
00137         $this->w=$this->DefPageFormat[1];
00138         $this->h=$this->DefPageFormat[0];
00139     }
00140     else
00141         $this->Error('Incorrect orientation: '.$orientation);
00142     $this->CurOrientation=$this->DefOrientation;
00143     $this->wPt=$this->w*$this->k;
00144     $this->hPt=$this->h*$this->k;
00145     //Page margins (1 cm)
00146     $margin=28.35/$this->k;
00147     $this->SetMargins($margin,$margin);
00148     //Interior cell margin (1 mm)
00149     $this->cMargin=$margin/10;
00150     //Line width (0.2 mm)
00151     $this->LineWidth=.567/$this->k;
00152     //Automatic page break
00153     $this->SetAutoPageBreak(true,2*$margin);
00154     //Full width display mode
00155     $this->SetDisplayMode('fullwidth');
00156     //Enable compression
00157     $this->SetCompression(true);
00158     //Set default PDF version number
00159     $this->PDFVersion='1.3';
00160 }
00161 
00162 function SetMargins($left, $top, $right=null)
00163 {
00164     //Set left, top and right margins
00165     $this->lMargin=$left;
00166     $this->tMargin=$top;
00167     if($right===null)
00168         $right=$left;
00169     $this->rMargin=$right;
00170 }
00171 
00172 function SetLeftMargin($margin)
00173 {
00174     //Set left margin
00175     $this->lMargin=$margin;
00176     if($this->page>0 && $this->x<$margin)
00177         $this->x=$margin;
00178 }
00179 
00180 function SetTopMargin($margin)
00181 {
00182     //Set top margin
00183     $this->tMargin=$margin;
00184 }
00185 
00186 function SetRightMargin($margin)
00187 {
00188     //Set right margin
00189     $this->rMargin=$margin;
00190 }
00191 
00192 function SetAutoPageBreak($auto, $margin=0)
00193 {
00194     //Set auto page break mode and triggering margin
00195     $this->AutoPageBreak=$auto;
00196     $this->bMargin=$margin;
00197     $this->PageBreakTrigger=$this->h-$margin;
00198 }
00199 
00200 function SetDisplayMode($zoom, $layout='continuous')
00201 {
00202     //Set display mode in viewer
00203     if($zoom=='fullpage' || $zoom=='fullwidth' || $zoom=='real' || $zoom=='default' || !is_string($zoom))
00204         $this->ZoomMode=$zoom;
00205     else
00206         $this->Error('Incorrect zoom display mode: '.$zoom);
00207     if($layout=='single' || $layout=='continuous' || $layout=='two' || $layout=='default')
00208         $this->LayoutMode=$layout;
00209     else
00210         $this->Error('Incorrect layout display mode: '.$layout);
00211 }
00212 
00213 function SetCompression($compress)
00214 {
00215     //Set page compression
00216     if(function_exists('gzcompress'))
00217         $this->compress=$compress;
00218     else
00219         $this->compress=false;
00220 }
00221 
00222 function SetTitle($title, $isUTF8=false)
00223 {
00224     //Title of document
00225     if($isUTF8)
00226         $title=$this->_UTF8toUTF16($title);
00227     $this->title=$title;
00228 }
00229 
00230 function SetSubject($subject, $isUTF8=false)
00231 {
00232     //Subject of document
00233     if($isUTF8)
00234         $subject=$this->_UTF8toUTF16($subject);
00235     $this->subject=$subject;
00236 }
00237 
00238 function SetAuthor($author, $isUTF8=false)
00239 {
00240     //Author of document
00241     if($isUTF8)
00242         $author=$this->_UTF8toUTF16($author);
00243     $this->author=$author;
00244 }
00245 
00246 function SetKeywords($keywords, $isUTF8=false)
00247 {
00248     //Keywords of document
00249     if($isUTF8)
00250         $keywords=$this->_UTF8toUTF16($keywords);
00251     $this->keywords=$keywords;
00252 }
00253 
00254 function SetCreator($creator, $isUTF8=false)
00255 {
00256     //Creator of document
00257     if($isUTF8)
00258         $creator=$this->_UTF8toUTF16($creator);
00259     $this->creator=$creator;
00260 }
00261 
00262 function AliasNbPages($alias='{nb}')
00263 {
00264     //Define an alias for total number of pages
00265     $this->AliasNbPages=$alias;
00266 }
00267 
00268 function Error($msg)
00269 {
00270     //Fatal error
00271     die('<b>FPDF error:</b> '.$msg);
00272 }
00273 
00274 function Open()
00275 {
00276     //Begin document
00277     $this->state=1;
00278 }
00279 
00280 function Close()
00281 {
00282     //Terminate document
00283     if($this->state==3)
00284         return;
00285     if($this->page==0)
00286         $this->AddPage();
00287     //Page footer
00288     $this->InFooter=true;
00289     $this->Footer();
00290     $this->InFooter=false;
00291     //Close page
00292     $this->_endpage();
00293     //Close document
00294     $this->_enddoc();
00295 }
00296 
00297 function AddPage($orientation='', $format='')
00298 {
00299     //Start a new page
00300     if($this->state==0)
00301         $this->Open();
00302     $family=$this->FontFamily;
00303     $style=$this->FontStyle.($this->underline ? 'U' : '');
00304     $size=$this->FontSizePt;
00305     $lw=$this->LineWidth;
00306     $dc=$this->DrawColor;
00307     $fc=$this->FillColor;
00308     $tc=$this->TextColor;
00309     $cf=$this->ColorFlag;
00310     if($this->page>0)
00311     {
00312         //Page footer
00313         $this->InFooter=true;
00314         $this->Footer();
00315         $this->InFooter=false;
00316         //Close page
00317         $this->_endpage();
00318     }
00319     //Start new page
00320     $this->_beginpage($orientation,$format);
00321     //Set line cap style to square
00322     $this->_out('2 J');
00323     //Set line width
00324     $this->LineWidth=$lw;
00325     $this->_out(sprintf('%.2F w',$lw*$this->k));
00326     //Set font
00327     if($family)
00328         $this->SetFont($family,$style,$size);
00329     //Set colors
00330     $this->DrawColor=$dc;
00331     if($dc!='0 G')
00332         $this->_out($dc);
00333     $this->FillColor=$fc;
00334     if($fc!='0 g')
00335         $this->_out($fc);
00336     $this->TextColor=$tc;
00337     $this->ColorFlag=$cf;
00338     //Page header
00339     $this->InHeader=true;
00340     $this->Header();
00341     $this->InHeader=false;
00342     //Restore line width
00343     if($this->LineWidth!=$lw)
00344     {
00345         $this->LineWidth=$lw;
00346         $this->_out(sprintf('%.2F w',$lw*$this->k));
00347     }
00348     //Restore font
00349     if($family)
00350         $this->SetFont($family,$style,$size);
00351     //Restore colors
00352     if($this->DrawColor!=$dc)
00353     {
00354         $this->DrawColor=$dc;
00355         $this->_out($dc);
00356     }
00357     if($this->FillColor!=$fc)
00358     {
00359         $this->FillColor=$fc;
00360         $this->_out($fc);
00361     }
00362     $this->TextColor=$tc;
00363     $this->ColorFlag=$cf;
00364 }
00365 
00366 function Header()
00367 {
00368     //To be implemented in your own inherited class
00369 }
00370 
00371 function Footer()
00372 {
00373     //To be implemented in your own inherited class
00374 }
00375 
00376 function PageNo()
00377 {
00378     //Get current page number
00379     return $this->page;
00380 }
00381 
00382 function SetDrawColor($r, $g=null, $b=null)
00383 {
00384     //Set color for all stroking operations
00385     if(($r==0 && $g==0 && $b==0) || $g===null)
00386         $this->DrawColor=sprintf('%.3F G',$r/255);
00387     else
00388         $this->DrawColor=sprintf('%.3F %.3F %.3F RG',$r/255,$g/255,$b/255);
00389     if($this->page>0)
00390         $this->_out($this->DrawColor);
00391 }
00392 
00393 function SetFillColor($r, $g=null, $b=null)
00394 {
00395     //Set color for all filling operations
00396     if(($r==0 && $g==0 && $b==0) || $g===null)
00397         $this->FillColor=sprintf('%.3F g',$r/255);
00398     else
00399         $this->FillColor=sprintf('%.3F %.3F %.3F rg',$r/255,$g/255,$b/255);
00400     $this->ColorFlag=($this->FillColor!=$this->TextColor);
00401     if($this->page>0)
00402         $this->_out($this->FillColor);
00403 }
00404 
00405 function SetTextColor($r, $g=null, $b=null)
00406 {
00407     //Set color for text
00408     if(($r==0 && $g==0 && $b==0) || $g===null)
00409         $this->TextColor=sprintf('%.3F g',$r/255);
00410     else
00411         $this->TextColor=sprintf('%.3F %.3F %.3F rg',$r/255,$g/255,$b/255);
00412     $this->ColorFlag=($this->FillColor!=$this->TextColor);
00413 }
00414 
00415 function GetStringWidth($s)
00416 {
00417     //Get width of a string in the current font
00418     $s=(string)$s;
00419     $cw=&$this->CurrentFont['cw'];
00420     $w=0;
00421     $l=strlen($s);
00422     for($i=0;$i<$l;$i++)
00423         $w+=$cw[$s[$i]];
00424     return $w*$this->FontSize/1000;
00425 }
00426 
00427 function SetLineWidth($width)
00428 {
00429     //Set line width
00430     $this->LineWidth=$width;
00431     if($this->page>0)
00432         $this->_out(sprintf('%.2F w',$width*$this->k));
00433 }
00434 
00435 function Line($x1, $y1, $x2, $y2)
00436 {
00437     //Draw a line
00438     $this->_out(sprintf('%.2F %.2F m %.2F %.2F l S',$x1*$this->k,($this->h-$y1)*$this->k,$x2*$this->k,($this->h-$y2)*$this->k));
00439 }
00440 
00441 function Rect($x, $y, $w, $h, $style='')
00442 {
00443     //Draw a rectangle
00444     if($style=='F')
00445         $op='f';
00446     elseif($style=='FD' || $style=='DF')
00447         $op='B';
00448     else
00449         $op='S';
00450     $this->_out(sprintf('%.2F %.2F %.2F %.2F re %s',$x*$this->k,($this->h-$y)*$this->k,$w*$this->k,-$h*$this->k,$op));
00451 }
00452 
00453 function AddFont($family, $style='', $file='')
00454 {
00455     //Add a TrueType or Type1 font
00456     $family=strtolower($family);
00457     if($file=='')
00458         $file=str_replace(' ','',$family).strtolower($style).'.php';
00459     if($family=='arial')
00460         $family='helvetica';
00461     $style=strtoupper($style);
00462     if($style=='IB')
00463         $style='BI';
00464     $fontkey=$family.$style;
00465     if(isset($this->fonts[$fontkey]))
00466         return;
00467     include($this->_getfontpath().$file);
00468     if(!isset($name))
00469         $this->Error('Could not include font definition file');
00470     $i=count($this->fonts)+1;
00471     $this->fonts[$fontkey]=array('i'=>$i, 'type'=>$type, 'name'=>$name, 'desc'=>$desc, 'up'=>$up, 'ut'=>$ut, 'cw'=>$cw, 'enc'=>$enc, 'file'=>$file);
00472     if($diff)
00473     {
00474         //Search existing encodings
00475         $d=0;
00476         $nb=count($this->diffs);
00477         for($i=1;$i<=$nb;$i++)
00478         {
00479             if($this->diffs[$i]==$diff)
00480             {
00481                 $d=$i;
00482                 break;
00483             }
00484         }
00485         if($d==0)
00486         {
00487             $d=$nb+1;
00488             $this->diffs[$d]=$diff;
00489         }
00490         $this->fonts[$fontkey]['diff']=$d;
00491     }
00492     if($file)
00493     {
00494         if($type=='TrueType')
00495             $this->FontFiles[$file]=array('length1'=>$originalsize);
00496         else
00497             $this->FontFiles[$file]=array('length1'=>$size1, 'length2'=>$size2);
00498     }
00499 }
00500 
00501 function SetFont($family, $style='', $size=0)
00502 {
00503     //Select a font; size given in points
00504     global $fpdf_charwidths;
00505 
00506     $family=strtolower($family);
00507     if($family=='')
00508         $family=$this->FontFamily;
00509     if($family=='arial')
00510         $family='helvetica';
00511     elseif($family=='symbol' || $family=='zapfdingbats')
00512         $style='';
00513     $style=strtoupper($style);
00514     if(strpos($style,'U')!==false)
00515     {
00516         $this->underline=true;
00517         $style=str_replace('U','',$style);
00518     }
00519     else
00520         $this->underline=false;
00521     if($style=='IB')
00522         $style='BI';
00523     if($size==0)
00524         $size=$this->FontSizePt;
00525     //Test if font is already selected
00526     if($this->FontFamily==$family && $this->FontStyle==$style && $this->FontSizePt==$size)
00527         return;
00528     //Test if used for the first time
00529     $fontkey=$family.$style;
00530     if(!isset($this->fonts[$fontkey]))
00531     {
00532         //Check if one of the standard fonts
00533         if(isset($this->CoreFonts[$fontkey]))
00534         {
00535             if(!isset($fpdf_charwidths[$fontkey]))
00536             {
00537                 //Load metric file
00538                 $file=$family;
00539                 if($family=='times' || $family=='helvetica')
00540                     $file.=strtolower($style);
00541                 include($this->_getfontpath().$file.'.php');
00542                 if(!isset($fpdf_charwidths[$fontkey]))
00543                     $this->Error('Could not include font metric file');
00544             }
00545             $i=count($this->fonts)+1;
00546             $name=$this->CoreFonts[$fontkey];
00547             $cw=$fpdf_charwidths[$fontkey];
00548             $this->fonts[$fontkey]=array('i'=>$i, 'type'=>'core', 'name'=>$name, 'up'=>-100, 'ut'=>50, 'cw'=>$cw);
00549         }
00550         else
00551             $this->Error('Undefined font: '.$family.' '.$style);
00552     }
00553     //Select it
00554     $this->FontFamily=$family;
00555     $this->FontStyle=$style;
00556     $this->FontSizePt=$size;
00557     $this->FontSize=$size/$this->k;
00558     $this->CurrentFont=&$this->fonts[$fontkey];
00559     if($this->page>0)
00560         $this->_out(sprintf('BT /F%d %.2F Tf ET',$this->CurrentFont['i'],$this->FontSizePt));
00561 }
00562 
00563 function SetFontSize($size)
00564 {
00565     //Set font size in points
00566     if($this->FontSizePt==$size)
00567         return;
00568     $this->FontSizePt=$size;
00569     $this->FontSize=$size/$this->k;
00570     if($this->page>0)
00571         $this->_out(sprintf('BT /F%d %.2F Tf ET',$this->CurrentFont['i'],$this->FontSizePt));
00572 }
00573 
00574 function AddLink()
00575 {
00576     //Create a new internal link
00577     $n=count($this->links)+1;
00578     $this->links[$n]=array(0, 0);
00579     return $n;
00580 }
00581 
00582 function SetLink($link, $y=0, $page=-1)
00583 {
00584     //Set destination of internal link
00585     if($y==-1)
00586         $y=$this->y;
00587     if($page==-1)
00588         $page=$this->page;
00589     $this->links[$link]=array($page, $y);
00590 }
00591 
00592 function Link($x, $y, $w, $h, $link)
00593 {
00594     //Put a link on the page
00595     $this->PageLinks[$this->page][]=array($x*$this->k, $this->hPt-$y*$this->k, $w*$this->k, $h*$this->k, $link);
00596 }
00597 
00598 function Text($x, $y, $txt)
00599 {
00600     //Output a string
00601     $s=sprintf('BT %.2F %.2F Td (%s) Tj ET',$x*$this->k,($this->h-$y)*$this->k,$this->_escape($txt));
00602     if($this->underline && $txt!='')
00603         $s.=' '.$this->_dounderline($x,$y,$txt);
00604     if($this->ColorFlag)
00605         $s='q '.$this->TextColor.' '.$s.' Q';
00606     $this->_out($s);
00607 }
00608 
00609 function AcceptPageBreak()
00610 {
00611     //Accept automatic page break or not
00612     return $this->AutoPageBreak;
00613 }
00614 
00615 function Cell($w, $h=0, $txt='', $border=0, $ln=0, $align='', $fill=false, $link='')
00616 {
00617     //Output a cell
00618     $k=$this->k;
00619     if($this->y+$h>$this->PageBreakTrigger && !$this->InHeader && !$this->InFooter && $this->AcceptPageBreak())
00620     {
00621         //Automatic page break
00622         $x=$this->x;
00623         $ws=$this->ws;
00624         if($ws>0)
00625         {
00626             $this->ws=0;
00627             $this->_out('0 Tw');
00628         }
00629         $this->AddPage($this->CurOrientation,$this->CurPageFormat);
00630         $this->x=$x;
00631         if($ws>0)
00632         {
00633             $this->ws=$ws;
00634             $this->_out(sprintf('%.3F Tw',$ws*$k));
00635         }
00636     }
00637     if($w==0)
00638         $w=$this->w-$this->rMargin-$this->x;
00639     $s='';
00640     if($fill || $border==1)
00641     {
00642         if($fill)
00643             $op=($border==1) ? 'B' : 'f';
00644         else
00645             $op='S';
00646         $s=sprintf('%.2F %.2F %.2F %.2F re %s ',$this->x*$k,($this->h-$this->y)*$k,$w*$k,-$h*$k,$op);
00647     }
00648     if(is_string($border))
00649     {
00650         $x=$this->x;
00651         $y=$this->y;
00652         if(strpos($border,'L')!==false)
00653             $s.=sprintf('%.2F %.2F m %.2F %.2F l S ',$x*$k,($this->h-$y)*$k,$x*$k,($this->h-($y+$h))*$k);
00654         if(strpos($border,'T')!==false)
00655             $s.=sprintf('%.2F %.2F m %.2F %.2F l S ',$x*$k,($this->h-$y)*$k,($x+$w)*$k,($this->h-$y)*$k);
00656         if(strpos($border,'R')!==false)
00657             $s.=sprintf('%.2F %.2F m %.2F %.2F l S ',($x+$w)*$k,($this->h-$y)*$k,($x+$w)*$k,($this->h-($y+$h))*$k);
00658         if(strpos($border,'B')!==false)
00659             $s.=sprintf('%.2F %.2F m %.2F %.2F l S ',$x*$k,($this->h-($y+$h))*$k,($x+$w)*$k,($this->h-($y+$h))*$k);
00660     }
00661     if($txt!=='')
00662     {
00663         if($align=='R')
00664             $dx=$w-$this->cMargin-$this->GetStringWidth($txt);
00665         elseif($align=='C')
00666             $dx=($w-$this->GetStringWidth($txt))/2;
00667         else
00668             $dx=$this->cMargin;
00669         if($this->ColorFlag)
00670             $s.='q '.$this->TextColor.' ';
00671         $txt2=str_replace(')','\\)',str_replace('(','\\(',str_replace('\\','\\\\',$txt)));
00672         $s.=sprintf('BT %.2F %.2F Td (%s) Tj ET',($this->x+$dx)*$k,($this->h-($this->y+.5*$h+.3*$this->FontSize))*$k,$txt2);
00673         if($this->underline)
00674             $s.=' '.$this->_dounderline($this->x+$dx,$this->y+.5*$h+.3*$this->FontSize,$txt);
00675         if($this->ColorFlag)
00676             $s.=' Q';
00677         if($link)
00678             $this->Link($this->x+$dx,$this->y+.5*$h-.5*$this->FontSize,$this->GetStringWidth($txt),$this->FontSize,$link);
00679     }
00680     if($s)
00681         $this->_out($s);
00682     $this->lasth=$h;
00683     if($ln>0)
00684     {
00685         //Go to next line
00686         $this->y+=$h;
00687         if($ln==1)
00688             $this->x=$this->lMargin;
00689     }
00690     else
00691         $this->x+=$w;
00692 }
00693 
00694 function MultiCell($w, $h, $txt, $border=0, $align='J', $fill=false)
00695 {
00696     //Output text with automatic or explicit line breaks
00697     $cw=&$this->CurrentFont['cw'];
00698     if($w==0)
00699         $w=$this->w-$this->rMargin-$this->x;
00700     $wmax=($w-2*$this->cMargin)*1000/$this->FontSize;
00701     $s=str_replace("\r",'',$txt);
00702     $nb=strlen($s);
00703     if($nb>0 && $s[$nb-1]=="\n")
00704         $nb--;
00705     $b=0;
00706     if($border)
00707     {
00708         if($border==1)
00709         {
00710             $border='LTRB';
00711             $b='LRT';
00712             $b2='LR';
00713         }
00714         else
00715         {
00716             $b2='';
00717             if(strpos($border,'L')!==false)
00718                 $b2.='L';
00719             if(strpos($border,'R')!==false)
00720                 $b2.='R';
00721             $b=(strpos($border,'T')!==false) ? $b2.'T' : $b2;
00722         }
00723     }
00724     $sep=-1;
00725     $i=0;
00726     $j=0;
00727     $l=0;
00728     $ns=0;
00729     $nl=1;
00730     while($i<$nb)
00731     {
00732         //Get next character
00733         $c=$s[$i];
00734         if($c=="\n")
00735         {
00736             //Explicit line break
00737             if($this->ws>0)
00738             {
00739                 $this->ws=0;
00740                 $this->_out('0 Tw');
00741             }
00742             $this->Cell($w,$h,substr($s,$j,$i-$j),$b,2,$align,$fill);
00743             $i++;
00744             $sep=-1;
00745             $j=$i;
00746             $l=0;
00747             $ns=0;
00748             $nl++;
00749             if($border && $nl==2)
00750                 $b=$b2;
00751             continue;
00752         }
00753         if($c==' ')
00754         {
00755             $sep=$i;
00756             $ls=$l;
00757             $ns++;
00758         }
00759         $l+=$cw[$c];
00760         if($l>$wmax)
00761         {
00762             //Automatic line break
00763             if($sep==-1)
00764             {
00765                 if($i==$j)
00766                     $i++;
00767                 if($this->ws>0)
00768                 {
00769                     $this->ws=0;
00770                     $this->_out('0 Tw');
00771                 }
00772                 $this->Cell($w,$h,substr($s,$j,$i-$j),$b,2,$align,$fill);
00773             }
00774             else
00775             {
00776                 if($align=='J')
00777                 {
00778                     $this->ws=($ns>1) ? ($wmax-$ls)/1000*$this->FontSize/($ns-1) : 0;
00779                     $this->_out(sprintf('%.3F Tw',$this->ws*$this->k));
00780                 }
00781                 $this->Cell($w,$h,substr($s,$j,$sep-$j),$b,2,$align,$fill);
00782                 $i=$sep+1;
00783             }
00784             $sep=-1;
00785             $j=$i;
00786             $l=0;
00787             $ns=0;
00788             $nl++;
00789             if($border && $nl==2)
00790                 $b=$b2;
00791         }
00792         else
00793             $i++;
00794     }
00795     //Last chunk
00796     if($this->ws>0)
00797     {
00798         $this->ws=0;
00799         $this->_out('0 Tw');
00800     }
00801     if($border && strpos($border,'B')!==false)
00802         $b.='B';
00803     $this->Cell($w,$h,substr($s,$j,$i-$j),$b,2,$align,$fill);
00804     $this->x=$this->lMargin;
00805 }
00806 
00807 function Write($h, $txt, $link='')
00808 {
00809     //Output text in flowing mode
00810     $cw=&$this->CurrentFont['cw'];
00811     $w=$this->w-$this->rMargin-$this->x;
00812     $wmax=($w-2*$this->cMargin)*1000/$this->FontSize;
00813     $s=str_replace("\r",'',$txt);
00814     $nb=strlen($s);
00815     $sep=-1;
00816     $i=0;
00817     $j=0;
00818     $l=0;
00819     $nl=1;
00820     while($i<$nb)
00821     {
00822         //Get next character
00823         $c=$s[$i];
00824         if($c=="\n")
00825         {
00826             //Explicit line break
00827             $this->Cell($w,$h,substr($s,$j,$i-$j),0,2,'',0,$link);
00828             $i++;
00829             $sep=-1;
00830             $j=$i;
00831             $l=0;
00832             if($nl==1)
00833             {
00834                 $this->x=$this->lMargin;
00835                 $w=$this->w-$this->rMargin-$this->x;
00836                 $wmax=($w-2*$this->cMargin)*1000/$this->FontSize;
00837             }
00838             $nl++;
00839             continue;
00840         }
00841         if($c==' ')
00842             $sep=$i;
00843         $l+=$cw[$c];
00844         if($l>$wmax)
00845         {
00846             //Automatic line break
00847             if($sep==-1)
00848             {
00849                 if($this->x>$this->lMargin)
00850                 {
00851                     //Move to next line
00852                     $this->x=$this->lMargin;
00853                     $this->y+=$h;
00854                     $w=$this->w-$this->rMargin-$this->x;
00855                     $wmax=($w-2*$this->cMargin)*1000/$this->FontSize;
00856                     $i++;
00857                     $nl++;
00858                     continue;
00859                 }
00860                 if($i==$j)
00861                     $i++;
00862                 $this->Cell($w,$h,substr($s,$j,$i-$j),0,2,'',0,$link);
00863             }
00864             else
00865             {
00866                 $this->Cell($w,$h,substr($s,$j,$sep-$j),0,2,'',0,$link);
00867                 $i=$sep+1;
00868             }
00869             $sep=-1;
00870             $j=$i;
00871             $l=0;
00872             if($nl==1)
00873             {
00874                 $this->x=$this->lMargin;
00875                 $w=$this->w-$this->rMargin-$this->x;
00876                 $wmax=($w-2*$this->cMargin)*1000/$this->FontSize;
00877             }
00878             $nl++;
00879         }
00880         else
00881             $i++;
00882     }
00883     //Last chunk
00884     if($i!=$j)
00885         $this->Cell($l/1000*$this->FontSize,$h,substr($s,$j),0,0,'',0,$link);
00886 }
00887 
00888 function Ln($h=null)
00889 {
00890     //Line feed; default value is last cell height
00891     $this->x=$this->lMargin;
00892     if($h===null)
00893         $this->y+=$this->lasth;
00894     else
00895         $this->y+=$h;
00896 }
00897 
00898 function Image($file, $x=null, $y=null, $w=0, $h=0, $type='', $link='')
00899 {
00900     //Put an image on the page
00901     if(!isset($this->images[$file]))
00902     {
00903         //First use of this image, get info
00904         if($type=='')
00905         {
00906             $pos=strrpos($file,'.');
00907             if(!$pos)
00908                 $this->Error('Image file has no extension and no type was specified: '.$file);
00909             $type=substr($file,$pos+1);
00910         }
00911         $type=strtolower($type);
00912         if($type=='jpeg')
00913             $type='jpg';
00914         $mtd='_parse'.$type;
00915         if(!method_exists($this,$mtd))
00916             $this->Error('Unsupported image type: '.$type);
00917         $info=$this->$mtd($file);
00918         $info['i']=count($this->images)+1;
00919         $this->images[$file]=$info;
00920     }
00921     else
00922         $info=$this->images[$file];
00923     //Automatic width and height calculation if needed
00924     if($w==0 && $h==0)
00925     {
00926         //Put image at 72 dpi
00927         $w=$info['w']/$this->k;
00928         $h=$info['h']/$this->k;
00929     }
00930     elseif($w==0)
00931         $w=$h*$info['w']/$info['h'];
00932     elseif($h==0)
00933         $h=$w*$info['h']/$info['w'];
00934     //Flowing mode
00935     if($y===null)
00936     {
00937         if($this->y+$h>$this->PageBreakTrigger && !$this->InHeader && !$this->InFooter && $this->AcceptPageBreak())
00938         {
00939             //Automatic page break
00940             $x2=$this->x;
00941             $this->AddPage($this->CurOrientation,$this->CurPageFormat);
00942             $this->x=$x2;
00943         }
00944         $y=$this->y;
00945         $this->y+=$h;
00946     }
00947     if($x===null)
00948         $x=$this->x;
00949     $this->_out(sprintf('q %.2F 0 0 %.2F %.2F %.2F cm /I%d Do Q',$w*$this->k,$h*$this->k,$x*$this->k,($this->h-($y+$h))*$this->k,$info['i']));
00950     if($link)
00951         $this->Link($x,$y,$w,$h,$link);
00952 }
00953 
00954 function GetX()
00955 {
00956     //Get x position
00957     return $this->x;
00958 }
00959 
00960 function SetX($x)
00961 {
00962     //Set x position
00963     if($x>=0)
00964         $this->x=$x;
00965     else
00966         $this->x=$this->w+$x;
00967 }
00968 
00969 function GetY()
00970 {
00971     //Get y position
00972     return $this->y;
00973 }
00974 
00975 function SetY($y)
00976 {
00977     //Set y position and reset x
00978     $this->x=$this->lMargin;
00979     if($y>=0)
00980         $this->y=$y;
00981     else
00982         $this->y=$this->h+$y;
00983 }
00984 
00985 function SetXY($x, $y)
00986 {
00987     //Set x and y positions
00988     $this->SetY($y);
00989     $this->SetX($x);
00990 }
00991 
00992 function Output($name='', $dest='')
00993 {
00994     //Output PDF to some destination
00995     if($this->state<3)
00996         $this->Close();
00997     $dest=strtoupper($dest);
00998     if($dest=='')
00999     {
01000         if($name=='')
01001         {
01002             $name='doc.pdf';
01003             $dest='I';
01004         }
01005         else
01006             $dest='F';
01007     }
01008     switch($dest)
01009     {
01010         case 'I':
01011             //Send to standard output
01012             if(ob_get_length())
01013                 $this->Error('Some data has already been output, can\'t send PDF file');
01014             if(php_sapi_name()!='cli')
01015             {
01016                 //We send to a browser
01017                 header('Content-Type: application/pdf');
01018                 if(headers_sent())
01019                     $this->Error('Some data has already been output, can\'t send PDF file');
01020                 header('Content-Length: '.strlen($this->buffer));
01021                 header('Content-Disposition: inline; filename="'.$name.'"');
01022                 header('Cache-Control: private, max-age=0, must-revalidate');
01023                 header('Pragma: public');
01024                 ini_set('zlib.output_compression','0');
01025             }
01026             echo $this->buffer;
01027             break;
01028         case 'D':
01029             //Download file
01030             if(ob_get_length())
01031                 $this->Error('Some data has already been output, can\'t send PDF file');
01032             header('Content-Type: application/x-download');
01033             if(headers_sent())
01034                 $this->Error('Some data has already been output, can\'t send PDF file');
01035             header('Content-Length: '.strlen($this->buffer));
01036             header('Content-Disposition: attachment; filename="'.$name.'"');
01037             header('Cache-Control: private, max-age=0, must-revalidate');
01038             header('Pragma: public');
01039             ini_set('zlib.output_compression','0');
01040             echo $this->buffer;
01041             break;
01042         case 'F':
01043             //Save to local file
01044             $f=fopen($name,'wb');
01045             if(!$f)
01046                 $this->Error('Unable to create output file: '.$name);
01047             fwrite($f,$this->buffer,strlen($this->buffer));
01048             fclose($f);
01049             break;
01050         case 'S':
01051             //Return as a string
01052             return $this->buffer;
01053         default:
01054             $this->Error('Incorrect output destination: '.$dest);
01055     }
01056     return '';
01057 }
01058 
01059 /*******************************************************************************
01060 *                                                                              *
01061 *                              Protected methods                               *
01062 *                                                                              *
01063 *******************************************************************************/
01064 function _dochecks()
01065 {
01066     //Check availability of %F
01067     if(sprintf('%.1F',1.0)!='1.0')
01068         $this->Error('This version of PHP is not supported');
01069     //Check mbstring overloading
01070     if(ini_get('mbstring.func_overload') & 2)
01071         $this->Error('mbstring overloading must be disabled');
01072     //Disable runtime magic quotes
01073     if(get_magic_quotes_runtime())
01074         @set_magic_quotes_runtime(0);
01075 }
01076 
01077 function _getpageformat($format)
01078 {
01079     $format=strtolower($format);
01080     if(!isset($this->PageFormats[$format]))
01081         $this->Error('Unknown page format: '.$format);
01082     $a=$this->PageFormats[$format];
01083     return array($a[0]/$this->k, $a[1]/$this->k);
01084 }
01085 
01086 function _getfontpath()
01087 {
01088     if(!defined('FPDF_FONTPATH') && is_dir(dirname(__FILE__).'/font'))
01089         define('FPDF_FONTPATH',dirname(__FILE__).'/font/');
01090     return defined('FPDF_FONTPATH') ? FPDF_FONTPATH : '';
01091 }
01092 
01093 function _beginpage($orientation, $format)
01094 {
01095     $this->page++;
01096     $this->pages[$this->page]='';
01097     $this->state=2;
01098     $this->x=$this->lMargin;
01099     $this->y=$this->tMargin;
01100     $this->FontFamily='';
01101     //Check page size
01102     if($orientation=='')
01103         $orientation=$this->DefOrientation;
01104     else
01105         $orientation=strtoupper($orientation[0]);
01106     if($format=='')
01107         $format=$this->DefPageFormat;
01108     else
01109     {
01110         if(is_string($format))
01111             $format=$this->_getpageformat($format);
01112     }
01113     if($orientation!=$this->CurOrientation || $format[0]!=$this->CurPageFormat[0] || $format[1]!=$this->CurPageFormat[1])
01114     {
01115         //New size
01116         if($orientation=='P')
01117         {
01118             $this->w=$format[0];
01119             $this->h=$format[1];
01120         }
01121         else
01122         {
01123             $this->w=$format[1];
01124             $this->h=$format[0];
01125         }
01126         $this->wPt=$this->w*$this->k;
01127         $this->hPt=$this->h*$this->k;
01128         $this->PageBreakTrigger=$this->h-$this->bMargin;
01129         $this->CurOrientation=$orientation;
01130         $this->CurPageFormat=$format;
01131     }
01132     if($orientation!=$this->DefOrientation || $format[0]!=$this->DefPageFormat[0] || $format[1]!=$this->DefPageFormat[1])
01133         $this->PageSizes[$this->page]=array($this->wPt, $this->hPt);
01134 }
01135 
01136 function _endpage()
01137 {
01138     $this->state=1;
01139 }
01140 
01141 function _escape($s)
01142 {
01143     //Escape special characters in strings
01144     $s=str_replace('\\','\\\\',$s);
01145     $s=str_replace('(','\\(',$s);
01146     $s=str_replace(')','\\)',$s);
01147     $s=str_replace("\r",'\\r',$s);
01148     return $s;
01149 }
01150 
01151 function _textstring($s)
01152 {
01153     //Format a text string
01154     return '('.$this->_escape($s).')';
01155 }
01156 
01157 function _UTF8toUTF16($s)
01158 {
01159     //Convert UTF-8 to UTF-16BE with BOM
01160     $res="\xFE\xFF";
01161     $nb=strlen($s);
01162     $i=0;
01163     while($i<$nb)
01164     {
01165         $c1=ord($s[$i++]);
01166         if($c1>=224)
01167         {
01168             //3-byte character
01169             $c2=ord($s[$i++]);
01170             $c3=ord($s[$i++]);
01171             $res.=chr((($c1 & 0x0F)<<4) + (($c2 & 0x3C)>>2));
01172             $res.=chr((($c2 & 0x03)<<6) + ($c3 & 0x3F));
01173         }
01174         elseif($c1>=192)
01175         {
01176             //2-byte character
01177             $c2=ord($s[$i++]);
01178             $res.=chr(($c1 & 0x1C)>>2);
01179             $res.=chr((($c1 & 0x03)<<6) + ($c2 & 0x3F));
01180         }
01181         else
01182         {
01183             //Single-byte character
01184             $res.="\0".chr($c1);
01185         }
01186     }
01187     return $res;
01188 }
01189 
01190 function _dounderline($x, $y, $txt)
01191 {
01192     //Underline text
01193     $up=$this->CurrentFont['up'];
01194     $ut=$this->CurrentFont['ut'];
01195     $w=$this->GetStringWidth($txt)+$this->ws*substr_count($txt,' ');
01196     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);
01197 }
01198 
01199 function _parsejpg($file)
01200 {
01201     //Extract info from a JPEG file
01202     $a=GetImageSize($file);
01203     if(!$a)
01204         $this->Error('Missing or incorrect image file: '.$file);
01205     if($a[2]!=2)
01206         $this->Error('Not a JPEG file: '.$file);
01207     if(!isset($a['channels']) || $a['channels']==3)
01208         $colspace='DeviceRGB';
01209     elseif($a['channels']==4)
01210         $colspace='DeviceCMYK';
01211     else
01212         $colspace='DeviceGray';
01213     $bpc=isset($a['bits']) ? $a['bits'] : 8;
01214     //Read whole file
01215     $f=fopen($file,'rb');
01216     $data='';
01217     while(!feof($f))
01218         $data.=fread($f,8192);
01219     fclose($f);
01220     return array('w'=>$a[0], 'h'=>$a[1], 'cs'=>$colspace, 'bpc'=>$bpc, 'f'=>'DCTDecode', 'data'=>$data);
01221 }
01222 
01223 function _parsepng($file)
01224 {
01225     //Extract info from a PNG file
01226     $f=fopen($file,'rb');
01227     if(!$f)
01228         $this->Error('Can\'t open image file: '.$file);
01229     //Check signature
01230     if($this->_readstream($f,8)!=chr(137).'PNG'.chr(13).chr(10).chr(26).chr(10))
01231         $this->Error('Not a PNG file: '.$file);
01232     //Read header chunk
01233     $this->_readstream($f,4);
01234     if($this->_readstream($f,4)!='IHDR')
01235         $this->Error('Incorrect PNG file: '.$file);
01236     $w=$this->_readint($f);
01237     $h=$this->_readint($f);
01238     $bpc=ord($this->_readstream($f,1));
01239     if($bpc>8)
01240         $this->Error('16-bit depth not supported: '.$file);
01241     $ct=ord($this->_readstream($f,1));
01242     if($ct==0)
01243         $colspace='DeviceGray';
01244     elseif($ct==2)
01245         $colspace='DeviceRGB';
01246     elseif($ct==3)
01247         $colspace='Indexed';
01248     else
01249         $this->Error('Alpha channel not supported: '.$file);
01250     if(ord($this->_readstream($f,1))!=0)
01251         $this->Error('Unknown compression method: '.$file);
01252     if(ord($this->_readstream($f,1))!=0)
01253         $this->Error('Unknown filter method: '.$file);
01254     if(ord($this->_readstream($f,1))!=0)
01255         $this->Error('Interlacing not supported: '.$file);
01256     $this->_readstream($f,4);
01257     $parms='/DecodeParms <</Predictor 15 /Colors '.($ct==2 ? 3 : 1).' /BitsPerComponent '.$bpc.' /Columns '.$w.'>>';
01258     //Scan chunks looking for palette, transparency and image data
01259     $pal='';
01260     $trns='';
01261     $data='';
01262     do
01263     {
01264         $n=$this->_readint($f);
01265         $type=$this->_readstream($f,4);
01266         if($type=='PLTE')
01267         {
01268             //Read palette
01269             $pal=$this->_readstream($f,$n);
01270             $this->_readstream($f,4);
01271         }
01272         elseif($type=='tRNS')
01273         {
01274             //Read transparency info
01275             $t=$this->_readstream($f,$n);
01276             if($ct==0)
01277                 $trns=array(ord(substr($t,1,1)));
01278             elseif($ct==2)
01279                 $trns=array(ord(substr($t,1,1)), ord(substr($t,3,1)), ord(substr($t,5,1)));
01280             else
01281             {
01282                 $pos=strpos($t,chr(0));
01283                 if($pos!==false)
01284                     $trns=array($pos);
01285             }
01286             $this->_readstream($f,4);
01287         }
01288         elseif($type=='IDAT')
01289         {
01290             //Read image data block
01291             $data.=$this->_readstream($f,$n);
01292             $this->_readstream($f,4);
01293         }
01294         elseif($type=='IEND')
01295             break;
01296         else
01297             $this->_readstream($f,$n+4);
01298     }
01299     while($n);
01300     if($colspace=='Indexed' && empty($pal))
01301         $this->Error('Missing palette in '.$file);
01302     fclose($f);
01303     return array('w'=>$w, 'h'=>$h, 'cs'=>$colspace, 'bpc'=>$bpc, 'f'=>'FlateDecode', 'parms'=>$parms, 'pal'=>$pal, 'trns'=>$trns, 'data'=>$data);
01304 }
01305 
01306 function _readstream($f, $n)
01307 {
01308     //Read n bytes from stream
01309     $res='';
01310     while($n>0 && !feof($f))
01311     {
01312         $s=fread($f,$n);
01313         if($s===false)
01314             $this->Error('Error while reading stream');
01315         $n-=strlen($s);
01316         $res.=$s;
01317     }
01318     if($n>0)
01319         $this->Error('Unexpected end of stream');
01320     return $res;
01321 }
01322 
01323 function _readint($f)
01324 {
01325     //Read a 4-byte integer from stream
01326     $a=unpack('Ni',$this->_readstream($f,4));
01327     return $a['i'];
01328 }
01329 
01330 function _parsegif($file)
01331 {
01332     //Extract info from a GIF file (via PNG conversion)
01333     if(!function_exists('imagepng'))
01334         $this->Error('GD extension is required for GIF support');
01335     if(!function_exists('imagecreatefromgif'))
01336         $this->Error('GD has no GIF read support');
01337     $im=imagecreatefromgif($file);
01338     if(!$im)
01339         $this->Error('Missing or incorrect image file: '.$file);
01340     imageinterlace($im,0);
01341     $tmp=tempnam('.','gif');
01342     if(!$tmp)
01343         $this->Error('Unable to create a temporary file');
01344     if(!imagepng($im,$tmp))
01345         $this->Error('Error while saving to temporary file');
01346     imagedestroy($im);
01347     $info=$this->_parsepng($tmp);
01348     unlink($tmp);
01349     return $info;
01350 }
01351 
01352 function _newobj()
01353 {
01354     //Begin a new object
01355     $this->n++;
01356     $this->offsets[$this->n]=strlen($this->buffer);
01357     $this->_out($this->n.' 0 obj');
01358 }
01359 
01360 function _putstream($s)
01361 {
01362     $this->_out('stream');
01363     $this->_out($s);
01364     $this->_out('endstream');
01365 }
01366 
01367 function _out($s)
01368 {
01369     //Add a line to the document
01370     if($this->state==2)
01371         $this->pages[$this->page].=$s."\n";
01372     else
01373         $this->buffer.=$s."\n";
01374 }
01375 
01376 function _putpages()
01377 {
01378     $nb=$this->page;
01379     if(!empty($this->AliasNbPages))
01380     {
01381         //Replace number of pages
01382         for($n=1;$n<=$nb;$n++)
01383             $this->pages[$n]=str_replace($this->AliasNbPages,$nb,$this->pages[$n]);
01384     }
01385     if($this->DefOrientation=='P')
01386     {
01387         $wPt=$this->DefPageFormat[0]*$this->k;
01388         $hPt=$this->DefPageFormat[1]*$this->k;
01389     }
01390     else
01391     {
01392         $wPt=$this->DefPageFormat[1]*$this->k;
01393         $hPt=$this->DefPageFormat[0]*$this->k;
01394     }
01395     $filter=($this->compress) ? '/Filter /FlateDecode ' : '';
01396     for($n=1;$n<=$nb;$n++)
01397     {
01398         //Page
01399         $this->_newobj();
01400         $this->_out('<</Type /Page');
01401         $this->_out('/Parent 1 0 R');
01402         if(isset($this->PageSizes[$n]))
01403             $this->_out(sprintf('/MediaBox [0 0 %.2F %.2F]',$this->PageSizes[$n][0],$this->PageSizes[$n][1]));
01404         $this->_out('/Resources 2 0 R');
01405         if(isset($this->PageLinks[$n]))
01406         {
01407             //Links
01408             $annots='/Annots [';
01409             foreach($this->PageLinks[$n] as $pl)
01410             {
01411                 $rect=sprintf('%.2F %.2F %.2F %.2F',$pl[0],$pl[1],$pl[0]+$pl[2],$pl[1]-$pl[3]);
01412                 $annots.='<</Type /Annot /Subtype /Link /Rect ['.$rect.'] /Border [0 0 0] ';
01413                 if(is_string($pl[4]))
01414                     $annots.='/A <</S /URI /URI '.$this->_textstring($pl[4]).'>>>>';
01415                 else
01416                 {
01417                     $l=$this->links[$pl[4]];
01418                     $h=isset($this->PageSizes[$l[0]]) ? $this->PageSizes[$l[0]][1] : $hPt;
01419                     $annots.=sprintf('/Dest [%d 0 R /XYZ 0 %.2F null]>>',1+2*$l[0],$h-$l[1]*$this->k);
01420                 }
01421             }
01422             $this->_out($annots.']');
01423         }
01424         $this->_out('/Contents '.($this->n+1).' 0 R>>');
01425         $this->_out('endobj');
01426         //Page content
01427         $p=($this->compress) ? gzcompress($this->pages[$n]) : $this->pages[$n];
01428         $this->_newobj();
01429         $this->_out('<<'.$filter.'/Length '.strlen($p).'>>');
01430         $this->_putstream($p);
01431         $this->_out('endobj');
01432     }
01433     //Pages root
01434     $this->offsets[1]=strlen($this->buffer);
01435     $this->_out('1 0 obj');
01436     $this->_out('<</Type /Pages');
01437     $kids='/Kids [';
01438     for($i=0;$i<$nb;$i++)
01439         $kids.=(3+2*$i).' 0 R ';
01440     $this->_out($kids.']');
01441     $this->_out('/Count '.$nb);
01442     $this->_out(sprintf('/MediaBox [0 0 %.2F %.2F]',$wPt,$hPt));
01443     $this->_out('>>');
01444     $this->_out('endobj');
01445 }
01446 
01447 function _putfonts()
01448 {
01449     $nf=$this->n;
01450     foreach($this->diffs as $diff)
01451     {
01452         //Encodings
01453         $this->_newobj();
01454         $this->_out('<</Type /Encoding /BaseEncoding /WinAnsiEncoding /Differences ['.$diff.']>>');
01455         $this->_out('endobj');
01456     }
01457     foreach($this->FontFiles as $file=>$info)
01458     {
01459         //Font file embedding
01460         $this->_newobj();
01461         $this->FontFiles[$file]['n']=$this->n;
01462         $font='';
01463         $f=fopen($this->_getfontpath().$file,'rb',1);
01464         if(!$f)
01465             $this->Error('Font file not found');
01466         while(!feof($f))
01467             $font.=fread($f,8192);
01468         fclose($f);
01469         $compressed=(substr($file,-2)=='.z');
01470         if(!$compressed && isset($info['length2']))
01471         {
01472             $header=(ord($font[0])==128);
01473             if($header)
01474             {
01475                 //Strip first binary header
01476                 $font=substr($font,6);
01477             }
01478             if($header && ord($font[$info['length1']])==128)
01479             {
01480                 //Strip second binary header
01481                 $font=substr($font,0,$info['length1']).substr($font,$info['length1']+6);
01482             }
01483         }
01484         $this->_out('<</Length '.strlen($font));
01485         if($compressed)
01486             $this->_out('/Filter /FlateDecode');
01487         $this->_out('/Length1 '.$info['length1']);
01488         if(isset($info['length2']))
01489             $this->_out('/Length2 '.$info['length2'].' /Length3 0');
01490         $this->_out('>>');
01491         $this->_putstream($font);
01492         $this->_out('endobj');
01493     }
01494     foreach($this->fonts as $k=>$font)
01495     {
01496         //Font objects
01497         $this->fonts[$k]['n']=$this->n+1;
01498         $type=$font['type'];
01499         $name=$font['name'];
01500         if($type=='core')
01501         {
01502             //Standard font
01503             $this->_newobj();
01504             $this->_out('<</Type /Font');
01505             $this->_out('/BaseFont /'.$name);
01506             $this->_out('/Subtype /Type1');
01507             if($name!='Symbol' && $name!='ZapfDingbats')
01508                 $this->_out('/Encoding /WinAnsiEncoding');
01509             $this->_out('>>');
01510             $this->_out('endobj');
01511         }
01512         elseif($type=='Type1' || $type=='TrueType')
01513         {
01514             //Additional Type1 or TrueType font
01515             $this->_newobj();
01516             $this->_out('<</Type /Font');
01517             $this->_out('/BaseFont /'.$name);
01518             $this->_out('/Subtype /'.$type);
01519             $this->_out('/FirstChar 32 /LastChar 255');
01520             $this->_out('/Widths '.($this->n+1).' 0 R');
01521             $this->_out('/FontDescriptor '.($this->n+2).' 0 R');
01522             if($font['enc'])
01523             {
01524                 if(isset($font['diff']))
01525                     $this->_out('/Encoding '.($nf+$font['diff']).' 0 R');
01526                 else
01527                     $this->_out('/Encoding /WinAnsiEncoding');
01528             }
01529             $this->_out('>>');
01530             $this->_out('endobj');
01531             //Widths
01532             $this->_newobj();
01533             $cw=&$font['cw'];
01534             $s='[';
01535             for($i=32;$i<=255;$i++)
01536                 $s.=$cw[chr($i)].' ';
01537             $this->_out($s.']');
01538             $this->_out('endobj');
01539             //Descriptor
01540             $this->_newobj();
01541             $s='<</Type /FontDescriptor /FontName /'.$name;
01542             foreach($font['desc'] as $k=>$v)
01543                 $s.=' /'.$k.' '.$v;
01544             $file=$font['file'];
01545             if($file)
01546                 $s.=' /FontFile'.($type=='Type1' ? '' : '2').' '.$this->FontFiles[$file]['n'].' 0 R';
01547             $this->_out($s.'>>');
01548             $this->_out('endobj');
01549         }
01550         else
01551         {
01552             //Allow for additional types
01553             $mtd='_put'.strtolower($type);
01554             if(!method_exists($this,$mtd))
01555                 $this->Error('Unsupported font type: '.$type);
01556             $this->$mtd($font);
01557         }
01558     }
01559 }
01560 
01561 function _putimages()
01562 {
01563     $filter=($this->compress) ? '/Filter /FlateDecode ' : '';
01564     reset($this->images);
01565     while(list($file,$info)=each($this->images))
01566     {
01567         $this->_newobj();
01568         $this->images[$file]['n']=$this->n;
01569         $this->_out('<</Type /XObject');
01570         $this->_out('/Subtype /Image');
01571         $this->_out('/Width '.$info['w']);
01572         $this->_out('/Height '.$info['h']);
01573         if($info['cs']=='Indexed')
01574             $this->_out('/ColorSpace [/Indexed /DeviceRGB '.(strlen($info['pal'])/3-1).' '.($this->n+1).' 0 R]');
01575         else
01576         {
01577             $this->_out('/ColorSpace /'.$info['cs']);
01578             if($info['cs']=='DeviceCMYK')
01579                 $this->_out('/Decode [1 0 1 0 1 0 1 0]');
01580         }
01581         $this->_out('/BitsPerComponent '.$info['bpc']);
01582         if(isset($info['f']))
01583             $this->_out('/Filter /'.$info['f']);
01584         if(isset($info['parms']))
01585             $this->_out($info['parms']);
01586         if(isset($info['trns']) && is_array($info['trns']))
01587         {
01588             $trns='';
01589             for($i=0;$i<count($info['trns']);$i++)
01590                 $trns.=$info['trns'][$i].' '.$info['trns'][$i].' ';
01591             $this->_out('/Mask ['.$trns.']');
01592         }
01593         $this->_out('/Length '.strlen($info['data']).'>>');
01594         $this->_putstream($info['data']);
01595         unset($this->images[$file]['data']);
01596         $this->_out('endobj');
01597         //Palette
01598         if($info['cs']=='Indexed')
01599         {
01600             $this->_newobj();
01601             $pal=($this->compress) ? gzcompress($info['pal']) : $info['pal'];
01602             $this->_out('<<'.$filter.'/Length '.strlen($pal).'>>');
01603             $this->_putstream($pal);
01604             $this->_out('endobj');
01605         }
01606     }
01607 }
01608 
01609 function _putxobjectdict()
01610 {
01611     foreach($this->images as $image)
01612         $this->_out('/I'.$image['i'].' '.$image['n'].' 0 R');
01613 }
01614 
01615 function _putresourcedict()
01616 {
01617     $this->_out('/ProcSet [/PDF /Text /ImageB /ImageC /ImageI]');
01618     $this->_out('/Font <<');
01619     foreach($this->fonts as $font)
01620         $this->_out('/F'.$font['i'].' '.$font['n'].' 0 R');
01621     $this->_out('>>');
01622     $this->_out('/XObject <<');
01623     $this->_putxobjectdict();
01624     $this->_out('>>');
01625 }
01626 
01627 function _putresources()
01628 {
01629     $this->_putfonts();
01630     $this->_putimages();
01631     //Resource dictionary
01632     $this->offsets[2]=strlen($this->buffer);
01633     $this->_out('2 0 obj');
01634     $this->_out('<<');
01635     $this->_putresourcedict();
01636     $this->_out('>>');
01637     $this->_out('endobj');
01638 }
01639 
01640 function _putinfo()
01641 {
01642     $this->_out('/Producer '.$this->_textstring('FPDF '.FPDF_VERSION));
01643     if(!empty($this->title))
01644         $this->_out('/Title '.$this->_textstring($this->title));
01645     if(!empty($this->subject))
01646         $this->_out('/Subject '.$this->_textstring($this->subject));
01647     if(!empty($this->author))
01648         $this->_out('/Author '.$this->_textstring($this->author));
01649     if(!empty($this->keywords))
01650         $this->_out('/Keywords '.$this->_textstring($this->keywords));
01651     if(!empty($this->creator))
01652         $this->_out('/Creator '.$this->_textstring($this->creator));
01653     $this->_out('/CreationDate '.$this->_textstring('D:'.@date('YmdHis')));
01654 }
01655 
01656 function _putcatalog()
01657 {
01658     $this->_out('/Type /Catalog');
01659     $this->_out('/Pages 1 0 R');
01660     if($this->ZoomMode=='fullpage')
01661         $this->_out('/OpenAction [3 0 R /Fit]');
01662     elseif($this->ZoomMode=='fullwidth')
01663         $this->_out('/OpenAction [3 0 R /FitH null]');
01664     elseif($this->ZoomMode=='real')
01665         $this->_out('/OpenAction [3 0 R /XYZ null null 1]');
01666     elseif(!is_string($this->ZoomMode))
01667         $this->_out('/OpenAction [3 0 R /XYZ null null '.($this->ZoomMode/100).']');
01668     if($this->LayoutMode=='single')
01669         $this->_out('/PageLayout /SinglePage');
01670     elseif($this->LayoutMode=='continuous')
01671         $this->_out('/PageLayout /OneColumn');
01672     elseif($this->LayoutMode=='two')
01673         $this->_out('/PageLayout /TwoColumnLeft');
01674 }
01675 
01676 function _putheader()
01677 {
01678     $this->_out('%PDF-'.$this->PDFVersion);
01679 }
01680 
01681 function _puttrailer()
01682 {
01683     $this->_out('/Size '.($this->n+1));
01684     $this->_out('/Root '.$this->n.' 0 R');
01685     $this->_out('/Info '.($this->n-1).' 0 R');
01686 }
01687 
01688 function _enddoc()
01689 {
01690     $this->_putheader();
01691     $this->_putpages();
01692     $this->_putresources();
01693     //Info
01694     $this->_newobj();
01695     $this->_out('<<');
01696     $this->_putinfo();
01697     $this->_out('>>');
01698     $this->_out('endobj');
01699     //Catalog
01700     $this->_newobj();
01701     $this->_out('<<');
01702     $this->_putcatalog();
01703     $this->_out('>>');
01704     $this->_out('endobj');
01705     //Cross-ref
01706     $o=strlen($this->buffer);
01707     $this->_out('xref');
01708     $this->_out('0 '.($this->n+1));
01709     $this->_out('0000000000 65535 f ');
01710     for($i=1;$i<=$this->n;$i++)
01711         $this->_out(sprintf('%010d 00000 n ',$this->offsets[$i]));
01712     //Trailer
01713     $this->_out('trailer');
01714     $this->_out('<<');
01715     $this->_puttrailer();
01716     $this->_out('>>');
01717     $this->_out('startxref');
01718     $this->_out($o);
01719     $this->_out('%%EOF');
01720     $this->state=3;
01721 }
01722 //End of class
01723 }
01724 
01725 //Handle special IE contype request
01726 if(isset($_SERVER['HTTP_USER_AGENT']) && $_SERVER['HTTP_USER_AGENT']=='contype')
01727 {
01728     header('Content-Type: application/pdf');
01729     exit;
01730 }
01731 
01732 ?>
 All Data Structures Files Functions Variables Enumerations