Source for file fpdf.php
Documentation is available at fpdf.php
/*******************************************************************************
* Author: Olivier PLATHEY *
* You may use and modify this software as you wish. *
*******************************************************************************/
define('FPDF_VERSION','1.53');
var $page; //current page number
var $n; //current object number
var $buffer; //buffer holding in-memory PDF
var $pages; //array containing pages
var $state; //current document state
var $k; //scale factor (number of points in user unit)
var $fwPt,$fhPt; //dimensions of page format in points
var $fw,$fh; //dimensions of page format in user unit
var $wPt,$hPt; //current dimensions of page in points
var $w,$h; //current dimensions of page in user unit
var $x,$y; //current position in user unit for cell positioning
var $lasth; //height of last cell printed
var $fonts; //array of used fonts
var $diffs; //array of encoding differences
var $images; //array of used images
var $links; //array of internal links
var $FontSize; //current font size in user unit
var $ColorFlag; //indicates whether fill and text colors are different
var $InFooter; //flag set when processing footer
/*******************************************************************************
*******************************************************************************/
function FPDF($orientation= 'P',$unit= 'mm',$format= 'A4')
//Initialization of properties
$this->CoreFonts= array('courier'=> 'Courier','courierB'=> 'Courier-Bold','courierI'=> 'Courier-Oblique','courierBI'=> 'Courier-BoldOblique',
'helvetica'=> 'Helvetica','helveticaB'=> 'Helvetica-Bold','helveticaI'=> 'Helvetica-Oblique','helveticaBI'=> 'Helvetica-BoldOblique',
'times'=> 'Times-Roman','timesB'=> 'Times-Bold','timesI'=> 'Times-Italic','timesBI'=> 'Times-BoldItalic',
'symbol'=> 'Symbol','zapfdingbats'=> 'ZapfDingbats');
$this->Error('Incorrect unit: '. $unit);
$format= array(841.89,1190.55);
$format= array(595.28,841.89);
$format= array(420.94,595.28);
elseif($format== 'letter')
$this->Error('Unknown page format: '. $format);
$this->fwPt= $format[0]* $this->k;
$this->fhPt= $format[1]* $this->k;
if($orientation== 'p' || $orientation== 'portrait')
elseif($orientation== 'l' || $orientation== 'landscape')
$this->Error('Incorrect orientation: '. $orientation);
$this->w= $this->wPt/ $this->k;
$this->h= $this->hPt/ $this->k;
//Interior cell margin (1 mm)
//Full width display mode
//Set default PDF version number
//Set left, top and right margins
if($this->page> 0 && $this->x< $margin)
//Set auto page break mode and triggering margin
//Set display mode in viewer
if($zoom== 'fullpage' || $zoom== 'fullwidth' || $zoom== 'real' || $zoom== 'default' || !is_string($zoom))
$this->Error('Incorrect zoom display mode: '. $zoom);
if($layout== 'single' || $layout== 'continuous' || $layout== 'two' || $layout== 'default')
$this->Error('Incorrect layout display mode: '. $layout);
//Define an alias for total number of pages
throw new Exception('FPDF error: ' . $msg);
//Set line cap style to square
$this->SetFont($family,$style,$size);
$this->SetFont($family,$style,$size);
//To be implemented in your own inherited class
//To be implemented in your own inherited class
//Get current page number
//Set color for all stroking operations
if(($r== 0 && $g== 0 && $b== 0) || $g==- 1)
//Set color for all filling operations
if(($r== 0 && $g== 0 && $b== 0) || $g==- 1)
if(($r== 0 && $g== 0 && $b== 0) || $g==- 1)
//Get width of a string in the current font
function Line($x1,$y1,$x2,$y2)
$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));
function Rect($x,$y,$w,$h,$style= '')
elseif($style== 'FD' || $style== 'DF')
$this->_out(sprintf('%.2f %.2f %.2f %.2f re %s',$x* $this->k,($this->h- $y)* $this->k,$w* $this->k,- $h* $this->k,$op));
function AddFont($family,$style= '',$file= '')
//Add a TrueType or Type1 font
if(isset ($this->fonts[$fontkey]))
$this->Error('Font already added: '. $family. ' '. $style);
$this->Error('Could not include font definition file');
$this->fonts[$fontkey]= array('i'=> $i,'type'=> $type,'name'=> $name,'desc'=> $desc,'up'=> $up,'ut'=> $ut,'cw'=> $cw,'enc'=> $enc,'file'=> $file);
//Search existing encodings
if($this->diffs[$i]== $diff)
$this->fonts[$fontkey]['diff']= $d;
$this->FontFiles[$file]= array('length1'=> $originalsize);
$this->FontFiles[$file]= array('length1'=> $size1,'length2'=> $size2);
function SetFont($family,$style= '',$size= 0)
//Select a font; size given in points
elseif($family== 'symbol' || $family== 'zapfdingbats')
if(strpos($style,'U')!== false)
//Test if font is already selected
//Test if used for the first time
if(!isset ($this->fonts[$fontkey]))
//Check if one of the standard fonts
if(!isset ($fpdf_charwidths[$fontkey]))
if($family== 'times' || $family== 'helvetica')
if(!isset ($fpdf_charwidths[$fontkey]))
$this->Error('Could not include font metric file');
$this->fonts[$fontkey]= array('i'=> $i,'type'=> 'core','name'=> $this->CoreFonts[$fontkey],'up'=>- 100,'ut'=> 50,'cw'=> $fpdf_charwidths[$fontkey]);
$this->Error('Undefined font: '. $family. ' '. $style);
//Set font size in points
//Create a new internal link
$this->links[$n]= array(0,0);
function SetLink($link,$y= 0,$page=- 1)
//Set destination of internal link
$this->links[$link]= array($page,$y);
function Link($x,$y,$w,$h,$link)
$this->PageLinks[$this->page][]= array($x* $this->k,$this->hPt- $y* $this->k,$w* $this->k,$h* $this->k,$link);
function Text($x,$y,$txt)
$s= sprintf('BT %.2f %.2f Td (%s) Tj ET',$x* $this->k,($this->h- $y)* $this->k,$this->_escape($txt));
//Accept automatic page break or not
function Cell($w,$h= 0,$txt= '',$border= 0,$ln= 0,$align= '',$fill= 0,$link= '')
if($fill== 1 || $border== 1)
$op= ($border== 1) ? 'B' : 'f';
$s= sprintf('%.2f %.2f %.2f %.2f re %s ',$this->x* $k,($this->h- $this->y)* $k,$w* $k,- $h* $k,$op);
if(strpos($border,'L')!== false)
$s.= sprintf('%.2f %.2f m %.2f %.2f l S ',$x* $k,($this->h- $y)* $k,$x* $k,($this->h- ($y+ $h))* $k);
if(strpos($border,'T')!== false)
$s.= sprintf('%.2f %.2f m %.2f %.2f l S ',$x* $k,($this->h- $y)* $k,($x+ $w)* $k,($this->h- $y)* $k);
if(strpos($border,'R')!== false)
$s.= sprintf('%.2f %.2f m %.2f %.2f l S ',($x+ $w)* $k,($this->h- $y)* $k,($x+ $w)* $k,($this->h- ($y+ $h))* $k);
if(strpos($border,'B')!== false)
$s.= sprintf('%.2f %.2f m %.2f %.2f l S ',$x* $k,($this->h- ($y+ $h))* $k,($x+ $w)* $k,($this->h- ($y+ $h))* $k);
$s.= sprintf('BT %.2f %.2f Td (%s) Tj ET',($this->x+ $dx)* $k,($this->h- ($this->y+ .5* $h+ .3* $this->FontSize))* $k,$txt2);
function MultiCell($w,$h,$txt,$border= 0,$align= 'J',$fill= 0)
//Output text with automatic or explicit line breaks
if($nb> 0 && $s[$nb- 1]== "\n")
if(strpos($border,'L')!== false)
if(strpos($border,'R')!== false)
$b= (strpos($border,'T')!== false) ? $b2. 'T' : $b2;
$this->Cell($w,$h,substr($s,$j,$i- $j),$b,2,$align,$fill);
$this->Cell($w,$h,substr($s,$j,$i- $j),$b,2,$align,$fill);
$this->ws= ($ns> 1) ? ($wmax- $ls)/ 1000* $this->FontSize/ ($ns- 1) : 0;
$this->Cell($w,$h,substr($s,$j,$sep- $j),$b,2,$align,$fill);
if($border && strpos($border,'B')!== false)
$this->Cell($w,$h,substr($s,$j,$i- $j),$b,0,$align,$fill);
//$this->x=$this->lMargin;
function Write($h,$txt,$link= '')
//Output text in flowing mode
$this->Cell($w,$h,substr($s,$j,$i- $j),0,2,'',0,$link);
$this->Cell($w,$h,substr($s,$j,$i- $j),0,2,'',0,$link);
$this->Cell($w,$h,substr($s,$j,$sep- $j),0,2,'',0,$link);
function Image($file,$x,$y,$w= 0,$h= 0,$type= '',$link= '',$tempFolder= '')
$this->Error('Image file has no extension and no type was specified: '. $file);
if($type== 'jpg' || $type== 'jpeg')
$tmpFile = $tempFolder . '/' . basename($file);
if (@imagejpeg($im, $tmpFile, 100) === true) {
//Put an image on the page
if(!isset ($this->images[$file]))
if($type== 'jpg' || $type== 'jpeg')
//Allow for additional formats
$this->Error('Unsupported image type: '. $type);
$info= $this->$mtd($file);
//Automatic width and height calculation if needed
$w= $h* $info['w']/ $info['h'];
$h= $w* $info['h']/ $info['w'];
$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']));
$this->Link($x,$y,$w,$h,$link);
//Line feed; default value is last cell height
//Set y position and reset x
function Output($name= '',$dest= '')
//Output PDF to some destination
//Finish document if necessary
//Send to standard output
$this->Error('Some data has already been output, can\'t send PDF file');
header('Content-Type: application/pdf');
$this->Error('Some data has already been output to browser, can\'t send PDF file');
header('Content-disposition: inline; filename="'. $name. '"');
$this->Error('Some data has already been output, can\'t send PDF file');
if(isset ($_SERVER['HTTP_USER_AGENT']) && strpos($_SERVER['HTTP_USER_AGENT'],'MSIE'))
header('Content-Type: application/force-download');
header('Content-Type: application/octet-stream');
$this->Error('Some data has already been output to browser, can\'t send PDF file');
header('Content-disposition: attachment; filename="'. $name. '"');
$this->Error('Unable to create output file: '. $name);
$this->Error('Incorrect output destination: '. $dest);
/*******************************************************************************
*******************************************************************************/
//Check for locale-related bug
$this->Error('Don\'t alter the locale before including class file');
//Check for decimal separator
//Replace number of pages
$filter= ($this->compress) ? '/Filter /FlateDecode ' : '';
$this->_out('<</Type /Page');
$this->_out('/Parent 1 0 R');
$this->_out(sprintf('/MediaBox [0 0 %.2f %.2f]',$hPt,$wPt));
$this->_out('/Resources 2 0 R');
$rect= sprintf('%.2f %.2f %.2f %.2f',$pl[0],$pl[1],$pl[0]+ $pl[2],$pl[1]- $pl[3]);
$annots.= '<</Type /Annot /Subtype /Link /Rect ['. $rect. '] /Border [0 0 0] ';
$annots.= '/A <</S /URI /URI '. $this->_textstring($pl[4]). '>>>>';
$annots.= sprintf('/Dest [%d 0 R /XYZ 0 %.2f null]>>',1+ 2* $l[0],$h- $l[1]* $this->k);
$this->_out($annots. ']');
$this->_out('/Contents '. ($this->n+ 1). ' 0 R>>');
$this->_out('<<'. $filter. '/Length '. strlen($p). '>>');
$this->_out('<</Type /Pages');
$this->_out('/Count '. $nb);
$this->_out(sprintf('/MediaBox [0 0 %.2f %.2f]',$wPt,$hPt));
foreach($this->diffs as $diff)
$this->_out('<</Type /Encoding /BaseEncoding /WinAnsiEncoding /Differences ['. $diff. ']>>');
$this->Error('Font file not found');
$compressed= (substr($file,- 2)== '.z');
if(!$compressed && isset ($info['length2']))
$header= (ord($font{0})== 128);
//Strip first binary header
if($header && ord($font{$info['length1']})== 128)
//Strip second binary header
$font= substr($font,0,$info['length1']). substr($font,$info['length1']+ 6);
$this->_out('/Filter /FlateDecode');
$this->_out('/Length1 '. $info['length1']);
if(isset ($info['length2']))
$this->_out('/Length2 '. $info['length2']. ' /Length3 0');
foreach($this->fonts as $k=> $font)
$this->fonts[$k]['n']= $this->n+ 1;
$this->_out('<</Type /Font');
$this->_out('/BaseFont /'. $name);
$this->_out('/Subtype /Type1');
if($name!= 'Symbol' && $name!= 'ZapfDingbats')
$this->_out('/Encoding /WinAnsiEncoding');
elseif($type== 'Type1' || $type== 'TrueType')
//Additional Type1 or TrueType font
$this->_out('<</Type /Font');
$this->_out('/BaseFont /'. $name);
$this->_out('/Subtype /'. $type);
$this->_out('/FirstChar 32 /LastChar 255');
$this->_out('/Widths '. ($this->n+ 1). ' 0 R');
$this->_out('/FontDescriptor '. ($this->n+ 2). ' 0 R');
$this->_out('/Encoding '. ($nf+ $font['diff']). ' 0 R');
$this->_out('/Encoding /WinAnsiEncoding');
$s= '<</Type /FontDescriptor /FontName /'. $name;
foreach($font['desc'] as $k=> $v)
$s.= ' /FontFile'. ($type== 'Type1' ? '' : '2'). ' '. $this->FontFiles[$file]['n']. ' 0 R';
//Allow for additional types
$this->Error('Unsupported font type: '. $type);
$filter= ($this->compress) ? '/Filter /FlateDecode ' : '';
$this->images[$file]['n']= $this->n;
$this->_out('<</Type /XObject');
$this->_out('/Subtype /Image');
$this->_out('/Width '. $info['w']);
$this->_out('/Height '. $info['h']);
if($info['cs']== 'Indexed')
$this->_out('/ColorSpace [/Indexed /DeviceRGB '. (strlen($info['pal'])/ 3- 1). ' '. ($this->n+ 1). ' 0 R]');
$this->_out('/ColorSpace /'. $info['cs']);
if($info['cs']== 'DeviceCMYK')
$this->_out('/Decode [1 0 1 0 1 0 1 0]');
$this->_out('/BitsPerComponent '. $info['bpc']);
$this->_out('/Filter /'. $info['f']);
if(isset ($info['parms']))
$this->_out($info['parms']);
if(isset ($info['trns']) && is_array($info['trns']))
$infoTrnsCount = count($info['trns']);
for($i= 0;$i< $infoTrnsCount;++ $i)
$trns.= $info['trns'][$i]. ' '. $info['trns'][$i]. ' ';
$this->_out('/Mask ['. $trns. ']');
$this->_out('/Length '. strlen($info['data']). '>>');
unset ($this->images[$file]['data']);
if($info['cs']== 'Indexed')
$this->_out('<<'. $filter. '/Length '. strlen($pal). '>>');
foreach($this->images as $image)
$this->_out('/I'. $image['i']. ' '. $image['n']. ' 0 R');
$this->_out('/ProcSet [/PDF /Text /ImageB /ImageC /ImageI]');
foreach($this->fonts as $font)
$this->_out('/F'. $font['i']. ' '. $font['n']. ' 0 R');
$this->_out('/XObject <<');
$this->_out('/Type /Catalog');
$this->_out('/Pages 1 0 R');
$this->_out('/OpenAction [3 0 R /Fit]');
$this->_out('/OpenAction [3 0 R /FitH null]');
$this->_out('/OpenAction [3 0 R /XYZ null null 1]');
$this->_out('/OpenAction [3 0 R /XYZ null null '. ($this->ZoomMode/ 100). ']');
$this->_out('/PageLayout /SinglePage');
$this->_out('/PageLayout /OneColumn');
$this->_out('/PageLayout /TwoColumnLeft');
$this->_out('/Size '. ($this->n+ 1));
$this->_out('/Root '. $this->n. ' 0 R');
$this->_out('/Info '. ($this->n- 1). ' 0 R');
$this->_out('0 '. ($this->n+ 1));
$this->_out('0000000000 65535 f ');
for($i= 1;$i<= $this->n;++ $i)
$this->_out('startxref');
$this->_out($this->n. ' 0 obj');
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);
//Extract info from a JPEG file
$this->Error('Missing or incorrect image file: '. $file);
$this->Error('Not a JPEG file: '. $file);
if(!isset ($a['channels']) || $a['channels']== 3)
elseif($a['channels']== 4)
$bpc=isset ($a['bits']) ? $a['bits'] : 8;
return array('w'=> $a[0],'h'=> $a[1],'cs'=> $colspace,'bpc'=> $bpc,'f'=> 'DCTDecode','data'=> $data);
//Extract info from a PNG file
$this->Error('Can\'t open image file: '. $file);
$this->Error('Not a PNG file: '. $file);
$this->Error('Incorrect PNG file: '. $file);
$this->Error('16-bit depth not supported: '. $file);
$this->Error('Alpha channel not supported: '. $file);
$this->Error('Unknown compression method: '. $file);
$this->Error('Unknown filter method: '. $file);
$this->Error('Interlacing not supported: '. $file);
$parms= '/DecodeParms <</Predictor 15 /Colors '. ($ct== 2 ? 3 : 1). ' /BitsPerComponent '. $bpc. ' /Columns '. $w. '>>';
//Scan chunks looking for palette, transparency and image data
if($colspace== 'Indexed' && empty($pal))
$this->Error('Missing palette in '. $file);
return array('w'=> $w,'h'=> $h,'cs'=> $colspace,'bpc'=> $bpc,'f'=> 'FlateDecode','parms'=> $parms,'pal'=> $pal,'trns'=> $trns,'data'=> $data);
//Read a 4-byte integer from file
//Add \ before \, ( and )
$this->_out('endstream');
//Add a line to the document
//Handle special IE contype request
if(isset ($_SERVER['HTTP_USER_AGENT']) && $_SERVER['HTTP_USER_AGENT']== 'contype')
//header('Content-Type: application/pdf');
|