/usr/local/miolo2/classes/ezpdf/class.pdf.php

Go to the documentation of this file.
00001 <?php
00002 function __sprintf($fmt, $value)
00003 {
00004     $r = sprintf($fmt, $value);
00005     return str_replace(',', '.', $r);
00006 }
00007 
00029 class Cpdf
00030 {
00031 
00035     var $numObj = 0;
00039     var $objects = array(
00040         );
00044     var $catalogId;
00049     var $fonts = array(
00050         );
00054     var $currentFont = '';
00058     var $currentBaseFont = '';
00062     var $currentFontNum = 0;
00066     var $currentNode;
00070     var $currentPage;
00074     var $currentContents;
00078     var $numFonts = 0;
00082     var $currentColour = array('r' => -1, 'g' => -1, 'b' => -1);
00086     var $currentStrokeColour = array('r' => -1, 'g' => -1, 'b' => -1);
00090     var $currentLineStyle = '';
00095     var $stateStack = array(
00096         );
00100     var $nStateStack = 0;
00104     var $numPages = 0;
00108     var $stack = array(
00109         );
00113     var $nStack = 0;
00118     var $looseObjects = array(
00119         );
00123     var $addLooseObjects = array(
00124         );
00129     var $infoObject = 0;
00133     var $numImages = 0;
00138     var $options = array('compression' => 1);
00142     var $firstPageId;
00147     var $wordSpaceAdjust = 0;
00151     var $procsetObjectId;
00157     var $fontFamilies = array(
00158         );
00162     var $currentTextState = '';
00166     var $messages = '';
00170     var $arc4 = '';
00174     var $arc4_objnum = 0;
00178     var $fileIdentifier = '';
00182     var $encrypted = 0;
00186     var $encryptionKey = '';
00190     var $callback = array(
00191         );
00195     var $nCallback = 0;
00200     var $destinations = array(
00201         );
00207     var $checkpoint = '';
00214     var $fonts_path;
00215 
00216     function Cpdf($pageSize = array(0, 0, 612, 792))
00217     {
00218         $this->newDocument($pageSize);
00219 
00220         $this->SetFontsPath('./fonts');
00221         // also initialize the font families that are known about already
00222         $this->setFontFamily('init');
00223     //  $this->fileIdentifier = md5('xxxxxxxx'.time());
00224 
00225     }
00226 
00245     function o_destination($id, $action, $options = '')
00246     {
00247         if ($action != 'new')
00248         {
00249             $o = &$this->objects[$id];
00250         }
00251 
00252         switch ($action)
00253             {
00254             case 'new':
00255                 $this->objects[$id] = array
00256                     (
00257                     't' => 'destination',
00258                     'info' => array(
00259                         )
00260                     );
00261 
00262                 $tmp = '';
00263 
00264                 switch ($options['type'])
00265                     {
00266                     case 'XYZ':
00267                     case 'FitR': $tmp = ' ' . $options['p3'] . $tmp;
00268 
00269                     case 'FitH':
00270                     case 'FitV':
00271                     case 'FitBH':
00272                     case 'FitBV': $tmp = ' ' . $options['p1'] . ' ' . $options['p2'] . $tmp;
00273 
00274                     case 'Fit':
00275                     case 'FitB':
00276                         $tmp = $options['type'] . $tmp;
00277 
00278                         $this->objects[$id]['info']['string'] = $tmp;
00279                         $this->objects[$id]['info']['page'] = $options['page'];
00280                     }
00281 
00282                 break;
00283 
00284             case 'out':
00285                 $tmp = $o['info'];
00286 
00287                 $res = "\n" . $id . " 0 obj\n" . '[' . $tmp['page'] . ' 0 R /' . $tmp['string'] . "]\nendobj\n";
00288                 return $res;
00289                 break;
00290             }
00291     }
00292 
00296     function o_viewerPreferences($id, $action, $options = '')
00297     {
00298         if ($action != 'new')
00299         {
00300             $o = &$this->objects[$id];
00301         }
00302 
00303         switch ($action)
00304             {
00305             case 'new':
00306                 $this->objects[$id] = array
00307                     (
00308                     't' => 'viewerPreferences',
00309                     'info' => array(
00310                         )
00311                     );
00312 
00313                 break;
00314 
00315             case 'add':
00316                 foreach ($options as $k => $v)
00317                 {
00318                     switch ($k)
00319                         {
00320                         case 'HideToolbar':
00321                         case 'HideMenubar':
00322                         case 'HideWindowUI':
00323                         case 'FitWindow':
00324                         case 'CenterWindow':
00325                         case 'NonFullScreenPageMode':
00326                         case 'Direction':
00327                             $o['info'][$k] = $v;
00328 
00329                             break;
00330                         }
00331                 }
00332 
00333                 break;
00334 
00335             case 'out':
00336                 $res = "\n" . $id . " 0 obj\n" . '<< ';
00337 
00338                 foreach ($o['info'] as $k => $v)
00339                 {
00340                     $res .= "\n/" . $k . ' ' . $v;
00341                 }
00342 
00343                 $res .= "\n>>\n";
00344                 return $res;
00345                 break;
00346             }
00347     }
00348 
00352     function o_catalog($id, $action, $options = '')
00353     {
00354         if ($action != 'new')
00355         {
00356             $o = &$this->objects[$id];
00357         }
00358 
00359         switch ($action)
00360             {
00361             case 'new':
00362                 $this->objects[$id] = array
00363                     (
00364                     't' => 'catalog',
00365                     'info' => array(
00366                         )
00367                     );
00368 
00369                 $this->catalogId = $id;
00370                 break;
00371 
00372             case 'outlines':
00373             case 'pages':
00374             case 'openHere':
00375                 $o['info'][$action] = $options;
00376 
00377                 break;
00378 
00379             case 'viewerPreferences':
00380                 if (!isset($o['info']['viewerPreferences']))
00381                 {
00382                     $this->numObj++;
00383                     $this->o_viewerPreferences($this->numObj, 'new');
00384                     $o['info']['viewerPreferences'] = $this->numObj;
00385                 }
00386 
00387                 $vp = $o['info']['viewerPreferences'];
00388                 $this->o_viewerPreferences($vp, 'add', $options);
00389                 break;
00390 
00391             case 'out':
00392                 $res = "\n" . $id . " 0 obj\n" . '<< /Type /Catalog';
00393 
00394                 foreach ($o['info'] as $k => $v)
00395                 {
00396                     switch ($k)
00397                         {
00398                         case 'outlines':
00399                             $res .= "\n" . '/Outlines ' . $v . ' 0 R';
00400 
00401                             break;
00402 
00403                         case 'pages':
00404                             $res .= "\n" . '/Pages ' . $v . ' 0 R';
00405 
00406                             break;
00407 
00408                         case 'viewerPreferences':
00409                             $res .= "\n" . '/ViewerPreferences ' . $o['info']['viewerPreferences'] . ' 0 R';
00410 
00411                             break;
00412 
00413                         case 'openHere':
00414                             $res .= "\n" . '/OpenAction ' . $o['info']['openHere'] . ' 0 R';
00415 
00416                             break;
00417                         }
00418                 }
00419 
00420                 $res .= " >>\nendobj";
00421                 return $res;
00422                 break;
00423             }
00424     }
00425 
00429     function o_pages($id, $action, $options = '')
00430     {
00431         if ($action != 'new')
00432         {
00433             $o = &$this->objects[$id];
00434         }
00435 
00436         switch ($action)
00437             {
00438             case 'new':
00439                 $this->objects[$id] = array
00440                     (
00441                     't' => 'pages',
00442                     'info' => array(
00443                         )
00444                     );
00445 
00446                 $this->o_catalog($this->catalogId, 'pages', $id);
00447                 break;
00448 
00449             case 'page':
00450                 if (!is_array($options))
00451                 {
00452                     // then it will just be the id of the new page
00453                     $o['info']['pages'][] = $options;
00454                 }
00455                 else
00456                 {
00457                     // then it should be an array having 'id','rid','pos', where rid=the page to which this one will be placed relative
00458                     // and pos is either 'before' or 'after', saying where this page will fit.
00459                     if (isset($options['id']) && isset($options['rid']) && isset($options['pos']))
00460                     {
00461                         $i = array_search($options['rid'], $o['info']['pages']);
00462 
00463                         if (isset($o['info']['pages'][$i]) && $o['info']['pages'][$i] == $options['rid'])
00464                         {
00465                             // then there is a match
00466                             // make a space
00467                             switch ($options['pos'])
00468                                 {
00469                                 case 'before':
00470                                     $k = $i;
00471 
00472                                     break;
00473 
00474                                 case 'after':
00475                                     $k = $i + 1;
00476 
00477                                     break;
00478 
00479                                 default:
00480                                     $k = -1;
00481 
00482                                     break;
00483                                 }
00484 
00485                             if ($k >= 0)
00486                             {
00487                                 for ($j = count($o['info']['pages']) - 1; $j >= $k; $j--)
00488                                 {
00489                                     $o['info']['pages'][$j + 1] = $o['info']['pages'][$j];
00490                                 }
00491 
00492                                 $o['info']['pages'][$k] = $options['id'];
00493                             }
00494                         }
00495                     }
00496                 }
00497 
00498                 break;
00499 
00500             case 'procset':
00501                 $o['info']['procset'] = $options;
00502 
00503                 break;
00504 
00505             case 'mediaBox':
00506                 $o['info']['mediaBox'] = $options; // which should be an array of 4 numbers
00507 
00508                 break;
00509 
00510             case 'font':
00511                 $o['info']['fonts'][] = array
00512                     (
00513                     'objNum' => $options['objNum'],
00514                     'fontNum' => $options['fontNum']
00515                     );
00516 
00517                 break;
00518 
00519             case 'xObject':
00520                 $o['info']['xObjects'][] = array
00521                     (
00522                     'objNum' => $options['objNum'],
00523                     'label' => $options['label']
00524                     );
00525 
00526                 break;
00527 
00528             case 'out':
00529                 if (count($o['info']['pages']))
00530                 {
00531                     $res = "\n" . $id . " 0 obj\n<< /Type /Pages\n/Kids [";
00532 
00533                     foreach ($o['info']['pages'] as $k => $v)
00534                     {
00535                         $res .= $v . " 0 R\n";
00536                     }
00537 
00538                     $res .= "]\n/Count " . count($this->objects[$id]['info']['pages']);
00539 
00540                     if ((isset($o['info']['fonts']) && count($o['info']['fonts'])) || isset($o['info']['procset']))
00541                     {
00542                         $res .= "\n/Resources <<";
00543 
00544                         if (isset($o['info']['procset']))
00545                         {
00546                             $res .= "\n/ProcSet " . $o['info']['procset'] . " 0 R";
00547                         }
00548 
00549                         if (isset($o['info']['fonts']) && count($o['info']['fonts']))
00550                         {
00551                             $res .= "\n/Font << ";
00552 
00553                             foreach ($o['info']['fonts'] as $finfo)
00554                             {
00555                                 $res .= "\n/F" . $finfo['fontNum'] . " " . $finfo['objNum'] . " 0 R";
00556                             }
00557 
00558                             $res .= " >>";
00559                         }
00560 
00561                         if (isset($o['info']['xObjects']) && count($o['info']['xObjects']))
00562                         {
00563                             $res .= "\n/XObject << ";
00564 
00565                             foreach ($o['info']['xObjects'] as $finfo)
00566                             {
00567                                 $res .= "\n/" . $finfo['label'] . " " . $finfo['objNum'] . " 0 R";
00568                             }
00569 
00570                             $res .= " >>";
00571                         }
00572 
00573                         $res .= "\n>>";
00574 
00575                         if (isset($o['info']['mediaBox']))
00576                         {
00577                             $tmp = $o['info']['mediaBox'];
00578                             $res .= "\n/MediaBox [" . __sprintf('%.3f',
00579                                                                 $tmp[0]) . ' ' . __sprintf('%.3f',
00580                                                                                            $tmp[1]) . ' '
00581                                         . __sprintf('%.3f', $tmp[2]) . ' ' . __sprintf('%.3f', $tmp[3]) . ']';
00582                         }
00583                     }
00584 
00585                     $res .= "\n >>\nendobj";
00586                 }
00587                 else
00588                 {
00589                     $res = "\n" . $id . " 0 obj\n<< /Type /Pages\n/Count 0\n>>\nendobj";
00590                 }
00591 
00592                 return $res;
00593                 break;
00594             }
00595     }
00596 
00600     function o_outlines($id, $action, $options = '')
00601     {
00602         if ($action != 'new')
00603         {
00604             $o = &$this->objects[$id];
00605         }
00606 
00607         switch ($action)
00608             {
00609             case 'new':
00610                 $this->objects[$id] = array
00611                     (
00612                     't' => 'outlines',
00613                     'info' => array('outlines' => array(
00614                         ))
00615                     );
00616 
00617                 $this->o_catalog($this->catalogId, 'outlines', $id);
00618                 break;
00619 
00620             case 'outline':
00621                 $o['info']['outlines'][] = $options;
00622 
00623                 break;
00624 
00625             case 'out':
00626                 if (count($o['info']['outlines']))
00627                 {
00628                     $res = "\n" . $id . " 0 obj\n<< /Type /Outlines /Kids [";
00629 
00630                     foreach ($o['info']['outlines'] as $k => $v)
00631                     {
00632                         $res .= $v . " 0 R ";
00633                     }
00634 
00635                     $res .= "] /Count " . count($o['info']['outlines']) . " >>\nendobj";
00636                 }
00637                 else
00638                 {
00639                     $res = "\n" . $id . " 0 obj\n<< /Type /Outlines /Count 0 >>\nendobj";
00640                 }
00641 
00642                 return $res;
00643                 break;
00644             }
00645     }
00646 
00650     function o_font($id, $action, $options = '')
00651     {
00652         if ($action != 'new')
00653         {
00654             $o = &$this->objects[$id];
00655         }
00656 
00657         switch ($action)
00658             {
00659             case 'new':
00660                 $this->objects[$id] = array
00661                     (
00662                     't' => 'font',
00663                     'info' => array('name' => $options['name'], 'SubType' => 'Type1')
00664                     );
00665 
00666                 $fontNum = $this->numFonts;
00667                 $this->objects[$id]['info']['fontNum'] = $fontNum;
00668 
00669                 // deal with the encoding and the differences
00670                 if (isset($options['differences']))
00671                 {
00672                     // then we'll need an encoding dictionary
00673                     $this->numObj++;
00674                     $this->o_fontEncoding($this->numObj, 'new', $options);
00675                     $this->objects[$id]['info']['encodingDictionary'] = $this->numObj;
00676                 }
00677                 else if (isset($options['encoding']))
00678                 {
00679                     // we can specify encoding here
00680                     switch ($options['encoding'])
00681                         {
00682                         case 'WinAnsiEncoding':
00683                         case 'MacRomanEncoding':
00684                         case 'MacExpertEncoding':
00685                             $this->objects[$id]['info']['encoding'] = $options['encoding'];
00686 
00687                             break;
00688 
00689                         case 'none': break;
00690 
00691                         default:
00692                             $this->objects[$id]['info']['encoding'] = 'WinAnsiEncoding';
00693 
00694                             break;
00695                         }
00696                 }
00697                 else
00698                 {
00699                     $this->objects[$id]['info']['encoding'] = 'WinAnsiEncoding';
00700                 }
00701 
00702                 // also tell the pages node about the new font
00703                 $this->o_pages($this->currentNode, 'font', array('fontNum' => $fontNum, 'objNum' => $id));
00704                 break;
00705 
00706             case 'add':
00707                 foreach ($options as $k => $v)
00708                 {
00709                     switch ($k)
00710                         {
00711                         case 'BaseFont':
00712                             $o['info']['name'] = $v;
00713 
00714                             break;
00715 
00716                         case 'FirstChar':
00717                         case 'LastChar':
00718                         case 'Widths':
00719                         case 'FontDescriptor':
00720                         case 'SubType':
00721                             $this->addMessage('o_font ' . $k . " : " . $v);
00722 
00723                             $o['info'][$k] = $v;
00724                             break;
00725                         }
00726                 }
00727 
00728                 break;
00729 
00730             case 'out':
00731                 $res = "\n" . $id . " 0 obj\n<< /Type /Font\n/Subtype /" . $o['info']['SubType'] . "\n";
00732 
00733                 $res .= "/Name /F" . $o['info']['fontNum'] . "\n";
00734                 $res .= "/BaseFont /" . $o['info']['name'] . "\n";
00735 
00736                 if (isset($o['info']['encodingDictionary']))
00737                 {
00738                     // then place a reference to the dictionary
00739                     $res .= "/Encoding " . $o['info']['encodingDictionary'] . " 0 R\n";
00740                 }
00741                 else if (isset($o['info']['encoding']))
00742                 {
00743                     // use the specified encoding
00744                     $res .= "/Encoding /" . $o['info']['encoding'] . "\n";
00745                 }
00746 
00747                 if (isset($o['info']['FirstChar']))
00748                 {
00749                     $res .= "/FirstChar " . $o['info']['FirstChar'] . "\n";
00750                 }
00751 
00752                 if (isset($o['info']['LastChar']))
00753                 {
00754                     $res .= "/LastChar " . $o['info']['LastChar'] . "\n";
00755                 }
00756 
00757                 if (isset($o['info']['Widths']))
00758                 {
00759                     $res .= "/Widths " . $o['info']['Widths'] . " 0 R\n";
00760                 }
00761 
00762                 if (isset($o['info']['FontDescriptor']))
00763                 {
00764                     $res .= "/FontDescriptor " . $o['info']['FontDescriptor'] . " 0 R\n";
00765                 }
00766 
00767                 $res .= ">>\nendobj";
00768                 return $res;
00769                 break;
00770             }
00771     }
00772 
00776     function o_fontDescriptor($id, $action, $options = '')
00777     {
00778         if ($action != 'new')
00779         {
00780             $o = &$this->objects[$id];
00781         }
00782 
00783         switch ($action)
00784             {
00785             case 'new':
00786                 $this->objects[$id] = array
00787                     (
00788                     't' => 'fontDescriptor',
00789                     'info' => $options
00790                     );
00791 
00792                 break;
00793 
00794             case 'out':
00795                 $res = "\n" . $id . " 0 obj\n<< /Type /FontDescriptor\n";
00796 
00797                 foreach ($o['info'] as $label => $value)
00798                 {
00799                     switch ($label)
00800                         {
00801                         case 'Ascent':
00802                         case 'CapHeight':
00803                         case 'Descent':
00804                         case 'Flags':
00805                         case 'ItalicAngle':
00806                         case 'StemV':
00807                         case 'AvgWidth':
00808                         case 'Leading':
00809                         case 'MaxWidth':
00810                         case 'MissingWidth':
00811                         case 'StemH':
00812                         case 'XHeight':
00813                         case 'CharSet':
00814                             if (strlen($value))
00815                             {
00816                                 $res .= '/' . $label . ' ' . $value . "\n";
00817                             }
00818 
00819                             break;
00820 
00821                         case 'FontFile':
00822                         case 'FontFile2':
00823                         case 'FontFile3':
00824                             $res .= '/' . $label . ' ' . $value . " 0 R\n";
00825 
00826                             break;
00827 
00828                         case 'FontBBox':
00829                             $res
00830                                 .= '/' . $label . ' [' . $value[0] . ' ' . $value[1] . ' ' . $value[2] . ' ' . $value[3]
00831                                        . "]\n";
00832 
00833                             break;
00834 
00835                         case 'FontName':
00836                             $res .= '/' . $label . ' /' . $value . "\n";
00837 
00838                             break;
00839                         }
00840                 }
00841 
00842                 $res .= ">>\nendobj";
00843                 return $res;
00844                 break;
00845             }
00846     }
00847 
00851     function o_fontEncoding($id, $action, $options = '')
00852     {
00853         if ($action != 'new')
00854         {
00855             $o = &$this->objects[$id];
00856         }
00857 
00858         switch ($action)
00859             {
00860             case 'new':
00861                 // the options array should contain 'differences' and maybe 'encoding'
00862                 $this->objects[$id] = array
00863                     (
00864                     't' => 'fontEncoding',
00865                     'info' => $options
00866                     );
00867 
00868                 break;
00869 
00870             case 'out':
00871                 $res = "\n" . $id . " 0 obj\n<< /Type /Encoding\n";
00872 
00873                 if (!isset($o['info']['encoding']))
00874                 {
00875                     $o['info']['encoding'] = 'WinAnsiEncoding';
00876                 }
00877 
00878                 if ($o['info']['encoding'] != 'none')
00879                 {
00880                     $res .= "/BaseEncoding /" . $o['info']['encoding'] . "\n";
00881                 }
00882 
00883                 $res .= "/Differences \n[";
00884                 $onum = -100;
00885 
00886                 foreach ($o['info']['differences'] as $num => $label)
00887                 {
00888                     if ($num != $onum + 1)
00889                     {
00890                         // we cannot make use of consecutive numbering
00891                         $res .= "\n" . $num . " /" . $label;
00892                     }
00893                     else
00894                     {
00895                         $res .= " /" . $label;
00896                     }
00897 
00898                     $onum = $num;
00899                 }
00900 
00901                 $res .= "\n]\n>>\nendobj";
00902                 return $res;
00903                 break;
00904             }
00905     }
00906 
00910     function o_procset($id, $action, $options = '')
00911     {
00912         if ($action != 'new')
00913         {
00914             $o = &$this->objects[$id];
00915         }
00916 
00917         switch ($action)
00918             {
00919             case 'new':
00920                 $this->objects[$id] = array
00921                     (
00922                     't' => 'procset',
00923                     'info' => array('PDF' => 1, 'Text' => 1)
00924                     );
00925 
00926                 $this->o_pages($this->currentNode, 'procset', $id);
00927                 $this->procsetObjectId = $id;
00928                 break;
00929 
00930             case 'add':
00931                 // this is to add new items to the procset list, despite the fact that this is considered
00932                 // obselete, the items are required for printing to some postscript printers
00933                 switch ($options)
00934                     {
00935                     case 'ImageB':
00936                     case 'ImageC':
00937                     case 'ImageI':
00938                         $o['info'][$options] = 1;
00939 
00940                         break;
00941                     }
00942 
00943                 break;
00944 
00945             case 'out':
00946                 $res = "\n" . $id . " 0 obj\n[";
00947 
00948                 foreach ($o['info'] as $label => $val)
00949                 {
00950                     $res .= '/' . $label . ' ';
00951                 }
00952 
00953                 $res .= "]\nendobj";
00954                 return $res;
00955                 break;
00956             }
00957     }
00958 
00962     function o_info($id, $action, $options = '')
00963     {
00964         if ($action != 'new')
00965         {
00966             $o = &$this->objects[$id];
00967         }
00968 
00969         switch ($action)
00970             {
00971             case 'new':
00972                 $this->infoObject = $id;
00973 
00974                 $date = 'D:' . date('Ymd');
00975                 $this->objects[$id] = array
00976                     (
00977                     't' => 'info',
00978                     'info' =>
00979                         array('Creator' => 'R and OS php pdf writer, http://www.ros.co.nz', 'CreationDate' => $date)
00980                     );
00981 
00982                 break;
00983 
00984             case 'Title':
00985             case 'Author':
00986             case 'Subject':
00987             case 'Keywords':
00988             case 'Creator':
00989             case 'Producer':
00990             case 'CreationDate':
00991             case 'ModDate':
00992             case 'Trapped':
00993                 $o['info'][$action] = $options;
00994 
00995                 break;
00996 
00997             case 'out':
00998                 if ($this->encrypted)
00999                 {
01000                     $this->encryptInit($id);
01001                 }
01002 
01003                 $res = "\n" . $id . " 0 obj\n<<\n";
01004 
01005                 foreach ($o['info'] as $k => $v)
01006                 {
01007                     $res .= '/' . $k . ' (';
01008 
01009                     if ($this->encrypted)
01010                     {
01011                         $res .= $this->filterText($this->ARC4($v));
01012                     }
01013                     else
01014                     {
01015                         $res .= $this->filterText($v);
01016                     }
01017 
01018                     $res .= ")\n";
01019                 }
01020 
01021                 $res .= ">>\nendobj";
01022                 return $res;
01023                 break;
01024             }
01025     }
01026 
01030     function o_action($id, $action, $options = '')
01031     {
01032         if ($action != 'new')
01033         {
01034             $o = &$this->objects[$id];
01035         }
01036 
01037         switch ($action)
01038             {
01039             case 'new':
01040                 if (is_array($options))
01041                 {
01042                     $this->objects[$id] = array
01043                         (
01044                         't' => 'action',
01045                         'info' => $options,
01046                         'type' => $options['type']
01047                         );
01048                 }
01049                 else
01050                 {
01051                     // then assume a URI action
01052                     $this->objects[$id] = array
01053                         (
01054                         't' => 'action',
01055                         'info' => $options,
01056                         'type' => 'URI'
01057                         );
01058                 }
01059 
01060                 break;
01061 
01062             case 'out':
01063                 if ($this->encrypted)
01064                 {
01065                     $this->encryptInit($id);
01066                 }
01067 
01068                 $res = "\n" . $id . " 0 obj\n<< /Type /Action";
01069 
01070                 switch ($o['type'])
01071                     {
01072                     case 'ilink':
01073                         // there will be an 'label' setting, this is the name of the destination
01074                         $res .= "\n/S /GoTo\n/D " . $this->destinations[(string)$o['info']['label']] . " 0 R";
01075 
01076                         break;
01077 
01078                     case 'URI':
01079                         $res .= "\n/S /URI\n/URI (";
01080 
01081                         if ($this->encrypted)
01082                         {
01083                             $res .= $this->filterText($this->ARC4($o['info']));
01084                         }
01085                         else
01086                         {
01087                             $res .= $this->filterText($o['info']);
01088                         }
01089 
01090                         $res .= ")";
01091                         break;
01092                     }
01093 
01094                 $res .= "\n>>\nendobj";
01095                 return $res;
01096                 break;
01097             }
01098     }
01099 
01104     function o_annotation($id, $action, $options = '')
01105     {
01106         if ($action != 'new')
01107         {
01108             $o = &$this->objects[$id];
01109         }
01110 
01111         switch ($action)
01112             {
01113             case 'new':
01114                 // add the annotation to the current page
01115                 $pageId = $this->currentPage;
01116 
01117                 $this->o_page($pageId, 'annot', $id);
01118 
01119                 // and add the action object which is going to be required
01120                 switch ($options['type'])
01121                     {
01122                     case 'link':
01123                         $this->objects[$id] = array
01124                             (
01125                             't' => 'annotation',
01126                             'info' => $options
01127                             );
01128 
01129                         $this->numObj++;
01130                         $this->o_action($this->numObj, 'new', $options['url']);
01131                         $this->objects[$id]['info']['actionId'] = $this->numObj;
01132                         break;
01133 
01134                     case 'ilink':
01135                         // this is to a named internal link
01136                         $label = $options['label'];
01137 
01138                         $this->objects[$id] = array
01139                             (
01140                             't' => 'annotation',
01141                             'info' => $options
01142                             );
01143 
01144                         $this->numObj++;
01145                         $this->o_action($this->numObj, 'new', array('type' => 'ilink', 'label' => $label));
01146                         $this->objects[$id]['info']['actionId'] = $this->numObj;
01147                         break;
01148                     }
01149 
01150                 break;
01151 
01152             case 'out':
01153                 $res = "\n" . $id . " 0 obj\n<< /Type /Annot";
01154 
01155                 switch ($o['info']['type'])
01156                     {
01157                     case 'link':
01158                     case 'ilink':
01159                         $res .= "\n/Subtype /Link";
01160 
01161                         break;
01162                     }
01163 
01164                 $res .= "\n/A " . $o['info']['actionId'] . " 0 R";
01165                 $res .= "\n/Border [0 0 0]";
01166                 $res .= "\n/H /I";
01167                 $res .= "\n/Rect [ ";
01168 
01169                 foreach ($o['info']['rect'] as $v)
01170                 {
01171                     $res .= __sprintf("%.4f ", $v);
01172                 }
01173 
01174                 $res .= "]";
01175                 $res .= "\n>>\nendobj";
01176                 return $res;
01177                 break;
01178             }
01179     }
01180 
01184     function o_page($id, $action, $options = '')
01185     {
01186         if ($action != 'new')
01187         {
01188             $o = &$this->objects[$id];
01189         }
01190 
01191         switch ($action)
01192             {
01193             case 'new':
01194                 $this->numPages++;
01195 
01196                 $this->objects[$id] = array
01197                     (
01198                     't' => 'page',
01199                     'info' => array('parent' => $this->currentNode, 'pageNum' => $this->numPages)
01200                     );
01201 
01202                 if (is_array($options))
01203                 {
01204                     // then this must be a page insertion, array shoudl contain 'rid','pos'=[before|after]
01205                     $options['id'] = $id;
01206                     $this->o_pages($this->currentNode, 'page', $options);
01207                 }
01208                 else
01209                 {
01210                     $this->o_pages($this->currentNode, 'page', $id);
01211                 }
01212 
01213                 $this->currentPage = $id;
01214                 //make a contents object to go with this page
01215                 $this->numObj++;
01216                 $this->o_contents($this->numObj, 'new', $id);
01217                 $this->currentContents = $this->numObj;
01218                 $this->objects[$id]['info']['contents'] = array(
01219                     );
01220 
01221                 $this->objects[$id]['info']['contents'][] = $this->numObj;
01222                 $match = ($this->numPages % 2 ? 'odd' : 'even');
01223 
01224                 foreach ($this->addLooseObjects as $oId => $target)
01225                 {
01226                     if ($target == 'all' || $match == $target)
01227                     {
01228                         $this->objects[$id]['info']['contents'][] = $oId;
01229                     }
01230                 }
01231 
01232                 break;
01233 
01234             case 'content':
01235                 $o['info']['contents'][] = $options;
01236 
01237                 break;
01238 
01239             case 'annot':
01240                 // add an annotation to this page
01241                 if (!isset($o['info']['annot']))
01242                 {
01243                     $o['info']['annot'] = array(
01244                         );
01245                 }
01246 
01247                 // $options should contain the id of the annotation dictionary
01248                 $o['info']['annot'][] = $options;
01249                 break;
01250 
01251             case 'out':
01252                 $res = "\n" . $id . " 0 obj\n<< /Type /Page";
01253 
01254                 $res .= "\n/Parent " . $o['info']['parent'] . " 0 R";
01255 
01256                 if (isset($o['info']['annot']))
01257                 {
01258                     $res .= "\n/Annots [";
01259 
01260                     foreach ($o['info']['annot'] as $aId)
01261                     {
01262                         $res .= " " . $aId . " 0 R";
01263                     }
01264 
01265                     $res .= " ]";
01266                 }
01267 
01268                 $count = count($o['info']['contents']);
01269 
01270                 if ($count == 1)
01271                 {
01272                     $res .= "\n/Contents " . $o['info']['contents'][0] . " 0 R";
01273                 }
01274                 else if ($count > 1)
01275                 {
01276                     $res .= "\n/Contents [\n";
01277 
01278                     foreach ($o['info']['contents'] as $cId)
01279                     {
01280                         $res .= $cId . " 0 R\n";
01281                     }
01282 
01283                     $res .= "]";
01284                 }
01285 
01286                 $res .= "\n>>\nendobj";
01287                 return $res;
01288                 break;
01289             }
01290     }
01291 
01295     function o_contents($id, $action, $options = '')
01296     {
01297         if ($action != 'new')
01298         {
01299             $o = &$this->objects[$id];
01300         }
01301 
01302         switch ($action)
01303             {
01304             case 'new':
01305                 $this->objects[$id] = array
01306                     (
01307                     't' => 'contents',
01308                     'c' => '',
01309                     'info' => array(
01310                         )
01311                     );
01312 
01313                 if (strlen($options) && intval($options))
01314                 {
01315                     // then this contents is the primary for a page
01316                     $this->objects[$id]['onPage'] = $options;
01317                 }
01318                 else if ($options == 'raw')
01319                 {
01320                     // then this page contains some other type of system object
01321                     $this->objects[$id]['raw'] = 1;
01322                 }
01323 
01324                 break;
01325 
01326             case 'add':
01327                 // add more options to the decleration
01328                 foreach ($options as $k => $v)
01329                 {
01330                     $o['info'][$k] = $v;
01331                 }
01332 
01333             case 'out':
01334                 $tmp = $o['c'];
01335 
01336                 $res = "\n" . $id . " 0 obj\n";
01337 
01338                 if (isset($this->objects[$id]['raw']))
01339                 {
01340                     $res .= $tmp;
01341                 }
01342                 else
01343                 {
01344                     $res .= "<<";
01345 
01346                     if (function_exists('gzcompress') && $this->options['compression'])
01347                     {
01348                         // then implement ZLIB based compression on this content stream
01349                         $res .= " /Filter /FlateDecode";
01350                         $tmp = gzcompress($tmp);
01351                     }
01352 
01353                     if ($this->encrypted)
01354                     {
01355                         $this->encryptInit($id);
01356                         $tmp = $this->ARC4($tmp);
01357                     }
01358 
01359                     foreach ($o['info'] as $k => $v)
01360                     {
01361                         $res .= "\n/" . $k . ' ' . $v;
01362                     }
01363 
01364                     $res .= "\n/Length " . strlen($tmp) . " >>\nstream\n" . $tmp . "\nendstream";
01365                 }
01366 
01367                 $res .= "\nendobj\n";
01368                 return $res;
01369                 break;
01370             }
01371     }
01372 
01376     function o_image($id, $action, $options = '')
01377     {
01378         if ($action != 'new')
01379         {
01380             $o = &$this->objects[$id];
01381         }
01382 
01383         switch ($action)
01384             {
01385             case 'new':
01386                 // make the new object
01387                 $this->objects[$id] = array
01388                     (
01389                     't' => 'image',
01390                     'data' => $options['data'],
01391                     'info' => array(
01392                         )
01393                     );
01394 
01395                 $this->objects[$id]['info']['Type'] = '/XObject';
01396                 $this->objects[$id]['info']['Subtype'] = '/Image';
01397                 $this->objects[$id]['info']['Width'] = $options['iw'];
01398                 $this->objects[$id]['info']['Height'] = $options['ih'];
01399 
01400                 if (!isset($options['type']) || $options['type'] == 'jpg')
01401                 {
01402                     if (!isset($options['channels']))
01403                     {
01404                         $options['channels'] = 3;
01405                     }
01406 
01407                     switch ($options['channels'])
01408                         {
01409                         case 1:
01410                             $this->objects[$id]['info']['ColorSpace'] = '/DeviceGray';
01411 
01412                             break;
01413 
01414                         default:
01415                             $this->objects[$id]['info']['ColorSpace'] = '/DeviceRGB';
01416 
01417                             break;
01418                         }
01419 
01420                     $this->objects[$id]['info']['Filter'] = '/DCTDecode';
01421                     $this->objects[$id]['info']['BitsPerComponent'] = 8;
01422                 }
01423                 else if ($options['type'] == 'png')
01424                 {
01425                     $this->objects[$id]['info']['Filter'] = '/FlateDecode';
01426                     $this->objects[$id]['info']['DecodeParms']
01427                         = '<< /Predictor 15 /Colors ' . $options['ncolor'] . ' /Columns ' . $options['iw']
01428                               . ' /BitsPerComponent ' . $options['bitsPerComponent'] . '>>';
01429 
01430                     if (strlen($options['pdata']))
01431                     {
01432                         $tmp = ' [ /Indexed /DeviceRGB ' . (strlen($options['pdata']) / 3 - 1) . ' ';
01433                         $this->numObj++;
01434                         $this->o_contents($this->numObj, 'new');
01435                         $this->objects[$this->numObj]['c'] = $options['pdata'];
01436                         $tmp .= $this->numObj . ' 0 R';
01437                         $tmp .= ' ]';
01438                         $this->objects[$id]['info']['ColorSpace'] = $tmp;
01439 
01440                         if (isset($options['transparency']))
01441                         {
01442                             switch ($options['transparency']['type'])
01443                                 {
01444                                 case 'indexed':
01445                                     $tmp = ' [ ' . $options['transparency']['data'] . ' '
01446                                                . $options['transparency']['data'] . '] ';
01447 
01448                                     $this->objects[$id]['info']['Mask'] = $tmp;
01449                                     break;
01450                                 }
01451                         }
01452                     }
01453                     else
01454                     {
01455                         $this->objects[$id]['info']['ColorSpace'] = '/' . $options['color'];
01456                     }
01457 
01458                     $this->objects[$id]['info']['BitsPerComponent'] = $options['bitsPerComponent'];
01459                 }
01460 
01461                 // assign it a place in the named resource dictionary as an external object, according to
01462                 // the label passed in with it.
01463                 $this->o_pages($this->currentNode, 'xObject', array('label' => $options['label'], 'objNum' => $id));
01464                 // also make sure that we have the right procset object for it.
01465                 $this->o_procset($this->procsetObjectId, 'add', 'ImageC');
01466                 break;
01467 
01468             case 'out':
01469                 $tmp = $o['data'];
01470 
01471                 $res = "\n" . $id . " 0 obj\n<<";
01472 
01473                 foreach ($o['info'] as $k => $v)
01474                 {
01475                     $res .= "\n/" . $k . ' ' . $v;
01476                 }
01477 
01478                 if ($this->encrypted)
01479                 {
01480                     $this->encryptInit($id);
01481                     $tmp = $this->ARC4($tmp);
01482                 }
01483 
01484                 $res .= "\n/Length " . strlen($tmp) . " >>\nstream\n" . $tmp . "\nendstream\nendobj\n";
01485                 return $res;
01486                 break;
01487             }
01488     }
01489 
01493     function o_encryption($id, $action, $options = '')
01494     {
01495         if ($action != 'new')
01496         {
01497             $o = &$this->objects[$id];
01498         }
01499 
01500         switch ($action)
01501             {
01502             case 'new':
01503                 // make the new object
01504                 $this->objects[$id] = array
01505                     (
01506                     't' => 'encryption',
01507                     'info' => $options
01508                     );
01509 
01510                 $this->arc4_objnum = $id;
01511                 // figure out the additional paramaters required
01512                 $pad = chr(0x28) . chr(0xBF) . chr(0x4E) . chr(0x5E) . chr(0x4E) . chr(0x75) . chr(0x8A) . chr(0x41)
01513                            . chr(0x64)
01514                            . chr(0x00) . chr(0x4E) . chr(0x56) . chr(0xFF) . chr(0xFA) . chr(0x01) . chr(0x08) . chr(
01515                                                                                                                      0x2E)
01516                            . chr(0x2E) . chr(0x00) . chr(0xB6) . chr(0xD0) . chr(0x68) . chr(0x3E) . chr(0x80) . chr(
01517                                                                                                                      0x2F)
01518                            . chr(0x0C) . chr(0xA9) . chr(0xFE) . chr(0x64) . chr(0x53) . chr(0x69) . chr(0x7A);
01519                 $len = strlen($options['owner']);
01520 
01521                 if ($len > 32)
01522                 {
01523                     $owner = substr($options['owner'], 0, 32);
01524                 }
01525                 else if ($len < 32)
01526                 {
01527                     $owner = $options['owner'] . substr($pad, 0, 32 - $len);
01528                 }
01529                 else
01530                 {
01531                     $owner = $options['owner'];
01532                 }
01533 
01534                 $len = strlen($options['user']);
01535 
01536                 if ($len > 32)
01537                 {
01538                     $user = substr($options['user'], 0, 32);
01539                 }
01540                 else if ($len < 32)
01541                 {
01542                     $user = $options['user'] . substr($pad, 0, 32 - $len);
01543                 }
01544                 else
01545                 {
01546                     $user = $options['user'];
01547                 }
01548 
01549                 $tmp = $this->md5_16($owner);
01550                 $okey = substr($tmp, 0, 5);
01551                 $this->ARC4_init($okey);
01552                 $ovalue = $this->ARC4($user);
01553                 $this->objects[$id]['info']['O'] = $ovalue;
01554                 // now make the u value, phew.
01555                 $tmp = $this->md5_16($user . $ovalue . chr($options['p']) . chr(255) . chr(255) . chr(255)
01556                                          . $this->fileIdentifier);
01557                 $ukey = substr($tmp, 0, 5);
01558 
01559                 $this->ARC4_init($ukey);
01560                 $this->encryptionKey = $ukey;
01561                 $this->encrypted = 1;
01562                 $uvalue = $this->ARC4($pad);
01563 
01564                 $this->objects[$id]['info']['U'] = $uvalue;
01565                 $this->encryptionKey = $ukey;
01566 
01567                 // initialize the arc4 array
01568                 break;
01569 
01570             case 'out':
01571                 $res = "\n" . $id . " 0 obj\n<<";
01572 
01573                 $res .= "\n/Filter /Standard";
01574                 $res .= "\n/V 1";
01575                 $res .= "\n/R 2";
01576                 $res .= "\n/O (" . $this->filterText($o['info']['O']) . ')';
01577                 $res .= "\n/U (" . $this->filterText($o['info']['U']) . ')';
01578                 // and the p-value needs to be converted to account for the twos-complement approach
01579                 $o['info']['p'] = (($o['info']['p'] ^ 255) + 1) * -1;
01580                 $res .= "\n/P " . ($o['info']['p']);
01581                 $res .= "\n>>\nendobj\n";
01582 
01583                 return $res;
01584                 break;
01585             }
01586     }
01587 
01596     function md5_16($string)
01597     {
01598         $tmp = md5($string);
01599         $out = '';
01600 
01601         for ($i = 0; $i <= 30; $i = $i + 2)
01602         {
01603             $out .= chr(hexdec(substr($tmp, $i, 2)));
01604         }
01605 
01606         return $out;
01607     }
01608 
01612     function encryptInit($id)
01613     {
01614         $tmp = $this->encryptionKey;
01615         $hex = dechex($id);
01616 
01617         if (strlen($hex) < 6)
01618         {
01619             $hex = substr('000000', 0, 6 - strlen($hex)) . $hex;
01620         }
01621 
01622         $tmp .= chr(hexdec(substr($hex, 4, 2))) . chr(hexdec(substr($hex, 2, 2))) . chr(hexdec(substr($hex, 0,
01623                                                                                                       2))) . chr(0)
01624                     . chr(0);
01625         $key = $this->md5_16($tmp);
01626         $this->ARC4_init(substr($key, 0, 10));
01627     }
01628 
01632     function ARC4_init($key = '')
01633     {
01634         $this->arc4 = '';
01635 
01636         // setup the control array
01637         if (strlen($key) == 0)
01638         {
01639             return;
01640         }
01641 
01642         $k = '';
01643 
01644         while (strlen($k) < 256)
01645         {
01646             $k .= $key;
01647         }
01648 
01649         $k = substr($k, 0, 256);
01650 
01651         for ($i = 0; $i < 256; $i++)
01652         {
01653             $this->arc4 .= chr($i);
01654         }
01655 
01656         $j = 0;
01657 
01658         for ($i = 0; $i < 256; $i++)
01659         {
01660             $t = $this->arc4[$i];
01661             $j = ($j + ord($t) + ord($k[$i])) % 256;
01662             $this->arc4[$i] = $this->arc4[$j];
01663             $this->arc4[$j] = $t;
01664         }
01665     }
01666 
01670     function ARC4($text)
01671     {
01672         $len = strlen($text);
01673         $a = 0;
01674         $b = 0;
01675         $c = $this->arc4;
01676         $out = '';
01677 
01678         for ($i = 0; $i < $len; $i++)
01679         {
01680             $a = ($a + 1) % 256;
01681             $t = $c[$a];
01682             $b = ($b + ord($t)) % 256;
01683             $c[$a] = $c[$b];
01684             $c[$b] = $t;
01685             $k = ord($c[(ord($c[$a]) + ord($c[$b])) % 256]);
01686             $out .= chr(ord($text[$i]) ^ $k);
01687         }
01688 
01689         return $out;
01690     }
01691 
01699     function addLink($url, $x0, $y0, $x1, $y1)
01700     {
01701         $this->numObj++;
01702         $info = array
01703             (
01704             'type' => 'link',
01705             'url' => $url,
01706             'rect' => array($x0, $y0, $x1, $y1)
01707             );
01708 
01709         $this->o_annotation($this->numObj, 'new', $info);
01710     }
01711 
01715     function addInternalLink($label, $x0, $y0, $x1, $y1)
01716     {
01717         $this->numObj++;
01718         $info = array
01719             (
01720             'type' => 'ilink',
01721             'label' => $label,
01722             'rect' => array($x0, $y0, $x1, $y1)
01723             );
01724 
01725         $this->o_annotation($this->numObj, 'new', $info);
01726     }
01727 
01733     function setEncryption($userPass = '', $ownerPass = '', $pc = array(
01734         ))
01735     {
01736         $p = bindec(11000000);
01737 
01738         $options = array
01739             (
01740             'print' => 4,
01741             'modify' => 8,
01742             'copy' => 16,
01743             'add' => 32
01744             );
01745 
01746         foreach ($pc as $k => $v)
01747         {
01748             if ($v && isset($options[$k]))
01749             {
01750                 $p += $options[$k];
01751             }
01752             else if (isset($options[$v]))
01753             {
01754                 $p += $options[$v];
01755             }
01756         }
01757 
01758         // implement encryption on the document
01759         if ($this->arc4_objnum == 0)
01760         {
01761             // then the block does not exist already, add it.
01762             $this->numObj++;
01763 
01764             if (strlen($ownerPass) == 0)
01765             {
01766                 $ownerPass = $userPass;
01767             }
01768 
01769             $this->o_encryption($this->numObj, 'new', array('user' => $userPass, 'owner' => $ownerPass, 'p' => $p));
01770         }
01771     }
01772 
01776     function checkAllHere()
01777     {
01778     }
01779 
01783     function output($debug = 0)
01784     {
01785         if ($debug)
01786         {
01787             // turn compression off
01788             $this->options['compression'] = 0;
01789         }
01790 
01791         if ($this->arc4_objnum)
01792         {
01793             $this->ARC4_init($this->encryptionKey);
01794         }
01795 
01796         $this->checkAllHere();
01797 
01798         $xref = array(
01799             );
01800 
01801         $content = "%PDF-1.3\n%âãÏÓ\n";
01802         //  $content="%PDF-1.3\n";
01803         $pos = strlen($content);
01804 
01805         foreach ($this->objects as $k => $v)
01806         {
01807             $tmp = 'o_' . $v['t'];
01808             $cont = $this->$tmp($k, 'out');
01809             $content .= $cont;
01810             $xref[] = $pos;
01811             $pos += strlen($cont);
01812         }
01813 
01814         $content .= "\nxref\n0 " . (count($xref) + 1) . "\n0000000000 65535 f \n";
01815 
01816         foreach ($xref as $p)
01817         {
01818             $content .= substr('0000000000', 0, 10 - strlen($p)) . $p . " 00000 n \n";
01819         }
01820 
01821         $content .= "\ntrailer\n  << /Size " . (count($xref)
01822                                                    + 1) . "\n     /Root 1 0 R\n     /Info " . $this->infoObject
01823                         . " 0 R\n";
01824 
01825         // if encryption has been applied to this document then add the marker for this dictionary
01826         if ($this->arc4_objnum > 0)
01827         {
01828             $content .= "/Encrypt " . $this->arc4_objnum . " 0 R\n";
01829         }
01830 
01831         if (strlen($this->fileIdentifier))
01832         {
01833             $content .= "/ID[<" . $this->fileIdentifier . "><" . $this->fileIdentifier . ">]\n";
01834         }
01835 
01836         $content .= "  >>\nstartxref\n" . $pos . "\n%%EOF\n";
01837         return $content;
01838     }
01839 
01847     function newDocument($pageSize = array(0, 0, 612, 792))
01848     {
01849         $this->numObj = 0;
01850         $this->objects = array(
01851             );
01852 
01853         $this->numObj++;
01854         $this->o_catalog($this->numObj, 'new');
01855 
01856         $this->numObj++;
01857         $this->o_outlines($this->numObj, 'new');
01858 
01859         $this->numObj++;
01860         $this->o_pages($this->numObj, 'new');
01861 
01862         $this->o_pages($this->numObj, 'mediaBox', $pageSize);
01863         $this->currentNode = 3;
01864 
01865         $this->numObj++;
01866         $this->o_procset($this->numObj, 'new');
01867 
01868         $this->numObj++;
01869         $this->o_info($this->numObj, 'new');
01870 
01871         $this->numObj++;
01872         $this->o_page($this->numObj, 'new');
01873 
01874         // need to store the first page id as there is no way to get it to the user during 
01875         // startup
01876         $this->firstPageId = $this->currentContents;
01877     }
01878 
01888     function openFont($font)
01889     {
01890         // assume that $font contains both the path and perhaps the extension to the file, split them
01891         $pos = strrpos($font, '/');
01892 
01893         if ($pos === false)
01894         {
01895             $dir = './';
01896             $name = $font;
01897         }
01898         else
01899         {
01900             $dir = substr($font, 0, $pos + 1);
01901             $name = substr($font, $pos + 1);
01902         }
01903 
01904         if (substr($name, -4) == '.afm')
01905         {
01906             $name = substr($name, 0, strlen($name) - 4);
01907         }
01908 
01909         $this->addMessage('openFont: ' . $font . ' - ' . $name);
01910 
01911         if (file_exists($dir . 'php_' . $name . '.afm'))
01912         {
01913             $this->addMessage('openFont: php file exists ' . $dir . 'php_' . $name . '.afm');
01914             $tmp = file($dir . 'php_' . $name . '.afm');
01915             $this->fonts[$font] = unserialize($tmp[0]);
01916 
01917             if (!isset($this->fonts[$font]['_version_']) || $this->fonts[$font]['_version_'] < 1)
01918             {
01919                 // if the font file is old, then clear it out and prepare for re-creation
01920                 $this->addMessage('openFont: clear out, make way for new version.');
01921                 unset($this->fonts[$font]);
01922             }
01923         }
01924 
01925         if (!isset($this->fonts[$font]) && file_exists($dir . $name . '.afm'))
01926         {
01927             // then rebuild the php_<font>.afm file from the <font>.afm file
01928             $this->addMessage('openFont: build php file from ' . $dir . $name . '.afm');
01929             $data = array(
01930                 );
01931 
01932             $file = file($dir . $name . '.afm');
01933 
01934             foreach ($file as $rowA)
01935             {
01936                 $row = trim($rowA);
01937                 $pos = strpos($row, ' ');
01938 
01939                 if ($pos)
01940                 {
01941                     // then there must be some keyword
01942                     $key = substr($row, 0, $pos);
01943 
01944                     switch ($key)
01945                         {
01946                         case 'FontName':
01947                         case 'FullName':
01948                         case 'FamilyName':
01949                         case 'Weight':
01950                         case 'ItalicAngle':
01951                         case 'IsFixedPitch':
01952                         case 'CharacterSet':
01953                         case 'UnderlinePosition':
01954                         case 'UnderlineThickness':
01955                         case 'Version':
01956                         case 'EncodingScheme':
01957                         case 'CapHeight':
01958                         case 'XHeight':
01959                         case 'Ascender':
01960                         case 'Descender':
01961                         case 'StdHW':
01962                         case 'StdVW':
01963                         case 'StartCharMetrics':
01964                             $data[$key] = trim(substr($row, $pos));
01965 
01966                             break;
01967 
01968                         case 'FontBBox':
01969                             $data[$key] = explode(' ', trim(substr($row, $pos)));
01970 
01971                             break;
01972 
01973                         case 'C':
01974                             //C 39 ; WX 222 ; N quoteright ; B 53 463 157 718 ;
01975                             $bits = explode(';', trim($row));
01976 
01977                             $dtmp = array(
01978                                 );
01979 
01980                             foreach ($bits as $bit)
01981                             {
01982                                 $bits2 = explode(' ', trim($bit));
01983 
01984                                 if (strlen($bits2[0]))
01985                                 {
01986                                     if (count($bits2) > 2)
01987                                     {
01988                                         $dtmp[$bits2[0]] = array(
01989                                             );
01990 
01991                                         for ($i = 1; $i < count($bits2); $i++)
01992                                         {
01993                                             $dtmp[$bits2[0]][] = $bits2[$i];
01994                                         }
01995                                     }
01996                                     else if (count($bits2) == 2)
01997                                     {
01998                                         $dtmp[$bits2[0]] = $bits2[1];
01999                                     }
02000                                 }
02001                             }
02002 
02003                             if ($dtmp['C'] >= 0)
02004                             {
02005                                 $data['C'][$dtmp['C']] = $dtmp;
02006                                 $data['C'][$dtmp['N']] = $dtmp;
02007                             }
02008                             else
02009                             {
02010                                 $data['C'][$dtmp['N']] = $dtmp;
02011                             }
02012 
02013                             break;
02014 
02015                         case 'KPX':
02016                             //KPX Adieresis yacute -40
02017                             $bits = explode(' ', trim($row));
02018 
02019                             $data['KPX'][$bits[1]][$bits[2]] = $bits[3];
02020                             break;
02021                         }
02022                 }
02023             }
02024 
02025             $data['_version_'] = 1;
02026             $this->fonts[$font] = $data;
02027             $fp = fopen($dir . 'php_' . $name . '.afm', 'w');
02028             fwrite($fp, serialize($data));
02029             fclose($fp);
02030         }
02031         else if (!isset($this->fonts[$font]))
02032         {
02033             $this->addMessage('openFont: no font file found');
02034         //    echo 'Font not Found '.$font;
02035         }
02036     }
02037 
02046     function selectFont($fontName, $encoding = '', $set = 1)
02047     {
02048         if (strpos($fontName, $this->fonts_path) === false)
02049             $fontName = $this->fonts_path . '/' . $fontName;
02050         //echo $fontName;
02051 
02052         if (!isset($this->fonts[$fontName]))
02053         {
02054             // load the file
02055             $this->openFont($fontName);
02056 
02057             if (isset($this->fonts[$fontName]))
02058             {
02059                 $this->numObj++;
02060                 $this->numFonts++;
02061                 $pos = strrpos($fontName, '/');
02062                 //      $dir=substr($fontName,0,$pos+1);
02063                 $name = substr($fontName, $pos + 1);
02064 
02065                 if (substr($name, -4) == '.afm')
02066                 {
02067                     $name = substr($name, 0, strlen($name) - 4);
02068                 }
02069 
02070                 $options = array('name' => $name);
02071 
02072                 if (is_array($encoding))
02073                 {
02074                     // then encoding and differences might be set
02075                     if (isset($encoding['encoding']))
02076                     {
02077                         $options['encoding'] = $encoding['encoding'];
02078                     }
02079 
02080                     if (isset($encoding['differences']))
02081                     {
02082                         $options['differences'] = $encoding['differences'];
02083                     }
02084                 }
02085                 else if (strlen($encoding))
02086                 {
02087                     // then perhaps only the encoding has been set
02088                     $options['encoding'] = $encoding;
02089                 }
02090 
02091                 $fontObj = $this->numObj;
02092                 $this->o_font($this->numObj, 'new', $options);
02093                 $this->fonts[$fontName]['fontNum'] = $this->numFonts;
02094                 // if this is a '.afm' font, and there is a '.pfa' file to go with it ( as there
02095                 // should be for all non-basic fonts), then load it into an object and put the
02096                 // references into the font object
02097                 $basefile = substr($fontName, 0, strlen($fontName) - 4);
02098 
02099                 if (file_exists($basefile . '.pfb'))
02100                 {
02101                     $fbtype = 'pfb';
02102                 }
02103                 else if (file_exists($basefile . '.ttf'))
02104                 {
02105                     $fbtype = 'ttf';
02106                 }
02107                 else
02108                 {
02109                     $fbtype = '';
02110                 }
02111 
02112                 $fbfile = $basefile . '.' . $fbtype;
02113 
02114                 //      $pfbfile = substr($fontName,0,strlen($fontName)-4).'.pfb';
02115                 //      $ttffile = substr($fontName,0,strlen($fontName)-4).'.ttf';
02116                 $this->addMessage('selectFont: checking for - ' . $fbfile);
02117 
02118                 if (substr($fontName, -4) == '.afm' && strlen($fbtype))
02119                 {
02120                     $adobeFontName = $this->fonts[$fontName]['FontName'];
02121                     //        $fontObj = $this->numObj;
02122                     $this->addMessage('selectFont: adding font file - ' . $fbfile . ' - ' . $adobeFontName);
02123                     // find the array of fond widths, and put that into an object.
02124                     $firstChar = -1;
02125                     $lastChar = 0;
02126                     $widths = array(
02127                         );
02128 
02129                     foreach ($this->fonts[$fontName]['C'] as $num => $d)
02130                     {
02131                         if (intval($num) > 0 || $num == '0')
02132                         {
02133                             if ($lastChar > 0 && $num > $lastChar + 1)
02134                             {
02135                                 for ($i = $lastChar + 1; $i < $num; $i++)
02136                                 {
02137                                     $widths[] = 0;
02138                                 }
02139                             }
02140 
02141                             $widths[] = $d['WX'];
02142 
02143                             if ($firstChar == -1)
02144                             {
02145                                 $firstChar = $num;
02146                             }
02147 
02148                             $lastChar = $num;
02149                         }
02150                     }
02151 
02152                     // also need to adjust the widths for the differences array
02153                     if (isset($options['differences']))
02154                     {
02155                         foreach ($options['differences'] as $charNum => $charName)
02156                         {
02157                             if ($charNum > $lastChar)
02158                             {
02159                                 for ($i = $lastChar + 1; $i <= $charNum; $i++)
02160                                 {
02161                                     $widths[] = 0;
02162                                 }
02163 
02164                                 $lastChar = $charNum;
02165                             }
02166 
02167                             if (isset($this->fonts[$fontName]['C'][$charName]))
02168                             {
02169                                 $widths[$charNum - $firstChar] = $this->fonts[$fontName]['C'][$charName]['WX'];
02170                             }
02171                         }
02172                     }
02173 
02174                     $this->addMessage('selectFont: FirstChar=' . $firstChar);
02175                     $this->addMessage('selectFont: LastChar=' . $lastChar);
02176                     $this->numObj++;
02177                     $this->o_contents($this->numObj, 'new', 'raw');
02178                     $this->objects[$this->numObj]['c'] .= '[';
02179 
02180                     foreach ($widths as $width)
02181                     {
02182                         $this->objects[$this->numObj]['c'] .= ' ' . $width;
02183                     }
02184 
02185                     $this->objects[$this->numObj]['c'] .= ' ]';
02186                     $widthid = $this->numObj;
02187 
02188                     // load the pfb file, and put that into an object too.
02189                     // note that pdf supports only binary format type 1 font files, though there is a 
02190                     // simple utility to convert them from pfa to pfb.
02191                     $fp = fopen($fbfile, 'rb');
02192                     $tmp = get_magic_quotes_runtime();
02193                     set_magic_quotes_runtime(0);
02194                     $data = fread($fp, filesize($fbfile));
02195                     set_magic_quotes_runtime($tmp);
02196                     fclose($fp);
02197 
02198                     // create the font descriptor
02199                     $this->numObj++;
02200                     $fontDescriptorId = $this->numObj;
02201                     $this->numObj++;
02202                     $pfbid = $this->numObj;
02203                     // determine flags (more than a little flakey, hopefully will not matter much)
02204                     $flags = 0;
02205 
02206                     if ($this->fonts[$fontName]['ItalicAngle'] != 0)
02207                     {
02208                         $flags += pow(2, 6);
02209                     }
02210 
02211                     if ($this->fonts[$fontName]['IsFixedPitch'] == 'true')
02212                     {
02213                         $flags += 1;
02214                     }
02215 
02216                     $flags += pow(2, 5); // assume non-sybolic
02217 
02218                     $list = array
02219                         (
02220                         'Ascent' => 'Ascender',
02221                         'CapHeight' => 'CapHeight',
02222                         'Descent' => 'Descender',
02223                         'FontBBox' => 'FontBBox',
02224                         'ItalicAngle' => 'ItalicAngle'
02225                         );
02226 
02227                     $fdopt = array
02228                         (
02229                         'Flags' => $flags,
02230                         'FontName' => $adobeFontName,
02231                         'StemV' => 100 // don't know what the value for this should be!
02232                         );
02233 
02234                     foreach ($list as $k => $v)
02235                     {
02236                         if (isset($this->fonts[$fontName][$v]))
02237                         {
02238                             $fdopt[$k] = $this->fonts[$fontName][$v];
02239                         }
02240                     }
02241 
02242                     if ($fbtype == 'pfb')
02243                     {
02244                         $fdopt['FontFile'] = $pfbid;
02245                     }
02246                     else if ($fbtype == 'ttf')
02247                     {
02248                         $fdopt['FontFile2'] = $pfbid;
02249                     }
02250 
02251                     $this->o_fontDescriptor($fontDescriptorId, 'new', $fdopt);
02252 
02253                     // embed the font program
02254                     $this->o_contents($this->numObj, 'new');
02255                     $this->objects[$pfbid]['c'] .= $data;
02256 
02257                     // determine the cruicial lengths within this file
02258                     if ($fbtype == 'pfb')
02259                     {
02260                         $l1 = strpos($data, 'eexec') + 6;
02261                         $l2 = strpos($data, '00000000') - $l1;
02262                         $l3 = strlen($data) - $l2 - $l1;
02263                         $this->o_contents($this->numObj, 'add',
02264                                           array('Length1' => $l1, 'Length2' => $l2, 'Length3' => $l3));
02265                     }
02266                     else if ($fbtype == 'ttf')
02267                     {
02268                         $l1 = strlen($data);
02269                         $this->o_contents($this->numObj, 'add', array('Length1' => $l1));
02270                     }
02271 
02272                     // tell the font object about all this new stuff
02273                     $tmp = array
02274                         (
02275                         'BaseFont' => $adobeFontName,
02276                         'Widths' => $widthid,
02277                         'FirstChar' => $firstChar,
02278                         'LastChar' => $lastChar,
02279                         'FontDescriptor' => $fontDescriptorId
02280                         );
02281 
02282                     if ($fbtype == 'ttf')
02283                     {
02284                         $tmp['SubType'] = 'TrueType';
02285                     }
02286 
02287                     $this->addMessage('adding extra info to font.(' . $fontObj . ')');
02288 
02289                     foreach ($tmp as $fk => $fv)
02290                     {
02291                         $this->addMessage($fk . " : " . $fv);
02292                     }
02293 
02294                     $this->o_font($fontObj, 'add', $tmp);
02295                 }
02296                 else
02297                 {
02298                     $this->addMessage(
02299                         'selectFont: pfb or ttf file not found, ok if this is one of the 14 standard fonts');
02300                 }
02301 
02302                 // also set the differences here, note that this means that these will take effect only the 
02303                 //first time that a font is selected, else they are ignored
02304                 if (isset($options['differences']))
02305                 {
02306                     $this->fonts[$fontName]['differences'] = $options['differences'];
02307                 }
02308             }
02309         }
02310 
02311         if ($set && isset($this->fonts[$fontName]))
02312         {
02313             // so if for some reason the font was not set in the last one then it will not be selected
02314             $this->currentBaseFont = $fontName;
02315             // the next line means that if a new font is selected, then the current text state will be
02316             // applied to it as well.
02317             $this->setCurrentFont();
02318         }
02319 
02320         return $this->currentFontNum;
02321     }
02322 
02335     function setCurrentFont()
02336     {
02337         if (strlen($this->currentBaseFont) == 0)
02338         {
02339             // then assume an initial font
02340             $this->selectFont($this->fonts_path . '/Helvetica.afm');
02341         }
02342 
02343         $cf = substr($this->currentBaseFont, strrpos($this->currentBaseFont, '/') + 1);
02344 
02345         if (strlen($this->currentTextState) && isset($this->fontFamilies[$cf]) && isset(
02346                                                                                       $this->fontFamilies[$cf][$this->currentTextState]))
02347         {
02348             // then we are in some state or another
02349             // and this font has a family, and the current setting exists within it
02350             // select the font, then return it
02351             $nf = substr($this->currentBaseFont, 0,
02352                          strrpos($this->currentBaseFont, '/') + 1) . $this->fontFamilies[$cf][$this->currentTextState];
02353             $this->selectFont($nf, '', 0);
02354             $this->currentFont = $nf;
02355             $this->currentFontNum = $this->fonts[$nf]['fontNum'];
02356         }
02357         else
02358         {
02359             // the this font must not have the right family member for the current state
02360             // simply assume the base font
02361             $this->currentFont = $this->currentBaseFont;
02362             $this->currentFontNum = $this->fonts[$this->currentFont]['fontNum'];
02363         }
02364     }
02365 
02370     function getFirstPageId()
02371     {
02372         return $this->firstPageId;
02373     }
02374 
02380     function addContent($content)
02381     {
02382         $this->objects[$this->currentContents]['c'] .= $content;
02383     }
02384 
02388     function setColor($r, $g, $b, $force = 0)
02389     {
02390         if ($r >= 0 && ($force || $r != $this->currentColour['r'] || $g != $this->currentColour['g']
02391                            || $b != $this->currentColour['b']))
02392         {
02393             $this->objects[$this->currentContents]['c'] .= "\n" . __sprintf('%.3f',
02394                                                                             $r) . ' ' . __sprintf('%.3f',
02395                                                                                                   $g) . ' '
02396                                                                . __sprintf('%.3f', $b) . ' rg';
02397             $this->currentColour = array
02398                 (
02399                 'r' => $r,
02400                 'g' => $g,
02401                 'b' => $b
02402                 );
02403         }
02404     }
02405 
02409     function setStrokeColor($r, $g, $b, $force = 0)
02410     {
02411         if ($r >= 0 && ($force || $r != $this->currentStrokeColour['r'] || $g != $this->currentStrokeColour['g']
02412                            || $b != $this->currentStrokeColour['b']))
02413         {
02414             $this->objects[$this->currentContents]['c'] .= "\n" . __sprintf('%.3f',
02415                                                                             $r) . ' ' . __sprintf('%.3f',
02416                                                                                                   $g) . ' '
02417                                                                . __sprintf('%.3f', $b) . ' RG';
02418             $this->currentStrokeColour = array
02419                 (
02420                 'r' => $r,
02421                 'g' => $g,
02422                 'b' => $b
02423                 );
02424         }
02425     }
02426 
02430     function line($x1, $y1, $x2, $y2)
02431     {
02432         $this->objects[$this->currentContents]['c'] .= "\n" . __sprintf('%.3f',
02433                                                                         $x1) . ' ' . __sprintf('%.3f',
02434                                                                                                $y1) . ' m '
02435                                                            . __sprintf('%.3f',
02436                                                                        $x2) . ' ' . __sprintf('%.3f', $y2) . ' l S';
02437     }
02438 
02442     function curve($x0, $y0, $x1, $y1, $x2, $y2, $x3, $y3)
02443     {
02444         // in the current line style, draw a bezier curve from (x0,y0) to (x3,y3) using the other two points
02445         // as the control points for the curve.
02446         $this->objects[$this->currentContents]['c'] .= "\n" . __sprintf('%.3f',
02447                                                                         $x0) . ' ' . __sprintf('%.3f',
02448                                                                                                $y0) . ' m '
02449                                                            . __sprintf('%.3f', $x1) . ' ' . __sprintf('%.3f', $y1);
02450         $this->objects[$this->currentContents]['c'] .= ' ' . __sprintf('%.3f',
02451                                                                        $x2) . ' ' . __sprintf('%.3f',
02452                                                                                               $y2) . ' '
02453                                                            . __sprintf('%.3f',
02454                                                                        $x3) . ' ' . __sprintf('%.3f', $y3) . ' c S';
02455     }
02456 
02460     function partEllipse($x0, $y0, $astart, $afinish, $r1, $r2 = 0, $angle = 0, $nSeg = 8)
02461     {
02462         $this->ellipse($x0, $y0, $r1, $r2, $angle, $nSeg, $astart, $afinish, 0);
02463     }
02464 
02468     function filledEllipse($x0, $y0, $r1, $r2 = 0, $angle = 0, $nSeg = 8, $astart = 0, $afinish = 360)
02469     {
02470         return $this->ellipse($x0, $y0, $r1, $r2 = 0, $angle, $nSeg, $astart, $afinish, 1, 1);
02471     }
02472 
02483     function ellipse($x0, $y0, $r1, $r2 = 0, $angle = 0, $nSeg = 8, $astart = 0, $afinish = 360, $close = 1, $fill = 0)
02484     {
02485         if ($r1 == 0)
02486         {
02487             return;
02488         }
02489 
02490         if ($r2 == 0)
02491         {
02492             $r2 = $r1;
02493         }
02494 
02495         if ($nSeg < 2)
02496         {
02497             $nSeg = 2;
02498         }
02499 
02500         $astart = deg2rad((float)$astart);
02501         $afinish = deg2rad((float)$afinish);
02502         $totalAngle = $afinish - $astart;
02503 
02504         $dt = $totalAngle / $nSeg;
02505         $dtm = $dt / 3;
02506 
02507         if ($angle != 0)
02508         {
02509             $a = -1 * deg2rad((float)$angle);
02510             $tmp = "\n q ";
02511             $tmp .= __sprintf('%.3f',
02512                               cos($a)) . ' ' . __sprintf('%.3f',
02513                                                          (-1.0 * sin($a))) . ' ' . __sprintf('%.3f',
02514                                                                                              sin($a)) . ' '
02515                         . __sprintf('%.3f', cos($a)) . ' ';
02516             $tmp .= __sprintf('%.3f', $x0) . ' ' . __sprintf('%.3f', $y0) . ' cm';
02517             $this->objects[$this->currentContents]['c'] .= $tmp;
02518             $x0 = 0;
02519             $y0 = 0;
02520         }
02521 
02522         $t1 = $astart;
02523         $a0 = $x0 + $r1 * cos($t1);
02524         $b0 = $y0 + $r2 * sin($t1);
02525         $c0 = -$r1 * sin($t1);
02526         $d0 = $r2 * cos($t1);
02527 
02528         $this->objects[$this->currentContents]['c'] .= "\n" . __sprintf('%.3f',
02529                                                                         $a0) . ' ' . __sprintf('%.3f', $b0) . ' m ';
02530 
02531         for ($i = 1; $i <= $nSeg; $i++)
02532         {
02533             // draw this bit of the total curve
02534             $t1 = $i * $dt + $astart;
02535             $a1 = $x0 + $r1 * cos($t1);
02536             $b1 = $y0 + $r2 * sin($t1);
02537             $c1 = -$r1 * sin($t1);
02538             $d1 = $r2 * cos($t1);
02539             $this->objects[$this->currentContents]['c'] .= "\n" . __sprintf('%.3f',
02540                                                                             ($a0 + $c0 * $dtm)) . ' ' . __sprintf(
02541                                                                                                             '%.3f',
02542                                                                                                             ($b0 + $d0
02543                                                                                                                 * $dtm));
02544             $this->objects[$this->currentContents]['c'] .= ' ' . __sprintf('%.3f',
02545                                                                            ($a1 - $c1 * $dtm)) . ' ' . __sprintf(
02546                                                                                                            '%.3f',
02547                                                                                                            ($b1 - $d1
02548                                                                                                                * $dtm))
02549                                                                . ' ' . __sprintf(
02550                                                                            '%.3f',
02551                                                                            $a1) . ' ' . __sprintf('%.3f', $b1) . ' c';
02552             $a0 = $a1;
02553             $b0 = $b1;
02554             $c0 = $c1;
02555             $d0 = $d1;
02556         }
02557 
02558         if ($fill)
02559         {
02560             $this->objects[$this->currentContents]['c'] .= ' f';
02561         }
02562         else
02563         {
02564             if ($close)
02565             {
02566                 $this->objects[$this->currentContents]['c'] .= ' s'; // small 's' signifies closing the path as well
02567             }
02568             else
02569             {
02570                 $this->objects[$this->currentContents]['c'] .= ' S';
02571             }
02572         }
02573 
02574         if ($angle != 0)
02575         {
02576             $this->objects[$this->currentContents]['c'] .= ' Q';
02577         }
02578     }
02579 
02593     function setLineStyle($width = 1, $cap = '', $join = '', $dash = '', $phase = 0)
02594     {
02595 
02596         // this is quite inefficient in that it sets all the parameters whenever 1 is changed, but will fix another day
02597         $string = '';
02598 
02599         if ($width > 0)
02600         {
02601             $string .= $width . ' w';
02602         }
02603 
02604         $ca = array
02605             (
02606             'butt' => 0,
02607             'round' => 1,
02608             'square' => 2
02609             );
02610 
02611         if (isset($ca[$cap]))
02612         {
02613             $string .= ' ' . $ca[$cap] . ' J';
02614         }
02615 
02616         $ja = array
02617             (
02618             'miter' => 0,
02619             'round' => 1,
02620             'bevel' => 2
02621             );
02622 
02623         if (isset($ja[$join]))
02624         {
02625             $string .= ' ' . $ja[$join] . ' j';
02626         }
02627 
02628         if (is_array($dash))
02629         {
02630             $string .= ' [';
02631 
02632             foreach ($dash as $len)
02633             {
02634                 $string .= ' ' . $len;
02635             }
02636 
02637             $string .= ' ] ' . $phase . ' d';
02638         }
02639 
02640         $this->currentLineStyle = $string;
02641         $this->objects[$this->currentContents]['c'] .= "\n" . $string;
02642     }
02643 
02647     function polygon($p, $np, $f = 0)
02648     {
02649         $this->objects[$this->currentContents]['c'] .= "\n";
02650         $this->objects[$this->currentContents]['c'] .= __sprintf('%.3f',
02651                                                                  $p[0]) . ' ' . __sprintf('%.3f', $p[1]) . ' m ';
02652 
02653         for ($i = 2; $i < $np * 2; $i = $i + 2)
02654         {
02655             $this->objects[$this->currentContents]['c'] .= __sprintf('%.3f',
02656                                                                      $p[$i]) . ' ' . __sprintf('%.3f',
02657                                                                                                $p[$i + 1]) . ' l ';
02658         }
02659 
02660         if ($f == 1)
02661         {
02662             $this->objects[$this->currentContents]['c'] .= ' f';
02663         }
02664         else
02665         {
02666             $this->objects[$this->currentContents]['c'] .= ' S';
02667         }
02668     }
02669 
02674     function filledRectangle($x1, $y1, $width, $height)
02675     {
02676         $this->objects[$this->currentContents]['c'] .= "\n" . __sprintf('%.3f',
02677                                                                         $x1) . ' ' . __sprintf('%.3f',
02678                                                                                                $y1) . ' '
02679                                                            . __sprintf('%.3f',
02680                                                                        $width) . ' ' . __sprintf('%.3f',
02681                                                                                                  $height) . ' re f';
02682     }
02683 
02688     function rectangle($x1, $y1, $width, $height)
02689     {
02690         $this->objects[$this->currentContents]['c'] .= "\n" . __sprintf('%.3f',
02691                                                                         $x1) . ' ' . __sprintf('%.3f',
02692                                                                                                $y1) . ' '
02693                                                            . __sprintf('%.3f',
02694                                                                        $width) . ' ' . __sprintf('%.3f',
02695                                                                                                  $height) . ' re S';
02696     }
02697 
02702     function newPage($insert = 0, $id = 0, $pos = 'after')
02703     {
02704 
02705         // if there is a state saved, then go up the stack closing them
02706         // then on the new page, re-open them with the right setings
02707 
02708         if ($this->nStateStack)
02709         {
02710             for ($i = $this->nStateStack; $i >= 1; $i--)
02711             {
02712                 $this->restoreState($i);
02713             }
02714         }
02715 
02716         $this->numObj++;
02717 
02718         if ($insert)
02719         {
02720             // the id from the ezPdf class is the od of the contents of the page, not the page object itself
02721             // query that object to find the parent
02722             $rid = $this->objects[$id]['onPage'];
02723             $opt = array
02724                 (
02725                 'rid' => $rid,
02726                 'pos' => $pos
02727                 );
02728 
02729             $this->o_page($this->numObj, 'new', $opt);
02730         }
02731         else
02732         {
02733             $this->o_page($this->numObj, 'new');
02734         }
02735 
02736         // if there is a stack saved, then put that onto the page
02737         if ($this->nStateStack)
02738         {
02739             for ($i = 1; $i <= $this->nStateStack; $i++)
02740             {
02741                 $this->saveState($i);
02742             }
02743         }
02744 
02745         // and if there has been a stroke or fill colour set, then transfer them
02746         if ($this->currentColour['r'] >= 0)
02747         {
02748             $this->setColor($this->currentColour['r'], $this->currentColour['g'], $this->currentColour['b'], 1);
02749         }
02750 
02751         if ($this->currentStrokeColour['r'] >= 0)
02752         {
02753             $this->setStrokeColor($this->currentStrokeColour['r'], $this->currentStrokeColour['g'],
02754                                   $this->currentStrokeColour['b'], 1);
02755         }
02756 
02757         // if there is a line style set, then put this in too
02758         if (strlen($this->currentLineStyle))
02759         {
02760             $this->objects[$this->currentContents]['c'] .= "\n" . $this->currentLineStyle;
02761         }
02762 
02763         // the call to the o_page object set currentContents to the present page, so this can be returned as the page id
02764         return $this->currentContents;
02765     }
02766 
02771     function stream($options = '')
02772     {
02773         // setting the options allows the adjustment of the headers
02774         // values at the moment are:
02775         // 'Content-Disposition'=>'filename'  - sets the filename, though not too sure how well this will 
02776         //        work as in my trial the browser seems to use the filename of the php file with .pdf on the end
02777         // 'Accept-Ranges'=>1 or 0 - if this is not set to 1, then this header is not included, off by default
02778         //    this header seems to have caused some problems despite tha fact that it is supposed to solve
02779         //    them, so I am leaving it off by default.
02780         // 'compress'=> 1 or 0 - apply content stream compression, this is on (1) by default
02781         if (!is_array($options))
02782         {
02783             $options = array(
02784                 );
02785         }
02786 
02787         if (isset($options['compress']) && $options['compress'] == 0)
02788         {
02789             $tmp = $this->output(1);
02790         }
02791         else
02792         {
02793             $tmp = $this->output();
02794         }
02795 
02796         header("Content-type: application/pdf");
02797         header("Content-Length: " . strlen(ltrim($tmp)));
02798         $fileName = (isset($options['Content-Disposition']) ? $options['Content-Disposition'] : 'file.pdf');
02799         header("Content-Disposition: inline; filename=" . $fileName);
02800 
02801         if (isset($options['Accept-Ranges']) && $options['Accept-Ranges'] == 1)
02802         {
02803             header("Accept-Ranges: " . strlen(ltrim($tmp)));
02804         }
02805 
02806         echo ltrim($tmp);
02807     }
02808 
02812     function getFontHeight($size)
02813     {
02814         if (!$this->numFonts)
02815         {
02816             $this->selectFont($this->fonts_path . '/Helvetica');
02817         }
02818 
02819         // for the current font, and the given size, what is the height of the font in user units
02820         $h = $this->fonts[$this->currentFont]['FontBBox'][3] - $this->fonts[$this->currentFont]['FontBBox'][1];
02821         return $size * $h / 1000;
02822     }
02823 
02829     function getFontDecender($size)
02830     {
02831         // note that this will most likely return a negative value
02832         if (!$this->numFonts)
02833         {
02834             $this->selectFont($this->fonts_path . '/Helvetica');
02835         }
02836 
02837         $h = $this->fonts[$this->currentFont]['FontBBox'][1];
02838         return $size * $h / 1000;
02839     }
02840 
02847     function filterText($text)
02848     {
02849         $text = str_replace('\\', '\\\\', $text);
02850         $text = str_replace('(', '\(', $text);
02851         $text = str_replace(')', '\)', $text);
02852         $text = str_replace('&lt;', '<', $text);
02853         $text = str_replace('&gt;', '>', $text);
02854         $text = str_replace('&#039;', '\'', $text);
02855         $text = str_replace('&quot;', '"', $text);
02856         $text = str_replace('&amp;', '&', $text);
02857 
02858         return $text;
02859     }
02860 
02867     function PRVTgetTextPosition($x, $y, $angle, $size, $wa, $text)
02868     {
02869         // given this information return an array containing x and y for the end position as elements 0 and 1
02870         $w = $this->getTextWidth($size, $text);
02871         // need to adjust for the number of spaces in this text
02872         $words = explode(' ', $text);
02873         $nspaces = count($words) - 1;
02874         $w += $wa * $nspaces;
02875         $a = deg2rad((float)$angle);
02876         return array(cos($a) * $w + $x, -sin($a) * $w + $y);
02877     }
02878 
02884     function PRVTcheckTextDirective(&$text, $i, &$f)
02885     {
02886         $x = 0;
02887         $y = 0;
02888         return $this->PRVTcheckTextDirective1($text, $i, $f, 0, $x, $y);
02889     }
02890 
02900     function PRVTcheckTextDirective1(&$text, $i, &$f, $final, &$x, &$y, $size = 0, $angle = 0, $wordSpaceAdjust = 0)
02901     {
02902         $directive = 0;
02903         $j = $i;
02904 
02905         if ($text[$j] == '<')
02906         {
02907             $j++;
02908 
02909             switch ($text[$j])
02910                 {
02911                 case '/':
02912                     $j++;
02913 
02914                     if (strlen($text) <= $j)
02915                     {
02916                         return $directive;
02917                     }
02918 
02919                     switch ($text[$j])
02920                         {
02921                         case 'b':
02922                         case 'i':
02923                             $j++;
02924 
02925                             if ($text[$j] == '>')
02926                             {
02927                                 $p = strrpos($this->currentTextState, $text[$j - 1]);
02928 
02929                                 if ($p !== false)
02930                                 {
02931                                     // then there is one to remove
02932                                     $this->currentTextState = substr($this->currentTextState, 0,
02933                                                                      $p) . substr($this->currentTextState, $p + 1);
02934                                 }
02935 
02936                                 $directive = $j - $i + 1;
02937                             }
02938 
02939                             break;
02940 
02941                         case 'c':
02942                             // this this might be a callback function
02943                             $j++;
02944 
02945                             $k = strpos($text, '>', $j);
02946 
02947                             if ($k !== false && $text[$j] == ':')
02948                             {
02949                                 // then this will be treated as a callback directive
02950                                 $directive = $k - $i + 1;
02951                                 $f = 0;
02952                                 // split the remainder on colons to get the function name and the paramater
02953                                 $tmp = substr($text, $j + 1, $k - $j - 1);
02954                                 $b1 = strpos($tmp, ':');
02955 
02956                                 if ($b1 !== false)
02957                                 {
02958                                     $func = substr($tmp, 0, $b1);
02959                                     $parm = substr($tmp, $b1 + 1);
02960                                 }
02961                                 else
02962                                 {
02963                                     $func = $tmp;
02964                                     $parm = '';
02965                                 }
02966 
02967                                 if (!isset($func) || !strlen(trim($func)))
02968                                 {
02969                                     $directive = 0;
02970                                 }
02971                                 else
02972                                 {
02973                                     // only call the function if this is the final call
02974                                     if ($final)
02975                                     {
02976                                         // need to assess the text position, calculate the text width to this point
02977                                         // can use getTextWidth to find the text width I think
02978                                         $tmp = $this->PRVTgetTextPosition(
02979                                                    $x, $y, $angle, $size, $wordSpaceAdjust, substr($text, 0, $i));
02980                                         $info = array
02981                                             (
02982                                             'x' => $tmp[0],
02983                                             'y' => $tmp[1],
02984                                             'angle' => $angle,
02985                                             'status' => 'end',
02986                                             'p' => $parm,
02987                                             'nCallback' => $this->nCallback
02988                                             );
02989 
02990                                         $x = $tmp[0];
02991                                         $y = $tmp[1];
02992                                         $ret = $this->$func($info);
02993 
02994                                         if (is_array($ret))
02995                                         {
02996                                             // then the return from the callback function could set the position, to start with, later will do font colour, and font
02997                                             foreach ($ret as $rk => $rv)
02998                                             {
02999                                                 switch ($rk)
03000                                                     {
03001                                                     case 'x':
03002                                                     case 'y':
03003                                                         $$rk = $rv;
03004 
03005                                                         break;
03006                                                     }
03007                                             }
03008                                         }
03009 
03010                                         // also remove from to the stack
03011                                         // for simplicity, just take from the end, fix this another day
03012                                         $this->nCallback--;
03013 
03014                                         if ($this->nCallback < 0)
03015                                         {
03016                                             $this->nCallBack = 0;
03017                                         }
03018                                     }
03019                                 }
03020                             }
03021 
03022                             break;
03023                         }
03024 
03025                     break;
03026 
03027                 case 'b':
03028                 case 'i':
03029                     $j++;
03030 
03031                     if ($text[$j] == '>')
03032                     {
03033                         $this->currentTextState .= $text[$j - 1];
03034                         $directive = $j - $i + 1;
03035                     }
03036 
03037                     break;
03038 
03039                 case 'C': $noClose = 1;
03040 
03041                 case 'c':
03042                     // this this might be a callback function
03043                     $j++;
03044 
03045                     $k = strpos($text, '>', $j);
03046 
03047                     if ($k !== false && $text[$j] == ':')
03048                     {
03049                         // then this will be treated as a callback directive
03050                         $directive = $k - $i + 1;
03051                         $f = 0;
03052                         // split the remainder on colons to get the function name and the paramater
03053                         //          $bits = explode(':',substr($text,$j+1,$k-$j-1));
03054                         $tmp = substr($text, $j + 1, $k - $j - 1);
03055                         $b1 = strpos($tmp, ':');
03056 
03057                         if ($b1 !== false)
03058                         {
03059                             $func = substr($tmp, 0, $b1);
03060                             $parm = substr($tmp, $b1 + 1);
03061                         }
03062                         else
03063                         {
03064                             $func = $tmp;
03065                             $parm = '';
03066                         }
03067 
03068                         if (!isset($func) || !strlen(trim($func)))
03069                         {
03070                             $directive = 0;
03071                         }
03072                         else
03073                         {
03074                             // only call the function if this is the final call, ie, the one actually doing printing, not measurement
03075                             if ($final)
03076                             {
03077                                 // need to assess the text position, calculate the text width to this point
03078                                 // can use getTextWidth to find the text width I think
03079                                 // also add the text height and decender
03080                                 $tmp = $this->PRVTgetTextPosition($x, $y, $angle, $size, $wordSpaceAdjust,
03081                                                                   substr($text, 0, $i));
03082                                 $info = array
03083                                     (
03084                                     'x' => $tmp[0],
03085                                     'y' => $tmp[1],
03086                                     'angle' => $angle,
03087                                     'status' => 'start',
03088                                     'p' => $parm,
03089                                     'f' => $func,
03090                                     'height' => $this->getFontHeight($size),
03091                                     'decender' => $this->getFontDecender($size)
03092                                     );
03093 
03094                                 $x = $tmp[0];
03095                                 $y = $tmp[1];
03096 
03097                                 if (!isset($noClose) || !$noClose)
03098                                 {
03099                                     // only add to the stack if this is a small 'c', therefore is a start-stop pair
03100                                     $this->nCallback++;
03101                                     $info['nCallback'] = $this->nCallback;
03102                                     $this->callback[$this->nCallback] = $info;
03103                                 }
03104 
03105                                 $ret = $this->$func($info);
03106 
03107                                 if (is_array($ret))
03108                                 {
03109                                     // then the return from the callback function could set the position, to start with, later will do font colour, and font
03110                                     foreach ($ret as $rk => $rv)
03111                                     {
03112                                         switch ($rk)
03113                                             {
03114                                             case 'x':
03115                                             case 'y':
03116                                                 $$rk = $rv;
03117 
03118                                                 break;
03119                                             }
03120                                     }
03121                                 }
03122                             }
03123                         }
03124                     }
03125 
03126                     break;
03127                 }
03128         }
03129 
03130         return $directive;
03131     }
03132 
03136     function addText($x, $y, $size, $text, $angle = 0, $wordSpaceAdjust = 0)
03137     {
03138         if (!$this->numFonts)
03139         {
03140             $this->selectFont($this->fonts_path . '/Helvetica');
03141         }
03142 
03143         // if there are any open callbacks, then they should be called, to show the start of the line
03144         if ($this->nCallback > 0)
03145         {
03146             for ($i = $this->nCallback; $i > 0; $i--)
03147             {
03148                 // call each function
03149                 $info = array
03150                     (
03151                     'x' => $x,
03152                     'y' => $y,
03153                     'angle' => $angle,
03154                     'status' => 'sol',
03155                     'p' => $this->callback[$i]['p'],
03156                     'nCallback' => $this->callback[$i]['nCallback'],
03157                     'height' => $this->callback[$i]['height'],
03158                     'decender' => $this->callback[$i]['decender']
03159                     );
03160 
03161                 $func = $this->callback[$i]['f'];
03162                 $this->$func($info);
03163             }
03164         }
03165 
03166         if ($angle == 0)
03167         {
03168             $this->objects[$this->currentContents]['c'] .= "\n" . 'BT ' . __sprintf('%.3f',
03169                                                                                     $x) . ' ' . __sprintf('%.3f',
03170                                                                                                           $y) . ' Td';
03171         }
03172         else
03173         {
03174             $a = deg2rad((float)$angle);
03175             $tmp = "\n" . 'BT ';
03176             $tmp .= __sprintf('%.3f',
03177                               cos($a)) . ' ' . __sprintf('%.3f',
03178                                                          (-1.0 * sin($a))) . ' ' . __sprintf('%.3f',
03179                                                                                              sin($a)) . ' '
03180                         . __sprintf('%.3f', cos($a)) . ' ';
03181             $tmp .= __sprintf('%.3f', $x) . ' ' . __sprintf('%.3f', $y) . ' Tm';
03182             $this->objects[$this->currentContents]['c'] .= $tmp;
03183         }
03184 
03185         if ($wordSpaceAdjust != 0 || $wordSpaceAdjust != $this->wordSpaceAdjust)
03186         {
03187             $this->wordSpaceAdjust = $wordSpaceAdjust;
03188             $this->objects[$this->currentContents]['c'] .= ' ' . __sprintf('%.3f', $wordSpaceAdjust) . ' Tw';
03189         }
03190 
03191         $len = strlen($text);
03192         $start = 0;
03193 
03194         for ($i = 0; $i < $len; $i++)
03195         {
03196             $f = 1;
03197             $directive = $this->PRVTcheckTextDirective($text, $i, $f);
03198 
03199             if ($directive)
03200             {
03201                 // then we should write what we need to
03202                 if ($i > $start)
03203                 {
03204                     $part = substr($text, $start, $i - $start);
03205                     $this->objects[$this->currentContents]['c']
03206                         .= ' /F' . $this->currentFontNum . ' ' . __sprintf('%.1f', $size) . ' Tf ';
03207                     $this->objects[$this->currentContents]['c'] .= ' (' . $this->filterText($part) . ') Tj';
03208                 }
03209 
03210                 if ($f)
03211                 {
03212                     // then there was nothing drastic done here, restore the contents
03213                     $this->setCurrentFont();
03214                 }
03215                 else
03216                 {
03217                     $this->objects[$this->currentContents]['c'] .= ' ET';
03218                     $f = 1;
03219                     $xp = $x;
03220                     $yp = $y;
03221                     $directive = $this->PRVTcheckTextDirective1(
03222                                      $text, $i, $f, 1, $xp, $yp, $size, $angle, $wordSpaceAdjust);
03223 
03224                     // restart the text object
03225                     if ($angle == 0)
03226                     {
03227                         $this->objects[$this->currentContents]['c'] .= "\n" . 'BT ' . __sprintf('%.3f',
03228                                                                                                 $xp) . ' '
03229                                                                            . __sprintf('%.3f', $yp) . ' Td';
03230                     }
03231                     else
03232                     {
03233                         $a = deg2rad((float)$angle);
03234                         $tmp = "\n" . 'BT ';
03235                         $tmp .= __sprintf('%.3f',
03236                                           cos($a)) . ' ' . __sprintf('%.3f',
03237                                                                      (-1.0 * sin($a))) . ' ' . __sprintf('%.3f',
03238                                                                                                          sin($a)) . ' '
03239                                     . __sprintf('%.3f', cos($a)) . ' ';
03240                         $tmp .= __sprintf('%.3f', $xp) . ' ' . __sprintf('%.3f', $yp) . ' Tm';
03241                         $this->objects[$this->currentContents]['c'] .= $tmp;
03242                     }
03243 
03244                     if ($wordSpaceAdjust != 0 || $wordSpaceAdjust != $this->wordSpaceAdjust)
03245                     {
03246                         $this->wordSpaceAdjust = $wordSpaceAdjust;
03247                         $this->objects[$this->currentContents]['c'] .= ' ' . __sprintf('%.3f',
03248                                                                                        $wordSpaceAdjust) . ' Tw';
03249                     }
03250                 }
03251 
03252                 // and move the writing point to the next piece of text
03253                 $i = $i + $directive - 1;
03254                 $start = $i + 1;
03255             }
03256         }
03257 
03258         if ($start < $len)
03259         {
03260             $part = substr($text, $start);
03261             $this->objects[$this->currentContents]['c'] .= ' /F' . $this->currentFontNum . ' ' . __sprintf('%.1f',
03262                                                                                                            $size)
03263                                                                . ' Tf ';
03264             $this->objects[$this->currentContents]['c'] .= ' (' . $this->filterText($part) . ') Tj';
03265         }
03266 
03267         $this->objects[$this->currentContents]['c'] .= ' ET';
03268 
03269         // if there are any open callbacks, then they should be called, to show the end of the line
03270         if ($this->nCallback > 0)
03271         {
03272             for ($i = $this->nCallback; $i > 0; $i--)
03273             {
03274                 // call each function
03275                 $tmp = $this->PRVTgetTextPosition($x, $y, $angle, $size, $wordSpaceAdjust, $text);
03276                 $info = array
03277                     (
03278                     'x' => $tmp[0],
03279                     'y' => $tmp[1],
03280                     'angle' => $angle,
03281                     'status' => 'eol',
03282                     'p' => $this->callback[$i]['p'],
03283                     'nCallback' => $this->callback[$i]['nCallback'],
03284                     'height' => $this->callback[$i]['height'],
03285                     'decender' => $this->callback[$i]['decender']
03286                     );
03287 
03288                 $func = $this->callback[$i]['f'];
03289                 $this->$func($info);
03290             }
03291         }
03292     }
03293 
03298     function getTextWidth($size, $text)
03299     {
03300         // this function should not change any of the settings, though it will need to
03301         // track any directives which change during calculation, so copy them at the start
03302         // and put them back at the end.
03303         $store_currentTextState = $this->currentTextState;
03304 
03305         if (!$this->numFonts)
03306         {
03307             $this->selectFont($this->fonts_path . '/Helvetica');
03308         }
03309 
03310         // converts a number or a float to a string so it can get the width
03311         $text = "$text";
03312 
03313         // hmm, this is where it all starts to get tricky - use the font information to
03314         // calculate the width of each character, add them up and convert to user units
03315         $w = 0;
03316         $len = strlen($text);
03317         $cf = $this->currentFont;
03318 
03319         for ($i = 0; $i < $len; $i++)
03320         {
03321             $f = 1;
03322             $directive = $this->PRVTcheckTextDirective($text, $i, $f);
03323 
03324             if ($directive)
03325             {
03326                 if ($f)
03327                 {
03328                     $this->setCurrentFont();
03329                     $cf = $this->currentFont;
03330                 }
03331 
03332                 $i = $i + $directive - 1;
03333             }
03334             else
03335             {
03336                 $char = ord($text[$i]);
03337 
03338                 if (isset($this->fonts[$cf]['differences'][$char]))
03339                 {
03340                     // then this character is being replaced by another
03341                     $name = $this->fonts[$cf]['differences'][$char];
03342 
03343                     if (isset($this->fonts[$cf]['C'][$name]['WX']))
03344                     {
03345                         $w += $this->fonts[$cf]['C'][$name]['WX'];
03346                     }
03347                 }
03348                 else if (isset($this->fonts[$cf]['C'][$char]['WX']))
03349                 {
03350                     $w += $this->fonts[$cf]['C'][$char]['WX'];
03351                 }
03352             }
03353         }
03354 
03355         $this->currentTextState = $store_currentTextState;
03356         $this->setCurrentFont();
03357 
03358         return $w * $size / 1000;
03359     }
03360 
03366     function PRVTadjustWrapText($text, $actual, $width, &$x, &$adjust, $justification)
03367     {
03368         switch ($justification)
03369             {
03370             case 'left':
03371                 return;
03372 
03373                 break;
03374 
03375             case 'right':
03376                 $x += $width - $actual;
03377 
03378                 break;
03379 
03380             case 'center':
03381             case 'centre':
03382                 $x += ($width - $actual) / 2;
03383 
03384                 break;
03385 
03386             case 'full':
03387                 // count the number of words
03388                 $words = explode(' ', $text);
03389 
03390                 $nspaces = count($words) - 1;
03391 
03392                 if ($nspaces > 0)
03393                 {
03394                     $adjust = ($width - $actual) / $nspaces;
03395                 }
03396                 else
03397                 {
03398                     $adjust = 0;
03399                 }
03400 
03401                 break;
03402             }
03403     }
03404 
03411     function addTextWrap($x, $y, $width, $size, $text, $justification = 'left', $angle = 0, $test = 0)
03412     {
03413         // this will display the text, and if it goes beyond the width $width, will backtrack to the 
03414         // previous space or hyphen, and return the remainder of the text.
03415 
03416         // $justification can be set to 'left','right','center','centre','full'
03417 
03418         // need to store the initial text state, as this will change during the width calculation
03419         // but will need to be re-set before printing, so that the chars work out right
03420         $store_currentTextState = $this->currentTextState;
03421 
03422         if (!$this->numFonts)
03423         {
03424             $this->selectFont($this->fonts_path . '/Helvetica');
03425         }
03426 
03427         if ($width <= 0)
03428         {
03429             // error, pretend it printed ok, otherwise risking a loop
03430             return '';
03431         }
03432 
03433         $w = 0;
03434         $break = 0;
03435         $breakWidth = 0;
03436         $len = strlen($text);
03437         $cf = $this->currentFont;
03438         $tw = $width / $size * 1000;
03439 
03440         for ($i = 0; $i < $len; $i++)
03441         {
03442             $f = 1;
03443             $directive = $this->PRVTcheckTextDirective($text, $i, $f);
03444 
03445             if ($directive)
03446             {
03447                 if ($f)
03448                 {
03449                     $this->setCurrentFont();
03450                     $cf = $this->currentFont;
03451                 }
03452 
03453                 $i = $i + $directive - 1;
03454             }
03455             else
03456             {
03457                 $cOrd = ord($text[$i]);
03458 
03459                 if (isset($this->fonts[$cf]['differences'][$cOrd]))
03460                 {
03461                     // then this character is being replaced by another
03462                     $cOrd2 = $this->fonts[$cf]['differences'][$cOrd];
03463                 }
03464                 else
03465                 {
03466                     $cOrd2 = $cOrd;
03467                 }
03468 
03469                 if (isset($this->fonts[$cf]['C'][$cOrd2]['WX']))
03470                 {
03471                     $w += $this->fonts[$cf]['C'][$cOrd2]['WX'];
03472                 }
03473 
03474                 if ($w > $tw)
03475                 {
03476                     // then we need to truncate this line
03477                     if ($break > 0)
03478                     {
03479                         // then we have somewhere that we can split :)
03480                         if ($text[$break] == ' ')
03481                         {
03482                             $tmp = substr($text, 0, $break);
03483                         }
03484                         else
03485                         {
03486                             $tmp = substr($text, 0, $break + 1);
03487                         }
03488 
03489                         $adjust = 0;
03490                         $this->PRVTadjustWrapText($tmp, $breakWidth, $width, $x, $adjust, $justification);
03491 
03492                         // reset the text state
03493                         $this->currentTextState = $store_currentTextState;
03494                         $this->setCurrentFont();
03495 
03496                         if (!$test)
03497                         {
03498                             $this->addText($x, $y, $size, $tmp, $angle, $adjust);
03499                         }
03500 
03501                         return substr($text, $break + 1);
03502                     }
03503                     else
03504                     {
03505                         // just split before the current character
03506                         $tmp = substr($text, 0, $i);
03507                         $adjust = 0;
03508                         $ctmp = ord($text[$i]);
03509 
03510                         if (isset($this->fonts[$cf]['differences'][$ctmp]))
03511                         {
03512                             $ctmp = $this->fonts[$cf]['differences'][$ctmp];
03513                         }
03514 
03515                         $tmpw = ($w - $this->fonts[$cf]['C'][$ctmp]['WX']) * $size / 1000;
03516                         $this->PRVTadjustWrapText($tmp, $tmpw, $width, $x, $adjust, $justification);
03517                         // reset the text state
03518                         $this->currentTextState = $store_currentTextState;
03519                         $this->setCurrentFont();
03520 
03521                         if (!$test)
03522                         {
03523                             $this->addText($x, $y, $size, $tmp, $angle, $adjust);
03524                         }
03525 
03526                         return substr($text, $i);
03527                     }
03528                 }
03529 
03530                 if ($text[$i] == '-')
03531                 {
03532                     $break = $i;
03533                     $breakWidth = $w * $size / 1000;
03534                 }
03535 
03536                 if ($text[$i] == ' ')
03537                 {
03538                     $break = $i;
03539                     $ctmp = ord($text[$i]);
03540 
03541                     if (isset($this->fonts[$cf]['differences'][$ctmp]))
03542                     {
03543                         $ctmp = $this->fonts[$cf]['differences'][$ctmp];
03544                     }
03545 
03546                     $breakWidth = ($w - $this->fonts[$cf]['C'][$ctmp]['WX']) * $size / 1000;
03547                 }
03548             }
03549         }
03550 
03551         // then there was no need to break this line
03552         if ($justification == 'full')
03553         {
03554             $justification = 'left';
03555         }
03556 
03557         $adjust = 0;
03558         $tmpw = $w * $size / 1000;
03559         //echo "text=$text    tmpw=$tmpw<br>";
03560         $this->PRVTadjustWrapText($text, $tmpw, $width, $x, $adjust, $justification);
03561         // reset the text state
03562         $this->currentTextState = $store_currentTextState;
03563         $this->setCurrentFont();
03564 
03565         if (!$test)
03566         {
03567             $this->addText($x, $y, $size, $text, $angle, $adjust, $angle);
03568         }
03569 
03570         return '';
03571     }
03572 
03579     function saveState($pageEnd = 0)
03580     {
03581         if ($pageEnd)
03582         {
03583             // this will be called at a new page to return the state to what it was on the 
03584             // end of the previous page, before the stack was closed down
03585             // This is to get around not being able to have open 'q' across pages
03586             $opt = $this->stateStack[$pageEnd]; // ok to use this as stack starts numbering at 1
03587             $this->setColor($opt['col']['r'], $opt['col']['g'], $opt['col']['b'], 1);
03588             $this->setStrokeColor($opt['str']['r'], $opt['str']['g'], $opt['str']['b'], 1);
03589             $this->objects[$this->currentContents]['c'] .= "\n" . $opt['lin'];
03590         //    $this->currentLineStyle = $opt['lin'];
03591         }
03592         else
03593         {
03594             $this->nStateStack++;
03595             $this->stateStack[$this->nStateStack] = array
03596                 (
03597                 'col' => $this->currentColour,
03598                 'str' => $this->currentStrokeColour,
03599                 'lin' => $this->currentLineStyle
03600                 );
03601         }
03602 
03603         $this->objects[$this->currentContents]['c'] .= "\nq";
03604     }
03605 
03609     function restoreState($pageEnd = 0)
03610     {
03611         if (!$pageEnd)
03612         {
03613             $n = $this->nStateStack;
03614             $this->currentColour = $this->stateStack[$n]['col'];
03615             $this->currentStrokeColour = $this->stateStack[$n]['str'];
03616             $this->objects[$this->currentContents]['c'] .= "\n" . $this->stateStack[$n]['lin'];
03617             $this->currentLineStyle = $this->stateStack[$n]['lin'];
03618             unset($this->stateStack[$n]);
03619             $this->nStateStack--;
03620         }
03621 
03622         $this->objects[$this->currentContents]['c'] .= "\nQ";
03623     }
03624 
03631     function openObject()
03632     {
03633         $this->nStack++;
03634         $this->stack[$this->nStack] = array
03635             (
03636             'c' => $this->currentContents,
03637             'p' => $this->currentPage
03638             );
03639 
03640         // add a new object of the content type, to hold the data flow
03641         $this->numObj++;
03642         $this->o_contents($this->numObj, 'new');
03643         $this->currentContents = $this->numObj;
03644         $this->looseObjects[$this->numObj] = 1;
03645 
03646         return $this->numObj;
03647     }
03648 
03652     function reopenObject($id)
03653     {
03654         $this->nStack++;
03655         $this->stack[$this->nStack] = array
03656             (
03657             'c' => $this->currentContents,
03658             'p' => $this->currentPage
03659             );
03660 
03661         $this->currentContents = $id;
03662 
03663         // also if this object is the primary contents for a page, then set the current page to its parent
03664         if (isset($this->objects[$id]['onPage']))
03665         {
03666             $this->currentPage = $this->objects[$id]['onPage'];
03667         }
03668     }
03669 
03673     function closeObject()
03674     {
03675         // close the object, as long as there was one open in the first place, which will be indicated by
03676         // an objectId on the stack.
03677         if ($this->nStack > 0)
03678         {
03679             $this->currentContents = $this->stack[$this->nStack]['c'];
03680             $this->currentPage = $this->stack[$this->nStack]['p'];
03681             $this->nStack--;
03682         // easier to probably not worry about removing the old entries, they will be overwritten
03683         // if there are new ones.
03684         }
03685     }
03686 
03690     function stopObject($id)
03691     {
03692         // if an object has been appearing on pages up to now, then stop it, this page will
03693         // be the last one that could contian it.
03694         if (isset($this->addLooseObjects[$id]))
03695         {
03696             $this->addLooseObjects[$id] = '';
03697         }
03698     }
03699 
03703     function addObject($id, $options = 'add')
03704     {
03705         // add the specified object to the page
03706         if (isset($this->looseObjects[$id]) && $this->currentContents != $id)
03707         {
03708             // then it is a valid object, and it is not being added to itself
03709             switch ($options)
03710                 {
03711                 case 'all':
03712                 // then this object is to be added to this page (done in the next block) and 
03713                 // all future new pages. 
03714                     $this->addLooseObjects[$id] = 'all';
03715 
03716                 case 'add':
03717                     if (isset($this->objects[$this->currentContents]['onPage']))
03718                     {
03719                         // then the destination contents is the primary for the page
03720                         // (though this object is actually added to that page)
03721                         $this->o_page($this->objects[$this->currentContents]['onPage'], 'content', $id);
03722                     }
03723 
03724                     break;
03725 
03726                 case 'even':
03727                     $this->addLooseObjects[$id] = 'even';
03728 
03729                     $pageObjectId = $this->objects[$this->currentContents]['onPage'];
03730 
03731                     if ($this->objects[$pageObjectId]['info']['pageNum'] % 2 == 0)
03732                     {
03733                         $this->addObject($id); // hacky huh :)
03734                     }
03735 
03736                     break;
03737 
03738                 case 'odd':
03739                     $this->addLooseObjects[$id] = 'odd';
03740 
03741                     $pageObjectId = $this->objects[$this->currentContents]['onPage'];
03742 
03743                     if ($this->objects[$pageObjectId]['info']['pageNum'] % 2 == 1)
03744                     {
03745                         $this->addObject($id); // hacky huh :)
03746                     }
03747 
03748                     break;
03749 
03750                 case 'next':
03751                     $this->addLooseObjects[$id] = 'all';
03752 
03753                     break;
03754 
03755                 case 'nexteven':
03756                     $this->addLooseObjects[$id] = 'even';
03757 
03758                     break;
03759 
03760                 case 'nextodd':
03761                     $this->addLooseObjects[$id] = 'odd';
03762 
03763                     break;
03764                 }
03765         }
03766     }
03767 
03771     function addInfo($label, $value = 0)
03772     {
03773         // this will only work if the label is one of the valid ones.
03774         // modify this so that arrays can be passed as well.
03775         // if $label is an array then assume that it is key=>value pairs
03776         // else assume that they are both scalar, anything else will probably error
03777         if (is_array($label))
03778         {
03779             foreach ($label as $l => $v)
03780             {
03781                 $this->o_info($this->infoObject, $l, $v);
03782             }
03783         }
03784         else
03785         {
03786             $this->o_info($this->infoObject, $label, $value);
03787         }
03788     }
03789 
03793     function setPreferences($label, $value = 0)
03794     {
03795         // this will only work if the label is one of the valid ones.
03796         if (is_array($label))
03797         {
03798             foreach ($label as $l => $v)
03799             {
03800                 $this->o_catalog($this->catalogId, 'viewerPreferences', array($l => $v));
03801             }
03802         }
03803         else
03804         {
03805             $this->o_catalog($this->catalogId, 'viewerPreferences', array($label => $value));
03806         }
03807     }
03808 
03814     function PRVT_getBytes(&$data, $pos, $num)
03815     {
03816         // return the integer represented by $num bytes from $pos within $data
03817         $ret = 0;
03818 
03819         for ($i = 0; $i < $num; $i++)
03820         {
03821             $ret = $ret * 256;
03822             $ret += ord($data[$pos + $i]);
03823         }
03824 
03825         return $ret;
03826     }
03827 
03832     function addPngFromFile($file, $x, $y, $w = 0, $h = 0)
03833     {
03834         // read in a png file, interpret it, then add to the system
03835         $error = 0;
03836         $tmp = get_magic_quotes_runtime();
03837         set_magic_quotes_runtime(0);
03838         $fp = @fopen($file, 'rb');
03839 
03840         if ($fp)
03841         {
03842             $data = '';
03843 
03844             while (!feof($fp))
03845             {
03846                 $data .= fread($fp, 1024);
03847             }
03848 
03849             fclose($fp);
03850         }
03851         else
03852         {
03853             $error = 1;
03854             $errormsg = 'trouble opening file: ' . $file;
03855         }
03856 
03857         set_magic_quotes_runtime($tmp);
03858 
03859         if (!$error)
03860         {
03861             $header = chr(137) . chr(80) . chr(78) . chr(71) . chr(13) . chr(10) . chr(26) . chr(10);
03862 
03863             if (substr($data, 0, 8) != $header)
03864             {
03865                 $error = 1;
03866                 $errormsg = 'this file does not have a valid header';
03867             }
03868         }
03869 
03870         if (!$error)
03871         {
03872             // set pointer
03873             $p = 8;
03874             $len = strlen($data);
03875             // cycle through the file, identifying chunks
03876             $haveHeader = 0;
03877             $info = array(
03878                 );
03879 
03880             $idata = '';
03881             $pdata = '';
03882 
03883             while ($p < $len)
03884             {
03885                 $chunkLen = $this->PRVT_getBytes($data, $p, 4);
03886                 $chunkType = substr($data, $p + 4, 4);
03887                 //      echo $chunkType.' - '.$chunkLen.'<br>';
03888 
03889                 switch ($chunkType)
03890                     {
03891                     case 'IHDR':
03892                         // this is where all the file information comes from
03893                         $info['width'] = $this->PRVT_getBytes($data, $p + 8, 4);
03894 
03895                         $info['height'] = $this->PRVT_getBytes($data, $p + 12, 4);
03896                         $info['bitDepth'] = ord($data[$p + 16]);
03897                         $info['colorType'] = ord($data[$p + 17]);
03898                         $info['compressionMethod'] = ord($data[$p + 18]);
03899                         $info['filterMethod'] = ord($data[$p + 19]);
03900                         $info['interlaceMethod'] = ord($data[$p + 20]);
03901                         //print_r($info);
03902                         $haveHeader = 1;
03903 
03904                         if ($info['compressionMethod'] != 0)
03905                         {
03906                             $error = 1;
03907                             $errormsg = 'unsupported compression method';
03908                         }
03909 
03910                         if ($info['filterMethod'] != 0)
03911                         {
03912                             $error = 1;
03913                             $errormsg = 'unsupported filter method';
03914                         }
03915 
03916                         break;
03917 
03918                     case 'PLTE':
03919                         $pdata .= substr($data, $p + 8, $chunkLen);
03920 
03921                         break;
03922 
03923                     case 'IDAT':
03924                         $idata .= substr($data, $p + 8, $chunkLen);
03925 
03926                         break;
03927 
03928                     case 'tRNS':
03929                         //this chunk can only occur once and it must occur after the PLTE chunk and before IDAT chunk 
03930                         //print "tRNS found, color type = ".$info['colorType']."<BR>"; 
03931                         $transparency = array(
03932                             );
03933 
03934                         if ($info['colorType'] == 3)
03935                         { // indexed color, rbg 
03936                             /* corresponding to entries in the plte chunk 
03937                             Alpha for palette index 0: 1 byte 
03938                             Alpha for palette index 1: 1 byte 
03939                             ...etc... 
03940                             */
03941                             // there will be one entry for each palette entry. up until the last non-opaque entry.
03942                             // set up an array, stretching over all palette entries which will be o (opaque) or 1 (transparent)
03943                             $transparency['type'] = 'indexed';
03944                             $numPalette = strlen($pdata) / 3;
03945                             $trans = 0;
03946 
03947                             for ($i = $chunkLen; $i >= 0; $i--)
03948                             {
03949                                 if (ord($data[$p + 8 + $i]) == 0)
03950                                 {
03951                                     $trans = $i;
03952                                 }
03953                             }
03954 
03955                             $transparency['data'] = $trans;
03956                         }
03957                         elseif ($info['colorType'] == 0)
03958                         { // grayscale 
03959                             /* corresponding to entries in the plte chunk 
03960                             Gray: 2 bytes, range 0 .. (2^bitdepth)-1 
03961                             */
03962                             //            $transparency['grayscale']=$this->PRVT_getBytes($data,$p+8,2); // g = grayscale 
03963                             $transparency['type'] = 'indexed';
03964                             $transparency['data'] = ord($data[$p + 8 + 1]);
03965                         }
03966                         elseif ($info['colorType'] == 2)
03967                         { // truecolor 
03968                             /* corresponding to entries in the plte chunk 
03969                             Red: 2 bytes, range 0 .. (2^bitdepth)-1 
03970                             Green: 2 bytes, range 0 .. (2^bitdepth)-1 
03971                             Blue: 2 bytes, range 0 .. (2^bitdepth)-1 
03972                             */
03973                             $transparency['r'] = $this->PRVT_getBytes($data, $p + 8, 2);  // r from truecolor 
03974                             $transparency['g'] = $this->PRVT_getBytes($data, $p + 10, 2); // g from truecolor 
03975                             $transparency['b'] = $this->PRVT_getBytes($data, $p + 12, 2); // b from truecolor 
03976                         }
03977                         else
03978                         {
03979                         //unsupported transparency type 
03980                         }
03981 
03982                         // KS End new code 
03983                         break;
03984 
03985                     default: break;
03986                     }
03987 
03988                 $p += $chunkLen + 12;
03989             }
03990 
03991             if (!$haveHeader)
03992             {
03993                 $error = 1;
03994                 $errormsg = 'information header is missing';
03995             }
03996 
03997             if (isset($info['interlaceMethod']) && $info['interlaceMethod'])
03998             {
03999                 $error = 1;
04000                 $errormsg = 'There appears to be no support for interlaced images in pdf.';
04001             }
04002         }
04003 
04004         if (!$error && $info['bitDepth'] > 8)
04005         {
04006             $error = 1;
04007             $errormsg = 'only bit depth of 8 or less is supported';
04008         }
04009 
04010         if (!$error)
04011         {
04012             if ($info['colorType'] != 2 && $info['colorType'] != 0 && $info['colorType'] != 3)
04013             {
04014                 $error = 1;
04015                 $errormsg
04016                     = 'transparancey alpha channel not supported, transparency only supported for palette images.';
04017             }
04018             else
04019             {
04020                 switch ($info['colorType'])
04021                     {
04022                     case 3:
04023                         $color = 'DeviceRGB';
04024 
04025                         $ncolor = 1;
04026                         break;
04027 
04028                     case 2:
04029                         $color = 'DeviceRGB';
04030 
04031                         $ncolor = 3;
04032                         break;
04033 
04034                     case 0:
04035                         $color = 'DeviceGray';
04036 
04037                         $ncolor = 1;
04038                         break;
04039                     }
04040             }
04041         }
04042 
04043         if ($error)
04044         {
04045             $this->addMessage('PNG error - (' . $file . ') ' . $errormsg);
04046             return;
04047         }
04048 
04049         if ($w == 0)
04050         {
04051             $w = $h / $info['height'] * $info['width'];
04052         }
04053 
04054         if ($h == 0)
04055         {
04056             $h = $w * $info['height'] / $info['width'];
04057         }
04058 
04059         //print_r($info);
04060         // so this image is ok... add it in.
04061         $this->numImages++;
04062         $im = $this->numImages;
04063         $label = 'I' . $im;
04064         $this->numObj++;
04065         //  $this->o_image($this->numObj,'new',array('label'=>$label,'data'=>$idata,'iw'=>$w,'ih'=>$h,'type'=>'png','ic'=>$info['width']));
04066         $options = array
04067             (
04068             'label' => $label,
04069             'data' => $idata,
04070             'bitsPerComponent' => $info['bitDepth'],
04071             'pdata' => $pdata,
04072             'iw' => $info['width'],
04073             'ih' => $info['height'],
04074             'type' => 'png',
04075             'color' => $color,
04076             'ncolor' => $ncolor
04077             );
04078 
04079         if (isset($transparency))
04080         {
04081             $options['transparency'] = $transparency;
04082         }
04083 
04084         $this->o_image($this->numObj, 'new', $options);
04085 
04086         $this->objects[$this->currentContents]['c'] .= "\nq";
04087         $this->objects[$this->currentContents]['c'] .= "\n" . __sprintf('%.3f',
04088                                                                         $w) . " 0 0 " . __sprintf('%.3f',
04089                                                                                                   $h) . " "
04090                                                            . __sprintf('%.3f',
04091                                                                        $x) . " " . __sprintf('%.3f', $y) . " cm";
04092         $this->objects[$this->currentContents]['c'] .= "\n/" . $label . ' Do';
04093         $this->objects[$this->currentContents]['c'] .= "\nQ";
04094     }
04095 
04099     function addJpegFromFile($img, $x, $y, $w = 0, $h = 0)
04100     {
04101         // attempt to add a jpeg image straight from a file, using no GD commands
04102         // note that this function is unable to operate on a remote file.
04103 
04104         if (!file_exists($img))
04105         {
04106             return;
04107         }
04108 
04109         $tmp = getimagesize($img);
04110         $imageWidth = $tmp[0];
04111         $imageHeight = $tmp[1];
04112 
04113         if (isset($tmp['channels']))
04114         {
04115             $channels = $tmp['channels'];
04116         }
04117         else
04118         {
04119             $channels = 3;
04120         }
04121 
04122         if ($w <= 0 && $h <= 0)
04123         {
04124             $w = $imageWidth;
04125         }
04126 
04127         if ($w == 0)
04128         {
04129             $w = $h / $imageHeight * $imageWidth;
04130         }
04131 
04132         if ($h == 0)
04133         {
04134             $h = $w * $imageHeight / $imageWidth;
04135         }
04136 
04137         $fp = fopen($img, 'rb');
04138 
04139         $tmp = get_magic_quotes_runtime();
04140         set_magic_quotes_runtime(0);
04141         $data = fread($fp, filesize($img));
04142         set_magic_quotes_runtime($tmp);
04143 
04144         fclose($fp);
04145 
04146         $this->addJpegImage_common($data, $x, $y, $w, $h, $imageWidth, $imageHeight, $channels);
04147     }
04148 
04154     function addImage(&$img, $x, $y, $w = 0, $h = 0, $quality = 75)
04155     {
04156         // add a new image into the current location, as an external object
04157         // add the image at $x,$y, and with width and height as defined by $w & $h
04158 
04159         // note that this will only work with full colour images and makes them jpg images for display
04160         // later versions could present lossless image formats if there is interest.
04161 
04162         // there seems to be some problem here in that images that have quality set above 75 do not appear
04163         // not too sure why this is, but in the meantime I have restricted this to 75.  
04164         if ($quality > 75)
04165         {
04166             $quality = 75;
04167         }
04168 
04169         // if the width or height are set to zero, then set the other one based on keeping the image
04170         // height/width ratio the same, if they are both zero, then give up :)
04171         $imageWidth = imagesx($img);
04172         $imageHeight = imagesy($img);
04173 
04174         if ($w <= 0 && $h <= 0)
04175         {
04176             return;
04177         }
04178 
04179         if ($w == 0)
04180         {
04181             $w = $h / $imageHeight * $imageWidth;
04182         }
04183 
04184         if ($h == 0)
04185         {
04186             $h = $w * $imageHeight / $imageWidth;
04187         }
04188 
04189         // gotta get the data out of the img..
04190 
04191         // so I write to a temp file, and then read it back.. soo ugly, my apologies.
04192         $tmpDir = '/tmp';
04193         $tmpName = tempnam($tmpDir, 'img');
04194         imagejpeg($img, $tmpName, $quality);
04195         $fp = fopen($tmpName, 'rb');
04196 
04197         $tmp = get_magic_quotes_runtime();
04198         set_magic_quotes_runtime(0);
04199         $fp = @fopen($tmpName, 'rb');
04200 
04201         if ($fp)
04202         {
04203             $data = '';
04204 
04205             while (!feof($fp))
04206             {
04207                 $data .= fread($fp, 1024);
04208             }
04209 
04210             fclose($fp);
04211         }
04212         else
04213         {
04214             $error = 1;
04215             $errormsg = 'trouble opening file';
04216         }
04217 
04218         //  $data = fread($fp,filesize($tmpName));
04219         set_magic_quotes_runtime($tmp);
04220         //  fclose($fp);
04221         unlink($tmpName);
04222         $this->addJpegImage_common($data, $x, $y, $w, $h, $imageWidth, $imageHeight);
04223     }
04224 
04230     function addJpegImage_common(&$data, $x, $y, $w = 0, $h = 0, $imageWidth, $imageHeight, $channels = 3)
04231     {
04232         // note that this function is not to be called externally
04233         // it is just the common code between the GD and the file options
04234         $this->numImages++;
04235         $im = $this->numImages;
04236         $label = 'I' . $im;
04237         $this->numObj++;
04238         $this->o_image($this->numObj,
04239                        'new',
04240                        array('label' => $label, 'data' => $data, 'iw' => $imageWidth, 'ih' => $imageHeight,
04241                              'channels' => $channels));
04242 
04243         $this->objects[$this->currentContents]['c'] .= "\nq";
04244         $this->objects[$this->currentContents]['c'] .= "\n" . __sprintf('%.3f',
04245                                                                         $w) . " 0 0 " . __sprintf('%.3f',
04246                                                                                                   $h) . " "
04247                                                            . __sprintf('%.3f',
04248                                                                        $x) . " " . __sprintf('%.3f', $y) . " cm";
04249         $this->objects[$this->currentContents]['c'] .= "\n/" . $label . ' Do';
04250         $this->objects[$this->currentContents]['c'] .= "\nQ";
04251     }
04252 
04256     function openHere($style, $a = 0, $b = 0, $c = 0)
04257     {
04258         // this function will open the document at a specified page, in a specified style
04259         // the values for style, and the required paramters are:
04260         // 'XYZ'  left, top, zoom
04261         // 'Fit'
04262         // 'FitH' top
04263         // 'FitV' left
04264         // 'FitR' left,bottom,right
04265         // 'FitB'
04266         // 'FitBH' top
04267         // 'FitBV' left
04268         $this->numObj++;
04269         $this->o_destination($this->numObj, 'new',
04270                              array('page' => $this->currentPage, 'type' => $style, 'p1' => $a, 'p2' => $b, 'p3' => $c));
04271         $id = $this->catalogId;
04272         $this->o_catalog($id, 'openHere', $this->numObj);
04273     }
04274 
04278     function addDestination($label, $style, $a = 0, $b = 0, $c = 0)
04279     {
04280         // associates the given label with the destination, it is done this way so that a destination can be specified after
04281         // it has been linked to
04282         // styles are the same as the 'openHere' function
04283         $this->numObj++;
04284         $this->o_destination($this->numObj, 'new',
04285                              array('page' => $this->currentPage, 'type' => $style, 'p1' => $a, 'p2' => $b, 'p3' => $c));
04286         $id = $this->numObj;
04287         // store the label->idf relationship, note that this means that labels can be used only once
04288         $this->destinations["$label"] = $id;
04289     }
04290 
04296     function setFontFamily($family, $options = '')
04297     {
04298         if (!is_array($options))
04299         {
04300             if ($family == 'init')
04301             {
04302                 // set the known family groups
04303                 // these font families will be used to enable bold and italic markers to be included
04304                 // within text streams. html forms will be used... <b></b> <i></i>
04305                 $this->fontFamilies['Helvetica.afm'] = array
04306                     (
04307                     'b' => 'Helvetica-Bold.afm',
04308                     'i' => 'Helvetica-Oblique.afm',
04309                     'bi' => 'Helvetica-BoldOblique.afm',
04310                     'ib' => 'Helvetica-BoldOblique.afm'
04311                     );
04312 
04313                 $this->fontFamilies['Courier.afm'] = array
04314                     (
04315                     'b' => 'Courier-Bold.afm',
04316                     'i' => 'Courier-Oblique.afm',
04317                     'bi' => 'Courier-BoldOblique.afm',
04318                     'ib' => 'Courier-BoldOblique.afm'
04319                     );
04320 
04321                 $this->fontFamilies['Times-Roman.afm'] = array
04322                     (
04323                     'b' => 'Times-Bold.afm',
04324                     'i' => 'Times-Italic.afm',
04325                     'bi' => 'Times-BoldItalic.afm',
04326                     'ib' => 'Times-BoldItalic.afm'
04327                     );
04328             }
04329         }
04330         else
04331         {
04332             // the user is trying to set a font family
04333             // note that this can also be used to set the base ones to something else
04334             if (strlen($family))
04335             {
04336                 $this->fontFamilies[$family] = $options;
04337             }
04338         }
04339     }
04340 
04344     function addMessage($message)
04345     {
04346         $this->messages .= $message . "\n";
04347     }
04348 
04352     /* PHP 4 
04353     function transaction($action){
04354       switch ($action){
04355         case 'start':
04356           // store all the data away into the checkpoint variable
04357           $data = get_object_vars($this);
04358           $this->checkpoint = $data;
04359           unset($data);
04360           break;
04361         case 'commit':
04362           if (is_array($this->checkpoint) && isset($this->checkpoint['checkpoint'])){
04363             $tmp = $this->checkpoint['checkpoint'];
04364             $this->checkpoint = $tmp;
04365             unset($tmp);
04366           } else {
04367             $this->checkpoint='';
04368           }
04369           break;
04370         case 'rewind':
04371           // do not destroy the current checkpoint, but move us back to the state then, so that we can try again
04372           if (is_array($this->checkpoint)){
04373             // can only abort if were inside a checkpoint
04374             $tmp = $this->checkpoint;
04375             foreach ($tmp as $k=>$v){
04376               if ($k != 'checkpoint'){
04377                 $this->$k=$v;
04378               }
04379             }
04380             unset($tmp);
04381           }
04382           break;
04383         case 'abort':
04384           if (is_array($this->checkpoint)){
04385             // can only abort if were inside a checkpoint
04386             $tmp = $this->checkpoint;
04387             foreach ($tmp as $k=>$v){
04388               $this->$k=$v;
04389             }
04390             unset($tmp);
04391           }
04392           break;
04393       }
04394     
04395     }
04396     */
04397     /* PHP 5 */
04398 
04399     function transaction($action)
04400     {
04401         switch ($action)
04402             {
04403             case 'start':
04404                 // store all the data away into the checkpoint variable
04405                 $this->checkpoint = clone $this;
04406 
04407                 break;
04408 
04409             case 'commit':
04410                 if (is_object($this->checkpoint) && isset($this->checkpoint->checkpoint))
04411                 {
04412                     $tmp = $this->checkpoint->checkpoint;
04413                     $this->checkpoint = $tmp;
04414                     unset($tmp);
04415                 }
04416                 else
04417                 {
04418                     $this->checkpoint = '';
04419                 }
04420 
04421                 break;
04422 
04423             case 'rewind':
04424                 // do not destroy the current checkpoint, but move us back to the state then, so that we can try again
04425                 if (is_object($this->checkpoint))
04426                 {
04427                     // can only abort if were inside a checkpoint
04428                     $tmp = $this->checkpoint;
04429 
04430                     foreach ($tmp as $k => $v)
04431                     {
04432                         if ($k != 'checkpoint')
04433                         {
04434                             $this->$k = $v;
04435                         }
04436                     }
04437 
04438                     unset($tmp);
04439                 }
04440 
04441                 break;
04442 
04443             case 'abort':
04444                 if (is_object($this->checkpoint))
04445                 {
04446                     // can only abort if were inside a checkpoint
04447                     $tmp = $this->checkpoint;
04448 
04449                     foreach ($tmp as $k => $v)
04450                     {
04451                         $this->$k = $v;
04452                     }
04453 
04454                     unset($tmp);
04455                 }
04456 
04457                 break;
04458             }
04459     }
04460     
04461 
04462     function SetFontsPath($path)
04463     {
04464         $this->fonts_path = $path;
04465     }
04466 } // end of class
04467 ?>
CopyLeft (L) 2001-2006 - [MIOLO Development Team] SOLIS - Cooperativa de Soluções Livres - Lajeado/RS - Brasil