PluginProbe
ERP: Complete HR, Accounting & CRM Suite Built for WooCommerce / 1.2.6
ERP: Complete HR, Accounting & CRM Suite Built for WooCommerce v1.2.6
1.17.9 1.17.8 1.17.7 1.17.6 1.17.5 1.17.4 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.2.7 1.2.8 1.3.0 1.3.1 1.3.11 1.3.12 1.3.13 1.3.14 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 1.3.7 All 143 releases
erp / includes / pdf / fpdf.php

fpdf.php in ERP: Complete HR, Accounting & CRM Suite Built for WooCommerce 1.2.6, at includes/pdf/fpdf.php

1,816 lines 46.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 namespace WeDevs\ERP;
3 /*******************************************************************************
4 * FPDF *
5 * *
6 * Version: 1.7 *
7 * Date: 2011-06-18 *
8 * Author: Olivier PLATHEY *
9 *******************************************************************************/
10
11 define('FPDF_VERSION','1.7');
12
13 class FPDF
14 {
15 var $page; // current page number
16 var $n; // current object number
17 var $offsets; // array of object offsets
18 var $buffer; // buffer holding in-memory PDF
19 var $pages; // array containing pages
20 var $state; // current document state
21 var $compress; // compression flag
22 var $k; // scale factor (number of points in user unit)
23 var $DefOrientation; // default orientation
24 var $CurOrientation; // current orientation
25 var $StdPageSizes; // standard page sizes
26 var $DefPageSize; // default page size
27 var $CurPageSize; // current page size
28 var $PageSizes; // used for pages with non default sizes or orientations
29 var $wPt, $hPt; // dimensions of current page in points
30 var $w, $h; // dimensions of current page in user unit
31 var $lMargin; // left margin
32 var $tMargin; // top margin
33 var $rMargin; // right margin
34 var $bMargin; // page break margin
35 var $cMargin; // cell margin
36 var $x, $y; // current position in user unit
37 var $lasth; // height of last printed cell
38 var $LineWidth; // line width in user unit
39 var $fontpath; // path containing fonts
40 var $CoreFonts; // array of core font names
41 var $fonts; // array of used fonts
42 var $FontFiles; // array of font files
43 var $diffs; // array of encoding differences
44 var $FontFamily; // current font family
45 var $FontStyle; // current font style
46 var $underline; // underlining flag
47 var $CurrentFont; // current font info
48 var $FontSizePt; // current font size in points
49 var $FontSize; // current font size in user unit
50 var $DrawColor; // commands for drawing color
51 var $FillColor; // commands for filling color
52 var $TextColor; // commands for text color
53 var $ColorFlag; // indicates whether fill and text colors are different
54 var $ws; // word spacing
55 var $images; // array of used images
56 var $PageLinks; // array of links in pages
57 var $links; // array of internal links
58 var $AutoPageBreak; // automatic page breaking
59 var $PageBreakTrigger; // threshold used to trigger page breaks
60 var $InHeader; // flag set when processing header
61 var $InFooter; // flag set when processing footer
62 var $ZoomMode; // zoom display mode
63 var $LayoutMode; // layout display mode
64 var $title; // title
65 var $subject; // subject
66 var $author; // author
67 var $keywords; // keywords
68 var $creator; // creator
69 var $AliasNbPages; // alias for total number of pages
70 var $PDFVersion; // PDF version number
71
72 /*******************************************************************************
73 * *
74 * Public methods *
75 * *
76 *******************************************************************************/
77 function FPDF($orientation='P', $unit='mm', $size='A4')
78 {
79 // Some checks
80 $this->_dochecks();
81 // Initialization of properties
82 $this->page = 0;
83 $this->n = 2;
84 $this->buffer = '';
85 $this->pages = array();
86 $this->PageSizes = array();
87 $this->state = 0;
88 $this->fonts = array();
89 $this->FontFiles = array();
90 $this->diffs = array();
91 $this->images = array();
92 $this->links = array();
93 $this->InHeader = false;
94 $this->InFooter = false;
95 $this->lasth = 0;
96 $this->FontFamily = '';
97 $this->FontStyle = '';
98 $this->FontSizePt = 12;
99 $this->underline = false;
100 $this->DrawColor = '0 G';
101 $this->FillColor = '0 g';
102 $this->TextColor = '0 g';
103 $this->ColorFlag = false;
104 $this->ws = 0;
105 // Font path
106 if(defined('FPDF_FONTPATH'))
107 {
108 $this->fontpath = FPDF_FONTPATH;
109 if(substr($this->fontpath,-1)!='/' && substr($this->fontpath,-1)!='\\')
110 $this->fontpath .= '/';
111 }
112 elseif(is_dir(dirname(__FILE__).'/font'))
113 $this->fontpath = dirname(__FILE__).'/font/';
114 else
115 $this->fontpath = '';
116 // Core fonts
117 $this->CoreFonts = array('courier', 'helvetica', 'times', 'symbol', 'zapfdingbats');
118 // Scale factor
119 if($unit=='pt')
120 $this->k = 1;
121 elseif($unit=='mm')
122 $this->k = 72/25.4;
123 elseif($unit=='cm')
124 $this->k = 72/2.54;
125 elseif($unit=='in')
126 $this->k = 72;
127 else
128 $this->Error('Incorrect unit: '.$unit);
129 // Page sizes
130 $this->StdPageSizes = array('a3'=>array(841.89,1190.55), 'a4'=>array(595.28,841.89), 'a5'=>array(420.94,595.28),
131 'letter'=>array(612,792), 'legal'=>array(612,1008));
132 $size = $this->_getpagesize($size);
133 $this->DefPageSize = $size;
134 $this->CurPageSize = $size;
135 // Page orientation
136 $orientation = strtolower($orientation);
137 if($orientation=='p' || $orientation=='portrait')
138 {
139 $this->DefOrientation = 'P';
140 $this->w = $size[0];
141 $this->h = $size[1];
142 }
143 elseif($orientation=='l' || $orientation=='landscape')
144 {
145 $this->DefOrientation = 'L';
146 $this->w = $size[1];
147 $this->h = $size[0];
148 }
149 else
150 $this->Error('Incorrect orientation: '.$orientation);
151 $this->CurOrientation = $this->DefOrientation;
152 $this->wPt = $this->w*$this->k;
153 $this->hPt = $this->h*$this->k;
154 // Page margins (1 cm)
155 $margin = 28.35/$this->k;
156 $this->SetMargins($margin,$margin);
157 // Interior cell margin (1 mm)
158 $this->cMargin = $margin/10;
159 // Line width (0.2 mm)
160 $this->LineWidth = .567/$this->k;
161 // Automatic page break
162 $this->SetAutoPageBreak(true,2*$margin);
163 // Default display mode
164 $this->SetDisplayMode('default');
165 // Enable compression
166 $this->SetCompression(true);
167 // Set default PDF version number
168 $this->PDFVersion = '1.3';
169 }
170
171 function SetMargins($left, $top, $right=null)
172 {
173 // Set left, top and right margins
174 $this->lMargin = $left;
175 $this->tMargin = $top;
176 if($right===null)
177 $right = $left;
178 $this->rMargin = $right;
179 }
180
181 function SetLeftMargin($margin)
182 {
183 // Set left margin
184 $this->lMargin = $margin;
185 if($this->page>0 && $this->x<$margin)
186 $this->x = $margin;
187 }
188
189 function SetTopMargin($margin)
190 {
191 // Set top margin
192 $this->tMargin = $margin;
193 }
194
195 function SetRightMargin($margin)
196 {
197 // Set right margin
198 $this->rMargin = $margin;
199 }
200
201 function SetAutoPageBreak($auto, $margin=0)
202 {
203 // Set auto page break mode and triggering margin
204 $this->AutoPageBreak = $auto;
205 $this->bMargin = $margin;
206 $this->PageBreakTrigger = $this->h-$margin;
207 }
208
209 function SetDisplayMode($zoom, $layout='default')
210 {
211 // Set display mode in viewer
212 if($zoom=='fullpage' || $zoom=='fullwidth' || $zoom=='real' || $zoom=='default' || !is_string($zoom))
213 $this->ZoomMode = $zoom;
214 else
215 $this->Error('Incorrect zoom display mode: '.$zoom);
216 if($layout=='single' || $layout=='continuous' || $layout=='two' || $layout=='default')
217 $this->LayoutMode = $layout;
218 else
219 $this->Error('Incorrect layout display mode: '.$layout);
220 }
221
222 function SetCompression($compress)
223 {
224 // Set page compression
225 if(function_exists('gzcompress'))
226 $this->compress = $compress;
227 else
228 $this->compress = false;
229 }
230
231 function SetTitle($title, $isUTF8=false)
232 {
233 // Title of document
234 if($isUTF8)
235 $title = $this->_UTF8toUTF16($title);
236 $this->title = $title;
237 }
238
239 function SetSubject($subject, $isUTF8=false)
240 {
241 // Subject of document
242 if($isUTF8)
243 $subject = $this->_UTF8toUTF16($subject);
244 $this->subject = $subject;
245 }
246
247 function SetAuthor($author, $isUTF8=false)
248 {
249 // Author of document
250 if($isUTF8)
251 $author = $this->_UTF8toUTF16($author);
252 $this->author = $author;
253 }
254
255 function SetKeywords($keywords, $isUTF8=false)
256 {
257 // Keywords of document
258 if($isUTF8)
259 $keywords = $this->_UTF8toUTF16($keywords);
260 $this->keywords = $keywords;
261 }
262
263 function SetCreator($creator, $isUTF8=false)
264 {
265 // Creator of document
266 if($isUTF8)
267 $creator = $this->_UTF8toUTF16($creator);
268 $this->creator = $creator;
269 }
270
271 function AliasNbPages($alias='{nb}')
272 {
273 // Define an alias for total number of pages
274 $this->AliasNbPages = $alias;
275 }
276
277 function Error($msg)
278 {
279 // Fatal error
280 die('<b>FPDF error:</b> '.$msg);
281 }
282
283 function Open()
284 {
285 // Begin document
286 $this->state = 1;
287 }
288
289 function Close()
290 {
291 // Terminate document
292 if($this->state==3)
293 return;
294 if($this->page==0)
295 $this->AddPage();
296 // Page footer
297 $this->InFooter = true;
298 $this->Footer();
299 $this->InFooter = false;
300 // Close page
301 $this->_endpage();
302 // Close document
303 $this->_enddoc();
304 }
305
306 function AddPage($orientation='', $size='')
307 {
308 //echo '<pre>'; print_r( $this ); echo '</pre>';
309 // Start a new page
310 if($this->state==0)
311 $this->Open();
312 $family = $this->FontFamily;
313 $style = $this->FontStyle.($this->underline ? 'U' : '');
314 $fontsize = $this->FontSizePt;
315 $lw = $this->LineWidth;
316 $dc = $this->DrawColor;
317 $fc = $this->FillColor;
318 $tc = $this->TextColor;
319 $cf = $this->ColorFlag;
320 if($this->page>0)
321 {
322 // Page footer
323 $this->InFooter = true;
324 $this->Footer();
325 $this->InFooter = false;
326 // Close page
327 $this->_endpage();
328 }
329 // Start new page
330 $this->_beginpage($orientation,$size);
331 // Set line cap style to square
332 $this->_out('2 J');
333 // Set line width
334 $this->LineWidth = $lw;
335 $this->_out(sprintf('%.2F w',$lw*$this->k));
336 // Set font
337 if($family)
338 $this->SetFont($family,$style,$fontsize);
339 // Set colors
340 $this->DrawColor = $dc;
341 if($dc!='0 G')
342 $this->_out($dc);
343 $this->FillColor = $fc;
344 if($fc!='0 g')
345 $this->_out($fc);
346 $this->TextColor = $tc;
347 $this->ColorFlag = $cf;
348 // Page header
349 $this->InHeader = true;
350 if ( isset( $this->page_status ) && $this->page_status == 'yes' ) {
351 $this->Header2();
352 } else {
353 $this->Header();
354 }
355
356 $this->InHeader = false;
357 // Restore line width
358 if($this->LineWidth!=$lw)
359 {
360 $this->LineWidth = $lw;
361 $this->_out(sprintf('%.2F w',$lw*$this->k));
362 }
363 // Restore font
364 if($family)
365 $this->SetFont($family,$style,$fontsize);
366 // Restore colors
367 if($this->DrawColor!=$dc)
368 {
369 $this->DrawColor = $dc;
370 $this->_out($dc);
371 }
372 if($this->FillColor!=$fc)
373 {
374 $this->FillColor = $fc;
375 $this->_out($fc);
376 }
377 $this->TextColor = $tc;
378 $this->ColorFlag = $cf;
379 }
380
381 function Header()
382 {
383 // To be implemented in your own inherited class
384
385 }
386
387 function Footer()
388 {
389 // To be implemented in your own inherited class
390 }
391
392 function PageNo()
393 {
394 // Get current page number
395 return $this->page;
396 }
397
398 function SetDrawColor($r, $g=null, $b=null)
399 {
400 // Set color for all stroking operations
401 if(($r==0 && $g==0 && $b==0) || $g===null)
402 $this->DrawColor = sprintf('%.3F G',$r/255);
403 else
404 $this->DrawColor = sprintf('%.3F %.3F %.3F RG',$r/255,$g/255,$b/255);
405 if($this->page>0)
406 $this->_out($this->DrawColor);
407 }
408
409 function SetFillColor($r, $g=null, $b=null)
410 {
411 // Set color for all filling operations
412 if(($r==0 && $g==0 && $b==0) || $g===null)
413 $this->FillColor = sprintf('%.3F g',$r/255);
414 else
415 $this->FillColor = sprintf('%.3F %.3F %.3F rg',$r/255,$g/255,$b/255);
416 $this->ColorFlag = ($this->FillColor!=$this->TextColor);
417 if($this->page>0)
418 $this->_out($this->FillColor);
419 }
420
421 function SetTextColor($r, $g=null, $b=null)
422 {
423 // Set color for text
424 if(($r==0 && $g==0 && $b==0) || $g===null)
425 $this->TextColor = sprintf('%.3F g',$r/255);
426 else
427 $this->TextColor = sprintf('%.3F %.3F %.3F rg',$r/255,$g/255,$b/255);
428 $this->ColorFlag = ($this->FillColor!=$this->TextColor);
429 }
430
431 function GetStringWidth($s)
432 {
433 // Get width of a string in the current font
434 $s = (string)$s;
435 $cw = &$this->CurrentFont['cw'];
436 $w = 0;
437 $l = strlen($s);
438 for($i=0;$i<$l;$i++)
439 $w += $cw[$s[$i]];
440 return $w*$this->FontSize/1000;
441 }
442
443 function SetLineWidth($width)
444 {
445 // Set line width
446 $this->LineWidth = $width;
447 if($this->page>0)
448 $this->_out(sprintf('%.2F w',$width*$this->k));
449 }
450
451 function Line($x1, $y1, $x2, $y2)
452 {
453 // Draw a line
454 $this->_out(sprintf('%.2F %.2F m %.2F %.2F l S',$x1*$this->k,($this->h-$y1)*$this->k,$x2*$this->k,($this->h-$y2)*$this->k));
455 }
456
457 function Rect($x, $y, $w, $h, $style='')
458 {
459 // Draw a rectangle
460 if($style=='F')
461 $op = 'f';
462 elseif($style=='FD' || $style=='DF')
463 $op = 'B';
464 else
465 $op = 'S';
466 $this->_out(sprintf('%.2F %.2F %.2F %.2F re %s',$x*$this->k,($this->h-$y)*$this->k,$w*$this->k,-$h*$this->k,$op));
467 }
468
469 function AddFont($family, $style='', $file='')
470 {
471 // Add a TrueType, OpenType or Type1 font
472 $family = strtolower($family);
473 if($file=='')
474 $file = str_replace(' ','',$family).strtolower($style).'.php';
475 $style = strtoupper($style);
476 if($style=='IB')
477 $style = 'BI';
478 $fontkey = $family.$style;
479 if(isset($this->fonts[$fontkey]))
480 return;
481 $info = $this->_loadfont($file);
482 $info['i'] = count($this->fonts)+1;
483 if(!empty($info['diff']))
484 {
485 // Search existing encodings
486 $n = array_search($info['diff'],$this->diffs);
487 if(!$n)
488 {
489 $n = count($this->diffs)+1;
490 $this->diffs[$n] = $info['diff'];
491 }
492 $info['diffn'] = $n;
493 }
494 if(!empty($info['file']))
495 {
496 // Embedded font
497 if($info['type']=='TrueType')
498 $this->FontFiles[$info['file']] = array('length1'=>$info['originalsize']);
499 else
500 $this->FontFiles[$info['file']] = array('length1'=>$info['size1'], 'length2'=>$info['size2']);
501 }
502 $this->fonts[$fontkey] = $info;
503 }
504
505 function SetFont($family, $style='', $size=0)
506 {
507 // Select a font; size given in points
508 if($family=='')
509 $family = $this->FontFamily;
510 else
511 $family = strtolower($family);
512 $style = strtoupper($style);
513 if(strpos($style,'U')!==false)
514 {
515 $this->underline = true;
516 $style = str_replace('U','',$style);
517 }
518 else
519 $this->underline = false;
520 if($style=='IB')
521 $style = 'BI';
522 if($size==0)
523 $size = $this->FontSizePt;
524 // Test if font is already selected
525 if($this->FontFamily==$family && $this->FontStyle==$style && $this->FontSizePt==$size)
526 return;
527 // Test if font is already loaded
528 $fontkey = $family.$style;
529 if(!isset($this->fonts[$fontkey]))
530 {
531 // Test if one of the core fonts
532 if($family=='arial')
533 $family = 'helvetica';
534 if(in_array($family,$this->CoreFonts))
535 {
536 if($family=='symbol' || $family=='zapfdingbats')
537 $style = '';
538 $fontkey = $family.$style;
539 if(!isset($this->fonts[$fontkey]))
540 $this->AddFont($family,$style);
541 }
542 else
543 $this->Error('Undefined font: '.$family.' '.$style);
544 }
545 // Select it
546 $this->FontFamily = $family;
547 $this->FontStyle = $style;
548 $this->FontSizePt = $size;
549 $this->FontSize = $size/$this->k;
550 $this->CurrentFont = &$this->fonts[$fontkey];
551 if($this->page>0)
552 $this->_out(sprintf('BT /F%d %.2F Tf ET',$this->CurrentFont['i'],$this->FontSizePt));
553 }
554
555 function SetFontSize($size)
556 {
557 // Set font size in points
558 if($this->FontSizePt==$size)
559 return;
560 $this->FontSizePt = $size;
561 $this->FontSize = $size/$this->k;
562 if($this->page>0)
563 $this->_out(sprintf('BT /F%d %.2F Tf ET',$this->CurrentFont['i'],$this->FontSizePt));
564 }
565
566 function AddLink()
567 {
568 // Create a new internal link
569 $n = count($this->links)+1;
570 $this->links[$n] = array(0, 0);
571 return $n;
572 }
573
574 function SetLink($link, $y=0, $page=-1)
575 {
576 // Set destination of internal link
577 if($y==-1)
578 $y = $this->y;
579 if($page==-1)
580 $page = $this->page;
581 $this->links[$link] = array($page, $y);
582 }
583
584 function Link($x, $y, $w, $h, $link)
585 {
586 // Put a link on the page
587 $this->PageLinks[$this->page][] = array($x*$this->k, $this->hPt-$y*$this->k, $w*$this->k, $h*$this->k, $link);
588 }
589
590 function Text($x, $y, $txt)
591 {
592 // Output a string
593 $s = sprintf('BT %.2F %.2F Td (%s) Tj ET',$x*$this->k,($this->h-$y)*$this->k,$this->_escape($txt));
594 if($this->underline && $txt!='')
595 $s .= ' '.$this->_dounderline($x,$y,$txt);
596 if($this->ColorFlag)
597 $s = 'q '.$this->TextColor.' '.$s.' Q';
598 $this->_out($s);
599 }
600
601 function AcceptPageBreak()
602 {
603 // Accept automatic page break or not
604 return $this->AutoPageBreak;
605 }
606
607 function Cell($w, $h=0, $txt='', $border=0, $ln=0, $align='', $fill=false, $link='')
608 {
609 // Output a cell
610
611 $k = $this->k;
612 if($this->y+$h>$this->PageBreakTrigger && !$this->InHeader && !$this->InFooter && $this->AcceptPageBreak())
613 {
614 // Automatic page break
615 $x = $this->x;
616 $ws = $this->ws;
617 if($ws>0)
618 {
619 $this->ws = 0;
620 $this->_out('0 Tw');
621 }
622 $this->AddPage($this->CurOrientation,$this->CurPageSize);
623 $this->x = $x;
624 if($ws>0)
625 {
626 $this->ws = $ws;
627 $this->_out(sprintf('%.3F Tw',$ws*$k));
628 }
629 }
630 if($w==0)
631 $w = $this->w-$this->rMargin-$this->x;
632 $s = '';
633 if($fill || $border==1)
634 {
635 if($fill)
636 $op = ($border==1) ? 'B' : 'f';
637 else
638 $op = 'S';
639 $s = sprintf('%.2F %.2F %.2F %.2F re %s ',$this->x*$k,($this->h-$this->y)*$k,$w*$k,-$h*$k,$op);
640 }
641
642 if(is_string($border))
643 {
644 $x = $this->x;
645 $y = $this->y;
646 if(strpos($border,'L')!==false)
647 $s .= sprintf('%.2F %.2F m %.2F %.2F l S ',$x*$k,($this->h-$y)*$k,$x*$k,($this->h-($y+$h))*$k);
648 if(strpos($border,'T')!==false)
649 $s .= sprintf('%.2F %.2F m %.2F %.2F l S ',$x*$k,($this->h-$y)*$k,($x+$w)*$k,($this->h-$y)*$k);
650 if(strpos($border,'R')!==false)
651 $s .= sprintf('%.2F %.2F m %.2F %.2F l S ',($x+$w)*$k,($this->h-$y)*$k,($x+$w)*$k,($this->h-($y+$h))*$k);
652 if(strpos($border,'B')!==false)
653 $s .= sprintf('%.2F %.2F m %.2F %.2F l S ',$x*$k,($this->h-($y+$h))*$k,($x+$w)*$k,($this->h-($y+$h))*$k);
654 }
655 if($txt!=='')
656 {
657 if($align=='R')
658 $dx = $w-$this->cMargin-$this->GetStringWidth($txt);
659 elseif($align=='C')
660 $dx = ($w-$this->GetStringWidth($txt))/2;
661 else
662 $dx = $this->cMargin;
663 if($this->ColorFlag)
664 $s .= 'q '.$this->TextColor.' ';
665 $txt2 = str_replace(')','\\)',str_replace('(','\\(',str_replace('\\','\\\\',$txt)));
666 $s .= sprintf('BT %.2F %.2F Td (%s) Tj ET',($this->x+$dx)*$k,($this->h-($this->y+.5*$h+.3*$this->FontSize))*$k,$txt2);
667 if($this->underline)
668 $s .= ' '.$this->_dounderline($this->x+$dx,$this->y+.5*$h+.3*$this->FontSize,$txt);
669 if($this->ColorFlag)
670 $s .= ' Q';
671 if($link)
672 $this->Link($this->x+$dx,$this->y+.5*$h-.5*$this->FontSize,$this->GetStringWidth($txt),$this->FontSize,$link);
673 }
674
675 if($s)
676 $this->_out($s);
677 $this->lasth = $h;
678 if($ln>0)
679 {
680 // Go to next line
681 $this->y += $h;
682 if($ln==1)
683 $this->x = $this->lMargin;
684 }
685 else
686 $this->x += $w;
687 }
688
689 function MultiCell($w, $h, $txt, $border=0, $align='J', $fill=false)
690 {
691 // Output text with automatic or explicit line breaks
692 $cw = &$this->CurrentFont['cw'];
693 if($w==0)
694 $w = $this->w-$this->rMargin-$this->x;
695 $wmax = ($w-2*$this->cMargin)*1000/$this->FontSize;
696 $s = str_replace("\r",'',$txt);
697 $nb = strlen($s);
698 if($nb>0 && $s[$nb-1]=="\n")
699 $nb--;
700 $b = 0;
701 if($border)
702 {
703 if($border==1)
704 {
705 $border = 'LTRB';
706 $b = 'LRT';
707 $b2 = 'LR';
708 }
709 else
710 {
711 $b2 = '';
712 if(strpos($border,'L')!==false)
713 $b2 .= 'L';
714 if(strpos($border,'R')!==false)
715 $b2 .= 'R';
716 $b = (strpos($border,'T')!==false) ? $b2.'T' : $b2;
717 }
718 }
719 $sep = -1;
720 $i = 0;
721 $j = 0;
722 $l = 0;
723 $ns = 0;
724 $nl = 1;
725 while($i<$nb)
726 {
727 // Get next character
728 $c = $s[$i];
729 if($c=="\n")
730 {
731 // Explicit line break
732 if($this->ws>0)
733 {
734 $this->ws = 0;
735 $this->_out('0 Tw');
736 }
737 $this->Cell($w,$h,substr($s,$j,$i-$j),$b,2,$align,$fill);
738 $i++;
739 $sep = -1;
740 $j = $i;
741 $l = 0;
742 $ns = 0;
743 $nl++;
744 if($border && $nl==2)
745 $b = $b2;
746 continue;
747 }
748 if($c==' ')
749 {
750 $sep = $i;
751 $ls = $l;
752 $ns++;
753 }
754 $l += $cw[$c];
755 if($l>$wmax)
756 {
757 // Automatic line break
758 if($sep==-1)
759 {
760 if($i==$j)
761 $i++;
762 if($this->ws>0)
763 {
764 $this->ws = 0;
765 $this->_out('0 Tw');
766 }
767 $this->Cell($w,$h,substr($s,$j,$i-$j),$b,2,$align,$fill);
768 }
769 else
770 {
771 if($align=='J')
772 {
773 $this->ws = ($ns>1) ? ($wmax-$ls)/1000*$this->FontSize/($ns-1) : 0;
774 $this->_out(sprintf('%.3F Tw',$this->ws*$this->k));
775 }
776 $this->Cell($w,$h,substr($s,$j,$sep-$j),$b,2,$align,$fill);
777 $i = $sep+1;
778 }
779 $sep = -1;
780 $j = $i;
781 $l = 0;
782 $ns = 0;
783 $nl++;
784 if($border && $nl==2)
785 $b = $b2;
786 }
787 else
788 $i++;
789 }
790 // Last chunk
791 if($this->ws>0)
792 {
793 $this->ws = 0;
794 $this->_out('0 Tw');
795 }
796 if($border && strpos($border,'B')!==false)
797 $b .= 'B';
798 $this->Cell($w,$h,substr($s,$j,$i-$j),$b,2,$align,$fill);
799 $this->x = $this->lMargin;
800 }
801
802 function Write($h, $txt, $link='')
803 {
804 // Output text in flowing mode
805 $cw = &$this->CurrentFont['cw'];
806 $w = $this->w-$this->rMargin-$this->x;
807 $wmax = ($w-2*$this->cMargin)*1000/$this->FontSize;
808 $s = str_replace("\r",'',$txt);
809 $nb = strlen($s);
810 $sep = -1;
811 $i = 0;
812 $j = 0;
813 $l = 0;
814 $nl = 1;
815 while($i<$nb)
816 {
817 // Get next character
818 $c = $s[$i];
819 if($c=="\n")
820 {
821 // Explicit line break
822 $this->Cell($w,$h,substr($s,$j,$i-$j),0,2,'',0,$link);
823 $i++;
824 $sep = -1;
825 $j = $i;
826 $l = 0;
827 if($nl==1)
828 {
829 $this->x = $this->lMargin;
830 $w = $this->w-$this->rMargin-$this->x;
831 $wmax = ($w-2*$this->cMargin)*1000/$this->FontSize;
832 }
833 $nl++;
834 continue;
835 }
836 if($c==' ')
837 $sep = $i;
838 $l += $cw[$c];
839 if($l>$wmax)
840 {
841 // Automatic line break
842 if($sep==-1)
843 {
844 if($this->x>$this->lMargin)
845 {
846 // Move to next line
847 $this->x = $this->lMargin;
848 $this->y += $h;
849 $w = $this->w-$this->rMargin-$this->x;
850 $wmax = ($w-2*$this->cMargin)*1000/$this->FontSize;
851 $i++;
852 $nl++;
853 continue;
854 }
855 if($i==$j)
856 $i++;
857 $this->Cell($w,$h,substr($s,$j,$i-$j),0,2,'',0,$link);
858 }
859 else
860 {
861 $this->Cell($w,$h,substr($s,$j,$sep-$j),0,2,'',0,$link);
862 $i = $sep+1;
863 }
864 $sep = -1;
865 $j = $i;
866 $l = 0;
867 if($nl==1)
868 {
869 $this->x = $this->lMargin;
870 $w = $this->w-$this->rMargin-$this->x;
871 $wmax = ($w-2*$this->cMargin)*1000/$this->FontSize;
872 }
873 $nl++;
874 }
875 else
876 $i++;
877 }
878 // Last chunk
879 if($i!=$j)
880 $this->Cell($l/1000*$this->FontSize,$h,substr($s,$j),0,0,'',0,$link);
881 }
882
883 function Ln($h=null)
884 {
885 // Line feed; default value is last cell height
886 $this->x = $this->lMargin;
887 if($h===null)
888 $this->y += $this->lasth;
889 else
890 $this->y += $h;
891 }
892
893 function Image($file, $x=null, $y=null, $w=0, $h=0, $type='', $link='')
894 {
895 // Put an image on the page
896 if(!isset($this->images[$file]))
897 {
898 // First use of this image, get info
899 if($type=='')
900 {
901 $pos = strrpos($file,'.');
902 if(!$pos)
903 $this->Error('Image file has no extension and no type was specified: '.$file);
904 $type = substr($file,$pos+1);
905 }
906 $type = strtolower($type);
907 if($type=='jpeg')
908 $type = 'jpg';
909 $mtd = '_parse'.$type;
910 if(!method_exists($this,$mtd))
911 $this->Error('Unsupported image type: '.$type);
912 $info = $this->$mtd($file);
913 $info['i'] = count($this->images)+1;
914 $this->images[$file] = $info;
915 }
916 else
917 $info = $this->images[$file];
918
919 // Automatic width and height calculation if needed
920 if($w==0 && $h==0)
921 {
922 // Put image at 96 dpi
923 $w = -96;
924 $h = -96;
925 }
926 if($w<0)
927 $w = -$info['w']*72/$w/$this->k;
928 if($h<0)
929 $h = -$info['h']*72/$h/$this->k;
930 if($w==0)
931 $w = $h*$info['w']/$info['h'];
932 if($h==0)
933 $h = $w*$info['h']/$info['w'];
934
935 // Flowing mode
936 if($y===null)
937 {
938 if($this->y+$h>$this->PageBreakTrigger && !$this->InHeader && !$this->InFooter && $this->AcceptPageBreak())
939 {
940 // Automatic page break
941 $x2 = $this->x;
942 $this->AddPage($this->CurOrientation,$this->CurPageSize);
943 $this->x = $x2;
944 }
945 $y = $this->y;
946 $this->y += $h;
947 }
948
949 if($x===null)
950 $x = $this->x;
951 $this->_out(sprintf('q %.2F 0 0 %.2F %.2F %.2F cm /I%d Do Q',$w*$this->k,$h*$this->k,$x*$this->k,($this->h-($y+$h))*$this->k,$info['i']));
952 if($link)
953 $this->Link($x,$y,$w,$h,$link);
954 }
955
956 function GetX()
957 {
958 // Get x position
959 return $this->x;
960 }
961
962 function SetX($x)
963 {
964 // Set x position
965 if($x>=0)
966 $this->x = $x;
967 else
968 $this->x = $this->w+$x;
969 }
970
971 function GetY()
972 {
973 // Get y position
974 return $this->y;
975 }
976
977 function SetY($y)
978 {
979 // Set y position and reset x
980 $this->x = $this->lMargin;
981 if($y>=0)
982 $this->y = $y;
983 else
984 $this->y = $this->h+$y;
985 }
986
987 function SetXY($x, $y)
988 {
989 // Set x and y positions
990 $this->SetY($y);
991 $this->SetX($x);
992 }
993
994 function Output($name='', $dest='')
995 {
996 // Output PDF to some destination
997 if($this->state<3)
998 $this->Close();
999 $dest = strtoupper($dest);
1000 if($dest=='')
1001 {
1002 if($name=='')
1003 {
1004 $name = 'doc.pdf';
1005 $dest = 'I';
1006 }
1007 else
1008 $dest = 'F';
1009 }
1010 switch($dest)
1011 {
1012 case 'I':
1013 // Send to standard output
1014 $this->_checkoutput();
1015 if(PHP_SAPI!='cli')
1016 {
1017 // We send to a browser
1018 header('Content-Type: application/pdf');
1019 header('Content-Disposition: inline; filename="'.$name.'"');
1020 header('Cache-Control: private, max-age=0, must-revalidate');
1021 header('Pragma: public');
1022 }
1023 echo $this->buffer;
1024 break;
1025 case 'D':
1026 // Download file
1027 $this->_checkoutput();
1028 header('Content-Type: application/x-download');
1029 header('Content-Disposition: attachment; filename="'.$name.'"');
1030 header('Cache-Control: private, max-age=0, must-revalidate');
1031 header('Pragma: public');
1032 echo $this->buffer;
1033 break;
1034 case 'F':
1035 // Save to local file
1036 $f = fopen($name,'wb');
1037 if(!$f)
1038 $this->Error('Unable to create output file: '.$name);
1039 fwrite($f,$this->buffer,strlen($this->buffer));
1040 fclose($f);
1041 break;
1042 case 'S':
1043 // Return as a string
1044 return $this->buffer;
1045 default:
1046 $this->Error('Incorrect output destination: '.$dest);
1047 }
1048 return '';
1049 }
1050
1051 /*******************************************************************************
1052 * *
1053 * Protected methods *
1054 * *
1055 *******************************************************************************/
1056 function _dochecks()
1057 {
1058 // Check availability of %F
1059 if(sprintf('%.1F',1.0)!='1.0')
1060 $this->Error('This version of PHP is not supported');
1061 // Check mbstring overloading
1062 if(ini_get('mbstring.func_overload') & 2)
1063 $this->Error('mbstring overloading must be disabled');
1064 // Ensure runtime magic quotes are disabled
1065 if(get_magic_quotes_runtime())
1066 @set_magic_quotes_runtime(0);
1067 }
1068
1069 function _checkoutput()
1070 {
1071 if(PHP_SAPI!='cli')
1072 {
1073 if(headers_sent($file,$line))
1074 $this->Error("Some data has already been output, can't send PDF file (output started at $file:$line)");
1075 }
1076 if(ob_get_length())
1077 {
1078 // The output buffer is not empty
1079 if(preg_match('/^(\xEF\xBB\xBF)?\s*$/',ob_get_contents()))
1080 {
1081 // It contains only a UTF-8 BOM and/or whitespace, let's clean it
1082 ob_clean();
1083 }
1084 else
1085 $this->Error("Some data has already been output, can't send PDF file");
1086 }
1087 }
1088
1089 function _getpagesize($size)
1090 {
1091 if(is_string($size))
1092 {
1093 $size = strtolower($size);
1094 if(!isset($this->StdPageSizes[$size]))
1095 $this->Error('Unknown page size: '.$size);
1096 $a = $this->StdPageSizes[$size];
1097 return array($a[0]/$this->k, $a[1]/$this->k);
1098 }
1099 else
1100 {
1101 if($size[0]>$size[1])
1102 return array($size[1], $size[0]);
1103 else
1104 return $size;
1105 }
1106 }
1107
1108 function _beginpage($orientation, $size)
1109 {
1110 $this->page++;
1111 $this->pages[$this->page] = '';
1112 $this->state = 2;
1113 $this->x = $this->lMargin;
1114 $this->y = $this->tMargin;
1115 $this->FontFamily = '';
1116 // Check page size and orientation
1117 if($orientation=='')
1118 $orientation = $this->DefOrientation;
1119 else
1120 $orientation = strtoupper($orientation[0]);
1121 if($size=='')
1122 $size = $this->DefPageSize;
1123 else
1124 $size = $this->_getpagesize($size);
1125 if($orientation!=$this->CurOrientation || $size[0]!=$this->CurPageSize[0] || $size[1]!=$this->CurPageSize[1])
1126 {
1127 // New size or orientation
1128 if($orientation=='P')
1129 {
1130 $this->w = $size[0];
1131 $this->h = $size[1];
1132 }
1133 else
1134 {
1135 $this->w = $size[1];
1136 $this->h = $size[0];
1137 }
1138 $this->wPt = $this->w*$this->k;
1139 $this->hPt = $this->h*$this->k;
1140 $this->PageBreakTrigger = $this->h-$this->bMargin;
1141 $this->CurOrientation = $orientation;
1142 $this->CurPageSize = $size;
1143 }
1144 if($orientation!=$this->DefOrientation || $size[0]!=$this->DefPageSize[0] || $size[1]!=$this->DefPageSize[1])
1145 $this->PageSizes[$this->page] = array($this->wPt, $this->hPt);
1146 }
1147
1148 function _endpage()
1149 {
1150 $this->state = 1;
1151 }
1152
1153 function _loadfont($font)
1154 {
1155 // Load a font definition file from the font directory
1156 include($this->fontpath.$font);
1157 $a = get_defined_vars();
1158 if(!isset($a['name']))
1159 $this->Error('Could not include font definition file');
1160 return $a;
1161 }
1162
1163 function _escape($s)
1164 {
1165 // Escape special characters in strings
1166 $s = str_replace('\\','\\\\',$s);
1167 $s = str_replace('(','\\(',$s);
1168 $s = str_replace(')','\\)',$s);
1169 $s = str_replace("\r",'\\r',$s);
1170 return $s;
1171 }
1172
1173 function _textstring($s)
1174 {
1175 // Format a text string
1176 return '('.$this->_escape($s).')';
1177 }
1178
1179 function _UTF8toUTF16($s)
1180 {
1181 // Convert UTF-8 to UTF-16BE with BOM
1182 $res = "\xFE\xFF";
1183 $nb = strlen($s);
1184 $i = 0;
1185 while($i<$nb)
1186 {
1187 $c1 = ord($s[$i++]);
1188 if($c1>=224)
1189 {
1190 // 3-byte character
1191 $c2 = ord($s[$i++]);
1192 $c3 = ord($s[$i++]);
1193 $res .= chr((($c1 & 0x0F)<<4) + (($c2 & 0x3C)>>2));
1194 $res .= chr((($c2 & 0x03)<<6) + ($c3 & 0x3F));
1195 }
1196 elseif($c1>=192)
1197 {
1198 // 2-byte character
1199 $c2 = ord($s[$i++]);
1200 $res .= chr(($c1 & 0x1C)>>2);
1201 $res .= chr((($c1 & 0x03)<<6) + ($c2 & 0x3F));
1202 }
1203 else
1204 {
1205 // Single-byte character
1206 $res .= "\0".chr($c1);
1207 }
1208 }
1209 return $res;
1210 }
1211
1212 function _dounderline($x, $y, $txt)
1213 {
1214 // Underline text
1215 $up = $this->CurrentFont['up'];
1216 $ut = $this->CurrentFont['ut'];
1217 $w = $this->GetStringWidth($txt)+$this->ws*substr_count($txt,' ');
1218 return sprintf('%.2F %.2F %.2F %.2F re f',$x*$this->k,($this->h-($y-$up/1000*$this->FontSize))*$this->k,$w*$this->k,-$ut/1000*$this->FontSizePt);
1219 }
1220
1221 function _parsejpg($file)
1222 {
1223 // Extract info from a JPEG file
1224 $a = getimagesize($file);
1225 if(!$a)
1226 $this->Error('Missing or incorrect image file: '.$file);
1227 if($a[2]!=2)
1228 $this->Error('Not a JPEG file: '.$file);
1229 if(!isset($a['channels']) || $a['channels']==3)
1230 $colspace = 'DeviceRGB';
1231 elseif($a['channels']==4)
1232 $colspace = 'DeviceCMYK';
1233 else
1234 $colspace = 'DeviceGray';
1235 $bpc = isset($a['bits']) ? $a['bits'] : 8;
1236 $data = file_get_contents($file);
1237 return array('w'=>$a[0], 'h'=>$a[1], 'cs'=>$colspace, 'bpc'=>$bpc, 'f'=>'DCTDecode', 'data'=>$data);
1238 }
1239
1240 function _parsepng($file)
1241 {
1242 // Extract info from a PNG file
1243 $f = fopen($file,'rb');
1244 if(!$f)
1245 $this->Error('Can\'t open image file: '.$file);
1246 $info = $this->_parsepngstream($f,$file);
1247 fclose($f);
1248 return $info;
1249 }
1250
1251 function _parsepngstream($f, $file)
1252 {
1253 // Check signature
1254 if($this->_readstream($f,8)!=chr(137).'PNG'.chr(13).chr(10).chr(26).chr(10))
1255 $this->Error('Not a PNG file: '.$file);
1256
1257 // Read header chunk
1258 $this->_readstream($f,4);
1259 if($this->_readstream($f,4)!='IHDR')
1260 $this->Error('Incorrect PNG file: '.$file);
1261 $w = $this->_readint($f);
1262 $h = $this->_readint($f);
1263 $bpc = ord($this->_readstream($f,1));
1264 if($bpc>8)
1265 $this->Error('16-bit depth not supported: '.$file);
1266 $ct = ord($this->_readstream($f,1));
1267 if($ct==0 || $ct==4)
1268 $colspace = 'DeviceGray';
1269 elseif($ct==2 || $ct==6)
1270 $colspace = 'DeviceRGB';
1271 elseif($ct==3)
1272 $colspace = 'Indexed';
1273 else
1274 $this->Error('Unknown color type: '.$file);
1275 if(ord($this->_readstream($f,1))!=0)
1276 $this->Error('Unknown compression method: '.$file);
1277 if(ord($this->_readstream($f,1))!=0)
1278 $this->Error('Unknown filter method: '.$file);
1279 if(ord($this->_readstream($f,1))!=0)
1280 $this->Error('Interlacing not supported: '.$file);
1281 $this->_readstream($f,4);
1282 $dp = '/Predictor 15 /Colors '.($colspace=='DeviceRGB' ? 3 : 1).' /BitsPerComponent '.$bpc.' /Columns '.$w;
1283
1284 // Scan chunks looking for palette, transparency and image data
1285 $pal = '';
1286 $trns = '';
1287 $data = '';
1288 do
1289 {
1290 $n = $this->_readint($f);
1291 $type = $this->_readstream($f,4);
1292 if($type=='PLTE')
1293 {
1294 // Read palette
1295 $pal = $this->_readstream($f,$n);
1296 $this->_readstream($f,4);
1297 }
1298 elseif($type=='tRNS')
1299 {
1300 // Read transparency info
1301 $t = $this->_readstream($f,$n);
1302 if($ct==0)
1303 $trns = array(ord(substr($t,1,1)));
1304 elseif($ct==2)
1305 $trns = array(ord(substr($t,1,1)), ord(substr($t,3,1)), ord(substr($t,5,1)));
1306 else
1307 {
1308 $pos = strpos($t,chr(0));
1309 if($pos!==false)
1310 $trns = array($pos);
1311 }
1312 $this->_readstream($f,4);
1313 }
1314 elseif($type=='IDAT')
1315 {
1316 // Read image data block
1317 $data .= $this->_readstream($f,$n);
1318 $this->_readstream($f,4);
1319 }
1320 elseif($type=='IEND')
1321 break;
1322 else
1323 $this->_readstream($f,$n+4);
1324 }
1325 while($n);
1326
1327 if($colspace=='Indexed' && empty($pal))
1328 $this->Error('Missing palette in '.$file);
1329 $info = array('w'=>$w, 'h'=>$h, 'cs'=>$colspace, 'bpc'=>$bpc, 'f'=>'FlateDecode', 'dp'=>$dp, 'pal'=>$pal, 'trns'=>$trns);
1330 if($ct>=4)
1331 {
1332 // Extract alpha channel
1333 if(!function_exists('gzuncompress'))
1334 $this->Error('Zlib not available, can\'t handle alpha channel: '.$file);
1335 $data = gzuncompress($data);
1336 $color = '';
1337 $alpha = '';
1338 if($ct==4)
1339 {
1340 // Gray image
1341 $len = 2*$w;
1342 for($i=0;$i<$h;$i++)
1343 {
1344 $pos = (1+$len)*$i;
1345 $color .= $data[$pos];
1346 $alpha .= $data[$pos];
1347 $line = substr($data,$pos+1,$len);
1348 $color .= preg_replace('/(.)./s','$1',$line);
1349 $alpha .= preg_replace('/.(.)/s','$1',$line);
1350 }
1351 }
1352 else
1353 {
1354 // RGB image
1355 $len = 4*$w;
1356 for($i=0;$i<$h;$i++)
1357 {
1358 $pos = (1+$len)*$i;
1359 $color .= $data[$pos];
1360 $alpha .= $data[$pos];
1361 $line = substr($data,$pos+1,$len);
1362 $color .= preg_replace('/(.{3})./s','$1',$line);
1363 $alpha .= preg_replace('/.{3}(.)/s','$1',$line);
1364 }
1365 }
1366 unset($data);
1367 $data = gzcompress($color);
1368 $info['smask'] = gzcompress($alpha);
1369 if($this->PDFVersion<'1.4')
1370 $this->PDFVersion = '1.4';
1371 }
1372 $info['data'] = $data;
1373 return $info;
1374 }
1375
1376 function _readstream($f, $n)
1377 {
1378 // Read n bytes from stream
1379 $res = '';
1380 while($n>0 && !feof($f))
1381 {
1382 $s = fread($f,$n);
1383 if($s===false)
1384 $this->Error('Error while reading stream');
1385 $n -= strlen($s);
1386 $res .= $s;
1387 }
1388 if($n>0)
1389 $this->Error('Unexpected end of stream');
1390 return $res;
1391 }
1392
1393 function _readint($f)
1394 {
1395 // Read a 4-byte integer from stream
1396 $a = unpack('Ni',$this->_readstream($f,4));
1397 return $a['i'];
1398 }
1399
1400 function _parsegif($file)
1401 {
1402 // Extract info from a GIF file (via PNG conversion)
1403 if(!function_exists('imagepng'))
1404 $this->Error('GD extension is required for GIF support');
1405 if(!function_exists('imagecreatefromgif'))
1406 $this->Error('GD has no GIF read support');
1407 $im = imagecreatefromgif($file);
1408 if(!$im)
1409 $this->Error('Missing or incorrect image file: '.$file);
1410 imageinterlace($im,0);
1411 $f = @fopen('php://temp','rb+');
1412 if($f)
1413 {
1414 // Perform conversion in memory
1415 ob_start();
1416 imagepng($im);
1417 $data = ob_get_clean();
1418 imagedestroy($im);
1419 fwrite($f,$data);
1420 rewind($f);
1421 $info = $this->_parsepngstream($f,$file);
1422 fclose($f);
1423 }
1424 else
1425 {
1426 // Use temporary file
1427 $tmp = tempnam('.','gif');
1428 if(!$tmp)
1429 $this->Error('Unable to create a temporary file');
1430 if(!imagepng($im,$tmp))
1431 $this->Error('Error while saving to temporary file');
1432 imagedestroy($im);
1433 $info = $this->_parsepng($tmp);
1434 unlink($tmp);
1435 }
1436 return $info;
1437 }
1438
1439 function _newobj()
1440 {
1441 // Begin a new object
1442 $this->n++;
1443 $this->offsets[$this->n] = strlen($this->buffer);
1444 $this->_out($this->n.' 0 obj');
1445 }
1446
1447 function _putstream($s)
1448 {
1449 $this->_out('stream');
1450 $this->_out($s);
1451 $this->_out('endstream');
1452 }
1453
1454 function _out($s)
1455 {
1456 // Add a line to the document
1457 if($this->state==2)
1458 $this->pages[$this->page] .= $s."\n";
1459 else
1460 $this->buffer .= $s."\n";
1461 }
1462
1463 function _putpages()
1464 {
1465 $nb = $this->page;
1466 if(!empty($this->AliasNbPages))
1467 {
1468 // Replace number of pages
1469 for($n=1;$n<=$nb;$n++)
1470 $this->pages[$n] = str_replace($this->AliasNbPages,$nb,$this->pages[$n]);
1471 }
1472 if($this->DefOrientation=='P')
1473 {
1474 $wPt = $this->DefPageSize[0]*$this->k;
1475 $hPt = $this->DefPageSize[1]*$this->k;
1476 }
1477 else
1478 {
1479 $wPt = $this->DefPageSize[1]*$this->k;
1480 $hPt = $this->DefPageSize[0]*$this->k;
1481 }
1482 $filter = ($this->compress) ? '/Filter /FlateDecode ' : '';
1483 for($n=1;$n<=$nb;$n++)
1484 {
1485 // Page
1486 $this->_newobj();
1487 $this->_out('<</Type /Page');
1488 $this->_out('/Parent 1 0 R');
1489 if(isset($this->PageSizes[$n]))
1490 $this->_out(sprintf('/MediaBox [0 0 %.2F %.2F]',$this->PageSizes[$n][0],$this->PageSizes[$n][1]));
1491 $this->_out('/Resources 2 0 R');
1492 if(isset($this->PageLinks[$n]))
1493 {
1494 // Links
1495 $annots = '/Annots [';
1496 foreach($this->PageLinks[$n] as $pl)
1497 {
1498 $rect = sprintf('%.2F %.2F %.2F %.2F',$pl[0],$pl[1],$pl[0]+$pl[2],$pl[1]-$pl[3]);
1499 $annots .= '<</Type /Annot /Subtype /Link /Rect ['.$rect.'] /Border [0 0 0] ';
1500 if(is_string($pl[4]))
1501 $annots .= '/A <</S /URI /URI '.$this->_textstring($pl[4]).'>>>>';
1502 else
1503 {
1504 $l = $this->links[$pl[4]];
1505 $h = isset($this->PageSizes[$l[0]]) ? $this->PageSizes[$l[0]][1] : $hPt;
1506 $annots .= sprintf('/Dest [%d 0 R /XYZ 0 %.2F null]>>',1+2*$l[0],$h-$l[1]*$this->k);
1507 }
1508 }
1509 $this->_out($annots.']');
1510 }
1511 if($this->PDFVersion>'1.3')
1512 $this->_out('/Group <</Type /Group /S /Transparency /CS /DeviceRGB>>');
1513 $this->_out('/Contents '.($this->n+1).' 0 R>>');
1514 $this->_out('endobj');
1515 // Page content
1516 $p = ($this->compress) ? gzcompress($this->pages[$n]) : $this->pages[$n];
1517 $this->_newobj();
1518 $this->_out('<<'.$filter.'/Length '.strlen($p).'>>');
1519 $this->_putstream($p);
1520 $this->_out('endobj');
1521 }
1522 // Pages root
1523 $this->offsets[1] = strlen($this->buffer);
1524 $this->_out('1 0 obj');
1525 $this->_out('<</Type /Pages');
1526 $kids = '/Kids [';
1527 for($i=0;$i<$nb;$i++)
1528 $kids .= (3+2*$i).' 0 R ';
1529 $this->_out($kids.']');
1530 $this->_out('/Count '.$nb);
1531 $this->_out(sprintf('/MediaBox [0 0 %.2F %.2F]',$wPt,$hPt));
1532 $this->_out('>>');
1533 $this->_out('endobj');
1534 }
1535
1536 function _putfonts()
1537 {
1538 $nf = $this->n;
1539 foreach($this->diffs as $diff)
1540 {
1541 // Encodings
1542 $this->_newobj();
1543 $this->_out('<</Type /Encoding /BaseEncoding /WinAnsiEncoding /Differences ['.$diff.']>>');
1544 $this->_out('endobj');
1545 }
1546 foreach($this->FontFiles as $file=>$info)
1547 {
1548 // Font file embedding
1549 $this->_newobj();
1550 $this->FontFiles[$file]['n'] = $this->n;
1551 $font = file_get_contents($this->fontpath.$file,true);
1552 if(!$font)
1553 $this->Error('Font file not found: '.$file);
1554 $compressed = (substr($file,-2)=='.z');
1555 if(!$compressed && isset($info['length2']))
1556 $font = substr($font,6,$info['length1']).substr($font,6+$info['length1']+6,$info['length2']);
1557 $this->_out('<</Length '.strlen($font));
1558 if($compressed)
1559 $this->_out('/Filter /FlateDecode');
1560 $this->_out('/Length1 '.$info['length1']);
1561 if(isset($info['length2']))
1562 $this->_out('/Length2 '.$info['length2'].' /Length3 0');
1563 $this->_out('>>');
1564 $this->_putstream($font);
1565 $this->_out('endobj');
1566 }
1567 foreach($this->fonts as $k=>$font)
1568 {
1569 // Font objects
1570 $this->fonts[$k]['n'] = $this->n+1;
1571 $type = $font['type'];
1572 $name = $font['name'];
1573 if($type=='Core')
1574 {
1575 // Core font
1576 $this->_newobj();
1577 $this->_out('<</Type /Font');
1578 $this->_out('/BaseFont /'.$name);
1579 $this->_out('/Subtype /Type1');
1580 if($name!='Symbol' && $name!='ZapfDingbats')
1581 $this->_out('/Encoding /WinAnsiEncoding');
1582 $this->_out('>>');
1583 $this->_out('endobj');
1584 }
1585 elseif($type=='Type1' || $type=='TrueType')
1586 {
1587 // Additional Type1 or TrueType/OpenType font
1588 $this->_newobj();
1589 $this->_out('<</Type /Font');
1590 $this->_out('/BaseFont /'.$name);
1591 $this->_out('/Subtype /'.$type);
1592 $this->_out('/FirstChar 32 /LastChar 255');
1593 $this->_out('/Widths '.($this->n+1).' 0 R');
1594 $this->_out('/FontDescriptor '.($this->n+2).' 0 R');
1595 if(isset($font['diffn']))
1596 $this->_out('/Encoding '.($nf+$font['diffn']).' 0 R');
1597 else
1598 $this->_out('/Encoding /WinAnsiEncoding');
1599 $this->_out('>>');
1600 $this->_out('endobj');
1601 // Widths
1602 $this->_newobj();
1603 $cw = &$font['cw'];
1604 $s = '[';
1605 for($i=32;$i<=255;$i++)
1606 $s .= $cw[chr($i)].' ';
1607 $this->_out($s.']');
1608 $this->_out('endobj');
1609 // Descriptor
1610 $this->_newobj();
1611 $s = '<</Type /FontDescriptor /FontName /'.$name;
1612 foreach($font['desc'] as $k=>$v)
1613 $s .= ' /'.$k.' '.$v;
1614 if(!empty($font['file']))
1615 $s .= ' /FontFile'.($type=='Type1' ? '' : '2').' '.$this->FontFiles[$font['file']]['n'].' 0 R';
1616 $this->_out($s.'>>');
1617 $this->_out('endobj');
1618 }
1619 else
1620 {
1621 // Allow for additional types
1622 $mtd = '_put'.strtolower($type);
1623 if(!method_exists($this,$mtd))
1624 $this->Error('Unsupported font type: '.$type);
1625 $this->$mtd($font);
1626 }
1627 }
1628 }
1629
1630 function _putimages()
1631 {
1632 foreach(array_keys($this->images) as $file)
1633 {
1634 $this->_putimage($this->images[$file]);
1635 unset($this->images[$file]['data']);
1636 unset($this->images[$file]['smask']);
1637 }
1638 }
1639
1640 function _putimage(&$info)
1641 {
1642 $this->_newobj();
1643 $info['n'] = $this->n;
1644 $this->_out('<</Type /XObject');
1645 $this->_out('/Subtype /Image');
1646 $this->_out('/Width '.$info['w']);
1647 $this->_out('/Height '.$info['h']);
1648 if($info['cs']=='Indexed')
1649 $this->_out('/ColorSpace [/Indexed /DeviceRGB '.(strlen($info['pal'])/3-1).' '.($this->n+1).' 0 R]');
1650 else
1651 {
1652 $this->_out('/ColorSpace /'.$info['cs']);
1653 if($info['cs']=='DeviceCMYK')
1654 $this->_out('/Decode [1 0 1 0 1 0 1 0]');
1655 }
1656 $this->_out('/BitsPerComponent '.$info['bpc']);
1657 if(isset($info['f']))
1658 $this->_out('/Filter /'.$info['f']);
1659 if(isset($info['dp']))
1660 $this->_out('/DecodeParms <<'.$info['dp'].'>>');
1661 if(isset($info['trns']) && is_array($info['trns']))
1662 {
1663 $trns = '';
1664 for($i=0;$i<count($info['trns']);$i++)
1665 $trns .= $info['trns'][$i].' '.$info['trns'][$i].' ';
1666 $this->_out('/Mask ['.$trns.']');
1667 }
1668 if(isset($info['smask']))
1669 $this->_out('/SMask '.($this->n+1).' 0 R');
1670 $this->_out('/Length '.strlen($info['data']).'>>');
1671 $this->_putstream($info['data']);
1672 $this->_out('endobj');
1673 // Soft mask
1674 if(isset($info['smask']))
1675 {
1676 $dp = '/Predictor 15 /Colors 1 /BitsPerComponent 8 /Columns '.$info['w'];
1677 $smask = array('w'=>$info['w'], 'h'=>$info['h'], 'cs'=>'DeviceGray', 'bpc'=>8, 'f'=>$info['f'], 'dp'=>$dp, 'data'=>$info['smask']);
1678 $this->_putimage($smask);
1679 }
1680 // Palette
1681 if($info['cs']=='Indexed')
1682 {
1683 $filter = ($this->compress) ? '/Filter /FlateDecode ' : '';
1684 $pal = ($this->compress) ? gzcompress($info['pal']) : $info['pal'];
1685 $this->_newobj();
1686 $this->_out('<<'.$filter.'/Length '.strlen($pal).'>>');
1687 $this->_putstream($pal);
1688 $this->_out('endobj');
1689 }
1690 }
1691
1692 function _putxobjectdict()
1693 {
1694 foreach($this->images as $image)
1695 $this->_out('/I'.$image['i'].' '.$image['n'].' 0 R');
1696 }
1697
1698 function _putresourcedict()
1699 {
1700 $this->_out('/ProcSet [/PDF /Text /ImageB /ImageC /ImageI]');
1701 $this->_out('/Font <<');
1702 foreach($this->fonts as $font)
1703 $this->_out('/F'.$font['i'].' '.$font['n'].' 0 R');
1704 $this->_out('>>');
1705 $this->_out('/XObject <<');
1706 $this->_putxobjectdict();
1707 $this->_out('>>');
1708 }
1709
1710 function _putresources()
1711 {
1712 $this->_putfonts();
1713 $this->_putimages();
1714 // Resource dictionary
1715 $this->offsets[2] = strlen($this->buffer);
1716 $this->_out('2 0 obj');
1717 $this->_out('<<');
1718 $this->_putresourcedict();
1719 $this->_out('>>');
1720 $this->_out('endobj');
1721 }
1722
1723 function _putinfo()
1724 {
1725 $this->_out('/Producer '.$this->_textstring('FPDF '.FPDF_VERSION));
1726 if(!empty($this->title))
1727 $this->_out('/Title '.$this->_textstring($this->title));
1728 if(!empty($this->subject))
1729 $this->_out('/Subject '.$this->_textstring($this->subject));
1730 if(!empty($this->author))
1731 $this->_out('/Author '.$this->_textstring($this->author));
1732 if(!empty($this->keywords))
1733 $this->_out('/Keywords '.$this->_textstring($this->keywords));
1734 if(!empty($this->creator))
1735 $this->_out('/Creator '.$this->_textstring($this->creator));
1736 $this->_out('/CreationDate '.$this->_textstring('D:'.@date('YmdHis')));
1737 }
1738
1739 function _putcatalog()
1740 {
1741 $this->_out('/Type /Catalog');
1742 $this->_out('/Pages 1 0 R');
1743 if($this->ZoomMode=='fullpage')
1744 $this->_out('/OpenAction [3 0 R /Fit]');
1745 elseif($this->ZoomMode=='fullwidth')
1746 $this->_out('/OpenAction [3 0 R /FitH null]');
1747 elseif($this->ZoomMode=='real')
1748 $this->_out('/OpenAction [3 0 R /XYZ null null 1]');
1749 elseif(!is_string($this->ZoomMode))
1750 $this->_out('/OpenAction [3 0 R /XYZ null null '.sprintf('%.2F',$this->ZoomMode/100).']');
1751 if($this->LayoutMode=='single')
1752 $this->_out('/PageLayout /SinglePage');
1753 elseif($this->LayoutMode=='continuous')
1754 $this->_out('/PageLayout /OneColumn');
1755 elseif($this->LayoutMode=='two')
1756 $this->_out('/PageLayout /TwoColumnLeft');
1757 }
1758
1759 function _putheader()
1760 {
1761 $this->_out('%PDF-'.$this->PDFVersion);
1762 }
1763
1764 function _puttrailer()
1765 {
1766 $this->_out('/Size '.($this->n+1));
1767 $this->_out('/Root '.$this->n.' 0 R');
1768 $this->_out('/Info '.($this->n-1).' 0 R');
1769 }
1770
1771 function _enddoc()
1772 {
1773 $this->_putheader();
1774 $this->_putpages();
1775 $this->_putresources();
1776 // Info
1777 $this->_newobj();
1778 $this->_out('<<');
1779 $this->_putinfo();
1780 $this->_out('>>');
1781 $this->_out('endobj');
1782 // Catalog
1783 $this->_newobj();
1784 $this->_out('<<');
1785 $this->_putcatalog();
1786 $this->_out('>>');
1787 $this->_out('endobj');
1788 // Cross-ref
1789 $o = strlen($this->buffer);
1790 $this->_out('xref');
1791 $this->_out('0 '.($this->n+1));
1792 $this->_out('0000000000 65535 f ');
1793 for($i=1;$i<=$this->n;$i++)
1794 $this->_out(sprintf('%010d 00000 n ',$this->offsets[$i]));
1795 // Trailer
1796 $this->_out('trailer');
1797 $this->_out('<<');
1798 $this->_puttrailer();
1799 $this->_out('>>');
1800 $this->_out('startxref');
1801 $this->_out($o);
1802 $this->_out('%%EOF');
1803 $this->state = 3;
1804 }
1805 // End of class
1806 }
1807
1808 // Handle special IE contype request
1809 if(isset($_SERVER['HTTP_USER_AGENT']) && $_SERVER['HTTP_USER_AGENT']=='contype')
1810 {
1811 header('Content-Type: application/pdf');
1812 exit;
1813 }
1814
1815 ?>
1816