00001 <?php
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038 include_once( 'lib/ezutils/classes/ezmath.php' );
00039 require_once( 'lib/compat.php' );
00040
00041 class Cpdf
00042 {
00043
00044
00045
00046
00047 var $numObj = 0;
00048
00049
00050
00051
00052 var $objects = array();
00053
00054
00055
00056
00057 var $catalogId;
00058
00059
00060
00061
00062
00063 var $fonts = array();
00064
00065
00066
00067
00068 var $currentFont = '';
00069
00070
00071
00072
00073 var $currentBaseFont = '';
00074
00075
00076
00077
00078 var $currentFontNum = 0;
00079
00080
00081
00082
00083 var $currentNode;
00084
00085
00086
00087
00088 var $currentPage;
00089
00090
00091
00092
00093 var $currentContents;
00094
00095
00096
00097
00098 var $numFonts = 0;
00099
00100
00101
00102
00103 var $currentColour;
00104
00105
00106
00107
00108 var $currentStrokeColour;
00109
00110
00111
00112
00113 var $currentLineStyle = '';
00114
00115
00116
00117
00118
00119 var $stateStack = array();
00120
00121
00122
00123
00124 var $nStateStack = 0;
00125
00126
00127
00128
00129 var $numPages = 0;
00130
00131
00132
00133
00134 var $stack = array();
00135
00136
00137
00138
00139 var $nStack = 0;
00140
00141
00142
00143
00144
00145 var $looseObjects = array();
00146
00147
00148
00149
00150 var $addLooseObjects = array();
00151
00152
00153
00154
00155
00156 var $infoObject = 0;
00157
00158
00159
00160
00161 var $numImages = 0;
00162
00163
00164
00165
00166
00167 var $options = array( 'compression' => 1 );
00168
00169
00170
00171
00172 var $firstPageId;
00173
00174
00175
00176
00177
00178 var $wordSpaceAdjust = 0;
00179
00180
00181
00182
00183 var $procsetObjectId;
00184
00185
00186
00187
00188
00189
00190 var $fontFamilies = array();
00191
00192
00193
00194
00195 var $currentTextState = '';
00196
00197
00198
00199
00200 var $messages = '';
00201
00202
00203
00204
00205 var $arc4 = '';
00206
00207
00208
00209
00210 var $arc4_objnum = 0;
00211
00212
00213
00214
00215 var $fileIdentifier = '';
00216
00217
00218
00219
00220 var $encrypted = 0;
00221
00222
00223
00224
00225 var $encryptionKey = '';
00226
00227
00228
00229
00230 var $callback = array();
00231
00232
00233
00234
00235 var $nCallback = 0;
00236
00237
00238
00239
00240
00241 var $destinations = array();
00242
00243
00244
00245
00246
00247
00248 var $checkpoint = '';
00249
00250
00251
00252
00253
00254
00255 function Cpdf ( $pageSize = array( 0, 0, 612, 792 ) )
00256 {
00257 $this->currentColour = eZMath::rgbToCMYK( array( 'r' => -1,
00258 'g' => -1,
00259 'b' => -1 ) );
00260 $this->currentStrokeColour = eZMath::rgbToCMYK( array( 'r' => -1,
00261 'g' => -1,
00262 'b' => -1 ) );
00263
00264 $this->newDocument( $pageSize );
00265
00266
00267 $this->setFontFamily( 'init' );
00268
00269
00270 }
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290 function o_destination( $id, $action, $options = '' )
00291 {
00292 if ( $action != 'new' )
00293 {
00294 $o =& $this->objects[$id];
00295 }
00296 switch ( $action )
00297 {
00298 case 'new':
00299 $this->objects[$id] = array( 't' => 'destination', 'info' => array() );
00300 $tmp = '';
00301 switch ( $options['type'] )
00302 {
00303 case 'XYZ':
00304 case 'FitR':
00305 $tmp = ' ' . ezsprintf( '%.3F', $options['p3'] ) . $tmp;
00306 case 'FitV':
00307 case 'FitBH':
00308 case 'FitBV':
00309 $tmp = ' ' . ezsprintf( '%.3F', $options['p2'] ) . $tmp;
00310 case 'Fit':
00311 case 'FitH':
00312 $tmp = ' ' . ezsprintf( '%.3F', $options['p1'] ) . $tmp;
00313 case 'FitB':
00314 $tmp = $options['type'] . $tmp;
00315 $this->objects[$id]['info']['string'] = $tmp;
00316 $this->objects[$id]['info']['page'] = $options['page'];
00317 }break;
00318
00319 case 'out':
00320 $tmp = $o['info'];
00321 $res = "\n" . $id . " 0 obj\n" . '[' . $tmp['page'] . ' 0 R /' . $tmp['string'] . "]\nendobj\n";
00322 return $res;
00323 break;
00324 }
00325 }
00326
00327
00328
00329
00330 function o_viewerPreferences( $id, $action, $options = '' )
00331 {
00332 if ( $action != 'new' )
00333 {
00334 $o =& $this->objects[$id];
00335 }
00336 switch ( $action )
00337 {
00338 case 'new':
00339 $this->objects[$id] = array( 't' => 'viewerPreferences', 'info' => array() );
00340 break;
00341 case 'add':
00342 foreach ( $options as $k => $v )
00343 {
00344 switch ( $k )
00345 {
00346 case 'HideToolbar':
00347 case 'HideMenubar':
00348 case 'HideWindowUI':
00349 case 'FitWindow':
00350 case 'CenterWindow':
00351 case 'NonFullScreenPageMode':
00352 case 'Direction':
00353 $o['info'][$k] = $v;
00354 break;
00355 }
00356 }break;
00357 case 'out':
00358 $res = "\n" . $id . " 0 obj\n" . '<< ';
00359 foreach($o['info'] as $k=>$v)
00360 {
00361 $res .= "\n/" . $k . ' ' . $v;
00362 }
00363 $res .= "\n>>\n";
00364 return $res;
00365 break;
00366 }
00367 }
00368
00369
00370
00371
00372 function o_catalog( $id, $action, $options = '' )
00373 {
00374 if ( $action != 'new' )
00375 {
00376 $o =& $this->objects[$id];
00377 }
00378 switch ( $action )
00379 {
00380 case 'new':
00381 $this->objects[$id] = array( 't' => 'catalog', 'info' => array() );
00382 $this->catalogId = $id;
00383 break;
00384 case 'outlines':
00385 case 'pages':
00386 case 'openHere':
00387 $o['info'][$action] = $options;
00388 break;
00389 case 'viewerPreferences':
00390 if ( !isset( $o['info']['viewerPreferences'] ) )
00391 {
00392 $this->numObj++;
00393 $this->o_viewerPreferences( $this->numObj, 'new' );
00394 $o['info']['viewerPreferences'] = $this->numObj;
00395 }
00396 $vp = $o['info']['viewerPreferences'];
00397 $this->o_viewerPreferences( $vp, 'add', $options );
00398 break;
00399 case 'out':
00400 $res= "\n" . $id . " 0 obj\n" . '<< /Type /Catalog';
00401 foreach ( $o['info'] as $k => $v )
00402 {
00403 switch ( $k )
00404 {
00405 case 'outlines':
00406 $res .= "\n" . '/Outlines ' . $v . ' 0 R';
00407 break;
00408 case 'pages':
00409 $res .= "\n" . '/Pages ' . $v . ' 0 R';
00410 break;
00411 case 'viewerPreferences':
00412 $res .= "\n" . '/ViewerPreferences ' . $o['info']['viewerPreferences'] . ' 0 R';
00413 break;
00414 case 'openHere':
00415 $res .= "\n" . '/OpenAction ' . $o['info']['openHere'] . ' 0 R';
00416 break;
00417 }
00418 }
00419 $res .= " >>\nendobj";
00420 return $res;
00421 break;
00422 }
00423 }
00424
00425
00426
00427
00428 function o_pages( $id, $action, $options = '' )
00429 {
00430 if ($action!='new')
00431 {
00432 $o =& $this->objects[$id];
00433 }
00434 switch ( $action )
00435 {
00436 case 'new':
00437 $this->objects[$id] = array( 't' => 'pages', 'info' => array() );
00438 $this->o_catalog( $this->catalogId, 'pages', $id );
00439 break;
00440 case 'page':
00441 if ( !is_array( $options ) )
00442 {
00443
00444 $o['info']['pages'][] = $options;
00445 }
00446 else
00447 {
00448
00449
00450 if ( isset( $options['id'] ) && isset( $options['rid'] ) && isset( $options['pos'] ) )
00451 {
00452 $i = array_search( $options['rid'], $o['info']['pages'] );
00453 if ( isset( $o['info']['pages'][$i] ) && $o['info']['pages'][$i] == $options['rid'])
00454 {
00455
00456
00457 switch ( $options['pos'] )
00458 {
00459 case 'before':
00460 $k = $i;
00461 break;
00462 case 'after':
00463 $k = $i + 1;
00464 break;
00465 default:
00466 $k = -1;
00467 break;
00468 }
00469 if ( $k >= 0 )
00470 {
00471 for ( $j = count( $o['info']['pages'] ) - 1; $j >= $k; $j-- )
00472 {
00473 $o['info']['pages'][$j+1] = $o['info']['pages'][$j];
00474 }
00475 $o['info']['pages'][$k] = $options['id'];
00476 }
00477 }
00478 }
00479 }break;
00480
00481 case 'procset':
00482 $o['info']['procset'] = $options;
00483 break;
00484 case 'mediaBox':
00485 $o['info']['mediaBox'] = $options;
00486 break;
00487 case 'font':
00488 $o['info']['fonts'][] = array( 'objNum' => $options['objNum'], 'fontNum' => $options['fontNum'] );
00489 break;
00490 case 'shading':
00491 $o['info']['shading'][] = array( 'objNum' => $options['objNum'], 'label' => $options['label'] );
00492 break;
00493 case 'xObject':
00494 $o['info']['xObjects'][] = array( 'objNum' => $options['objNum'], 'label' => $options['label'] );
00495 break;
00496 case 'out':
00497 if ( count( $o['info']['pages'] ) )
00498 {
00499 $res = "\n" . $id . " 0 obj\n<< /Type /Pages\n/Kids [";
00500 foreach ( $o['info']['pages'] as $k => $v )
00501 {
00502 $res .= $v . " 0 R\n";
00503 }
00504 $res .= "]\n/Count " . count( $this->objects[$id]['info']['pages'] );
00505 if ( ( isset( $o['info']['fonts'] ) && count( $o['info']['fonts'] ) ) || isset( $o['info']['procset'] ) )
00506 {
00507 $res .= "\n/Resources <<";
00508 if ( isset( $o['info']['procset'] ) )
00509 {
00510 $res .= "\n/ProcSet " . $o['info']['procset'] . " 0 R";
00511 }
00512 if ( isset( $o['info']['fonts'] ) && count( $o['info']['fonts'] ) )
00513 {
00514 $res .= "\n/Font << ";
00515 foreach ( $o['info']['fonts'] as $finfo )
00516 {
00517 $res .= "\n/F" . $finfo['fontNum'] . " " . $finfo['objNum'] . " 0 R";
00518 }
00519 $res .= " >>";
00520 }
00521
00522 if ( isset( $o['info']['shading'] ) && count( $o['info']['shading'] ) )
00523 {
00524 $res .= "\n/Shading <<";
00525 foreach ( $o['info']['shading'] as $finfo )
00526 {
00527 $res .= "\n/" . $finfo['label'] . " " . $finfo['objNum'] . " 0 R";
00528 }
00529 $res .= " >>";
00530 }
00531
00532 if ( isset( $o['info']['xObjects'] ) && count( $o['info']['xObjects'] ) )
00533 {
00534 $res .= "\n/XObject << ";
00535 foreach ( $o['info']['xObjects'] as $finfo )
00536 {
00537 $res .= "\n/" . $finfo['label'] . " " . $finfo['objNum'] . " 0 R";
00538 }
00539 $res .= " >>";
00540 }
00541 $res .= "\n>>";
00542 if ( isset( $o['info']['mediaBox'] ) )
00543 {
00544 $tmp = $o['info']['mediaBox'];
00545 $res .= "\n/MediaBox [" . ezsprintf( '%.3F', $tmp[0] ) . ' ' . ezsprintf( '%.3F', $tmp[1] ) . ' ' . ezsprintf( '%.3F', $tmp[2] ) . ' ' . ezsprintf( '%.3F', $tmp[3] ) . ']';
00546 }
00547 }
00548 $res.="\n >>\nendobj";
00549 }
00550 else
00551 {
00552 $res = "\n" . $id . " 0 obj\n<< /Type /Pages\n/Count 0\n>>\nendobj";
00553 }
00554 return $res;
00555 break;
00556 }
00557 }
00558
00559
00560
00561
00562 function o_outlines( $id, $action, $options = '' )
00563 {
00564 if ( $action != 'new' )
00565 {
00566 $o =& $this->objects[$id];
00567 }
00568 switch ( $action )
00569 {
00570 case 'new':
00571 $this->objects[$id] = array( 't' => 'outlines', 'info' => array( 'outlines' => array() ) );
00572 $this->o_catalog( $this->catalogId, 'outlines', $id );
00573 break;
00574 case 'outline':
00575 $o['info']['outlines'][] = $options;
00576 break;
00577 case 'out':
00578 if ( count( $o['info']['outlines'] ) )
00579 {
00580 $res = "\n" . $id . " 0 obj\n<< /Type /Outlines /Kids [";
00581 foreach ( $o['info']['outlines'] as $k => $v )
00582 {
00583 $res .= $v . " 0 R ";
00584 }
00585 $res .= "] /Count " . count( $o['info']['outlines'] ) . " >>\nendobj";
00586 }
00587 else
00588 {
00589 $res = "\n" . $id . " 0 obj\n<< /Type /Outlines /Count 0 >>\nendobj";
00590 }
00591 return $res;
00592 break;
00593 }
00594 }
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604 function o_function( $id, $action, $options = '' )
00605 {
00606 if ( $action != 'new' )
00607 {
00608 $o =& $this->objects[$id];
00609 }
00610
00611 switch ( $action )
00612 {
00613 case 'new':
00614 {
00615 $this->objects[$id] = array ( 't' => 'function',
00616 'info' => array() );
00617
00618 if ( isset( $options['type'] ) )
00619 {
00620 $this->objects[$id]['info']['type'] = $options['type'];
00621 }
00622 else
00623 {
00624 $this->objects[$id]['info']['type'] = '2';
00625 }
00626
00627 if ( isset( $options['Domain'] ) )
00628 {
00629 $this->objects[$id]['info']['Domain'] = $options['Domain'];
00630 }
00631 else
00632 {
00633 $this->objects[$id]['info']['Domain'] = '[0.0 1.0]';
00634 }
00635
00636 if ( $this->objects[$id]['info']['type'] == '2' )
00637 {
00638 if ( isset( $options['C0'] ) )
00639 {
00640 $this->objects[$id]['info']['C0'] = $options['C0'];
00641 }
00642
00643 if ( isset( $options['C1'] ) )
00644 {
00645 $this->objects[$id]['info']['C1'] = $options['C1'];
00646 }
00647
00648 if ( isset( $options['N'] ) )
00649 {
00650 $this->objects[$id]['info']['N'] = $options['N'];
00651 }
00652 else
00653 {
00654 $this->objects[$id]['info']['N'] = '1.0';
00655 }
00656 }
00657
00658 } break;
00659
00660 case 'out':
00661 {
00662 $res = "\n" . $id . " 0 obj\n<< ";
00663 $res.= "/FunctionType " . $o['info']['type'] . "\n";
00664 $res.= "/Domain " . $o['info']['Domain'] . "\n";
00665 if ( isset ( $o['info']['C0'] ) )
00666 $res.= "/C0 " . $o['info']['C0'] . "\n";
00667 if ( isset ( $o['info']['C1'] ) )
00668 $res.= "/C1 " . $o['info']['C1'] . "\n";
00669 $res.= "/N " . $o['info']['N'] . "\n";
00670 $res.= ">>\nendobject";
00671 return $res;
00672 } break;
00673 }
00674 }
00675
00676
00677
00678
00679
00680
00681
00682
00683
00684
00685
00686 function o_pattern( $id, $action, $options = '' )
00687 {
00688 if ( $action != 'new' )
00689 {
00690 $o =& $this->objects[$id];
00691 }
00692
00693 switch ( $action )
00694 {
00695 case 'new':
00696 {
00697 $this->objects[$id] = array( 't' => 'shading',
00698 'info' => array() );
00699
00700 if ( isset( $options['type'] ) )
00701 {
00702 $this->objects[$id]['info']['PatternType'] = $options['type'];
00703 }
00704 else
00705 {
00706 $this->objects[$id]['info']['PatternType'] = '2';
00707 }
00708
00709 if ( isset( $options['matrix'] ) )
00710 {
00711 $this->objects[$id]['info']['Matrix'] = '[ ';
00712 foreach ( $options['matrix'] as $coord )
00713 {
00714 $this->objects[$id]['info']['Matrix'] .= ezsprintf( ' %.3F ', $coord );
00715 }
00716 $this->objects[$id]['info']['Matrix'] .= ' ]';
00717 }
00718
00719 if ( $this->objects[$id]['info']['PatternType'] == 1 )
00720 {
00721 $this->objects[$id]['info']['PaintType'] = $options['paintType'];
00722 $this->objects[$id]['info']['TilingType'] = $options['tilingType'];
00723
00724 $this->objects[$id]['info']['BBox'] = '[ ';
00725 foreach ( $options['bbox'] as $coord )
00726 {
00727 $this->objects[$id]['info']['BBox'] .= ezsprintf( ' %.3F ', $coord );
00728 }
00729 $this->objects[$id]['info']['BBox'] .= ']';
00730
00731 $this->objects[$id]['info']['XStep'] = $options['xstep'];
00732 $this->objects[$id]['info']['YStep'] = $options['ystep'];
00733 }
00734 else
00735 {
00736 if ( isset( $options['shading'] ) )
00737 {
00738 $this->objects[$id]['info']['Shading'] = $options['shading'] . ' R';
00739 }
00740 }
00741 } break;
00742
00743 case 'out':
00744 {
00745 $res = "\n" . $id . " 0 obj\n<< ";
00746 foreach ( $this->objects[$id]['info'] as $key => $info )
00747 {
00748 $res .= '/' . $key . ' ' . $info[$key] . "\n";
00749 }
00750 $res .= ">>\nendobject";
00751 return $res;
00752 } break;
00753 }
00754 }
00755
00756
00757
00758
00759
00760
00761
00762
00763
00764
00765
00766
00767 function o_shading( $id, $action, $options = '' )
00768 {
00769 if ( $action != 'new' )
00770 {
00771 $o =& $this->objects[$id];
00772 }
00773
00774 switch ( $action )
00775 {
00776 case 'new':
00777 {
00778 $this->objects[$id] = array( 't' => 'shading',
00779 'info' => array( 'type' => '2',
00780 'ColorSpace' => '/DeviceCMYK' ) );
00781
00782 if ( !isset( $options['orientation'] ) )
00783 {
00784 $options['orientation'] = 'vertical';
00785 }
00786
00787 if ( $options['orientation'] == 'horizontal' )
00788 {
00789 $angle = 0;
00790 }
00791 else if ( $options['orientation'] == 'vertical' )
00792 {
00793 $angle = deg2rad( 90 );
00794 }
00795 else
00796 {
00797 $angle = $options['orientation'];
00798 }
00799
00800 $this->objects[$id]['info']['Coords'] = '[ '.
00801 ezsprintf( '%.3F', $options['size']['x1'] ) . ' ' .
00802 ezsprintf( '%.3F', $options['size']['y1'] + $options['size']['height'] ) . ' ' .
00803 ezsprintf( '%.3F', $options['size']['x1'] + $options['size']['width'] * cos( $angle ) ) . ' ' .
00804 ezsprintf( '%.3F', $options['size']['y1'] + $options['size']['height'] * ( 1 - sin( $angle ) ) ) . ']';
00805
00806
00807
00808 if ( is_array( $options['color0'] ) )
00809 {
00810 if ( count( $options['color0'] ) == 3 )
00811 {
00812 $options['color0'] = eZMath::rgbToCMYK( $options['color0'] );
00813 }
00814 $color0 = array ( 'c' => ezsprintf( '%.3F', $options['color0']['c'] ),
00815 'm' => ezsprintf( '%.3F', $options['color0']['m'] ),
00816 'y' => ezsprintf( '%.3F', $options['color0']['y'] ),
00817 'k' => ezsprintf( '%.3F', $options['color0']['k'] ) );
00818 }
00819 else
00820 {
00821 $color0 = eZMath::rgbToCMYK2( 0, 0, 0 );
00822 }
00823 if ( is_array( $options['color1'] ) )
00824 {
00825 if ( count( $options['color1'] ) == 3 )
00826 {
00827 $options['color1'] = eZMath::rgbToCMYK( $options['color1'] );
00828 }
00829 $color1 = array ( 'c' => ezsprintf( '%.3F', $options['color1']['c'] ),
00830 'm' => ezsprintf( '%.3F', $options['color1']['m'] ),
00831 'y' => ezsprintf( '%.3F', $options['color1']['y'] ),
00832 'k' => ezsprintf( '%.3F', $options['color1']['k'] ) );
00833 }
00834 else
00835 {
00836 $color1 = eZMath::rgbToCMYK2( 1, 1, 1 );
00837 }
00838
00839 $this->numObj++;
00840 $this->objects[$id]['info']['Function'] = $this->numObj;
00841 $this->o_function( $this->numObj, 'new', array ( 'type' => '2',
00842 'Domain' => '[0.0 1.0]',
00843 'C0' => '['.$color0['c'].' '.$color0['m'].' '.$color0['y'].' '.$color0['k'].']',
00844 'C1' => '['.$color1['c'].' '.$color1['m'].' '.$color1['y'].' '.$color1['k'].']',
00845 'N' => '1.0' ) );
00846 $this->objects[$id]['info']['Extend'] = '[true true]';
00847
00848 $this->o_pages( $this->currentNode, 'shading', array( 'label' => 'Sh' . $id,
00849 'objNum'=> $id ) );
00850 return 'Sh' . $id;
00851 } break;
00852
00853 case 'out':
00854 {
00855 $res = "\n" . $id . " 0 obj\n<< ";
00856 $res.= "/ShadingType " . $o['info']['type'] . "\n";
00857 $res.= "/ColorSpace " . $o['info']['ColorSpace'] . "\n";
00858 $res.= "/Coords " . $o['info']['Coords'] . "\n";
00859 $res.= "/Function " . $o['info']['Function'] . " 0 R\n";
00860 $res.= "/Extend " . $o['info']['Extend'] . "\n";
00861 $res.= ">>\nendobject";
00862 return $res;
00863 } break;
00864 }
00865 }
00866
00867
00868
00869
00870 function o_font( $id, $action, $options = '' )
00871 {
00872 if ( $action != 'new' )
00873 {
00874 $o =& $this->objects[$id];
00875 }
00876 switch ( $action )
00877 {
00878 case 'new':
00879 $this->objects[$id] = array( 't' => 'font',
00880 'info' => array( 'name' => $options['name'],
00881 'SubType' => 'Type1' ) );
00882 $fontNum = $this->numFonts;
00883 $this->objects[$id]['info']['fontNum'] = $fontNum;
00884
00885 if ( isset( $options['differences'] ) )
00886 {
00887
00888 $this->numObj++;
00889 $this->o_fontEncoding( $this->numObj, 'new', $options );
00890 $this->objects[$id]['info']['encodingDictionary'] = $this->numObj;
00891 }
00892 else if ( isset( $options['encoding'] ) )
00893 {
00894
00895 switch ( $options['encoding'] )
00896 {
00897 case 'WinAnsiEncoding':
00898 case 'MacRomanEncoding':
00899 case 'MacExpertEncoding':
00900 $this->objects[$id]['info']['encoding'] = $options['encoding'];
00901 break;
00902 case 'none':
00903 break;
00904 default:
00905 $this->objects[$id]['info']['encoding'] = 'WinAnsiEncoding';
00906 break;
00907 }
00908 }
00909 else
00910 {
00911 $this->objects[$id]['info']['encoding'] = 'WinAnsiEncoding';
00912 }
00913
00914 $this->o_pages( $this->currentNode, 'font', array( 'fontNum' => $fontNum, 'objNum' => $id ) );
00915 break;
00916
00917 case 'add':
00918 foreach ( $options as $k => $v )
00919 {
00920 switch ( $k )
00921 {
00922 case 'BaseFont':
00923 $o['info']['name'] = $v;
00924 break;
00925 case 'FirstChar':
00926 case 'LastChar':
00927 case 'Widths':
00928 case 'FontDescriptor':
00929 case 'SubType':
00930 $this->addMessage( 'o_font ' . $k . " : " . $v );
00931 $o['info'][$k] = $v;
00932 break;
00933 }
00934 }
00935 break;
00936
00937 case 'out':
00938 $res = "\n" . $id . " 0 obj\n<< /Type /Font\n/Subtype /" . $o['info']['SubType'] . "\n";
00939 $res.= "/Name /F" . $o['info']['fontNum'] . "\n";
00940 $res.= "/BaseFont /" . $o['info']['name'] . "\n";
00941 if ( isset( $o['info']['encodingDictionary'] ) )
00942 {
00943
00944 $res.= "/Encoding " . $o['info']['encodingDictionary'] . " 0 R\n";
00945 }
00946 else if ( isset( $o['info']['encoding'] ) )
00947 {
00948
00949 $res.= "/Encoding /" . $o['info']['encoding'] . "\n";
00950 }
00951 if ( isset($o['info']['FirstChar'] ) )
00952 {
00953 $res.= "/FirstChar " . $o['info']['FirstChar'] . "\n";
00954 }
00955 if ( isset( $o['info']['LastChar'] ) )
00956 {
00957 $res.= "/LastChar " . $o['info']['LastChar'] . "\n";
00958 }
00959 if ( isset( $o['info']['Widths'] ) )
00960 {
00961 $res.= "/Widths " . $o['info']['Widths'] . " 0 R\n";
00962 }
00963 if ( isset( $o['info']['FontDescriptor'] ) )
00964 {
00965 $res.= "/FontDescriptor " . $o['info']['FontDescriptor'] . " 0 R\n";
00966 }
00967 $res.= ">>\nendobj";
00968 return $res;
00969 break;
00970 }
00971 }
00972
00973
00974
00975
00976 function o_fontDescriptor( $id, $action, $options = '')
00977 {
00978 if ( $action != 'new' )
00979 {
00980 $o =& $this->objects[$id];
00981 }
00982 switch ( $action )
00983 {
00984 case 'new':
00985 $this->objects[$id] = array( 't' => 'fontDescriptor', 'info' => $options );
00986 break;
00987 case 'out':
00988 $res = "\n" . $id . " 0 obj\n<< /Type /FontDescriptor\n";
00989 foreach ( $o['info'] as $label => $value )
00990 {
00991 switch ( $label )
00992 {
00993 case 'Ascent':
00994 case 'CapHeight':
00995 case 'Descent':
00996 case 'Flags':
00997 case 'ItalicAngle':
00998 case 'StemV':
00999 case 'AvgWidth':
01000 case 'Leading':
01001 case 'MaxWidth':
01002 case 'MissingWidth':
01003 case 'StemH':
01004 case 'XHeight':
01005 case 'CharSet':
01006 if ( strlen( $value ) )
01007 {
01008 $res.= '/'.$label.' '.$value."\n";
01009 }
01010 break;
01011 case 'FontFile':
01012 case 'FontFile2':
01013 case 'FontFile3':
01014 $res.= '/'.$label.' '.$value." 0 R\n";
01015 break;
01016 case 'FontBBox':
01017 $res.= '/'.$label.' ['.$value[0].' '.$value[1].' '.$value[2].' '.$value[3]."]\n";
01018 break;
01019 case 'FontName':
01020 $res.= '/'.$label.' /'.$value."\n";
01021 break;
01022 }
01023 }
01024 $res .= ">>\nendobj";
01025 return $res;
01026 break;
01027 }
01028 }
01029
01030
01031
01032
01033 function o_fontEncoding( $id, $action, $options = '' )
01034 {
01035 if ( $action != 'new' )
01036 {
01037 $o =& $this->objects[$id];
01038 }
01039 switch ( $action )
01040 {
01041 case 'new':
01042
01043 $this->objects[$id] = array( 't' => 'fontEncoding',
01044 'info' => $options );
01045 break;
01046 case 'out':
01047 $res = "\n" . $id . " 0 obj\n<< /Type /Encoding\n";
01048 if ( !isset( $o['info']['encoding'] ) )
01049 {
01050 $o['info']['encoding'] = 'WinAnsiEncoding';
01051 }
01052 if ( $o['info']['encoding'] != 'none' )
01053 {
01054 $res.= "/BaseEncoding /" . $o['info']['encoding'] . "\n";
01055 }
01056 $res.= "/Differences \n[";
01057 $onum = -100;
01058 foreach ( $o['info']['differences'] as $num => $label )
01059 {
01060 if ($num!=$onum+1)
01061 {
01062
01063 $res.= "\n".$num." /".$label;
01064 }
01065 else
01066 {
01067 $res.= " /".$label;
01068 }
01069 $onum = $num;
01070 }
01071 $res .= "\n]\n>>\nendobj";
01072 return $res;
01073 break;
01074 }
01075 }
01076
01077
01078
01079
01080 function o_procset( $id, $action, $options = '' )
01081 {
01082 if ( $action != 'new' )
01083 {
01084 $o =& $this->objects[$id];
01085 }
01086 switch ( $action )
01087 {
01088 case 'new':
01089 $this->objects[$id] = array( 't' => 'procset',
01090 'info' => array( 'PDF' => 1, 'Text' => 1 ) );
01091 $this->o_pages( $this->currentNode, 'procset', $id );
01092 $this->procsetObjectId = $id;
01093 break;
01094 case 'add':
01095
01096
01097 switch ( $options )
01098 {
01099 case 'ImageB':
01100 case 'ImageC':
01101 case 'ImageI':
01102 $o['info'][$options] = 1;
01103 break;
01104 }
01105 break;
01106 case 'out':
01107 $res = "\n" . $id . " 0 obj\n[";
01108 foreach ( $o['info'] as $label => $val )
01109 {
01110 $res .= '/'.$label.' ';
01111 }
01112 $res .= "]\nendobj";
01113 return $res;
01114 break;
01115 }
01116 }
01117
01118
01119
01120
01121 function o_info( $id, $action, $options = '' )
01122 {
01123 if ( $action != 'new' )
01124 {
01125 $o =& $this->objects[$id];
01126 }
01127 switch ($action)
01128 {
01129 case 'new':
01130 $this->infoObject = $id;
01131 $date = 'D:' . date( 'Ymd' );
01132 $this->objects[$id] = array( 't' => 'info',
01133 'info' => array( 'Creator' => 'eZ publish CMS, http://ez.no',
01134 'CreationDate' => $date ) );
01135 break;
01136 case 'Title':
01137 case 'Author':
01138 case 'Subject':
01139 case 'Keywords':
01140 case 'Creator':
01141 case 'Producer':
01142 case 'CreationDate':
01143 case 'ModDate':
01144 case 'Trapped':
01145 $o['info'][$action]=$options;
01146 break;
01147 case 'out':
01148 if ( $this->encrypted )
01149 {
01150 $this->encryptInit( $id );
01151 }
01152 $res = "\n" . $id . " 0 obj\n<<\n";
01153 foreach ( $o['info'] as $k => $v )
01154 {
01155 $res .= '/' . $k . ' (';
01156 if ( $this->encrypted )
01157 {
01158 $res .= $this->filterText( $this->ARC4( $v ) );
01159 }
01160 else
01161 {
01162 $res .= $this->filterText( $v );
01163 }
01164 $res .= ")\n";
01165 }
01166 $res .= ">>\nendobj";
01167 return $res;
01168 break;
01169 }
01170 }
01171
01172
01173
01174
01175 function o_action( $id, $action, $options = '' )
01176 {
01177 if ( $action != 'new' )
01178 {
01179 $o =& $this->objects[$id];
01180 }
01181 switch ( $action )
01182 {
01183 case 'new':
01184 if ( is_array( $options ) )
01185 {
01186 $this->objects[$id] = array( 't' => 'action',
01187 'info' => $options,
01188 'type' => $options['type'] );
01189 }
01190 else
01191 {
01192
01193 $this->objects[$id] = array( 't' => 'action',
01194 'info' => $options,
01195 'type' => 'URI' );
01196 }
01197 break;
01198 case 'out':
01199 if ( $this->encrypted )
01200 {
01201 $this->encryptInit( $id );
01202 }
01203 $res = "\n" . $id . " 0 obj\n<< /Type /Action";
01204 switch( $o['type'] )
01205 {
01206 case 'ilink':
01207
01208
01209 $res .= "\n/S /GoTo\n/D [" . $this->objects[ $this->destinations[ (string)$o['info']['label'] ] ]['info']['page'] . " 0 R /" .
01210 $this->objects[ $this->destinations[ (string)$o['info']['label'] ] ]['info']['string'] . ']';
01211 break;
01212 case 'URI':
01213 $res .= "\n/S /URI\n/URI (";
01214 if ( $this->encrypted )
01215 {
01216 $res .= $this->filterText( $this->ARC4( $o['info'] ) );
01217 }
01218 else
01219 {
01220 $res .= $this->filterText( $o['info'] );
01221 }
01222 $res .= ")";
01223 break;
01224 }
01225 $res .= "\n>>\nendobj";
01226 return $res;
01227 break;
01228 }
01229 }
01230
01231
01232
01233
01234
01235 function o_annotation( $id, $action, $options = '' )
01236 {
01237 if ( $action != 'new' )
01238 {
01239 $o =& $this->objects[$id];
01240 }
01241 switch ( $action )
01242 {
01243 case 'new':
01244
01245 $pageId = $this->currentPage;
01246 $this->o_page( $pageId, 'annot', $id);
01247
01248 switch ( $options['type'] )
01249 {
01250 case 'link':
01251 $this->objects[$id] = array( 't' => 'annotation', 'info' => $options );
01252 $this->numObj++;
01253 $this->o_action( $this->numObj, 'new', $options['url'] );
01254 $this->objects[$id]['info']['actionId'] = $this->numObj;
01255 break;
01256 case 'ilink':
01257
01258 $label = $options['label'];
01259 $this->objects[$id] = array( 't' => 'annotation', 'info' => $options );
01260 $this->numObj++;
01261 $this->o_action( $this->numObj, 'new', array( 'type' => 'ilink', 'label' => $label ) );
01262 $this->objects[$id]['info']['actionId'] = $this->numObj;
01263 break;
01264 }
01265 break;
01266
01267 case 'out':
01268 $res = "\n" . $id . " 0 obj\n<< /Type /Annot";
01269 switch ( $o['info']['type'] )
01270 {
01271 case 'link':
01272 case 'ilink':
01273 $res.= "\n/Subtype /Link";
01274 break;
01275 }
01276 $res.= "\n/A ".$o['info']['actionId']." 0 R";
01277 $res.= "\n/Border [0 0 0]";
01278 $res.= "\n/H /I";
01279 $res.= "\n/Rect [ ";
01280 foreach ( $o['info']['rect'] as $v )
01281 {
01282 $res.= ezsprintf( "%.4F ", $v );
01283 }
01284 $res.= "]";
01285 $res.= "\n>>\nendobj";
01286 return $res;
01287 break;
01288 }
01289 }
01290
01291
01292
01293
01294 function o_page($id,$action,$options=''){
01295 if ($action!='new'){
01296 $o =& $this->objects[$id];
01297 }
01298 switch ($action){
01299 case 'new':
01300 $this->numPages++;
01301 $this->objects[$id]=array('t'=>'page','info'=>array('parent'=>$this->currentNode,'pageNum'=>$this->numPages));
01302 if (is_array($options)){
01303
01304 $options['id']=$id;
01305 $this->o_pages($this->currentNode,'page',$options);
01306 } else {
01307 $this->o_pages($this->currentNode,'page',$id);
01308 }
01309 $this->currentPage=$id;
01310
01311 $this->numObj++;
01312 $this->o_contents($this->numObj,'new',$id);
01313 $this->currentContents=$this->numObj;
01314 $this->objects[$id]['info']['contents']=array();
01315 $this->objects[$id]['info']['contents'][]=$this->numObj;
01316 $match = ($this->numPages%2 ? 'odd' : 'even');
01317 foreach($this->addLooseObjects as $oId=>$target){
01318 if ($target=='all' || $match==$target){
01319 $this->objects[$id]['info']['contents'][]=$oId;
01320 }
01321 }
01322 break;
01323 case 'content':
01324 $o['info']['contents'][]=$options;
01325 break;
01326 case 'annot':
01327
01328 if (!isset($o['info']['annot'])){
01329 $o['info']['annot']=array();
01330 }
01331
01332 $o['info']['annot'][]=$options;
01333 break;
01334 case 'out':
01335 $res="\n".$id." 0 obj\n<< /Type /Page";
01336 $res.="\n/Parent ".$o['info']['parent']." 0 R";
01337 if (isset($o['info']['annot'])){
01338 $res.="\n/Annots [";
01339 foreach($o['info']['annot'] as $aId){
01340 $res.=" ".$aId." 0 R";
01341 }
01342 $res.=" ]";
01343 }
01344 $count = count($o['info']['contents']);
01345 if ($count==1){
01346 $res.="\n/Contents ".$o['info']['contents'][0]." 0 R";
01347 } else if ($count>1){
01348 $res.="\n/Contents [\n";
01349 foreach ($o['info']['contents'] as $cId){
01350 $res.=$cId." 0 R\n";
01351 }
01352 $res.="]";
01353 }
01354 $res.="\n>>\nendobj";
01355 return $res;
01356 break;
01357 }
01358 }
01359
01360
01361
01362
01363 function o_contents($id,$action,$options=''){
01364 if ($action!='new'){
01365 $o =& $this->objects[$id];
01366 }
01367 switch ($action){
01368 case 'new':
01369 $this->objects[$id]=array('t'=>'contents','c'=>'','info'=>array());
01370 if (strlen($options) && intval($options)){
01371
01372 $this->objects[$id]['onPage']=$options;
01373 } else if ($options=='raw'){
01374
01375 $this->objects[$id]['raw']=1;
01376 }
01377 break;
01378 case 'add':
01379
01380 foreach ($options as $k=>$v){
01381 $o['info'][$k]=$v;
01382 }
01383 case 'out':
01384 $tmp=$o['c'];
01385 $res= "\n".$id." 0 obj\n";
01386 if (isset($this->objects[$id]['raw'])){
01387 $res.=$tmp;
01388 } else {
01389 $res.= "<<";
01390 if (function_exists('gzcompress') && $this->options['compression']){
01391
01392 $res.=" /Filter /FlateDecode";
01393 $tmp = gzcompress($tmp);
01394 }
01395 if ($this->encrypted){
01396 $this->encryptInit($id);
01397 $tmp = $this->ARC4($tmp);
01398 }
01399 foreach($o['info'] as $k=>$v){
01400 $res .= "\n/".$k.' '.$v;
01401 }
01402 $res.="\n/Length ".strlen($tmp)." >>\nstream\n".$tmp."\nendstream";
01403 }
01404 $res.="\nendobj\n";
01405 return $res;
01406 break;
01407 }
01408 }
01409
01410
01411
01412
01413 function o_image($id,$action,$options=''){
01414 if ($action!='new'){
01415 $o =& $this->objects[$id];
01416 }
01417 switch($action){
01418 case 'new':
01419
01420 $this->objects[$id]=array('t'=>'image','data'=>$options['data'],'info'=>array());
01421 $this->objects[$id]['info']['Type']='/XObject';
01422 $this->objects[$id]['info']['Subtype']='/Image';
01423 $this->objects[$id]['info']['Width']=$options['iw'];
01424 $this->objects[$id]['info']['Height']=$options['ih'];
01425 if (!isset($options['type']) || $options['type']=='jpg'){
01426 if (!isset($options['channels'])){
01427 $options['channels']=3;
01428 }
01429 switch($options['channels']){
01430 case 1:
01431 $this->objects[$id]['info']['ColorSpace']='/DeviceGray';
01432 break;
01433 default:
01434 $this->objects[$id]['info']['ColorSpace']='/DeviceRGB';
01435 break;
01436 }
01437 $this->objects[$id]['info']['Filter']='/DCTDecode';
01438 $this->objects[$id]['info']['BitsPerComponent']=8;
01439 } else if ($options['type']=='png'){
01440 $this->objects[$id]['info']['Filter']='/FlateDecode';
01441 $this->objects[$id]['info']['DecodeParms']='<< /Predictor 15 /Colors '.$options['ncolor'].' /Columns '.$options['iw'].' /BitsPerComponent '.$options['bitsPerComponent'].'>>';
01442 if (strlen($options['pdata'])){
01443 $tmp = ' [ /Indexed /DeviceCMYK '.(strlen($options['pdata'])/3-1).' ';
01444 $this->numObj++;
01445 $this->o_contents($this->numObj,'new');
01446 $this->objects[$this->numObj]['c']=$options['pdata'];
01447 $tmp.=$this->numObj.' 0 R';
01448 $tmp .=' ]';
01449 $this->objects[$id]['info']['ColorSpace'] = $tmp;
01450 if (isset($options['transparency'])){
01451 switch($options['transparency']['type']){
01452 case 'indexed':
01453 $tmp=' [ '.$options['transparency']['data'].' '.$options['transparency']['data'].'] ';
01454 $this->objects[$id]['info']['Mask'] = $tmp;
01455 break;
01456 }
01457 }
01458 } else {
01459 $this->objects[$id]['info']['ColorSpace']='/'.$options['color'];
01460 }
01461 $this->objects[$id]['info']['BitsPerComponent']=$options['bitsPerComponent'];
01462 }
01463
01464
01465 $this->o_pages($this->currentNode,'xObject',array('label'=>$options['label'],'objNum'=>$id));
01466
01467 $this->o_procset($this->procsetObjectId,'add','ImageC');
01468 break;
01469 case 'out':
01470 $tmp=$o['data'];
01471 $res= "\n".$id." 0 obj\n<<";
01472 foreach($o['info'] as $k=>$v){
01473 $res.="\n/".$k.' '.$v;
01474 }
01475 if ($this->encrypted){
01476 $this->encryptInit($id);
01477 $tmp = $this->ARC4($tmp);
01478 }
01479 $res.="\n/Length ".strlen($tmp)." >>\nstream\n".$tmp."\nendstream\nendobj\n";
01480 return $res;
01481 break;
01482 }
01483 }
01484
01485
01486
01487
01488 function o_encryption($id,$action,$options=''){
01489 if ($action!='new'){
01490 $o =& $this->objects[$id];
01491 }
01492 switch($action){
01493 case 'new':
01494
01495 $this->objects[$id]=array('t'=>'encryption','info'=>$options);
01496 $this->arc4_objnum=$id;
01497
01498 $pad = chr(0x28).chr(0xBF).chr(0x4E).chr(0x5E).chr(0x4E).chr(0x75).chr(0x8A).chr(0x41).chr(0x64).chr(0x00).chr(0x4E).chr(0x56).chr(0xFF).chr(0xFA).chr(0x01).chr(0x08).chr(0x2E).chr(0x2E).chr(0x00).chr(0xB6).chr(0xD0).chr(0x68).chr(0x3E).chr(0x80).chr(0x2F).chr(0x0C).chr(0xA9).chr(0xFE).chr(0x64).chr(0x53).chr(0x69).chr(0x7A);
01499 $len = strlen($options['owner']);
01500 if ($len>32){
01501 $owner = substr($options['owner'],0,32);
01502 } else if ($len<32){
01503 $owner = $options['owner'].substr($pad,0,32-$len);
01504 } else {
01505 $owner = $options['owner'];
01506 }
01507 $len = strlen($options['user']);
01508 if ($len>32){
01509 $user = substr($options['user'],0,32);
01510 } else if ($len<32){
01511 $user = $options['user'].substr($pad,0,32-$len);
01512 } else {
01513 $user = $options['user'];
01514 }
01515 $tmp = $this->md5_16($owner);
01516 $okey = substr($tmp,0,5);
01517 $this->ARC4_init($okey);
01518 $ovalue=$this->ARC4($user);
01519 $this->objects[$id]['info']['O']=$ovalue;
01520
01521 $tmp = $this->md5_16($user.$ovalue.chr($options['p']).chr(255).chr(255).chr(255).$this->fileIdentifier);
01522 $ukey = substr($tmp,0,5);
01523
01524 $this->ARC4_init($ukey);
01525 $this->encryptionKey = $ukey;
01526 $this->encrypted=1;
01527 $uvalue=$this->ARC4($pad);
01528
01529 $this->objects[$id]['info']['U']=$uvalue;
01530 $this->encryptionKey=$ukey;
01531
01532
01533 break;
01534 case 'out':
01535 $res= "\n".$id." 0 obj\n<<";
01536 $res.="\n/Filter /Standard";
01537 $res.="\n/V 1";
01538 $res.="\n/R 2";
01539 $res.="\n/O (".$this->filterText($o['info']['O']).')';
01540 $res.="\n/U (".$this->filterText($o['info']['U']).')';
01541
01542 $o['info']['p'] = (($o['info']['p']^255)+1)*-1;
01543 $res.="\n/P ".($o['info']['p']);
01544 $res.="\n>>\nendobj\n";
01545
01546 return $res;
01547 break;
01548 }
01549 }
01550
01551
01552
01553
01554
01555
01556
01557
01558
01559 function md5_16($string){
01560 $tmp = md5($string);
01561 $out='';
01562 for ($i=0;$i<=30;$i=$i+2){
01563 $out.=chr(hexdec(substr($tmp,$i,2)));
01564 }
01565 return $out;
01566 }
01567
01568
01569
01570
01571 function encryptInit($id){
01572 $tmp = $this->encryptionKey;
01573 $hex = dechex($id);
01574 if (strlen($hex)<6){
01575 $hex = substr('000000',0,6-strlen($hex)).$hex;
01576 }
01577 $tmp.= chr(hexdec(substr($hex,4,2))).chr(hexdec(substr($hex,2,2))).chr(hexdec(substr($hex,0,2))).chr(0).chr(0);
01578 $key = $this->md5_16($tmp);
01579 $this->ARC4_init(substr($key,0,10));
01580 }
01581
01582
01583
01584
01585 function ARC4_init($key=''){
01586 $this->arc4 = '';
01587
01588 if (strlen($key)==0){
01589 return;
01590 }
01591 $k = '';
01592 while(strlen($k)<256){
01593 $k.=$key;
01594 }
01595 $k=substr($k,0,256);
01596 for ($i=0;$i<256;$i++){
01597 $this->arc4 .= chr($i);
01598 }
01599 $j=0;
01600 for ($i=0;$i<256;$i++){
01601 $t = $this->arc4[$i];
01602 $j = ($j + ord($t) + ord($k[$i]))%256;
01603 $this->arc4[$i]=$this->arc4[$j];
01604 $this->arc4[$j]=$t;
01605 }
01606 }
01607
01608
01609
01610
01611 function ARC4($text){
01612 $len=strlen($text);
01613 $a=0;
01614 $b=0;
01615 $c = $this->arc4;
01616 $out='';
01617 for ($i=0;$i<$len;$i++){
01618 $a = ($a+1)%256;
01619 $t= $c[$a];
01620 $b = ($b+ord($t))%256;
01621 $c[$a]=$c[$b];
01622 $c[$b]=$t;
01623 $k = ord($c[(ord($c[$a])+ord($c[$b]))%256]);
01624 $out.=chr(ord($text[$i]) ^ $k);
01625 }
01626
01627 return $out;
01628 }
01629
01630
01631
01632
01633
01634
01635
01636
01637 function addLink($url,$x0,$y0,$x1,$y1){
01638 $this->numObj++;
01639 $info = array('type'=>'link','url'=>$url,'rect'=>array($x0,$y0,$x1,$y1));
01640 $this->o_annotation($this->numObj,'new',$info);
01641 }
01642
01643
01644
01645
01646 function addInternalLink($label,$x0,$y0,$x1,$y1){
01647 $this->numObj++;
01648 $info = array('type'=>'ilink','label'=>$label,'rect'=>array($x0,$y0,$x1,$y1));
01649 $this->o_annotation($this->numObj,'new',$info);
01650 }
01651
01652
01653
01654
01655
01656
01657 function setEncryption($userPass='',$ownerPass='',$pc=array()){
01658 $p=bindec(11000000);
01659
01660 $options = array(
01661 'print'=>4
01662 ,'modify'=>8
01663 ,'copy'=>16
01664 ,'add'=>32
01665 );
01666 foreach($pc as $k=>$v){
01667 if ($v && isset($options[$k])){
01668 $p+=$options[$k];
01669 } else if (isset($options[$v])){
01670 $p+=$options[$v];
01671 }
01672 }
01673
01674 if ($this->arc4_objnum == 0){
01675
01676 $this->numObj++;
01677 if (strlen($ownerPass)==0){
01678 $ownerPass=$userPass;
01679 }
01680 $this->o_encryption($this->numObj,'new',array('user'=>$userPass,'owner'=>$ownerPass,'p'=>$p));
01681 }
01682 }
01683
01684
01685
01686
01687 function checkAllHere(){
01688 }
01689
01690
01691
01692
01693 function output($debug=0){
01694
01695 if ($debug){
01696
01697 $this->options['compression']=0;
01698 }
01699
01700 if ($this->arc4_objnum){
01701 $this->ARC4_init($this->encryptionKey);
01702 }
01703
01704 $this->checkAllHere();
01705
01706 $xref=array();
01707 $content="%PDF-1.3\n%âãÏÓ\n";
01708
01709 $pos=strlen($content);
01710 foreach($this->objects as $k=>$v){
01711 $tmp='o_'.$v['t'];
01712 $cont=$this->$tmp($k,'out');
01713 $content.=$cont;
01714 $xref[]=$pos;
01715 $pos+=strlen($cont);
01716 }
01717 $content.="\nxref\n0 ".(count($xref)+1)."\n0000000000 65535 f \n";
01718 foreach($xref as $p){
01719 ++$p;
01720 $content.=substr('0000000000',0,10-strlen($p)).$p." 00000 n \n";
01721 }
01722 $content.="\ntrailer\n << /Size ".(count($xref)+1)."\n /Root 1 0 R\n /Info ".$this->infoObject." 0 R\n";
01723
01724 if ($this->arc4_objnum > 0){
01725 $content .= "/Encrypt ".$this->arc4_objnum." 0 R\n";
01726 }
01727 if (strlen($this->fileIdentifier)){
01728 $content .= "/ID[<".$this->fileIdentifier."><".$this->fileIdentifier.">]\n";
01729 }
01730 $content .= " >>\nstartxref\n".($pos+1)."\n%%EOF\n";
01731
01732 return $content;
01733 }
01734
01735
01736
01737
01738
01739
01740
01741
01742 function newDocument($pageSize=array(0,0,612,792)){
01743 $this->numObj=0;
01744 $this->objects = array();
01745
01746 $this->numObj++;
01747 $this->o_catalog($this->numObj,'new');
01748
01749 $this->numObj++;
01750 $this->o_outlines($this->numObj,'new');
01751
01752 $this->numObj++;
01753 $this->o_pages($this->numObj,'new');
01754
01755 $this->o_pages($this->numObj,'mediaBox',$pageSize);
01756 $this->currentNode = 3;
01757
01758 $this->numObj++;
01759 $this->o_procset($this->numObj,'new');
01760
01761 $this->numObj++;
01762 $this->o_info($this->numObj,'new');
01763
01764 $this->numObj++;
01765 $this->o_page($this->numObj,'new');
01766
01767
01768
01769 $this->firstPageId = $this->currentContents;
01770 }
01771
01772
01773
01774
01775
01776
01777
01778
01779
01780
01781 function openFont( $font )
01782 {
01783
01784 $pos = strrpos( $font, '/' );
01785 if ( $pos === false )
01786 {
01787 $dir = './';
01788 $name = $font;
01789 }
01790 else
01791 {
01792 $dir = substr( $font, 0, $pos + 1 );
01793 $name = substr( $font, $pos + 1 );
01794 }
01795
01796 if ( substr( $name, -5 ) == '.font' )
01797 {
01798 $name = substr( $name, 0, strlen( $name ) - 5 );
01799 }
01800
01801 $this->addMessage( 'openFont: ' . $font . ' - ' . $name );
01802 if ( file_exists( $dir.'php_'.$name.'.font' ) )
01803 {
01804 $this->addMessage( 'openFont: php file exists ' . $dir . 'php_' . $name . '.font' );
01805 $tmp = file( $dir . 'php_' . $name . '.font' );
01806 $this->fonts[$font] = unserialize( $tmp[0] );
01807 if ( !isset( $this->fonts[$font]['_version_'] ) || $this->fonts[$font]['_version_'] < 1 )
01808 {
01809
01810 $this->addMessage( 'openFont: clear out, make way for new version.' );
01811 unset( $this->fonts[$font] );
01812 }
01813 }
01814 if ( !isset( $this->fonts[$font] ) && file_exists( $dir.$name.'.afm' ) )
01815 {
01816
01817 $this->addMessage( 'openFont: build php file from ' . $dir.$name.'.afm' );
01818 $data = array();
01819 $file = file( $dir.$name.'.afm' );
01820 foreach ( $file as $rowA )
01821 {
01822 $row = trim( $rowA );
01823 $pos = strpos( $row, ' ' );
01824 if ( $pos )
01825 {
01826
01827 $key = substr( $row, 0, $pos );
01828 switch ( $key )
01829 {
01830 case 'FontName':
01831 case 'FullName':
01832 case 'FamilyName':
01833 case 'Weight':
01834 case 'ItalicAngle':
01835 case 'IsFixedPitch':
01836 case 'CharacterSet':
01837 case 'UnderlinePosition':
01838 case 'UnderlineThickness':
01839 case 'Version':
01840 case 'EncodingScheme':
01841 case 'CapHeight':
01842 case 'XHeight':
01843 case 'Ascender':
01844 case 'Descender':
01845 case 'StdHW':
01846 case 'StdVW':
01847 case 'StartCharMetrics':
01848 $data[$key] = trim( substr( $row, $pos ) );
01849 break;
01850 case 'FontBBox':
01851 $data[$key] = explode(' ', trim( substr( $row, $pos ) ) );
01852 break;
01853 case 'C':
01854
01855 $bits = explode( ';', trim( $row ) );
01856 $dtmp = array();
01857 foreach ( $bits as $bit )
01858 {
01859 $bits2 = explode( ' ', trim( $bit ) );
01860 if ( strlen( $bits2[0] ) )
01861 {
01862 if ( count( $bits2 ) > 2 )
01863 {
01864 $dtmp[$bits2[0]] = array();
01865 for ( $i = 1; $i < count( $bits2 ); $i++ )
01866 {
01867 $dtmp[$bits2[0]][] = $bits2[$i];
01868 }
01869 }
01870 else if ( count( $bits2 ) == 2 )
01871 {
01872 $dtmp[$bits2[0]] = $bits2[1];
01873 }
01874 }
01875 }
01876 if ( $dtmp['C'] >= 0 )
01877 {
01878 $data['C'][$dtmp['C']] = $dtmp;
01879 $data['C'][$dtmp['N']] = $dtmp;
01880 }
01881 else
01882 {
01883 $data['C'][$dtmp['N']] = $dtmp;
01884 }
01885 break;
01886
01887 case 'KPX':
01888
01889 $bits = explode( ' ', trim( $row ) );
01890 $data['KPX'][$bits[1]][$bits[2]] = $bits[3];
01891 break;
01892 }
01893 }
01894 }
01895 $data['_version_'] = 1;
01896 $this->fonts[$font] = $data;
01897 $fp = fopen( $dir.'php_'.$name.'.font', 'w' );
01898 fwrite( $fp, serialize( $data ) );
01899 fclose( $fp );
01900 }
01901 else if ( !isset( $this->fonts[$font] ) )
01902 {
01903 $this->addMessage( 'openFont: no font file found' );
01904
01905 }
01906 }
01907
01908
01909
01910
01911
01912
01913
01914
01915
01916 function selectFont( $fontName, $encoding = '', $set = 1 )
01917 {
01918 if ( !isset( $this->fonts[$fontName] ) )
01919 {
01920
01921 $this->openFont( $fontName );
01922 if ( isset( $this->fonts[$fontName] ) )
01923 {
01924 $this->numObj++;
01925 $this->numFonts++;
01926 $pos = strrpos( $fontName, '/' );
01927 $name = substr( $fontName, $pos + 1 );
01928 if ( substr( $name, -5 ) == '.font' )
01929 {
01930 $name = substr( $name, 0, strlen( $name ) - 5 );
01931 }
01932 if ( !isset( $this->fontFamilies[$name] ) )
01933 {
01934 $this->setFontFamily( $name, array( 'b' => $name . '-Bold',
01935 'i' => $name . '-Italic',
01936 'bi' => $name . '-BoldItalic',
01937 'ib' => $name . '-BoldItalic' ) );
01938 }
01939 $options = array( 'name' => $name );
01940 if ( is_array( $encoding ) )
01941 {
01942
01943 if ( isset( $encoding['encoding'] ) )
01944 {
01945 $options['encoding'] = $encoding['encoding'];
01946 }
01947 if ( isset( $encoding['differences'] ) )
01948 {
01949 $options['differences'] = $encoding['differences'];
01950 }
01951 }
01952 else if ( strlen( $encoding ) )
01953 {
01954
01955 $options['encoding'] = $encoding;
01956 }
01957 $fontObj = $this->numObj;
01958 $this->o_font( $this->numObj, 'new', $options );
01959 $this->fonts[$fontName]['fontNum'] = $this->numFonts;
01960
01961
01962
01963 $basefile = substr( $fontName, 0, strlen( $fontName ) );
01964 if ( file_exists( $basefile.'.pfb' ) )
01965 {
01966 $fbtype = 'pfb';
01967 }
01968 else if ( file_exists( $basefile.'.ttf' ) )
01969 {
01970 $fbtype = 'ttf';
01971 }
01972 else
01973 {
01974 $fbtype = '';
01975 }
01976 $fbfile = $basefile.'.'.$fbtype;
01977
01978 $this->addMessage( 'selectFont: checking for - ' . $fbfile );
01979 if ( strlen( $fbtype ) )
01980 {
01981 $adobeFontName = $this->fonts[$fontName]['FontName'];
01982 $this->addMessage( 'selectFont: adding font file - ' . $fbfile . ' - ' . $adobeFontName );
01983
01984 $firstChar = -1;
01985 $lastChar = 0;
01986 $widths = array();
01987 foreach ( $this->fonts[$fontName]['C'] as $num => $d )
01988 {
01989 if ( intval($num) > 0 || $num == '0' )
01990 {
01991 if ( $lastChar > 0 && $num > $lastChar + 1 )
01992 {
01993 for ( $i = $lastChar + 1; $i < $num; $i++ )
01994 {
01995 $widths[] = 0;
01996 }
01997 }
01998 $widths[] = $d['WX'];
01999 if ( $firstChar == -1 )
02000 {
02001 $firstChar = $num;
02002 }
02003 $lastChar = $num;
02004 }
02005 }
02006
02007 if ( isset( $options['differences'] ) )
02008 {
02009 foreach( $options['differences'] as $charNum => $charName )
02010 {
02011 if ( $charNum > $lastChar )
02012 {
02013 for( $i = $lastChar + 1; $i <= $charNum; $i++ )
02014 {
02015 $widths[] = 0;
02016 }
02017 $lastChar = $charNum;
02018 }
02019 if ( isset( $this->fonts[$fontName]['C'][$charName] ) )
02020 {
02021 $widths[$charNum-$firstChar] = $this->fonts[$fontName]['C'][$charName]['WX'];
02022 }
02023 }
02024 }
02025 $this->addMessage( 'selectFont: FirstChar=' . $firstChar );
02026 $this->addMessage( 'selectFont: LastChar=' . $lastChar );
02027 $this->numObj++;
02028 $this->o_contents( $this->numObj, 'new', 'raw' );
02029 $this->objects[$this->numObj]['c'] .= '[';
02030 foreach ( $widths as $width )
02031 {
02032 $this->objects[$this->numObj]['c'] .= ' ' . $width;
02033 }
02034 $this->objects[$this->numObj]['c'] .= ' ]';
02035 $widthid = $this->numObj;
02036
02037
02038
02039
02040 $fp = fopen( $fbfile, 'rb' );
02041 $tmp = get_magic_quotes_runtime();
02042 set_magic_quotes_runtime( 0 );
02043 $data = fread( $fp, filesize( $fbfile ) );
02044 set_magic_quotes_runtime( $tmp );
02045 fclose( $fp );
02046
02047
02048 $this->numObj++;
02049 $fontDescriptorId = $this->numObj;
02050 $this->numObj++;
02051 $pfbid = $this->numObj;
02052
02053 $flags=0;
02054 if ( $this->fonts[$fontName]['ItalicAngle'] != 0 )
02055 {
02056 $flags += pow( 2, 6 );
02057 }
02058 if ( $this->fonts[$fontName]['IsFixedPitch'] == 'true' )
02059 {
02060 $flags += 1;
02061 }
02062 $flags += pow( 2, 5 );
02063
02064 $list = array( 'Ascent' => 'Ascender',
02065 'CapHeight' => 'CapHeight',
02066 'Descent' => 'Descender',
02067 'FontBBox' => 'FontBBox',
02068 'ItalicAngle' => 'ItalicAngle' );
02069 $fdopt = array( 'Flags' => $flags,
02070 'FontName' => $adobeFontName,
02071 'StemV' => 100
02072 );
02073 foreach ( $list as $k => $v )
02074 {
02075 if ( isset( $this->fonts[$fontName][$v] ) )
02076 {
02077 $fdopt[$k] = $this->fonts[$fontName][$v];
02078 }
02079 }
02080
02081 if ( $fbtype == 'pfb' )
02082 {
02083 $fdopt['FontFile'] = $pfbid;
02084 }
02085 else if ( $fbtype == 'ttf' )
02086 {
02087 $fdopt['FontFile2'] = $pfbid;
02088 }
02089 $this->o_fontDescriptor( $fontDescriptorId, 'new', $fdopt );
02090
02091
02092 $this->o_contents( $this->numObj, 'new' );
02093 $this->objects[$pfbid]['c'] .= $data;
02094
02095 if ($fbtype=='pfb')
02096 {
02097 $l1 = strpos($data,'eexec') + 6;
02098 $l2 = strpos($data,'00000000') - $l1;
02099 $l3 = strlen($data) - $l2 - $l1;
02100 $this->o_contents( $this->numObj, 'add', array( 'Length1' => $l1,
02101 'Length2' => $l2,
02102 'Length3' => $l3 ) );
02103 }
02104 else if ( $fbtype == 'ttf' )
02105 {
02106 $l1 = strlen($data);
02107 $this->o_contents( $this->numObj, 'add', array( 'Length1' => $l1 ) );
02108 }
02109
02110
02111 $tmp = array( 'BaseFont' => $adobeFontName,
02112 'Widths' => $widthid,
02113 'FirstChar' => $firstChar,
02114 'LastChar' => $lastChar,
02115 'FontDescriptor' => $fontDescriptorId );
02116 if ( $fbtype == 'ttf' )
02117 {
02118 $tmp['SubType'] = 'TrueType';
02119 }
02120 $this->addMessage( 'adding extra info to font.('.$fontObj.')' );
02121 foreach ( $tmp as $fk => $fv )
02122 {
02123 $this->addMessage( $fk." : ".$fv );
02124 }
02125 $this->o_font( $fontObj, 'add', $tmp );
02126
02127 }
02128 else
02129 {
02130 $this->addMessage( 'selectFont: pfb or ttf file not found, ok if this is one of the 14 standard fonts' );
02131 }
02132
02133
02134
02135
02136 if ( isset( $options['differences'] ) )
02137 {
02138 $this->fonts[$fontName]['differences'] = $options['differences'];
02139 }
02140 }
02141 }
02142 if ( $set && isset( $this->fonts[$fontName] ) )
02143 {
02144
02145 $this->currentBaseFont = $fontName;
02146
02147
02148 $this->setCurrentFont();
02149 }
02150 return $this->currentFontNum;
02151 }
02152
02153
02154
02155
02156
02157
02158 function currentFont()
02159 {
02160 return $this->currentBaseFont;
02161 }
02162
02163
02164
02165
02166
02167
02168
02169
02170
02171
02172
02173
02174
02175 function setCurrentFont()
02176 {
02177 if ( strlen( $this->currentBaseFont ) == 0 )
02178 {
02179
02180 $this->selectFont( 'lib/ezpdf/classes/fonts/Helvetica' );
02181 }
02182 $cf = substr( $this->currentBaseFont, strrpos( $this->currentBaseFont, '/' ) + 1 );
02183 if ( strlen( $this->currentTextState )
02184 && isset( $this->fontFamilies[$cf] )
02185 && isset( $this->fontFamilies[$cf][$this->currentTextState] ) )
02186 {
02187
02188
02189
02190 $nf = substr( $this->currentBaseFont, 0, strrpos( $this->currentBaseFont, '/' ) + 1 ) .
02191 $this->fontFamilies[$cf][$this->currentTextState];
02192 $this->selectFont( $nf, '', 0 );
02193 $this->currentFont = $nf;
02194 $this->currentFontNum = $this->fonts[$nf]['fontNum'];
02195 }
02196 else
02197 {
02198
02199
02200 $this->currentFont = $this->currentBaseFont;
02201 $this->currentFontNum = $this->fonts[$this->currentFont]['fontNum'];
02202 }
02203 }
02204
02205
02206
02207
02208
02209 function getFirstPageId()
02210 {
02211 return $this->firstPageId;
02212 }
02213
02214
02215
02216
02217
02218
02219 function addContent( $content )
02220 {
02221 $this->objects[$this->currentContents]['c'] .= $content;
02222 }
02223
02224
02225
02226
02227 function setColorRGB( $r, $g, $b, $force = 0 )
02228 {
02229 $this->setColor( eZMath::rgbToCMYK2( $r, $g, $b ), $force );
02230 }
02231
02232
02233
02234
02235
02236
02237 function setColor( $cmykArray, $force = 0 )
02238 {
02239 if ( $force || !$this->compareCMYK( $cmykArray, $this->currentColour ) )
02240 {
02241 $this->objects[$this->currentContents]['c'] .= "\n" .
02242 ezsprintf( '%.3F', $cmykArray['c'] ) . ' ' . ezsprintf( '%.3F', $cmykArray['m'] ) . ' ' .
02243 ezsprintf( '%.3F', $cmykArray['y'] ) . ' ' . ezsprintf( '%.3F', $cmykArray['k'] ) . ' k';
02244 $this->currentColour = $cmykArray;
02245 }
02246 }
02247
02248
02249
02250
02251 function setStrokeColorRGB( $r, $g, $b, $force = 0 )
02252 {
02253 $this->setStrokeColor( eZMath::rgbToCMYK2( $r, $g, $b ), $force );
02254 }
02255
02256
02257
02258
02259
02260
02261
02262 function setStrokeColor( $cmykArray, $force = 0 )
02263 {
02264 if ( $force || !$this->compareCMYK( $cmykArray, $this->currentStrokeColour ) )
02265 {
02266 $this->objects[$this->currentContents]['c'] .= "\n" .
02267 ezsprintf( '%.3F', $cmykArray['c'] ) . ' ' . ezsprintf( '%.3F', $cmykArray['m'] ) . ' ' .
02268 ezsprintf( '%.3F', $cmykArray['y'] ) . ' ' . ezsprintf( '%.3F', $cmykArray['k'] ) . ' K';
02269 $this->currentStrokeColour = $cmykArray;
02270 }
02271 }
02272
02273
02274
02275
02276 function line( $x1, $y1, $x2, $y2 )
02277 {
02278 $this->objects[$this->currentContents]['c'] .= "\n".ezsprintf('%.3F',$x1).' '.ezsprintf('%.3F',$y1).' m '.ezsprintf('%.3F',$x2).' '.ezsprintf('%.3F',$y2).' l S';
02279 }
02280
02281
02282
02283
02284 function curve( $x0, $y0, $x1, $y1, $x2, $y2, $x3, $y3 )
02285 {
02286
02287
02288 $this->objects[$this->currentContents]['c'].="\n".ezsprintf('%.3F',$x0).' '.ezsprintf('%.3F',$y0).' m '.ezsprintf('%.3F',$x1).' '.ezsprintf('%.3F',$y1);
02289 $this->objects[$this->currentContents]['c'].= ' '.ezsprintf('%.3F',$x2).' '.ezsprintf('%.3F',$y2).' '.ezsprintf('%.3F',$x3).' '.ezsprintf('%.3F',$y3).' c S';
02290 }
02291
02292
02293
02294
02295 function partEllipse( $x0, $y0, $astart, $afinish, $r1, $r2 = 0, $angle = 0, $nSeg = 8 )
02296 {
02297 $this->ellipse( $x0, $y0, $r1, $r2, $angle, $nSeg, $astart, $afinish, 0 );
02298 }
02299
02300
02301
02302
02303 function filledEllipse( $x0, $y0, $r1, $r2 = 0, $angle = 0, $nSeg = 8, $astart = 0, $afinish = 360 )
02304 {
02305 return $this->ellipse( $x0, $y0, $r1, $r2 = 0, $angle, $nSeg, $astart, $afinish, 1, 1 );
02306 }
02307
02308
02309
02310
02311
02312
02313
02314
02315
02316
02317
02318 function ellipse( $x0, $y0, $r1, $r2 = 0, $angle = 0, $nSeg = 8, $astart = 0, $afinish = 360, $close = 1, $fill = 0 )
02319 {
02320 if ( $r1 == 0 )
02321 {
02322 return;
02323 }
02324 if ( $r2 == 0 )
02325 {
02326 $r2 = $r1;
02327 }
02328 if ( $nSeg < 2 )
02329 {
02330 $nSeg = 2;
02331 }
02332
02333 $astart = deg2rad( (float)$astart );
02334 $afinish = deg2rad( (float)$afinish );
02335 $totalAngle = $afinish - $astart;
02336
02337 $dt = $totalAngle / $nSeg;
02338 $dtm = $dt / 3;
02339
02340 if ( $angle != 0 )
02341 {
02342 $a = -1*deg2rad((float)$angle);
02343 $tmp = "\n q ";
02344 $tmp .= ezsprintf('%.3F',cos($a)).' '.ezsprintf('%.3F',(-1.0*sin($a))).' '.ezsprintf('%.3F',sin($a)).' '.ezsprintf('%.3F',cos($a)).' ';
02345 $tmp .= ezsprintf('%.3F',$x0).' '.ezsprintf('%.3F',$y0).' cm';
02346 $this->objects[$this->currentContents]['c'].= $tmp;
02347 $x0=0;
02348 $y0=0;
02349 }
02350
02351 $t1 = $astart;
02352 $a0 = $x0 + $r1*cos($t1);
02353 $b0 = $y0 + $r2*sin($t1);
02354 $c0 = -$r1 * sin($t1);
02355 $d0 = $r2 * cos($t1);
02356
02357 $this->objects[$this->currentContents]['c'] .= "\n".ezsprintf('%.3F',$a0).' '.ezsprintf('%.3F',$b0).' m ';
02358 for ($i=1;$i<=$nSeg;$i++)
02359 {
02360
02361 $t1 = $i*$dt + $astart;
02362 $a1 = $x0 + $r1*cos($t1);
02363 $b1 = $y0 + $r2*sin($t1);
02364 $c1 = -$r1 * sin($t1);
02365 $d1 = $r2 * cos($t1);
02366 $this->objects[$this->currentContents]['c'].= "\n".ezsprintf('%.3F',($a0+$c0*$dtm)).' '.ezsprintf('%.3F',($b0+$d0*$dtm));
02367 $this->objects[$this->currentContents]['c'].= ' '.ezsprintf('%.3F',($a1-$c1*$dtm)).' '.ezsprintf('%.3F',($b1-$d1*$dtm)).' '.ezsprintf('%.3F',$a1).' '.ezsprintf('%.3F',$b1).' c';
02368 $a0 = $a1;
02369 $b0 = $b1;
02370 $c0 = $c1;
02371 $d0 = $d1;
02372 }
02373 if ( $fill )
02374 {
02375 $this->objects[$this->currentContents]['c'].= ' f';
02376 }
02377 else
02378 {
02379 if ($close)
02380 {
02381 $this->objects[$this->currentContents]['c'].= ' s';
02382 }
02383 else
02384 {
02385 $this->objects[$this->currentContents]['c'].= ' S';
02386 }
02387 }
02388 if ( $angle != 0 )
02389 {
02390 $this->objects[$this->currentContents]['c'].= ' Q';
02391 }
02392 }
02393
02394
02395
02396
02397
02398
02399
02400
02401
02402
02403
02404
02405
02406
02407 function setLineStyle( $width = 1, $cap = '', $join = '', $dash = '', $phase = 0 )
02408 {
02409
02410
02411 $string = '';
02412 if ( $width > 0 )
02413 {
02414 $string.= $width.' w';
02415 }
02416 $ca = array( 'butt' => 0, 'round' => 1, 'square' => 2 );
02417 if ( isset( $ca[$cap] ) )
02418 {
02419 $string.= ' '.$ca[$cap].' J';
02420 }
02421 $ja = array('miter'=>0,'round'=>1,'bevel'=>2);
02422 if ( isset( $ja[$join] ) )
02423 {
02424 $string.= ' '.$ja[$join].' j';
02425 }
02426 if ( is_array( $dash ) )
02427 {
02428 $string.= ' [';
02429 foreach ( $dash as $len )
02430 {
02431 $string.=' '.$len;
02432 }
02433 $string.= ' ] '.$phase.' d';
02434 }
02435 $this->currentLineStyle = $string;
02436 $this->objects[$this->currentContents]['c'].= "\n".$string;
02437 }
02438
02439
02440
02441
02442 function polygon( $p, $np, $f = 0 )
02443 {
02444 $this->objects[$this->currentContents]['c'].= "\n";
02445 $this->objects[$this->currentContents]['c'].= ezsprintf('%.3F',$p[0]).' '.ezsprintf('%.3F',$p[1]).' m ';
02446 for ( $i = 2; $i < $np*2; $i = $i + 2 )
02447 {
02448 $this->objects[$this->currentContents]['c'].= ezsprintf('%.3F',$p[$i]).' '.ezsprintf('%.3F',$p[$i+1]).' l ';
02449 }
02450 if ( $f == 1 )
02451 {
02452 $this->objects[$this->currentContents]['c'].= ' f';
02453 }
02454 else
02455 {
02456 $this->objects[$this->currentContents]['c'].= ' S';
02457 }
02458 }
02459
02460
02461
02462
02463
02464
02465
02466
02467
02468
02469
02470
02471
02472 function shadedRectangle( $x1, $y1, $width, $height, $options )
02473 {
02474 $this->numObj++;
02475 $shadingLabel = $this->o_shading( $this->numObj, 'new', $options );
02476
02477 $this->saveState();
02478
02479 $this->objects[$this->currentContents]['c'].="\n".ezsprintf('%.3F',$x1).' '.ezsprintf('%.3F',$y1).' '.ezsprintf('%.3F',$width).' '.ezsprintf('%.3F',$height).' re';
02480
02481 $this->objects[$this->currentContents]['c'].="\nW n";
02482
02483 $this->objects[$this->currentContents]['c'].="\n/".$shadingLabel.' sh';
02484
02485 $this->restoreState();
02486 }
02487
02488
02489
02490
02491
02492 function filledRectangle( $x1, $y1, $width, $height )
02493 {
02494 $this->objects[$this->currentContents]['c'].="\n".ezsprintf('%.3F',$x1).' '.ezsprintf('%.3F',$y1).' '.ezsprintf('%.3F',$width).' '.ezsprintf('%.3F',$height).' re f';
02495 }
02496
02497
02498
02499
02500
02501 function rectangle( $x1, $y1, $width, $height )
02502 {
02503 $this->objects[$this->currentContents]['c'].="\n".ezsprintf('%.3F',$x1).' '.ezsprintf('%.3F',$y1).' '.ezsprintf('%.3F',$width).' '.ezsprintf('%.3F',$height).' re S';
02504 }
02505
02506
02507
02508
02509
02510 function newPage( $insert = 0, $id = 0, $pos = 'after' )
02511 {
02512
02513
02514
02515 if ( $this->nStateStack )
02516 {
02517 for ( $i = $this->nStateStack; $i >= 1; $i-- )
02518 {
02519 $this->restoreState( $i );
02520 }
02521 }
02522
02523 $this->numObj++;
02524 if ( $insert )
02525 {
02526
02527
02528 $rid = $this->objects[$id]['onPage'];
02529 $opt = array( 'rid' => $rid, 'pos' => $pos );
02530 $this->o_page( $this->numObj, 'new', $opt);
02531 }
02532 else
02533 {
02534 $this->o_page( $this->numObj, 'new' );
02535 }
02536
02537 if ( $this->nStateStack )
02538 {
02539 for ( $i = 1; $i <= $this->nStateStack; $i++)
02540 {
02541 $this->saveState($i);
02542 }
02543 }
02544
02545 if ( $this->currentColour['c'] >= 0 )
02546 {
02547 $this->setColor( $this->currentColour, 1 );
02548 }
02549 if ( $this->currentStrokeColour['c'] >= 0 )
02550 {
02551 $this->setStrokeColor( $this->currentStrokeColour, 1 );
02552 }
02553
02554
02555 if ( strlen( $this->currentLineStyle ) )
02556 {
02557 $this->objects[$this->currentContents]['c'].= "\n".$this->currentLineStyle;
02558 }
02559
02560
02561 return $this->currentContents;
02562 }
02563
02564
02565
02566
02567
02568 function stream( $options = '' )
02569 {
02570
02571
02572
02573
02574
02575
02576
02577
02578 if ( !is_array( $options ) )
02579 {
02580 $options = array();
02581 }
02582 if ( isset( $options['compress'] ) && $options['compress'] == 0 )
02583 {
02584 $tmp = $this->output( 1 );
02585 }
02586 else
02587 {
02588 $tmp = $this->output();
02589 }
02590 $tmp = ltrim( $tmp );
02591
02592 ob_clean();
02593
02594 header( 'Pragma: ' );
02595 header( 'Cache-Control: ' );
02596
02597 header( "Expires: ". gmdate( 'D, d M Y H:i:s', time() + 10 ) . 'GMT' );
02598 header( 'X-Powered-By: eZ publish' );
02599
02600 header( 'Content-Length: '.strlen( $tmp ) );
02601 header( 'Content-Type: application/pdf' );
02602 header( 'Content-Transfer-Encoding: binary' );
02603 header( 'Accept-Ranges: bytes' );
02604
02605 ob_end_clean();
02606
02607 echo $tmp;
02608
02609 include_once( 'lib/ezutils/classes/ezexecution.php' );
02610 eZExecution::cleanExit();
02611 }
02612
02613
02614
02615
02616 function getFontHeight( $size = false )
02617 {
02618 if ( !$this->numFonts )
02619 {
02620 $this->selectFont( './fonts/Helvetica' );
02621 }
02622
02623 $h = $this->fonts[$this->currentFont]['FontBBox'][3]-$this->fonts[$this->currentFont]['FontBBox'][1];
02624 if ( $size === false )
02625 {
02626 $size = $this->fontSize();
02627 }
02628 return $this->ez['lineSpace'] * $size * $h / 1000;
02629 }
02630
02631
02632
02633
02634
02635
02636 function getFontDecender( $size = false )
02637 {
02638
02639 if ( !$this->numFonts )
02640 {
02641 $this->selectFont( './fonts/Helvetica' );
02642 }
02643 $h = $this->fonts[$this->currentFont]['FontBBox'][1];
02644 if ( $size === false )
02645 {
02646 $size = $this->fontSize();
02647 }
02648 return $size*$h/1000;
02649 }
02650
02651
02652
02653
02654
02655
02656
02657 function filterText( $text )
02658 {
02659 $text = str_replace('\\','\\\\',$text);
02660 $text = str_replace('(','\(',$text);
02661 $text = str_replace(')','\)',$text);
02662 $text = str_replace('<','<',$text);
02663 $text = str_replace('>','>',$text);
02664 $text = str_replace(''','\'',$text);
02665 $text = str_replace('"','"',$text);
02666 $text = str_replace('&','&',$text);
02667
02668 return $text;
02669 }
02670
02671
02672
02673
02674
02675
02676
02677 function PRVTgetTextPosition( $x, $y, $angle, $size, $wa, $text )
02678 {
02679 $tmp = false;
02680
02681
02682 $w = $this->getTextWidth($size,$text);
02683
02684 $words = explode(' ',$text);
02685 $nspaces=count($words)-1;
02686 $w += $wa*$nspaces;
02687 $a = deg2rad((float)$angle);
02688 if ( $tmp )
02689 {
02690 return array($this->xOffset(),-sin($a)*$w+$y);
02691 }
02692 return array(cos($a)*$w+$x,-sin($a)*$w+$y);
02693 }
02694
02695
02696
02697
02698
02699
02700 function PRVTcheckTextDirective( &$text, $i, &$f, $final = 0 )
02701 {
02702 $x = 0;
02703 $y = 0;
02704 return $this->PRVTcheckTextDirective1( $text, $i, $f, $final, $x, $y );
02705 }
02706
02707
02708
02709
02710
02711
02712
02713
02714
02715
02716 function PRVTcheckTextDirective1( &$text, $i, &$f, $final, &$x, &$y, $size = 0, $angle = 0, $wordSpaceAdjust = 0 )
02717 {
02718 $newTextState = $this->currentTextState;
02719 $noClose = 0;
02720 $directive = 0;
02721 $j = $i;
02722 if ( $text[$j] == '<' )
02723 {
02724 $j++;
02725 switch ( $text[$j] )
02726 {
02727 case '/':
02728 $j++;
02729 if (strlen($text) <= $j)
02730 {
02731 return $directive;
02732 }
02733 switch ( $text[$j] )
02734 {
02735 case 'b':
02736 case 'i':
02737 ++$j;
02738 if ( $text[$j] == '>' )
02739 {
02740 if ( $final === true )
02741 $this->currentTextState = substr( $this->currentTextState, 0, $p).substr( $this->currentTextState, $p+1);
02742 $directive = $j-$i+1;
02743 }
02744 break;
02745
02746 case 'c':
02747 {
02748
02749 $j++;
02750 $k = strpos( $text, '>', $j );
02751 if ( $k !== false && $text[$j] == ':' )
02752 {
02753
02754 $directive = $k-$i+1;
02755 $f = 0;
02756
02757 $tmp = substr( $text, $j+1, $k-$j-1 );
02758 $b1 = strpos( $tmp, ':' );
02759 if ( $b1 !== false )
02760 {
02761 $func = substr( $tmp, 0, $b1 );
02762 $parm = substr( $tmp, $b1+1 );
02763 }
02764 else
02765 {
02766 $func = $tmp;
02767 $parm = '';
02768 }
02769 if ( !isset( $func ) || !strlen( trim( $func ) ) )
02770 {
02771 $directive = 0;
02772 }
02773 else
02774 {
02775
02776 if ( $final === 1 )
02777 {
02778
02779
02780 if ( $x < $this->leftMargin() )
02781 {
02782 $x = $this->leftMargin();
02783 }
02784 $startInfo = $this->callback[$this->nCallback];
02785
02786 if ( $x < $this->xOffset() )
02787 {
02788 $x = $this->xOffset();
02789 }
02790 $tmp = $this->PRVTgetTextPosition( $x, $y, $angle, $size, $wordSpaceAdjust, substr( $text, $startInfo['i'], $i-$startInfo['i'] ) );
02791 $info = array( 'x' => $tmp[0],'y' => $tmp[1], 'angle' => $angle, 'status' => 'end', 'p' => $parm, 'nCallback' => $this->nCallback );
02792
02793 $x = $tmp[0];
02794 $y = $tmp[1];
02795 $ret = $this->$func( $info );
02796 if ( is_array( $ret ) )
02797 {
02798
02799 foreach ( $ret as $rk => $rv )
02800 {
02801 switch ( $rk )
02802 {
02803 case 'x':
02804 case 'y':
02805 $$rk = $rv;
02806 break;
02807 }
02808 }
02809 }
02810
02811
02812 $this->nCallback--;
02813 if ( $this->nCallback < 0 )
02814 {
02815 $this->nCallBack = 0;
02816 }
02817 }
02818 }
02819 }
02820 } break;
02821 }
02822 break;
02823
02824 case 'b':
02825 case 'i':
02826 ++$j;
02827
02828 if ( $text[$j] == '>' )
02829 {
02830 if ( $final === true )
02831 $this->currentTextState .= $text[$j-1];
02832 $directive = $j-$i+1;
02833 }
02834 break;
02835
02836 case 'C':
02837 $noClose = 1;
02838 case 'c':
02839
02840 $j++;
02841 $k = strpos( $text, '>', $j );
02842 if ( $k !== false && $text[$j] == ':' )
02843 {
02844
02845 $directive = $k-$i+1;
02846 $f=0;
02847
02848 $tmp = substr( $text, $j+1, $k-$j-1 );
02849 $b1 = strpos( $tmp, ':' );
02850 if ( $b1 !== false )
02851 {
02852 $func = substr( $tmp, 0, $b1 );
02853 $parm = substr( $tmp, $b1+1 );
02854 }
02855 else
02856 {
02857 $func = $tmp;
02858 $parm = '';
02859 }
02860 if ( !isset( $func ) || !strlen( trim( $func ) ) )
02861 {
02862 $directive=0;
02863 }
02864 else
02865 {
02866
02867 if ($final === 1)
02868 {
02869
02870
02871
02872 $tmp = $this->PRVTgetTextPosition($x,$y,$angle,$size,$wordSpaceAdjust,substr($text,0,$i));
02873 if ( $tmp[0] < $this->leftMargin() )
02874 {
02875 $tmp[0] = $this->leftMargin();
02876 }
02877 if ( $tmp[0] < $this->xOffset() )
02878 {
02879 $tmp[0] = $this->xOffset();
02880 }
02881 $info = array( 'x' => $tmp[0],
02882 'y' => $tmp[1],
02883 'angle' => $angle,
02884 'status' => 'start',
02885 'p' => $parm,
02886 'f' => $func,
02887 'height' => $this->getFontHeight( $size ),
02888 'decender' => $this->getFontDecender( $size ),
02889 'i' => $i );
02890
02891 $x = $tmp[0];
02892 $y = $tmp[1];
02893 if (!isset($noClose) || !$noClose)
02894 {
02895
02896 $this->nCallback++;
02897 $info['nCallback']=$this->nCallback;
02898 $this->callback[$this->nCallback]=$info;
02899 }
02900 $ret = $this->$func( $info );
02901 if ( is_array( $ret ) )
02902 {
02903
02904 foreach ( $ret as $rk => $rv )
02905 {
02906 switch ( $rk )
02907 {
02908 case 'x':
02909 case 'y':
02910 $$rk=$rv;
02911 break;
02912 }
02913 }
02914 }
02915 }
02916 }
02917 }
02918 break;
02919 }
02920 }
02921 return array( 'directive' => $directive,
02922 'y' => (float)$y,
02923 'noClose' => $noClose,
02924 'run_final' => ( $f == 0 ) );
02925 }
02926
02927
02928
02929
02930
02931
02932 function addText( $x, $y, $size, $text, $angle = 0, $wordSpaceAdjust = 0 )
02933 {
02934 $returnArray = array( 'height' => -1 );
02935
02936 if (!$this->numFonts)
02937 {
02938 $this->selectFont('./fonts/Helvetica');
02939 }
02940
02941
02942 if ($this->nCallback>0)
02943 {
02944 for ( $i = $this->nCallback; $i > 0; $i-- )
02945 {
02946
02947 $info = array( 'x' => $x, 'y' => $y,
02948 'angle' => $angle,
02949 'status' => 'sol',
02950 'p' => $this->callback[$i]['p'],
02951 'nCallback' => $this->callback[$i]['nCallback'],
02952 'height' => $this->callback[$i]['height'],
02953 'decender' => $this->callback[$i]['decender'] );
02954 $func = $this->callback[$i]['f'];
02955 $this->$func( $info );
02956 }
02957 }
02958 if ( $angle == 0 )
02959 {
02960 $this->objects[$this->currentContents]['c'] .= "\n".'BT '.ezsprintf('%.3F',$x).' '.ezsprintf('%.3F',$y).' Td';
02961 }
02962 else
02963 {
02964 $a = deg2rad((float)$angle);
02965 $tmp = "\n".'BT ';
02966 $tmp .= ezsprintf('%.3F',cos($a)).' '.ezsprintf('%.3F',(-1.0*sin($a))).' '.ezsprintf('%.3F',sin($a)).' '.ezsprintf('%.3F',cos($a)).' ';
02967 $tmp .= ezsprintf('%.3F',$x).' '.ezsprintf('%.3F',$y).' Tm';
02968 $this->objects[$this->currentContents]['c'] .= $tmp;
02969 }
02970 if ($wordSpaceAdjust!=0 || $wordSpaceAdjust != $this->wordSpaceAdjust)
02971 {
02972 $this->wordSpaceAdjust=$wordSpaceAdjust;
02973 $this->objects[$this->currentContents]['c'].=' '.ezsprintf('%.3F',$wordSpaceAdjust).' Tw';
02974 }
02975 $len = strlen($text);
02976 $start = 0;
02977 for ( $i = 0; $i < $len; $i++ )
02978 {
02979 $f = 1;
02980 $directiveArray = $this->PRVTcheckTextDirective( $text, $i, $f, true );
02981 $directive = $directiveArray['directive'];
02982 if ($directive)
02983 {
02984
02985 if ( $i > $start )
02986 {
02987 $part = substr($text,$start,$i-$start);
02988 $this->objects[$this->currentContents]['c'].=' /F'.$this->currentFontNum.' '.ezsprintf('%.1F',$size).' Tf ';
02989 $this->objects[$this->currentContents]['c'].=' ('.$this->filterText($part).') Tj';
02990 }
02991 if ( !$directiveArray['run_final'] )
02992 {
02993
02994 $this->setCurrentFont();
02995 }
02996 else
02997 {
02998 $this->objects[$this->currentContents]['c'] .= ' ET';
02999 $f = 1;
03000 $xp = $x;
03001 $yp = $y;
03002 $directiveArray = $this->PRVTcheckTextDirective1( $text, $i, $f, 1, $xp, $yp, $size, $angle, $wordSpaceAdjust );
03003 if ( $directiveArray['y'] != 0 )
03004 {
03005 $returnArray['height'] = $y - $directiveArray['y'];
03006 }
03007
03008 $directive = $directiveArray['directive'];
03009
03010
03011 if ( $angle == 0 )
03012 {
03013 $this->objects[$this->currentContents]['c'] .= "\n".'BT '.ezsprintf('%.3F',$xp).' '.ezsprintf('%.3F',$yp).' Td';
03014 }
03015 else
03016 {
03017 $a = deg2rad( (float)$angle );
03018 $tmp = "\n".'BT ';
03019 $tmp .= ezsprintf('%.3F',cos($a)).' '.ezsprintf('%.3F',(-1.0*sin($a))).' '.ezsprintf('%.3F',sin($a)).' '.ezsprintf('%.3F',cos($a)).' ';
03020 $tmp .= ezsprintf('%.3F',$xp).' '.ezsprintf('%.3F',$yp).' Tm';
03021 $this->objects[$this->currentContents]['c'] .= $tmp;
03022 }
03023 if ($wordSpaceAdjust!=0 || $wordSpaceAdjust != $this->wordSpaceAdjust)
03024 {
03025 $this->wordSpaceAdjust=$wordSpaceAdjust;
03026 $this->objects[$this->currentContents]['c'] .= ' '.ezsprintf('%.3F',$wordSpaceAdjust).' Tw';
03027 }
03028 }
03029
03030 $i = $i + $directive - 1;
03031 $start = $i + 1;
03032 }
03033
03034 }
03035 if ( $start < $len )
03036 {
03037 $part = substr($text,$start);
03038 $this->objects[$this->currentContents]['c'].=' /F'.$this->currentFontNum.' '.ezsprintf('%.1F',$size).' Tf ';
03039 $this->objects[$this->currentContents]['c'].=' ('.$this->filterText($part).') Tj';
03040 }
03041 $this->objects[$this->currentContents]['c'].=' ET';
03042
03043
03044 if ( $this->nCallback > 0 )
03045 {
03046 for ( $i = $this->nCallback; $i > 0; $i-- )
03047 {
03048
03049 $tmp = $this->PRVTgetTextPosition( $x, $y, $angle, $size, $wordSpaceAdjust, $text );
03050 $info = array('x' => $tmp[0], 'y' => $tmp[1],
03051 'angle' => $angle,
03052 'status' => 'eol',
03053 'p' => $this->callback[$i]['p'],
03054 'nCallback' => $this->callback[$i]['nCallback'],
03055 'height' => $this->callback[$i]['height'],
03056 'decender' => $this->callback[$i]['decender'] );
03057 $func = $this->callback[$i]['f'];
03058 $this->$func( $info );
03059 }
03060 }
03061
03062 return $returnArray;
03063 }
03064
03065
03066
03067
03068
03069 function getTextWidth( $size, $text )
03070 {
03071
03072
03073
03074 $this->pushTextState( $this->currentTextState );
03075
03076 if (!$this->numFonts)
03077 {
03078 $this->selectFont('./fonts/Helvetica');
03079 }
03080
03081
03082 $text = "$text";
03083
03084
03085 $w = 0;
03086 $len = strlen( $text );
03087 $cf = $this->currentFont;
03088 for ( $i = 0; $i < $len; $i++ )
03089 {
03090 $f = 1;
03091 $directiveArray = $this->PRVTcheckTextDirective( $text, $i, $f );
03092 $directive = $directiveArray['directive'];
03093 if ( $directive )
03094 {
03095 if ($f)
03096 {
03097 $this->setCurrentFont();
03098 $cf = $this->currentFont;
03099 }
03100 $i = $i + $directive-1;
03101 }
03102 else
03103 {
03104 $char = ord( $text[$i] );
03105 if ( isset($this->fonts[$cf]['differences'][$char] ) )
03106 {
03107
03108 $name = $this->fonts[$cf]['differences'][$char];
03109 if ( isset($this->fonts[$cf]['C'][$name]['WX'] ) )
03110 {
03111 $w += $this->fonts[$cf]['C'][$name]['WX'];
03112 }
03113 }
03114 else if ( isset($this->fonts[$cf]['C'][$char]['WX'] ) )
03115 {
03116 $w += $this->fonts[$cf]['C'][$char]['WX'];
03117 }
03118 else
03119 {
03120 $w += 700;
03121 }
03122 }
03123 }
03124
03125 $this->popTextState();
03126 $this->setCurrentFont();
03127
03128 return $w*$size/1000;
03129 }
03130
03131
03132
03133
03134
03135
03136 function PRVTadjustWrapText( $text, $actual, $width, &$x, &$adjust, $justification )
03137 {
03138 switch ( $justification )
03139 {
03140 case 'left':
03141 return;
03142 break;
03143 case 'right':
03144 $x += $width - $actual;
03145 break;
03146 case 'center':
03147 case 'centre':
03148 $x += ($width - $actual) / 2;
03149 break;
03150 case 'full':
03151
03152 $words = explode( ' ', $text );
03153 $nspaces = count($words) - 1;
03154 if ( $nspaces > 0 )
03155 {
03156 $adjust = ($width-$actual) / $nspaces;
03157 }
03158 else
03159 {
03160 $adjust = 0;
03161 }
03162 break;
03163 }
03164 }
03165
03166
03167
03168
03169
03170
03171
03172
03173
03174
03175
03176 function addTextWrap( $x, $y, $width, $size, $text, $justification = 'left', $angle = 0, $test = 0 )
03177 {
03178
03179
03180
03181
03182
03183
03184
03185 $store_currentTextState = $this->currentTextState;
03186 $returnArray = array ( 'text' => '',
03187 'width' => 0,
03188 'height' => 0 );
03189 if ( $text != '' )
03190 {
03191 $returnArray['height'] = $this->getFontHeight( $size );
03192 }
03193
03194 if ( !$this->numFonts )
03195 {
03196 $this->selectFont('./fonts/Helvetica');
03197 }
03198 if ( $width <= 0 )
03199 {
03200
03201 return $returnArray;
03202 }
03203 $w = 0;
03204 $break = 0;
03205 $breakWidth = 0;
03206 $len = strlen( $text );
03207 $cf = $this->currentFont;
03208 $tw = $width/$size*1000;
03209 $directive = 0;
03210 for ( $i = 0; $i < $len; $i++ )
03211 {
03212 $f = 1;
03213 $directiveArray = $this->PRVTcheckTextDirective( $text, $i, $f );
03214 $deltaDirective = $directiveArray['directive'];
03215 $directive += $deltaDirective;
03216 if ( $directiveArray['y'] != 0 )
03217 {
03218 $y -= $directiveArray['y'];
03219 $returnArray['height'] = $directiveArray['y'];
03220 }
03221 if ($deltaDirective)
03222 {
03223 if ($f)
03224 {
03225 $this->setCurrentFont();
03226 $cf = $this->currentFont;
03227 }
03228 $i=$i+$deltaDirective-1;
03229 }
03230 else
03231 {
03232 $cOrd = ord($text[$i]);
03233 if ( isset( $this->fonts[$cf]['differences'][$cOrd] ) )
03234 {
03235
03236 $cOrd2 = $this->fonts[$cf]['differences'][$cOrd];
03237 }
03238 else
03239 {
03240 $cOrd2 = $cOrd;
03241 }
03242
03243 if ( isset( $this->fonts[$cf]['C'][$cOrd2]['WX'] ) )
03244 {
03245 $w += $this->fonts[$cf]['C'][$cOrd2]['WX'];
03246 }
03247 else
03248 {
03249 $w += 700;
03250 }
03251
03252 if ( $w > $tw )
03253 {
03254
03255 if ( $break > 0 )
03256 {
03257
03258 if ($text[$break] == ' ')
03259 {
03260 $tmp = substr( $text, 0, $break );
03261 }
03262 else
03263 {
03264 $tmp = substr( $text, 0, $break + 1 );
03265 }
03266 $adjust = 0;
03267 $this->PRVTadjustWrapText( $tmp, $breakWidth, $width, $x, $adjust, $justification );
03268
03269
03270 $this->currentTextState = $store_currentTextState;
03271 $this->setCurrentFont();
03272 if ( !$test )
03273 {
03274 $addTextArray = $this->addText( $x, $y, $size, $tmp, $angle, $adjust );
03275 if ( $addTextArray['height'] != -1 &&
03276 $returnArray['height'] < $addTextArray['height'] )
03277 {
03278 $returnArray['height'] = $addTextArray['height'];
03279 }
03280 }
03281 $returnArray['text'] = substr( $text, $break + 1 );
03282 return $returnArray;
03283 }
03284 else
03285 {
03286
03287 $tmp = substr( $text, 0, $i );
03288 $adjust = 0;
03289 $ctmp = ord( $text[$i] );
03290 if ( isset($this->fonts[$cf]['differences'][$ctmp] ) )
03291 {
03292 $ctmp = $this->fonts[$cf]['differences'][$ctmp];
03293 }
03294 $tmpw = ( $w - $this->fonts[$cf]['C'][$ctmp]['WX'] ) * $size/1000;
03295 $this->PRVTadjustWrapText( $tmp, $tmpw, $width, $x, $adjust, $justification );
03296
03297 $this->currentTextState = $store_currentTextState;
03298 $this->setCurrentFont();
03299 if ( !$test )
03300 {
03301 $addTextArray = $this->addText( $x, $y, $size, $tmp, $angle, $adjust );
03302 if ( $addTextArray['height'] != -1 &&
03303 $returnArray['height'] < $addTextArray['height'] )
03304 {
03305 $returnArray['height'] = $addTextArray['height'];
03306 }
03307 }
03308 $returnArray['text'] = substr( $text, $i );
03309 return $returnArray;
03310 }
03311 }
03312
03313 if ( $text[$i] == '-' )
03314 {
03315 $break = $i;
03316 $breakWidth = $w*$size/1000;
03317 }
03318 if ( $text[$i] == ' ' )
03319 {
03320 $break = $i;
03321 $ctmp = ord( $text[$i] );
03322 if ( isset($this->fonts[$cf]['differences'][$ctmp] ) )
03323 {
03324 $ctmp = $this->fonts[$cf]['differences'][$ctmp];
03325 }
03326 $breakWidth = ( $w - $this->fonts[$cf]['C'][$ctmp]['WX'] ) * $size/1000;
03327 }
03328 }
03329 }
03330
03331 if ( $justification == 'full' )
03332 {
03333 $justification = 'left';
03334 }
03335 $adjust = 0;
03336 $tmpw = $w * $size/1000;
03337 $this->PRVTadjustWrapText( $text, $tmpw, $width, $x, $adjust, $justification );
03338
03339 $this->currentTextState = $store_currentTextState;
03340 $this->setCurrentFont();
03341 if ( !$test )
03342 {
03343 $addTextArray = $this->addText( $x, $y, $size, $text, $angle, $adjust, $angle );
03344 if ( isset( $directive ) && $directive == $len )
03345 {
03346 return array( 'only_directive' => true );
03347 }
03348
03349 if ( $addTextArray['height'] != -1 &&
03350 $returnArray['height'] < $addTextArray['height'] )
03351 {
03352 $returnArray['height'] = $addTextArray['height'];
03353 }
03354 }
03355 $returnArray['width'] = $tmpw;
03356 return $returnArray;
03357 }
03358
03359
03360
03361
03362
03363
03364
03365 function saveState( $pageEnd = 0 )
03366 {
03367 if ( $pageEnd )
03368 {
03369
03370
03371
03372 $opt = $this->stateStack[$pageEnd];
03373 $this->setColor($opt['col'],1);
03374 $this->setStrokeColor($opt['str'],1);
03375 $this->objects[$this->currentContents]['c'].="\n".$opt['lin'];
03376
03377 }
03378 else
03379 {
03380 $this->nStateStack++;
03381 $this->stateStack[$this->nStateStack]=array( 'col' => $this->currentColour,
03382 'str' => $this->currentStrokeColour,
03383 'lin' => $this->currentLineStyle );
03384 }
03385 $this->objects[$this->currentContents]['c'] .= "\nq";
03386 }
03387
03388
03389
03390
03391 function restoreState( $pageEnd = 0 )
03392 {
03393 if ( !$pageEnd )
03394 {
03395 $n = $this->nStateStack;
03396 $this->currentColour = $this->stateStack[$n]['col'];
03397 $this->currentStrokeColour = $this->stateStack[$n]['str'];
03398 $this->objects[$this->currentContents]['c'] .= "\n".$this->stateStack[$n]['lin'];
03399 $this->currentLineStyle = $this->stateStack[$n]['lin'];
03400 unset( $this->stateStack[$n] );
03401 $this->nStateStack--;
03402 }
03403 $this->objects[$this->currentContents]['c'] .= "\nQ";
03404 }
03405
03406
03407
03408
03409
03410
03411
03412 function openObject()
03413 {
03414 $this->nStack++;
03415 $this->stack[$this->nStack] = array( 'c' => $this->currentContents,
03416 'p' => $this->currentPage );
03417
03418 $this->numObj++;
03419 $this->o_contents( $this->numObj, 'new' );
03420 $this->currentContents = $this->numObj;
03421 $this->looseObjects[$this->numObj] = 1;
03422
03423 return $this->numObj;
03424 }
03425
03426
03427
03428
03429 function reopenObject( $id )
03430 {
03431 $this->nStack++;
03432 $this->stack[$this->nStack] = array( 'c' => $this->currentContents,
03433 'p' => $this->currentPage );
03434 $this->currentContents=$id;
03435
03436 if ( isset( $this->objects[$id]['onPage'] ) )
03437 {
03438 $this->currentPage = $this->objects[$id]['onPage'];
03439 }
03440 }
03441
03442
03443
03444
03445 function closeObject()
03446 {
03447
03448
03449 if ( $this->nStack > 0 )
03450 {
03451 $this->currentContents=$this->stack[$this->nStack]['c'];
03452 $this->currentPage=$this->stack[$this->nStack]['p'];
03453 $this->nStack--;
03454
03455
03456 }
03457 }
03458
03459
03460
03461
03462 function stopObject( $id )
03463 {
03464
03465
03466 if ( isset( $this->addLooseObjects[$id] ) )
03467 {
03468 $this->addLooseObjects[$id] = '';
03469 }
03470 }
03471
03472
03473
03474
03475 function addObject( $id, $options = 'add' )
03476 {
03477
03478 if ( isset( $this->looseObjects[$id] ) && $this->currentContents != $id )
03479 {
03480
03481 switch ( $options )
03482 {
03483 case 'all':
03484
03485
03486 $this->addLooseObjects[$id] = 'all';
03487 case 'add':
03488 if ( isset( $this->objects[$this->currentContents]['onPage'] ) )
03489 {
03490
03491
03492 $this->o_page( $this->objects[$this->currentContents]['onPage'], 'content', $id );
03493 }
03494 break;
03495 case 'even':
03496 $this->addLooseObjects[$id] = 'even';
03497 $pageObjectId = $this->objects[$this->currentContents]['onPage'];
03498 if ( $this->objects[$pageObjectId]['info']['pageNum'] % 2 == 0 )
03499 {
03500 $this->addObject( $id );
03501 }
03502 break;
03503 case 'odd':
03504 $this->addLooseObjects[$id] = 'odd';
03505 $pageObjectId = $this->objects[$this->currentContents]['onPage'];
03506 if ( $this->objects[$pageObjectId]['info']['pageNum'] % 2 == 1 )
03507 {
03508 $this->addObject( $id );
03509 }
03510 break;
03511 case 'next':
03512 $this->addLooseObjects[$id] = 'all';
03513 break;
03514 case 'nexteven':
03515 $this->addLooseObjects[$id] = 'even';
03516 break;
03517 case 'nextodd':
03518 $this->addLooseObjects[$id] = 'odd';
03519 break;
03520 }
03521 }
03522 }
03523
03524
03525
03526
03527 function addInfo( $label, $value = 0 )
03528 {
03529
03530
03531
03532
03533 if ( is_array( $label ) )
03534 {
03535 foreach ( $label as $l => $v )
03536 {
03537 $this->o_info( $this->infoObject, $l, $v );
03538 }
03539 }
03540 else
03541 {
03542 $this->o_info( $this->infoObject, $label, $value );
03543 }
03544 }
03545
03546
03547
03548
03549 function setPreferences( $label, $value = 0 )
03550 {
03551
03552 if ( is_array( $label ) )
03553 {
03554 foreach ( $label as $l => $v )
03555 {
03556 $this->o_catalog( $this->catalogId, 'viewerPreferences', array( $l => $v ) );
03557 }
03558 }
03559 else
03560 {
03561 $this->o_catalog( $this->catalogId, 'viewerPreferences', array( $label => $value ) );
03562 }
03563 }
03564
03565
03566
03567
03568
03569
03570 function PRVT_getBytes( &$data, $pos, $num )
03571 {
03572
03573 $ret = 0;
03574 for ( $i = 0; $i < $num; $i++ )
03575 {
03576 $ret = $ret * 256;
03577 $ret+= ord( $data[$pos+$i] );
03578 }
03579 return $ret;
03580 }
03581
03582
03583
03584
03585
03586
03587
03588 function addPngFromFile( $file, $x, $y, $w = 0, $h = 0 )
03589 {
03590
03591 $error = 0;
03592 $tmp = get_magic_quotes_runtime();
03593 set_magic_quotes_runtime(0);
03594 $fp = @fopen( $file, 'rb' );
03595 if ( $fp )
03596 {
03597 $data = '';
03598 while ( !feof( $fp ) )
03599 {
03600 $data .= fread( $fp, 1024 );
03601 }
03602 fclose( $fp );
03603 }
03604 else
03605 {
03606 $error = 1;
03607 $errormsg = 'trouble opening file: '.$file;
03608 }
03609 set_magic_quotes_runtime( $tmp );
03610
03611 if ( !$error )
03612 {
03613 $header = chr(137).chr(80).chr(78).chr(71).chr(13).chr(10).chr(26).chr(10);
03614 if ( substr( $data, 0, 8 ) != $header )
03615 {
03616 $error = 1;
03617 $errormsg = 'this file does not have a valid header';
03618 }
03619 }
03620
03621 if ( !$error )
03622 {
03623
03624 $p = 8;
03625 $len = strlen($data);
03626
03627 $haveHeader = 0;
03628 $info = array();
03629 $idata = '';
03630 $pdata = '';
03631 while ( $p < $len )
03632 {
03633 $chunkLen = $this->PRVT_getBytes($data,$p,4);
03634 $chunkType = substr($data,$p+4,4);
03635
03636
03637 switch ( $chunkType )
03638 {
03639 case 'IHDR':
03640
03641 $info['width'] = $this->PRVT_getBytes( $data, $p+8, 4 );
03642 $info['height'] = $this->PRVT_getBytes( $data, $p+12, 4);
03643 $info['bitDepth'] = ord( $data[$p+16] );
03644 $info['colorType'] = ord( $data[$p+17] );
03645 $info['compressionMethod'] = ord( $data[$p+18] );
03646 $info['filterMethod'] = ord( $data[$p+19] );
03647 $info['interlaceMethod'] = ord( $data[$p+20] );
03648
03649 $haveHeader = 1;
03650 if ( $info['compressionMethod'] != 0 )
03651 {
03652 $error = 1;
03653 $errormsg = 'unsupported compression method';
03654 }
03655 if ( $info['filterMethod'] != 0 )
03656 {
03657 $error = 1;
03658 $errormsg = 'unsupported filter method';
03659 }
03660 break;
03661
03662 case 'PLTE':
03663 $pdata .= substr( $data, $p + 8, $chunkLen );
03664 break;
03665 case 'IDAT':
03666 $idata .= substr( $data, $p + 8, $chunkLen );
03667 break;
03668 case 'tRNS':
03669
03670
03671 $transparency = array();
03672 if ( $info['colorType'] == 3 )
03673 {
03674
03675
03676
03677
03678
03679
03680
03681
03682 $transparency['type'] = 'indexed';
03683 $numPalette = strlen($pdata)/3;
03684 $trans = 0;
03685 for ( $i = $chunkLen; $i >= 0; $i-- )
03686 {
03687 if ( ord( $data[$p+8+$i] ) == 0 )
03688 {
03689 $trans = $i;
03690 }
03691 }
03692 $transparency['data'] = $trans;
03693
03694 }
03695 elseif ( $info['colorType'] == 0 )
03696 {
03697
03698
03699
03700
03701
03702 $transparency['type'] = 'indexed';
03703 $transparency['data'] = ord( $data[$p+8+1] );
03704
03705 }
03706 elseif ( $info['colorType'] == 2)
03707 {
03708
03709
03710
03711
03712
03713
03714 $transparency['r'] = $this->PRVT_getBytes( $data, $p+8, 2 );
03715 $transparency['g'] = $this->PRVT_getBytes( $data, $p+10 ,2 );
03716 $transparency['b'] = $this->PRVT_getBytes( $data, $p+12 ,2 );
03717 }
03718 else
03719 {
03720
03721 }
03722
03723 break;
03724 default:
03725 break;
03726 }
03727
03728 $p += $chunkLen+12;
03729 }
03730
03731 if ( !$haveHeader )
03732 {
03733 $error = 1;
03734 $errormsg = 'information header is missing';
03735 }
03736 if ( isset( $info['interlaceMethod']) && $info['interlaceMethod'] )
03737 {
03738 $error = 1;
03739 $errormsg = 'There appears to be no support for interlaced images in pdf.';
03740 }
03741 }
03742
03743 if ( !$error && $info['bitDepth'] > 8 )
03744 {
03745 $error = 1;
03746 $errormsg = 'only bit depth of 8 or less is supported';
03747 }
03748
03749 if ( !$error )
03750 {
03751 if ( $info['colorType'] != 2 && $info['colorType'] != 0 && $info['colorType'] != 3 )
03752 {
03753 $error = 1;
03754 $errormsg = 'transparancey alpha channel not supported, transparency only supported for palette images.';
03755 }
03756 else
03757 {
03758 switch ( $info['colorType'] )
03759 {
03760 case 3:
03761 $color = 'DeviceRGB';
03762 $ncolor = 1;
03763 break;
03764 case 2:
03765 $color = 'DeviceRGB';
03766 $ncolor = 3;
03767 break;
03768 case 0:
03769 $color = 'DeviceGray';
03770 $ncolor = 1;
03771 break;
03772 }
03773 }
03774 }
03775 if ( $error )
03776 {
03777 eZDebug::writeError( 'Adding PNG file, '. $file .', to PDF failed: '.$errormsg, 'Cpdf::addPngFromFile' );
03778 $this->addMessage('PNG error - ('.$file.') '.$errormsg);
03779 return false;
03780 }
03781 if ( $w == 0 )
03782 {
03783 $w = $h/$info['height'] * $info['width'];
03784 }
03785 if ( $h == 0 )
03786 {
03787 $h = $w * $info['height'] / $info['width'];
03788 }
03789
03790
03791 $this->numImages++;
03792 $im = $this->numImages;
03793 $label = 'I'.$im;
03794 $this->numObj++;
03795
03796 $options = array( 'label' => $label,
03797 'data' => $idata,
03798 'bitsPerComponent' => $info['bitDepth'],
03799 'pdata' => $pdata,
03800 'iw' => $info['width'],
03801 'ih' => $info['height'],
03802 'type' => 'png',
03803 'color' => $color,
03804 'ncolor' => $ncolor );
03805
03806 if ( isset( $transparency ) )
03807 {
03808 $options['transparency'] = $transparency;
03809 }
03810 $this->o_image( $this->numObj, 'new', $options );
03811
03812 $this->objects[$this->currentContents]['c'].="\nq";
03813 $this->objects[$this->currentContents]['c'].="\n".ezsprintf('%.3F',$w)." 0 0 ".ezsprintf('%.3F',$h)." ".ezsprintf('%.3F',$x)." ".ezsprintf('%.3F',$y)." cm";
03814 $this->objects[$this->currentContents]['c'].="\n/".$label.' Do';
03815 $this->objects[$this->currentContents]['c'].="\nQ";
03816 }
03817
03818
03819
03820
03821 function addJpegFromFile( $img, $x, $y, $w = 0, $h = 0 )
03822 {
03823
03824
03825
03826 if ( !file_exists( $img ) )
03827 {
03828
03829 return;
03830 }
03831
03832 $tmp = getimagesize( $img );
03833 $imageWidth = $tmp[0];
03834 $imageHeight = $tmp[1];
03835
03836 if ( isset( $tmp['channels'] ) )
03837 {
03838 $channels = $tmp['channels'];
03839 }
03840 else
03841 {
03842 $channels = 3;
03843 }
03844
03845 if ( $w <= 0 && $h <= 0 )
03846 {
03847 $w = $imageWidth;
03848 }
03849 if ( $w == 0 )
03850 {
03851 $w = $h / $imageHeight * $imageWidth;
03852 }
03853 if ( $h == 0 )
03854 {
03855 $h = $w * $imageHeight / $imageWidth;
03856 }
03857
03858 $fp = fopen( $img, 'rb' );
03859
03860 $tmp = get_magic_quotes_runtime();
03861 set_magic_quotes_runtime( 0 );
03862 $data = fread( $fp, filesize( $img ) );
03863 set_magic_quotes_runtime( $tmp );
03864
03865 fclose( $fp );
03866
03867 $this->addJpegImage_common( $data, $x, $y, $w, $h, $imageWidth, $imageHeight, $channels );
03868 }
03869
03870
03871
03872
03873
03874
03875 function addImage( &$img, $x, $y, $w = 0, $h = 0, $quality = 75 )
03876 {
03877
03878
03879
03880
03881
03882
03883
03884
03885 if ( $quality > 75 )
03886 {
03887 $quality = 75;
03888 }
03889
03890
03891
03892 $imageWidth = imagesx( $img );
03893 $imageHeight = imagesy( $img );
03894
03895 if ( $w <= 0 && $h <= 0 )
03896 {
03897 return;
03898 }
03899 if ( $w == 0 )
03900 {
03901 $w = $h / $imageHeight * $imageWidth;
03902 }
03903 if ( $h == 0 )
03904 {
03905 $h = $w * $imageHeight / $imageWidth;
03906 }
03907
03908
03909
03910
03911 $tmpDir = '/tmp';
03912 $tmpName = tempnam( $tmpDir, 'img' );
03913 imagejpeg( $img, $tmpName, $quality );
03914 $fp = fopen( $tmpName, 'rb' );
03915
03916 $tmp = get_magic_quotes_runtime();
03917 set_magic_quotes_runtime( 0 );
03918 $fp = @fopen( $tmpName, 'rb' );
03919 if ( $fp )
03920 {
03921 $data = '';
03922 while ( !feof( $fp ) )
03923 {
03924 $data .= fread( $fp, 1024 );
03925 }
03926 fclose( $fp );
03927 }
03928 else
03929 {
03930 $error = 1;
03931 $errormsg = 'trouble opening file';
03932 }
03933
03934 set_magic_quotes_runtime( $tmp );
03935
03936 unlink( $tmpName );
03937 $this->addJpegImage_common( $data, $x, $y, $w, $h, $imageWidth, $imageHeight );
03938 }
03939
03940
03941
03942
03943
03944
03945 function addJpegImage_common( &$data, $x, $y, $w = 0, $h = 0, $imageWidth, $imageHeight, $channels = 3 )
03946 {
03947
03948
03949 $this->numImages++;
03950 $im = $this->numImages;
03951 $label = 'I'.$im;
03952 $this->numObj++;
03953 $this->o_image( $this->numObj, 'new', array( 'label' => $label,
03954 'data' => $data,
03955 'iw' => $imageWidth,
03956 'ih' => $imageHeight,
03957 'channels' => $channels ) );
03958
03959 $this->objects[$this->currentContents]['c'] .= "\nq";
03960 $this->objects[$this->currentContents]['c'] .= "\n".ezsprintf('%.3F',$w)." 0 0 ".ezsprintf('%.3F',$h)." ".ezsprintf('%.3F',$x)." ".ezsprintf('%.3F',$y)." cm";
03961 $this->objects[$this->currentContents]['c'] .= "\n/".$label.' Do';
03962 $this->objects[$this->currentContents]['c'] .= "\nQ";
03963 }
03964
03965
03966
03967
03968 function openHere( $style, $a = 0, $b = 0, $c = 0 )
03969 {
03970
03971
03972
03973
03974
03975
03976
03977
03978
03979
03980 $this->numObj++;
03981 $this->o_destination( $this->numObj, 'new', array( 'page' => $this->currentPage,
03982 'type' => $style,
03983 'p1' => $a, 'p2' => $b, 'p3' => $c ) );
03984 $id = $this->catalogId;
03985 $this->o_catalog( $id, 'openHere', $this->numObj );
03986 }
03987
03988
03989
03990
03991 function addDestination($label,$style,$a=0,$b=0,$c=0)
03992 {
03993
03994
03995
03996 $this->numObj++;
03997 $this->o_destination( $this->numObj, 'new', array( 'page' => $this->currentPage,
03998 'type' => $style,
03999 'p1' => $a, 'p2' => $b, 'p3' => $c ) );
04000 $id = $this->numObj;
04001
04002 $this->destinations["$label"] = $id;
04003 }
04004
04005
04006
04007
04008
04009
04010 function setFontFamily($family,$options='')
04011 {
04012 if (!is_array($options))
04013 {
04014 if ($family=='init')
04015 {
04016
04017
04018
04019 $this->fontFamilies['Helvetica'] = array(
04020 'b'=>'Helvetica-Bold'
04021 ,'i'=>'Helvetica-Oblique'
04022 ,'bi'=>'Helvetica-BoldOblique'
04023 ,'ib'=>'Helvetica-BoldOblique'
04024 );
04025 $this->fontFamilies['Courier'] = array(
04026 'b'=>'Courier-Bold'
04027 ,'i'=>'Courier-Oblique'
04028 ,'bi'=>'Courier-BoldOblique'
04029 ,'ib'=>'Courier-BoldOblique'
04030 );
04031 $this->fontFamilies['Times-Roman'] = array(
04032 'b'=>'Times-Bold'
04033 ,'i'=>'Times-Italic'
04034 ,'bi'=>'Times-BoldItalic'
04035 ,'ib'=>'Times-BoldItalic'
04036 );
04037 }
04038 }
04039 else
04040 {
04041
04042
04043 if (strlen($family))
04044 {
04045 $this->fontFamilies[$family] = $options;
04046 }
04047 }
04048 }
04049
04050
04051
04052
04053 function addMessage( $message )
04054 {
04055 $this->messages .= $message."\n";
04056 }
04057
04058
04059
04060
04061 function transaction( $action )
04062 {
04063 switch ( $action )
04064 {
04065 case 'start':
04066
04067 $data = get_object_vars( $this );
04068 $this->checkpoint = $data;
04069 unset( $data );
04070 break;
04071 case 'commit':
04072 if ( is_array( $this->checkpoint ) && isset( $this->checkpoint['checkpoint'] ) )
04073 {
04074 $tmp = $this->checkpoint['checkpoint'];
04075 $this->checkpoint = $tmp;
04076 unset( $tmp );
04077 }
04078 else
04079 {
04080 $this->checkpoint = '';
04081 }
04082 break;
04083 case 'rewind':
04084
04085 if ( is_array( $this->checkpoint ) )
04086 {
04087
04088 $tmp = $this->checkpoint;
04089 foreach ( $tmp as $k => $v )
04090 {
04091 if ( $k != 'checkpoint' )
04092 {
04093 $this->$k = $v;
04094 }
04095 }
04096 unset($tmp);
04097 }
04098 break;
04099 case 'abort':
04100 if ( is_array( $this->checkpoint ) )
04101 {
04102
04103 $tmp = $this->checkpoint;
04104 foreach ( $tmp as $k => $v )
04105 {
04106 $this->$k = $v;
04107 }
04108 unset($tmp);
04109 }
04110 break;
04111 }
04112
04113 }
04114
04115
04116
04117
04118
04119
04120
04121
04122
04123 function compareCMYK( $cmykArray1, $cmykArray2 )
04124 {
04125 return ( $cmykArray1['c'] == $cmykArray2['c'] &&
04126 $cmykArray1['m'] == $cmykArray2['m'] &&
04127 $cmykArray1['y'] == $cmykArray2['y'] &&
04128 $cmykArray1['k'] == $cmykArray2['k'] );
04129 }
04130
04131
04132
04133
04134
04135
04136 function pushTextState( $newState )
04137 {
04138 $this->textStateStack[] = $this->currentTextState;
04139 $this->currentTextState = $newState;
04140 $this->setCurrentFont();
04141 }
04142
04143
04144
04145
04146 function popTextState( )
04147 {
04148 $this->currentTextState = array_pop( $this->textStateStack );
04149 $this->setCurrentFont();
04150 }
04151
04152 var $textStateStack = array( '' );
04153 }
04154
04155 ?>