2 /****************************************************************************
\r
6 * Author: Olivier PLATHEY *
\r
7 * License: Freeware *
\r
9 * You may use and modify this software as you wish. *
\r
10 ****************************************************************************/
\r
11 define('FPDF_VERSION','1.51');
\r
15 //Private properties
\r
16 var $page; //current page number
\r
17 var $n; //current object number
\r
18 var $offsets; //array of object offsets
\r
19 var $buffer; //buffer holding in-memory PDF
\r
20 var $pages; //array containing pages
\r
21 var $state; //current document state
\r
22 var $compress; //compression flag
\r
23 var $DefOrientation; //default orientation
\r
24 var $CurOrientation; //current orientation
\r
25 var $OrientationChanges; //array indicating orientation changes
\r
26 var $fwPt,$fhPt; //dimensions of page format in points
\r
27 var $fw,$fh; //dimensions of page format in user unit
\r
28 var $wPt,$hPt; //current dimensions of page in points
\r
29 var $k; //scale factor (number of points in user unit)
\r
30 var $w,$h; //current dimensions of page in user unit
\r
31 var $lMargin; //left margin
\r
32 var $tMargin; //top margin
\r
33 var $rMargin; //right margin
\r
34 var $bMargin; //page break margin
\r
35 var $cMargin; //cell margin
\r
36 var $x,$y; //current position in user unit for cell positionning
\r
37 var $lasth; //height of last cell printed
\r
38 var $LineWidth; //line width in user unit
\r
39 var $CoreFonts; //array of standard font names
\r
40 var $fonts; //array of used fonts
\r
41 var $FontFiles; //array of font files
\r
42 var $diffs; //array of encoding differences
\r
43 var $images; //array of used images
\r
44 var $PageLinks; //array of links in pages
\r
45 var $links; //array of internal links
\r
46 var $FontFamily; //current font family
\r
47 var $FontStyle; //current font style
\r
48 var $underline; //underlining flag
\r
49 var $CurrentFont; //current font info
\r
50 var $FontSizePt; //current font size in points
\r
51 var $FontSize; //current font size in user unit
\r
52 var $DrawColor; //commands for drawing color
\r
53 var $FillColor; //commands for filling color
\r
54 var $TextColor; //commands for text color
\r
55 var $ColorFlag; //indicates whether fill and text colors are different
\r
56 var $ws; //word spacing
\r
57 var $AutoPageBreak; //automatic page breaking
\r
58 var $PageBreakTrigger; //threshold used to trigger page breaks
\r
59 var $InFooter; //flag set when processing footer
\r
60 var $ZoomMode; //zoom display mode
\r
61 var $LayoutMode; //layout display mode
\r
63 var $subject; //subject
\r
64 var $author; //author
\r
65 var $keywords; //keywords
\r
66 var $creator; //creator
\r
67 var $AliasNbPages; //alias for total number of pages
\r
72 /****************************************************************************
\r
76 ****************************************************************************/
\r
77 function __construct($orientation='P',$unit='mm',$format='A4')
\r
79 //Check for PHP locale-related bug
\r
81 $this->Error('Don\'t alter the locale before including class file');
\r
82 //Initialization of properties
\r
86 $this->pages=array();
\r
87 $this->OrientationChanges=array();
\r
89 $this->fonts=array();
\r
90 $this->FontFiles=array();
\r
91 $this->diffs=array();
\r
92 $this->images=array();
\r
93 $this->links=array();
\r
94 $this->InFooter=false;
\r
95 $this->FontFamily='';
\r
96 $this->FontStyle='';
\r
97 $this->FontSizePt=12;
\r
98 $this->underline=false;
\r
99 $this->DrawColor='0 G';
\r
100 $this->FillColor='0 g';
\r
101 $this->TextColor='0 g';
\r
102 $this->ColorFlag=false;
\r
105 $this->CoreFonts['courier']='Courier';
\r
106 $this->CoreFonts['courierB']='Courier-Bold';
\r
107 $this->CoreFonts['courierI']='Courier-Oblique';
\r
108 $this->CoreFonts['courierBI']='Courier-BoldOblique';
\r
109 $this->CoreFonts['helvetica']='Helvetica';
\r
110 $this->CoreFonts['helveticaB']='Helvetica-Bold';
\r
111 $this->CoreFonts['helveticaI']='Helvetica-Oblique';
\r
112 $this->CoreFonts['helveticaBI']='Helvetica-BoldOblique';
\r
113 $this->CoreFonts['times']='Times-Roman';
\r
114 $this->CoreFonts['timesB']='Times-Bold';
\r
115 $this->CoreFonts['timesI']='Times-Italic';
\r
116 $this->CoreFonts['timesBI']='Times-BoldItalic';
\r
117 $this->CoreFonts['symbol']='Symbol';
\r
118 $this->CoreFonts['zapfdingbats']='ZapfDingbats';
\r
122 elseif($unit=='mm')
\r
124 elseif($unit=='cm')
\r
126 elseif($unit=='in')
\r
129 $this->Error('Incorrect unit: '.$unit);
\r
131 if(is_string($format))
\r
133 $format=strtolower($format);
\r
135 $format=array(841.89,1190.55);
\r
136 elseif($format=='a4')
\r
137 $format=array(595.28,841.89);
\r
138 elseif($format=='a5')
\r
139 $format=array(420.94,595.28);
\r
140 elseif($format=='letter')
\r
141 $format=array(612,792);
\r
142 elseif($format=='legal')
\r
143 $format=array(612,1008);
\r
145 $this->Error('Unknown page format: '.$format);
\r
146 $this->fwPt=$format[0];
\r
147 $this->fhPt=$format[1];
\r
151 $this->fwPt=$format[0]*$this->k;
\r
152 $this->fhPt=$format[1]*$this->k;
\r
154 $this->CurPageFormat = $format; //FC with 1.6...
\r
158 $this->fw=$this->fwPt/$this->k;
\r
159 $this->fh=$this->fhPt/$this->k;
\r
161 $orientation=strtolower($orientation);
\r
162 if($orientation=='p' or $orientation=='portrait')
\r
164 $this->DefOrientation='P';
\r
165 $this->wPt=$this->fwPt;
\r
166 $this->hPt=$this->fhPt;
\r
168 elseif($orientation=='l' or $orientation=='landscape')
\r
170 $this->DefOrientation='L';
\r
171 $this->wPt=$this->fhPt;
\r
172 $this->hPt=$this->fwPt;
\r
175 $this->Error('Incorrect orientation: '.$orientation);
\r
176 $this->CurOrientation=$this->DefOrientation;
\r
177 $this->w=$this->wPt/$this->k;
\r
178 $this->h=$this->hPt/$this->k;
\r
179 //Page margins (1 cm)
\r
180 $margin=28.35/$this->k;
\r
181 $this->SetMargins($margin,$margin);
\r
182 //Interior cell margin (1 mm)
\r
183 $this->cMargin=$margin/10;
\r
184 //Line width (0.2 mm)
\r
185 $this->LineWidth=.567/$this->k;
\r
186 //Automatic page break
\r
187 $this->SetAutoPageBreak(true,2*$margin);
\r
188 //Full width display mode
\r
189 $this->SetDisplayMode('fullwidth');
\r
191 $this->SetCompression(true);
\r
193 $this->PDFVersion = '1.4';
\r
196 function SetMargins($left,$top,$right=-1)
\r
198 //Set left, top and right margins
\r
199 $this->lMargin=$left;
\r
200 $this->tMargin=$top;
\r
203 $this->rMargin=$right;
\r
206 function SetLeftMargin($margin)
\r
209 $this->lMargin=$margin;
\r
210 if($this->page>0 and $this->x<$margin)
\r
214 function SetTopMargin($margin)
\r
217 $this->tMargin=$margin;
\r
220 function SetRightMargin($margin)
\r
223 $this->rMargin=$margin;
\r
226 function SetAutoPageBreak($auto,$margin=0)
\r
228 //Set auto page break mode and triggering margin
\r
229 $this->AutoPageBreak=$auto;
\r
230 $this->bMargin=$margin;
\r
231 $this->PageBreakTrigger=$this->h-$margin;
\r
234 function SetDisplayMode($zoom,$layout='continuous')
\r
236 //Set display mode in viewer
\r
237 if($zoom=='fullpage' or $zoom=='fullwidth' or $zoom=='real' or $zoom=='default' or !is_string($zoom))
\r
238 $this->ZoomMode=$zoom;
\r
239 elseif($zoom=='zoom')
\r
240 $this->ZoomMode=$layout;
\r
242 $this->Error('Incorrect zoom display mode: '.$zoom);
\r
243 if($layout=='single' or $layout=='continuous' or $layout=='two' or $layout=='default')
\r
244 $this->LayoutMode=$layout;
\r
245 elseif($zoom!='zoom')
\r
246 $this->Error('Incorrect layout display mode: '.$layout);
\r
249 function SetCompression($compress)
\r
251 //Set page compression
\r
252 if(function_exists('gzcompress'))
\r
253 $this->compress=$compress;
\r
255 $this->compress=false;
\r
258 function SetTitle($title)
\r
260 //Title of document
\r
261 $this->title=$title;
\r
264 function SetSubject($subject)
\r
266 //Subject of document
\r
267 $this->subject=$subject;
\r
270 function SetAuthor($author)
\r
272 //Author of document
\r
273 $this->author=$author;
\r
276 function SetKeywords($keywords)
\r
278 //Keywords of document
\r
279 $this->keywords=$keywords;
\r
282 function SetCreator($creator)
\r
284 //Creator of document
\r
285 $this->creator=$creator;
\r
288 function AliasNbPages($alias='{nb}')
\r
290 //Define an alias for total number of pages
\r
291 $this->AliasNbPages=$alias;
\r
294 function Error($msg)
\r
297 die('<B>FPDF error: </B>'.$msg);
\r
303 $this->_begindoc();
\r
308 //Terminate document
\r
312 $this->InFooter=true;
\r
314 $this->InFooter=false;
\r
321 function AddPage($orientation='')
\r
324 $family=$this->FontFamily;
\r
325 $style=$this->FontStyle.($this->underline ? 'U' : '');
\r
326 $size=$this->FontSizePt;
\r
327 $lw=$this->LineWidth;
\r
328 $dc=$this->DrawColor;
\r
329 $fc=$this->FillColor;
\r
330 $tc=$this->TextColor;
\r
331 $cf=$this->ColorFlag;
\r
335 $this->InFooter=true;
\r
337 $this->InFooter=false;
\r
342 $this->_beginpage($orientation);
\r
343 //Set line cap style to square
\r
344 $this->_out('2 J');
\r
346 $this->LineWidth=$lw;
\r
347 $this->_out(sprintf('%.2f w',$lw*$this->k));
\r
350 $this->SetFont($family,$style,$size);
\r
352 $this->DrawColor=$dc;
\r
355 $this->FillColor=$fc;
\r
358 $this->TextColor=$tc;
\r
359 $this->ColorFlag=$cf;
\r
362 //Restore line width
\r
363 if($this->LineWidth!=$lw)
\r
365 $this->LineWidth=$lw;
\r
366 $this->_out(sprintf('%.2f w',$lw*$this->k));
\r
370 $this->SetFont($family,$style,$size);
\r
372 if($this->DrawColor!=$dc)
\r
374 $this->DrawColor=$dc;
\r
377 if($this->FillColor!=$fc)
\r
379 $this->FillColor=$fc;
\r
382 $this->TextColor=$tc;
\r
383 $this->ColorFlag=$cf;
\r
388 //To be implemented in your own inherited class
\r
393 //To be implemented in your own inherited class
\r
398 //Get current page number
\r
399 return $this->page;
\r
402 function SetDrawColor($r,$g=-1,$b=-1)
\r
404 //Set color for all stroking operations
\r
405 if(($r==0 and $g==0 and $b==0) or $g==-1)
\r
406 $this->DrawColor=sprintf('%.3f G',$r/255);
\r
408 $this->DrawColor=sprintf('%.3f %.3f %.3f RG',$r/255,$g/255,$b/255);
\r
410 $this->_out($this->DrawColor);
\r
413 function SetFillColor($r,$g=-1,$b=-1)
\r
415 //Set color for all filling operations
\r
416 if(($r==0 and $g==0 and $b==0) or $g==-1)
\r
417 $this->FillColor=sprintf('%.3f g',$r/255);
\r
419 $this->FillColor=sprintf('%.3f %.3f %.3f rg',$r/255,$g/255,$b/255);
\r
420 $this->ColorFlag=($this->FillColor!=$this->TextColor);
\r
422 $this->_out($this->FillColor);
\r
425 function SetTextColor($r,$g=-1,$b=-1)
\r
427 //Set color for text
\r
428 if(($r==0 and $g==0 and $b==0) or $g==-1)
\r
429 $this->TextColor=sprintf('%.3f g',$r/255);
\r
431 $this->TextColor=sprintf('%.3f %.3f %.3f rg',$r/255,$g/255,$b/255);
\r
432 $this->ColorFlag=($this->FillColor!=$this->TextColor);
\r
435 function GetStringWidth($s)
\r
437 //Get width of a string in the current font
\r
439 $cw=&$this->CurrentFont['cw'];
\r
442 for($i=0;$i<$l;$i++)
\r
444 return $w*$this->FontSize/1000;
\r
447 function SetLineWidth($width)
\r
450 $this->LineWidth=$width;
\r
452 $this->_out(sprintf('%.2f w',$width*$this->k));
\r
455 function Line($x1,$y1,$x2,$y2)
\r
458 if (!is_array($x1)) {
\r
460 sprintf('%.2f %.2f m %.2f %.2f l S',$x1*$this->k,($this->h-$y1)*$this->k,$x2*$this->k,($this->h-$y2)*$this->k));
\r
463 $type= 'm';$out='';
\r
464 for ($i=0;$i<count($x1);$i+=2) {
\r
465 $out .= sprintf(' %.2f %.2f %s',$x1[$i]*$this->k,($this->h-$x1[$i+1])*$this->k,$type);
\r
468 $this->_out(ltrim($out) . ' f');
\r
473 function Rect($x,$y,$w,$h,$style='')
\r
478 elseif($style=='FD' or $style=='DF')
\r
482 $this->_out(sprintf('%.2f %.2f %.2f %.2f re %s',$x*$this->k,($this->h-$y)*$this->k,$w*$this->k,-$h*$this->k,$op));
\r
485 function AddFont($family,$style='',$file='')
\r
487 //var_dump(array($family, $style, $file));//Add a TrueType or Type1 font
\r
488 $family=strtolower($family);
\r
489 if($family=='arial')
\r
490 $family='helvetica';
\r
491 $style=strtoupper($style);
\r
494 if(isset($this->fonts[$family.$style]))
\r
495 $this->Error('Font already added: '.$family.' '.$style);
\r
497 $file=str_replace(' ','',$family).strtolower($style).'.php';
\r
499 if (file_exists(dirname(__FILE__) .'/FpdfAlt/'.$file)) {
\r
500 include 'FpdfAlt/'.$file;
\r
502 if(!isset($name)) {
\r
503 $this->Error('Could not include font definition file');
\r
505 $i=count($this->fonts)+1;
\r
506 $this->fonts[$family.$style]=array('i'=>$i,'type'=>$type,'name'=>$name,'desc'=>$desc,'up'=>$up,'ut'=>$ut,'cw'=>$cw,'enc'=>$enc,'file'=>$file);
\r
509 //Search existing encodings
\r
511 $nb=count($this->diffs);
\r
512 for($i=1;$i<=$nb;$i++)
\r
513 if($this->diffs[$i]==$diff)
\r
521 $this->diffs[$d]=$diff;
\r
523 $this->fonts[$family.$style]['diff']=$d;
\r
527 if($type=='TrueType')
\r
528 $this->FontFiles[$file]=array('length1'=>$originalsize);
\r
530 $this->FontFiles[$file]=array('length1'=>$size1,'length2'=>$size2);
\r
534 function SetFont($family,$style='',$size=0)
\r
536 //Select a font; size given in points
\r
537 global $fpdf_charwidths;
\r
539 $family=strtolower($family);
\r
541 $family=$this->FontFamily;
\r
542 if($family=='arial')
\r
543 $family='helvetica';
\r
544 elseif($family=='symbol' or $family=='zapfdingbats')
\r
546 $style=strtoupper($style);
\r
547 if(is_int(strpos($style,'U')))
\r
549 $this->underline=true;
\r
550 $style=str_replace('U','',$style);
\r
553 $this->underline=false;
\r
557 $size=$this->FontSizePt;
\r
558 //Test if font is already selected
\r
559 if($this->FontFamily==$family and $this->FontStyle==$style and $this->FontSizePt==$size)
\r
561 //Test if used for the first time
\r
562 $fontkey=$family.$style;
\r
563 if(!isset($this->fonts[$fontkey]))
\r
565 //Check if one of the standard fonts
\r
566 if(isset($this->CoreFonts[$fontkey]))
\r
568 if(!isset($fpdf_charwidths[$fontkey]))
\r
572 if($family=='times' or $family=='helvetica')
\r
573 $file.=strtolower($style);
\r
575 if (file_exists(dirname(__FILE__) .'/FpdfAlt/'.$file)) {
\r
576 include 'FpdfAlt/'.$file;
\r
578 if(!isset($fpdf_charwidths[$fontkey]))
\r
579 $this->Error('Could not include font metric file');
\r
581 $i=count($this->fonts)+1;
\r
582 $this->fonts[$fontkey]=array('i'=>$i,'type'=>'core','name'=>$this->CoreFonts[$fontkey],'up'=>-100,'ut'=>50,'cw'=>$fpdf_charwidths[$fontkey]);
\r
585 $this->Error('Undefined font: '.$family.' '.$style);
\r
588 $this->FontFamily=$family;
\r
589 $this->FontStyle=$style;
\r
590 $this->FontSizePt=$size;
\r
591 $this->FontSize=$size/$this->k;
\r
592 $this->CurrentFont=&$this->fonts[$fontkey];
\r
594 $this->_out(sprintf('BT /F%d %.2f Tf ET',$this->CurrentFont['i'],$this->FontSizePt));
\r
597 function SetFontSize($size)
\r
599 //Set font size in points
\r
600 if($this->FontSizePt==$size)
\r
602 $this->FontSizePt=$size;
\r
603 $this->FontSize=$size/$this->k;
\r
605 $this->_out(sprintf('BT /F%d %.2f Tf ET',$this->CurrentFont['i'],$this->FontSizePt));
\r
610 //Create a new internal link
\r
611 $n=count($this->links)+1;
\r
612 $this->links[$n]=array(0,0);
\r
616 function SetLink($link,$y=0,$page=-1)
\r
618 //Set destination of internal link
\r
623 $this->links[$link]=array($page,$y);
\r
626 function Link($x,$y,$w,$h,$link)
\r
628 //Put a link on the page
\r
629 $this->PageLinks[$this->page][]=array($x*$this->k,$this->hPt-$y*$this->k,$w*$this->k,$h*$this->k,$link);
\r
632 function Text($x,$y,$txt)
\r
635 $txt=str_replace(')','\\)',str_replace('(','\\(',str_replace('\\','\\\\',$txt)));
\r
636 $s=sprintf('BT %.2f %.2f Td (%s) Tj ET',$x*$this->k,($this->h-$y)*$this->k,$txt);
\r
637 if($this->underline and $txt!='')
\r
638 $s.=' '.$this->_dounderline($x,$y,$txt);
\r
639 if($this->ColorFlag)
\r
640 $s='q '.$this->TextColor.' '.$s.' Q';
\r
644 function AcceptPageBreak()
\r
646 //Accept automatic page break or not
\r
647 return $this->AutoPageBreak;
\r
650 function Cell($w,$h=0,$txt='',$border=0,$ln=0,$align='',$fill=0,$link='')
\r
654 if($this->y+$h>$this->PageBreakTrigger and !$this->InFooter and $this->AcceptPageBreak())
\r
661 $this->_out('0 Tw');
\r
663 $this->AddPage($this->CurOrientation);
\r
668 $this->_out(sprintf('%.3f Tw',$ws*$k));
\r
672 $w=$this->w-$this->rMargin-$this->x;
\r
674 if($fill==1 or $border==1)
\r
677 $op=($border==1) ? 'B' : 'f';
\r
680 $s=sprintf('%.2f %.2f %.2f %.2f re %s ',$this->x*$k,($this->h-$this->y)*$k,$w*$k,-$h*$k,$op);
\r
682 if(is_string($border))
\r
686 if(is_int(strpos($border,'L')))
\r
687 $s.=sprintf('%.2f %.2f m %.2f %.2f l S ',$x*$k,($this->h-$y)*$k,$x*$k,($this->h-($y+$h))*$k);
\r
688 if(is_int(strpos($border,'T')))
\r
689 $s.=sprintf('%.2f %.2f m %.2f %.2f l S ',$x*$k,($this->h-$y)*$k,($x+$w)*$k,($this->h-$y)*$k);
\r
690 if(is_int(strpos($border,'R')))
\r
691 $s.=sprintf('%.2f %.2f m %.2f %.2f l S ',($x+$w)*$k,($this->h-$y)*$k,($x+$w)*$k,($this->h-($y+$h))*$k);
\r
692 if(is_int(strpos($border,'B')))
\r
693 $s.=sprintf('%.2f %.2f m %.2f %.2f l S ',$x*$k,($this->h-($y+$h))*$k,($x+$w)*$k,($this->h-($y+$h))*$k);
\r
698 $dx=$w-$this->cMargin-$this->GetStringWidth($txt);
\r
699 elseif($align=='C')
\r
700 $dx=($w-$this->GetStringWidth($txt))/2;
\r
702 $dx=$this->cMargin;
\r
703 $txt=str_replace(')','\\)',str_replace('(','\\(',str_replace('\\','\\\\',$txt)));
\r
704 if($this->ColorFlag)
\r
705 $s.='q '.$this->TextColor.' ';
\r
706 $s.=sprintf('BT %.2f %.2f Td (%s) Tj ET',($this->x+$dx)*$k,($this->h-($this->y+.5*$h+.3*$this->FontSize))*$k,$txt);
\r
707 if($this->underline)
\r
708 $s.=' '.$this->_dounderline($this->x+$dx,$this->y+.5*$h+.3*$this->FontSize,$txt);
\r
709 if($this->ColorFlag)
\r
712 $this->Link($this->x+$dx,$this->y+.5*$h-.5*$this->FontSize,$this->GetStringWidth($txt),$this->FontSize,$link);
\r
722 $this->x=$this->lMargin;
\r
728 function MultiCell($w,$h,$txt,$border=0,$align='J',$fill=0)
\r
730 //Output text with automatic or explicit line breaks
\r
731 $cw=&$this->CurrentFont['cw'];
\r
733 $w=$this->w-$this->rMargin-$this->x;
\r
734 $wmax=($w-2*$this->cMargin)*1000/$this->FontSize;
\r
735 $s=str_replace("\r",'',$txt);
\r
737 if($nb>0 and $s[$nb-1]=="\n")
\r
751 if(is_int(strpos($border,'L')))
\r
753 if(is_int(strpos($border,'R')))
\r
755 $b=is_int(strpos($border,'T')) ? $b2.'T' : $b2;
\r
766 //Get next character
\r
770 //Explicit line break
\r
774 $this->_out('0 Tw');
\r
776 $this->Cell($w,$h,substr($s,$j,$i-$j),$b,2,$align,$fill);
\r
783 if($border and $nl==2)
\r
796 //Automatic line break
\r
804 $this->_out('0 Tw');
\r
806 $this->Cell($w,$h,substr($s,$j,$i-$j),$b,2,$align,$fill);
\r
812 $this->ws=($ns>1) ? ($wmax-$ls)/1000*$this->FontSize/($ns-1) : 0;
\r
813 $this->_out(sprintf('%.3f Tw',$this->ws*$this->k));
\r
815 $this->Cell($w,$h,substr($s,$j,$sep-$j),$b,2,$align,$fill);
\r
823 if($border and $nl==2)
\r
833 $this->_out('0 Tw');
\r
835 if($border and is_int(strpos($border,'B')))
\r
837 $this->Cell($w,$h,substr($s,$j,$i),$b,2,$align,$fill);
\r
838 $this->x=$this->lMargin;
\r
841 function Write($h,$txt,$link='')
\r
843 //Output text in flowing mode
\r
844 $cw=&$this->CurrentFont['cw'];
\r
845 $w=$this->w-$this->rMargin-$this->x;
\r
846 $wmax=($w-2*$this->cMargin)*1000/$this->FontSize;
\r
847 $s=str_replace("\r",'',$txt);
\r
856 //Get next character
\r
860 //Explicit line break
\r
861 $this->Cell($w,$h,substr($s,$j,$i-$j),0,2,'',0,$link);
\r
868 $this->x=$this->lMargin;
\r
869 $w=$this->w-$this->rMargin-$this->x;
\r
870 $wmax=($w-2*$this->cMargin)*1000/$this->FontSize;
\r
883 //Automatic line break
\r
886 if($this->x>$this->lMargin)
\r
888 //Move to next line
\r
889 $this->x=$this->lMargin;
\r
891 $w=$this->w-$this->rMargin-$this->x;
\r
892 $wmax=($w-2*$this->cMargin)*1000/$this->FontSize;
\r
899 $this->Cell($w,$h,substr($s,$j,$i-$j),0,2,'',0,$link);
\r
903 $this->Cell($w,$h,substr($s,$j,$sep-$j),0,2,'',0,$link);
\r
911 $this->x=$this->lMargin;
\r
912 $w=$this->w-$this->rMargin-$this->x;
\r
913 $wmax=($w-2*$this->cMargin)*1000/$this->FontSize;
\r
922 $this->Cell($l/1000*$this->FontSize,$h,substr($s,$j,$i),0,0,'',0,$link);
\r
925 function Image($file,$x,$y,$w,$h=0,$type='',$link='')
\r
927 //Put an image on the page
\r
928 if(!isset($this->images[$file]))
\r
930 //First use of image, get info
\r
933 $pos=strrpos($file,'.');
\r
935 $this->Error('Image file has no extension and no type was specified: '.$file);
\r
936 $type=substr($file,$pos+1);
\r
938 $type=strtolower($type);
\r
939 //$mqr=get_magic_quotes_runtime();
\r
940 // set_magic_quotes_runtime(0);
\r
941 if($type=='jpg' or $type=='jpeg')
\r
942 $info=$this->_parsejpg($file);
\r
943 elseif($type=='png')
\r
944 $info=$this->_parsepng($file);
\r
946 $this->Error('Unsupported image file type: '.$type);
\r
947 //set_magic_quotes_runtime($mqr);
\r
948 $info['i']=count($this->images)+1;
\r
949 $this->images[$file]=$info;
\r
952 $info=$this->images[$file];
\r
953 //Automatic width or height calculation
\r
955 $w=$h*$info['w']/$info['h'];
\r
957 $h=$w*$info['h']/$info['w'];
\r
958 $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']));
\r
960 $this->Link($x,$y,$w,$h,$link);
\r
965 //Line feed; default value is last cell height
\r
966 $this->x=$this->lMargin;
\r
968 $this->y+=$this->lasth;
\r
985 $this->x=$this->w+$x;
\r
996 //Set y position and reset x
\r
997 $this->x=$this->lMargin;
\r
1001 $this->y=$this->h+$y;
\r
1004 function SetXY($x,$y)
\r
1006 //Set x and y positions
\r
1011 function Output($file='',$download=false)
\r
1013 //Output PDF to file or browser
\r
1014 global $HTTP_ENV_VARS;
\r
1016 if($this->state<3)
\r
1021 Header('Content-Type: application/pdf');
\r
1022 if(headers_sent())
\r
1023 $this->Error('Some data has already been output to browser, can\'t send PDF file');
\r
1024 Header('Content-Length: '.strlen($this->buffer));
\r
1025 Header('Content-disposition: inline; filename=doc.pdf');
\r
1026 echo $this->buffer;
\r
1033 if(isset($HTTP_ENV_VARS['HTTP_USER_AGENT']) and strpos($HTTP_ENV_VARS['HTTP_USER_AGENT'],'MSIE 5.5'))
\r
1034 Header('Content-Type: application/dummy');
\r
1036 Header('Content-Type: application/octet-stream');
\r
1037 if(headers_sent())
\r
1038 $this->Error('Some data has already been output to browser, can\'t send PDF file');
\r
1039 Header('Content-Length: '.strlen($this->buffer));
\r
1040 Header('Content-disposition: attachment; filename='.$file);
\r
1041 echo $this->buffer;
\r
1045 //Save file locally
\r
1046 $f=fopen($file,'wb');
\r
1048 $this->Error('Unable to create output file: '.$file);
\r
1049 fwrite($f,$this->buffer,strlen($this->buffer));
\r
1055 /****************************************************************************
\r
1057 * Private methods *
\r
1059 ****************************************************************************/
\r
1060 function _begindoc()
\r
1064 $this->_out('%PDF-1.3');
\r
1067 function _putpages()
\r
1070 if(!empty($this->AliasNbPages))
\r
1072 //Replace number of pages
\r
1073 for($n=1;$n<=$nb;$n++)
\r
1074 $this->pages[$n]=str_replace($this->AliasNbPages,$nb,$this->pages[$n]);
\r
1076 if($this->DefOrientation=='P')
\r
1086 $filter=($this->compress) ? '/Filter /FlateDecode ' : '';
\r
1087 for($n=1;$n<=$nb;$n++)
\r
1091 $this->_out('<</Type /Page');
\r
1092 $this->_out('/Parent 1 0 R');
\r
1093 if(isset($this->OrientationChanges[$n]))
\r
1094 $this->_out(sprintf('/MediaBox [0 0 %.2f %.2f]',$hPt,$wPt));
\r
1095 $this->_out('/Resources 2 0 R');
\r
1096 if(isset($this->PageLinks[$n]))
\r
1099 $annots='/Annots [';
\r
1100 foreach($this->PageLinks[$n] as $pl)
\r
1102 $rect=sprintf('%.2f %.2f %.2f %.2f',$pl[0],$pl[1],$pl[0]+$pl[2],$pl[1]-$pl[3]);
\r
1103 $annots.='<</Type /Annot /Subtype /Link /Rect ['.$rect.'] /Border [0 0 0] ';
\r
1104 if(is_string($pl[4]))
\r
1105 $annots.='/A <</S /URI /URI '.$this->_textstring($pl[4]).'>>>>';
\r
1108 $l=$this->links[$pl[4]];
\r
1109 $h=isset($this->OrientationChanges[$l[0]]) ? $wPt : $hPt;
\r
1110 $annots.=sprintf('/Dest [%d 0 R /XYZ 0 %.2f null]>>',1+2*$l[0],$h-$l[1]*$this->k);
\r
1113 $this->_out($annots.']');
\r
1115 $this->_out('/Group <</Type /Group /S /Transparency /CS /DeviceRGB>>');
\r
1116 $this->_out('/Contents '.($this->n+1).' 0 R>>');
\r
1117 $this->_out('endobj');
\r
1119 $p=($this->compress) ? gzcompress($this->pages[$n]) : $this->pages[$n];
\r
1121 $this->_out('<<'.$filter.'/Length '.strlen($p).'>>');
\r
1122 $this->_putstream($p);
\r
1123 $this->_out('endobj');
\r
1126 $this->offsets[1]=strlen($this->buffer);
\r
1127 $this->_out('1 0 obj');
\r
1128 $this->_out('<</Type /Pages');
\r
1130 for($i=0;$i<$nb;$i++)
\r
1131 $kids.=(3+2*$i).' 0 R ';
\r
1132 $this->_out($kids.']');
\r
1133 $this->_out('/Count '.$nb);
\r
1134 $this->_out(sprintf('/MediaBox [0 0 %.2f %.2f]',$wPt,$hPt));
\r
1135 $this->_out('>>');
\r
1136 $this->_out('endobj');
\r
1139 function _putfonts()
\r
1142 foreach($this->diffs as $diff)
\r
1146 $this->_out('<</Type /Encoding /BaseEncoding /WinAnsiEncoding /Differences ['.$diff.']>>');
\r
1147 $this->_out('endobj');
\r
1149 $mqr=get_magic_quotes_runtime();
\r
1150 //set_magic_quotes_runtime(0);
\r
1151 foreach($this->FontFiles as $file=>$info)
\r
1153 //Font file embedding
\r
1155 $this->FontFiles[$file]['n']=$this->n;
\r
1156 if(defined('FPDF_FONTPATH'))
\r
1157 $file=FPDF_FONTPATH.$file;
\r
1158 $size=filesize($file);
\r
1160 $this->Error('Font file not found');
\r
1161 $this->_out('<</Length '.$size);
\r
1162 if(substr($file,-2)=='.z')
\r
1163 $this->_out('/Filter /FlateDecode');
\r
1164 $this->_out('/Length1 '.$info['length1']);
\r
1165 if(isset($info['length2']))
\r
1166 $this->_out('/Length2 '.$info['length2'].' /Length3 0');
\r
1167 $this->_out('>>');
\r
1168 $f=fopen($file,'rb');
\r
1169 $this->_putstream(fread($f,$size));
\r
1171 $this->_out('endobj');
\r
1173 //set_magic_quotes_runtime($mqr);
\r
1174 foreach($this->fonts as $k=>$font)
\r
1178 $this->fonts[$k]['n']=$this->n;
\r
1179 $name=$font['name'];
\r
1180 $this->_out('<</Type /Font');
\r
1181 $this->_out('/BaseFont /'.$name);
\r
1182 if($font['type']=='core')
\r
1185 $this->_out('/Subtype /Type1');
\r
1186 if($name!='Symbol' and $name!='ZapfDingbats')
\r
1187 $this->_out('/Encoding /WinAnsiEncoding');
\r
1192 $this->_out('/Subtype /'.$font['type']);
\r
1193 $this->_out('/FirstChar 32');
\r
1194 $this->_out('/LastChar 255');
\r
1195 $this->_out('/Widths '.($this->n+1).' 0 R');
\r
1196 $this->_out('/FontDescriptor '.($this->n+2).' 0 R');
\r
1199 if(isset($font['diff']))
\r
1200 $this->_out('/Encoding '.($nf+$font['diff']).' 0 R');
\r
1202 $this->_out('/Encoding /WinAnsiEncoding');
\r
1205 $this->_out('>>');
\r
1206 $this->_out('endobj');
\r
1207 if($font['type']!='core')
\r
1213 for($i=32;$i<=255;$i++)
\r
1214 $s.=$cw[chr($i)].' ';
\r
1215 $this->_out($s.']');
\r
1216 $this->_out('endobj');
\r
1219 $s='<</Type /FontDescriptor /FontName /'.$name;
\r
1220 foreach($font['desc'] as $k=>$v)
\r
1221 $s.=' /'.$k.' '.$v;
\r
1222 $file=$font['file'];
\r
1224 $s.=' /FontFile'.($font['type']=='Type1' ? '' : '2').' '.$this->FontFiles[$file]['n'].' 0 R';
\r
1225 $this->_out($s.'>>');
\r
1226 $this->_out('endobj');
\r
1231 function _putimages()
\r
1233 $filter=($this->compress) ? '/Filter /FlateDecode ' : '';
\r
1234 foreach($this->images as $file=>$info)
\r
1237 $this->images[$file]['n']=$this->n;
\r
1238 $this->_out('<</Type /XObject');
\r
1239 $this->_out('/Subtype /Image');
\r
1240 $this->_out('/Width '.$info['w']);
\r
1241 $this->_out('/Height '.$info['h']);
\r
1242 if($info['cs']=='Indexed')
\r
1243 $this->_out('/ColorSpace [/Indexed /DeviceRGB '.(strlen($info['pal'])/3-1).' '.($this->n+1).' 0 R]');
\r
1246 $this->_out('/ColorSpace /'.$info['cs']);
\r
1247 if($info['cs']=='DeviceCMYK')
\r
1248 $this->_out('/Decode [1 0 1 0 1 0 1 0]');
\r
1250 $this->_out('/BitsPerComponent '.$info['bpc']);
\r
1251 $this->_out('/Filter /'.$info['f']);
\r
1252 if(isset($info['parms']))
\r
1253 $this->_out($info['parms']);
\r
1254 if(isset($info['trns']) and is_array($info['trns']))
\r
1257 for($i=0;$i<count($info['trns']);$i++)
\r
1258 $trns.=$info['trns'][$i].' '.$info['trns'][$i].' ';
\r
1259 $this->_out('/Mask ['.$trns.']');
\r
1261 $this->_out('/Length '.strlen($info['data']).'>>');
\r
1262 $this->_putstream($info['data']);
\r
1263 $this->_out('endobj');
\r
1265 if($info['cs']=='Indexed')
\r
1268 $pal=($this->compress) ? gzcompress($info['pal']) : $info['pal'];
\r
1269 $this->_out('<<'.$filter.'/Length '.strlen($pal).'>>');
\r
1270 $this->_putstream($pal);
\r
1271 $this->_out('endobj');
\r
1276 function _putresources()
\r
1278 $this->_putfonts();
\r
1279 $this->_putimages();
\r
1280 //Resource dictionary
\r
1281 $this->offsets[2]=strlen($this->buffer);
\r
1282 $this->_out('2 0 obj');
\r
1283 $this->_out('<</ProcSet [/PDF /Text /ImageB /ImageC /ImageI]');
\r
1284 $this->_out('/Font <<');
\r
1285 foreach($this->fonts as $font)
\r
1286 $this->_out('/F'.$font['i'].' '.$font['n'].' 0 R');
\r
1287 $this->_out('>>');
\r
1288 if(count($this->images))
\r
1290 $this->_out('/XObject <<');
\r
1291 foreach($this->images as $image)
\r
1292 $this->_out('/I'.$image['i'].' '.$image['n'].' 0 R');
\r
1293 $this->_out('>>');
\r
1295 $this->_out('>>');
\r
1296 $this->_out('endobj');
\r
1299 function _putinfo()
\r
1301 $this->_out('/Producer '.$this->_textstring('FPDF '.FPDF_VERSION));
\r
1302 if(!empty($this->title))
\r
1303 $this->_out('/Title '.$this->_textstring($this->title));
\r
1304 if(!empty($this->subject))
\r
1305 $this->_out('/Subject '.$this->_textstring($this->subject));
\r
1306 if(!empty($this->author))
\r
1307 $this->_out('/Author '.$this->_textstring($this->author));
\r
1308 if(!empty($this->keywords))
\r
1309 $this->_out('/Keywords '.$this->_textstring($this->keywords));
\r
1310 if(!empty($this->creator))
\r
1311 $this->_out('/Creator '.$this->_textstring($this->creator));
\r
1312 $this->_out('/CreationDate '.$this->_textstring('D:'.date('YmdHis')));
\r
1315 function _putcatalog()
\r
1317 $this->_out('/Type /Catalog');
\r
1318 $this->_out('/Pages 1 0 R');
\r
1319 if($this->ZoomMode=='fullpage')
\r
1320 $this->_out('/OpenAction [3 0 R /Fit]');
\r
1321 elseif($this->ZoomMode=='fullwidth')
\r
1322 $this->_out('/OpenAction [3 0 R /FitH null]');
\r
1323 elseif($this->ZoomMode=='real')
\r
1324 $this->_out('/OpenAction [3 0 R /XYZ null null 1]');
\r
1325 elseif(!is_string($this->ZoomMode))
\r
1326 $this->_out('/OpenAction [3 0 R /XYZ null null '.($this->ZoomMode/100).']');
\r
1327 if($this->LayoutMode=='single')
\r
1328 $this->_out('/PageLayout /SinglePage');
\r
1329 elseif($this->LayoutMode=='continuous')
\r
1330 $this->_out('/PageLayout /OneColumn');
\r
1331 elseif($this->LayoutMode=='two')
\r
1332 $this->_out('/PageLayout /TwoColumnLeft');
\r
1335 function _putheader()
\r
1337 $this->_out('%PDF-'.$this->PDFVersion);
\r
1341 function _puttrailer()
\r
1343 $this->_out('/Size '.($this->n+1));
\r
1344 $this->_out('/Root '.$this->n.' 0 R');
\r
1345 $this->_out('/Info '.($this->n-1).' 0 R');
\r
1348 function _enddoc()
\r
1350 $this->_putheader();
\r
1351 $this->_putpages();
\r
1352 $this->_putresources();
\r
1355 $this->_out('<<');
\r
1356 $this->_putinfo();
\r
1357 $this->_out('>>');
\r
1358 $this->_out('endobj');
\r
1361 $this->_out('<<');
\r
1362 $this->_putcatalog();
\r
1363 $this->_out('>>');
\r
1364 $this->_out('endobj');
\r
1366 $o=strlen($this->buffer);
\r
1367 $this->_out('xref');
\r
1368 $this->_out('0 '.($this->n+1));
\r
1369 $this->_out('0000000000 65535 f ');
\r
1370 for($i=1;$i<=$this->n;$i++)
\r
1371 $this->_out(sprintf('%010d 00000 n ',$this->offsets[$i]));
\r
1373 $this->_out('trailer');
\r
1374 $this->_out('<<');
\r
1375 $this->_puttrailer();
\r
1376 $this->_out('>>');
\r
1377 $this->_out('startxref');
\r
1379 $this->_out('%%EOF');
\r
1383 function _beginpage($orientation)
\r
1386 $this->pages[$this->page]='';
\r
1388 $this->x=$this->lMargin;
\r
1389 $this->y=$this->tMargin;
\r
1391 $this->FontFamily='';
\r
1392 //Page orientation
\r
1394 $orientation=$this->DefOrientation;
\r
1397 $orientation=strtoupper($orientation[0]);
\r
1398 if($orientation!=$this->DefOrientation)
\r
1399 $this->OrientationChanges[$this->page]=true;
\r
1401 if($orientation!=$this->CurOrientation)
\r
1403 //Change orientation
\r
1404 if($orientation=='P')
\r
1406 $this->wPt=$this->fwPt;
\r
1407 $this->hPt=$this->fhPt;
\r
1408 $this->w=$this->fw;
\r
1409 $this->h=$this->fh;
\r
1413 $this->wPt=$this->fhPt;
\r
1414 $this->hPt=$this->fwPt;
\r
1415 $this->w=$this->fh;
\r
1416 $this->h=$this->fw;
\r
1418 $this->PageBreakTrigger=$this->h-$this->bMargin;
\r
1419 $this->CurOrientation=$orientation;
\r
1423 function _endpage()
\r
1425 //End of page contents
\r
1429 function _newobj()
\r
1431 //Begin a new object
\r
1433 $this->offsets[$this->n]=strlen($this->buffer);
\r
1434 $this->_out($this->n.' 0 obj');
\r
1437 function _dounderline($x,$y,$txt)
\r
1440 $up=$this->CurrentFont['up'];
\r
1441 $ut=$this->CurrentFont['ut'];
\r
1442 $w=$this->GetStringWidth($txt)+$this->ws*substr_count($txt,' ');
\r
1443 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);
\r
1446 function _parsejpg($file)
\r
1448 //Extract info from a JPEG file
\r
1449 $a=GetImageSize($file);
\r
1451 $this->Error('Missing or incorrect image file: '.$file);
\r
1453 $this->Error('Not a JPEG file: '.$file);
\r
1454 if(!isset($a['channels']) or $a['channels']==3)
\r
1455 $colspace='DeviceRGB';
\r
1456 elseif($a['channels']==4)
\r
1457 $colspace='DeviceCMYK';
\r
1459 $colspace='DeviceGray';
\r
1460 $bpc=isset($a['bits']) ? $a['bits'] : 8;
\r
1462 $f=fopen($file,'rb');
\r
1463 $data=fread($f,filesize($file));
\r
1465 return array('w'=>$a[0],'h'=>$a[1],'cs'=>$colspace,'bpc'=>$bpc,'f'=>'DCTDecode','data'=>$data);
\r
1468 function _parsepng($file)
\r
1470 //Extract info from a PNG file
\r
1471 $f=fopen($file,'rb');
\r
1473 $this->Error('Can\'t open image file: '.$file);
\r
1475 if(fread($f,8)!=chr(137).'PNG'.chr(13).chr(10).chr(26).chr(10))
\r
1476 $this->Error('Not a PNG file: '.$file);
\r
1477 //Read header chunk
\r
1479 if(fread($f,4)!='IHDR')
\r
1480 $this->Error('Incorrect PNG file: '.$file);
\r
1481 $w=$this->_freadint($f);
\r
1482 $h=$this->_freadint($f);
\r
1483 $bpc=ord(fread($f,1));
\r
1485 $this->Error('16-bit depth not supported: '.$file);
\r
1486 $ct=ord(fread($f,1));
\r
1488 $colspace='DeviceGray';
\r
1490 $colspace='DeviceRGB';
\r
1492 $colspace='Indexed';
\r
1494 $this->Error("Alpha channel not supported: $ct ".$file);
\r
1495 if(ord(fread($f,1))!=0)
\r
1496 $this->Error('Unknown compression method: '.$file);
\r
1497 if(ord(fread($f,1))!=0)
\r
1498 $this->Error('Unknown filter method: '.$file);
\r
1499 if(ord(fread($f,1))!=0)
\r
1500 $this->Error('Interlacing not supported: '.$file);
\r
1502 $parms='/DecodeParms <</Predictor 15 /Colors '.($ct==2 ? 3 : 1).' /BitsPerComponent '.$bpc.' /Columns '.$w.'>>';
\r
1503 //Scan chunks looking for palette, transparency and image data
\r
1509 $n=$this->_freadint($f);
\r
1510 $type=fread($f,4);
\r
1514 $pal=fread($f,$n);
\r
1517 elseif($type=='tRNS')
\r
1519 //Read transparency info
\r
1522 $trns=array(ord(substr($t,1,1)));
\r
1524 $trns=array(ord(substr($t,1,1)),ord(substr($t,3,1)),ord(substr($t,5,1)));
\r
1527 $pos=strpos($t,chr(0));
\r
1529 $trns=array($pos);
\r
1533 elseif($type=='IDAT')
\r
1535 //Read image data block
\r
1536 $data.=fread($f,$n);
\r
1539 elseif($type=='IEND')
\r
1545 if($colspace=='Indexed' and empty($pal))
\r
1546 $this->Error('Missing palette in '.$file);
\r
1548 return array('w'=>$w,'h'=>$h,'cs'=>$colspace,'bpc'=>$bpc,'f'=>'FlateDecode','parms'=>$parms,'pal'=>$pal,'trns'=>$trns,'data'=>$data);
\r
1551 function _freadint($f)
\r
1553 //Read a 4-byte integer from file
\r
1554 $i=ord(fread($f,1))<<24;
\r
1555 $i+=ord(fread($f,1))<<16;
\r
1556 $i+=ord(fread($f,1))<<8;
\r
1557 $i+=ord(fread($f,1));
\r
1561 function _textstring($s)
\r
1563 //Format a text string
\r
1564 return '('.$this->_escape($s).')';
\r
1567 function _escape($s)
\r
1569 //Add \ before \, ( and )
\r
1570 return str_replace(')','\\)',str_replace('(','\\(',str_replace('\\','\\\\',$s)));
\r
1573 function _putstream($s)
\r
1575 $this->_out('stream');
\r
1577 $this->_out('endstream');
\r
1582 //Add a line to the document
\r
1583 if($this->state==2)
\r
1584 $this->pages[$this->page].=$s."\n";
\r
1586 $this->buffer.=$s."\n";
\r
1591 //Handle silly IE contype request
\r