Exponential 6.0.13 Exponential Enterprise Open Source CMS - PHP Class Reference

class.ezpdf.php
Go to the documentation of this file.
1 <?php
17 class Cezpdf extends Cpdf
18 {
19
20 public $ez=array('fontSize'=>10); // used for storing most of the page configuration parameters
21 public $y; // this is the current vertical positon on the page of the writing point, very important
22 public $ezPages=array(); // keep an array of the ids of the pages, making it easy to go back and add page numbers etc.
23 public $ezPageCount=0;
24
25 // ------------------------------------------------------------------------------
26
33 public function __construct( $paper = 'a4', $orientation = 'portrait' )
34 {
35 // Assuming that people don't want to specify the paper size using the absolute coordinates
36 // allow a couple of options:
37 // orientation can be 'portrait' or 'landscape'
38 // or, to actually set the coordinates, then pass an array in as the first parameter.
39 // the defaults are as shown.
40 //
41 // -------------------------
42 // 2002-07-24 - Nicola Asuni (info@tecnick.com):
43 // Added new page formats (45 standard ISO paper formats and 4 american common formats)
44 // paper cordinates are calculated in this way: (inches * 72) where 1 inch = 2.54 cm
45 //
46 // Now you may also pass a 2 values array containing the page width and height in centimeters
47 // -------------------------
48
49 if ( !is_array( $paper ) )
50 {
51 switch ( strtoupper( $paper ) )
52 {
53 case '4A0': {$size = array(0,0,4767.87,6740.79); break;}
54 case '2A0': {$size = array(0,0,3370.39,4767.87); break;}
55 case 'A0': {$size = array(0,0,2383.94,3370.39); break;}
56 case 'A1': {$size = array(0,0,1683.78,2383.94); break;}
57 case 'A2': {$size = array(0,0,1190.55,1683.78); break;}
58 case 'A3': {$size = array(0,0,841.89,1190.55); break;}
59 case 'A4': default: {$size = array(0,0,595.28,841.89); break;}
60 case 'A5': {$size = array(0,0,419.53,595.28); break;}
61 case 'A6': {$size = array(0,0,297.64,419.53); break;}
62 case 'A7': {$size = array(0,0,209.76,297.64); break;}
63 case 'A8': {$size = array(0,0,147.40,209.76); break;}
64 case 'A9': {$size = array(0,0,104.88,147.40); break;}
65 case 'A10': {$size = array(0,0,73.70,104.88); break;}
66 case 'B0': {$size = array(0,0,2834.65,4008.19); break;}
67 case 'B1': {$size = array(0,0,2004.09,2834.65); break;}
68 case 'B2': {$size = array(0,0,1417.32,2004.09); break;}
69 case 'B3': {$size = array(0,0,1000.63,1417.32); break;}
70 case 'B4': {$size = array(0,0,708.66,1000.63); break;}
71 case 'B5': {$size = array(0,0,498.90,708.66); break;}
72 case 'B6': {$size = array(0,0,354.33,498.90); break;}
73 case 'B7': {$size = array(0,0,249.45,354.33); break;}
74 case 'B8': {$size = array(0,0,175.75,249.45); break;}
75 case 'B9': {$size = array(0,0,124.72,175.75); break;}
76 case 'B10': {$size = array(0,0,87.87,124.72); break;}
77 case 'C0': {$size = array(0,0,2599.37,3676.54); break;}
78 case 'C1': {$size = array(0,0,1836.85,2599.37); break;}
79 case 'C2': {$size = array(0,0,1298.27,1836.85); break;}
80 case 'C3': {$size = array(0,0,918.43,1298.27); break;}
81 case 'C4': {$size = array(0,0,649.13,918.43); break;}
82 case 'C5': {$size = array(0,0,459.21,649.13); break;}
83 case 'C6': {$size = array(0,0,323.15,459.21); break;}
84 case 'C7': {$size = array(0,0,229.61,323.15); break;}
85 case 'C8': {$size = array(0,0,161.57,229.61); break;}
86 case 'C9': {$size = array(0,0,113.39,161.57); break;}
87 case 'C10': {$size = array(0,0,79.37,113.39); break;}
88 case 'RA0': {$size = array(0,0,2437.80,3458.27); break;}
89 case 'RA1': {$size = array(0,0,1729.13,2437.80); break;}
90 case 'RA2': {$size = array(0,0,1218.90,1729.13); break;}
91 case 'RA3': {$size = array(0,0,864.57,1218.90); break;}
92 case 'RA4': {$size = array(0,0,609.45,864.57); break;}
93 case 'SRA0': {$size = array(0,0,2551.18,3628.35); break;}
94 case 'SRA1': {$size = array(0,0,1814.17,2551.18); break;}
95 case 'SRA2': {$size = array(0,0,1275.59,1814.17); break;}
96 case 'SRA3': {$size = array(0,0,907.09,1275.59); break;}
97 case 'SRA4': {$size = array(0,0,637.80,907.09); break;}
98 case 'LETTER': {$size = array(0,0,612.00,792.00); break;}
99 case 'LEGAL': {$size = array(0,0,612.00,1008.00); break;}
100 case 'EXECUTIVE': {$size = array(0,0,521.86,756.00); break;}
101 case 'FOLIO': {$size = array(0,0,612.00,936.00); break;}
102 }
103 switch ( strtolower( $orientation ) )
104 {
105 case 'landscape':
106 $a=$size[3];
107 $size[3]=$size[2];
108 $size[2]=$a;
109 break;
110 }
111 }
112 else
113 {
114 if ( count( $paper ) > 2 )
115 { // then an array was sent it to set the size
116 $size = $paper;
117 }
118 else
119 { //size in centimeters has been passed
120 $size[0] = 0;
121 $size[1] = 0;
122 $size[2] = ( $paper[0] / 2.54 ) * 72;
123 $size[3] = ( $paper[1] / 2.54 ) * 72;
124 }
125 }
126 parent::__construct( $size );
127 $this->ez['pageWidth']=$size[2];
128 $this->ez['pageHeight']=$size[3];
129
130 // also set the margins to some reasonable defaults
131 $config = eZINI::instance( 'pdf.ini' );
132
133 $this->ez['topMargin']=$config->variable( 'PDFGeneral', 'TopMargin' );
134 $this->ez['bottomMargin']=$config->variable( 'PDFGeneral', 'BottomMargin' );
135 $this->ez['leftMargin']=$config->variable( 'PDFGeneral', 'LeftMargin' );
136 $this->ez['rightMargin']=$config->variable( 'PDFGeneral', 'RightMargin' );
137
138 // set the current writing position to the top of the first page
139 $this->y = $this->ez['pageHeight']-$this->ez['topMargin'];
140 $this->ez['xOffset'] = 0;
141
142 // set current text justification
143 $this->ez['justification'] = 'left';
144 $this->ez['lineSpace'] = 1;
145 // and get the ID of the page that was created during the instancing process.
146 $this->ezPages[1]=$this->getFirstPageId();
147 $this->ezPageCount=1;
148 }
149
150 // ------------------------------------------------------------------------------
151 // 2002-07-24: Nicola Asuni (info@tecnick.com)
152 // Set Margins in centimeters
153 function ezSetCmMargins( $top, $bottom, $left, $right )
154 {
155 $top = ( $top / 2.54 ) * 72;
156 $bottom = ( $bottom / 2.54 ) * 72;
157 $left = ( $left / 2.54 ) * 72;
158 $right = ( $right / 2.54 ) * 72;
159 $this->ezSetMargins( $top, $bottom, $left, $right );
160 }
161
162 // ------------------------------------------------------------------------------
163 // 2003-11-04 Kåre Køhler Høvik ( eZ Systems, http://ez.no )
164 // Set fontsize
165
166 function setFontSize( $size )
167 {
168 $this->ez['fontSize'] = $size;
169 }
170
171 // ------------------------------------------------------------------------------
172 // 2003-11-06 Kåre Køhler Høvik ( eZ Systems, http://ez.no )
173 // Set justification
174
175 function setJustification( $align )
176 {
177 $this->ez['justification'] = $align;
178 }
179
180 // ------------------------------------------------------------------------------
181 // 2003-11-06 Kåre Køhler Høvik ( eZ Systems, http://ez.no )
182 // Get justification
183
184 function justification()
185 {
186 return $this->ez['justification'];
187 }
188
189 // ------------------------------------------------------------------------------
190 // 2003-11-04 Kåre Køhler Høvik ( eZ Systems, http://ez.no )
191 // Get fontsize
192
193 function fontSize()
194 {
195 return $this->ez['fontSize'];
196 }
197
198 // ------------------------------------------------------------------------------
199
200 function ezColumnsStart( $options = array() )
201 {
202 // start from the current y-position, make the set number of columne
203 if ( isset( $this->ez['columns'] ) && $this->ez['columns'] == 1 )
204 { // if we are already in a column mode then just return.
205 return;
206 }
207 $def = array( 'gap'=>10, 'num'=>2 );
208 foreach( $def as $k => $v )
209 {
210 if ( !isset( $options[$k] ) )
211 {
212 $options[$k] = $v;
213 }
214 }
215 // setup the columns
216 $this->ez['columns'] = array( 'on' => 1, 'colNum' => 1 );
217
218 // store the current margins
219 $this->ez['columns']['margins'] = array( $this->ez['leftMargin'],
220 $this->ez['rightMargin'],
221 $this->ez['topMargin'],
222 $this->ez['bottomMargin'] );
223 // and store the settings for the columns
224 $this->ez['columns']['options'] = $options;
225 // then reset the margins to suit the new columns
226 // safe enough to assume the first column here, but start from the current y-position
227 $this->ez['topMargin'] = $this->ez['pageHeight']-$this->y;
228 $width = ( $this->ez['pageWidth'] - $this->ez['leftMargin'] - $this->ez['rightMargin'] - ( $options['num'] - 1 ) * $options['gap'] ) / $options['num'];
229 $this->ez['columns']['width'] = $width;
230 $this->ez['rightMargin'] = $this->ez['pageWidth'] - $this->ez['leftMargin'] - $width;
231
232 }
233 // ------------------------------------------------------------------------------
234 function ezColumnsStop()
235 {
236 if ( isset( $this->ez['columns'] ) && $this->ez['columns']['on']==1 )
237 {
238 $this->ez['columns']['on'] = 0;
239 $this->ez['leftMargin'] = $this->ez['columns']['margins'][0];
240 $this->ez['rightMargin'] = $this->ez['columns']['margins'][1];
241 $this->ez['topMargin'] = $this->ez['columns']['margins'][2];
242 $this->ez['bottomMargin'] = $this->ez['columns']['margins'][3];
243 }
244 }
245 // ------------------------------------------------------------------------------
246 function ezInsertMode( $status = 1, $pageNum = 1, $pos = 'before' )
247 {
248 // puts the document into insert mode. new pages are inserted until this is re-called with status=0
249 // by default pages wil be inserted at the start of the document
250 switch ( $status )
251 {
252 case '1':
253 if ( isset( $this->ezPages[$pageNum] ) )
254 {
255 $this->ez['insertMode'] = 1;
256 $this->ez['insertOptions'] = array( 'id' => $this->ezPages[$pageNum],
257 'pos' => $pos );
258 } break;
259 case '0':
260 $this->ez['insertMode'] = 0;
261 break;
262 }
263 }
264 // ------------------------------------------------------------------------------
265
266 function ezNewPage()
267 {
268 $pageRequired = 1;
269 if ( isset( $this->ez['columns'] ) && $this->ez['columns']['on'] == 1 )
270 {
271 // check if this is just going to a new column
272 // increment the column number
273
274 $this->ez['columns']['colNum']++;
275 if ( $this->ez['columns']['colNum'] <= $this->ez['columns']['options']['num'] )
276 {
277 // then just reset to the top of the next column
278 $pageRequired=0;
279 }
280 else
281 {
282 $this->ez['columns']['colNum'] = 1;
283 $this->ez['topMargin'] = $this->ez['columns']['margins'][2];
284 }
285
286 $width = $this->ez['columns']['width'];
287 $this->ez['leftMargin'] = $this->ez['columns']['margins'][0] + ( $this->ez['columns']['colNum'] - 1 ) * ( $this->ez['columns']['options']['gap'] + $width );
288 $this->ez['rightMargin'] = $this->ez['pageWidth'] - $this->ez['leftMargin'] - $width;
289 }
290
291 if ( $pageRequired )
292 {
293 // make a new page, setting the writing point back to the top
294 $this->y = $this->ez['pageHeight']-$this->ez['topMargin'] - $this->getFontHeight();
295 $this->ez['xOffset'] = 0;
296 // make the new page with a call to the basic class.
297 $this->ezPageCount++;
298 if ( isset( $this->ez['insertMode'] ) && $this->ez['insertMode'] == 1 )
299 {
300 $id = $this->ezPages[$this->ezPageCount] = $this->newPage( 1, $this->ez['insertOptions']['id'], $this->ez['insertOptions']['pos'] );
301 // then manipulate the insert options so that inserted pages follow each other
302 $this->ez['insertOptions']['id'] = $id;
303 $this->ez['insertOptions']['pos'] = 'after';
304 }
305 else
306 {
307 $this->ezPages[$this->ezPageCount] = $this->newPage();
308 }
309 }
310 else
311 {
312 $this->y = $this->ez['pageHeight']-$this->ez['topMargin'] - $this->getFontHeight();
313 $this->ez['xOffset'] = 0;
314 }
315 $this->RightMarginArray = array();
316 $this->LeftMarginArray = array();
317 }
318
319 // ------------------------------------------------------------------------------
320
321 function ezSetMargins( $top, $bottom, $left, $right )
322 {
323 // sets the margins to new values
324 $this->ez['topMargin'] = $top;
325 $this->ez['bottomMargin'] = $bottom;
326 $this->ez['leftMargin'] = $left;
327 $this->ez['rightMargin'] = $right;
328 $this->LeftMarginArray = array();
329 $this->RightMarginArray = array();
330 // check to see if this means that the current writing position is outside the
331 // writable area
332 if ( $this->y > $this->ez['pageHeight'] - $top )
333 {
334 // then move y down
335 $this->ezSetY( $this->ez['pageHeight'] - $top );
336 }
337 if ( $this->y < $bottom )
338 {
339 // then make a new page
340 $this->ezNewPage();
341 }
342 }
343
344 // ------------------------------------------------------------------------------
345
346 function ezGetCurrentPageNumber()
347 {
348 // return the strict numbering (1,2,3,4..) number of the current page
349 return $this->ezPageCount;
350 }
351
352 // ------------------------------------------------------------------------------
353
354 function ezStartPageNumbers( $x, $y, $size, $pos = 'left', $pattern = '{PAGENUM} of {TOTALPAGENUM}', $num = '' )
355 {
356 // put page numbers on the pages from here.
357 // place then on the 'pos' side of the coordinates (x,y).
358 // pos can be 'left' or 'right'
359 // use the given 'pattern' for display, where (PAGENUM} and {TOTALPAGENUM} are replaced
360 // as required.
361 // if $num is set, then make the first page this number, the number of total pages will
362 // be adjusted to account for this.
363 // Adjust this function so that each time you 'start' page numbers then you effectively start a different batch
364 // return the number of the batch, so that they can be stopped in a different order if required.
365 if ( !$pos || !strlen( $pos ) )
366 {
367 $pos='left';
368 }
369 if ( !$pattern || !strlen( $pattern ) )
370 {
371 $pattern = '{PAGENUM} of {TOTALPAGENUM}';
372 }
373 if ( !isset( $this->ez['pageNumbering'] ) )
374 {
375 $this->ez['pageNumbering'] = array();
376 }
377 $i = count( $this->ez['pageNumbering'] );
378 $this->ez['pageNumbering'][$i][$this->ezPageCount] = array( 'x' => $x, 'y' => $y, 'pos' => $pos, 'pattern' => $pattern, 'num' => $num, 'size' => $size );
379 return $i;
380 }
381
382 // ------------------------------------------------------------------------------
383
384 function ezWhatPageNumber( $pageNum, $i = 0 )
385 {
386 // given a particular generic page number (ie, document numbered sequentially from beginning),
387 // return the page number under a particular page numbering scheme ($i)
388 $num = 0;
389 $start = 1;
390 $startNum = 1;
391 if ( !isset( $this->ez['pageNumbering'] ) )
392 {
393 $this->addMessage( 'WARNING: page numbering called for and wasn\'t started with ezStartPageNumbers' );
394 return 0;
395 }
396 foreach ( $this->ez['pageNumbering'][$i] as $k => $v )
397 {
398 if ( $k <= $pageNum )
399 {
400 if ( is_array( $v ) )
401 {
402 // start block
403 if ( strlen( $v['num'] ) )
404 {
405 // a start was specified
406 $start = $v['num'];
407 $startNum = $k;
408 $num = $pageNum - $startNum + $start;
409 }
410 }
411 else
412 {
413 // stop block
414 $num = 0;
415 }
416 }
417 }
418 return $num;
419 }
420
421 // ------------------------------------------------------------------------------
422
423 function ezStopPageNumbers( $stopTotal = 0, $next = 0, $i = 0 )
424 {
425 // if stopTotal=1 then the totalling of pages for this number will stop too
426 // if $next=1, then do this page, but not the next, else do not do this page either
427 // if $i is set, then stop that particular pagenumbering sequence.
428 if ( !isset( $this->ez['pageNumbering'] ) )
429 {
430 $this->ez['pageNumbering'] = array();
431 }
432 if ( $next && isset( $this->ez['pageNumbering'][$i][$this->ezPageCount] ) &&
433 is_array( $this->ez['pageNumbering'][$i][$this->ezPageCount] ) )
434 {
435 // then this has only just been started, this will over-write the start, and nothing will appear
436 // add a special command to the start block, telling it to stop as well
437 if ( $stopTotal )
438 {
439 $this->ez['pageNumbering'][$i][$this->ezPageCount]['stoptn'] = 1;
440 }
441 else
442 {
443 $this->ez['pageNumbering'][$i][$this->ezPageCount]['stopn'] = 1;
444 }
445 }
446 else
447 {
448 if ( $stopTotal )
449 {
450 $this->ez['pageNumbering'][$i][$this->ezPageCount] = 'stopt';
451 }
452 else
453 {
454 $this->ez['pageNumbering'][$i][$this->ezPageCount] = 'stop';
455 }
456 if ( $next )
457 {
458 $this->ez['pageNumbering'][$i][$this->ezPageCount] .= 'n';
459 }
460 }
461 }
462
463 // ------------------------------------------------------------------------------
464
465 function ezPRVTpageNumberSearch( $lbl, &$tmp )
466 {
467 foreach ( $tmp as $i => $v )
468 {
469 if ( is_array( $v ) )
470 {
471 if ( isset( $v[$lbl] ) )
472 {
473 return $i;
474 }
475 }
476 else
477 {
478 if ( $v == $lbl )
479 {
480 return $i;
481 }
482 }
483 }
484 return 0;
485 }
486
487 // ------------------------------------------------------------------------------
488
489 function ezPRVTaddPageNumbers()
490 {
491 // this will go through the pageNumbering array and add the page numbers are required
492 if ( isset( $this->ez['pageNumbering'] ) )
493 {
494 $totalPages1 = $this->ezPageCount;
495 $tmp1 = $this->ez['pageNumbering'];
496 $status = 0;
497 foreach ( $tmp1 as $i => $tmp )
498 {
499 // do each of the page numbering systems
500 // firstly, find the total pages for this one
501 $k = $this->ezPRVTpageNumberSearch( 'stopt', $tmp );
502 if ( $k && $k > 0 )
503 {
504 $totalPages = $k - 1;
505 }
506 else
507 {
508 $l = $this->ezPRVTpageNumberSearch( 'stoptn', $tmp );
509 if ( $l && $l > 0 )
510 {
511 $totalPages = $l;
512 }
513 else
514 {
515 $totalPages = $totalPages1;
516 }
517 }
518 foreach ( $this->ezPages as $pageNum => $id )
519 {
520 if ( isset( $tmp[$pageNum] ) )
521 {
522 if ( is_array( $tmp[$pageNum] ) )
523 {
524 // then this must be starting page numbers
525 $status = 1;
526 $info = $tmp[$pageNum];
527 $info['dnum'] = $info['num'] - $pageNum;
528 // also check for the special case of the numbering stopping and starting on the same page
529 if ( isset( $info['stopn'] ) || isset( $info['stoptn'] ) )
530 {
531 $status = 2;
532 }
533 }
534 else if ( $tmp[$pageNum] == 'stop' || $tmp[$pageNum] == 'stopt' )
535 {
536 // then we are stopping page numbers
537 $status = 0;
538 }
539 else if ( $status == 1 && ( $tmp[$pageNum] == 'stoptn' || $tmp[$pageNum] == 'stopn' ) )
540 {
541 // then we are stopping page numbers
542 $status = 2;
543 }
544 }
545 if ( $status )
546 {
547 // then add the page numbering to this page
548 if ( strlen( $info['num'] ) )
549 {
550 $num = $pageNum + $info['dnum'];
551 }
552 else
553 {
554 $num = $pageNum;
555 }
556 $total = $totalPages + $num - $pageNum;
557 $pat = str_replace( '{PAGENUM}', $num, $info['pattern'] );
558 $pat = str_replace( '{TOTALPAGENUM}', $total, $pat );
559 $this->reopenObject( $id );
560 switch ( $info['pos'] )
561 {
562 case 'right':
563 $this->addText( $info['x'], $info['y'], $info['size'], $pat );
564 break;
565 default:
566 $w = $this->getTextWidth( $info['size'], $pat );
567 $this->addText( $info['x'] - $w, $info['y'], $info['size'], $pat );
568 break;
569 }
570 $this->closeObject();
571 }
572 if ( $status == 2 )
573 {
574 $status = 0;
575 }
576 }
577 }
578 }
579 }
580
581 // ------------------------------------------------------------------------------
582
583 function ezPRVTcleanUp()
584 {
585 $this->ezPRVTaddPageNumbers();
586 }
587
588 // ------------------------------------------------------------------------------
589
590 function ezStream( $options = '' )
591 {
592 $this->ezPRVTcleanUp();
593 $this->stream( $options );
594 }
595
596 // ------------------------------------------------------------------------------
597
598 function ezOutput( $options = 0 )
599 {
600 $this->ezPRVTcleanUp();
601 return $this->output( $options );
602 }
603
604 // ------------------------------------------------------------------------------
605
606 function ezSetY( $y )
607 {
608 // used to change the vertical position of the writing point.
609 $this->y = $y;
610 $this->ez['xOffset'] = 0;
611 if ( $this->y < $this->ez['bottomMargin'] )
612 {
613 // then make a new page
614 $this->ezNewPage();
615 }
616 }
617
618 // ------------------------------------------------------------------------------
619
620 function ezSetDy( $dy, $mod = '' )
621 {
622 // used to change the vertical position of the writing point.
623 // changes up by a positive increment, so enter a negative number to go
624 // down the page
625 // if $mod is set to 'makeSpace' and a new page is forced, then the pointed will be moved
626 // down on the new page, this will allow space to be reserved for graphics etc.
627 $this->y += $dy;
628 $this->ez['xOffset'] = 0;
629 if ( $this->y < $this->ez['bottomMargin'] )
630 {
631 // then make a new page
632 $this->ezNewPage();
633 if ( $mod == 'makeSpace' )
634 {
635 $this->y += $dy;
636 }
637 }
638 }
639
640 // ------------------------------------------------------------------------------
641
642 function ezPrvtTableDrawLines( $pos, $gap, $x0, $x1, $y0, $y1, $y2, $col, $inner, $outer, $opt = 1 )
643 {
644 $x0 = 1000;
645 $x1 = 0;
646 $this->setStrokeColorRGB( $col[0], $col[1], $col[2] );
647 $cnt = 0;
648 $n = count( $pos );
649 foreach ( $pos as $x )
650 {
651 $cnt++;
652 if ( $cnt == 1 || $cnt == $n )
653 {
654 $this->setLineStyle( $outer );
655 }
656 else
657 {
658 $this->setLineStyle( $inner );
659 }
660 $this->line( $x - $gap / 2, $y0, $x - $gap / 2, $y2 );
661 if ( $x > $x1 )
662 {
663 $x1 = $x;
664 }
665 if ( $x < $x0 )
666 {
667 $x0 = $x;
668 }
669 }
670 $this->setLineStyle( $outer );
671 $this->line( $x0 - $gap / 2 - $outer / 2, $y0, $x1 - $gap / 2 + $outer / 2, $y0 );
672 // only do the second line if it is different to the first, AND each row does not have
673 // a line on it.
674 if ( $y0 != $y1 && $opt < 2 )
675 {
676 $this->line( $x0 - $gap / 2, $y1, $x1 - $gap / 2, $y1 );
677 }
678 $this->line( $x0 - $gap / 2 - $outer / 2, $y2, $x1 - $gap / 2 + $outer / 2, $y2 );
679 }
680
681 // ------------------------------------------------------------------------------
682
683 function ezPrvtTableColumnHeadings( $cols, $pos, $maxWidth, $height, $decender, $gap, $size, &$y, $optionsAll = array() )
684 {
685 // uses ezText to add the text, and returns the height taken by the largest heading
686 // this page will move the headings to a new page if they will not fit completely on this one
687 // transaction support will be used to implement this
688
689 if ( isset( $optionsAll['cols'] ) )
690 {
691 $options = $optionsAll['cols'];
692 }
693 else
694 {
695 $options = array();
696 }
697
698 $mx = 0;
699 $startPage = $this->ezPageCount;
700 $secondGo = 0;
701
702 // $y is the position at which the top of the table should start, so the base
703 // of the first text, is $y-$height-$gap-$decender, but ezText starts by dropping $height
704
705 // the return from this function is the total cell height, including gaps, and $y is adjusted
706 // to be the postion of the bottom line
707
708 // begin the transaction
709 $this->transaction( 'start' );
710 $ok = 0;
711 // $y-=$gap-$decender;
712 $y -= $gap;
713 while ( $ok == 0 )
714 {
715 foreach ( $cols as $colName => $colHeading )
716 {
717 $this->ezSetY( $y );
718 if ( isset( $options[$colName] ) && isset( $options[$colName]['justification'] ) )
719 {
720 $justification = $options[$colName]['justification'];
721 }
722 else
723 {
724 $justification = $this->ez['justification'];
725 }
726 // $this->ezText($colHeading,$size,array('aleft'=> $pos[$colName],'aright'=>($maxWidth[$colName]+$pos[$colName]),'justification'=>$justification));
727 $dy = $y - $this->y;
728 if ( $dy > $mx )
729 {
730 $mx = $dy;
731 }
732 }
733 $y = $y - $mx - $gap + $decender;
734 // $y -= $mx-$gap+$decender;
735
736 // now, if this has moved to a new page, then abort the transaction, move to a new page, and put it there
737 // do not check on the second time around, to avoid an infinite loop
738 if ( $this->ezPageCount != $startPage && $secondGo == 0 )
739 {
740 $this->transaction( 'rewind' );
741 $this->ezNewPage();
742 $y = $this->y - $gap - $decender;
743 $ok = 0;
744 $secondGo = 1;
745 // $y = $store_y;
746 $mx = 0;
747 }
748 else
749 {
750 $this->transaction( 'commit' );
751 $ok = 1;
752 }
753 }
754
755 return $mx + $gap * 2 - $decender;
756 }
757
758 // ------------------------------------------------------------------------------
759
768 function eZGetMaxWordWidth( $size, $text )
769 {
770 $mx = 0;
771 $text = str_replace( '-', ' ', $text );
772 $words = str_word_count( $text, 1 );
773 foreach ( $words as $word )
774 {
775 $w = $this->getTextWidth($size,$word);
776 if ( $w > $mx )
777 {
778 $mx = $w;
779 }
780 }
781 return $mx;
782 }
783
784 function ezPrvtGetTextWidth( $size, $text )
785 {
786 // will calculate the maximum width, taking into account that the text may be broken
787 // by line breaks.
788 $mx = 0;
789 $lines = explode( "\n", $text );
790 foreach ( $lines as $line )
791 {
792 $w = $this->getTextWidth( $size, $line );
793 if ( $w > $mx )
794 {
795 $mx = $w;
796 }
797 }
798 return $mx;
799 }
800
814 function ezShadedRectangle( $x1, $y1, $width, $height, $col1, $col2, $direction = 'vertical' )
815 {
816 $this->shadedRectangle( $x1, $y1, $width, $height, array( 'orientation' => $direction,
817 'color0' => $col1,
818 'color1' => $col2,
819 'size' => array( 'x1' => $x1,
820 'y1' => $y1,
821 'width' => $width,
822 'height' => $height ) ) );
823 }
824
825 // ------------------------------------------------------------------------------
826 function ezProcessText( $text )
827 {
828 // this function will intially be used to implement underlining support, but could be used for a range of other
829 // purposes
830 $search = array( '<u>', '<U>', '</u>', '</U>' );
831 $replace = array( '<c:uline>', '<c:uline>', '</c:uline>', '</c:uline>' );
832 return str_replace( $search, $replace, $text );
833 }
834
835 // ------------------------------------------------------------------------------
836
837 function ezText( $text, $size = 0, $options = array(), $test = 0 )
838 {
839 // this will add a string of text to the document, starting at the current drawing
840 // position.
841 // it will wrap to keep within the margins, including optional offsets from the left
842 // and the right, if $size is not specified, then it will be the last one used, or
843 // the default value (12 I think).
844 // the text will go to the start of the next line when a return code "\n" is found.
845 // possible options are:
846 // 'left'=> number, gap to leave from the left margin
847 // 'right'=> number, gap to leave from the right margin
848 // 'aleft'=> number, absolute left position (overrides 'left')
849 // 'aright'=> number, absolute right position (overrides 'right')
850 // 'justification' => 'left','right','center','centre','full'
851 // 'top_margin' => set top margin manualy
852
853 // only set one of the next two items (leading overrides spacing)
854 // 'leading' => number, defines the total height taken by the line, independent of the font height.
855 // 'spacing' => a real number, though usually set to one of 1, 1.5, 2 (line spacing as used in word processing)
856
857 // if $test is set then this should just check if the text is going to flow onto a new page or not, returning true or false
858
859 // apply the filtering which will make the underlining function.
860 if ( strlen( $text ) == 0 )
861 return $this->y;
862
863 $text = $this->ezProcessText( $text );
864
865 $newPage = false;
866 $store_y = $this->y;
867 $left = $angle = $adjust = 0;
868
869 if ( is_array( $options ) && isset( $options['aright'] ) )
870 {
871 $right = $options['aright'];
872 }
873 else
874 {
875 $right = $this->ez['pageWidth'] - $this->rightMargin() - ( ( is_array( $options ) && isset( $options['right'] ) ) ? $options['right'] : 0 );
876 }
877 if ( $size <= 0 )
878 {
879 $size = $this->ez['fontSize'];
880 }
881 else
882 {
883 $this->ez['fontSize'] = $size;
884 }
885
886 if ( is_array( $options ) && isset( $options['top_margin'] ) )
887 {
888 $this->y = $this->ez['pageHeight'] - $options['top_margin'];
889 }
890
891 if ( is_array( $options ) && isset( $options['justification'] ) )
892 {
893 $just = $options['justification'];
894 }
895 else
896 {
897 $just = $this->ez['justification'];
898 }
899
900 // modifications to give leading and spacing based on those given by Craig Heydenburg 1/1/02
901 if ( is_array( $options ) && isset( $options['leading'] ) )
902 { // use leading instead of spacing
903 $height = $options['leading'];
904 }
905 else if ( is_array( $options ) && isset( $options['spacing'] ) )
906 {
907 $height = $this->getFontHeight( $size ) * $options['spacing'];
908 }
909 else
910 {
911 $height = $this->getFontHeight( $size );
912 }
913
914 $lastOnlyDirective = false;
915 $lines = explode( "\n", $text );
916 if ( $text == "\n" )
917 {
918 $lines = array( "" );
919 }
920 foreach ( array_keys( $lines ) as $key )
921 {
922 $line = $lines[$key];
923 if ( ( $key > 0 || strlen( $line ) == 0 ) &&
924 !$lastOnlyDirective )
925 {
926 $this->y = $this->y - $height;
927 $this->ez['xOffset'] = 0;
928 }
929 $lastOnlyDirective = false;
930 while ( strlen( $line ) )
931 {
932 $noClose = 1;
933 while ( $noClose )
934 {
935 $f = 1;
936 $directiveArray = $this->PRVTcheckTextDirective( $line, 0, $f );
937 $noClose = $directiveArray['noClose'];
938 if ( $noClose )
939 {
940 if ( $this->ez['xOffset'] != 0 )
941 {
942 $left = $this->ez['xOffset'];
943 }
944 else
945 {
946 $left = $this->leftMargin() + ( (is_array( $options ) && isset( $options['left'] ) ) ? $options['left'] : 0 );
947 }
948
949 $textInfo = $this->addText( $left, $this->y, $size, substr( $line, 0, $directiveArray['directive'] ), $angle, $adjust );
950 $line = substr( $line, $directiveArray['directive'] );
951 if ( isset( $textInfo['width'] ) && $textInfo['width'] != 0 )
952 {
953 $this->setXOffset( $left + $textInfo['width'] );
954 }
955 }
956 }
957
958 if ( $this->y < $this->ez['bottomMargin'] )
959 {
960 if ( $test )
961 {
962 $newPage = true;
963 }
964 else if ( strlen( trim( $line ) ) )
965 {
966 $this->ezNewPage();
967 // and then re-calc the left and right, in case they have changed due to columns
968 }
969 }
970 if ( $this->ez['xOffset'] != 0 )
971 {
972 $left = $this->ez['xOffset'];
973 }
974 else
975 {
976 $left = $this->leftMargin() + ( ( is_array( $options ) && isset( $options['left'] ) ) ? $options['left'] : 0 );
977 }
978
979 if ( is_array( $options ) && isset( $options['aleft'] ) )
980 {
981 $left=$options['aleft'];
982 }
983 if ( is_array( $options ) && isset( $options['aright'] ) )
984 {
985 $right = $options['aright'];
986 }
987 else
988 {
989 $right = $this->ez['pageWidth'] - $this->rightMargin() - ( ( is_array( $options ) && isset( $options['right'] ) ) ? $options['right'] : 0 );
990 }
991
992 $textInfo = $this->addTextWrap( $left, $this->y, $right - $left, $size, $line, $just, 0, $test );
993 if ( isset( $textInfo['only_directive'] ) &&
994 $textInfo['only_directive'] === true )
995 {
996 $lastOnlyDirective = true;
997 $line = '';
998 continue;
999 }
1000 $line = $textInfo['text'];
1001 if ( strlen( $line ) || $textInfo['width'] == 0 )
1002 {
1003 $this->y = $this->y - $height;
1004 $this->ez['xOffset'] = 0;
1005 }
1006 else if ( $textInfo['width'] != 0 )
1007 {
1008 $this->setXOffset( $left + $textInfo['width'] );
1009 }
1010 }
1011 }
1012
1013 if ( $test )
1014 {
1015 $this->y = $store_y;
1016 return $newPage;
1017 }
1018 else
1019 {
1020 return $this->y;
1021 }
1022 }
1023
1024 // ------------------------------------------------------------------------------
1025
1026 function ezImage( $image, $pad = 5, $width = 0, $resize = 'full', $just = 'center', $border = '' )
1027 {
1028 // beta ezimage function
1029 if ( stristr( $image, '://' ) ) //copy to temp file
1030 {
1031 $fp = @fopen( $image, "rb" );
1032 while( !feof( $fp ) )
1033 {
1034 $cont.= fread( $fp, 1024 );
1035 }
1036 fclose( $fp );
1037 $image = tempnam ( "/tmp", "php-pdf" );
1038 $fp2 = @fopen( $image, "w" );
1039 fwrite( $fp2, $cont );
1040 fclose( $fp2 );
1041 $temp = true;
1042 }
1043
1044 if ( !( file_exists( $image ) ) )
1045 return false; // return immediately if image file does not exist
1046 $imageInfo = getimagesize( $image );
1047 switch ( $imageInfo[2] )
1048 {
1049 case 2:
1050 $type = "jpeg";
1051 break;
1052 case 3:
1053 $type = "png";
1054 break;
1055 default:
1056 return false; // return if file is not jpg or png
1057 }
1058 if ( $width == 0 )
1059 $width = $imageInfo[0]; // set width
1060 $ratio = $imageInfo[0] / $imageInfo[1];
1061
1062 //get maximum width of image
1063 if ( isset( $this->ez['columns'] ) && $this->ez['columns']['on'] == 1 )
1064 {
1065 $bigwidth = $this->ez['columns']['width'] - ( $pad * 2 );
1066 }
1067 else
1068 {
1069 $bigwidth = $this->ez['pageWidth'] - ( $pad * 2 );
1070 }
1071 //fix width if larger than maximum or if $resize=full
1072 if ( $resize == 'full' || $resize == 'width' || $width > $bigwidth )
1073 {
1074 $width = $bigwidth;
1075 }
1076
1077 $height = ( $width / $ratio ); //set height
1078
1079 //fix size if runs off page
1080 if ( $height > ( $this->y - $this->ez['bottomMargin'] - ( $pad * 2 ) ) )
1081 {
1082 if ( $resize != 'full' )
1083 {
1084 $this->ezNewPage();
1085 }
1086 else
1087 {
1088 $height = ( $this->y - $this->ez['bottomMargin'] - ( $pad * 2 ) ); // shrink height
1089 $width = ( $height * $ratio ); // fix width
1090 }
1091 }
1092
1093 // fix x-offset if image smaller than bigwidth
1094 if ( $width < $bigwidth )
1095 {
1096 // center if justification=center
1097 if ( $just == 'center' )
1098 {
1099 $offset = ( $bigwidth - $width ) / 2;
1100 }
1101 //move to right if justification=right
1102 if ( $just == 'right' )
1103 {
1104 $offset = ( $bigwidth - $width );
1105 }
1106 //leave at left if justification=left
1107 if ( $just == 'left' )
1108 {
1109 $offset = 0;
1110 }
1111 }
1112
1113
1114 // call appropriate function
1115 if ( $type == "jpeg" )
1116 {
1117 $this->addJpegFromFile( $image, $this->leftMargin() + $pad + $offset, $this->y + $this->getFontHeight( $this->ez['fontSize'] ) - $pad - $height, $width );
1118 }
1119
1120 if ( $type == "png" )
1121 {
1122 $this->addPngFromFile( $image, $this->leftMargin() + $pad + $offset, $this->y + $this->getFontHeight( $this->ez['fontSize'] ) - $pad - $height, $width );
1123 }
1124 //draw border
1125 if ( $border != '' )
1126 {
1127 if ( !( isset( $border['color'] ) ) )
1128 {
1129 $border['color']['red'] = .5;
1130 $border['color']['blue'] = .5;
1131 $border['color']['green'] = .5;
1132 }
1133 if ( !( isset( $border['width'] ) ) )
1134 $border['width'] = 1;
1135 if ( !( isset( $border['cap'] ) ) )
1136 $border['cap'] = 'round';
1137 if ( !( isset( $border['join']) ) )
1138 $border['join'] = 'round';
1139
1140 $this->setStrokeColorRGB( $border['color']['red'], $border['color']['green'], $border['color']['blue'] );
1141 $this->setLineStyle( $border['width'], $border['cap'], $border['join'] );
1142 $this->rectangle( $this->leftMargin() + $pad + $offset, $this->y + $this->getFontHeight( $this->ez['fontSize'] ) - $pad - $height, $width, $height );
1143
1144 }
1145 // move y below image
1146 $this->y = $this->y - $pad - $height;
1147 $this->ez['xOffset'] = 0;
1148 //remove tempfile for remote images
1149 if ( $temp == true )
1150 unlink( $image );
1151
1152 }
1153 // ------------------------------------------------------------------------------
1154
1155 // note that templating code is still considered developmental - have not really figured
1156 // out a good way of doing this yet.
1157 function loadTemplate( $templateFile )
1158 {
1159 // this function will load the requested template ($file includes full or relative pathname)
1160 // the code for the template will be modified to make it name safe, and then stored in
1161 // an array for later use
1162 // The id of the template will be returned for the user to operate on it later
1163 if ( !file_exists( $templateFile ) )
1164 {
1165 return -1;
1166 }
1167
1168 $code = implode( '', file( $templateFile ) );
1169 if ( !strlen( $code ) )
1170 {
1171 return;
1172 }
1173
1174 $code = trim( $code );
1175 if ( substr( $code, 0, 5 ) == '<?php' )
1176 {
1177 $code = substr( $code, 5 );
1178 }
1179 if ( substr( $code, -2 ) == '?>' )
1180 {
1181 $code = substr( $code, 0, strlen( $code ) - 2 );
1182 }
1183 if ( isset( $this->ez['numTemplates'] ) )
1184 {
1185 $newNum = $this->ez['numTemplates'];
1186 $this->ez['numTemplates']++;
1187 }
1188 else
1189 {
1190 $newNum = 0;
1191 $this->ez['numTemplates'] = 1;
1192 $this->ez['templates'] = array();
1193 }
1194
1195 $this->ez['templates'][$newNum]['code'] = $code;
1196
1197 return $newNum;
1198 }
1199
1200 // ------------------------------------------------------------------------------
1201
1202 function execTemplate( $id, $data = array(), $options = array() )
1203 {
1204 // execute the given template on the current document.
1205 if ( !isset( $this->ez['templates'][$id] ) )
1206 {
1207 return;
1208 }
1209 eval( $this->ez['templates'][$id]['code'] );
1210 }
1211
1212 // ------------------------------------------------------------------------------
1213 function ilink( $info )
1214 {
1215 return $this->alink( $info, 1 );
1216 }
1217
1218 function alink( $info, $internal = 0 )
1219 {
1220 // a callback function to support the formation of clickable links within the document
1221 $lineFactor = 0.05; // the thickness of the line as a proportion of the height. also the drop of the line.
1222 switch( $info['status'] )
1223 {
1224 case 'start':
1225 case 'sol':
1226 // the beginning of the link
1227 // this should contain the URl for the link as the 'p' entry, and will also contain the value of 'nCallback'
1228 if (!isset($this->ez['links']))
1229 {
1230 $this->ez['links'] = array();
1231 }
1232 $i = $info['nCallback'];
1233
1234 $this->ez['links'][$i] = array( 'x' => $info['x'],
1235 'y' => $info['y'],
1236 'angle' => $info['angle'],
1237 'decender' => $info['decender'],
1238 'height' => $info['height'],
1239 'url'=>rawurldecode( $info['p'] ) );
1240 if ( $internal == 0 )
1241 {
1242 $this->saveState();
1243 $this->setColorRGB( 0, 0, 1 );
1244 $this->setStrokeColorRGB( 0, 0, 1 );
1245 $thick = $info['height'] * $lineFactor;
1246 $this->setLineStyle( $thick );
1247 }
1248 break;
1249 case 'end':
1250 case 'eol':
1251 // the end of the link
1252 // assume that it is the most recent opening which has closed
1253 $i = $info['nCallback'];
1254 $start = $this->ez['links'][$i];
1255 // add underlining
1256 if ($internal)
1257 {
1258 $this->addInternalLink( $start['url'], $start['x'], $start['y'] + $start['decender'], $info['x'], $start['y'] + $start['decender'] + $start['height'] );
1259 }
1260 else
1261 {
1262 $a = deg2rad( (float)$start['angle'] - 90.0 );
1263 $drop = $start['height'] * $lineFactor * 1.5;
1264 $dropx = cos( $a ) * $drop;
1265 $dropy = -sin( $a ) * $drop;
1266 $this->line( $start['x'] - $dropx, $start['y'] - $dropy, $info['x'] - $dropx, $info['y'] - $dropy );
1267 $this->addLink( $start['url'], $start['x'], $start['y'] + $start['decender'], $info['x'], $start['y'] + $start['decender'] + $start['height'] );
1268 $this->restoreState();
1269 }
1270 break;
1271 }
1272 }
1273
1274 // ------------------------------------------------------------------------------
1275
1276 function uline( $info )
1277 {
1278 // a callback function to support underlining
1279 $lineFactor = 0.05; // the thickness of the line as a proportion of the height. also the drop of the line.
1280 switch ( $info['status'] )
1281 {
1282 case 'start':
1283 case 'sol':
1284 // the beginning of the underline zone
1285 if ( !isset( $this->ez['links'] ) )
1286 {
1287 $this->ez['links'] = array();
1288 }
1289 $i = $info['nCallback'];
1290 $this->ez['links'][$i] = array( 'x' => $info['x'],
1291 'y' => $info['y'],
1292 'angle' => $info['angle'],
1293 'decender' => $info['decender'],
1294 'height' => $info['height'] );
1295 $this->saveState();
1296 $thick = $info['height'] * $lineFactor;
1297 $this->setLineStyle( $thick );
1298 break;
1299
1300 case 'end':
1301 case 'eol':
1302 // the end of the link
1303 // assume that it is the most recent opening which has closed
1304 $i = $info['nCallback'];
1305 $start = $this->ez['links'][$i];
1306 // add underlining
1307 $a = deg2rad( (float) $start['angle'] - 90.0 );
1308 $drop = $start['height'] * $lineFactor * 1.5;
1309 $dropx = cos( $a ) * $drop;
1310 $dropy = -sin( $a ) * $drop;
1311 $this->line( $start['x'] - $dropx, $start['y'] - $dropy, $info['x'] - $dropx, $info['y'] - $dropy );
1312 $this->restoreState();
1313 break;
1314 }
1315 }
1316
1317 // ------------------------------------------------------------------------------
1318 // 2003-11-04 Kåre Køhler Høvik ( eZ Systems, http://ez.no )
1319 // Set fontsize
1320
1321 function strike( $info )
1322 {
1323 // a callback function to support underlining
1324 $lineFactor = 0.05; // the thickness of the line as a proportion of the height. also the drop of the line.
1325 switch ( $info['status'] )
1326 {
1327 case 'start':
1328 case 'sol':
1329 // the beginning of the underline zone
1330 if ( !isset( $this->ez['links'] ) )
1331 {
1332 $this->ez['links'] = array();
1333 }
1334 $i = $info['nCallback'];
1335 $this->ez['links'][$i] = array( 'x' => $info['x'],
1336 'y' => $info['y'],
1337 'angle' => $info['angle'],
1338 'decender' => $info['decender'],
1339 'height' => $info['height'] );
1340 $this->saveState();
1341 $thick = $info['height'] * $lineFactor;
1342 $this->setLineStyle( $thick );
1343 break;
1344
1345 case 'end':
1346 case 'eol':
1347 // the end of the link
1348 // assume that it is the most recent opening which has closed
1349 $i = $info['nCallback'];
1350 $start = $this->ez['links'][$i];
1351 // add underlining
1352 $a = deg2rad( (float) $start['angle'] - 90.0 );
1353 $drop = $start['height'] / 2;
1354 $dropx = cos( $a ) * $drop;
1355 $dropy = -sin( $a ) * $drop;
1356 $this->line( $start['x'] - $dropx, $start['y'] + $dropy, $info['x'] - $dropx, $info['y'] + $dropy );
1357 $this->restoreState();
1358 break;
1359 }
1360 }
1361
1365 function lineHeight( $options = array() )
1366 {
1367 if ( is_array( $options ) && isset( $options['size'] ) )
1368 {
1369 $size = $options['size'];
1370 }
1371 else
1372 {
1373 $size = $this->ez['fontSize'];
1374 }
1375
1376 if ( is_array( $options ) && isset( $options['leading'] ) )
1377 { // use leading instead of spacing
1378 $height = $options['leading'];
1379 }
1380 else if ( is_array( $options ) && isset( $options['spacing'] ) )
1381 {
1382 $height = $this->getFontHeight( $size ) * $options['spacing'];
1383 }
1384 else
1385 {
1386 $height = $this->getFontHeight( $size );
1387 }
1388
1389 return $height;
1390 }
1391
1398 function rightMargin( $yOffset = false )
1399 {
1400 if ( $yOffset === false )
1401 {
1402 $yOffset = $this->yOffset();
1403 }
1404
1405 foreach ( $this->RightMarginArray as $rightMargin )
1406 {
1407 if ( $yOffset > $rightMargin['start'] &&
1408 $yOffset < $rightMargin['stop'] )
1409 {
1410 return $rightMargin['margin'];
1411 }
1412 }
1413
1414 return $this->ez['rightMargin'];
1415 }
1416
1423 function leftMargin( $yOffset = false )
1424 {
1425 $maxMargin = $this->ez['leftMargin'];
1426
1427 if ( $yOffset === false )
1428 {
1429 $yOffset = $this->yOffset();
1430 }
1431
1432 foreach ( $this->LeftMarginArray as $leftMargin )
1433 {
1434 if ( $yOffset > $leftMargin['start'] &&
1435 $yOffset < $leftMargin['stop'] &&
1436 $leftMargin['margin'] > $maxMargin )
1437 {
1438 $maxMargin = $leftMargin['margin'];
1439 }
1440 }
1441
1442 return $maxMargin;
1443 }
1444
1452 function setLimitedLeftMargin( $startY, $stopY, $leftMargin )
1453 {
1454 $this->LeftMarginArray[] = array( 'start' => $startY,
1455 'stop' => $stopY,
1456 'margin' => $leftMargin );
1457 }
1458
1466 function setLimitedRightMargin( $startY, $stopY, $rightMargin )
1467 {
1468 $this->RightMarginArray[] = array( 'start' => $startY,
1469 'stop' => $stopY,
1470 'margin' => $rightMargin );
1471 }
1472
1473 public $LeftMarginArray = array();
1474 public $RightMarginArray = array();
1475 }
1476
1477 // ------------------------------------------------------------------------------
1478
1479
1480 ?>
Cezpdf
Cezpdf provides.
Cpdf
Cpdf provides.
Definition: class.pdf.php:18
Copyright © 1998 – 2026 7x. All rights reserved. Licensed under the GNU GPLv2+.