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
00222 $this->setFontFamily('init');
00223
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
00453 $o['info']['pages'][] = $options;
00454 }
00455 else
00456 {
00457
00458
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
00466
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;
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
00670 if (isset($options['differences']))
00671 {
00672
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
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
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
00739 $res .= "/Encoding " . $o['info']['encodingDictionary'] . " 0 R\n";
00740 }
00741 else if (isset($o['info']['encoding']))
00742 {
00743
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
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
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
00932
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:
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
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
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
01115 $pageId = $this->currentPage;
01116
01117 $this->o_page($pageId, 'annot', $id);
01118
01119
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
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
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
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
01241 if (!isset($o['info']['annot']))
01242 {
01243 $o['info']['annot'] = array(
01244 );
01245 }
01246
01247
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
01316 $this->objects[$id]['onPage'] = $options;
01317 }
01318 else if ($options == 'raw')
01319 {
01320
01321 $this->objects[$id]['raw'] = 1;
01322 }
01323
01324 break;
01325
01326 case 'add':
01327
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
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
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
01462
01463 $this->o_pages($this->currentNode, 'xObject', array('label' => $options['label'], 'objNum' => $id));
01464
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
01504 $this->objects[$id] = array
01505 (
01506 't' => 'encryption',
01507 'info' => $options
01508 );
01509
01510 $this->arc4_objnum = $id;
01511
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
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
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
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
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
01759 if ($this->arc4_objnum == 0)
01760 {
01761
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
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
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
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
01875
01876 $this->firstPageId = $this->currentContents;
01877 }
01878
01888 function openFont($font)
01889 {
01890
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
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
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
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
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
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
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
02051
02052 if (!isset($this->fonts[$fontName]))
02053 {
02054
02055 $this->openFont($fontName);
02056
02057 if (isset($this->fonts[$fontName]))
02058 {
02059 $this->numObj++;
02060 $this->numFonts++;
02061 $pos = strrpos($fontName, '/');
02062
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
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
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
02095
02096
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
02115
02116 $this->addMessage('selectFont: checking for - ' . $fbfile);
02117
02118 if (substr($fontName, -4) == '.afm' && strlen($fbtype))
02119 {
02120 $adobeFontName = $this->fonts[$fontName]['FontName'];
02121
02122 $this->addMessage('selectFont: adding font file - ' . $fbfile . ' - ' . $adobeFontName);
02123
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
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
02189
02190
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
02199 $this->numObj++;
02200 $fontDescriptorId = $this->numObj;
02201 $this->numObj++;
02202 $pfbid = $this->numObj;
02203
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);
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
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
02254 $this->o_contents($this->numObj, 'new');
02255 $this->objects[$pfbid]['c'] .= $data;
02256
02257
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
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
02303
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
02314 $this->currentBaseFont = $fontName;
02315
02316
02317 $this->setCurrentFont();
02318 }
02319
02320 return $this->currentFontNum;
02321 }
02322
02335 function setCurrentFont()
02336 {
02337 if (strlen($this->currentBaseFont) == 0)
02338 {
02339
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
02349
02350
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
02360
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
02445
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
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';
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
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
02706
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
02721
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
02737 if ($this->nStateStack)
02738 {
02739 for ($i = 1; $i <= $this->nStateStack; $i++)
02740 {
02741 $this->saveState($i);
02742 }
02743 }
02744
02745
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
02758 if (strlen($this->currentLineStyle))
02759 {
02760 $this->objects[$this->currentContents]['c'] .= "\n" . $this->currentLineStyle;
02761 }
02762
02763
02764 return $this->currentContents;
02765 }
02766
02771 function stream($options = '')
02772 {
02773
02774
02775
02776
02777
02778
02779
02780
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
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
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('<', '<', $text);
02853 $text = str_replace('>', '>', $text);
02854 $text = str_replace(''', '\'', $text);
02855 $text = str_replace('"', '"', $text);
02856 $text = str_replace('&', '&', $text);
02857
02858 return $text;
02859 }
02860
02867 function PRVTgetTextPosition($x, $y, $angle, $size, $wa, $text)
02868 {
02869
02870 $w = $this->getTextWidth($size, $text);
02871
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
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
02943 $j++;
02944
02945 $k = strpos($text, '>', $j);
02946
02947 if ($k !== false && $text[$j] == ':')
02948 {
02949
02950 $directive = $k - $i + 1;
02951 $f = 0;
02952
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
02974 if ($final)
02975 {
02976
02977
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
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
03011
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
03043 $j++;
03044
03045 $k = strpos($text, '>', $j);
03046
03047 if ($k !== false && $text[$j] == ':')
03048 {
03049
03050 $directive = $k - $i + 1;
03051 $f = 0;
03052
03053
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
03075 if ($final)
03076 {
03077
03078
03079
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
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
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
03144 if ($this->nCallback > 0)
03145 {
03146 for ($i = $this->nCallback; $i > 0; $i--)
03147 {
03148
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
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
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
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
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
03270 if ($this->nCallback > 0)
03271 {
03272 for ($i = $this->nCallback; $i > 0; $i--)
03273 {
03274
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
03301
03302
03303 $store_currentTextState = $this->currentTextState;
03304
03305 if (!$this->numFonts)
03306 {
03307 $this->selectFont($this->fonts_path . '/Helvetica');
03308 }
03309
03310
03311 $text = "$text";
03312
03313
03314
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
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
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
03414
03415
03416
03417
03418
03419
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
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
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
03477 if ($break > 0)
03478 {
03479
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
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
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
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
03552 if ($justification == 'full')
03553 {
03554 $justification = 'left';
03555 }
03556
03557 $adjust = 0;
03558 $tmpw = $w * $size / 1000;
03559
03560 $this->PRVTadjustWrapText($text, $tmpw, $width, $x, $adjust, $justification);
03561
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
03584
03585
03586 $opt = $this->stateStack[$pageEnd];
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
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
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
03664 if (isset($this->objects[$id]['onPage']))
03665 {
03666 $this->currentPage = $this->objects[$id]['onPage'];
03667 }
03668 }
03669
03673 function closeObject()
03674 {
03675
03676
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
03683
03684 }
03685 }
03686
03690 function stopObject($id)
03691 {
03692
03693
03694 if (isset($this->addLooseObjects[$id]))
03695 {
03696 $this->addLooseObjects[$id] = '';
03697 }
03698 }
03699
03703 function addObject($id, $options = 'add')
03704 {
03705
03706 if (isset($this->looseObjects[$id]) && $this->currentContents != $id)
03707 {
03708
03709 switch ($options)
03710 {
03711 case 'all':
03712
03713
03714 $this->addLooseObjects[$id] = 'all';
03715
03716 case 'add':
03717 if (isset($this->objects[$this->currentContents]['onPage']))
03718 {
03719
03720
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);
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);
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
03774
03775
03776
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
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
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
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
03873 $p = 8;
03874 $len = strlen($data);
03875
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
03888
03889 switch ($chunkType)
03890 {
03891 case 'IHDR':
03892
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
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
03930
03931 $transparency = array(
03932 );
03933
03934 if ($info['colorType'] == 3)
03935 {
03936
03937
03938
03939
03940
03941
03942
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 {
03959
03960
03961
03962
03963 $transparency['type'] = 'indexed';
03964 $transparency['data'] = ord($data[$p + 8 + 1]);
03965 }
03966 elseif ($info['colorType'] == 2)
03967 {
03968
03969
03970
03971
03972
03973 $transparency['r'] = $this->PRVT_getBytes($data, $p + 8, 2);
03974 $transparency['g'] = $this->PRVT_getBytes($data, $p + 10, 2);
03975 $transparency['b'] = $this->PRVT_getBytes($data, $p + 12, 2);
03976 }
03977 else
03978 {
03979
03980 }
03981
03982
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
04060
04061 $this->numImages++;
04062 $im = $this->numImages;
04063 $label = 'I' . $im;
04064 $this->numObj++;
04065
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
04102
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
04157
04158
04159
04160
04161
04162
04163
04164 if ($quality > 75)
04165 {
04166 $quality = 75;
04167 }
04168
04169
04170
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
04190
04191
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
04219 set_magic_quotes_runtime($tmp);
04220
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
04233
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
04259
04260
04261
04262
04263
04264
04265
04266
04267
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
04281
04282
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
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
04303
04304
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
04333
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
04353
04354
04355
04356
04357
04358
04359
04360
04361
04362
04363
04364
04365
04366
04367
04368
04369
04370
04371
04372
04373
04374
04375
04376
04377
04378
04379
04380
04381
04382
04383
04384
04385
04386
04387
04388
04389
04390
04391
04392
04393
04394
04395
04396
04397
04398
04399 function transaction($action)
04400 {
04401 switch ($action)
04402 {
04403 case 'start':
04404
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
04425 if (is_object($this->checkpoint))
04426 {
04427
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
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 }
04467 ?>