Passed
Push — master ( 63d1f8...7c50e7 )
by Joe Nilson
02:33
created

FPDF::AddPage()   F

Complexity

Conditions 11
Paths 1024

Size

Total Lines 67
Code Lines 45

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 11
eloc 45
c 1
b 0
f 0
nc 1024
nop 3
dl 0
loc 67
rs 3.15

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/*******************************************************************************
3
* FPDF                                                                         *
4
*                                                                              *
5
* Version: 1.83                                                                *
6
* Date:    2021-04-18                                                          *
7
* Author:  Olivier PLATHEY                                                     *
8
*******************************************************************************/
9
10
define('FPDF_VERSION','1.83');
11
12
class FPDF
13
{
14
protected $page;               // current page number
15
protected $n;                  // current object number
16
protected $offsets;            // array of object offsets
17
protected $buffer;             // buffer holding in-memory PDF
18
protected $pages;              // array containing pages
19
protected $state;              // current document state
20
protected $compress;           // compression flag
21
protected $k;                  // scale factor (number of points in user unit)
22
protected $DefOrientation;     // default orientation
23
protected $CurOrientation;     // current orientation
24
protected $StdPageSizes;       // standard page sizes
25
protected $DefPageSize;        // default page size
26
protected $CurPageSize;        // current page size
27
protected $CurRotation;        // current page rotation
28
protected $PageInfo;           // page-related data
29
protected $wPt, $hPt;          // dimensions of current page in points
30
protected $w, $h;              // dimensions of current page in user unit
31
protected $lMargin;            // left margin
32
protected $tMargin;            // top margin
33
protected $rMargin;            // right margin
34
protected $bMargin;            // page break margin
35
protected $cMargin;            // cell margin
36
protected $x, $y;              // current position in user unit
37
protected $lasth;              // height of last printed cell
38
protected $LineWidth;          // line width in user unit
39
protected $fontpath;           // path containing fonts
40
protected $CoreFonts;          // array of core font names
41
protected $fonts;              // array of used fonts
42
protected $FontFiles;          // array of font files
43
protected $encodings;          // array of encodings
44
protected $cmaps;              // array of ToUnicode CMaps
45
protected $FontFamily;         // current font family
46
protected $FontStyle;          // current font style
47
protected $underline;          // underlining flag
48
protected $CurrentFont;        // current font info
49
protected $FontSizePt;         // current font size in points
50
protected $FontSize;           // current font size in user unit
51
protected $DrawColor;          // commands for drawing color
52
protected $FillColor;          // commands for filling color
53
protected $TextColor;          // commands for text color
54
protected $ColorFlag;          // indicates whether fill and text colors are different
55
protected $WithAlpha;          // indicates whether alpha channel is used
56
protected $ws;                 // word spacing
57
protected $images;             // array of used images
58
protected $PageLinks;          // array of links in pages
59
protected $links;              // array of internal links
60
protected $AutoPageBreak;      // automatic page breaking
61
protected $PageBreakTrigger;   // threshold used to trigger page breaks
62
protected $InHeader;           // flag set when processing header
63
protected $InFooter;           // flag set when processing footer
64
protected $AliasNbPages;       // alias for total number of pages
65
protected $ZoomMode;           // zoom display mode
66
protected $LayoutMode;         // layout display mode
67
protected $metadata;           // document properties
68
protected $PDFVersion;         // PDF version number
69
70
/*******************************************************************************
71
*                               Public methods                                 *
72
*******************************************************************************/
73
74
function __construct($orientation='P', $unit='mm', $size='A4')
75
{
76
	// Some checks
77
	$this->_dochecks();
78
	// Initialization of properties
79
	$this->state = 0;
80
	$this->page = 0;
81
	$this->n = 2;
82
	$this->buffer = '';
83
	$this->pages = array();
84
	$this->PageInfo = array();
85
	$this->fonts = array();
86
	$this->FontFiles = array();
87
	$this->encodings = array();
88
	$this->cmaps = array();
89
	$this->images = array();
90
	$this->links = array();
91
	$this->InHeader = false;
92
	$this->InFooter = false;
93
	$this->lasth = 0;
94
	$this->FontFamily = '';
95
	$this->FontStyle = '';
96
	$this->FontSizePt = 12;
97
	$this->underline = false;
98
	$this->DrawColor = '0 G';
99
	$this->FillColor = '0 g';
100
	$this->TextColor = '0 g';
101
	$this->ColorFlag = false;
102
	$this->WithAlpha = false;
103
	$this->ws = 0;
104
	// Font path
105
	if(defined('FPDF_FONTPATH'))
106
	{
107
		$this->fontpath = FPDF_FONTPATH;
0 ignored issues
show
Bug introduced by
The constant FPDF_FONTPATH was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
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','verdana','calligra','Arimo-Regular');
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 rotation
154
	$this->CurRotation = 0;
155
	// Page margins (1 cm)
156
	$margin = 28.35/$this->k;
157
	$this->SetMargins($margin,$margin);
158
	// Interior cell margin (1 mm)
159
	$this->cMargin = $margin/10;
160
	// Line width (0.2 mm)
161
	$this->LineWidth = .567/$this->k;
162
	// Automatic page break
163
	$this->SetAutoPageBreak(true,2*$margin);
164
	// Default display mode
165
	$this->SetDisplayMode('default');
166
	// Enable compression
167
	$this->SetCompression(true);
168
	// Set default PDF version number
169
	$this->PDFVersion = '1.3';
170
}
171
172
function SetMargins($left, $top, $right=null)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
173
{
174
	// Set left, top and right margins
175
	$this->lMargin = $left;
176
	$this->tMargin = $top;
177
	if($right===null)
178
		$right = $left;
179
	$this->rMargin = $right;
180
}
181
182
function SetLeftMargin($margin)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
183
{
184
	// Set left margin
185
	$this->lMargin = $margin;
186
	if($this->page>0 && $this->x<$margin)
187
		$this->x = $margin;
188
}
189
190
function SetTopMargin($margin)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
191
{
192
	// Set top margin
193
	$this->tMargin = $margin;
194
}
195
196
function SetRightMargin($margin)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
197
{
198
	// Set right margin
199
	$this->rMargin = $margin;
200
}
201
202
function SetAutoPageBreak($auto, $margin=0)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
203
{
204
	// Set auto page break mode and triggering margin
205
	$this->AutoPageBreak = $auto;
206
	$this->bMargin = $margin;
207
	$this->PageBreakTrigger = $this->h-$margin;
208
}
209
210
function SetDisplayMode($zoom, $layout='default')
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
211
{
212
	// Set display mode in viewer
213
	if($zoom=='fullpage' || $zoom=='fullwidth' || $zoom=='real' || $zoom=='default' || !is_string($zoom))
214
		$this->ZoomMode = $zoom;
215
	else
216
		$this->Error('Incorrect zoom display mode: '.$zoom);
217
	if($layout=='single' || $layout=='continuous' || $layout=='two' || $layout=='default')
218
		$this->LayoutMode = $layout;
219
	else
220
		$this->Error('Incorrect layout display mode: '.$layout);
221
}
222
223
function SetCompression($compress)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
224
{
225
	// Set page compression
226
	if(function_exists('gzcompress'))
227
		$this->compress = $compress;
228
	else
229
		$this->compress = false;
230
}
231
232
function SetTitle($title, $isUTF8=false)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
233
{
234
	// Title of document
235
	$this->metadata['Title'] = $isUTF8 ? $title : utf8_encode($title);
236
}
237
238
function SetAuthor($author, $isUTF8=false)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
239
{
240
	// Author of document
241
	$this->metadata['Author'] = $isUTF8 ? $author : utf8_encode($author);
242
}
243
244
function SetSubject($subject, $isUTF8=false)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
245
{
246
	// Subject of document
247
	$this->metadata['Subject'] = $isUTF8 ? $subject : utf8_encode($subject);
248
}
249
250
function SetKeywords($keywords, $isUTF8=false)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
251
{
252
	// Keywords of document
253
	$this->metadata['Keywords'] = $isUTF8 ? $keywords : utf8_encode($keywords);
254
}
255
256
function SetCreator($creator, $isUTF8=false)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
257
{
258
	// Creator of document
259
	$this->metadata['Creator'] = $isUTF8 ? $creator : utf8_encode($creator);
260
}
261
262
function AliasNbPages($alias='{nb}')
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
263
{
264
	// Define an alias for total number of pages
265
	$this->AliasNbPages = $alias;
266
}
267
268
function Error($msg)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
269
{
270
	// Fatal error
271
	throw new Exception('FPDF error: '.$msg);
272
}
273
274
function Close()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
275
{
276
	// Terminate document
277
	if($this->state==3)
278
		return;
279
	if($this->page==0)
280
		$this->AddPage();
281
	// Page footer
282
	$this->InFooter = true;
283
	$this->Footer();
284
	$this->InFooter = false;
285
	// Close page
286
	$this->_endpage();
287
	// Close document
288
	$this->_enddoc();
289
}
290
291
function AddPage($orientation='', $size='', $rotation=0)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
292
{
293
	// Start a new page
294
	if($this->state==3)
295
		$this->Error('The document is closed');
296
	$family = $this->FontFamily;
297
	$style = $this->FontStyle.($this->underline ? 'U' : '');
298
	$fontsize = $this->FontSizePt;
299
	$lw = $this->LineWidth;
300
	$dc = $this->DrawColor;
301
	$fc = $this->FillColor;
302
	$tc = $this->TextColor;
303
	$cf = $this->ColorFlag;
304
	if($this->page>0)
305
	{
306
		// Page footer
307
		$this->InFooter = true;
308
		$this->Footer();
309
		$this->InFooter = false;
310
		// Close page
311
		$this->_endpage();
312
	}
313
	// Start new page
314
	$this->_beginpage($orientation,$size,$rotation);
315
	// Set line cap style to square
316
	$this->_out('2 J');
317
	// Set line width
318
	$this->LineWidth = $lw;
319
	$this->_out(sprintf('%.2F w',$lw*$this->k));
320
	// Set font
321
	if($family)
322
		$this->SetFont($family,$style,$fontsize);
323
	// Set colors
324
	$this->DrawColor = $dc;
325
	if($dc!='0 G')
326
		$this->_out($dc);
327
	$this->FillColor = $fc;
328
	if($fc!='0 g')
329
		$this->_out($fc);
330
	$this->TextColor = $tc;
331
	$this->ColorFlag = $cf;
332
	// Page header
333
	$this->InHeader = true;
334
	$this->Header();
335
	$this->InHeader = false;
336
	// Restore line width
337
	if($this->LineWidth!=$lw)
338
	{
339
		$this->LineWidth = $lw;
340
		$this->_out(sprintf('%.2F w',$lw*$this->k));
341
	}
342
	// Restore font
343
	if($family)
344
		$this->SetFont($family,$style,$fontsize);
345
	// Restore colors
346
	if($this->DrawColor!=$dc)
347
	{
348
		$this->DrawColor = $dc;
349
		$this->_out($dc);
350
	}
351
	if($this->FillColor!=$fc)
352
	{
353
		$this->FillColor = $fc;
354
		$this->_out($fc);
355
	}
356
	$this->TextColor = $tc;
357
	$this->ColorFlag = $cf;
358
}
359
360
function Header()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
361
{
362
	// To be implemented in your own inherited class
363
}
364
365
function Footer()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
366
{
367
	// To be implemented in your own inherited class
368
}
369
370
function PageNo()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
371
{
372
	// Get current page number
373
	return $this->page;
374
}
375
376
function SetDrawColor($r, $g=null, $b=null)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
377
{
378
	// Set color for all stroking operations
379
	if(($r==0 && $g==0 && $b==0) || $g===null)
380
		$this->DrawColor = sprintf('%.3F G',$r/255);
381
	else
382
		$this->DrawColor = sprintf('%.3F %.3F %.3F RG',$r/255,$g/255,$b/255);
383
	if($this->page>0)
384
		$this->_out($this->DrawColor);
385
}
386
387
function SetFillColor($r, $g=null, $b=null)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
388
{
389
	// Set color for all filling operations
390
	if(($r==0 && $g==0 && $b==0) || $g===null)
391
		$this->FillColor = sprintf('%.3F g',$r/255);
392
	else
393
		$this->FillColor = sprintf('%.3F %.3F %.3F rg',$r/255,$g/255,$b/255);
394
	$this->ColorFlag = ($this->FillColor!=$this->TextColor);
395
	if($this->page>0)
396
		$this->_out($this->FillColor);
397
}
398
399
function SetTextColor($r, $g=null, $b=null)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
400
{
401
	// Set color for text
402
	if(($r==0 && $g==0 && $b==0) || $g===null)
403
		$this->TextColor = sprintf('%.3F g',$r/255);
404
	else
405
		$this->TextColor = sprintf('%.3F %.3F %.3F rg',$r/255,$g/255,$b/255);
406
	$this->ColorFlag = ($this->FillColor!=$this->TextColor);
407
}
408
409
function GetStringWidth($s)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
410
{
411
	// Get width of a string in the current font
412
	$s = (string)$s;
413
	$cw = &$this->CurrentFont['cw'];
414
	$w = 0;
415
	$l = strlen($s);
416
	for($i=0;$i<$l;$i++)
417
		$w += $cw[$s[$i]];
418
	return $w*$this->FontSize/1000;
419
}
420
421
function SetLineWidth($width)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
422
{
423
	// Set line width
424
	$this->LineWidth = $width;
425
	if($this->page>0)
426
		$this->_out(sprintf('%.2F w',$width*$this->k));
427
}
428
429
function Line($x1, $y1, $x2, $y2)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
430
{
431
	// Draw a line
432
	$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));
433
}
434
435
function Rect($x, $y, $w, $h, $style='')
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
436
{
437
	// Draw a rectangle
438
	if($style=='F')
439
		$op = 'f';
440
	elseif($style=='FD' || $style=='DF')
441
		$op = 'B';
442
	else
443
		$op = 'S';
444
	$this->_out(sprintf('%.2F %.2F %.2F %.2F re %s',$x*$this->k,($this->h-$y)*$this->k,$w*$this->k,-$h*$this->k,$op));
445
}
446
447
function AddFont($family, $style='', $file='')
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
448
{
449
	// Add a TrueType, OpenType or Type1 font
450
	$family = strtolower($family);
451
	if($file=='')
452
		$file = str_replace(' ','',$family).strtolower($style).'.php';
453
	$style = strtoupper($style);
454
	if($style=='IB')
455
		$style = 'BI';
456
	$fontkey = $family.$style;
457
	if(isset($this->fonts[$fontkey]))
458
		return;
459
	$info = $this->_loadfont($file);
460
	$info['i'] = count($this->fonts)+1;
461
	if(!empty($info['file']))
462
	{
463
		// Embedded font
464
		if($info['type']=='TrueType')
465
			$this->FontFiles[$info['file']] = array('length1'=>$info['originalsize']);
466
		else
467
			$this->FontFiles[$info['file']] = array('length1'=>$info['size1'], 'length2'=>$info['size2']);
468
	}
469
	$this->fonts[$fontkey] = $info;
470
}
471
472
function SetFont($family, $style='', $size=0)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
473
{
474
	// Select a font; size given in points
475
	if($family=='')
476
		$family = $this->FontFamily;
477
	else
478
		$family = strtolower($family);
479
	$style = strtoupper($style);
480
	if(strpos($style,'U')!==false)
481
	{
482
		$this->underline = true;
483
		$style = str_replace('U','',$style);
484
	}
485
	else
486
		$this->underline = false;
487
	if($style=='IB')
488
		$style = 'BI';
489
	if($size==0)
490
		$size = $this->FontSizePt;
491
	// Test if font is already selected
492
	if($this->FontFamily==$family && $this->FontStyle==$style && $this->FontSizePt==$size)
493
		return;
494
	// Test if font is already loaded
495
	$fontkey = $family.$style;
496
	if(!isset($this->fonts[$fontkey]))
497
	{
498
		// Test if one of the core fonts
499
		if($family=='arial')
500
			$family = 'helvetica';
501
		if(in_array($family,$this->CoreFonts))
502
		{
503
			if($family=='symbol' || $family=='zapfdingbats')
504
				$style = '';
505
			$fontkey = $family.$style;
506
			if(!isset($this->fonts[$fontkey]))
507
				$this->AddFont($family,$style);
508
		}
509
		else
510
			$this->Error('Undefined font: '.$family.' '.$style);
511
	}
512
	// Select it
513
	$this->FontFamily = $family;
514
	$this->FontStyle = $style;
515
	$this->FontSizePt = $size;
516
	$this->FontSize = $size/$this->k;
517
	$this->CurrentFont = &$this->fonts[$fontkey];
518
	if($this->page>0)
519
		$this->_out(sprintf('BT /F%d %.2F Tf ET',$this->CurrentFont['i'],$this->FontSizePt));
520
}
521
522
function SetFontSize($size)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
523
{
524
	// Set font size in points
525
	if($this->FontSizePt==$size)
526
		return;
527
	$this->FontSizePt = $size;
528
	$this->FontSize = $size/$this->k;
529
	if($this->page>0)
530
		$this->_out(sprintf('BT /F%d %.2F Tf ET',$this->CurrentFont['i'],$this->FontSizePt));
531
}
532
533
function AddLink()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
534
{
535
	// Create a new internal link
536
	$n = count($this->links)+1;
537
	$this->links[$n] = array(0, 0);
538
	return $n;
539
}
540
541
function SetLink($link, $y=0, $page=-1)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
542
{
543
	// Set destination of internal link
544
	if($y==-1)
545
		$y = $this->y;
546
	if($page==-1)
547
		$page = $this->page;
548
	$this->links[$link] = array($page, $y);
549
}
550
551
function Link($x, $y, $w, $h, $link)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
552
{
553
	// Put a link on the page
554
	$this->PageLinks[$this->page][] = array($x*$this->k, $this->hPt-$y*$this->k, $w*$this->k, $h*$this->k, $link);
555
}
556
557
function Text($x, $y, $txt)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
558
{
559
	// Output a string
560
	if(!isset($this->CurrentFont))
561
		$this->Error('No font has been set');
562
	$s = sprintf('BT %.2F %.2F Td (%s) Tj ET',$x*$this->k,($this->h-$y)*$this->k,$this->_escape($txt));
563
	if($this->underline && $txt!='')
564
		$s .= ' '.$this->_dounderline($x,$y,$txt);
565
	if($this->ColorFlag)
566
		$s = 'q '.$this->TextColor.' '.$s.' Q';
567
	$this->_out($s);
568
}
569
570
function AcceptPageBreak()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
571
{
572
	// Accept automatic page break or not
573
	return $this->AutoPageBreak;
574
}
575
576
function Cell($w, $h=0, $txt='', $border=0, $ln=0, $align='', $fill=false, $link='')
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
577
{
578
	// Output a cell
579
	$k = $this->k;
580
	if($this->y+$h>$this->PageBreakTrigger && !$this->InHeader && !$this->InFooter && $this->AcceptPageBreak())
581
	{
582
		// Automatic page break
583
		$x = $this->x;
584
		$ws = $this->ws;
585
		if($ws>0)
586
		{
587
			$this->ws = 0;
588
			$this->_out('0 Tw');
589
		}
590
		$this->AddPage($this->CurOrientation,$this->CurPageSize,$this->CurRotation);
591
		$this->x = $x;
592
		if($ws>0)
593
		{
594
			$this->ws = $ws;
595
			$this->_out(sprintf('%.3F Tw',$ws*$k));
596
		}
597
	}
598
	if($w==0)
599
		$w = $this->w-$this->rMargin-$this->x;
600
	$s = '';
601
	if($fill || $border==1)
602
	{
603
		if($fill)
604
			$op = ($border==1) ? 'B' : 'f';
605
		else
606
			$op = 'S';
607
		$s = sprintf('%.2F %.2F %.2F %.2F re %s ',$this->x*$k,($this->h-$this->y)*$k,$w*$k,-$h*$k,$op);
608
	}
609
	if(is_string($border))
610
	{
611
		$x = $this->x;
612
		$y = $this->y;
613
		if(strpos($border,'L')!==false)
614
			$s .= sprintf('%.2F %.2F m %.2F %.2F l S ',$x*$k,($this->h-$y)*$k,$x*$k,($this->h-($y+$h))*$k);
615
		if(strpos($border,'T')!==false)
616
			$s .= sprintf('%.2F %.2F m %.2F %.2F l S ',$x*$k,($this->h-$y)*$k,($x+$w)*$k,($this->h-$y)*$k);
617
		if(strpos($border,'R')!==false)
618
			$s .= sprintf('%.2F %.2F m %.2F %.2F l S ',($x+$w)*$k,($this->h-$y)*$k,($x+$w)*$k,($this->h-($y+$h))*$k);
619
		if(strpos($border,'B')!==false)
620
			$s .= sprintf('%.2F %.2F m %.2F %.2F l S ',$x*$k,($this->h-($y+$h))*$k,($x+$w)*$k,($this->h-($y+$h))*$k);
621
	}
622
	if($txt!=='')
623
	{
624
		if(!isset($this->CurrentFont))
625
			$this->Error('No font has been set');
626
		if($align=='R')
627
			$dx = $w-$this->cMargin-$this->GetStringWidth($txt);
628
		elseif($align=='C')
629
			$dx = ($w-$this->GetStringWidth($txt))/2;
630
		else
631
			$dx = $this->cMargin;
632
		if($this->ColorFlag)
633
			$s .= 'q '.$this->TextColor.' ';
634
		$s .= sprintf('BT %.2F %.2F Td (%s) Tj ET',($this->x+$dx)*$k,($this->h-($this->y+.5*$h+.3*$this->FontSize))*$k,$this->_escape($txt));
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
656
function MultiCell($w, $h, $txt, $border=0, $align='J', $fill=false)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
657
{
658
	// Output text with automatic or explicit line breaks
659
	if(!isset($this->CurrentFont))
660
		$this->Error('No font has been set');
661
	$cw = &$this->CurrentFont['cw'];
662
	if($w==0)
663
		$w = $this->w-$this->rMargin-$this->x;
664
	$wmax = ($w-2*$this->cMargin)*1000/$this->FontSize;
665
	$s = str_replace("\r",'',$txt);
666
	$nb = strlen($s);
667
	if($nb>0 && $s[$nb-1]=="\n")
668
		$nb--;
669
	$b = 0;
670
	if($border)
671
	{
672
		if($border==1)
673
		{
674
			$border = 'LTRB';
675
			$b = 'LRT';
676
			$b2 = 'LR';
677
		}
678
		else
679
		{
680
			$b2 = '';
681
			if(strpos($border,'L')!==false)
682
				$b2 .= 'L';
683
			if(strpos($border,'R')!==false)
684
				$b2 .= 'R';
685
			$b = (strpos($border,'T')!==false) ? $b2.'T' : $b2;
686
		}
687
	}
688
	$sep = -1;
689
	$i = 0;
690
	$j = 0;
691
	$l = 0;
692
	$ns = 0;
693
	$nl = 1;
694
	while($i<$nb)
695
	{
696
		// Get next character
697
		$c = $s[$i];
698
		if($c=="\n")
699
		{
700
			// Explicit line break
701
			if($this->ws>0)
702
			{
703
				$this->ws = 0;
704
				$this->_out('0 Tw');
705
			}
706
			$this->Cell($w,$h,substr($s,$j,$i-$j),$b,2,$align,$fill);
707
			$i++;
708
			$sep = -1;
709
			$j = $i;
710
			$l = 0;
711
			$ns = 0;
712
			$nl++;
713
			if($border && $nl==2)
714
				$b = $b2;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $b2 does not seem to be defined for all execution paths leading up to this point.
Loading history...
715
			continue;
716
		}
717
		if($c==' ')
718
		{
719
			$sep = $i;
720
			$ls = $l;
721
			$ns++;
722
		}
723
		$l += $cw[$c];
724
		if($l>$wmax)
725
		{
726
			// Automatic line break
727
			if($sep==-1)
728
			{
729
				if($i==$j)
730
					$i++;
731
				if($this->ws>0)
732
				{
733
					$this->ws = 0;
734
					$this->_out('0 Tw');
735
				}
736
				$this->Cell($w,$h,substr($s,$j,$i-$j),$b,2,$align,$fill);
737
			}
738
			else
739
			{
740
				if($align=='J')
741
				{
742
					$this->ws = ($ns>1) ? ($wmax-$ls)/1000*$this->FontSize/($ns-1) : 0;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $ls does not seem to be defined for all execution paths leading up to this point.
Loading history...
743
					$this->_out(sprintf('%.3F Tw',$this->ws*$this->k));
744
				}
745
				$this->Cell($w,$h,substr($s,$j,$sep-$j),$b,2,$align,$fill);
746
				$i = $sep+1;
747
			}
748
			$sep = -1;
749
			$j = $i;
750
			$l = 0;
751
			$ns = 0;
752
			$nl++;
753
			if($border && $nl==2)
754
				$b = $b2;
755
		}
756
		else
757
			$i++;
758
	}
759
	// Last chunk
760
	if($this->ws>0)
761
	{
762
		$this->ws = 0;
763
		$this->_out('0 Tw');
764
	}
765
	if($border && strpos($border,'B')!==false)
766
		$b .= 'B';
767
	$this->Cell($w,$h,substr($s,$j,$i-$j),$b,2,$align,$fill);
768
	$this->x = $this->lMargin;
769
}
770
771
function Write($h, $txt, $link='')
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
772
{
773
	// Output text in flowing mode
774
	if(!isset($this->CurrentFont))
775
		$this->Error('No font has been set');
776
	$cw = &$this->CurrentFont['cw'];
777
	$w = $this->w-$this->rMargin-$this->x;
778
	$wmax = ($w-2*$this->cMargin)*1000/$this->FontSize;
779
	$s = str_replace("\r",'',$txt);
780
	$nb = strlen($s);
781
	$sep = -1;
782
	$i = 0;
783
	$j = 0;
784
	$l = 0;
785
	$nl = 1;
786
	while($i<$nb)
787
	{
788
		// Get next character
789
		$c = $s[$i];
790
		if($c=="\n")
791
		{
792
			// Explicit line break
793
			$this->Cell($w,$h,substr($s,$j,$i-$j),0,2,'',false,$link);
794
			$i++;
795
			$sep = -1;
796
			$j = $i;
797
			$l = 0;
798
			if($nl==1)
799
			{
800
				$this->x = $this->lMargin;
801
				$w = $this->w-$this->rMargin-$this->x;
802
				$wmax = ($w-2*$this->cMargin)*1000/$this->FontSize;
803
			}
804
			$nl++;
805
			continue;
806
		}
807
		if($c==' ')
808
			$sep = $i;
809
		$l += $cw[$c];
810
		if($l>$wmax)
811
		{
812
			// Automatic line break
813
			if($sep==-1)
814
			{
815
				if($this->x>$this->lMargin)
816
				{
817
					// Move to next line
818
					$this->x = $this->lMargin;
819
					$this->y += $h;
820
					$w = $this->w-$this->rMargin-$this->x;
821
					$wmax = ($w-2*$this->cMargin)*1000/$this->FontSize;
822
					$i++;
823
					$nl++;
824
					continue;
825
				}
826
				if($i==$j)
827
					$i++;
828
				$this->Cell($w,$h,substr($s,$j,$i-$j),0,2,'',false,$link);
829
			}
830
			else
831
			{
832
				$this->Cell($w,$h,substr($s,$j,$sep-$j),0,2,'',false,$link);
833
				$i = $sep+1;
834
			}
835
			$sep = -1;
836
			$j = $i;
837
			$l = 0;
838
			if($nl==1)
839
			{
840
				$this->x = $this->lMargin;
841
				$w = $this->w-$this->rMargin-$this->x;
842
				$wmax = ($w-2*$this->cMargin)*1000/$this->FontSize;
843
			}
844
			$nl++;
845
		}
846
		else
847
			$i++;
848
	}
849
	// Last chunk
850
	if($i!=$j)
851
		$this->Cell($l/1000*$this->FontSize,$h,substr($s,$j),0,0,'',false,$link);
852
}
853
854
function Ln($h=null)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
855
{
856
	// Line feed; default value is the last cell height
857
	$this->x = $this->lMargin;
858
	if($h===null)
859
		$this->y += $this->lasth;
860
	else
861
		$this->y += $h;
862
}
863
864
function Image($file, $x=null, $y=null, $w=0, $h=0, $type='', $link='')
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
865
{
866
	// Put an image on the page
867
	if($file=='')
868
		$this->Error('Image file name is empty');
869
	if(!isset($this->images[$file]))
870
	{
871
		// First use of this image, get info
872
		if($type=='')
873
		{
874
			$pos = strrpos($file,'.');
875
			if(!$pos)
876
				$this->Error('Image file has no extension and no type was specified: '.$file);
877
			$type = substr($file,$pos+1);
878
		}
879
		$type = strtolower($type);
880
		if($type=='jpeg')
881
			$type = 'jpg';
882
		$mtd = '_parse'.$type;
883
		if(!method_exists($this,$mtd))
884
			$this->Error('Unsupported image type: '.$type);
885
		$info = $this->$mtd($file);
886
		$info['i'] = count($this->images)+1;
887
		$this->images[$file] = $info;
888
	}
889
	else
890
		$info = $this->images[$file];
891
892
	// Automatic width and height calculation if needed
893
	if($w==0 && $h==0)
894
	{
895
		// Put image at 96 dpi
896
		$w = -96;
897
		$h = -96;
898
	}
899
	if($w<0)
900
		$w = -$info['w']*72/$w/$this->k;
901
	if($h<0)
902
		$h = -$info['h']*72/$h/$this->k;
903
	if($w==0)
904
		$w = $h*$info['w']/$info['h'];
905
	if($h==0)
906
		$h = $w*$info['h']/$info['w'];
907
908
	// Flowing mode
909
	if($y===null)
910
	{
911
		if($this->y+$h>$this->PageBreakTrigger && !$this->InHeader && !$this->InFooter && $this->AcceptPageBreak())
912
		{
913
			// Automatic page break
914
			$x2 = $this->x;
915
			$this->AddPage($this->CurOrientation,$this->CurPageSize,$this->CurRotation);
916
			$this->x = $x2;
917
		}
918
		$y = $this->y;
919
		$this->y += $h;
920
	}
921
922
	if($x===null)
923
		$x = $this->x;
924
	$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']));
925
	if($link)
926
		$this->Link($x,$y,$w,$h,$link);
927
}
928
929
function GetPageWidth()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
930
{
931
	// Get current page width
932
	return $this->w;
933
}
934
935
function GetPageHeight()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
936
{
937
	// Get current page height
938
	return $this->h;
939
}
940
941
function GetX()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
942
{
943
	// Get x position
944
	return $this->x;
945
}
946
947
function SetX($x)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
948
{
949
	// Set x position
950
	if($x>=0)
951
		$this->x = $x;
952
	else
953
		$this->x = $this->w+$x;
954
}
955
956
function GetY()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
957
{
958
	// Get y position
959
	return $this->y;
960
}
961
962
function SetY($y, $resetX=true)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
963
{
964
	// Set y position and optionally reset x
965
	if($y>=0)
966
		$this->y = $y;
967
	else
968
		$this->y = $this->h+$y;
969
	if($resetX)
970
		$this->x = $this->lMargin;
971
}
972
973
function SetXY($x, $y)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
974
{
975
	// Set x and y positions
976
	$this->SetX($x);
977
	$this->SetY($y,false);
978
}
979
980
function Output($dest='', $name='', $isUTF8=false)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
981
{
982
	// Output PDF to some destination
983
	$this->Close();
984
	if(strlen($name)==1 && strlen($dest)!=1)
985
	{
986
		// Fix parameter order
987
		$tmp = $dest;
988
		$dest = $name;
989
		$name = $tmp;
990
	}
991
	if($dest=='')
992
		$dest = 'I';
993
	if($name=='')
994
		$name = 'doc.pdf';
995
	switch(strtoupper($dest))
996
	{
997
		case 'I':
998
			// Send to standard output
999
			$this->_checkoutput();
1000
			if(PHP_SAPI!='cli')
1001
			{
1002
				// We send to a browser
1003
				header('Content-Type: application/pdf');
1004
				header('Content-Disposition: inline; '.$this->_httpencode('filename',$name,$isUTF8));
1005
				header('Cache-Control: private, max-age=0, must-revalidate');
1006
				header('Pragma: public');
1007
			}
1008
			echo $this->buffer;
1009
			break;
1010
		case 'D':
1011
			// Download file
1012
			$this->_checkoutput();
1013
			header('Content-Type: application/x-download');
1014
			header('Content-Disposition: attachment; '.$this->_httpencode('filename',$name,$isUTF8));
1015
			header('Cache-Control: private, max-age=0, must-revalidate');
1016
			header('Pragma: public');
1017
			echo $this->buffer;
1018
			break;
1019
		case 'F':
1020
			// Save to local file
1021
			if(!file_put_contents($name,$this->buffer))
1022
				$this->Error('Unable to create output file: '.$name);
1023
			break;
1024
		case 'S':
1025
			// Return as a string
1026
			return $this->buffer;
1027
		default:
1028
			$this->Error('Incorrect output destination: '.$dest);
1029
	}
1030
	return '';
1031
}
1032
1033
/*******************************************************************************
1034
*                              Protected methods                               *
1035
*******************************************************************************/
1036
1037
protected function _dochecks()
1038
{
1039
	// Check mbstring overloading
1040
	if(ini_get('mbstring.func_overload') & 2)
1041
		$this->Error('mbstring overloading must be disabled');
1042
}
1043
1044
protected function _checkoutput()
1045
{
1046
	if(PHP_SAPI!='cli')
1047
	{
1048
		if(headers_sent($file,$line))
1049
			$this->Error("Some data has already been output, can't send PDF file (output started at $file:$line)");
1050
	}
1051
	if(ob_get_length())
1052
	{
1053
		// The output buffer is not empty
1054
		if(preg_match('/^(\xEF\xBB\xBF)?\s*$/',ob_get_contents()))
1055
		{
1056
			// It contains only a UTF-8 BOM and/or whitespace, let's clean it
1057
			ob_clean();
1058
		}
1059
		else
1060
			$this->Error("Some data has already been output, can't send PDF file");
1061
	}
1062
}
1063
1064
protected function _getpagesize($size)
1065
{
1066
	if(is_string($size))
1067
	{
1068
		$size = strtolower($size);
1069
		if(!isset($this->StdPageSizes[$size]))
1070
			$this->Error('Unknown page size: '.$size);
1071
		$a = $this->StdPageSizes[$size];
1072
		return array($a[0]/$this->k, $a[1]/$this->k);
1073
	}
1074
	else
1075
	{
1076
		if($size[0]>$size[1])
1077
			return array($size[1], $size[0]);
1078
		else
1079
			return $size;
1080
	}
1081
}
1082
1083
protected function _beginpage($orientation, $size, $rotation)
1084
{
1085
	$this->page++;
1086
	$this->pages[$this->page] = '';
1087
	$this->PageLinks[$this->page] = array();
1088
	$this->state = 2;
1089
	$this->x = $this->lMargin;
1090
	$this->y = $this->tMargin;
1091
	$this->FontFamily = '';
1092
	// Check page size and orientation
1093
	if($orientation=='')
1094
		$orientation = $this->DefOrientation;
1095
	else
1096
		$orientation = strtoupper($orientation[0]);
1097
	if($size=='')
1098
		$size = $this->DefPageSize;
1099
	else
1100
		$size = $this->_getpagesize($size);
1101
	if($orientation!=$this->CurOrientation || $size[0]!=$this->CurPageSize[0] || $size[1]!=$this->CurPageSize[1])
1102
	{
1103
		// New size or orientation
1104
		if($orientation=='P')
1105
		{
1106
			$this->w = $size[0];
1107
			$this->h = $size[1];
1108
		}
1109
		else
1110
		{
1111
			$this->w = $size[1];
1112
			$this->h = $size[0];
1113
		}
1114
		$this->wPt = $this->w*$this->k;
1115
		$this->hPt = $this->h*$this->k;
1116
		$this->PageBreakTrigger = $this->h-$this->bMargin;
1117
		$this->CurOrientation = $orientation;
1118
		$this->CurPageSize = $size;
1119
	}
1120
	if($orientation!=$this->DefOrientation || $size[0]!=$this->DefPageSize[0] || $size[1]!=$this->DefPageSize[1])
1121
		$this->PageInfo[$this->page]['size'] = array($this->wPt, $this->hPt);
1122
	if($rotation!=0)
1123
	{
1124
		if($rotation%90!=0)
1125
			$this->Error('Incorrect rotation value: '.$rotation);
1126
		$this->CurRotation = $rotation;
1127
		$this->PageInfo[$this->page]['rotation'] = $rotation;
1128
	}
1129
}
1130
1131
protected function _endpage()
1132
{
1133
	$this->state = 1;
1134
}
1135
1136
protected function _loadfont($font)
1137
{
1138
	// Load a font definition file from the font directory
1139
	if(strpos($font,'/')!==false || strpos($font,"\\")!==false)
1140
		$this->Error('Incorrect font definition file name: '.$font);
1141
	include($this->fontpath.$font);
1142
	if(!isset($name))
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $name seems to never exist and therefore isset should always be false.
Loading history...
1143
		$this->Error('Could not include font definition file');
1144
	if(isset($enc))
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $enc seems to never exist and therefore isset should always be false.
Loading history...
1145
		$enc = strtolower($enc);
1146
	if(!isset($subsetted))
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $subsetted seems to never exist and therefore isset should always be false.
Loading history...
1147
		$subsetted = false;
1148
	return get_defined_vars();
1149
}
1150
1151
protected function _isascii($s)
1152
{
1153
	// Test if string is ASCII
1154
	$nb = strlen($s);
1155
	for($i=0;$i<$nb;$i++)
1156
	{
1157
		if(ord($s[$i])>127)
1158
			return false;
1159
	}
1160
	return true;
1161
}
1162
1163
protected function _httpencode($param, $value, $isUTF8)
1164
{
1165
	// Encode HTTP header field parameter
1166
	if($this->_isascii($value))
1167
		return $param.'="'.$value.'"';
1168
	if(!$isUTF8)
1169
		$value = utf8_encode($value);
1170
	if(strpos($_SERVER['HTTP_USER_AGENT'],'MSIE')!==false)
1171
		return $param.'="'.rawurlencode($value).'"';
1172
	else
1173
		return $param."*=UTF-8''".rawurlencode($value);
1174
}
1175
1176
protected function _UTF8toUTF16($s)
1177
{
1178
	// Convert UTF-8 to UTF-16BE with BOM
1179
	$res = "\xFE\xFF";
1180
	$nb = strlen($s);
1181
	$i = 0;
1182
	while($i<$nb)
1183
	{
1184
		$c1 = ord($s[$i++]);
1185
		if($c1>=224)
1186
		{
1187
			// 3-byte character
1188
			$c2 = ord($s[$i++]);
1189
			$c3 = ord($s[$i++]);
1190
			$res .= chr((($c1 & 0x0F)<<4) + (($c2 & 0x3C)>>2));
1191
			$res .= chr((($c2 & 0x03)<<6) + ($c3 & 0x3F));
1192
		}
1193
		elseif($c1>=192)
1194
		{
1195
			// 2-byte character
1196
			$c2 = ord($s[$i++]);
1197
			$res .= chr(($c1 & 0x1C)>>2);
1198
			$res .= chr((($c1 & 0x03)<<6) + ($c2 & 0x3F));
1199
		}
1200
		else
1201
		{
1202
			// Single-byte character
1203
			$res .= "\0".chr($c1);
1204
		}
1205
	}
1206
	return $res;
1207
}
1208
1209
protected function _escape($s)
1210
{
1211
	// Escape special characters
1212
	if(strpos($s,'(')!==false || strpos($s,')')!==false || strpos($s,'\\')!==false || strpos($s,"\r")!==false)
1213
		return str_replace(array('\\','(',')',"\r"), array('\\\\','\\(','\\)','\\r'), $s);
1214
	else
1215
		return $s;
1216
}
1217
1218
protected function _textstring($s)
1219
{
1220
	// Format a text string
1221
	if(!$this->_isascii($s))
1222
		$s = $this->_UTF8toUTF16($s);
1223
	return '('.$this->_escape($s).')';
1224
}
1225
1226
protected function _dounderline($x, $y, $txt)
1227
{
1228
	// Underline text
1229
	$up = $this->CurrentFont['up'];
1230
	$ut = $this->CurrentFont['ut'];
1231
	$w = $this->GetStringWidth($txt)+$this->ws*substr_count($txt,' ');
1232
	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);
1233
}
1234
1235
protected function _parsejpg($file)
1236
{
1237
	// Extract info from a JPEG file
1238
	$a = getimagesize($file);
1239
	if(!$a)
0 ignored issues
show
Bug Best Practice introduced by
The expression $a of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
1240
		$this->Error('Missing or incorrect image file: '.$file);
1241
	if($a[2]!=2)
1242
		$this->Error('Not a JPEG file: '.$file);
1243
	if(!isset($a['channels']) || $a['channels']==3)
1244
		$colspace = 'DeviceRGB';
1245
	elseif($a['channels']==4)
1246
		$colspace = 'DeviceCMYK';
1247
	else
1248
		$colspace = 'DeviceGray';
1249
	$bpc = isset($a['bits']) ? $a['bits'] : 8;
1250
	$data = file_get_contents($file);
1251
	return array('w'=>$a[0], 'h'=>$a[1], 'cs'=>$colspace, 'bpc'=>$bpc, 'f'=>'DCTDecode', 'data'=>$data);
1252
}
1253
1254
protected function _parsepng($file)
1255
{
1256
	// Extract info from a PNG file
1257
	$f = fopen($file,'rb');
1258
	if(!$f)
0 ignored issues
show
introduced by
$f is of type resource, thus it always evaluated to false.
Loading history...
1259
		$this->Error('Can\'t open image file: '.$file);
1260
	$info = $this->_parsepngstream($f,$file);
1261
	fclose($f);
1262
	return $info;
1263
}
1264
1265
protected function _parsepngstream($f, $file)
1266
{
1267
	// Check signature
1268
	if($this->_readstream($f,8)!=chr(137).'PNG'.chr(13).chr(10).chr(26).chr(10))
1269
		$this->Error('Not a PNG file: '.$file);
1270
1271
	// Read header chunk
1272
	$this->_readstream($f,4);
1273
	if($this->_readstream($f,4)!='IHDR')
1274
		$this->Error('Incorrect PNG file: '.$file);
1275
	$w = $this->_readint($f);
1276
	$h = $this->_readint($f);
1277
	$bpc = ord($this->_readstream($f,1));
1278
	if($bpc>8)
1279
		$this->Error('16-bit depth not supported: '.$file);
1280
	$ct = ord($this->_readstream($f,1));
1281
	if($ct==0 || $ct==4)
1282
		$colspace = 'DeviceGray';
1283
	elseif($ct==2 || $ct==6)
1284
		$colspace = 'DeviceRGB';
1285
	elseif($ct==3)
1286
		$colspace = 'Indexed';
1287
	else
1288
		$this->Error('Unknown color type: '.$file);
1289
	if(ord($this->_readstream($f,1))!=0)
1290
		$this->Error('Unknown compression method: '.$file);
1291
	if(ord($this->_readstream($f,1))!=0)
1292
		$this->Error('Unknown filter method: '.$file);
1293
	if(ord($this->_readstream($f,1))!=0)
1294
		$this->Error('Interlacing not supported: '.$file);
1295
	$this->_readstream($f,4);
1296
	$dp = '/Predictor 15 /Colors '.($colspace=='DeviceRGB' ? 3 : 1).' /BitsPerComponent '.$bpc.' /Columns '.$w;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $colspace does not seem to be defined for all execution paths leading up to this point.
Loading history...
1297
1298
	// Scan chunks looking for palette, transparency and image data
1299
	$pal = '';
1300
	$trns = '';
1301
	$data = '';
1302
	do
1303
	{
1304
		$n = $this->_readint($f);
1305
		$type = $this->_readstream($f,4);
1306
		if($type=='PLTE')
1307
		{
1308
			// Read palette
1309
			$pal = $this->_readstream($f,$n);
1310
			$this->_readstream($f,4);
1311
		}
1312
		elseif($type=='tRNS')
1313
		{
1314
			// Read transparency info
1315
			$t = $this->_readstream($f,$n);
1316
			if($ct==0)
1317
				$trns = array(ord(substr($t,1,1)));
1318
			elseif($ct==2)
1319
				$trns = array(ord(substr($t,1,1)), ord(substr($t,3,1)), ord(substr($t,5,1)));
1320
			else
1321
			{
1322
				$pos = strpos($t,chr(0));
1323
				if($pos!==false)
1324
					$trns = array($pos);
1325
			}
1326
			$this->_readstream($f,4);
1327
		}
1328
		elseif($type=='IDAT')
1329
		{
1330
			// Read image data block
1331
			$data .= $this->_readstream($f,$n);
1332
			$this->_readstream($f,4);
1333
		}
1334
		elseif($type=='IEND')
1335
			break;
1336
		else
1337
			$this->_readstream($f,$n+4);
1338
	}
1339
	while($n);
1340
1341
	if($colspace=='Indexed' && empty($pal))
1342
		$this->Error('Missing palette in '.$file);
1343
	$info = array('w'=>$w, 'h'=>$h, 'cs'=>$colspace, 'bpc'=>$bpc, 'f'=>'FlateDecode', 'dp'=>$dp, 'pal'=>$pal, 'trns'=>$trns);
1344
	if($ct>=4)
1345
	{
1346
		// Extract alpha channel
1347
		if(!function_exists('gzuncompress'))
1348
			$this->Error('Zlib not available, can\'t handle alpha channel: '.$file);
1349
		$data = gzuncompress($data);
1350
		$color = '';
1351
		$alpha = '';
1352
		if($ct==4)
1353
		{
1354
			// Gray image
1355
			$len = 2*$w;
1356
			for($i=0;$i<$h;$i++)
1357
			{
1358
				$pos = (1+$len)*$i;
1359
				$color .= $data[$pos];
1360
				$alpha .= $data[$pos];
1361
				$line = substr($data,$pos+1,$len);
1362
				$color .= preg_replace('/(.)./s','$1',$line);
1363
				$alpha .= preg_replace('/.(.)/s','$1',$line);
1364
			}
1365
		}
1366
		else
1367
		{
1368
			// RGB image
1369
			$len = 4*$w;
1370
			for($i=0;$i<$h;$i++)
1371
			{
1372
				$pos = (1+$len)*$i;
1373
				$color .= $data[$pos];
1374
				$alpha .= $data[$pos];
1375
				$line = substr($data,$pos+1,$len);
1376
				$color .= preg_replace('/(.{3})./s','$1',$line);
1377
				$alpha .= preg_replace('/.{3}(.)/s','$1',$line);
1378
			}
1379
		}
1380
		unset($data);
1381
		$data = gzcompress($color);
1382
		$info['smask'] = gzcompress($alpha);
1383
		$this->WithAlpha = true;
1384
		if($this->PDFVersion<'1.4')
1385
			$this->PDFVersion = '1.4';
1386
	}
1387
	$info['data'] = $data;
1388
	return $info;
1389
}
1390
1391
protected function _readstream($f, $n)
1392
{
1393
	// Read n bytes from stream
1394
	$res = '';
1395
	while($n>0 && !feof($f))
1396
	{
1397
		$s = fread($f,$n);
1398
		if($s===false)
1399
			$this->Error('Error while reading stream');
1400
		$n -= strlen($s);
1401
		$res .= $s;
1402
	}
1403
	if($n>0)
1404
		$this->Error('Unexpected end of stream');
1405
	return $res;
1406
}
1407
1408
protected function _readint($f)
1409
{
1410
	// Read a 4-byte integer from stream
1411
	$a = unpack('Ni',$this->_readstream($f,4));
1412
	return $a['i'];
1413
}
1414
1415
protected function _parsegif($file)
1416
{
1417
	// Extract info from a GIF file (via PNG conversion)
1418
	if(!function_exists('imagepng'))
1419
		$this->Error('GD extension is required for GIF support');
1420
	if(!function_exists('imagecreatefromgif'))
1421
		$this->Error('GD has no GIF read support');
1422
	$im = imagecreatefromgif($file);
1423
	if(!$im)
1424
		$this->Error('Missing or incorrect image file: '.$file);
1425
	imageinterlace($im,0);
1426
	ob_start();
1427
	imagepng($im);
1428
	$data = ob_get_clean();
1429
	imagedestroy($im);
1430
	$f = fopen('php://temp','rb+');
1431
	if(!$f)
0 ignored issues
show
introduced by
$f is of type resource, thus it always evaluated to false.
Loading history...
1432
		$this->Error('Unable to create memory stream');
1433
	fwrite($f,$data);
1434
	rewind($f);
1435
	$info = $this->_parsepngstream($f,$file);
1436
	fclose($f);
1437
	return $info;
1438
}
1439
1440
protected function _out($s)
1441
{
1442
	// Add a line to the document
1443
	if($this->state==2)
1444
		$this->pages[$this->page] .= $s."\n";
1445
	elseif($this->state==1)
1446
		$this->_put($s);
1447
	elseif($this->state==0)
1448
		$this->Error('No page has been added yet');
1449
	elseif($this->state==3)
1450
		$this->Error('The document is closed');
1451
}
1452
1453
protected function _put($s)
1454
{
1455
	$this->buffer .= $s."\n";
1456
}
1457
1458
protected function _getoffset()
1459
{
1460
	return strlen($this->buffer);
1461
}
1462
1463
protected function _newobj($n=null)
1464
{
1465
	// Begin a new object
1466
	if($n===null)
1467
		$n = ++$this->n;
1468
	$this->offsets[$n] = $this->_getoffset();
1469
	$this->_put($n.' 0 obj');
1470
}
1471
1472
protected function _putstream($data)
1473
{
1474
	$this->_put('stream');
1475
	$this->_put($data);
1476
	$this->_put('endstream');
1477
}
1478
1479
protected function _putstreamobject($data)
1480
{
1481
	if($this->compress)
1482
	{
1483
		$entries = '/Filter /FlateDecode ';
1484
		$data = gzcompress($data);
1485
	}
1486
	else
1487
		$entries = '';
1488
	$entries .= '/Length '.strlen($data);
1489
	$this->_newobj();
1490
	$this->_put('<<'.$entries.'>>');
1491
	$this->_putstream($data);
1492
	$this->_put('endobj');
1493
}
1494
1495
protected function _putpage($n)
1496
{
1497
	$this->_newobj();
1498
	$this->_put('<</Type /Page');
1499
	$this->_put('/Parent 1 0 R');
1500
	if(isset($this->PageInfo[$n]['size']))
1501
		$this->_put(sprintf('/MediaBox [0 0 %.2F %.2F]',$this->PageInfo[$n]['size'][0],$this->PageInfo[$n]['size'][1]));
1502
	if(isset($this->PageInfo[$n]['rotation']))
1503
		$this->_put('/Rotate '.$this->PageInfo[$n]['rotation']);
1504
	$this->_put('/Resources 2 0 R');
1505
	if(!empty($this->PageLinks[$n]))
1506
	{
1507
		$s = '/Annots [';
1508
		foreach($this->PageLinks[$n] as $pl)
1509
			$s .= $pl[5].' 0 R ';
1510
		$s .= ']';
1511
		$this->_put($s);
1512
	}
1513
	if($this->WithAlpha)
1514
		$this->_put('/Group <</Type /Group /S /Transparency /CS /DeviceRGB>>');
1515
	$this->_put('/Contents '.($this->n+1).' 0 R>>');
1516
	$this->_put('endobj');
1517
	// Page content
1518
	if(!empty($this->AliasNbPages))
1519
		$this->pages[$n] = str_replace($this->AliasNbPages,$this->page,$this->pages[$n]);
1520
	$this->_putstreamobject($this->pages[$n]);
1521
	// Annotations
1522
	foreach($this->PageLinks[$n] as $pl)
1523
	{
1524
		$rect = sprintf('%.2F %.2F %.2F %.2F',$pl[0],$pl[1],$pl[0]+$pl[2],$pl[1]-$pl[3]);
1525
		$s = '<</Type /Annot /Subtype /Link /Rect ['.$rect.'] /Border [0 0 0] ';
1526
		if(is_string($pl[4]))
1527
			$s .= '/A <</S /URI /URI '.$this->_textstring($pl[4]).'>>>>';
1528
		else
1529
		{
1530
			$l = $this->links[$pl[4]];
1531
			if(isset($this->PageInfo[$l[0]]['size']))
1532
				$h = $this->PageInfo[$l[0]]['size'][1];
1533
			else
1534
				$h = ($this->DefOrientation=='P') ? $this->DefPageSize[1]*$this->k : $this->DefPageSize[0]*$this->k;
1535
			$s .= sprintf('/Dest [%d 0 R /XYZ 0 %.2F null]>>',$this->PageInfo[$l[0]]['n'],$h-$l[1]*$this->k);
1536
		}
1537
		$this->_newobj();
1538
		$this->_put($s);
1539
		$this->_put('endobj');
1540
	}
1541
}
1542
1543
protected function _putpages()
1544
{
1545
	$nb = $this->page;
1546
	$n = $this->n;
1547
	for($i=1;$i<=$nb;$i++)
1548
	{
1549
		$this->PageInfo[$i]['n'] = ++$n;
1550
		$n++;
1551
		foreach($this->PageLinks[$i] as &$pl)
1552
			$pl[5] = ++$n;
1553
		unset($pl);
1554
	}
1555
	for($i=1;$i<=$nb;$i++)
1556
		$this->_putpage($i);
1557
	// Pages root
1558
	$this->_newobj(1);
1559
	$this->_put('<</Type /Pages');
1560
	$kids = '/Kids [';
1561
	for($i=1;$i<=$nb;$i++)
1562
		$kids .= $this->PageInfo[$i]['n'].' 0 R ';
1563
	$kids .= ']';
1564
	$this->_put($kids);
1565
	$this->_put('/Count '.$nb);
1566
	if($this->DefOrientation=='P')
1567
	{
1568
		$w = $this->DefPageSize[0];
1569
		$h = $this->DefPageSize[1];
1570
	}
1571
	else
1572
	{
1573
		$w = $this->DefPageSize[1];
1574
		$h = $this->DefPageSize[0];
1575
	}
1576
	$this->_put(sprintf('/MediaBox [0 0 %.2F %.2F]',$w*$this->k,$h*$this->k));
1577
	$this->_put('>>');
1578
	$this->_put('endobj');
1579
}
1580
1581
protected function _putfonts()
1582
{
1583
	foreach($this->FontFiles as $file=>$info)
1584
	{
1585
		// Font file embedding
1586
		$this->_newobj();
1587
		$this->FontFiles[$file]['n'] = $this->n;
1588
		$font = file_get_contents($this->fontpath.$file,true);
1589
		if(!$font)
1590
			$this->Error('Font file not found: '.$file);
1591
		$compressed = (substr($file,-2)=='.z');
1592
		if(!$compressed && isset($info['length2']))
1593
			$font = substr($font,6,$info['length1']).substr($font,6+$info['length1']+6,$info['length2']);
1594
		$this->_put('<</Length '.strlen($font));
1595
		if($compressed)
1596
			$this->_put('/Filter /FlateDecode');
1597
		$this->_put('/Length1 '.$info['length1']);
1598
		if(isset($info['length2']))
1599
			$this->_put('/Length2 '.$info['length2'].' /Length3 0');
1600
		$this->_put('>>');
1601
		$this->_putstream($font);
1602
		$this->_put('endobj');
1603
	}
1604
	foreach($this->fonts as $k=>$font)
1605
	{
1606
		// Encoding
1607
		if(isset($font['diff']))
1608
		{
1609
			if(!isset($this->encodings[$font['enc']]))
1610
			{
1611
				$this->_newobj();
1612
				$this->_put('<</Type /Encoding /BaseEncoding /WinAnsiEncoding /Differences ['.$font['diff'].']>>');
1613
				$this->_put('endobj');
1614
				$this->encodings[$font['enc']] = $this->n;
1615
			}
1616
		}
1617
		// ToUnicode CMap
1618
		if(isset($font['uv']))
1619
		{
1620
			if(isset($font['enc']))
1621
				$cmapkey = $font['enc'];
1622
			else
1623
				$cmapkey = $font['name'];
1624
			if(!isset($this->cmaps[$cmapkey]))
1625
			{
1626
				$cmap = $this->_tounicodecmap($font['uv']);
1627
				$this->_putstreamobject($cmap);
1628
				$this->cmaps[$cmapkey] = $this->n;
1629
			}
1630
		}
1631
		// Font object
1632
		$this->fonts[$k]['n'] = $this->n+1;
1633
		$type = $font['type'];
1634
		$name = $font['name'];
1635
		if($font['subsetted'])
1636
			$name = 'AAAAAA+'.$name;
1637
		if($type=='Core')
1638
		{
1639
			// Core font
1640
			$this->_newobj();
1641
			$this->_put('<</Type /Font');
1642
			$this->_put('/BaseFont /'.$name);
1643
			$this->_put('/Subtype /Type1');
1644
			if($name!='Symbol' && $name!='ZapfDingbats')
1645
				$this->_put('/Encoding /WinAnsiEncoding');
1646
			if(isset($font['uv']))
1647
				$this->_put('/ToUnicode '.$this->cmaps[$cmapkey].' 0 R');
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $cmapkey does not seem to be defined for all execution paths leading up to this point.
Loading history...
1648
			$this->_put('>>');
1649
			$this->_put('endobj');
1650
		}
1651
		elseif($type=='Type1' || $type=='TrueType')
1652
		{
1653
			// Additional Type1 or TrueType/OpenType font
1654
			$this->_newobj();
1655
			$this->_put('<</Type /Font');
1656
			$this->_put('/BaseFont /'.$name);
1657
			$this->_put('/Subtype /'.$type);
1658
			$this->_put('/FirstChar 32 /LastChar 255');
1659
			$this->_put('/Widths '.($this->n+1).' 0 R');
1660
			$this->_put('/FontDescriptor '.($this->n+2).' 0 R');
1661
			if(isset($font['diff']))
1662
				$this->_put('/Encoding '.$this->encodings[$font['enc']].' 0 R');
1663
			else
1664
				$this->_put('/Encoding /WinAnsiEncoding');
1665
			if(isset($font['uv']))
1666
				$this->_put('/ToUnicode '.$this->cmaps[$cmapkey].' 0 R');
1667
			$this->_put('>>');
1668
			$this->_put('endobj');
1669
			// Widths
1670
			$this->_newobj();
1671
			$cw = &$font['cw'];
1672
			$s = '[';
1673
			for($i=32;$i<=255;$i++)
1674
				$s .= $cw[chr($i)].' ';
1675
			$this->_put($s.']');
1676
			$this->_put('endobj');
1677
			// Descriptor
1678
			$this->_newobj();
1679
			$s = '<</Type /FontDescriptor /FontName /'.$name;
1680
			foreach($font['desc'] as $k=>$v)
0 ignored issues
show
Comprehensibility Bug introduced by
$k is overwriting a variable from outer foreach loop.
Loading history...
1681
				$s .= ' /'.$k.' '.$v;
1682
			if(!empty($font['file']))
1683
				$s .= ' /FontFile'.($type=='Type1' ? '' : '2').' '.$this->FontFiles[$font['file']]['n'].' 0 R';
1684
			$this->_put($s.'>>');
1685
			$this->_put('endobj');
1686
		}
1687
		else
1688
		{
1689
			// Allow for additional types
1690
			$mtd = '_put'.strtolower($type);
1691
			if(!method_exists($this,$mtd))
1692
				$this->Error('Unsupported font type: '.$type);
1693
			$this->$mtd($font);
1694
		}
1695
	}
1696
}
1697
1698
protected function _tounicodecmap($uv)
1699
{
1700
	$ranges = '';
1701
	$nbr = 0;
1702
	$chars = '';
1703
	$nbc = 0;
1704
	foreach($uv as $c=>$v)
1705
	{
1706
		if(is_array($v))
1707
		{
1708
			$ranges .= sprintf("<%02X> <%02X> <%04X>\n",$c,$c+$v[1]-1,$v[0]);
1709
			$nbr++;
1710
		}
1711
		else
1712
		{
1713
			$chars .= sprintf("<%02X> <%04X>\n",$c,$v);
1714
			$nbc++;
1715
		}
1716
	}
1717
	$s = "/CIDInit /ProcSet findresource begin\n";
1718
	$s .= "12 dict begin\n";
1719
	$s .= "begincmap\n";
1720
	$s .= "/CIDSystemInfo\n";
1721
	$s .= "<</Registry (Adobe)\n";
1722
	$s .= "/Ordering (UCS)\n";
1723
	$s .= "/Supplement 0\n";
1724
	$s .= ">> def\n";
1725
	$s .= "/CMapName /Adobe-Identity-UCS def\n";
1726
	$s .= "/CMapType 2 def\n";
1727
	$s .= "1 begincodespacerange\n";
1728
	$s .= "<00> <FF>\n";
1729
	$s .= "endcodespacerange\n";
1730
	if($nbr>0)
1731
	{
1732
		$s .= "$nbr beginbfrange\n";
1733
		$s .= $ranges;
1734
		$s .= "endbfrange\n";
1735
	}
1736
	if($nbc>0)
1737
	{
1738
		$s .= "$nbc beginbfchar\n";
1739
		$s .= $chars;
1740
		$s .= "endbfchar\n";
1741
	}
1742
	$s .= "endcmap\n";
1743
	$s .= "CMapName currentdict /CMap defineresource pop\n";
1744
	$s .= "end\n";
1745
	$s .= "end";
1746
	return $s;
1747
}
1748
1749
protected function _putimages()
1750
{
1751
	foreach(array_keys($this->images) as $file)
1752
	{
1753
		$this->_putimage($this->images[$file]);
1754
		unset($this->images[$file]['data']);
1755
		unset($this->images[$file]['smask']);
1756
	}
1757
}
1758
1759
protected function _putimage(&$info)
1760
{
1761
	$this->_newobj();
1762
	$info['n'] = $this->n;
1763
	$this->_put('<</Type /XObject');
1764
	$this->_put('/Subtype /Image');
1765
	$this->_put('/Width '.$info['w']);
1766
	$this->_put('/Height '.$info['h']);
1767
	if($info['cs']=='Indexed')
1768
		$this->_put('/ColorSpace [/Indexed /DeviceRGB '.(strlen($info['pal'])/3-1).' '.($this->n+1).' 0 R]');
1769
	else
1770
	{
1771
		$this->_put('/ColorSpace /'.$info['cs']);
1772
		if($info['cs']=='DeviceCMYK')
1773
			$this->_put('/Decode [1 0 1 0 1 0 1 0]');
1774
	}
1775
	$this->_put('/BitsPerComponent '.$info['bpc']);
1776
	if(isset($info['f']))
1777
		$this->_put('/Filter /'.$info['f']);
1778
	if(isset($info['dp']))
1779
		$this->_put('/DecodeParms <<'.$info['dp'].'>>');
1780
	if(isset($info['trns']) && is_array($info['trns']))
1781
	{
1782
		$trns = '';
1783
		for($i=0;$i<count($info['trns']);$i++)
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
1784
			$trns .= $info['trns'][$i].' '.$info['trns'][$i].' ';
1785
		$this->_put('/Mask ['.$trns.']');
1786
	}
1787
	if(isset($info['smask']))
1788
		$this->_put('/SMask '.($this->n+1).' 0 R');
1789
	$this->_put('/Length '.strlen($info['data']).'>>');
1790
	$this->_putstream($info['data']);
1791
	$this->_put('endobj');
1792
	// Soft mask
1793
	if(isset($info['smask']))
1794
	{
1795
		$dp = '/Predictor 15 /Colors 1 /BitsPerComponent 8 /Columns '.$info['w'];
1796
		$smask = array('w'=>$info['w'], 'h'=>$info['h'], 'cs'=>'DeviceGray', 'bpc'=>8, 'f'=>$info['f'], 'dp'=>$dp, 'data'=>$info['smask']);
1797
		$this->_putimage($smask);
1798
	}
1799
	// Palette
1800
	if($info['cs']=='Indexed')
1801
		$this->_putstreamobject($info['pal']);
1802
}
1803
1804
protected function _putxobjectdict()
1805
{
1806
	foreach($this->images as $image)
1807
		$this->_put('/I'.$image['i'].' '.$image['n'].' 0 R');
1808
}
1809
1810
protected function _putresourcedict()
1811
{
1812
	$this->_put('/ProcSet [/PDF /Text /ImageB /ImageC /ImageI]');
1813
	$this->_put('/Font <<');
1814
	foreach($this->fonts as $font)
1815
		$this->_put('/F'.$font['i'].' '.$font['n'].' 0 R');
1816
	$this->_put('>>');
1817
	$this->_put('/XObject <<');
1818
	$this->_putxobjectdict();
1819
	$this->_put('>>');
1820
}
1821
1822
protected function _putresources()
1823
{
1824
	$this->_putfonts();
1825
	$this->_putimages();
1826
	// Resource dictionary
1827
	$this->_newobj(2);
1828
	$this->_put('<<');
1829
	$this->_putresourcedict();
1830
	$this->_put('>>');
1831
	$this->_put('endobj');
1832
}
1833
1834
protected function _putinfo()
1835
{
1836
	$this->metadata['Producer'] = 'FPDF '.FPDF_VERSION;
1837
	$this->metadata['CreationDate'] = 'D:'.@date('YmdHis');
1838
	foreach($this->metadata as $key=>$value)
1839
		$this->_put('/'.$key.' '.$this->_textstring($value));
1840
}
1841
1842
protected function _putcatalog()
1843
{
1844
	$n = $this->PageInfo[1]['n'];
1845
	$this->_put('/Type /Catalog');
1846
	$this->_put('/Pages 1 0 R');
1847
	if($this->ZoomMode=='fullpage')
1848
		$this->_put('/OpenAction ['.$n.' 0 R /Fit]');
1849
	elseif($this->ZoomMode=='fullwidth')
1850
		$this->_put('/OpenAction ['.$n.' 0 R /FitH null]');
1851
	elseif($this->ZoomMode=='real')
1852
		$this->_put('/OpenAction ['.$n.' 0 R /XYZ null null 1]');
1853
	elseif(!is_string($this->ZoomMode))
1854
		$this->_put('/OpenAction ['.$n.' 0 R /XYZ null null '.sprintf('%.2F',$this->ZoomMode/100).']');
1855
	if($this->LayoutMode=='single')
1856
		$this->_put('/PageLayout /SinglePage');
1857
	elseif($this->LayoutMode=='continuous')
1858
		$this->_put('/PageLayout /OneColumn');
1859
	elseif($this->LayoutMode=='two')
1860
		$this->_put('/PageLayout /TwoColumnLeft');
1861
}
1862
1863
protected function _putheader()
1864
{
1865
	$this->_put('%PDF-'.$this->PDFVersion);
1866
}
1867
1868
protected function _puttrailer()
1869
{
1870
	$this->_put('/Size '.($this->n+1));
1871
	$this->_put('/Root '.$this->n.' 0 R');
1872
	$this->_put('/Info '.($this->n-1).' 0 R');
1873
}
1874
1875
protected function _enddoc()
1876
{
1877
	$this->_putheader();
1878
	$this->_putpages();
1879
	$this->_putresources();
1880
	// Info
1881
	$this->_newobj();
1882
	$this->_put('<<');
1883
	$this->_putinfo();
1884
	$this->_put('>>');
1885
	$this->_put('endobj');
1886
	// Catalog
1887
	$this->_newobj();
1888
	$this->_put('<<');
1889
	$this->_putcatalog();
1890
	$this->_put('>>');
1891
	$this->_put('endobj');
1892
	// Cross-ref
1893
	$offset = $this->_getoffset();
1894
	$this->_put('xref');
1895
	$this->_put('0 '.($this->n+1));
1896
	$this->_put('0000000000 65535 f ');
1897
	for($i=1;$i<=$this->n;$i++)
1898
		$this->_put(sprintf('%010d 00000 n ',$this->offsets[$i]));
1899
	// Trailer
1900
	$this->_put('trailer');
1901
	$this->_put('<<');
1902
	$this->_puttrailer();
1903
	$this->_put('>>');
1904
	$this->_put('startxref');
1905
	$this->_put($offset);
1906
	$this->_put('%%EOF');
1907
	$this->state = 3;
1908
}
1909
}
1910
?>
0 ignored issues
show
Best Practice introduced by
It is not recommended to use PHP's closing tag ?> in files other than templates.

Using a closing tag in PHP files that only contain PHP code is not recommended as you might accidentally add whitespace after the closing tag which would then be output by PHP. This can cause severe problems, for example headers cannot be sent anymore.

A simple precaution is to leave off the closing tag as it is not required, and it also has no negative effects whatsoever.

Loading history...
1911