fpdf.php 44 KB

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