Subversion Repositories ALCASAR

Rev

Details | Last modification | View Log

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