-<?php\r
-/*******************************************************************************\r
-* FPDF *\r
-* *\r
-* Version: 1.81 *\r
-* Date: 2015-12-20 *\r
-* Author: Olivier PLATHEY *\r
-*******************************************************************************/\r
-\r
-define('FPDF_VERSION','1.81');\r
-\r
-class FPDF\r
-{\r
-protected $page; // current page number\r
-protected $n; // current object number\r
-protected $offsets; // array of object offsets\r
-protected $buffer; // buffer holding in-memory PDF\r
-protected $pages; // array containing pages\r
-protected $state; // current document state\r
-protected $compress; // compression flag\r
-protected $k; // scale factor (number of points in user unit)\r
-protected $DefOrientation; // default orientation\r
-protected $CurOrientation; // current orientation\r
-protected $StdPageSizes; // standard page sizes\r
-protected $DefPageSize; // default page size\r
-protected $CurPageSize; // current page size\r
-protected $CurRotation; // current page rotation\r
-protected $PageInfo; // page-related data\r
-protected $wPt, $hPt; // dimensions of current page in points\r
-protected $w, $h; // dimensions of current page in user unit\r
-protected $lMargin; // left margin\r
-protected $tMargin; // top margin\r
-protected $rMargin; // right margin\r
-protected $bMargin; // page break margin\r
-protected $cMargin; // cell margin\r
-protected $x, $y; // current position in user unit\r
-protected $lasth; // height of last printed cell\r
-protected $LineWidth; // line width in user unit\r
-protected $fontpath; // path containing fonts\r
-protected $CoreFonts; // array of core font names\r
-protected $fonts; // array of used fonts\r
-protected $FontFiles; // array of font files\r
-protected $encodings; // array of encodings\r
-protected $cmaps; // array of ToUnicode CMaps\r
-protected $FontFamily; // current font family\r
-protected $FontStyle; // current font style\r
-protected $underline; // underlining flag\r
-protected $CurrentFont; // current font info\r
-protected $FontSizePt; // current font size in points\r
-protected $FontSize; // current font size in user unit\r
-protected $DrawColor; // commands for drawing color\r
-protected $FillColor; // commands for filling color\r
-protected $TextColor; // commands for text color\r
-protected $ColorFlag; // indicates whether fill and text colors are different\r
-protected $WithAlpha; // indicates whether alpha channel is used\r
-protected $ws; // word spacing\r
-protected $images; // array of used images\r
-protected $PageLinks; // array of links in pages\r
-protected $links; // array of internal links\r
-protected $AutoPageBreak; // automatic page breaking\r
-protected $PageBreakTrigger; // threshold used to trigger page breaks\r
-protected $InHeader; // flag set when processing header\r
-protected $InFooter; // flag set when processing footer\r
-protected $AliasNbPages; // alias for total number of pages\r
-protected $ZoomMode; // zoom display mode\r
-protected $LayoutMode; // layout display mode\r
-protected $metadata; // document properties\r
-protected $PDFVersion; // PDF version number\r
-\r
-/*******************************************************************************\r
-* Public methods *\r
-*******************************************************************************/\r
-\r
-function __construct($orientation='P', $unit='mm', $size='A4')\r
-{\r
- // Some checks\r
- $this->_dochecks();\r
- // Initialization of properties\r
- $this->state = 0;\r
- $this->page = 0;\r
- $this->n = 2;\r
- $this->buffer = '';\r
- $this->pages = array();\r
- $this->PageInfo = array();\r
- $this->fonts = array();\r
- $this->FontFiles = array();\r
- $this->encodings = array();\r
- $this->cmaps = array();\r
- $this->images = array();\r
- $this->links = array();\r
- $this->InHeader = false;\r
- $this->InFooter = false;\r
- $this->lasth = 0;\r
- $this->FontFamily = '';\r
- $this->FontStyle = '';\r
- $this->FontSizePt = 12;\r
- $this->underline = false;\r
- $this->DrawColor = '0 G';\r
- $this->FillColor = '0 g';\r
- $this->TextColor = '0 g';\r
- $this->ColorFlag = false;\r
- $this->WithAlpha = false;\r
- $this->ws = 0;\r
- // Font path\r
- if(defined('FPDF_FONTPATH'))\r
- {\r
- $this->fontpath = FPDF_FONTPATH;\r
- if(substr($this->fontpath,-1)!='/' && substr($this->fontpath,-1)!='\\')\r
- $this->fontpath .= '/';\r
- }\r
- elseif(is_dir(dirname(__FILE__).'/font'))\r
- $this->fontpath = dirname(__FILE__).'/font/';\r
- else\r
- $this->fontpath = '';\r
- // Core fonts\r
- $this->CoreFonts = array('courier', 'helvetica', 'times', 'symbol', 'zapfdingbats');\r
- // Scale factor\r
- if($unit=='pt')\r
- $this->k = 1;\r
- elseif($unit=='mm')\r
- $this->k = 72/25.4;\r
- elseif($unit=='cm')\r
- $this->k = 72/2.54;\r
- elseif($unit=='in')\r
- $this->k = 72;\r
- else\r
- $this->Error('Incorrect unit: '.$unit);\r
- // Page sizes\r
- $this->StdPageSizes = array('a3'=>array(841.89,1190.55), 'a4'=>array(595.28,841.89), 'a5'=>array(420.94,595.28),\r
- 'letter'=>array(612,792), 'legal'=>array(612,1008));\r
- $size = $this->_getpagesize($size);\r
- $this->DefPageSize = $size;\r
- $this->CurPageSize = $size;\r
- // Page orientation\r
- $orientation = strtolower($orientation);\r
- if($orientation=='p' || $orientation=='portrait')\r
- {\r
- $this->DefOrientation = 'P';\r
- $this->w = $size[0];\r
- $this->h = $size[1];\r
- }\r
- elseif($orientation=='l' || $orientation=='landscape')\r
- {\r
- $this->DefOrientation = 'L';\r
- $this->w = $size[1];\r
- $this->h = $size[0];\r
- }\r
- else\r
- $this->Error('Incorrect orientation: '.$orientation);\r
- $this->CurOrientation = $this->DefOrientation;\r
- $this->wPt = $this->w*$this->k;\r
- $this->hPt = $this->h*$this->k;\r
- // Page rotation\r
- $this->CurRotation = 0;\r
- // Page margins (1 cm)\r
- $margin = 28.35/$this->k;\r
- $this->SetMargins($margin,$margin);\r
- // Interior cell margin (1 mm)\r
- $this->cMargin = $margin/10;\r
- // Line width (0.2 mm)\r
- $this->LineWidth = .567/$this->k;\r
- // Automatic page break\r
- $this->SetAutoPageBreak(true,2*$margin);\r
- // Default display mode\r
- $this->SetDisplayMode('default');\r
- // Enable compression\r
- $this->SetCompression(true);\r
- // Set default PDF version number\r
- $this->PDFVersion = '1.3';\r
-}\r
-\r
-function SetMargins($left, $top, $right=null)\r
-{\r
- // Set left, top and right margins\r
- $this->lMargin = $left;\r
- $this->tMargin = $top;\r
- if($right===null)\r
- $right = $left;\r
- $this->rMargin = $right;\r
-}\r
-\r
-function SetLeftMargin($margin)\r
-{\r
- // Set left margin\r
- $this->lMargin = $margin;\r
- if($this->page>0 && $this->x<$margin)\r
- $this->x = $margin;\r
-}\r
-\r
-function SetTopMargin($margin)\r
-{\r
- // Set top margin\r
- $this->tMargin = $margin;\r
-}\r
-\r
-function SetRightMargin($margin)\r
-{\r
- // Set right margin\r
- $this->rMargin = $margin;\r
-}\r
-\r
-function SetAutoPageBreak($auto, $margin=0)\r
-{\r
- // Set auto page break mode and triggering margin\r
- $this->AutoPageBreak = $auto;\r
- $this->bMargin = $margin;\r
- $this->PageBreakTrigger = $this->h-$margin;\r
-}\r
-\r
-function SetDisplayMode($zoom, $layout='default')\r
-{\r
- // Set display mode in viewer\r
- if($zoom=='fullpage' || $zoom=='fullwidth' || $zoom=='real' || $zoom=='default' || !is_string($zoom))\r
- $this->ZoomMode = $zoom;\r
- else\r
- $this->Error('Incorrect zoom display mode: '.$zoom);\r
- if($layout=='single' || $layout=='continuous' || $layout=='two' || $layout=='default')\r
- $this->LayoutMode = $layout;\r
- else\r
- $this->Error('Incorrect layout display mode: '.$layout);\r
-}\r
-\r
-function SetCompression($compress)\r
-{\r
- // Set page compression\r
- if(function_exists('gzcompress'))\r
- $this->compress = $compress;\r
- else\r
- $this->compress = false;\r
-}\r
-\r
-function SetTitle($title, $isUTF8=false)\r
-{\r
- // Title of document\r
- $this->metadata['Title'] = $isUTF8 ? $title : utf8_encode($title);\r
-}\r
-\r
-function SetAuthor($author, $isUTF8=false)\r
-{\r
- // Author of document\r
- $this->metadata['Author'] = $isUTF8 ? $author : utf8_encode($author);\r
-}\r
-\r
-function SetSubject($subject, $isUTF8=false)\r
-{\r
- // Subject of document\r
- $this->metadata['Subject'] = $isUTF8 ? $subject : utf8_encode($subject);\r
-}\r
-\r
-function SetKeywords($keywords, $isUTF8=false)\r
-{\r
- // Keywords of document\r
- $this->metadata['Keywords'] = $isUTF8 ? $keywords : utf8_encode($keywords);\r
-}\r
-\r
-function SetCreator($creator, $isUTF8=false)\r
-{\r
- // Creator of document\r
- $this->metadata['Creator'] = $isUTF8 ? $creator : utf8_encode($creator);\r
-}\r
-\r
-function AliasNbPages($alias='{nb}')\r
-{\r
- // Define an alias for total number of pages\r
- $this->AliasNbPages = $alias;\r
-}\r
-\r
-function Error($msg)\r
-{\r
- // Fatal error\r
- throw new Exception('FPDF error: '.$msg);\r
-}\r
-\r
-function Close()\r
-{\r
- // Terminate document\r
- if($this->state==3)\r
- return;\r
- if($this->page==0)\r
- $this->AddPage();\r
- // Page footer\r
- $this->InFooter = true;\r
- $this->Footer();\r
- $this->InFooter = false;\r
- // Close page\r
- $this->_endpage();\r
- // Close document\r
- $this->_enddoc();\r
-}\r
-\r
-function AddPage($orientation='', $size='', $rotation=0)\r
-{\r
- // Start a new page\r
- if($this->state==3)\r
- $this->Error('The document is closed');\r
- $family = $this->FontFamily;\r
- $style = $this->FontStyle.($this->underline ? 'U' : '');\r
- $fontsize = $this->FontSizePt;\r
- $lw = $this->LineWidth;\r
- $dc = $this->DrawColor;\r
- $fc = $this->FillColor;\r
- $tc = $this->TextColor;\r
- $cf = $this->ColorFlag;\r
- if($this->page>0)\r
- {\r
- // Page footer\r
- $this->InFooter = true;\r
- $this->Footer();\r
- $this->InFooter = false;\r
- // Close page\r
- $this->_endpage();\r
- }\r
- // Start new page\r
- $this->_beginpage($orientation,$size,$rotation);\r
- // Set line cap style to square\r
- $this->_out('2 J');\r
- // Set line width\r
- $this->LineWidth = $lw;\r
- $this->_out(sprintf('%.2F w',$lw*$this->k));\r
- // Set font\r
- if($family)\r
- $this->SetFont($family,$style,$fontsize);\r
- // Set colors\r
- $this->DrawColor = $dc;\r
- if($dc!='0 G')\r
- $this->_out($dc);\r
- $this->FillColor = $fc;\r
- if($fc!='0 g')\r
- $this->_out($fc);\r
- $this->TextColor = $tc;\r
- $this->ColorFlag = $cf;\r
- // Page header\r
- $this->InHeader = true;\r
- $this->Header();\r
- $this->InHeader = false;\r
- // Restore line width\r
- if($this->LineWidth!=$lw)\r
- {\r
- $this->LineWidth = $lw;\r
- $this->_out(sprintf('%.2F w',$lw*$this->k));\r
- }\r
- // Restore font\r
- if($family)\r
- $this->SetFont($family,$style,$fontsize);\r
- // Restore colors\r
- if($this->DrawColor!=$dc)\r
- {\r
- $this->DrawColor = $dc;\r
- $this->_out($dc);\r
- }\r
- if($this->FillColor!=$fc)\r
- {\r
- $this->FillColor = $fc;\r
- $this->_out($fc);\r
- }\r
- $this->TextColor = $tc;\r
- $this->ColorFlag = $cf;\r
-}\r
-\r
-function Header()\r
-{\r
- // To be implemented in your own inherited class\r
-}\r
-\r
-function Footer()\r
-{\r
- // To be implemented in your own inherited class\r
-}\r
-\r
-function PageNo()\r
-{\r
- // Get current page number\r
- return $this->page;\r
-}\r
-\r
-function SetDrawColor($r, $g=null, $b=null)\r
-{\r
- // Set color for all stroking operations\r
- if(($r==0 && $g==0 && $b==0) || $g===null)\r
- $this->DrawColor = sprintf('%.3F G',$r/255);\r
- else\r
- $this->DrawColor = sprintf('%.3F %.3F %.3F RG',$r/255,$g/255,$b/255);\r
- if($this->page>0)\r
- $this->_out($this->DrawColor);\r
-}\r
-\r
-function SetFillColor($r, $g=null, $b=null)\r
-{\r
- // Set color for all filling operations\r
- if(($r==0 && $g==0 && $b==0) || $g===null)\r
- $this->FillColor = sprintf('%.3F g',$r/255);\r
- else\r
- $this->FillColor = sprintf('%.3F %.3F %.3F rg',$r/255,$g/255,$b/255);\r
- $this->ColorFlag = ($this->FillColor!=$this->TextColor);\r
- if($this->page>0)\r
- $this->_out($this->FillColor);\r
-}\r
-\r
-function SetTextColor($r, $g=null, $b=null)\r
-{\r
- // Set color for text\r
- if(($r==0 && $g==0 && $b==0) || $g===null)\r
- $this->TextColor = sprintf('%.3F g',$r/255);\r
- else\r
- $this->TextColor = sprintf('%.3F %.3F %.3F rg',$r/255,$g/255,$b/255);\r
- $this->ColorFlag = ($this->FillColor!=$this->TextColor);\r
-}\r
-\r
-function GetStringWidth($s)\r
-{\r
- // Get width of a string in the current font\r
- $s = (string)$s;\r
- $cw = &$this->CurrentFont['cw'];\r
- $w = 0;\r
- $l = strlen($s);\r
- for($i=0;$i<$l;$i++)\r
- $w += $cw[$s[$i]];\r
- return $w*$this->FontSize/1000;\r
-}\r
-\r
-function SetLineWidth($width)\r
-{\r
- // Set line width\r
- $this->LineWidth = $width;\r
- if($this->page>0)\r
- $this->_out(sprintf('%.2F w',$width*$this->k));\r
-}\r
-\r
-function Line($x1, $y1, $x2, $y2)\r
-{\r
- // Draw a line\r
- $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));\r
-}\r
-\r
-function Rect($x, $y, $w, $h, $style='')\r
-{\r
- // Draw a rectangle\r
- if($style=='F')\r
- $op = 'f';\r
- elseif($style=='FD' || $style=='DF')\r
- $op = 'B';\r
- else\r
- $op = 'S';\r
- $this->_out(sprintf('%.2F %.2F %.2F %.2F re %s',$x*$this->k,($this->h-$y)*$this->k,$w*$this->k,-$h*$this->k,$op));\r
-}\r
-\r
-function AddFont($family, $style='', $file='')\r
-{\r
- // Add a TrueType, OpenType or Type1 font\r
- $family = strtolower($family);\r
- if($file=='')\r
- $file = str_replace(' ','',$family).strtolower($style).'.php';\r
- $style = strtoupper($style);\r
- if($style=='IB')\r
- $style = 'BI';\r
- $fontkey = $family.$style;\r
- if(isset($this->fonts[$fontkey]))\r
- return;\r
- $info = $this->_loadfont($file);\r
- $info['i'] = count($this->fonts)+1;\r
- if(!empty($info['file']))\r
- {\r
- // Embedded font\r
- if($info['type']=='TrueType')\r
- $this->FontFiles[$info['file']] = array('length1'=>$info['originalsize']);\r
- else\r
- $this->FontFiles[$info['file']] = array('length1'=>$info['size1'], 'length2'=>$info['size2']);\r
- }\r
- $this->fonts[$fontkey] = $info;\r
-}\r
-\r
-function SetFont($family, $style='', $size=0)\r
-{\r
- // Select a font; size given in points\r
- if($family=='')\r
- $family = $this->FontFamily;\r
- else\r
- $family = strtolower($family);\r
- $style = strtoupper($style);\r
- if(strpos($style,'U')!==false)\r
- {\r
- $this->underline = true;\r
- $style = str_replace('U','',$style);\r
- }\r
- else\r
- $this->underline = false;\r
- if($style=='IB')\r
- $style = 'BI';\r
- if($size==0)\r
- $size = $this->FontSizePt;\r
- // Test if font is already selected\r
- if($this->FontFamily==$family && $this->FontStyle==$style && $this->FontSizePt==$size)\r
- return;\r
- // Test if font is already loaded\r
- $fontkey = $family.$style;\r
- if(!isset($this->fonts[$fontkey]))\r
- {\r
- // Test if one of the core fonts\r
- if($family=='arial')\r
- $family = 'helvetica';\r
- if(in_array($family,$this->CoreFonts))\r
- {\r
- if($family=='symbol' || $family=='zapfdingbats')\r
- $style = '';\r
- $fontkey = $family.$style;\r
- if(!isset($this->fonts[$fontkey]))\r
- $this->AddFont($family,$style);\r
- }\r
- else\r
- $this->Error('Undefined font: '.$family.' '.$style);\r
- }\r
- // Select it\r
- $this->FontFamily = $family;\r
- $this->FontStyle = $style;\r
- $this->FontSizePt = $size;\r
- $this->FontSize = $size/$this->k;\r
- $this->CurrentFont = &$this->fonts[$fontkey];\r
- if($this->page>0)\r
- $this->_out(sprintf('BT /F%d %.2F Tf ET',$this->CurrentFont['i'],$this->FontSizePt));\r
-}\r
-\r
-function SetFontSize($size)\r
-{\r
- // Set font size in points\r
- if($this->FontSizePt==$size)\r
- return;\r
- $this->FontSizePt = $size;\r
- $this->FontSize = $size/$this->k;\r
- if($this->page>0)\r
- $this->_out(sprintf('BT /F%d %.2F Tf ET',$this->CurrentFont['i'],$this->FontSizePt));\r
-}\r
-\r
-function AddLink()\r
-{\r
- // Create a new internal link\r
- $n = count($this->links)+1;\r
- $this->links[$n] = array(0, 0);\r
- return $n;\r
-}\r
-\r
-function SetLink($link, $y=0, $page=-1)\r
-{\r
- // Set destination of internal link\r
- if($y==-1)\r
- $y = $this->y;\r
- if($page==-1)\r
- $page = $this->page;\r
- $this->links[$link] = array($page, $y);\r
-}\r
-\r
-function Link($x, $y, $w, $h, $link)\r
-{\r
- // Put a link on the page\r
- $this->PageLinks[$this->page][] = array($x*$this->k, $this->hPt-$y*$this->k, $w*$this->k, $h*$this->k, $link);\r
-}\r
-\r
-function Text($x, $y, $txt)\r
-{\r
- // Output a string\r
- if(!isset($this->CurrentFont))\r
- $this->Error('No font has been set');\r
- $s = sprintf('BT %.2F %.2F Td (%s) Tj ET',$x*$this->k,($this->h-$y)*$this->k,$this->_escape($txt));\r
- if($this->underline && $txt!='')\r
- $s .= ' '.$this->_dounderline($x,$y,$txt);\r
- if($this->ColorFlag)\r
- $s = 'q '.$this->TextColor.' '.$s.' Q';\r
- $this->_out($s);\r
-}\r
-\r
-function AcceptPageBreak()\r
-{\r
- // Accept automatic page break or not\r
- return $this->AutoPageBreak;\r
-}\r
-\r
-function Cell($w, $h=0, $txt='', $border=0, $ln=0, $align='', $fill=false, $link='')\r
-{\r
- // Output a cell\r
- $k = $this->k;\r
- if($this->y+$h>$this->PageBreakTrigger && !$this->InHeader && !$this->InFooter && $this->AcceptPageBreak())\r
- {\r
- // Automatic page break\r
- $x = $this->x;\r
- $ws = $this->ws;\r
- if($ws>0)\r
- {\r
- $this->ws = 0;\r
- $this->_out('0 Tw');\r
- }\r
- $this->AddPage($this->CurOrientation,$this->CurPageSize,$this->CurRotation);\r
- $this->x = $x;\r
- if($ws>0)\r
- {\r
- $this->ws = $ws;\r
- $this->_out(sprintf('%.3F Tw',$ws*$k));\r
- }\r
- }\r
- if($w==0)\r
- $w = $this->w-$this->rMargin-$this->x;\r
- $s = '';\r
- if($fill || $border==1)\r
- {\r
- if($fill)\r
- $op = ($border==1) ? 'B' : 'f';\r
- else\r
- $op = 'S';\r
- $s = sprintf('%.2F %.2F %.2F %.2F re %s ',$this->x*$k,($this->h-$this->y)*$k,$w*$k,-$h*$k,$op);\r
- }\r
- if(is_string($border))\r
- {\r
- $x = $this->x;\r
- $y = $this->y;\r
- if(strpos($border,'L')!==false)\r
- $s .= sprintf('%.2F %.2F m %.2F %.2F l S ',$x*$k,($this->h-$y)*$k,$x*$k,($this->h-($y+$h))*$k);\r
- if(strpos($border,'T')!==false)\r
- $s .= sprintf('%.2F %.2F m %.2F %.2F l S ',$x*$k,($this->h-$y)*$k,($x+$w)*$k,($this->h-$y)*$k);\r
- if(strpos($border,'R')!==false)\r
- $s .= sprintf('%.2F %.2F m %.2F %.2F l S ',($x+$w)*$k,($this->h-$y)*$k,($x+$w)*$k,($this->h-($y+$h))*$k);\r
- if(strpos($border,'B')!==false)\r
- $s .= sprintf('%.2F %.2F m %.2F %.2F l S ',$x*$k,($this->h-($y+$h))*$k,($x+$w)*$k,($this->h-($y+$h))*$k);\r
- }\r
- if($txt!=='')\r
- {\r
- if(!isset($this->CurrentFont))\r
- $this->Error('No font has been set');\r
- if($align=='R')\r
- $dx = $w-$this->cMargin-$this->GetStringWidth($txt);\r
- elseif($align=='C')\r
- $dx = ($w-$this->GetStringWidth($txt))/2;\r
- else\r
- $dx = $this->cMargin;\r
- if($this->ColorFlag)\r
- $s .= 'q '.$this->TextColor.' ';\r
- $s .= sprintf('BT %.2F %.2F Td (%s) Tj ET',($this->x+$dx)*$k,($this->h-($this->y+.5*$h+.3*$this->FontSize))*$k,$this->_escape($txt));\r
- if($this->underline)\r
- $s .= ' '.$this->_dounderline($this->x+$dx,$this->y+.5*$h+.3*$this->FontSize,$txt);\r
- if($this->ColorFlag)\r
- $s .= ' Q';\r
- if($link)\r
- $this->Link($this->x+$dx,$this->y+.5*$h-.5*$this->FontSize,$this->GetStringWidth($txt),$this->FontSize,$link);\r
- }\r
- if($s)\r
- $this->_out($s);\r
- $this->lasth = $h;\r
- if($ln>0)\r
- {\r
- // Go to next line\r
- $this->y += $h;\r
- if($ln==1)\r
- $this->x = $this->lMargin;\r
- }\r
- else\r
- $this->x += $w;\r
-}\r
-\r
-function MultiCell($w, $h, $txt, $border=0, $align='J', $fill=false)\r
-{\r
- // Output text with automatic or explicit line breaks\r
- if(!isset($this->CurrentFont))\r
- $this->Error('No font has been set');\r
- $cw = &$this->CurrentFont['cw'];\r
- if($w==0)\r
- $w = $this->w-$this->rMargin-$this->x;\r
- $wmax = ($w-2*$this->cMargin)*1000/$this->FontSize;\r
- $s = str_replace("\r",'',$txt);\r
- $nb = strlen($s);\r
- if($nb>0 && $s[$nb-1]=="\n")\r
- $nb--;\r
- $b = 0;\r
- if($border)\r
- {\r
- if($border==1)\r
- {\r
- $border = 'LTRB';\r
- $b = 'LRT';\r
- $b2 = 'LR';\r
- }\r
- else\r
- {\r
- $b2 = '';\r
- if(strpos($border,'L')!==false)\r
- $b2 .= 'L';\r
- if(strpos($border,'R')!==false)\r
- $b2 .= 'R';\r
- $b = (strpos($border,'T')!==false) ? $b2.'T' : $b2;\r
- }\r
- }\r
- $sep = -1;\r
- $i = 0;\r
- $j = 0;\r
- $l = 0;\r
- $ns = 0;\r
- $nl = 1;\r
- while($i<$nb)\r
- {\r
- // Get next character\r
- $c = $s[$i];\r
- if($c=="\n")\r
- {\r
- // Explicit line break\r
- if($this->ws>0)\r
- {\r
- $this->ws = 0;\r
- $this->_out('0 Tw');\r
- }\r
- $this->Cell($w,$h,substr($s,$j,$i-$j),$b,2,$align,$fill);\r
- $i++;\r
- $sep = -1;\r
- $j = $i;\r
- $l = 0;\r
- $ns = 0;\r
- $nl++;\r
- if($border && $nl==2)\r
- $b = $b2;\r
- continue;\r
- }\r
- if($c==' ')\r
- {\r
- $sep = $i;\r
- $ls = $l;\r
- $ns++;\r
- }\r
- $l += $cw[$c];\r
- if($l>$wmax)\r
- {\r
- // Automatic line break\r
- if($sep==-1)\r
- {\r
- if($i==$j)\r
- $i++;\r
- if($this->ws>0)\r
- {\r
- $this->ws = 0;\r
- $this->_out('0 Tw');\r
- }\r
- $this->Cell($w,$h,substr($s,$j,$i-$j),$b,2,$align,$fill);\r
- }\r
- else\r
- {\r
- if($align=='J')\r
- {\r
- $this->ws = ($ns>1) ? ($wmax-$ls)/1000*$this->FontSize/($ns-1) : 0;\r
- $this->_out(sprintf('%.3F Tw',$this->ws*$this->k));\r
- }\r
- $this->Cell($w,$h,substr($s,$j,$sep-$j),$b,2,$align,$fill);\r
- $i = $sep+1;\r
- }\r
- $sep = -1;\r
- $j = $i;\r
- $l = 0;\r
- $ns = 0;\r
- $nl++;\r
- if($border && $nl==2)\r
- $b = $b2;\r
- }\r
- else\r
- $i++;\r
- }\r
- // Last chunk\r
- if($this->ws>0)\r
- {\r
- $this->ws = 0;\r
- $this->_out('0 Tw');\r
- }\r
- if($border && strpos($border,'B')!==false)\r
- $b .= 'B';\r
- $this->Cell($w,$h,substr($s,$j,$i-$j),$b,2,$align,$fill);\r
- $this->x = $this->lMargin;\r
-}\r
-\r
-function Write($h, $txt, $link='')\r
-{\r
- // Output text in flowing mode\r
- if(!isset($this->CurrentFont))\r
- $this->Error('No font has been set');\r
- $cw = &$this->CurrentFont['cw'];\r
- $w = $this->w-$this->rMargin-$this->x;\r
- $wmax = ($w-2*$this->cMargin)*1000/$this->FontSize;\r
- $s = str_replace("\r",'',$txt);\r
- $nb = strlen($s);\r
- $sep = -1;\r
- $i = 0;\r
- $j = 0;\r
- $l = 0;\r
- $nl = 1;\r
- while($i<$nb)\r
- {\r
- // Get next character\r
- $c = $s[$i];\r
- if($c=="\n")\r
- {\r
- // Explicit line break\r
- $this->Cell($w,$h,substr($s,$j,$i-$j),0,2,'',false,$link);\r
- $i++;\r
- $sep = -1;\r
- $j = $i;\r
- $l = 0;\r
- if($nl==1)\r
- {\r
- $this->x = $this->lMargin;\r
- $w = $this->w-$this->rMargin-$this->x;\r
- $wmax = ($w-2*$this->cMargin)*1000/$this->FontSize;\r
- }\r
- $nl++;\r
- continue;\r
- }\r
- if($c==' ')\r
- $sep = $i;\r
- $l += $cw[$c];\r
- if($l>$wmax)\r
- {\r
- // Automatic line break\r
- if($sep==-1)\r
- {\r
- if($this->x>$this->lMargin)\r
- {\r
- // Move to next line\r
- $this->x = $this->lMargin;\r
- $this->y += $h;\r
- $w = $this->w-$this->rMargin-$this->x;\r
- $wmax = ($w-2*$this->cMargin)*1000/$this->FontSize;\r
- $i++;\r
- $nl++;\r
- continue;\r
- }\r
- if($i==$j)\r
- $i++;\r
- $this->Cell($w,$h,substr($s,$j,$i-$j),0,2,'',false,$link);\r
- }\r
- else\r
- {\r
- $this->Cell($w,$h,substr($s,$j,$sep-$j),0,2,'',false,$link);\r
- $i = $sep+1;\r
- }\r
- $sep = -1;\r
- $j = $i;\r
- $l = 0;\r
- if($nl==1)\r
- {\r
- $this->x = $this->lMargin;\r
- $w = $this->w-$this->rMargin-$this->x;\r
- $wmax = ($w-2*$this->cMargin)*1000/$this->FontSize;\r
- }\r
- $nl++;\r
- }\r
- else\r
- $i++;\r
- }\r
- // Last chunk\r
- if($i!=$j)\r
- $this->Cell($l/1000*$this->FontSize,$h,substr($s,$j),0,0,'',false,$link);\r
-}\r
-\r
-function Ln($h=null)\r
-{\r
- // Line feed; default value is the last cell height\r
- $this->x = $this->lMargin;\r
- if($h===null)\r
- $this->y += $this->lasth;\r
- else\r
- $this->y += $h;\r
-}\r
-\r
-function Image($file, $x=null, $y=null, $w=0, $h=0, $type='', $link='')\r
-{\r
- // Put an image on the page\r
- if($file=='')\r
- $this->Error('Image file name is empty');\r
- if(!isset($this->images[$file]))\r
- {\r
- // First use of this image, get info\r
- if($type=='')\r
- {\r
- $pos = strrpos($file,'.');\r
- if(!$pos)\r
- $this->Error('Image file has no extension and no type was specified: '.$file);\r
- $type = substr($file,$pos+1);\r
- }\r
- $type = strtolower($type);\r
- if($type=='jpeg')\r
- $type = 'jpg';\r
- $mtd = '_parse'.$type;\r
- if(!method_exists($this,$mtd))\r
- $this->Error('Unsupported image type: '.$type);\r
- $info = $this->$mtd($file);\r
- $info['i'] = count($this->images)+1;\r
- $this->images[$file] = $info;\r
- }\r
- else\r
- $info = $this->images[$file];\r
-\r
- // Automatic width and height calculation if needed\r
- if($w==0 && $h==0)\r
- {\r
- // Put image at 96 dpi\r
- $w = -96;\r
- $h = -96;\r
- }\r
- if($w<0)\r
- $w = -$info['w']*72/$w/$this->k;\r
- if($h<0)\r
- $h = -$info['h']*72/$h/$this->k;\r
- if($w==0)\r
- $w = $h*$info['w']/$info['h'];\r
- if($h==0)\r
- $h = $w*$info['h']/$info['w'];\r
-\r
- // Flowing mode\r
- if($y===null)\r
- {\r
- if($this->y+$h>$this->PageBreakTrigger && !$this->InHeader && !$this->InFooter && $this->AcceptPageBreak())\r
- {\r
- // Automatic page break\r
- $x2 = $this->x;\r
- $this->AddPage($this->CurOrientation,$this->CurPageSize,$this->CurRotation);\r
- $this->x = $x2;\r
- }\r
- $y = $this->y;\r
- $this->y += $h;\r
- }\r
-\r
- if($x===null)\r
- $x = $this->x;\r
- $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']));\r
- if($link)\r
- $this->Link($x,$y,$w,$h,$link);\r
-}\r
-\r
-function GetPageWidth()\r
-{\r
- // Get current page width\r
- return $this->w;\r
-}\r
-\r
-function GetPageHeight()\r
-{\r
- // Get current page height\r
- return $this->h;\r
-}\r
-\r
-function GetX()\r
-{\r
- // Get x position\r
- return $this->x;\r
-}\r
-\r
-function SetX($x)\r
-{\r
- // Set x position\r
- if($x>=0)\r
- $this->x = $x;\r
- else\r
- $this->x = $this->w+$x;\r
-}\r
-\r
-function GetY()\r
-{\r
- // Get y position\r
- return $this->y;\r
-}\r
-\r
-function SetY($y, $resetX=true)\r
-{\r
- // Set y position and optionally reset x\r
- if($y>=0)\r
- $this->y = $y;\r
- else\r
- $this->y = $this->h+$y;\r
- if($resetX)\r
- $this->x = $this->lMargin;\r
-}\r
-\r
-function SetXY($x, $y)\r
-{\r
- // Set x and y positions\r
- $this->SetX($x);\r
- $this->SetY($y,false);\r
-}\r
-\r
-function Output($dest='', $name='', $isUTF8=false)\r
-{\r
- // Output PDF to some destination\r
- $this->Close();\r
- if(strlen($name)==1 && strlen($dest)!=1)\r
- {\r
- // Fix parameter order\r
- $tmp = $dest;\r
- $dest = $name;\r
- $name = $tmp;\r
- }\r
- if($dest=='')\r
- $dest = 'I';\r
- if($name=='')\r
- $name = 'doc.pdf';\r
- switch(strtoupper($dest))\r
- {\r
- case 'I':\r
- // Send to standard output\r
- $this->_checkoutput();\r
- if(PHP_SAPI!='cli')\r
- {\r
- // We send to a browser\r
- header('Content-Type: application/pdf');\r
- header('Content-Disposition: inline; '.$this->_httpencode('filename',$name,$isUTF8));\r
- header('Cache-Control: private, max-age=0, must-revalidate');\r
- header('Pragma: public');\r
- }\r
- echo $this->buffer;\r
- break;\r
- case 'D':\r
- // Download file\r
- $this->_checkoutput();\r
- header('Content-Type: application/x-download');\r
- header('Content-Disposition: attachment; '.$this->_httpencode('filename',$name,$isUTF8));\r
- header('Cache-Control: private, max-age=0, must-revalidate');\r
- header('Pragma: public');\r
- echo $this->buffer;\r
- break;\r
- case 'F':\r
- // Save to local file\r
- if(!file_put_contents($name,$this->buffer))\r
- $this->Error('Unable to create output file: '.$name);\r
- break;\r
- case 'S':\r
- // Return as a string\r
- return $this->buffer;\r
- default:\r
- $this->Error('Incorrect output destination: '.$dest);\r
- }\r
- return '';\r
-}\r
-\r
-/*******************************************************************************\r
-* Protected methods *\r
-*******************************************************************************/\r
-\r
-protected function _dochecks()\r
-{\r
- // Check mbstring overloading\r
- if(ini_get('mbstring.func_overload') & 2)\r
- $this->Error('mbstring overloading must be disabled');\r
- // Ensure runtime magic quotes are disabled\r
- if(get_magic_quotes_runtime())\r
- @set_magic_quotes_runtime(0);\r
-}\r
-\r
-protected function _checkoutput()\r
-{\r
- if(PHP_SAPI!='cli')\r
- {\r
- if(headers_sent($file,$line))\r
- $this->Error("Some data has already been output, can't send PDF file (output started at $file:$line)");\r
- }\r
- if(ob_get_length())\r
- {\r
- // The output buffer is not empty\r
- if(preg_match('/^(\xEF\xBB\xBF)?\s*$/',ob_get_contents()))\r
- {\r
- // It contains only a UTF-8 BOM and/or whitespace, let's clean it\r
- ob_clean();\r
- }\r
- else\r
- $this->Error("Some data has already been output, can't send PDF file");\r
- }\r
-}\r
-\r
-protected function _getpagesize($size)\r
-{\r
- if(is_string($size))\r
- {\r
- $size = strtolower($size);\r
- if(!isset($this->StdPageSizes[$size]))\r
- $this->Error('Unknown page size: '.$size);\r
- $a = $this->StdPageSizes[$size];\r
- return array($a[0]/$this->k, $a[1]/$this->k);\r
- }\r
- else\r
- {\r
- if($size[0]>$size[1])\r
- return array($size[1], $size[0]);\r
- else\r
- return $size;\r
- }\r
-}\r
-\r
-protected function _beginpage($orientation, $size, $rotation)\r
-{\r
- $this->page++;\r
- $this->pages[$this->page] = '';\r
- $this->state = 2;\r
- $this->x = $this->lMargin;\r
- $this->y = $this->tMargin;\r
- $this->FontFamily = '';\r
- // Check page size and orientation\r
- if($orientation=='')\r
- $orientation = $this->DefOrientation;\r
- else\r
- $orientation = strtoupper($orientation[0]);\r
- if($size=='')\r
- $size = $this->DefPageSize;\r
- else\r
- $size = $this->_getpagesize($size);\r
- if($orientation!=$this->CurOrientation || $size[0]!=$this->CurPageSize[0] || $size[1]!=$this->CurPageSize[1])\r
- {\r
- // New size or orientation\r
- if($orientation=='P')\r
- {\r
- $this->w = $size[0];\r
- $this->h = $size[1];\r
- }\r
- else\r
- {\r
- $this->w = $size[1];\r
- $this->h = $size[0];\r
- }\r
- $this->wPt = $this->w*$this->k;\r
- $this->hPt = $this->h*$this->k;\r
- $this->PageBreakTrigger = $this->h-$this->bMargin;\r
- $this->CurOrientation = $orientation;\r
- $this->CurPageSize = $size;\r
- }\r
- if($orientation!=$this->DefOrientation || $size[0]!=$this->DefPageSize[0] || $size[1]!=$this->DefPageSize[1])\r
- $this->PageInfo[$this->page]['size'] = array($this->wPt, $this->hPt);\r
- if($rotation!=0)\r
- {\r
- if($rotation%90!=0)\r
- $this->Error('Incorrect rotation value: '.$rotation);\r
- $this->CurRotation = $rotation;\r
- $this->PageInfo[$this->page]['rotation'] = $rotation;\r
- }\r
-}\r
-\r
-protected function _endpage()\r
-{\r
- $this->state = 1;\r
-}\r
-\r
-protected function _loadfont($font)\r
-{\r
- // Load a font definition file from the font directory\r
- if(strpos($font,'/')!==false || strpos($font,"\\")!==false)\r
- $this->Error('Incorrect font definition file name: '.$font);\r
- include($this->fontpath.$font);\r
- if(!isset($name))\r
- $this->Error('Could not include font definition file');\r
- if(isset($enc))\r
- $enc = strtolower($enc);\r
- if(!isset($subsetted))\r
- $subsetted = false;\r
- return get_defined_vars();\r
-}\r
-\r
-protected function _isascii($s)\r
-{\r
- // Test if string is ASCII\r
- $nb = strlen($s);\r
- for($i=0;$i<$nb;$i++)\r
- {\r
- if(ord($s[$i])>127)\r
- return false;\r
- }\r
- return true;\r
-}\r
-\r
-protected function _httpencode($param, $value, $isUTF8)\r
-{\r
- // Encode HTTP header field parameter\r
- if($this->_isascii($value))\r
- return $param.'="'.$value.'"';\r
- if(!$isUTF8)\r
- $value = utf8_encode($value);\r
- if(strpos($_SERVER['HTTP_USER_AGENT'],'MSIE')!==false)\r
- return $param.'="'.rawurlencode($value).'"';\r
- else\r
- return $param."*=UTF-8''".rawurlencode($value);\r
-}\r
-\r
-protected function _UTF8toUTF16($s)\r
-{\r
- // Convert UTF-8 to UTF-16BE with BOM\r
- $res = "\xFE\xFF";\r
- $nb = strlen($s);\r
- $i = 0;\r
- while($i<$nb)\r
- {\r
- $c1 = ord($s[$i++]);\r
- if($c1>=224)\r
- {\r
- // 3-byte character\r
- $c2 = ord($s[$i++]);\r
- $c3 = ord($s[$i++]);\r
- $res .= chr((($c1 & 0x0F)<<4) + (($c2 & 0x3C)>>2));\r
- $res .= chr((($c2 & 0x03)<<6) + ($c3 & 0x3F));\r
- }\r
- elseif($c1>=192)\r
- {\r
- // 2-byte character\r
- $c2 = ord($s[$i++]);\r
- $res .= chr(($c1 & 0x1C)>>2);\r
- $res .= chr((($c1 & 0x03)<<6) + ($c2 & 0x3F));\r
- }\r
- else\r
- {\r
- // Single-byte character\r
- $res .= "\0".chr($c1);\r
- }\r
- }\r
- return $res;\r
-}\r
-\r
-protected function _escape($s)\r
-{\r
- // Escape special characters\r
- if(strpos($s,'(')!==false || strpos($s,')')!==false || strpos($s,'\\')!==false || strpos($s,"\r")!==false)\r
- return str_replace(array('\\','(',')',"\r"), array('\\\\','\\(','\\)','\\r'), $s);\r
- else\r
- return $s;\r
-}\r
-\r
-protected function _textstring($s)\r
-{\r
- // Format a text string\r
- if(!$this->_isascii($s))\r
- $s = $this->_UTF8toUTF16($s);\r
- return '('.$this->_escape($s).')';\r
-}\r
-\r
-protected function _dounderline($x, $y, $txt)\r
-{\r
- // Underline text\r
- $up = $this->CurrentFont['up'];\r
- $ut = $this->CurrentFont['ut'];\r
- $w = $this->GetStringWidth($txt)+$this->ws*substr_count($txt,' ');\r
- 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);\r
-}\r
-\r
-protected function _parsejpg($file)\r
-{\r
- // Extract info from a JPEG file\r
- $a = getimagesize($file);\r
- if(!$a)\r
- $this->Error('Missing or incorrect image file: '.$file);\r
- if($a[2]!=2)\r
- $this->Error('Not a JPEG file: '.$file);\r
- if(!isset($a['channels']) || $a['channels']==3)\r
- $colspace = 'DeviceRGB';\r
- elseif($a['channels']==4)\r
- $colspace = 'DeviceCMYK';\r
- else\r
- $colspace = 'DeviceGray';\r
- $bpc = isset($a['bits']) ? $a['bits'] : 8;\r
- $data = file_get_contents($file);\r
- return array('w'=>$a[0], 'h'=>$a[1], 'cs'=>$colspace, 'bpc'=>$bpc, 'f'=>'DCTDecode', 'data'=>$data);\r
-}\r
-\r
-protected function _parsepng($file)\r
-{\r
- // Extract info from a PNG file\r
- $f = fopen($file,'rb');\r
- if(!$f)\r
- $this->Error('Can\'t open image file: '.$file);\r
- $info = $this->_parsepngstream($f,$file);\r
- fclose($f);\r
- return $info;\r
-}\r
-\r
-protected function _parsepngstream($f, $file)\r
-{\r
- // Check signature\r
- if($this->_readstream($f,8)!=chr(137).'PNG'.chr(13).chr(10).chr(26).chr(10))\r
- $this->Error('Not a PNG file: '.$file);\r
-\r
- // Read header chunk\r
- $this->_readstream($f,4);\r
- if($this->_readstream($f,4)!='IHDR')\r
- $this->Error('Incorrect PNG file: '.$file);\r
- $w = $this->_readint($f);\r
- $h = $this->_readint($f);\r
- $bpc = ord($this->_readstream($f,1));\r
- if($bpc>8)\r
- $this->Error('16-bit depth not supported: '.$file);\r
- $ct = ord($this->_readstream($f,1));\r
- if($ct==0 || $ct==4)\r
- $colspace = 'DeviceGray';\r
- elseif($ct==2 || $ct==6)\r
- $colspace = 'DeviceRGB';\r
- elseif($ct==3)\r
- $colspace = 'Indexed';\r
- else\r
- $this->Error('Unknown color type: '.$file);\r
- if(ord($this->_readstream($f,1))!=0)\r
- $this->Error('Unknown compression method: '.$file);\r
- if(ord($this->_readstream($f,1))!=0)\r
- $this->Error('Unknown filter method: '.$file);\r
- if(ord($this->_readstream($f,1))!=0)\r
- $this->Error('Interlacing not supported: '.$file);\r
- $this->_readstream($f,4);\r
- $dp = '/Predictor 15 /Colors '.($colspace=='DeviceRGB' ? 3 : 1).' /BitsPerComponent '.$bpc.' /Columns '.$w;\r
-\r
- // Scan chunks looking for palette, transparency and image data\r
- $pal = '';\r
- $trns = '';\r
- $data = '';\r
- do\r
- {\r
- $n = $this->_readint($f);\r
- $type = $this->_readstream($f,4);\r
- if($type=='PLTE')\r
- {\r
- // Read palette\r
- $pal = $this->_readstream($f,$n);\r
- $this->_readstream($f,4);\r
- }\r
- elseif($type=='tRNS')\r
- {\r
- // Read transparency info\r
- $t = $this->_readstream($f,$n);\r
- if($ct==0)\r
- $trns = array(ord(substr($t,1,1)));\r
- elseif($ct==2)\r
- $trns = array(ord(substr($t,1,1)), ord(substr($t,3,1)), ord(substr($t,5,1)));\r
- else\r
- {\r
- $pos = strpos($t,chr(0));\r
- if($pos!==false)\r
- $trns = array($pos);\r
- }\r
- $this->_readstream($f,4);\r
- }\r
- elseif($type=='IDAT')\r
- {\r
- // Read image data block\r
- $data .= $this->_readstream($f,$n);\r
- $this->_readstream($f,4);\r
- }\r
- elseif($type=='IEND')\r
- break;\r
- else\r
- $this->_readstream($f,$n+4);\r
- }\r
- while($n);\r
-\r
- if($colspace=='Indexed' && empty($pal))\r
- $this->Error('Missing palette in '.$file);\r
- $info = array('w'=>$w, 'h'=>$h, 'cs'=>$colspace, 'bpc'=>$bpc, 'f'=>'FlateDecode', 'dp'=>$dp, 'pal'=>$pal, 'trns'=>$trns);\r
- if($ct>=4)\r
- {\r
- // Extract alpha channel\r
- if(!function_exists('gzuncompress'))\r
- $this->Error('Zlib not available, can\'t handle alpha channel: '.$file);\r
- $data = gzuncompress($data);\r
- $color = '';\r
- $alpha = '';\r
- if($ct==4)\r
- {\r
- // Gray image\r
- $len = 2*$w;\r
- for($i=0;$i<$h;$i++)\r
- {\r
- $pos = (1+$len)*$i;\r
- $color .= $data[$pos];\r
- $alpha .= $data[$pos];\r
- $line = substr($data,$pos+1,$len);\r
- $color .= preg_replace('/(.)./s','$1',$line);\r
- $alpha .= preg_replace('/.(.)/s','$1',$line);\r
- }\r
- }\r
- else\r
- {\r
- // RGB image\r
- $len = 4*$w;\r
- for($i=0;$i<$h;$i++)\r
- {\r
- $pos = (1+$len)*$i;\r
- $color .= $data[$pos];\r
- $alpha .= $data[$pos];\r
- $line = substr($data,$pos+1,$len);\r
- $color .= preg_replace('/(.{3})./s','$1',$line);\r
- $alpha .= preg_replace('/.{3}(.)/s','$1',$line);\r
- }\r
- }\r
- unset($data);\r
- $data = gzcompress($color);\r
- $info['smask'] = gzcompress($alpha);\r
- $this->WithAlpha = true;\r
- if($this->PDFVersion<'1.4')\r
- $this->PDFVersion = '1.4';\r
- }\r
- $info['data'] = $data;\r
- return $info;\r
-}\r
-\r
-protected function _readstream($f, $n)\r
-{\r
- // Read n bytes from stream\r
- $res = '';\r
- while($n>0 && !feof($f))\r
- {\r
- $s = fread($f,$n);\r
- if($s===false)\r
- $this->Error('Error while reading stream');\r
- $n -= strlen($s);\r
- $res .= $s;\r
- }\r
- if($n>0)\r
- $this->Error('Unexpected end of stream');\r
- return $res;\r
-}\r
-\r
-protected function _readint($f)\r
-{\r
- // Read a 4-byte integer from stream\r
- $a = unpack('Ni',$this->_readstream($f,4));\r
- return $a['i'];\r
-}\r
-\r
-protected function _parsegif($file)\r
-{\r
- // Extract info from a GIF file (via PNG conversion)\r
- if(!function_exists('imagepng'))\r
- $this->Error('GD extension is required for GIF support');\r
- if(!function_exists('imagecreatefromgif'))\r
- $this->Error('GD has no GIF read support');\r
- $im = imagecreatefromgif($file);\r
- if(!$im)\r
- $this->Error('Missing or incorrect image file: '.$file);\r
- imageinterlace($im,0);\r
- ob_start();\r
- imagepng($im);\r
- $data = ob_get_clean();\r
- imagedestroy($im);\r
- $f = fopen('php://temp','rb+');\r
- if(!$f)\r
- $this->Error('Unable to create memory stream');\r
- fwrite($f,$data);\r
- rewind($f);\r
- $info = $this->_parsepngstream($f,$file);\r
- fclose($f);\r
- return $info;\r
-}\r
-\r
-protected function _out($s)\r
-{\r
- // Add a line to the document\r
- if($this->state==2)\r
- $this->pages[$this->page] .= $s."\n";\r
- elseif($this->state==1)\r
- $this->_put($s);\r
- elseif($this->state==0)\r
- $this->Error('No page has been added yet');\r
- elseif($this->state==3)\r
- $this->Error('The document is closed');\r
-}\r
-\r
-protected function _put($s)\r
-{\r
- $this->buffer .= $s."\n";\r
-}\r
-\r
-protected function _getoffset()\r
-{\r
- return strlen($this->buffer);\r
-}\r
-\r
-protected function _newobj($n=null)\r
-{\r
- // Begin a new object\r
- if($n===null)\r
- $n = ++$this->n;\r
- $this->offsets[$n] = $this->_getoffset();\r
- $this->_put($n.' 0 obj');\r
-}\r
-\r
-protected function _putstream($data)\r
-{\r
- $this->_put('stream');\r
- $this->_put($data);\r
- $this->_put('endstream');\r
-}\r
-\r
-protected function _putstreamobject($data)\r
-{\r
- if($this->compress)\r
- {\r
- $entries = '/Filter /FlateDecode ';\r
- $data = gzcompress($data);\r
- }\r
- else\r
- $entries = '';\r
- $entries .= '/Length '.strlen($data);\r
- $this->_newobj();\r
- $this->_put('<<'.$entries.'>>');\r
- $this->_putstream($data);\r
- $this->_put('endobj');\r
-}\r
-\r
-protected function _putpage($n)\r
-{\r
- $this->_newobj();\r
- $this->_put('<</Type /Page');\r
- $this->_put('/Parent 1 0 R');\r
- if(isset($this->PageInfo[$n]['size']))\r
- $this->_put(sprintf('/MediaBox [0 0 %.2F %.2F]',$this->PageInfo[$n]['size'][0],$this->PageInfo[$n]['size'][1]));\r
- if(isset($this->PageInfo[$n]['rotation']))\r
- $this->_put('/Rotate '.$this->PageInfo[$n]['rotation']);\r
- $this->_put('/Resources 2 0 R');\r
- if(isset($this->PageLinks[$n]))\r
- {\r
- // Links\r
- $annots = '/Annots [';\r
- foreach($this->PageLinks[$n] as $pl)\r
- {\r
- $rect = sprintf('%.2F %.2F %.2F %.2F',$pl[0],$pl[1],$pl[0]+$pl[2],$pl[1]-$pl[3]);\r
- $annots .= '<</Type /Annot /Subtype /Link /Rect ['.$rect.'] /Border [0 0 0] ';\r
- if(is_string($pl[4]))\r
- $annots .= '/A <</S /URI /URI '.$this->_textstring($pl[4]).'>>>>';\r
- else\r
- {\r
- $l = $this->links[$pl[4]];\r
- if(isset($this->PageInfo[$l[0]]['size']))\r
- $h = $this->PageInfo[$l[0]]['size'][1];\r
- else\r
- $h = ($this->DefOrientation=='P') ? $this->DefPageSize[1]*$this->k : $this->DefPageSize[0]*$this->k;\r
- $annots .= sprintf('/Dest [%d 0 R /XYZ 0 %.2F null]>>',$this->PageInfo[$l[0]]['n'],$h-$l[1]*$this->k);\r
- }\r
- }\r
- $this->_put($annots.']');\r
- }\r
- if($this->WithAlpha)\r
- $this->_put('/Group <</Type /Group /S /Transparency /CS /DeviceRGB>>');\r
- $this->_put('/Contents '.($this->n+1).' 0 R>>');\r
- $this->_put('endobj');\r
- // Page content\r
- if(!empty($this->AliasNbPages))\r
- $this->pages[$n] = str_replace($this->AliasNbPages,$this->page,$this->pages[$n]);\r
- $this->_putstreamobject($this->pages[$n]);\r
-}\r
-\r
-protected function _putpages()\r
-{\r
- $nb = $this->page;\r
- for($n=1;$n<=$nb;$n++)\r
- $this->PageInfo[$n]['n'] = $this->n+1+2*($n-1);\r
- for($n=1;$n<=$nb;$n++)\r
- $this->_putpage($n);\r
- // Pages root\r
- $this->_newobj(1);\r
- $this->_put('<</Type /Pages');\r
- $kids = '/Kids [';\r
- for($n=1;$n<=$nb;$n++)\r
- $kids .= $this->PageInfo[$n]['n'].' 0 R ';\r
- $this->_put($kids.']');\r
- $this->_put('/Count '.$nb);\r
- if($this->DefOrientation=='P')\r
- {\r
- $w = $this->DefPageSize[0];\r
- $h = $this->DefPageSize[1];\r
- }\r
- else\r
- {\r
- $w = $this->DefPageSize[1];\r
- $h = $this->DefPageSize[0];\r
- }\r
- $this->_put(sprintf('/MediaBox [0 0 %.2F %.2F]',$w*$this->k,$h*$this->k));\r
- $this->_put('>>');\r
- $this->_put('endobj');\r
-}\r
-\r
-protected function _putfonts()\r
-{\r
- foreach($this->FontFiles as $file=>$info)\r
- {\r
- // Font file embedding\r
- $this->_newobj();\r
- $this->FontFiles[$file]['n'] = $this->n;\r
- $font = file_get_contents($this->fontpath.$file,true);\r
- if(!$font)\r
- $this->Error('Font file not found: '.$file);\r
- $compressed = (substr($file,-2)=='.z');\r
- if(!$compressed && isset($info['length2']))\r
- $font = substr($font,6,$info['length1']).substr($font,6+$info['length1']+6,$info['length2']);\r
- $this->_put('<</Length '.strlen($font));\r
- if($compressed)\r
- $this->_put('/Filter /FlateDecode');\r
- $this->_put('/Length1 '.$info['length1']);\r
- if(isset($info['length2']))\r
- $this->_put('/Length2 '.$info['length2'].' /Length3 0');\r
- $this->_put('>>');\r
- $this->_putstream($font);\r
- $this->_put('endobj');\r
- }\r
- foreach($this->fonts as $k=>$font)\r
- {\r
- // Encoding\r
- if(isset($font['diff']))\r
- {\r
- if(!isset($this->encodings[$font['enc']]))\r
- {\r
- $this->_newobj();\r
- $this->_put('<</Type /Encoding /BaseEncoding /WinAnsiEncoding /Differences ['.$font['diff'].']>>');\r
- $this->_put('endobj');\r
- $this->encodings[$font['enc']] = $this->n;\r
- }\r
- }\r
- // ToUnicode CMap\r
- if(isset($font['uv']))\r
- {\r
- if(isset($font['enc']))\r
- $cmapkey = $font['enc'];\r
- else\r
- $cmapkey = $font['name'];\r
- if(!isset($this->cmaps[$cmapkey]))\r
- {\r
- $cmap = $this->_tounicodecmap($font['uv']);\r
- $this->_putstreamobject($cmap);\r
- $this->cmaps[$cmapkey] = $this->n;\r
- }\r
- }\r
- // Font object\r
- $this->fonts[$k]['n'] = $this->n+1;\r
- $type = $font['type'];\r
- $name = $font['name'];\r
- if($font['subsetted'])\r
- $name = 'AAAAAA+'.$name;\r
- if($type=='Core')\r
- {\r
- // Core font\r
- $this->_newobj();\r
- $this->_put('<</Type /Font');\r
- $this->_put('/BaseFont /'.$name);\r
- $this->_put('/Subtype /Type1');\r
- if($name!='Symbol' && $name!='ZapfDingbats')\r
- $this->_put('/Encoding /WinAnsiEncoding');\r
- if(isset($font['uv']))\r
- $this->_put('/ToUnicode '.$this->cmaps[$cmapkey].' 0 R');\r
- $this->_put('>>');\r
- $this->_put('endobj');\r
- }\r
- elseif($type=='Type1' || $type=='TrueType')\r
- {\r
- // Additional Type1 or TrueType/OpenType font\r
- $this->_newobj();\r
- $this->_put('<</Type /Font');\r
- $this->_put('/BaseFont /'.$name);\r
- $this->_put('/Subtype /'.$type);\r
- $this->_put('/FirstChar 32 /LastChar 255');\r
- $this->_put('/Widths '.($this->n+1).' 0 R');\r
- $this->_put('/FontDescriptor '.($this->n+2).' 0 R');\r
- if(isset($font['diff']))\r
- $this->_put('/Encoding '.$this->encodings[$font['enc']].' 0 R');\r
- else\r
- $this->_put('/Encoding /WinAnsiEncoding');\r
- if(isset($font['uv']))\r
- $this->_put('/ToUnicode '.$this->cmaps[$cmapkey].' 0 R');\r
- $this->_put('>>');\r
- $this->_put('endobj');\r
- // Widths\r
- $this->_newobj();\r
- $cw = &$font['cw'];\r
- $s = '[';\r
- for($i=32;$i<=255;$i++)\r
- $s .= $cw[chr($i)].' ';\r
- $this->_put($s.']');\r
- $this->_put('endobj');\r
- // Descriptor\r
- $this->_newobj();\r
- $s = '<</Type /FontDescriptor /FontName /'.$name;\r
- foreach($font['desc'] as $k=>$v)\r
- $s .= ' /'.$k.' '.$v;\r
- if(!empty($font['file']))\r
- $s .= ' /FontFile'.($type=='Type1' ? '' : '2').' '.$this->FontFiles[$font['file']]['n'].' 0 R';\r
- $this->_put($s.'>>');\r
- $this->_put('endobj');\r
- }\r
- else\r
- {\r
- // Allow for additional types\r
- $mtd = '_put'.strtolower($type);\r
- if(!method_exists($this,$mtd))\r
- $this->Error('Unsupported font type: '.$type);\r
- $this->$mtd($font);\r
- }\r
- }\r
-}\r
-\r
-protected function _tounicodecmap($uv)\r
-{\r
- $ranges = '';\r
- $nbr = 0;\r
- $chars = '';\r
- $nbc = 0;\r
- foreach($uv as $c=>$v)\r
- {\r
- if(is_array($v))\r
- {\r
- $ranges .= sprintf("<%02X> <%02X> <%04X>\n",$c,$c+$v[1]-1,$v[0]);\r
- $nbr++;\r
- }\r
- else\r
- {\r
- $chars .= sprintf("<%02X> <%04X>\n",$c,$v);\r
- $nbc++;\r
- }\r
- }\r
- $s = "/CIDInit /ProcSet findresource begin\n";\r
- $s .= "12 dict begin\n";\r
- $s .= "begincmap\n";\r
- $s .= "/CIDSystemInfo\n";\r
- $s .= "<</Registry (Adobe)\n";\r
- $s .= "/Ordering (UCS)\n";\r
- $s .= "/Supplement 0\n";\r
- $s .= ">> def\n";\r
- $s .= "/CMapName /Adobe-Identity-UCS def\n";\r
- $s .= "/CMapType 2 def\n";\r
- $s .= "1 begincodespacerange\n";\r
- $s .= "<00> <FF>\n";\r
- $s .= "endcodespacerange\n";\r
- if($nbr>0)\r
- {\r
- $s .= "$nbr beginbfrange\n";\r
- $s .= $ranges;\r
- $s .= "endbfrange\n";\r
- }\r
- if($nbc>0)\r
- {\r
- $s .= "$nbc beginbfchar\n";\r
- $s .= $chars;\r
- $s .= "endbfchar\n";\r
- }\r
- $s .= "endcmap\n";\r
- $s .= "CMapName currentdict /CMap defineresource pop\n";\r
- $s .= "end\n";\r
- $s .= "end";\r
- return $s;\r
-}\r
-\r
-protected function _putimages()\r
-{\r
- foreach(array_keys($this->images) as $file)\r
- {\r
- $this->_putimage($this->images[$file]);\r
- unset($this->images[$file]['data']);\r
- unset($this->images[$file]['smask']);\r
- }\r
-}\r
-\r
-protected function _putimage(&$info)\r
-{\r
- $this->_newobj();\r
- $info['n'] = $this->n;\r
- $this->_put('<</Type /XObject');\r
- $this->_put('/Subtype /Image');\r
- $this->_put('/Width '.$info['w']);\r
- $this->_put('/Height '.$info['h']);\r
- if($info['cs']=='Indexed')\r
- $this->_put('/ColorSpace [/Indexed /DeviceRGB '.(strlen($info['pal'])/3-1).' '.($this->n+1).' 0 R]');\r
- else\r
- {\r
- $this->_put('/ColorSpace /'.$info['cs']);\r
- if($info['cs']=='DeviceCMYK')\r
- $this->_put('/Decode [1 0 1 0 1 0 1 0]');\r
- }\r
- $this->_put('/BitsPerComponent '.$info['bpc']);\r
- if(isset($info['f']))\r
- $this->_put('/Filter /'.$info['f']);\r
- if(isset($info['dp']))\r
- $this->_put('/DecodeParms <<'.$info['dp'].'>>');\r
- if(isset($info['trns']) && is_array($info['trns']))\r
- {\r
- $trns = '';\r
- for($i=0;$i<count($info['trns']);$i++)\r
- $trns .= $info['trns'][$i].' '.$info['trns'][$i].' ';\r
- $this->_put('/Mask ['.$trns.']');\r
- }\r
- if(isset($info['smask']))\r
- $this->_put('/SMask '.($this->n+1).' 0 R');\r
- $this->_put('/Length '.strlen($info['data']).'>>');\r
- $this->_putstream($info['data']);\r
- $this->_put('endobj');\r
- // Soft mask\r
- if(isset($info['smask']))\r
- {\r
- $dp = '/Predictor 15 /Colors 1 /BitsPerComponent 8 /Columns '.$info['w'];\r
- $smask = array('w'=>$info['w'], 'h'=>$info['h'], 'cs'=>'DeviceGray', 'bpc'=>8, 'f'=>$info['f'], 'dp'=>$dp, 'data'=>$info['smask']);\r
- $this->_putimage($smask);\r
- }\r
- // Palette\r
- if($info['cs']=='Indexed')\r
- $this->_putstreamobject($info['pal']);\r
-}\r
-\r
-protected function _putxobjectdict()\r
-{\r
- foreach($this->images as $image)\r
- $this->_put('/I'.$image['i'].' '.$image['n'].' 0 R');\r
-}\r
-\r
-protected function _putresourcedict()\r
-{\r
- $this->_put('/ProcSet [/PDF /Text /ImageB /ImageC /ImageI]');\r
- $this->_put('/Font <<');\r
- foreach($this->fonts as $font)\r
- $this->_put('/F'.$font['i'].' '.$font['n'].' 0 R');\r
- $this->_put('>>');\r
- $this->_put('/XObject <<');\r
- $this->_putxobjectdict();\r
- $this->_put('>>');\r
-}\r
-\r
-protected function _putresources()\r
-{\r
- $this->_putfonts();\r
- $this->_putimages();\r
- // Resource dictionary\r
- $this->_newobj(2);\r
- $this->_put('<<');\r
- $this->_putresourcedict();\r
- $this->_put('>>');\r
- $this->_put('endobj');\r
-}\r
-\r
-protected function _putinfo()\r
-{\r
- $this->metadata['Producer'] = 'FPDF '.FPDF_VERSION;\r
- $this->metadata['CreationDate'] = 'D:'.@date('YmdHis');\r
- foreach($this->metadata as $key=>$value)\r
- $this->_put('/'.$key.' '.$this->_textstring($value));\r
-}\r
-\r
-protected function _putcatalog()\r
-{\r
- $n = $this->PageInfo[1]['n'];\r
- $this->_put('/Type /Catalog');\r
- $this->_put('/Pages 1 0 R');\r
- if($this->ZoomMode=='fullpage')\r
- $this->_put('/OpenAction ['.$n.' 0 R /Fit]');\r
- elseif($this->ZoomMode=='fullwidth')\r
- $this->_put('/OpenAction ['.$n.' 0 R /FitH null]');\r
- elseif($this->ZoomMode=='real')\r
- $this->_put('/OpenAction ['.$n.' 0 R /XYZ null null 1]');\r
- elseif(!is_string($this->ZoomMode))\r
- $this->_put('/OpenAction ['.$n.' 0 R /XYZ null null '.sprintf('%.2F',$this->ZoomMode/100).']');\r
- if($this->LayoutMode=='single')\r
- $this->_put('/PageLayout /SinglePage');\r
- elseif($this->LayoutMode=='continuous')\r
- $this->_put('/PageLayout /OneColumn');\r
- elseif($this->LayoutMode=='two')\r
- $this->_put('/PageLayout /TwoColumnLeft');\r
-}\r
-\r
-protected function _putheader()\r
-{\r
- $this->_put('%PDF-'.$this->PDFVersion);\r
-}\r
-\r
-protected function _puttrailer()\r
-{\r
- $this->_put('/Size '.($this->n+1));\r
- $this->_put('/Root '.$this->n.' 0 R');\r
- $this->_put('/Info '.($this->n-1).' 0 R');\r
-}\r
-\r
-protected function _enddoc()\r
-{\r
- $this->_putheader();\r
- $this->_putpages();\r
- $this->_putresources();\r
- // Info\r
- $this->_newobj();\r
- $this->_put('<<');\r
- $this->_putinfo();\r
- $this->_put('>>');\r
- $this->_put('endobj');\r
- // Catalog\r
- $this->_newobj();\r
- $this->_put('<<');\r
- $this->_putcatalog();\r
- $this->_put('>>');\r
- $this->_put('endobj');\r
- // Cross-ref\r
- $offset = $this->_getoffset();\r
- $this->_put('xref');\r
- $this->_put('0 '.($this->n+1));\r
- $this->_put('0000000000 65535 f ');\r
- for($i=1;$i<=$this->n;$i++)\r
- $this->_put(sprintf('%010d 00000 n ',$this->offsets[$i]));\r
- // Trailer\r
- $this->_put('trailer');\r
- $this->_put('<<');\r
- $this->_puttrailer();\r
- $this->_put('>>');\r
- $this->_put('startxref');\r
- $this->_put($offset);\r
- $this->_put('%%EOF');\r
- $this->state = 3;\r
-}\r
-}\r
-?>\r