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