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