removed mods directory from the ATutor codebase
[atutor.git] / mods / pdf_converter / class.pdf.php
diff --git a/mods/pdf_converter/class.pdf.php b/mods/pdf_converter/class.pdf.php
deleted file mode 100644 (file)
index d8b720c..0000000
+++ /dev/null
@@ -1,3077 +0,0 @@
-<?php\r
-/**\r
-* Cpdf\r
-*\r
-* http://www.ros.co.nz/pdf\r
-*\r
-* A PHP class to provide the basic functionality to create a pdf document without\r
-* any requirement for additional modules.\r
-*\r
-* Note that they companion class CezPdf can be used to extend this class and dramatically\r
-* simplify the creation of documents.\r
-*\r
-* IMPORTANT NOTE\r
-* there is no warranty, implied or otherwise with this software.\r
-*\r
-* LICENCE\r
-* This code has been placed in the Public Domain for all to enjoy.\r
-*\r
-* @author              Wayne Munro <pdf@ros.co.nz>\r
-* @version     009\r
-* @package     Cpdf\r
-*/\r
-class Cpdf {\r
-\r
-/**\r
-* the current number of pdf objects in the document\r
-*/\r
-var $numObj=0;\r
-/**\r
-* this array contains all of the pdf objects, ready for final assembly\r
-*/\r
-var $objects = array();\r
-/**\r
-* the objectId (number within the objects array) of the document catalog\r
-*/\r
-var $catalogId;\r
-/**\r
-* array carrying information about the fonts that the system currently knows about\r
-* used to ensure that a font is not loaded twice, among other things\r
-*/\r
-var $fonts=array();\r
-/**\r
-* a record of the current font\r
-*/\r
-var $currentFont='';\r
-/**\r
-* the current base font\r
-*/\r
-var $currentBaseFont='';\r
-/**\r
-* the number of the current font within the font array\r
-*/\r
-var $currentFontNum=0;\r
-/**\r
-*\r
-*/\r
-var $currentNode;\r
-/**\r
-* object number of the current page\r
-*/\r
-var $currentPage;\r
-/**\r
-* object number of the currently active contents block\r
-*/\r
-var $currentContents;\r
-/**\r
-* number of fonts within the system\r
-*/\r
-var $numFonts=0;\r
-/**\r
-* current colour for fill operations, defaults to inactive value, all three components should be between 0 and 1 inclusive when active\r
-*/\r
-var $currentColour=array('r'=>-1,'g'=>-1,'b'=>-1);\r
-/**\r
-* current colour for stroke operations (lines etc.)\r
-*/\r
-var $currentStrokeColour=array('r'=>-1,'g'=>-1,'b'=>-1);\r
-/**\r
-* current style that lines are drawn in\r
-*/\r
-var $currentLineStyle='';\r
-/**\r
-* an array which is used to save the state of the document, mainly the colours and styles\r
-* it is used to temporarily change to another state, the change back to what it was before\r
-*/\r
-var $stateStack = array();\r
-/**\r
-* number of elements within the state stack\r
-*/\r
-var $nStateStack = 0;\r
-/**\r
-* number of page objects within the document\r
-*/\r
-var $numPages=0;\r
-/**\r
-* object Id storage stack\r
-*/\r
-var $stack=array();\r
-/**\r
-* number of elements within the object Id storage stack\r
-*/\r
-var $nStack=0;\r
-/**\r
-* an array which contains information about the objects which are not firmly attached to pages\r
-* these have been added with the addObject function\r
-*/\r
-var $looseObjects=array();\r
-/**\r
-* array contains infomation about how the loose objects are to be added to the document\r
-*/\r
-var $addLooseObjects=array();\r
-/**\r
-* the objectId of the information object for the document\r
-* this contains authorship, title etc.\r
-*/\r
-var $infoObject=0;\r
-/**\r
-* number of images being tracked within the document\r
-*/\r
-var $numImages=0;\r
-/**\r
-* an array containing options about the document\r
-* it defaults to turning on the compression of the objects\r
-*/\r
-var $options=array('compression'=>1);\r
-/**\r
-* the objectId of the first page of the document\r
-*/\r
-var $firstPageId;\r
-/**\r
-* used to track the last used value of the inter-word spacing, this is so that it is known\r
-* when the spacing is changed.\r
-*/\r
-var $wordSpaceAdjust=0;\r
-/**\r
-* the object Id of the procset object\r
-*/\r
-var $procsetObjectId;\r
-/**\r
-* store the information about the relationship between font families\r
-* this used so that the code knows which font is the bold version of another font, etc.\r
-* the value of this array is initialised in the constuctor function.\r
-*/\r
-var $fontFamilies = array();\r
-/**\r
-* track if the current font is bolded or italicised\r
-*/\r
-var $currentTextState = '';\r
-/**\r
-* messages are stored here during processing, these can be selected afterwards to give some useful debug information\r
-*/\r
-var $messages='';\r
-/**\r
-* the ancryption array for the document encryption is stored here\r
-*/\r
-var $arc4='';\r
-/**\r
-* the object Id of the encryption information\r
-*/\r
-var $arc4_objnum=0;\r
-/**\r
-* the file identifier, used to uniquely identify a pdf document\r
-*/\r
-var $fileIdentifier='';\r
-/**\r
-* a flag to say if a document is to be encrypted or not\r
-*/\r
-var $encrypted=0;\r
-/**\r
-* the ancryption key for the encryption of all the document content (structure is not encrypted)\r
-*/\r
-var $encryptionKey='';\r
-/**\r
-* array which forms a stack to keep track of nested callback functions\r
-*/\r
-var $callback = array();\r
-/**\r
-* the number of callback functions in the callback array\r
-*/\r
-var $nCallback = 0;\r
-/**\r
-* store label->id pairs for named destinations, these will be used to replace internal links\r
-* done this way so that destinations can be defined after the location that links to them\r
-*/\r
-var $destinations = array();\r
-/**\r
-* store the stack for the transaction commands, each item in here is a record of the values of all the\r
-* variables within the class, so that the user can rollback at will (from each 'start' command)\r
-* note that this includes the objects array, so these can be large.\r
-*/\r
-var $checkpoint = '';\r
-/**\r
-* class constructor\r
-* this will start a new document\r
-* @var array array of 4 numbers, defining the bottom left and upper right corner of the page. first two are normally zero.\r
-*/\r
-function Cpdf ($pageSize=array(0,0,612,792)){\r
-  $this->newDocument($pageSize);\r
-\r
-  // also initialize the font families that are known about already\r
-  $this->setFontFamily('init');\r
-//  $this->fileIdentifier = md5('xxxxxxxx'.time());\r
-\r
-}\r
-\r
-/**\r
-* Document object methods (internal use only)\r
-*\r
-* There is about one object method for each type of object in the pdf document\r
-* Each function has the same call list ($id,$action,$options).\r
-* $id = the object ID of the object, or what it is to be if it is being created\r
-* $action = a string specifying the action to be performed, though ALL must support:\r
-*                 'new' - create the object with the id $id\r
-*                 'out' - produce the output for the pdf object\r
-* $options = optional, a string or array containing the various parameters for the object\r
-*\r
-* These, in conjunction with the output function are the ONLY way for output to be produced\r
-* within the pdf 'file'.\r
-*/\r
-\r
-/**\r
-*destination object, used to specify the location for the user to jump to, presently on opening\r
-*/\r
-function o_destination($id,$action,$options=''){\r
-  if ($action!='new'){\r
-       $o =& $this->objects[$id];\r
-  }\r
-  switch($action){\r
-       case 'new':\r
-         $this->objects[$id]=array('t'=>'destination','info'=>array());\r
-         $tmp = '';\r
-         switch ($options['type']){\r
-               case 'XYZ':\r
-               case 'FitR':\r
-                 $tmp =  ' '.$options['p3'].$tmp;\r
-               case 'FitH':\r
-               case 'FitV':\r
-               case 'FitBH':\r
-               case 'FitBV':\r
-                 $tmp =  ' '.$options['p1'].' '.$options['p2'].$tmp;\r
-               case 'Fit':\r
-               case 'FitB':\r
-                 $tmp =  $options['type'].$tmp;\r
-                 $this->objects[$id]['info']['string']=$tmp;\r
-                 $this->objects[$id]['info']['page']=$options['page'];\r
-         }\r
-         break;\r
-       case 'out':\r
-         $tmp = $o['info'];\r
-         $res="\n".$id." 0 obj\n".'['.$tmp['page'].' 0 R /'.$tmp['string']."]\nendobj\n";\r
-         return $res;\r
-         break;\r
-  }\r
-}\r
-\r
-/**\r
-* set the viewer preferences\r
-*/\r
-function o_viewerPreferences($id,$action,$options=''){\r
-  if ($action!='new'){\r
-       $o =& $this->objects[$id];\r
-  }\r
-  switch ($action){\r
-       case 'new':\r
-         $this->objects[$id]=array('t'=>'viewerPreferences','info'=>array());\r
-         break;\r
-       case 'add':\r
-         foreach($options as $k=>$v){\r
-               switch ($k){\r
-                 case 'HideToolbar':\r
-                 case 'HideMenubar':\r
-                 case 'HideWindowUI':\r
-                 case 'FitWindow':\r
-                 case 'CenterWindow':\r
-                 case 'NonFullScreenPageMode':\r
-                 case 'Direction':\r
-                       $o['info'][$k]=$v;\r
-                 break;\r
-               }\r
-         }\r
-         break;\r
-       case 'out':\r
-\r
-         $res="\n".$id." 0 obj\n".'<< ';\r
-         foreach($o['info'] as $k=>$v){\r
-               $res.="\n/".$k.' '.$v;\r
-         }\r
-         $res.="\n>>\n";\r
-         return $res;\r
-         break;\r
-  }\r
-}\r
-\r
-/**\r
-* define the document catalog, the overall controller for the document\r
-*/\r
-function o_catalog($id,$action,$options=''){\r
-  if ($action!='new'){\r
-       $o =& $this->objects[$id];\r
-  }\r
-  switch ($action){\r
-       case 'new':\r
-         $this->objects[$id]=array('t'=>'catalog','info'=>array());\r
-         $this->catalogId=$id;\r
-         break;\r
-       case 'outlines':\r
-       case 'pages':\r
-       case 'openHere':\r
-         $o['info'][$action]=$options;\r
-         break;\r
-       case 'viewerPreferences':\r
-         if (!isset($o['info']['viewerPreferences'])){\r
-               $this->numObj++;\r
-               $this->o_viewerPreferences($this->numObj,'new');\r
-               $o['info']['viewerPreferences']=$this->numObj;\r
-         }\r
-         $vp = $o['info']['viewerPreferences'];\r
-         $this->o_viewerPreferences($vp,'add',$options);\r
-         break;\r
-       case 'out':\r
-         $res="\n".$id." 0 obj\n".'<< /Type /Catalog';\r
-         foreach($o['info'] as $k=>$v){\r
-               switch($k){\r
-                 case 'outlines':\r
-                       $res.="\n".'/Outlines '.$v.' 0 R';\r
-                       break;\r
-                 case 'pages':\r
-                       $res.="\n".'/Pages '.$v.' 0 R';\r
-                       break;\r
-                 case 'viewerPreferences':\r
-                       $res.="\n".'/ViewerPreferences '.$o['info']['viewerPreferences'].' 0 R';\r
-                       break;\r
-                 case 'openHere':\r
-                       $res.="\n".'/OpenAction '.$o['info']['openHere'].' 0 R';\r
-                       break;\r
-               }\r
-         }\r
-         $res.=" >>\nendobj";\r
-         return $res;\r
-         break;\r
-  }\r
-}\r
-\r
-/**\r
-* object which is a parent to the pages in the document\r
-*/\r
-function o_pages($id,$action,$options=''){\r
-  if ($action!='new'){\r
-       $o =& $this->objects[$id];\r
-  }\r
-  switch ($action){\r
-       case 'new':\r
-         $this->objects[$id]=array('t'=>'pages','info'=>array());\r
-         $this->o_catalog($this->catalogId,'pages',$id);\r
-         break;\r
-       case 'page':\r
-         if (!is_array($options)){\r
-               // then it will just be the id of the new page\r
-               $o['info']['pages'][]=$options;\r
-         } else {\r
-               // then it should be an array having 'id','rid','pos', where rid=the page to which this one will be placed relative\r
-               // and pos is either 'before' or 'after', saying where this page will fit.\r
-               if (isset($options['id']) && isset($options['rid']) && isset($options['pos'])){\r
-                 $i = array_search($options['rid'],$o['info']['pages']);\r
-                 if (isset($o['info']['pages'][$i]) && $o['info']['pages'][$i]==$options['rid']){\r
-                       // then there is a match\r
-                       // make a space\r
-                       switch ($options['pos']){\r
-                         case 'before':\r
-                               $k = $i;\r
-                               break;\r
-                         case 'after':\r
-                               $k=$i+1;\r
-                               break;\r
-                         default:\r
-                               $k=-1;\r
-                               break;\r
-                       }\r
-                       if ($k>=0){\r
-                         for ($j=count($o['info']['pages'])-1;$j>=$k;$j--){\r
-                               $o['info']['pages'][$j+1]=$o['info']['pages'][$j];\r
-                         }\r
-                         $o['info']['pages'][$k]=$options['id'];\r
-                       }\r
-                 }\r
-               }\r
-         }\r
-         break;\r
-       case 'procset':\r
-         $o['info']['procset']=$options;\r
-         break;\r
-       case 'mediaBox':\r
-         $o['info']['mediaBox']=$options; // which should be an array of 4 numbers\r
-         break;\r
-       case 'font':\r
-         $o['info']['fonts'][]=array('objNum'=>$options['objNum'],'fontNum'=>$options['fontNum']);\r
-         break;\r
-       case 'xObject':\r
-         $o['info']['xObjects'][]=array('objNum'=>$options['objNum'],'label'=>$options['label']);\r
-         break;\r
-       case 'out':\r
-         if (count($o['info']['pages'])){\r
-               $res="\n".$id." 0 obj\n<< /Type /Pages\n/Kids [";\r
-               foreach($o['info']['pages'] as $k=>$v){\r
-                 $res.=$v." 0 R\n";\r
-               }\r
-               $res.="]\n/Count ".count($this->objects[$id]['info']['pages']);\r
-               if ((isset($o['info']['fonts']) && count($o['info']['fonts'])) || isset($o['info']['procset'])){\r
-                 $res.="\n/Resources <<";\r
-                 if (isset($o['info']['procset'])){\r
-                       $res.="\n/ProcSet ".$o['info']['procset']." 0 R";\r
-                 }\r
-                 if (isset($o['info']['fonts']) && count($o['info']['fonts'])){\r
-                       $res.="\n/Font << ";\r
-                       foreach($o['info']['fonts'] as $finfo){\r
-                         $res.="\n/F".$finfo['fontNum']." ".$finfo['objNum']." 0 R";\r
-                       }\r
-                       $res.=" >>";\r
-                 }\r
-                 if (isset($o['info']['xObjects']) && count($o['info']['xObjects'])){\r
-                       $res.="\n/XObject << ";\r
-                       foreach($o['info']['xObjects'] as $finfo){\r
-                         $res.="\n/".$finfo['label']." ".$finfo['objNum']." 0 R";\r
-                       }\r
-                       $res.=" >>";\r
-                 }\r
-                 $res.="\n>>";\r
-                 if (isset($o['info']['mediaBox'])){\r
-                       $tmp=$o['info']['mediaBox'];\r
-                       $res.="\n/MediaBox [".sprintf('%.3f',$tmp[0]).' '.sprintf('%.3f',$tmp[1]).' '.sprintf('%.3f',$tmp[2]).' '.sprintf('%.3f',$tmp[3]).']';\r
-                 }\r
-               }\r
-               $res.="\n >>\nendobj";\r
-         } else {\r
-               $res="\n".$id." 0 obj\n<< /Type /Pages\n/Count 0\n>>\nendobj";\r
-         }\r
-         return $res;\r
-       break;\r
-  }\r
-}\r
-\r
-/**\r
-* define the outlines in the doc, empty for now\r
-*/\r
-function o_outlines($id,$action,$options=''){\r
-  if ($action!='new'){\r
-       $o =& $this->objects[$id];\r
-  }\r
-  switch ($action){\r
-       case 'new':\r
-         $this->objects[$id]=array('t'=>'outlines','info'=>array('outlines'=>array()));\r
-         $this->o_catalog($this->catalogId,'outlines',$id);\r
-         break;\r
-       case 'outline':\r
-         $o['info']['outlines'][]=$options;\r
-         break;\r
-       case 'out':\r
-         if (count($o['info']['outlines'])){\r
-               $res="\n".$id." 0 obj\n<< /Type /Outlines /Kids [";\r
-               foreach($o['info']['outlines'] as $k=>$v){\r
-                 $res.=$v." 0 R ";\r
-               }\r
-               $res.="] /Count ".count($o['info']['outlines'])." >>\nendobj";\r
-         } else {\r
-               $res="\n".$id." 0 obj\n<< /Type /Outlines /Count 0 >>\nendobj";\r
-         }\r
-         return $res;\r
-         break;\r
-  }\r
-}\r
-\r
-/**\r
-* an object to hold the font description\r
-*/\r
-function o_font($id,$action,$options=''){\r
-  if ($action!='new'){\r
-       $o =& $this->objects[$id];\r
-  }\r
-  switch ($action){\r
-       case 'new':\r
-         $this->objects[$id]=array('t'=>'font','info'=>array('name'=>$options['name'],'SubType'=>'Type1'));\r
-         $fontNum=$this->numFonts;\r
-         $this->objects[$id]['info']['fontNum']=$fontNum;\r
-         // deal with the encoding and the differences\r
-         if (isset($options['differences'])){\r
-               // then we'll need an encoding dictionary\r
-               $this->numObj++;\r
-               $this->o_fontEncoding($this->numObj,'new',$options);\r
-               $this->objects[$id]['info']['encodingDictionary']=$this->numObj;\r
-         } else if (isset($options['encoding'])){\r
-               // we can specify encoding here\r
-               switch($options['encoding']){\r
-                 case 'WinAnsiEncoding':\r
-                 case 'MacRomanEncoding':\r
-                 case 'MacExpertEncoding':\r
-                       $this->objects[$id]['info']['encoding']=$options['encoding'];\r
-                       break;\r
-                 case 'none':\r
-                       break;\r
-                 default:\r
-                       $this->objects[$id]['info']['encoding']='WinAnsiEncoding';\r
-                       break;\r
-               }\r
-         } else {\r
-               $this->objects[$id]['info']['encoding']='WinAnsiEncoding';\r
-         }\r
-         // also tell the pages node about the new font\r
-         $this->o_pages($this->currentNode,'font',array('fontNum'=>$fontNum,'objNum'=>$id));\r
-         break;\r
-       case 'add':\r
-         foreach ($options as $k=>$v){\r
-               switch ($k){\r
-                 case 'BaseFont':\r
-                       $o['info']['name'] = $v;\r
-                       break;\r
-                 case 'FirstChar':\r
-                 case 'LastChar':\r
-                 case 'Widths':\r
-                 case 'FontDescriptor':\r
-                 case 'SubType':\r
-                 $this->addMessage('o_font '.$k." : ".$v);\r
-                       $o['info'][$k] = $v;\r
-                       break;\r
-               }\r
-        }\r
-         break;\r
-       case 'out':\r
-         $res="\n".$id." 0 obj\n<< /Type /Font\n/Subtype /".$o['info']['SubType']."\n";\r
-         $res.="/Name /F".$o['info']['fontNum']."\n";\r
-         $res.="/BaseFont /".$o['info']['name']."\n";\r
-         if (isset($o['info']['encodingDictionary'])){\r
-               // then place a reference to the dictionary\r
-               $res.="/Encoding ".$o['info']['encodingDictionary']." 0 R\n";\r
-         } else if (isset($o['info']['encoding'])){\r
-               // use the specified encoding\r
-               $res.="/Encoding /".$o['info']['encoding']."\n";\r
-         }\r
-         if (isset($o['info']['FirstChar'])){\r
-               $res.="/FirstChar ".$o['info']['FirstChar']."\n";\r
-         }\r
-         if (isset($o['info']['LastChar'])){\r
-               $res.="/LastChar ".$o['info']['LastChar']."\n";\r
-         }\r
-         if (isset($o['info']['Widths'])){\r
-               $res.="/Widths ".$o['info']['Widths']." 0 R\n";\r
-         }\r
-         if (isset($o['info']['FontDescriptor'])){\r
-               $res.="/FontDescriptor ".$o['info']['FontDescriptor']." 0 R\n";\r
-         }\r
-         $res.=">>\nendobj";\r
-         return $res;\r
-         break;\r
-  }\r
-}\r
-\r
-/**\r
-* a font descriptor, needed for including additional fonts\r
-*/\r
-function o_fontDescriptor($id,$action,$options=''){\r
-  if ($action!='new'){\r
-       $o =& $this->objects[$id];\r
-  }\r
-  switch ($action){\r
-       case 'new':\r
-         $this->objects[$id]=array('t'=>'fontDescriptor','info'=>$options);\r
-         break;\r
-       case 'out':\r
-         $res="\n".$id." 0 obj\n<< /Type /FontDescriptor\n";\r
-         foreach ($o['info'] as $label => $value){\r
-               switch ($label){\r
-                 case 'Ascent':\r
-                 case 'CapHeight':\r
-                 case 'Descent':\r
-                 case 'Flags':\r
-                 case 'ItalicAngle':\r
-                 case 'StemV':\r
-                 case 'AvgWidth':\r
-                 case 'Leading':\r
-                 case 'MaxWidth':\r
-                 case 'MissingWidth':\r
-                 case 'StemH':\r
-                 case 'XHeight':\r
-                 case 'CharSet':\r
-                       if (strlen($value)){\r
-                         $res.='/'.$label.' '.$value."\n";\r
-                       }\r
-                       break;\r
-                 case 'FontFile':\r
-                 case 'FontFile2':\r
-                 case 'FontFile3':\r
-                       $res.='/'.$label.' '.$value." 0 R\n";\r
-                       break;\r
-                 case 'FontBBox':\r
-                       $res.='/'.$label.' ['.$value[0].' '.$value[1].' '.$value[2].' '.$value[3]."]\n";\r
-                       break;\r
-                 case 'FontName':\r
-                       $res.='/'.$label.' /'.$value."\n";\r
-                       break;\r
-               }\r
-         }\r
-         $res.=">>\nendobj";\r
-         return $res;\r
-         break;\r
-  }\r
-}\r
-\r
-/**\r
-* the font encoding\r
-*/\r
-function o_fontEncoding($id,$action,$options=''){\r
-  if ($action!='new'){\r
-       $o =& $this->objects[$id];\r
-  }\r
-  switch ($action){\r
-       case 'new':\r
-         // the options array should contain 'differences' and maybe 'encoding'\r
-         $this->objects[$id]=array('t'=>'fontEncoding','info'=>$options);\r
-         break;\r
-       case 'out':\r
-         $res="\n".$id." 0 obj\n<< /Type /Encoding\n";\r
-         if (!isset($o['info']['encoding'])){\r
-               $o['info']['encoding']='WinAnsiEncoding';\r
-         }\r
-         if ($o['info']['encoding']!='none'){\r
-               $res.="/BaseEncoding /".$o['info']['encoding']."\n";\r
-         }\r
-         $res.="/Differences \n[";\r
-         $onum=-100;\r
-         foreach($o['info']['differences'] as $num=>$label){\r
-               if ($num!=$onum+1){\r
-                 // we cannot make use of consecutive numbering\r
-                 $res.= "\n".$num." /".$label;\r
-               } else {\r
-                 $res.= " /".$label;\r
-               }\r
-               $onum=$num;\r
-         }\r
-         $res.="\n]\n>>\nendobj";\r
-         return $res;\r
-         break;\r
-  }\r
-}\r
-\r
-/**\r
-* the document procset, solves some problems with printing to old PS printers\r
-*/\r
-function o_procset($id,$action,$options=''){\r
-  if ($action!='new'){\r
-       $o =& $this->objects[$id];\r
-  }\r
-  switch ($action){\r
-       case 'new':\r
-         $this->objects[$id]=array('t'=>'procset','info'=>array('PDF'=>1,'Text'=>1));\r
-         $this->o_pages($this->currentNode,'procset',$id);\r
-         $this->procsetObjectId=$id;\r
-         break;\r
-       case 'add':\r
-         // this is to add new items to the procset list, despite the fact that this is considered\r
-         // obselete, the items are required for printing to some postscript printers\r
-         switch ($options) {\r
-               case 'ImageB':\r
-               case 'ImageC':\r
-               case 'ImageI':\r
-                 $o['info'][$options]=1;\r
-                 break;\r
-         }\r
-         break;\r
-       case 'out':\r
-         $res="\n".$id." 0 obj\n[";\r
-         foreach ($o['info'] as $label=>$val){\r
-               $res.='/'.$label.' ';\r
-         }\r
-         $res.="]\nendobj";\r
-         return $res;\r
-         break;\r
-  }\r
-}\r
-\r
-/**\r
-* define the document information\r
-*/\r
-function o_info($id,$action,$options=''){\r
-  if ($action!='new'){\r
-       $o =& $this->objects[$id];\r
-  }\r
-  switch ($action){\r
-       case 'new':\r
-         $this->infoObject=$id;\r
-         $date='D:'.date('Ymd');\r
-         $this->objects[$id]=array('t'=>'info','info'=>array('Creator'=>'R and OS php pdf writer, http://www.ros.co.nz','CreationDate'=>$date));\r
-         break;\r
-       case 'Title':\r
-       case 'Author':\r
-       case 'Subject':\r
-       case 'Keywords':\r
-       case 'Creator':\r
-       case 'Producer':\r
-       case 'CreationDate':\r
-       case 'ModDate':\r
-       case 'Trapped':\r
-         $o['info'][$action]=$options;\r
-         break;\r
-       case 'out':\r
-         if ($this->encrypted){\r
-               $this->encryptInit($id);\r
-         }\r
-         $res="\n".$id." 0 obj\n<<\n";\r
-         foreach ($o['info']  as $k=>$v){\r
-               $res.='/'.$k.' (';\r
-               if ($this->encrypted){\r
-                 $res.=$this->filterText($this->ARC4($v));\r
-               } else {\r
-                 $res.=$this->filterText($v);\r
-               }\r
-               $res.=")\n";\r
-         }\r
-         $res.=">>\nendobj";\r
-         return $res;\r
-         break;\r
-  }\r
-}\r
-\r
-/**\r
-* an action object, used to link to URLS initially\r
-*/\r
-function o_action($id,$action,$options=''){\r
-  if ($action!='new'){\r
-       $o =& $this->objects[$id];\r
-  }\r
-  switch ($action){\r
-       case 'new':\r
-         if (is_array($options)){\r
-               $this->objects[$id]=array('t'=>'action','info'=>$options,'type'=>$options['type']);\r
-         } else {\r
-               // then assume a URI action\r
-               $this->objects[$id]=array('t'=>'action','info'=>$options,'type'=>'URI');\r
-         }\r
-         break;\r
-       case 'out':\r
-         if ($this->encrypted){\r
-               $this->encryptInit($id);\r
-         }\r
-         $res="\n".$id." 0 obj\n<< /Type /Action";\r
-         switch($o['type']){\r
-               case 'ilink':\r
-                 // there will be an 'label' setting, this is the name of the destination\r
-                 $res.="\n/S /GoTo\n/D ".$this->destinations[(string)$o['info']['label']]." 0 R";\r
-                 break;\r
-               case 'URI':\r
-                 $res.="\n/S /URI\n/URI (";\r
-                 if ($this->encrypted){\r
-                       $res.=$this->filterText($this->ARC4($o['info']));\r
-                 } else {\r
-                       $res.=$this->filterText($o['info']);\r
-                 }\r
-                 $res.=")";\r
-                 break;\r
-         }\r
-         $res.="\n>>\nendobj";\r
-         return $res;\r
-         break;\r
-  }\r
-}\r
-\r
-/**\r
-* an annotation object, this will add an annotation to the current page.\r
-* initially will support just link annotations\r
-*/\r
-function o_annotation($id,$action,$options=''){\r
-  if ($action!='new'){\r
-       $o =& $this->objects[$id];\r
-  }\r
-  switch ($action){\r
-       case 'new':\r
-         // add the annotation to the current page\r
-         $pageId = $this->currentPage;\r
-         $this->o_page($pageId,'annot',$id);\r
-         // and add the action object which is going to be required\r
-         switch($options['type']){\r
-               case 'link':\r
-                 $this->objects[$id]=array('t'=>'annotation','info'=>$options);\r
-                 $this->numObj++;\r
-                 $this->o_action($this->numObj,'new',$options['url']);\r
-                 $this->objects[$id]['info']['actionId']=$this->numObj;\r
-                 break;\r
-               case 'ilink':\r
-                 // this is to a named internal link\r
-                 $label = $options['label'];\r
-                 $this->objects[$id]=array('t'=>'annotation','info'=>$options);\r
-                 $this->numObj++;\r
-                 $this->o_action($this->numObj,'new',array('type'=>'ilink','label'=>$label));\r
-                 $this->objects[$id]['info']['actionId']=$this->numObj;\r
-                 break;\r
-         }\r
-         break;\r
-       case 'out':\r
-         $res="\n".$id." 0 obj\n<< /Type /Annot";\r
-         switch($o['info']['type']){\r
-               case 'link':\r
-               case 'ilink':\r
-                 $res.= "\n/Subtype /Link";\r
-                 break;\r
-         }\r
-         $res.="\n/A ".$o['info']['actionId']." 0 R";\r
-         $res.="\n/Border [0 0 0]";\r
-         $res.="\n/H /I";\r
-         $res.="\n/Rect [ ";\r
-         foreach($o['info']['rect'] as $v){\r
-               $res.= sprintf("%.4f ",$v);\r
-         }\r
-         $res.="]";\r
-         $res.="\n>>\nendobj";\r
-         return $res;\r
-         break;\r
-  }\r
-}\r
-\r
-/**\r
-* a page object, it also creates a contents object to hold its contents\r
-*/\r
-function o_page($id,$action,$options=''){\r
-  if ($action!='new'){\r
-       $o =& $this->objects[$id];\r
-  }\r
-  switch ($action){\r
-       case 'new':\r
-         $this->numPages++;\r
-         $this->objects[$id]=array('t'=>'page','info'=>array('parent'=>$this->currentNode,'pageNum'=>$this->numPages));\r
-         if (is_array($options)){\r
-               // then this must be a page insertion, array shoudl contain 'rid','pos'=[before|after]\r
-               $options['id']=$id;\r
-               $this->o_pages($this->currentNode,'page',$options);\r
-         } else {\r
-               $this->o_pages($this->currentNode,'page',$id);\r
-         }\r
-         $this->currentPage=$id;\r
-         //make a contents object to go with this page\r
-         $this->numObj++;\r
-         $this->o_contents($this->numObj,'new',$id);\r
-         $this->currentContents=$this->numObj;\r
-         $this->objects[$id]['info']['contents']=array();\r
-         $this->objects[$id]['info']['contents'][]=$this->numObj;\r
-         $match = ($this->numPages%2 ? 'odd' : 'even');\r
-         foreach($this->addLooseObjects as $oId=>$target){\r
-               if ($target=='all' || $match==$target){\r
-                 $this->objects[$id]['info']['contents'][]=$oId;\r
-               }\r
-         }\r
-         break;\r
-       case 'content':\r
-         $o['info']['contents'][]=$options;\r
-         break;\r
-       case 'annot':\r
-         // add an annotation to this page\r
-         if (!isset($o['info']['annot'])){\r
-               $o['info']['annot']=array();\r
-         }\r
-         // $options should contain the id of the annotation dictionary\r
-         $o['info']['annot'][]=$options;\r
-         break;\r
-       case 'out':\r
-         $res="\n".$id." 0 obj\n<< /Type /Page";\r
-         $res.="\n/Parent ".$o['info']['parent']." 0 R";\r
-         if (isset($o['info']['annot'])){\r
-               $res.="\n/Annots [";\r
-               foreach($o['info']['annot'] as $aId){\r
-                 $res.=" ".$aId." 0 R";\r
-               }\r
-               $res.=" ]";\r
-         }\r
-         $count = count($o['info']['contents']);\r
-         if ($count==1){\r
-               $res.="\n/Contents ".$o['info']['contents'][0]." 0 R";\r
-         } else if ($count>1){\r
-               $res.="\n/Contents [\n";\r
-               foreach ($o['info']['contents'] as $cId){\r
-                 $res.=$cId." 0 R\n";\r
-               }\r
-               $res.="]";\r
-         }\r
-         $res.="\n>>\nendobj";\r
-         return $res;\r
-         break;\r
-  }\r
-}\r
-\r
-/**\r
-* the contents objects hold all of the content which appears on pages\r
-*/\r
-function o_contents($id,$action,$options=''){\r
-  if ($action!='new'){\r
-       $o =& $this->objects[$id];\r
-  }\r
-  switch ($action){\r
-       case 'new':\r
-         $this->objects[$id]=array('t'=>'contents','c'=>'','info'=>array());\r
-         if (strlen($options) && intval($options)){\r
-               // then this contents is the primary for a page\r
-               $this->objects[$id]['onPage']=$options;\r
-         } else if ($options=='raw'){\r
-               // then this page contains some other type of system object\r
-               $this->objects[$id]['raw']=1;\r
-         }\r
-         break;\r
-       case 'add':\r
-         // add more options to the decleration\r
-         foreach ($options as $k=>$v){\r
-               $o['info'][$k]=$v;\r
-         }\r
-       case 'out':\r
-         $tmp=$o['c'];\r
-         $res= "\n".$id." 0 obj\n";\r
-         if (isset($this->objects[$id]['raw'])){\r
-               $res.=$tmp;\r
-         } else {\r
-               $res.= "<<";\r
-               if (function_exists('gzcompress') && $this->options['compression']){\r
-                 // then implement ZLIB based compression on this content stream\r
-                 $res.=" /Filter /FlateDecode";\r
-                 $tmp = gzcompress($tmp);\r
-               }\r
-               if ($this->encrypted){\r
-                 $this->encryptInit($id);\r
-                 $tmp = $this->ARC4($tmp);\r
-               }\r
-               foreach($o['info'] as $k=>$v){\r
-                 $res .= "\n/".$k.' '.$v;\r
-               }\r
-               $res.="\n/Length ".strlen($tmp)." >>\nstream\n".$tmp."\nendstream";\r
-         }\r
-         $res.="\nendobj\n";\r
-         return $res;\r
-         break;\r
-  }\r
-}\r
-\r
-/**\r
-* an image object, will be an XObject in the document, includes description and data\r
-*/\r
-function o_image($id,$action,$options=''){\r
-  if ($action!='new'){\r
-       $o =& $this->objects[$id];\r
-  }\r
-  switch($action){\r
-       case 'new':\r
-         // make the new object\r
-         $this->objects[$id]=array('t'=>'image','data'=>$options['data'],'info'=>array());\r
-         $this->objects[$id]['info']['Type']='/XObject';\r
-         $this->objects[$id]['info']['Subtype']='/Image';\r
-         $this->objects[$id]['info']['Width']=$options['iw'];\r
-         $this->objects[$id]['info']['Height']=$options['ih'];\r
-         if (!isset($options['type']) || $options['type']=='jpg'){\r
-               if (!isset($options['channels'])){\r
-                 $options['channels']=3;\r
-               }\r
-               switch($options['channels']){\r
-                 case 1:\r
-                       $this->objects[$id]['info']['ColorSpace']='/DeviceGray';\r
-                       break;\r
-                 default:\r
-                       $this->objects[$id]['info']['ColorSpace']='/DeviceRGB';\r
-                       break;\r
-               }\r
-               $this->objects[$id]['info']['Filter']='/DCTDecode';\r
-               $this->objects[$id]['info']['BitsPerComponent']=8;\r
-         } else if ($options['type']=='png'){\r
-               $this->objects[$id]['info']['Filter']='/FlateDecode';\r
-               $this->objects[$id]['info']['DecodeParms']='<< /Predictor 15 /Colors '.$options['ncolor'].' /Columns '.$options['iw'].' /BitsPerComponent '.$options['bitsPerComponent'].'>>';\r
-               if (strlen($options['pdata'])){\r
-                 $tmp = ' [ /Indexed /DeviceRGB '.(strlen($options['pdata'])/3-1).' ';\r
-                 $this->numObj++;\r
-                 $this->o_contents($this->numObj,'new');\r
-                 $this->objects[$this->numObj]['c']=$options['pdata'];\r
-                 $tmp.=$this->numObj.' 0 R';\r
-                 $tmp .=' ]';\r
-                 $this->objects[$id]['info']['ColorSpace'] = $tmp;\r
-                 if (isset($options['transparency'])){\r
-                       switch($options['transparency']['type']){\r
-                         case 'indexed':\r
-                               $tmp=' [ '.$options['transparency']['data'].' '.$options['transparency']['data'].'] ';\r
-                               $this->objects[$id]['info']['Mask'] = $tmp;\r
-                               break;\r
-                       }\r
-                 }\r
-               } else {\r
-                 $this->objects[$id]['info']['ColorSpace']='/'.$options['color'];\r
-               }\r
-               $this->objects[$id]['info']['BitsPerComponent']=$options['bitsPerComponent'];\r
-         }\r
-         // assign it a place in the named resource dictionary as an external object, according to\r
-         // the label passed in with it.\r
-         $this->o_pages($this->currentNode,'xObject',array('label'=>$options['label'],'objNum'=>$id));\r
-         // also make sure that we have the right procset object for it.\r
-         $this->o_procset($this->procsetObjectId,'add','ImageC');\r
-         break;\r
-       case 'out':\r
-         $tmp=$o['data'];\r
-         $res= "\n".$id." 0 obj\n<<";\r
-         foreach($o['info'] as $k=>$v){\r
-               $res.="\n/".$k.' '.$v;\r
-         }\r
-         if ($this->encrypted){\r
-               $this->encryptInit($id);\r
-               $tmp = $this->ARC4($tmp);\r
-         }\r
-         $res.="\n/Length ".strlen($tmp)." >>\nstream\n".$tmp."\nendstream\nendobj\n";\r
-         return $res;\r
-         break;\r
-  }\r
-}\r
-\r
-/**\r
-* encryption object.\r
-*/\r
-function o_encryption($id,$action,$options=''){\r
-  if ($action!='new'){\r
-       $o =& $this->objects[$id];\r
-  }\r
-  switch($action){\r
-       case 'new':\r
-         // make the new object\r
-         $this->objects[$id]=array('t'=>'encryption','info'=>$options);\r
-         $this->arc4_objnum=$id;\r
-         // figure out the additional paramaters required\r
-         $pad = chr(0x28).chr(0xBF).chr(0x4E).chr(0x5E).chr(0x4E).chr(0x75).chr(0x8A).chr(0x41).chr(0x64).chr(0x00).chr(0x4E).chr(0x56).chr(0xFF).chr(0xFA).chr(0x01).chr(0x08).chr(0x2E).chr(0x2E).chr(0x00).chr(0xB6).chr(0xD0).chr(0x68).chr(0x3E).chr(0x80).chr(0x2F).chr(0x0C).chr(0xA9).chr(0xFE).chr(0x64).chr(0x53).chr(0x69).chr(0x7A);\r
-         $len = strlen($options['owner']);\r
-         if ($len>32){\r
-               $owner = substr($options['owner'],0,32);\r
-         } else if ($len<32){\r
-               $owner = $options['owner'].substr($pad,0,32-$len);\r
-         } else {\r
-               $owner = $options['owner'];\r
-         }\r
-         $len = strlen($options['user']);\r
-         if ($len>32){\r
-               $user = substr($options['user'],0,32);\r
-         } else if ($len<32){\r
-               $user = $options['user'].substr($pad,0,32-$len);\r
-         } else {\r
-               $user = $options['user'];\r
-         }\r
-         $tmp = $this->md5_16($owner);\r
-         $okey = substr($tmp,0,5);\r
-         $this->ARC4_init($okey);\r
-         $ovalue=$this->ARC4($user);\r
-         $this->objects[$id]['info']['O']=$ovalue;\r
-         // now make the u value, phew.\r
-         $tmp = $this->md5_16($user.$ovalue.chr($options['p']).chr(255).chr(255).chr(255).$this->fileIdentifier);\r
-         $ukey = substr($tmp,0,5);\r
-\r
-         $this->ARC4_init($ukey);\r
-         $this->encryptionKey = $ukey;\r
-         $this->encrypted=1;\r
-         $uvalue=$this->ARC4($pad);\r
-\r
-         $this->objects[$id]['info']['U']=$uvalue;\r
-         $this->encryptionKey=$ukey;\r
-\r
-         // initialize the arc4 array\r
-         break;\r
-       case 'out':\r
-         $res= "\n".$id." 0 obj\n<<";\r
-         $res.="\n/Filter /Standard";\r
-         $res.="\n/V 1";\r
-         $res.="\n/R 2";\r
-         $res.="\n/O (".$this->filterText($o['info']['O']).')';\r
-         $res.="\n/U (".$this->filterText($o['info']['U']).')';\r
-         // and the p-value needs to be converted to account for the twos-complement approach\r
-         $o['info']['p'] = (($o['info']['p']^255)+1)*-1;\r
-         $res.="\n/P ".($o['info']['p']);\r
-         $res.="\n>>\nendobj\n";\r
-\r
-         return $res;\r
-         break;\r
-  }\r
-}\r
-\r
-/**\r
-* ARC4 functions\r
-* A series of function to implement ARC4 encoding in PHP\r
-*/\r
-\r
-/**\r
-* calculate the 16 byte version of the 128 bit md5 digest of the string\r
-*/\r
-function md5_16($string){\r
-  $tmp = md5($string);\r
-  $out='';\r
-  for ($i=0;$i<=30;$i=$i+2){\r
-       $out.=chr(hexdec(substr($tmp,$i,2)));\r
-  }\r
-  return $out;\r
-}\r
-\r
-/**\r
-* initialize the encryption for processing a particular object\r
-*/\r
-function encryptInit($id){\r
-  $tmp = $this->encryptionKey;\r
-  $hex = dechex($id);\r
-  if (strlen($hex)<6){\r
-       $hex = substr('000000',0,6-strlen($hex)).$hex;\r
-  }\r
-  $tmp.= chr(hexdec(substr($hex,4,2))).chr(hexdec(substr($hex,2,2))).chr(hexdec(substr($hex,0,2))).chr(0).chr(0);\r
-  $key = $this->md5_16($tmp);\r
-  $this->ARC4_init(substr($key,0,10));\r
-}\r
-\r
-/**\r
-* initialize the ARC4 encryption\r
-*/\r
-function ARC4_init($key=''){\r
-  $this->arc4 = '';\r
-  // setup the control array\r
-  if (strlen($key)==0){\r
-       return;\r
-  }\r
-  $k = '';\r
-  while(strlen($k)<256){\r
-       $k.=$key;\r
-  }\r
-  $k=substr($k,0,256);\r
-  for ($i=0;$i<256;$i++){\r
-       $this->arc4 .= chr($i);\r
-  }\r
-  $j=0;\r
-  for ($i=0;$i<256;$i++){\r
-       $t = $this->arc4[$i];\r
-       $j = ($j + ord($t) + ord($k[$i]))%256;\r
-       $this->arc4[$i]=$this->arc4[$j];\r
-       $this->arc4[$j]=$t;\r
-  }\r
-}\r
-\r
-/**\r
-* ARC4 encrypt a text string\r
-*/\r
-function ARC4($text){\r
-  $len=strlen($text);\r
-  $a=0;\r
-  $b=0;\r
-  $c = $this->arc4;\r
-  $out='';\r
-  for ($i=0;$i<$len;$i++){\r
-       $a = ($a+1)%256;\r
-       $t= $c[$a];\r
-       $b = ($b+ord($t))%256;\r
-       $c[$a]=$c[$b];\r
-       $c[$b]=$t;\r
-       $k = ord($c[(ord($c[$a])+ord($c[$b]))%256]);\r
-       $out.=chr(ord($text[$i]) ^ $k);\r
-  }\r
-\r
-  return $out;\r
-}\r
-\r
-/**\r
-* functions which can be called to adjust or add to the document\r
-*/\r
-\r
-/**\r
-* add a link in the document to an external URL\r
-*/\r
-function addLink($url,$x0,$y0,$x1,$y1){\r
-  $this->numObj++;\r
-  $info = array('type'=>'link','url'=>$url,'rect'=>array($x0,$y0,$x1,$y1));\r
-  $this->o_annotation($this->numObj,'new',$info);\r
-}\r
-\r
-/**\r
-* add a link in the document to an internal destination (ie. within the document)\r
-*/\r
-function addInternalLink($label,$x0,$y0,$x1,$y1){\r
-  $this->numObj++;\r
-  $info = array('type'=>'ilink','label'=>$label,'rect'=>array($x0,$y0,$x1,$y1));\r
-  $this->o_annotation($this->numObj,'new',$info);\r
-}\r
-\r
-/**\r
-* set the encryption of the document\r
-* can be used to turn it on and/or set the passwords which it will have.\r
-* also the functions that the user will have are set here, such as print, modify, add\r
-*/\r
-function setEncryption($userPass='',$ownerPass='',$pc=array()){\r
-  $p=bindec(11000000);\r
-\r
-  $options = array(\r
-        'print'=>4\r
-       ,'modify'=>8\r
-       ,'copy'=>16\r
-       ,'add'=>32\r
-  );\r
-  foreach($pc as $k=>$v){\r
-       if ($v && isset($options[$k])){\r
-         $p+=$options[$k];\r
-       } else if (isset($options[$v])){\r
-         $p+=$options[$v];\r
-       }\r
-  }\r
-  // implement encryption on the document\r
-  if ($this->arc4_objnum == 0){\r
-       // then the block does not exist already, add it.\r
-       $this->numObj++;\r
-       if (strlen($ownerPass)==0){\r
-         $ownerPass=$userPass;\r
-       }\r
-       $this->o_encryption($this->numObj,'new',array('user'=>$userPass,'owner'=>$ownerPass,'p'=>$p));\r
-  }\r
-}\r
-\r
-/**\r
-* should be used for internal checks, not implemented as yet\r
-*/\r
-function checkAllHere(){\r
-}\r
-\r
-/**\r
-* return the pdf stream as a string returned from the function\r
-*/\r
-function output($debug=0){\r
-\r
-  if ($debug){\r
-       // turn compression off\r
-       $this->options['compression']=0;\r
-  }\r
-\r
-  if ($this->arc4_objnum){\r
-       $this->ARC4_init($this->encryptionKey);\r
-  }\r
-\r
-  $this->checkAllHere();\r
-\r
-  $xref=array();\r
-  $content="%PDF-1.3\n%����\n";\r
-//  $content="%PDF-1.3\n";\r
-  $pos=strlen($content);\r
-  foreach($this->objects as $k=>$v){\r
-       $tmp='o_'.$v['t'];\r
-       $cont=$this->$tmp($k,'out');\r
-       $content.=$cont;\r
-       $xref[]=$pos;\r
-       $pos+=strlen($cont);\r
-  }\r
-  $content.="\nxref\n0 ".(count($xref)+1)."\n0000000000 65535 f \n";\r
-  foreach($xref as $p){\r
-       $content.=substr('0000000000',0,10-strlen($p)).$p." 00000 n \n";\r
-  }\r
-  $content.="\ntrailer\n  << /Size ".(count($xref)+1)."\n       /Root 1 0 R\n   /Info ".$this->infoObject." 0 R\n";\r
-  // if encryption has been applied to this document then add the marker for this dictionary\r
-  if ($this->arc4_objnum > 0){\r
-       $content .= "/Encrypt ".$this->arc4_objnum." 0 R\n";\r
-  }\r
-  if (strlen($this->fileIdentifier)){\r
-       $content .= "/ID[<".$this->fileIdentifier."><".$this->fileIdentifier.">]\n";\r
-  }\r
-  $content .= "  >>\nstartxref\n".$pos."\n%%EOF\n";\r
-  return $content;\r
-}\r
-\r
-/**\r
-* intialize a new document\r
-* if this is called on an existing document results may be unpredictable, but the existing document would be lost at minimum\r
-* this function is called automatically by the constructor function\r
-*\r
-* @access private\r
-*/\r
-function newDocument($pageSize=array(0,0,612,792)){\r
-  $this->numObj=0;\r
-  $this->objects = array();\r
-\r
-  $this->numObj++;\r
-  $this->o_catalog($this->numObj,'new');\r
-\r
-  $this->numObj++;\r
-  $this->o_outlines($this->numObj,'new');\r
-\r
-  $this->numObj++;\r
-  $this->o_pages($this->numObj,'new');\r
-\r
-  $this->o_pages($this->numObj,'mediaBox',$pageSize);\r
-  $this->currentNode = 3;\r
-\r
-  $this->numObj++;\r
-  $this->o_procset($this->numObj,'new');\r
-\r
-  $this->numObj++;\r
-  $this->o_info($this->numObj,'new');\r
-\r
-  $this->numObj++;\r
-  $this->o_page($this->numObj,'new');\r
-\r
-  // need to store the first page id as there is no way to get it to the user during\r
-  // startup\r
-  $this->firstPageId = $this->currentContents;\r
-}\r
-\r
-/**\r
-* open the font file and return a php structure containing it.\r
-* first check if this one has been done before and saved in a form more suited to php\r
-* note that if a php serialized version does not exist it will try and make one, but will\r
-* require write access to the directory to do it... it is MUCH faster to have these serialized\r
-* files.\r
-*\r
-* @access private\r
-*/\r
-function openFont($font){\r
-  // assume that $font contains both the path and perhaps the extension to the file, split them\r
-  $pos=strrpos($font,'/');\r
-  if ($pos===false){\r
-       $dir = './media/';\r
-       $name = $font;\r
-  } else {\r
-       //$dir=substr($font,0,$pos+1);\r
-       $dir="./media/";\r
-       $name=substr($font,$pos+1);\r
-  }\r
-\r
-  if (substr($name,-4)=='.afm'){\r
-       $name=substr($name,0,strlen($name)-4);\r
-  }\r
-  $this->addMessage('openFont: '.$font.' - '.$name);\r
-  if (file_exists($dir.'php_'.$name.'.afm')){\r
-       $this->addMessage('openFont: php file exists '.$dir.'php_'.$name.'.afm');\r
-       $tmp = file($dir.'php_'.$name.'.afm');\r
-       $this->fonts[$font]=unserialize($tmp[0]);\r
-       if (!isset($this->fonts[$font]['_version_']) || $this->fonts[$font]['_version_']<1){\r
-         // if the font file is old, then clear it out and prepare for re-creation\r
-         $this->addMessage('openFont: clear out, make way for new version.');\r
-         unset($this->fonts[$font]);\r
-       }\r
-  }\r
-  if (!isset($this->fonts[$font]) && file_exists($dir.$name.'.afm')){\r
-       // then rebuild the php_<font>.afm file from the <font>.afm file\r
-       $this->addMessage('openFont: build php file from '.$dir.$name.'.afm');\r
-       $data = array();\r
-       $file = file($dir.$name.'.afm');\r
-       foreach ($file as $rowA){\r
-         $row=trim($rowA);\r
-         $pos=strpos($row,' ');\r
-         if ($pos){\r
-               // then there must be some keyword\r
-               $key = substr($row,0,$pos);\r
-               switch ($key){\r
-                 case 'FontName':\r
-                 case 'FullName':\r
-                 case 'FamilyName':\r
-                 case 'Weight':\r
-                 case 'ItalicAngle':\r
-                 case 'IsFixedPitch':\r
-                 case 'CharacterSet':\r
-                 case 'UnderlinePosition':\r
-                 case 'UnderlineThickness':\r
-                 case 'Version':\r
-                 case 'EncodingScheme':\r
-                 case 'CapHeight':\r
-                 case 'XHeight':\r
-                 case 'Ascender':\r
-                 case 'Descender':\r
-                 case 'StdHW':\r
-                 case 'StdVW':\r
-                 case 'StartCharMetrics':\r
-                       $data[$key]=trim(substr($row,$pos));\r
-                       break;\r
-                 case 'FontBBox':\r
-                       $data[$key]=explode(' ',trim(substr($row,$pos)));\r
-                       break;\r
-                 case 'C':\r
-                       //C 39 ; WX 222 ; N quoteright ; B 53 463 157 718 ;\r
-                       $bits=explode(';',trim($row));\r
-                       $dtmp=array();\r
-                       foreach($bits as $bit){\r
-                         $bits2 = explode(' ',trim($bit));\r
-                         if (strlen($bits2[0])){\r
-                               if (count($bits2)>2){\r
-                                 $dtmp[$bits2[0]]=array();\r
-                                 for ($i=1;$i<count($bits2);$i++){\r
-                                       $dtmp[$bits2[0]][]=$bits2[$i];\r
-                                 }\r
-                               } else if (count($bits2)==2){\r
-                                 $dtmp[$bits2[0]]=$bits2[1];\r
-                               }\r
-                         }\r
-                       }\r
-                       if ($dtmp['C']>=0){\r
-                         $data['C'][$dtmp['C']]=$dtmp;\r
-                         $data['C'][$dtmp['N']]=$dtmp;\r
-                       } else {\r
-                         $data['C'][$dtmp['N']]=$dtmp;\r
-                       }\r
-                       break;\r
-                 case 'KPX':\r
-                       //KPX Adieresis yacute -40\r
-                       $bits=explode(' ',trim($row));\r
-                       $data['KPX'][$bits[1]][$bits[2]]=$bits[3];\r
-                       break;\r
-               }\r
-         }\r
-       }\r
-       $data['_version_']=1;\r
-       $this->fonts[$font]=$data;\r
-       $fp = @fopen($dir.'php_'.$name.'.afm','w') or die ("Please make sure your \"media\" directory is writeable (CHMOD 777).");\r
-       fwrite($fp,serialize($data));\r
-       fclose($fp);\r
-       mosChmod($dir.'php_'.$name.'.afm');\r
-  } else if (!isset($this->fonts[$font])){\r
-       $this->addMessage('openFont: no font file found');\r
-//     echo 'Font not Found '.$font;\r
-  }\r
-}\r
-\r
-/**\r
-* if the font is not loaded then load it and make the required object\r
-* else just make it the current font\r
-* the encoding array can contain 'encoding'=> 'none','WinAnsiEncoding','MacRomanEncoding' or 'MacExpertEncoding'\r
-* note that encoding='none' will need to be used for symbolic fonts\r
-* and 'differences' => an array of mappings between numbers 0->255 and character names.\r
-*\r
-*/\r
-function selectFont($fontName,$encoding='',$set=1){\r
-  if (!isset($this->fonts[$fontName])){\r
-       // load the file\r
-       $this->openFont($fontName);\r
-       if (isset($this->fonts[$fontName])){\r
-         $this->numObj++;\r
-         $this->numFonts++;\r
-         $pos=strrpos($fontName,'/');\r
-//       $dir=substr($fontName,0,$pos+1);\r
-         $name=substr($fontName,$pos+1);\r
-         if (substr($name,-4)=='.afm'){\r
-               $name=substr($name,0,strlen($name)-4);\r
-         }\r
-         $options=array('name'=>$name);\r
-         if (is_array($encoding)){\r
-               // then encoding and differences might be set\r
-               if (isset($encoding['encoding'])){\r
-                 $options['encoding']=$encoding['encoding'];\r
-               }\r
-               if (isset($encoding['differences'])){\r
-                 $options['differences']=$encoding['differences'];\r
-               }\r
-         } else if (strlen($encoding)){\r
-               // then perhaps only the encoding has been set\r
-               $options['encoding']=$encoding;\r
-         }\r
-         $fontObj = $this->numObj;\r
-         $this->o_font($this->numObj,'new',$options);\r
-         $this->fonts[$fontName]['fontNum']=$this->numFonts;\r
-         // if this is a '.afm' font, and there is a '.pfa' file to go with it ( as there\r
-         // should be for all non-basic fonts), then load it into an object and put the\r
-         // references into the font object\r
-         $basefile = substr($fontName,0,strlen($fontName)-4);\r
-         if (file_exists($basefile.'.pfb')){\r
-               $fbtype = 'pfb';\r
-         } else if (file_exists($basefile.'.ttf')){\r
-               $fbtype = 'ttf';\r
-         } else {\r
-               $fbtype='';\r
-         }\r
-         $fbfile = $basefile.'.'.$fbtype;\r
-\r
-//       $pfbfile = substr($fontName,0,strlen($fontName)-4).'.pfb';\r
-//       $ttffile = substr($fontName,0,strlen($fontName)-4).'.ttf';\r
-         $this->addMessage('selectFont: checking for - '.$fbfile);\r
-         if (substr($fontName,-4)=='.afm' && strlen($fbtype) ){\r
-               $adobeFontName = $this->fonts[$fontName]['FontName'];\r
-//             $fontObj = $this->numObj;\r
-               $this->addMessage('selectFont: adding font file - '.$fbfile.' - '.$adobeFontName);\r
-               // find the array of fond widths, and put that into an object.\r
-               $firstChar = -1;\r
-               $lastChar = 0;\r
-               $widths = array();\r
-               foreach ($this->fonts[$fontName]['C'] as $num=>$d){\r
-                 if (intval($num)>0 || $num=='0'){\r
-                       if ($lastChar>0 && $num>$lastChar+1){\r
-                         for($i=$lastChar+1;$i<$num;$i++){\r
-                               $widths[] = 0;\r
-                         }\r
-                       }\r
-                       $widths[] = $d['WX'];\r
-                       if ($firstChar==-1){\r
-                         $firstChar = $num;\r
-                       }\r
-                       $lastChar = $num;\r
-                 }\r
-               }\r
-               // also need to adjust the widths for the differences array\r
-               if (isset($options['differences'])){\r
-                 foreach($options['differences'] as $charNum=>$charName){\r
-                       if ($charNum>$lastChar){\r
-                         for($i=$lastChar+1;$i<=$charNum;$i++){\r
-                               $widths[]=0;\r
-                         }\r
-                         $lastChar=$charNum;\r
-                       }\r
-                       if (isset($this->fonts[$fontName]['C'][$charName])){\r
-                         $widths[$charNum-$firstChar]=$this->fonts[$fontName]['C'][$charName]['WX'];\r
-                       }\r
-                 }\r
-               }\r
-               $this->addMessage('selectFont: FirstChar='.$firstChar);\r
-               $this->addMessage('selectFont: LastChar='.$lastChar);\r
-               $this->numObj++;\r
-               $this->o_contents($this->numObj,'new','raw');\r
-               $this->objects[$this->numObj]['c'].='[';\r
-               foreach($widths as $width){\r
-                 $this->objects[$this->numObj]['c'].=' '.$width;\r
-               }\r
-               $this->objects[$this->numObj]['c'].=' ]';\r
-               $widthid = $this->numObj;\r
-\r
-               // load the pfb file, and put that into an object too.\r
-               // note that pdf supports only binary format type 1 font files, though there is a\r
-               // simple utility to convert them from pfa to pfb.\r
-               $fp = fopen($fbfile,'rb');\r
-               $tmp = get_magic_quotes_runtime();\r
-               set_magic_quotes_runtime(0);\r
-               $data = fread($fp,filesize($fbfile));\r
-               set_magic_quotes_runtime($tmp);\r
-               fclose($fp);\r
-\r
-               // create the font descriptor\r
-               $this->numObj++;\r
-               $fontDescriptorId = $this->numObj;\r
-               $this->numObj++;\r
-               $pfbid = $this->numObj;\r
-               // determine flags (more than a little flakey, hopefully will not matter much)\r
-               $flags=0;\r
-               if ($this->fonts[$fontName]['ItalicAngle']!=0){ $flags+=pow(2,6); }\r
-               if ($this->fonts[$fontName]['IsFixedPitch']=='true'){ $flags+=1; }\r
-               $flags+=pow(2,5); // assume non-sybolic\r
-\r
-               $list = array('Ascent'=>'Ascender','CapHeight'=>'CapHeight','Descent'=>'Descender','FontBBox'=>'FontBBox','ItalicAngle'=>'ItalicAngle');\r
-               $fdopt = array(\r
-                'Flags'=>$flags\r
-                ,'FontName'=>$adobeFontName\r
-                ,'StemV'=>100  // don't know what the value for this should be!\r
-               );\r
-               foreach($list as $k=>$v){\r
-                 if (isset($this->fonts[$fontName][$v])){\r
-                       $fdopt[$k]=$this->fonts[$fontName][$v];\r
-                 }\r
-               }\r
-\r
-               if ($fbtype=='pfb'){\r
-                 $fdopt['FontFile']=$pfbid;\r
-               } else if ($fbtype=='ttf'){\r
-                 $fdopt['FontFile2']=$pfbid;\r
-               }\r
-               $this->o_fontDescriptor($fontDescriptorId,'new',$fdopt);\r
-\r
-               // embed the font program\r
-               $this->o_contents($this->numObj,'new');\r
-               $this->objects[$pfbid]['c'].=$data;\r
-               // determine the cruicial lengths within this file\r
-               if ($fbtype=='pfb'){\r
-                 $l1 = strpos($data,'eexec')+6;\r
-                 $l2 = strpos($data,'00000000')-$l1;\r
-                 $l3 = strlen($data)-$l2-$l1;\r
-                 $this->o_contents($this->numObj,'add',array('Length1'=>$l1,'Length2'=>$l2,'Length3'=>$l3));\r
-               } else if ($fbtype=='ttf'){\r
-                 $l1 = strlen($data);\r
-                 $this->o_contents($this->numObj,'add',array('Length1'=>$l1));\r
-               }\r
-\r
-\r
-               // tell the font object about all this new stuff\r
-               $tmp = array('BaseFont'=>$adobeFontName,'Widths'=>$widthid\r
-                                                                         ,'FirstChar'=>$firstChar,'LastChar'=>$lastChar\r
-                                                                         ,'FontDescriptor'=>$fontDescriptorId);\r
-               if ($fbtype=='ttf'){\r
-                 $tmp['SubType']='TrueType';\r
-               }\r
-               $this->addMessage('adding extra info to font.('.$fontObj.')');\r
-               foreach($tmp as $fk=>$fv){\r
-                 $this->addMessage($fk." : ".$fv);\r
-               }\r
-               $this->o_font($fontObj,'add',$tmp);\r
-\r
-         } else {\r
-               $this->addMessage('selectFont: pfb or ttf file not found, ok if this is one of the 14 standard fonts');\r
-         }\r
-\r
-\r
-         // also set the differences here, note that this means that these will take effect only the\r
-         //first time that a font is selected, else they are ignored\r
-         if (isset($options['differences'])){\r
-               $this->fonts[$fontName]['differences']=$options['differences'];\r
-         }\r
-       }\r
-  }\r
-  if ($set && isset($this->fonts[$fontName])){\r
-       // so if for some reason the font was not set in the last one then it will not be selected\r
-       $this->currentBaseFont=$fontName;\r
-       // the next line means that if a new font is selected, then the current text state will be\r
-       // applied to it as well.\r
-       $this->setCurrentFont();\r
-  }\r
-  return $this->currentFontNum;\r
-}\r
-\r
-/**\r
-* sets up the current font, based on the font families, and the current text state\r
-* note that this system is quite flexible, a <b><i> font can be completely different to a\r
-* <i><b> font, and even <b><b> will have to be defined within the family to have meaning\r
-* This function is to be called whenever the currentTextState is changed, it will update\r
-* the currentFont setting to whatever the appropriatte family one is.\r
-* If the user calls selectFont themselves then that will reset the currentBaseFont, and the currentFont\r
-* This function will change the currentFont to whatever it should be, but will not change the\r
-* currentBaseFont.\r
-*\r
-* @access private\r
-*/\r
-function setCurrentFont(){\r
-  if (strlen($this->currentBaseFont)==0){\r
-       // then assume an initial font\r
-       $this->selectFont('./fonts/Helvetica.afm');\r
-  }\r
-  $cf = substr($this->currentBaseFont,strrpos($this->currentBaseFont,'/')+1);\r
-  if (strlen($this->currentTextState)\r
-       && isset($this->fontFamilies[$cf])\r
-         && isset($this->fontFamilies[$cf][$this->currentTextState])){\r
-       // then we are in some state or another\r
-       // and this font has a family, and the current setting exists within it\r
-       // select the font, then return it\r
-       $nf = substr($this->currentBaseFont,0,strrpos($this->currentBaseFont,'/')+1).$this->fontFamilies[$cf][$this->currentTextState];\r
-       $this->selectFont($nf,'',0);\r
-       $this->currentFont = $nf;\r
-       $this->currentFontNum = $this->fonts[$nf]['fontNum'];\r
-  } else {\r
-       // the this font must not have the right family member for the current state\r
-       // simply assume the base font\r
-       $this->currentFont = $this->currentBaseFont;\r
-       $this->currentFontNum = $this->fonts[$this->currentFont]['fontNum'];\r
-  }\r
-}\r
-\r
-/**\r
-* function for the user to find out what the ID is of the first page that was created during\r
-* startup - useful if they wish to add something to it later.\r
-*/\r
-function getFirstPageId(){\r
-  return $this->firstPageId;\r
-}\r
-\r
-/**\r
-* add content to the currently active object\r
-*\r
-* @access private\r
-*/\r
-function addContent($content){\r
-  $this->objects[$this->currentContents]['c'].=$content;\r
-}\r
-\r
-/**\r
-* sets the colour for fill operations\r
-*/\r
-function setColor($r,$g,$b,$force=0){\r
-  if ($r>=0 && ($force || $r!=$this->currentColour['r'] || $g!=$this->currentColour['g'] || $b!=$this->currentColour['b'])){\r
-       $this->objects[$this->currentContents]['c'].="\n".sprintf('%.3f',$r).' '.sprintf('%.3f',$g).' '.sprintf('%.3f',$b).' rg';\r
-       $this->currentColour=array('r'=>$r,'g'=>$g,'b'=>$b);\r
-  }\r
-}\r
-\r
-/**\r
-* sets the colour for stroke operations\r
-*/\r
-function setStrokeColor($r,$g,$b,$force=0){\r
-  if ($r>=0 && ($force || $r!=$this->currentStrokeColour['r'] || $g!=$this->currentStrokeColour['g'] || $b!=$this->currentStrokeColour['b'])){\r
-       $this->objects[$this->currentContents]['c'].="\n".sprintf('%.3f',$r).' '.sprintf('%.3f',$g).' '.sprintf('%.3f',$b).' RG';\r
-       $this->currentStrokeColour=array('r'=>$r,'g'=>$g,'b'=>$b);\r
-  }\r
-}\r
-\r
-/**\r
-* draw a line from one set of coordinates to another\r
-*/\r
-function line($x1,$y1,$x2,$y2){\r
-  $this->objects[$this->currentContents]['c'].="\n".sprintf('%.3f',$x1).' '.sprintf('%.3f',$y1).' m '.sprintf('%.3f',$x2).' '.sprintf('%.3f',$y2).' l S';\r
-}\r
-\r
-/**\r
-* draw a bezier curve based on 4 control points\r
-*/\r
-function curve($x0,$y0,$x1,$y1,$x2,$y2,$x3,$y3){\r
-  // in the current line style, draw a bezier curve from (x0,y0) to (x3,y3) using the other two points\r
-  // as the control points for the curve.\r
-  $this->objects[$this->currentContents]['c'].="\n".sprintf('%.3f',$x0).' '.sprintf('%.3f',$y0).' m '.sprintf('%.3f',$x1).' '.sprintf('%.3f',$y1);\r
-  $this->objects[$this->currentContents]['c'].= ' '.sprintf('%.3f',$x2).' '.sprintf('%.3f',$y2).' '.sprintf('%.3f',$x3).' '.sprintf('%.3f',$y3).' c S';\r
-}\r
-\r
-/**\r
-* draw a part of an ellipse\r
-*/\r
-function partEllipse($x0,$y0,$astart,$afinish,$r1,$r2=0,$angle=0,$nSeg=8){\r
-  $this->ellipse($x0,$y0,$r1,$r2,$angle,$nSeg,$astart,$afinish,0);\r
-}\r
-\r
-/**\r
-* draw a filled ellipse\r
-*/\r
-function filledEllipse($x0,$y0,$r1,$r2=0,$angle=0,$nSeg=8,$astart=0,$afinish=360){\r
-  return $this->ellipse($x0,$y0,$r1,$r2=0,$angle,$nSeg,$astart,$afinish,1,1);\r
-}\r
-\r
-/**\r
-* draw an ellipse\r
-* note that the part and filled ellipse are just special cases of this function\r
-*\r
-* draws an ellipse in the current line style\r
-* centered at $x0,$y0, radii $r1,$r2\r
-* if $r2 is not set, then a circle is drawn\r
-* nSeg is not allowed to be less than 2, as this will simply draw a line (and will even draw a\r
-* pretty crappy shape at 2, as we are approximating with bezier curves.\r
-*/\r
-function ellipse($x0,$y0,$r1,$r2=0,$angle=0,$nSeg=8,$astart=0,$afinish=360,$close=1,$fill=0){\r
-  if ($r1==0){\r
-       return;\r
-  }\r
-  if ($r2==0){\r
-       $r2=$r1;\r
-  }\r
-  if ($nSeg<2){\r
-       $nSeg=2;\r
-  }\r
-\r
-  $astart = deg2rad((float)$astart);\r
-  $afinish = deg2rad((float)$afinish);\r
-  $totalAngle =$afinish-$astart;\r
-\r
-  $dt = $totalAngle/$nSeg;\r
-  $dtm = $dt/3;\r
-\r
-  if ($angle != 0){\r
-       $a = -1*deg2rad((float)$angle);\r
-       $tmp = "\n q ";\r
-       $tmp .= sprintf('%.3f',cos($a)).' '.sprintf('%.3f',(-1.0*sin($a))).' '.sprintf('%.3f',sin($a)).' '.sprintf('%.3f',cos($a)).' ';\r
-       $tmp .= sprintf('%.3f',$x0).' '.sprintf('%.3f',$y0).' cm';\r
-       $this->objects[$this->currentContents]['c'].= $tmp;\r
-       $x0=0;\r
-       $y0=0;\r
-  }\r
-\r
-  $t1 = $astart;\r
-  $a0 = $x0+$r1*cos($t1);\r
-  $b0 = $y0+$r2*sin($t1);\r
-  $c0 = -$r1*sin($t1);\r
-  $d0 = $r2*cos($t1);\r
-\r
-  $this->objects[$this->currentContents]['c'].="\n".sprintf('%.3f',$a0).' '.sprintf('%.3f',$b0).' m ';\r
-  for ($i=1;$i<=$nSeg;$i++){\r
-       // draw this bit of the total curve\r
-       $t1 = $i*$dt+$astart;\r
-       $a1 = $x0+$r1*cos($t1);\r
-       $b1 = $y0+$r2*sin($t1);\r
-       $c1 = -$r1*sin($t1);\r
-       $d1 = $r2*cos($t1);\r
-       $this->objects[$this->currentContents]['c'].="\n".sprintf('%.3f',($a0+$c0*$dtm)).' '.sprintf('%.3f',($b0+$d0*$dtm));\r
-       $this->objects[$this->currentContents]['c'].= ' '.sprintf('%.3f',($a1-$c1*$dtm)).' '.sprintf('%.3f',($b1-$d1*$dtm)).' '.sprintf('%.3f',$a1).' '.sprintf('%.3f',$b1).' c';\r
-       $a0=$a1;\r
-       $b0=$b1;\r
-       $c0=$c1;\r
-       $d0=$d1;\r
-  }\r
-  if ($fill){\r
-       $this->objects[$this->currentContents]['c'].=' f';\r
-  } else {\r
-       if ($close){\r
-         $this->objects[$this->currentContents]['c'].=' s'; // small 's' signifies closing the path as well\r
-       } else {\r
-         $this->objects[$this->currentContents]['c'].=' S';\r
-       }\r
-  }\r
-  if ($angle !=0){\r
-       $this->objects[$this->currentContents]['c'].=' Q';\r
-  }\r
-}\r
-\r
-/**\r
-* this sets the line drawing style.\r
-* width, is the thickness of the line in user units\r
-* cap is the type of cap to put on the line, values can be 'butt','round','square'\r
-*      where the diffference between 'square' and 'butt' is that 'square' projects a flat end past the\r
-*      end of the line.\r
-* join can be 'miter', 'round', 'bevel'\r
-* dash is an array which sets the dash pattern, is a series of length values, which are the lengths of the\r
-*   on and off dashes.\r
-*   (2) represents 2 on, 2 off, 2 on , 2 off ...\r
-*   (2,1) is 2 on, 1 off, 2 on, 1 off.. etc\r
-* phase is a modifier on the dash pattern which is used to shift the point at which the pattern starts.\r
-*/\r
-function setLineStyle($width=1,$cap='',$join='',$dash='',$phase=0){\r
-\r
-  // this is quite inefficient in that it sets all the parameters whenever 1 is changed, but will fix another day\r
-  $string = '';\r
-  if ($width>0){\r
-       $string.= $width.' w';\r
-  }\r
-  $ca = array('butt'=>0,'round'=>1,'square'=>2);\r
-  if (isset($ca[$cap])){\r
-       $string.= ' '.$ca[$cap].' J';\r
-  }\r
-  $ja = array('miter'=>0,'round'=>1,'bevel'=>2);\r
-  if (isset($ja[$join])){\r
-       $string.= ' '.$ja[$join].' j';\r
-  }\r
-  if (is_array($dash)){\r
-       $string.= ' [';\r
-       foreach ($dash as $len){\r
-         $string.=' '.$len;\r
-       }\r
-       $string.= ' ] '.$phase.' d';\r
-  }\r
-  $this->currentLineStyle = $string;\r
-  $this->objects[$this->currentContents]['c'].="\n".$string;\r
-}\r
-\r
-/**\r
-* draw a polygon, the syntax for this is similar to the GD polygon command\r
-*/\r
-function polygon($p,$np,$f=0){\r
-  $this->objects[$this->currentContents]['c'].="\n";\r
-  $this->objects[$this->currentContents]['c'].=sprintf('%.3f',$p[0]).' '.sprintf('%.3f',$p[1]).' m ';\r
-  for ($i=2;$i<$np*2;$i=$i+2){\r
-       $this->objects[$this->currentContents]['c'].= sprintf('%.3f',$p[$i]).' '.sprintf('%.3f',$p[$i+1]).' l ';\r
-  }\r
-  if ($f==1){\r
-       $this->objects[$this->currentContents]['c'].=' f';\r
-  } else {\r
-       $this->objects[$this->currentContents]['c'].=' S';\r
-  }\r
-}\r
-\r
-/**\r
-* a filled rectangle, note that it is the width and height of the rectangle which are the secondary paramaters, not\r
-* the coordinates of the upper-right corner\r
-*/\r
-function filledRectangle($x1,$y1,$width,$height){\r
-  $this->objects[$this->currentContents]['c'].="\n".sprintf('%.3f',$x1).' '.sprintf('%.3f',$y1).' '.sprintf('%.3f',$width).' '.sprintf('%.3f',$height).' re f';\r
-}\r
-\r
-/**\r
-* draw a rectangle, note that it is the width and height of the rectangle which are the secondary paramaters, not\r
-* the coordinates of the upper-right corner\r
-*/\r
-function rectangle($x1,$y1,$width,$height){\r
-  $this->objects[$this->currentContents]['c'].="\n".sprintf('%.3f',$x1).' '.sprintf('%.3f',$y1).' '.sprintf('%.3f',$width).' '.sprintf('%.3f',$height).' re S';\r
-}\r
-\r
-/**\r
-* add a new page to the document\r
-* this also makes the new page the current active object\r
-*/\r
-function newPage($insert=0,$id=0,$pos='after'){\r
-\r
-  // if there is a state saved, then go up the stack closing them\r
-  // then on the new page, re-open them with the right setings\r
-\r
-  if ($this->nStateStack){\r
-       for ($i=$this->nStateStack;$i>=1;$i--){\r
-         $this->restoreState($i);\r
-       }\r
-  }\r
-\r
-  $this->numObj++;\r
-  if ($insert){\r
-       // the id from the ezPdf class is the od of the contents of the page, not the page object itself\r
-       // query that object to find the parent\r
-       $rid = $this->objects[$id]['onPage'];\r
-       $opt= array('rid'=>$rid,'pos'=>$pos);\r
-       $this->o_page($this->numObj,'new',$opt);\r
-  } else {\r
-       $this->o_page($this->numObj,'new');\r
-  }\r
-  // if there is a stack saved, then put that onto the page\r
-  if ($this->nStateStack){\r
-       for ($i=1;$i<=$this->nStateStack;$i++){\r
-         $this->saveState($i);\r
-       }\r
-  }\r
-  // and if there has been a stroke or fill colour set, then transfer them\r
-  if ($this->currentColour['r']>=0){\r
-       $this->setColor($this->currentColour['r'],$this->currentColour['g'],$this->currentColour['b'],1);\r
-  }\r
-  if ($this->currentStrokeColour['r']>=0){\r
-       $this->setStrokeColor($this->currentStrokeColour['r'],$this->currentStrokeColour['g'],$this->currentStrokeColour['b'],1);\r
-  }\r
-\r
-  // if there is a line style set, then put this in too\r
-  if (strlen($this->currentLineStyle)){\r
-       $this->objects[$this->currentContents]['c'].="\n".$this->currentLineStyle;\r
-  }\r
-\r
-  // the call to the o_page object set currentContents to the present page, so this can be returned as the page id\r
-  return $this->currentContents;\r
-}\r
-\r
-/**\r
-* output the pdf code, streaming it to the browser\r
-* the relevant headers are set so that hopefully the browser will recognise it\r
-*/\r
-function stream($options=''){\r
-  // setting the options allows the adjustment of the headers\r
-  // values at the moment are:\r
-  // 'Content-Disposition'=>'filename'  - sets the filename, though not too sure how well this will\r
-  //           work as in my trial the browser seems to use the filename of the php file with .pdf on the end\r
-  // 'Accept-Ranges'=>1 or 0 - if this is not set to 1, then this header is not included, off by default\r
-  //   this header seems to have caused some problems despite tha fact that it is supposed to solve\r
-  //   them, so I am leaving it off by default.\r
-  // 'compress'=> 1 or 0 - apply content stream compression, this is on (1) by default\r
-  if (!is_array($options)){\r
-       $options=array();\r
-  }\r
-  if ( isset($options['compress']) && $options['compress']==0){\r
-       $tmp = $this->output(1);\r
-  } else {\r
-       $tmp = $this->output();\r
-  }\r
-  header("Content-type: application/pdf");\r
-  header("Content-Length: ".strlen(ltrim($tmp)));\r
-  $fileName = (isset($options['Content-Disposition'])?$options['Content-Disposition']:'file.pdf');\r
-  header("Content-Disposition: inline; filename=".$fileName);\r
-  if (isset($options['Accept-Ranges']) && $options['Accept-Ranges']==1){\r
-       header("Accept-Ranges: ".strlen(ltrim($tmp)));\r
-  }\r
-  echo ltrim($tmp);\r
-}\r
-\r
-/**\r
-* return the height in units of the current font in the given size\r
-*/\r
-function getFontHeight($size){\r
-  if (!$this->numFonts){\r
-       $this->selectFont('./fonts/Helvetica');\r
-  }\r
-  // for the current font, and the given size, what is the height of the font in user units\r
-  $h = $this->fonts[$this->currentFont]['FontBBox'][3]-$this->fonts[$this->currentFont]['FontBBox'][1];\r
-  return $size*$h/1000;\r
-}\r
-\r
-/**\r
-* return the font decender, this will normally return a negative number\r
-* if you add this number to the baseline, you get the level of the bottom of the font\r
-* it is in the pdf user units\r
-*/\r
-function getFontDecender($size){\r
-  // note that this will most likely return a negative value\r
-  if (!$this->numFonts){\r
-       $this->selectFont('./fonts/Helvetica');\r
-  }\r
-  $h = $this->fonts[$this->currentFont]['FontBBox'][1];\r
-  return $size*$h/1000;\r
-}\r
-\r
-/**\r
-* filter the text, this is applied to all text just before being inserted into the pdf document\r
-* it escapes the various things that need to be escaped, and so on\r
-*\r
-* @access private\r
-*/\r
-function filterText($text){\r
-  $text = str_replace('\\','\\\\',$text);\r
-  $text = str_replace('(','\(',$text);\r
-  $text = str_replace(')','\)',$text);\r
-  $text = str_replace('&lt;','<',$text);\r
-  $text = str_replace('&gt;','>',$text);\r
-  $text = str_replace('&#039;','\'',$text);\r
-  $text = str_replace('&quot;','"',$text);\r
-  $text = str_replace('&amp;','&',$text);\r
-\r
-  return $text;\r
-}\r
-\r
-/**\r
-* given a start position and information about how text is to be laid out, calculate where\r
-* on the page the text will end\r
-*\r
-* @access private\r
-*/\r
-function PRVTgetTextPosition($x,$y,$angle,$size,$wa,$text){\r
-  // given this information return an array containing x and y for the end position as elements 0 and 1\r
-  $w = $this->getTextWidth($size,$text);\r
-  // need to adjust for the number of spaces in this text\r
-  $words = explode(' ',$text);\r
-  $nspaces=count($words)-1;\r
-  $w += $wa*$nspaces;\r
-  $a = deg2rad((float)$angle);\r
-  return array(cos($a)*$w+$x,-sin($a)*$w+$y);\r
-}\r
-\r
-/**\r
-* wrapper function for PRVTcheckTextDirective1\r
-*\r
-* @access private\r
-*/\r
-function PRVTcheckTextDirective(&$text,$i,&$f){\r
-  $x=0;\r
-  $y=0;\r
-  return $this->PRVTcheckTextDirective1($text,$i,$f,0,$x,$y);\r
-}\r
-\r
-/**\r
-* checks if the text stream contains a control directive\r
-* if so then makes some changes and returns the number of characters involved in the directive\r
-* this has been re-worked to include everything neccesary to fins the current writing point, so that\r
-* the location can be sent to the callback function if required\r
-* if the directive does not require a font change, then $f should be set to 0\r
-*\r
-* @access private\r
-*/\r
-function PRVTcheckTextDirective1(&$text,$i,&$f,$final,&$x,&$y,$size=0,$angle=0,$wordSpaceAdjust=0){\r
-  $directive = 0;\r
-  $j=$i;\r
-  if ($text[$j]=='<'){\r
-       $j++;\r
-       switch($text[$j]){\r
-         case '/':\r
-               $j++;\r
-               if (strlen($text) <= $j){\r
-                 return $directive;\r
-               }\r
-               switch($text[$j]){\r
-                 case 'b':\r
-                 case 'i':\r
-                       $j++;\r
-                       if ($text[$j]=='>'){\r
-                         $p = strrpos($this->currentTextState,$text[$j-1]);\r
-                         if ($p !== false){\r
-                               // then there is one to remove\r
-                               $this->currentTextState = substr($this->currentTextState,0,$p).substr($this->currentTextState,$p+1);\r
-                         }\r
-                         $directive=$j-$i+1;\r
-                       }\r
-                       break;\r
-                 case 'c':\r
-                       // this this might be a callback function\r
-                       $j++;\r
-                       $k = strpos($text,'>',$j);\r
-                       if ($k!==false && $text[$j]==':'){\r
-                         // then this will be treated as a callback directive\r
-                         $directive = $k-$i+1;\r
-                         $f=0;\r
-                         // split the remainder on colons to get the function name and the paramater\r
-                         $tmp = substr($text,$j+1,$k-$j-1);\r
-                         $b1 = strpos($tmp,':');\r
-                         if ($b1!==false){\r
-                               $func = substr($tmp,0,$b1);\r
-                               $parm = substr($tmp,$b1+1);\r
-                         } else {\r
-                               $func=$tmp;\r
-                               $parm='';\r
-                         }\r
-                         if (!isset($func) || !strlen(trim($func))){\r
-                               $directive=0;\r
-                         } else {\r
-                               // only call the function if this is the final call\r
-                               if ($final){\r
-                                 // need to assess the text position, calculate the text width to this point\r
-                                 // can use getTextWidth to find the text width I think\r
-                                 $tmp = $this->PRVTgetTextPosition($x,$y,$angle,$size,$wordSpaceAdjust,substr($text,0,$i));\r
-                                 $info = array('x'=>$tmp[0],'y'=>$tmp[1],'angle'=>$angle,'status'=>'end','p'=>$parm,'nCallback'=>$this->nCallback);\r
-                                 $x=$tmp[0];\r
-                                 $y=$tmp[1];\r
-                                 $ret = $this->$func($info);\r
-                                 if (is_array($ret)){\r
-                                       // then the return from the callback function could set the position, to start with, later will do font colour, and font\r
-                                       foreach($ret as $rk=>$rv){\r
-                                         switch($rk){\r
-                                               case 'x':\r
-                                               case 'y':\r
-                                                 $$rk=$rv;\r
-                                                 break;\r
-                                         }\r
-                                       }\r
-                                 }\r
-                                 // also remove from to the stack\r
-                                 // for simplicity, just take from the end, fix this another day\r
-                                 $this->nCallback--;\r
-                                 if ($this->nCallback<0){\r
-                                       $this->nCallBack=0;\r
-                                 }\r
-                               }\r
-                         }\r
-                       }\r
-                       break;\r
-               }\r
-               break;\r
-         case 'b':\r
-         case 'i':\r
-               $j++;\r
-               if ($text[$j]=='>'){\r
-                 $this->currentTextState.=$text[$j-1];\r
-                 $directive=$j-$i+1;\r
-               }\r
-               break;\r
-         case 'C':\r
-               $noClose=1;\r
-         case 'c':\r
-               // this this might be a callback function\r
-               $j++;\r
-               $k = strpos($text,'>',$j);\r
-               if ($k!==false && $text[$j]==':'){\r
-                 // then this will be treated as a callback directive\r
-                 $directive = $k-$i+1;\r
-                 $f=0;\r
-                 // split the remainder on colons to get the function name and the paramater\r
-//               $bits = explode(':',substr($text,$j+1,$k-$j-1));\r
-                 $tmp = substr($text,$j+1,$k-$j-1);\r
-                 $b1 = strpos($tmp,':');\r
-                 if ($b1!==false){\r
-                       $func = substr($tmp,0,$b1);\r
-                       $parm = substr($tmp,$b1+1);\r
-                 } else {\r
-                       $func=$tmp;\r
-                       $parm='';\r
-                 }\r
-                 if (!isset($func) || !strlen(trim($func))){\r
-                       $directive=0;\r
-                 } else {\r
-                       // only call the function if this is the final call, ie, the one actually doing printing, not measurement\r
-                       if ($final){\r
-                         // need to assess the text position, calculate the text width to this point\r
-                         // can use getTextWidth to find the text width I think\r
-                         // also add the text height and decender\r
-                         $tmp = $this->PRVTgetTextPosition($x,$y,$angle,$size,$wordSpaceAdjust,substr($text,0,$i));\r
-                         $info = array('x'=>$tmp[0],'y'=>$tmp[1],'angle'=>$angle,'status'=>'start','p'=>$parm,'f'=>$func,'height'=>$this->getFontHeight($size),'decender'=>$this->getFontDecender($size));\r
-                         $x=$tmp[0];\r
-                         $y=$tmp[1];\r
-                         if (!isset($noClose) || !$noClose){\r
-                               // only add to the stack if this is a small 'c', therefore is a start-stop pair\r
-                               $this->nCallback++;\r
-                               $info['nCallback']=$this->nCallback;\r
-                               $this->callback[$this->nCallback]=$info;\r
-                         }\r
-                         $ret = $this->$func($info);\r
-                         if (is_array($ret)){\r
-                               // then the return from the callback function could set the position, to start with, later will do font colour, and font\r
-                               foreach($ret as $rk=>$rv){\r
-                                 switch($rk){\r
-                                       case 'x':\r
-                                       case 'y':\r
-                                         $$rk=$rv;\r
-                                         break;\r
-                                 }\r
-                               }\r
-                         }\r
-                       }\r
-                 }\r
-               }\r
-               break;\r
-       }\r
-  }\r
-  return $directive;\r
-}\r
-\r
-/**\r
-* add text to the document, at a specified location, size and angle on the page\r
-*/\r
-function addText($x,$y,$size,$text,$angle=0,$wordSpaceAdjust=0){\r
-  if (!$this->numFonts){$this->selectFont('./fonts/Helvetica');}\r
-\r
-  // if there are any open callbacks, then they should be called, to show the start of the line\r
-  if ($this->nCallback>0){\r
-       for ($i=$this->nCallback;$i>0;$i--){\r
-         // call each function\r
-         $info = array('x'=>$x,'y'=>$y,'angle'=>$angle,'status'=>'sol','p'=>$this->callback[$i]['p'],'nCallback'=>$this->callback[$i]['nCallback'],'height'=>$this->callback[$i]['height'],'decender'=>$this->callback[$i]['decender']);\r
-         $func = $this->callback[$i]['f'];\r
-         $this->$func($info);\r
-       }\r
-  }\r
-  if ($angle==0){\r
-       $this->objects[$this->currentContents]['c'].="\n".'BT '.sprintf('%.3f',$x).' '.sprintf('%.3f',$y).' Td';\r
-  } else {\r
-       $a = deg2rad((float)$angle);\r
-       $tmp = "\n".'BT ';\r
-       $tmp .= sprintf('%.3f',cos($a)).' '.sprintf('%.3f',(-1.0*sin($a))).' '.sprintf('%.3f',sin($a)).' '.sprintf('%.3f',cos($a)).' ';\r
-       $tmp .= sprintf('%.3f',$x).' '.sprintf('%.3f',$y).' Tm';\r
-       $this->objects[$this->currentContents]['c'] .= $tmp;\r
-  }\r
-  if ($wordSpaceAdjust!=0 || $wordSpaceAdjust != $this->wordSpaceAdjust){\r
-       $this->wordSpaceAdjust=$wordSpaceAdjust;\r
-       $this->objects[$this->currentContents]['c'].=' '.sprintf('%.3f',$wordSpaceAdjust).' Tw';\r
-  }\r
-  $len=strlen($text);\r
-  $start=0;\r
-  for ($i=0;$i<$len;$i++){\r
-       $f=1;\r
-       $directive = $this->PRVTcheckTextDirective($text,$i,$f);\r
-       if ($directive){\r
-         // then we should write what we need to\r
-         if ($i>$start){\r
-               $part = substr($text,$start,$i-$start);\r
-               $this->objects[$this->currentContents]['c'].=' /F'.$this->currentFontNum.' '.sprintf('%.1f',$size).' Tf ';\r
-               $this->objects[$this->currentContents]['c'].=' ('.$this->filterText($part).') Tj';\r
-         }\r
-         if ($f){\r
-               // then there was nothing drastic done here, restore the contents\r
-               $this->setCurrentFont();\r
-         } else {\r
-               $this->objects[$this->currentContents]['c'] .= ' ET';\r
-               $f=1;\r
-               $xp=$x;\r
-               $yp=$y;\r
-               $directive = $this->PRVTcheckTextDirective1($text,$i,$f,1,$xp,$yp,$size,$angle,$wordSpaceAdjust);\r
-\r
-               // restart the text object\r
-                 if ($angle==0){\r
-                       $this->objects[$this->currentContents]['c'].="\n".'BT '.sprintf('%.3f',$xp).' '.sprintf('%.3f',$yp).' Td';\r
-                 } else {\r
-                       $a = deg2rad((float)$angle);\r
-                       $tmp = "\n".'BT ';\r
-                       $tmp .= sprintf('%.3f',cos($a)).' '.sprintf('%.3f',(-1.0*sin($a))).' '.sprintf('%.3f',sin($a)).' '.sprintf('%.3f',cos($a)).' ';\r
-                       $tmp .= sprintf('%.3f',$xp).' '.sprintf('%.3f',$yp).' Tm';\r
-                       $this->objects[$this->currentContents]['c'] .= $tmp;\r
-                 }\r
-                 if ($wordSpaceAdjust!=0 || $wordSpaceAdjust != $this->wordSpaceAdjust){\r
-                       $this->wordSpaceAdjust=$wordSpaceAdjust;\r
-                       $this->objects[$this->currentContents]['c'].=' '.sprintf('%.3f',$wordSpaceAdjust).' Tw';\r
-                 }\r
-         }\r
-         // and move the writing point to the next piece of text\r
-         $i=$i+$directive-1;\r
-         $start=$i+1;\r
-       }\r
-\r
-  }\r
-  if ($start<$len){\r
-       $part = substr($text,$start);\r
-       $this->objects[$this->currentContents]['c'].=' /F'.$this->currentFontNum.' '.sprintf('%.1f',$size).' Tf ';\r
-       $this->objects[$this->currentContents]['c'].=' ('.$this->filterText($part).') Tj';\r
-  }\r
-  $this->objects[$this->currentContents]['c'].=' ET';\r
-\r
-  // if there are any open callbacks, then they should be called, to show the end of the line\r
-  if ($this->nCallback>0){\r
-       for ($i=$this->nCallback;$i>0;$i--){\r
-         // call each function\r
-         $tmp = $this->PRVTgetTextPosition($x,$y,$angle,$size,$wordSpaceAdjust,$text);\r
-         $info = array('x'=>$tmp[0],'y'=>$tmp[1],'angle'=>$angle,'status'=>'eol','p'=>$this->callback[$i]['p'],'nCallback'=>$this->callback[$i]['nCallback'],'height'=>$this->callback[$i]['height'],'decender'=>$this->callback[$i]['decender']);\r
-         $func = $this->callback[$i]['f'];\r
-         $this->$func($info);\r
-       }\r
-  }\r
-\r
-}\r
-\r
-/**\r
-* calculate how wide a given text string will be on a page, at a given size.\r
-* this can be called externally, but is alse used by the other class functions\r
-*/\r
-function getTextWidth($size,$text){\r
-  // this function should not change any of the settings, though it will need to\r
-  // track any directives which change during calculation, so copy them at the start\r
-  // and put them back at the end.\r
-  $store_currentTextState = $this->currentTextState;\r
-\r
-  if (!$this->numFonts){\r
-       $this->selectFont('./fonts/Helvetica');\r
-  }\r
-\r
-  // converts a number or a float to a string so it can get the width\r
-  $text = "$text";\r
-\r
-  // hmm, this is where it all starts to get tricky - use the font information to\r
-  // calculate the width of each character, add them up and convert to user units\r
-  $w=0;\r
-  $len=strlen($text);\r
-  $cf = $this->currentFont;\r
-  for ($i=0;$i<$len;$i++){\r
-       $f=1;\r
-       $directive = $this->PRVTcheckTextDirective($text,$i,$f);\r
-       if ($directive){\r
-         if ($f){\r
-               $this->setCurrentFont();\r
-               $cf = $this->currentFont;\r
-         }\r
-         $i=$i+$directive-1;\r
-       } else {\r
-         $char=ord($text[$i]);\r
-         if (isset($this->fonts[$cf]['differences'][$char])){\r
-               // then this character is being replaced by another\r
-               $name = $this->fonts[$cf]['differences'][$char];\r
-               if (isset($this->fonts[$cf]['C'][$name]['WX'])){\r
-                 $w+=$this->fonts[$cf]['C'][$name]['WX'];\r
-               }\r
-         } else if (isset($this->fonts[$cf]['C'][$char]['WX'])){\r
-               $w+=$this->fonts[$cf]['C'][$char]['WX'];\r
-         }\r
-       }\r
-  }\r
-\r
-  $this->currentTextState = $store_currentTextState;\r
-  $this->setCurrentFont();\r
-\r
-  return $w*$size/1000;\r
-}\r
-\r
-/**\r
-* do a part of the calculation for sorting out the justification of the text\r
-*\r
-* @access private\r
-*/\r
-function PRVTadjustWrapText($text,$actual,$width,&$x,&$adjust,$justification){\r
-  switch ($justification){\r
-       case 'left':\r
-         return;\r
-         break;\r
-       case 'right':\r
-         $x+=$width-$actual;\r
-         break;\r
-       case 'center':\r
-       case 'centre':\r
-         $x+=($width-$actual)/2;\r
-         break;\r
-       case 'full':\r
-         // count the number of words\r
-         $words = explode(' ',$text);\r
-         $nspaces=count($words)-1;\r
-         if ($nspaces>0){\r
-               $adjust = ($width-$actual)/$nspaces;\r
-         } else {\r
-               $adjust=0;\r
-         }\r
-         break;\r
-  }\r
-}\r
-\r
-/**\r
-* add text to the page, but ensure that it fits within a certain width\r
-* if it does not fit then put in as much as possible, splitting at word boundaries\r
-* and return the remainder.\r
-* justification and angle can also be specified for the text\r
-*/\r
-function addTextWrap($x,$y,$width,$size,$text,$justification='left',$angle=0,$test=0){\r
-  // this will display the text, and if it goes beyond the width $width, will backtrack to the\r
-  // previous space or hyphen, and return the remainder of the text.\r
-\r
-  // $justification can be set to 'left','right','center','centre','full'\r
-\r
-  // need to store the initial text state, as this will change during the width calculation\r
-  // but will need to be re-set before printing, so that the chars work out right\r
-  $store_currentTextState = $this->currentTextState;\r
-\r
-  if (!$this->numFonts){$this->selectFont('./fonts/Helvetica');}\r
-  if ($width<=0){\r
-       // error, pretend it printed ok, otherwise risking a loop\r
-       return '';\r
-  }\r
-  $w=0;\r
-  $break=0;\r
-  $breakWidth=0;\r
-  $len=strlen($text);\r
-  $cf = $this->currentFont;\r
-  $tw = $width/$size*1000;\r
-  for ($i=0;$i<$len;$i++){\r
-       $f=1;\r
-       $directive = $this->PRVTcheckTextDirective($text,$i,$f);\r
-       if ($directive){\r
-         if ($f){\r
-               $this->setCurrentFont();\r
-               $cf = $this->currentFont;\r
-         }\r
-         $i=$i+$directive-1;\r
-       } else {\r
-         $cOrd = ord($text[$i]);\r
-         if (isset($this->fonts[$cf]['differences'][$cOrd])){\r
-               // then this character is being replaced by another\r
-               $cOrd2 = $this->fonts[$cf]['differences'][$cOrd];\r
-         } else {\r
-               $cOrd2 = $cOrd;\r
-         }\r
-\r
-         if (isset($this->fonts[$cf]['C'][$cOrd2]['WX'])){\r
-               $w+=$this->fonts[$cf]['C'][$cOrd2]['WX'];\r
-         }\r
-         if ($w>$tw){\r
-               // then we need to truncate this line\r
-               if ($break>0){\r
-                 // then we have somewhere that we can split :)\r
-                 if ($text[$break]==' '){\r
-                       $tmp = substr($text,0,$break);\r
-                 } else {\r
-                       $tmp = substr($text,0,$break+1);\r
-                 }\r
-                 $adjust=0;\r
-                 $this->PRVTadjustWrapText($tmp,$breakWidth,$width,$x,$adjust,$justification);\r
-\r
-                 // reset the text state\r
-                 $this->currentTextState = $store_currentTextState;\r
-                 $this->setCurrentFont();\r
-                 if (!$test){\r
-                       $this->addText($x,$y,$size,$tmp,$angle,$adjust);\r
-                 }\r
-                 return substr($text,$break+1);\r
-               } else {\r
-                 // just split before the current character\r
-                 $tmp = substr($text,0,$i);\r
-                 $adjust=0;\r
-                 $ctmp=ord($text[$i]);\r
-                 if (isset($this->fonts[$cf]['differences'][$ctmp])){\r
-                       $ctmp=$this->fonts[$cf]['differences'][$ctmp];\r
-                 }\r
-                 $tmpw=($w-$this->fonts[$cf]['C'][$ctmp]['WX'])*$size/1000;\r
-                 $this->PRVTadjustWrapText($tmp,$tmpw,$width,$x,$adjust,$justification);\r
-                 // reset the text state\r
-                 $this->currentTextState = $store_currentTextState;\r
-                 $this->setCurrentFont();\r
-                 if (!$test){\r
-                       $this->addText($x,$y,$size,$tmp,$angle,$adjust);\r
-                 }\r
-                 return substr($text,$i);\r
-               }\r
-         }\r
-         if ($text[$i]=='-'){\r
-               $break=$i;\r
-               $breakWidth = $w*$size/1000;\r
-         }\r
-         if ($text[$i]==' '){\r
-               $break=$i;\r
-               $ctmp=ord($text[$i]);\r
-               if (isset($this->fonts[$cf]['differences'][$ctmp])){\r
-                 $ctmp=$this->fonts[$cf]['differences'][$ctmp];\r
-               }\r
-               $breakWidth = ($w-$this->fonts[$cf]['C'][$ctmp]['WX'])*$size/1000;\r
-         }\r
-       }\r
-  }\r
-  // then there was no need to break this line\r
-  if ($justification=='full'){\r
-       $justification='left';\r
-  }\r
-  $adjust=0;\r
-  $tmpw=$w*$size/1000;\r
-  $this->PRVTadjustWrapText($text,$tmpw,$width,$x,$adjust,$justification);\r
-  // reset the text state\r
-  $this->currentTextState = $store_currentTextState;\r
-  $this->setCurrentFont();\r
-  if (!$test){\r
-       $this->addText($x,$y,$size,$text,$angle,$adjust,$angle);\r
-  }\r
-  return '';\r
-}\r
-\r
-/**\r
-* this will be called at a new page to return the state to what it was on the\r
-* end of the previous page, before the stack was closed down\r
-* This is to get around not being able to have open 'q' across pages\r
-*\r
-*/\r
-function saveState($pageEnd=0){\r
-  if ($pageEnd){\r
-       // this will be called at a new page to return the state to what it was on the\r
-       // end of the previous page, before the stack was closed down\r
-       // This is to get around not being able to have open 'q' across pages\r
-       $opt = $this->stateStack[$pageEnd]; // ok to use this as stack starts numbering at 1\r
-       $this->setColor($opt['col']['r'],$opt['col']['g'],$opt['col']['b'],1);\r
-       $this->setStrokeColor($opt['str']['r'],$opt['str']['g'],$opt['str']['b'],1);\r
-       $this->objects[$this->currentContents]['c'].="\n".$opt['lin'];\r
-//     $this->currentLineStyle = $opt['lin'];\r
-  } else {\r
-       $this->nStateStack++;\r
-       $this->stateStack[$this->nStateStack]=array(\r
-         'col'=>$this->currentColour\r
-        ,'str'=>$this->currentStrokeColour\r
-        ,'lin'=>$this->currentLineStyle\r
-       );\r
-  }\r
-  $this->objects[$this->currentContents]['c'].="\nq";\r
-}\r
-\r
-/**\r
-* restore a previously saved state\r
-*/\r
-function restoreState($pageEnd=0){\r
-  if (!$pageEnd){\r
-       $n = $this->nStateStack;\r
-       $this->currentColour = $this->stateStack[$n]['col'];\r
-       $this->currentStrokeColour = $this->stateStack[$n]['str'];\r
-       $this->objects[$this->currentContents]['c'].="\n".$this->stateStack[$n]['lin'];\r
-       $this->currentLineStyle = $this->stateStack[$n]['lin'];\r
-       unset($this->stateStack[$n]);\r
-       $this->nStateStack--;\r
-  }\r
-  $this->objects[$this->currentContents]['c'].="\nQ";\r
-}\r
-\r
-/**\r
-* make a loose object, the output will go into this object, until it is closed, then will revert to\r
-* the current one.\r
-* this object will not appear until it is included within a page.\r
-* the function will return the object number\r
-*/\r
-function openObject(){\r
-  $this->nStack++;\r
-  $this->stack[$this->nStack]=array('c'=>$this->currentContents,'p'=>$this->currentPage);\r
-  // add a new object of the content type, to hold the data flow\r
-  $this->numObj++;\r
-  $this->o_contents($this->numObj,'new');\r
-  $this->currentContents=$this->numObj;\r
-  $this->looseObjects[$this->numObj]=1;\r
-\r
-  return $this->numObj;\r
-}\r
-\r
-/**\r
-* open an existing object for editing\r
-*/\r
-function reopenObject($id){\r
-   $this->nStack++;\r
-   $this->stack[$this->nStack]=array('c'=>$this->currentContents,'p'=>$this->currentPage);\r
-   $this->currentContents=$id;\r
-   // also if this object is the primary contents for a page, then set the current page to its parent\r
-   if (isset($this->objects[$id]['onPage'])){\r
-        $this->currentPage = $this->objects[$id]['onPage'];\r
-   }\r
-}\r
-\r
-/**\r
-* close an object\r
-*/\r
-function closeObject(){\r
-  // close the object, as long as there was one open in the first place, which will be indicated by\r
-  // an objectId on the stack.\r
-  if ($this->nStack>0){\r
-       $this->currentContents=$this->stack[$this->nStack]['c'];\r
-       $this->currentPage=$this->stack[$this->nStack]['p'];\r
-       $this->nStack--;\r
-       // easier to probably not worry about removing the old entries, they will be overwritten\r
-       // if there are new ones.\r
-  }\r
-}\r
-\r
-/**\r
-* stop an object from appearing on pages from this point on\r
-*/\r
-function stopObject($id){\r
-  // if an object has been appearing on pages up to now, then stop it, this page will\r
-  // be the last one that could contian it.\r
-  if (isset($this->addLooseObjects[$id])){\r
-       $this->addLooseObjects[$id]='';\r
-  }\r
-}\r
-\r
-/**\r
-* after an object has been created, it wil only show if it has been added, using this function.\r
-*/\r
-function addObject($id,$options='add'){\r
-  // add the specified object to the page\r
-  if (isset($this->looseObjects[$id]) && $this->currentContents!=$id){\r
-       // then it is a valid object, and it is not being added to itself\r
-       switch($options){\r
-         case 'all':\r
-               // then this object is to be added to this page (done in the next block) and\r
-               // all future new pages.\r
-               $this->addLooseObjects[$id]='all';\r
-         case 'add':\r
-               if (isset($this->objects[$this->currentContents]['onPage'])){\r
-                 // then the destination contents is the primary for the page\r
-                 // (though this object is actually added to that page)\r
-                 $this->o_page($this->objects[$this->currentContents]['onPage'],'content',$id);\r
-               }\r
-               break;\r
-         case 'even':\r
-               $this->addLooseObjects[$id]='even';\r
-               $pageObjectId=$this->objects[$this->currentContents]['onPage'];\r
-               if ($this->objects[$pageObjectId]['info']['pageNum']%2==0){\r
-                 $this->addObject($id); // hacky huh :)\r
-               }\r
-               break;\r
-         case 'odd':\r
-               $this->addLooseObjects[$id]='odd';\r
-               $pageObjectId=$this->objects[$this->currentContents]['onPage'];\r
-               if ($this->objects[$pageObjectId]['info']['pageNum']%2==1){\r
-                 $this->addObject($id); // hacky huh :)\r
-               }\r
-               break;\r
-         case 'next':\r
-               $this->addLooseObjects[$id]='all';\r
-               break;\r
-         case 'nexteven':\r
-               $this->addLooseObjects[$id]='even';\r
-               break;\r
-         case 'nextodd':\r
-               $this->addLooseObjects[$id]='odd';\r
-               break;\r
-       }\r
-  }\r
-}\r
-\r
-/**\r
-* add content to the documents info object\r
-*/\r
-function addInfo($label,$value=0){\r
-  // this will only work if the label is one of the valid ones.\r
-  // modify this so that arrays can be passed as well.\r
-  // if $label is an array then assume that it is key=>value pairs\r
-  // else assume that they are both scalar, anything else will probably error\r
-  if (is_array($label)){\r
-       foreach ($label as $l=>$v){\r
-         $this->o_info($this->infoObject,$l,$v);\r
-       }\r
-  } else {\r
-       $this->o_info($this->infoObject,$label,$value);\r
-  }\r
-}\r
-\r
-/**\r
-* set the viewer preferences of the document, it is up to the browser to obey these.\r
-*/\r
-function setPreferences($label,$value=0){\r
-  // this will only work if the label is one of the valid ones.\r
-  if (is_array($label)){\r
-       foreach ($label as $l=>$v){\r
-         $this->o_catalog($this->catalogId,'viewerPreferences',array($l=>$v));\r
-       }\r
-  } else {\r
-       $this->o_catalog($this->catalogId,'viewerPreferences',array($label=>$value));\r
-  }\r
-}\r
-\r
-/**\r
-* extract an integer from a position in a byte stream\r
-*\r
-* @access private\r
-*/\r
-function PRVT_getBytes(&$data,$pos,$num){\r
-  // return the integer represented by $num bytes from $pos within $data\r
-  $ret=0;\r
-  for ($i=0;$i<$num;$i++){\r
-       $ret=$ret*256;\r
-       $ret+=ord($data[$pos+$i]);\r
-  }\r
-  return $ret;\r
-}\r
-\r
-/**\r
-* add a PNG image into the document, from a file\r
-* this should work with remote files\r
-*/\r
-function addPngFromFile($file,$x,$y,$w=0,$h=0){\r
-  // read in a png file, interpret it, then add to the system\r
-  $error=0;\r
-  $tmp = get_magic_quotes_runtime();\r
-  set_magic_quotes_runtime(0);\r
-  $fp = @fopen($file,'rb');\r
-  if ($fp){\r
-       $data='';\r
-       while(!feof($fp)){\r
-         $data .= fread($fp,1024);\r
-       }\r
-       fclose($fp);\r
-  } else {\r
-       $error = 1;\r
-       $errormsg = 'trouble opening file: '.$file;\r
-  }\r
-  set_magic_quotes_runtime($tmp);\r
-\r
-  if (!$error){\r
-       $header = chr(137).chr(80).chr(78).chr(71).chr(13).chr(10).chr(26).chr(10);\r
-       if (substr($data,0,8)!=$header){\r
-         $error=1;\r
-         $errormsg = 'this file does not have a valid header';\r
-       }\r
-  }\r
-\r
-  if (!$error){\r
-       // set pointer\r
-       $p = 8;\r
-       $len = strlen($data);\r
-       // cycle through the file, identifying chunks\r
-       $haveHeader=0;\r
-       $info=array();\r
-       $idata='';\r
-       $pdata='';\r
-       while ($p<$len){\r
-         $chunkLen = $this->PRVT_getBytes($data,$p,4);\r
-         $chunkType = substr($data,$p+4,4);\r
-//       echo $chunkType.' - '.$chunkLen.'<br>';\r
-\r
-         switch($chunkType){\r
-               case 'IHDR':\r
-                 // this is where all the file information comes from\r
-                 $info['width']=$this->PRVT_getBytes($data,$p+8,4);\r
-                 $info['height']=$this->PRVT_getBytes($data,$p+12,4);\r
-                 $info['bitDepth']=ord($data[$p+16]);\r
-                 $info['colorType']=ord($data[$p+17]);\r
-                 $info['compressionMethod']=ord($data[$p+18]);\r
-                 $info['filterMethod']=ord($data[$p+19]);\r
-                 $info['interlaceMethod']=ord($data[$p+20]);\r
-//print_r($info);\r
-                 $haveHeader=1;\r
-                 if ($info['compressionMethod']!=0){\r
-                       $error=1;\r
-                       $errormsg = 'unsupported compression method';\r
-                 }\r
-                 if ($info['filterMethod']!=0){\r
-                       $error=1;\r
-                       $errormsg = 'unsupported filter method';\r
-                 }\r
-                 break;\r
-               case 'PLTE':\r
-                 $pdata.=substr($data,$p+8,$chunkLen);\r
-                 break;\r
-               case 'IDAT':\r
-                 $idata.=substr($data,$p+8,$chunkLen);\r
-                 break;\r
-               case 'tRNS':\r
-                 //this chunk can only occur once and it must occur after the PLTE chunk and before IDAT chunk\r
-                 //print "tRNS found, color type = ".$info['colorType']."<BR>";\r
-                 $transparency = array();\r
-                 if ($info['colorType'] == 3) { // indexed color, rbg\r
-                 /* corresponding to entries in the plte chunk\r
-                 Alpha for palette index 0: 1 byte\r
-                 Alpha for palette index 1: 1 byte\r
-                 ...etc...\r
-                 */\r
-                       // there will be one entry for each palette entry. up until the last non-opaque entry.\r
-                       // set up an array, stretching over all palette entries which will be o (opaque) or 1 (transparent)\r
-                       $transparency['type']='indexed';\r
-                       $numPalette = strlen($pdata)/3;\r
-                       $trans=0;\r
-                       for ($i=$chunkLen;$i>=0;$i--){\r
-                         if (ord($data[$p+8+$i])==0){\r
-                               $trans=$i;\r
-                         }\r
-                       }\r
-                       $transparency['data'] = $trans;\r
-\r
-                 } elseif($info['colorType'] == 0) { // grayscale\r
-                 /* corresponding to entries in the plte chunk\r
-                 Gray: 2 bytes, range 0 .. (2^bitdepth)-1\r
-                 */\r
-//                     $transparency['grayscale']=$this->PRVT_getBytes($data,$p+8,2); // g = grayscale\r
-                       $transparency['type']='indexed';\r
-                       $transparency['data'] = ord($data[$p+8+1]);\r
-\r
-                 } elseif($info['colorType'] == 2) { // truecolor\r
-                 /* corresponding to entries in the plte chunk\r
-                 Red: 2 bytes, range 0 .. (2^bitdepth)-1\r
-                 Green: 2 bytes, range 0 .. (2^bitdepth)-1\r
-                 Blue: 2 bytes, range 0 .. (2^bitdepth)-1\r
-                 */\r
-                       $transparency['r']=$this->PRVT_getBytes($data,$p+8,2); // r from truecolor\r
-                       $transparency['g']=$this->PRVT_getBytes($data,$p+10,2); // g from truecolor\r
-                       $transparency['b']=$this->PRVT_getBytes($data,$p+12,2); // b from truecolor\r
-\r
-                 } else {\r
-                 //unsupported transparency type\r
-                 }\r
-                 // KS End new code\r
-                 break;\r
-               default:\r
-                 break;\r
-         }\r
-\r
-         $p += $chunkLen+12;\r
-       }\r
-\r
-       if(!$haveHeader){\r
-         $error = 1;\r
-         $errormsg = 'information header is missing';\r
-       }\r
-       if (isset($info['interlaceMethod']) && $info['interlaceMethod']){\r
-         $error = 1;\r
-         $errormsg = 'There appears to be no support for interlaced images in pdf.';\r
-       }\r
-  }\r
-\r
-  if (!$error && $info['bitDepth'] > 8){\r
-       $error = 1;\r
-       $errormsg = 'only bit depth of 8 or less is supported';\r
-  }\r
-\r
-  if (!$error){\r
-       if ($info['colorType']!=2 && $info['colorType']!=0 && $info['colorType']!=3){\r
-         $error = 1;\r
-         $errormsg = 'transparancey alpha channel not supported, transparency only supported for palette images.';\r
-       } else {\r
-         switch ($info['colorType']){\r
-               case 3:\r
-                 $color = 'DeviceRGB';\r
-                 $ncolor=1;\r
-                 break;\r
-               case 2:\r
-                 $color = 'DeviceRGB';\r
-                 $ncolor=3;\r
-                 break;\r
-               case 0:\r
-                 $color = 'DeviceGray';\r
-                 $ncolor=1;\r
-                 break;\r
-         }\r
-       }\r
-  }\r
-  if ($error){\r
-       $this->addMessage('PNG error - ('.$file.') '.$errormsg);\r
-       return;\r
-  }\r
-  if ($w==0){\r
-       $w=$h/$info['height']*$info['width'];\r
-  }\r
-  if ($h==0){\r
-       $h=$w*$info['height']/$info['width'];\r
-  }\r
-//print_r($info);\r
-  // so this image is ok... add it in.\r
-  $this->numImages++;\r
-  $im=$this->numImages;\r
-  $label='I'.$im;\r
-  $this->numObj++;\r
-//  $this->o_image($this->numObj,'new',array('label'=>$label,'data'=>$idata,'iw'=>$w,'ih'=>$h,'type'=>'png','ic'=>$info['width']));\r
-  $options = array('label'=>$label,'data'=>$idata,'bitsPerComponent'=>$info['bitDepth'],'pdata'=>$pdata\r
-                                                                         ,'iw'=>$info['width'],'ih'=>$info['height'],'type'=>'png','color'=>$color,'ncolor'=>$ncolor);\r
-  if (isset($transparency)){\r
-       $options['transparency']=$transparency;\r
-  }\r
-  $this->o_image($this->numObj,'new',$options);\r
-\r
-  $this->objects[$this->currentContents]['c'].="\nq";\r
-  $this->objects[$this->currentContents]['c'].="\n".sprintf('%.3f',$w)." 0 0 ".sprintf('%.3f',$h)." ".sprintf('%.3f',$x)." ".sprintf('%.3f',$y)." cm";\r
-  $this->objects[$this->currentContents]['c'].="\n/".$label.' Do';\r
-  $this->objects[$this->currentContents]['c'].="\nQ";\r
-}\r
-\r
-/**\r
-* add a JPEG image into the document, from a file\r
-*/\r
-function addJpegFromFile($img,$x,$y,$w=0,$h=0){\r
-  // attempt to add a jpeg image straight from a file, using no GD commands\r
-  // note that this function is unable to operate on a remote file.\r
-\r
-  if (!file_exists($img)){\r
-       return;\r
-  }\r
-\r
-  $tmp=getimagesize($img);\r
-  $imageWidth=$tmp[0];\r
-  $imageHeight=$tmp[1];\r
-\r
-  if (isset($tmp['channels'])){\r
-       $channels = $tmp['channels'];\r
-  } else {\r
-       $channels = 3;\r
-  }\r
-\r
-  if ($w<=0 && $h<=0){\r
-       $w=$imageWidth;\r
-  }\r
-  if ($w==0){\r
-       $w=$h/$imageHeight*$imageWidth;\r
-  }\r
-  if ($h==0){\r
-       $h=$w*$imageHeight/$imageWidth;\r
-  }\r
-\r
-  $fp=fopen($img,'rb');\r
-\r
-  $tmp = get_magic_quotes_runtime();\r
-  set_magic_quotes_runtime(0);\r
-  $data = fread($fp,filesize($img));\r
-  set_magic_quotes_runtime($tmp);\r
-\r
-  fclose($fp);\r
-\r
-  $this->addJpegImage_common($data,$x,$y,$w,$h,$imageWidth,$imageHeight,$channels);\r
-}\r
-\r
-/**\r
-* add an image into the document, from a GD object\r
-* this function is not all that reliable, and I would probably encourage people to use\r
-* the file based functions\r
-*/\r
-function addImage(&$img,$x,$y,$w=0,$h=0,$quality=75){\r
-  // add a new image into the current location, as an external object\r
-  // add the image at $x,$y, and with width and height as defined by $w & $h\r
-\r
-  // note that this will only work with full colour images and makes them jpg images for display\r
-  // later versions could present lossless image formats if there is interest.\r
-\r
-  // there seems to be some problem here in that images that have quality set above 75 do not appear\r
-  // not too sure why this is, but in the meantime I have restricted this to 75.\r
-  if ($quality>75){\r
-       $quality=75;\r
-  }\r
-\r
-  // if the width or height are set to zero, then set the other one based on keeping the image\r
-  // height/width ratio the same, if they are both zero, then give up :)\r
-  $imageWidth=imagesx($img);\r
-  $imageHeight=imagesy($img);\r
-\r
-  if ($w<=0 && $h<=0){\r
-       return;\r
-  }\r
-  if ($w==0){\r
-       $w=$h/$imageHeight*$imageWidth;\r
-  }\r
-  if ($h==0){\r
-       $h=$w*$imageHeight/$imageWidth;\r
-  }\r
-\r
-  // gotta get the data out of the img..\r
-\r
-  // so I write to a temp file, and then read it back.. soo ugly, my apologies.\r
-  $tmpDir='/tmp';\r
-  $tmpName=tempnam($tmpDir,'img');\r
-  imagejpeg($img,$tmpName,$quality);\r
-  $fp=fopen($tmpName,'rb');\r
-\r
-  $tmp = get_magic_quotes_runtime();\r
-  set_magic_quotes_runtime(0);\r
-  $fp = @fopen($tmpName,'rb');\r
-  if ($fp){\r
-       $data='';\r
-       while(!feof($fp)){\r
-         $data .= fread($fp,1024);\r
-       }\r
-       fclose($fp);\r
-  } else {\r
-       $error = 1;\r
-       $errormsg = 'trouble opening file';\r
-  }\r
-//  $data = fread($fp,filesize($tmpName));\r
-  set_magic_quotes_runtime($tmp);\r
-//  fclose($fp);\r
-  unlink($tmpName);\r
-  $this->addJpegImage_common($data,$x,$y,$w,$h,$imageWidth,$imageHeight);\r
-}\r
-\r
-/**\r
-* common code used by the two JPEG adding functions\r
-*\r
-* @access private\r
-*/\r
-function addJpegImage_common(&$data,$x,$y,$w=0,$h=0,$imageWidth,$imageHeight,$channels=3){\r
-  // note that this function is not to be called externally\r
-  // it is just the common code between the GD and the file options\r
-  $this->numImages++;\r
-  $im=$this->numImages;\r
-  $label='I'.$im;\r
-  $this->numObj++;\r
-  $this->o_image($this->numObj,'new',array('label'=>$label,'data'=>$data,'iw'=>$imageWidth,'ih'=>$imageHeight,'channels'=>$channels));\r
-\r
-  $this->objects[$this->currentContents]['c'].="\nq";\r
-  $this->objects[$this->currentContents]['c'].="\n".sprintf('%.3f',$w)." 0 0 ".sprintf('%.3f',$h)." ".sprintf('%.3f',$x)." ".sprintf('%.3f',$y)." cm";\r
-  $this->objects[$this->currentContents]['c'].="\n/".$label.' Do';\r
-  $this->objects[$this->currentContents]['c'].="\nQ";\r
-}\r
-\r
-/**\r
-* specify where the document should open when it first starts\r
-*/\r
-function openHere($style,$a=0,$b=0,$c=0){\r
-  // this function will open the document at a specified page, in a specified style\r
-  // the values for style, and the required paramters are:\r
-  // 'XYZ'  left, top, zoom\r
-  // 'Fit'\r
-  // 'FitH' top\r
-  // 'FitV' left\r
-  // 'FitR' left,bottom,right\r
-  // 'FitB'\r
-  // 'FitBH' top\r
-  // 'FitBV' left\r
-  $this->numObj++;\r
-  $this->o_destination($this->numObj,'new',array('page'=>$this->currentPage,'type'=>$style,'p1'=>$a,'p2'=>$b,'p3'=>$c));\r
-  $id = $this->catalogId;\r
-  $this->o_catalog($id,'openHere',$this->numObj);\r
-}\r
-\r
-/**\r
-* create a labelled destination within the document\r
-*/\r
-function addDestination($label,$style,$a=0,$b=0,$c=0){\r
-  // associates the given label with the destination, it is done this way so that a destination can be specified after\r
-  // it has been linked to\r
-  // styles are the same as the 'openHere' function\r
-  $this->numObj++;\r
-  $this->o_destination($this->numObj,'new',array('page'=>$this->currentPage,'type'=>$style,'p1'=>$a,'p2'=>$b,'p3'=>$c));\r
-  $id = $this->numObj;\r
-  // store the label->idf relationship, note that this means that labels can be used only once\r
-  $this->destinations["$label"]=$id;\r
-}\r
-\r
-/**\r
-* define font families, this is used to initialize the font families for the default fonts\r
-* and for the user to add new ones for their fonts. The default bahavious can be overridden should\r
-* that be desired.\r
-*/\r
-function setFontFamily($family,$options=''){\r
-  if (!is_array($options)){\r
-       if ($family=='init'){\r
-         // set the known family groups\r
-         // these font families will be used to enable bold and italic markers to be included\r
-         // within text streams. html forms will be used... <b></b> <i></i>\r
-         $this->fontFamilies['Helvetica.afm']=array(\r
-                'b'=>'Helvetica-Bold.afm'\r
-               ,'i'=>'Helvetica-Oblique.afm'\r
-               ,'bi'=>'Helvetica-BoldOblique.afm'\r
-               ,'ib'=>'Helvetica-BoldOblique.afm'\r
-         );\r
-         $this->fontFamilies['Courier.afm']=array(\r
-                'b'=>'Courier-Bold.afm'\r
-               ,'i'=>'Courier-Oblique.afm'\r
-               ,'bi'=>'Courier-BoldOblique.afm'\r
-               ,'ib'=>'Courier-BoldOblique.afm'\r
-         );\r
-         $this->fontFamilies['Times-Roman.afm']=array(\r
-                'b'=>'Times-Bold.afm'\r
-               ,'i'=>'Times-Italic.afm'\r
-               ,'bi'=>'Times-BoldItalic.afm'\r
-               ,'ib'=>'Times-BoldItalic.afm'\r
-         );\r
-       }\r
-  } else {\r
-       // the user is trying to set a font family\r
-       // note that this can also be used to set the base ones to something else\r
-       if (strlen($family)){\r
-         $this->fontFamilies[$family] = $options;\r
-       }\r
-  }\r
-}\r
-\r
-/**\r
-* used to add messages for use in debugging\r
-*/\r
-function addMessage($message){\r
-  $this->messages.=$message."\n";\r
-}\r
-\r
-/**\r
-* a few functions which should allow the document to be treated transactionally.\r
-*/\r
-function transaction($action){\r
-  switch ($action){\r
-       case 'start':\r
-         // store all the data away into the checkpoint variable\r
-         $data = get_object_vars($this);\r
-         $this->checkpoint = $data;\r
-         unset($data);\r
-         break;\r
-       case 'commit':\r
-         if (is_array($this->checkpoint) && isset($this->checkpoint['checkpoint'])){\r
-               $tmp = $this->checkpoint['checkpoint'];\r
-               $this->checkpoint = $tmp;\r
-               unset($tmp);\r
-         } else {\r
-               $this->checkpoint='';\r
-         }\r
-         break;\r
-       case 'rewind':\r
-         // do not destroy the current checkpoint, but move us back to the state then, so that we can try again\r
-         if (is_array($this->checkpoint)){\r
-               // can only abort if were inside a checkpoint\r
-               $tmp = $this->checkpoint;\r
-               foreach ($tmp as $k=>$v){\r
-                 if ($k != 'checkpoint'){\r
-                       $this->$k=$v;\r
-                 }\r
-               }\r
-               unset($tmp);\r
-         }\r
-         break;\r
-       case 'abort':\r
-         if (is_array($this->checkpoint)){\r
-               // can only abort if were inside a checkpoint\r
-               $tmp = $this->checkpoint;\r
-               foreach ($tmp as $k=>$v){\r
-                 $this->$k=$v;\r
-               }\r
-               unset($tmp);\r
-         }\r
-         break;\r
-  }\r
-\r
-}\r
-\r
-} // end of class\r
-\r
-?>
\ No newline at end of file