source: branches/version-2_11-dev/data/module/fpdf/fpdf.php @ 20993

Revision 20993, 44.2 KB checked in by Seasoft, 15 years ago (diff)

#1374 (依存ライブラリのアップデート)

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