tFPDF::_putTTfontwidths()   F
last analyzed

Complexity

Conditions 32
Paths 3660

Size

Total Lines 101

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 32
nc 3660
nop 2
dl 0
loc 101
rs 0
c 0
b 0
f 0

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
* tFPDF (based on FPDF 1.82)                                                   *
4
*                                                                              *
5
* Version:  1.32                                                               *
6
* Date:     2020-08-29                                                         *
7
* Authors:  Ian Back <[email protected]>                                           *
8
*           Tycho Veltmeijer <[email protected]> (versions 1.30+)       *
9
* License:  LGPL                                                               *
10
*******************************************************************************/
11
12
define('tFPDF_VERSION','1.32');
13
14
class tFPDF
15
{
16
protected $unifontSubset;
17
protected $page;               // current page number
18
protected $n;                  // current object number
19
protected $offsets;            // array of object offsets
20
protected $buffer;             // buffer holding in-memory PDF
21
protected $pages;              // array containing pages
22
protected $state;              // current document state
23
protected $compress;           // compression flag
24
protected $k;                  // scale factor (number of points in user unit)
25
protected $DefOrientation;     // default orientation
26
protected $CurOrientation;     // current orientation
27
protected $StdPageSizes;       // standard page sizes
28
protected $DefPageSize;        // default page size
29
protected $CurPageSize;        // current page size
30
protected $CurRotation;        // current page rotation
31
protected $PageInfo;           // page-related data
32
protected $wPt, $hPt;          // dimensions of current page in points
33
protected $w, $h;              // dimensions of current page in user unit
34
protected $lMargin;            // left margin
35
protected $tMargin;            // top margin
36
protected $rMargin;            // right margin
37
protected $bMargin;            // page break margin
38
protected $cMargin;            // cell margin
39
protected $x, $y;              // current position in user unit
40
protected $lasth;              // height of last printed cell
41
protected $LineWidth;          // line width in user unit
42
protected $fontpath;           // path containing fonts
43
protected $CoreFonts;          // array of core font names
44
protected $fonts;              // array of used fonts
45
protected $FontFiles;          // array of font files
46
protected $encodings;          // array of encodings
47
protected $cmaps;              // array of ToUnicode CMaps
48
protected $FontFamily;         // current font family
49
protected $FontStyle;          // current font style
50
protected $underline;          // underlining flag
51
protected $CurrentFont;        // current font info
52
protected $FontSizePt;         // current font size in points
53
protected $FontSize;           // current font size in user unit
54
protected $DrawColor;          // commands for drawing color
55
protected $FillColor;          // commands for filling color
56
protected $TextColor;          // commands for text color
57
protected $ColorFlag;          // indicates whether fill and text colors are different
58
protected $WithAlpha;          // indicates whether alpha channel is used
59
protected $ws;                 // word spacing
60
protected $images;             // array of used images
61
protected $PageLinks;          // array of links in pages
62
protected $links;              // array of internal links
63
protected $AutoPageBreak;      // automatic page breaking
64
protected $PageBreakTrigger;   // threshold used to trigger page breaks
65
protected $InHeader;           // flag set when processing header
66
protected $InFooter;           // flag set when processing footer
67
protected $AliasNbPages;       // alias for total number of pages
68
protected $ZoomMode;           // zoom display mode
69
protected $LayoutMode;         // layout display mode
70
protected $metadata;           // document properties
71
protected $PDFVersion;         // PDF version number
72
73
/*******************************************************************************
74
*                               Public methods                                 *
75
*******************************************************************************/
76
77
function __construct($orientation='P', $unit='mm', $size='A4')
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...
78
{
79
	// Some checks
80
	$this->_dochecks();
81
	// Initialization of properties
82
	$this->state = 0;
83
	$this->page = 0;
84
	$this->n = 2;
85
	$this->buffer = '';
86
	$this->pages = array();
87
	$this->PageInfo = array();
88
	$this->fonts = array();
89
	$this->FontFiles = array();
90
	$this->encodings = array();
91
	$this->cmaps = array();
92
	$this->images = array();
93
	$this->links = array();
94
	$this->InHeader = false;
95
	$this->InFooter = false;
96
	$this->lasth = 0;
97
	$this->FontFamily = '';
98
	$this->FontStyle = '';
99
	$this->FontSizePt = 12;
100
	$this->underline = false;
101
	$this->DrawColor = '0 G';
102
	$this->FillColor = '0 g';
103
	$this->TextColor = '0 g';
104
	$this->ColorFlag = false;
105
	$this->WithAlpha = false;
106
	$this->ws = 0;
107
	// Font path
108
	if(defined('FPDF_FONTPATH'))
109
	{
110
		$this->fontpath = FPDF_FONTPATH;
111
		if(substr($this->fontpath,-1)!='/' && substr($this->fontpath,-1)!='\\')
112
			$this->fontpath .= '/';
113
	}
114
	elseif(is_dir(dirname(__FILE__).'/font'))
115
		$this->fontpath = dirname(__FILE__).'/font/';
116
	else
117
		$this->fontpath = '';
118
	// Core fonts
119
	$this->CoreFonts = array('courier', 'helvetica', 'times', 'symbol', 'zapfdingbats');
120
	// Scale factor
121
	if($unit=='pt')
122
		$this->k = 1;
123
	elseif($unit=='mm')
124
		$this->k = 72/25.4;
125
	elseif($unit=='cm')
126
		$this->k = 72/2.54;
127
	elseif($unit=='in')
128
		$this->k = 72;
129
	else
130
		$this->Error('Incorrect unit: '.$unit);
131
	// Page sizes
132
	$this->StdPageSizes = array('a3'=>array(841.89,1190.55), 'a4'=>array(595.28,841.89), 'a5'=>array(420.94,595.28),
133
		'letter'=>array(612,792), 'legal'=>array(612,1008));
134
	$size = $this->_getpagesize($size);
135
	$this->DefPageSize = $size;
136
	$this->CurPageSize = $size;
137
	// Page orientation
138
	$orientation = strtolower($orientation);
139
	if($orientation=='p' || $orientation=='portrait')
140
	{
141
		$this->DefOrientation = 'P';
142
		$this->w = $size[0];
143
		$this->h = $size[1];
144
	}
145
	elseif($orientation=='l' || $orientation=='landscape')
146
	{
147
		$this->DefOrientation = 'L';
148
		$this->w = $size[1];
149
		$this->h = $size[0];
150
	}
151
	else
152
		$this->Error('Incorrect orientation: '.$orientation);
153
	$this->CurOrientation = $this->DefOrientation;
154
	$this->wPt = $this->w*$this->k;
155
	$this->hPt = $this->h*$this->k;
156
	// Page rotation
157
	$this->CurRotation = 0;
158
	// Page margins (1 cm)
159
	$margin = 28.35/$this->k;
160
	$this->SetMargins($margin,$margin);
161
	// Interior cell margin (1 mm)
162
	$this->cMargin = $margin/10;
163
	// Line width (0.2 mm)
164
	$this->LineWidth = .567/$this->k;
165
	// Automatic page break
166
	$this->SetAutoPageBreak(true,2*$margin);
167
	// Default display mode
168
	$this->SetDisplayMode('default');
169
	// Enable compression
170
	$this->SetCompression(true);
171
	// Set default PDF version number
172
	$this->PDFVersion = '1.3';
173
}
174
175
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...
176
{
177
	// Set left, top and right margins
178
	$this->lMargin = $left;
179
	$this->tMargin = $top;
180
	if($right===null)
181
		$right = $left;
182
	$this->rMargin = $right;
183
}
184
185
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...
186
{
187
	// Set left margin
188
	$this->lMargin = $margin;
189
	if($this->page>0 && $this->x<$margin)
190
		$this->x = $margin;
191
}
192
193
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...
194
{
195
	// Set top margin
196
	$this->tMargin = $margin;
197
}
198
199
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...
200
{
201
	// Set right margin
202
	$this->rMargin = $margin;
203
}
204
205
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...
206
{
207
	// Set auto page break mode and triggering margin
208
	$this->AutoPageBreak = $auto;
209
	$this->bMargin = $margin;
210
	$this->PageBreakTrigger = $this->h-$margin;
211
}
212
213
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...
214
{
215
	// Set display mode in viewer
216
	if($zoom=='fullpage' || $zoom=='fullwidth' || $zoom=='real' || $zoom=='default' || !is_string($zoom))
217
		$this->ZoomMode = $zoom;
218
	else
219
		$this->Error('Incorrect zoom display mode: '.$zoom);
220
	if($layout=='single' || $layout=='continuous' || $layout=='two' || $layout=='default')
221
		$this->LayoutMode = $layout;
222
	else
223
		$this->Error('Incorrect layout display mode: '.$layout);
224
}
225
226
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...
227
{
228
	// Set page compression
229
	if(function_exists('gzcompress'))
230
		$this->compress = $compress;
231
	else
232
		$this->compress = false;
233
}
234
235
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...
236
{
237
	// Title of document
238
	$this->metadata['Title'] = $isUTF8 ? $title : utf8_encode($title);
239
}
240
241
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...
242
{
243
	// Author of document
244
	$this->metadata['Author'] = $isUTF8 ? $author : utf8_encode($author);
245
}
246
247
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...
248
{
249
	// Subject of document
250
	$this->metadata['Subject'] = $isUTF8 ? $subject : utf8_encode($subject);
251
}
252
253
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...
254
{
255
	// Keywords of document
256
	$this->metadata['Keywords'] = $isUTF8 ? $keywords : utf8_encode($keywords);
257
}
258
259
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...
260
{
261
	// Creator of document
262
	$this->metadata['Creator'] = $isUTF8 ? $creator : utf8_encode($creator);
263
}
264
265
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...
266
{
267
	// Define an alias for total number of pages
268
	$this->AliasNbPages = $alias;
269
}
270
271
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...
272
{
273
	// Fatal error
274
	throw new Exception('FPDF error: '.$msg);
275
}
276
277
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...
278
{
279
	// Terminate document
280
	if($this->state==3)
281
		return;
282
	if($this->page==0)
283
		$this->AddPage();
284
	// Page footer
285
	$this->InFooter = true;
286
	$this->Footer();
287
	$this->InFooter = false;
288
	// Close page
289
	$this->_endpage();
290
	// Close document
291
	$this->_enddoc();
292
}
293
294
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...
295
{
296
	// Start a new page
297
	if($this->state==3)
298
		$this->Error('The document is closed');
299
	$family = $this->FontFamily;
300
	$style = $this->FontStyle.($this->underline ? 'U' : '');
301
	$fontsize = $this->FontSizePt;
302
	$lw = $this->LineWidth;
303
	$dc = $this->DrawColor;
304
	$fc = $this->FillColor;
305
	$tc = $this->TextColor;
306
	$cf = $this->ColorFlag;
307
	if($this->page>0)
308
	{
309
		// Page footer
310
		$this->InFooter = true;
311
		$this->Footer();
312
		$this->InFooter = false;
313
		// Close page
314
		$this->_endpage();
315
	}
316
	// Start new page
317
	$this->_beginpage($orientation,$size,$rotation);
318
	// Set line cap style to square
319
	$this->_out('2 J');
320
	// Set line width
321
	$this->LineWidth = $lw;
322
	$this->_out(sprintf('%.2F w',$lw*$this->k));
323
	// Set font
324
	if($family)
325
		$this->SetFont($family,$style,$fontsize);
326
	// Set colors
327
	$this->DrawColor = $dc;
328
	if($dc!='0 G')
329
		$this->_out($dc);
330
	$this->FillColor = $fc;
331
	if($fc!='0 g')
332
		$this->_out($fc);
333
	$this->TextColor = $tc;
334
	$this->ColorFlag = $cf;
335
	// Page header
336
	$this->InHeader = true;
337
	$this->Header();
338
	$this->InHeader = false;
339
	// Restore line width
340
	if($this->LineWidth!=$lw)
341
	{
342
		$this->LineWidth = $lw;
343
		$this->_out(sprintf('%.2F w',$lw*$this->k));
344
	}
345
	// Restore font
346
	if($family)
347
		$this->SetFont($family,$style,$fontsize);
348
	// Restore colors
349
	if($this->DrawColor!=$dc)
350
	{
351
		$this->DrawColor = $dc;
352
		$this->_out($dc);
353
	}
354
	if($this->FillColor!=$fc)
355
	{
356
		$this->FillColor = $fc;
357
		$this->_out($fc);
358
	}
359
	$this->TextColor = $tc;
360
	$this->ColorFlag = $cf;
361
}
362
363
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...
364
{
365
	// To be implemented in your own inherited class
366
}
367
368
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...
369
{
370
	// To be implemented in your own inherited class
371
}
372
373
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...
374
{
375
	// Get current page number
376
	return $this->page;
377
}
378
379
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...
380
{
381
	// Set color for all stroking operations
382
	if(($r==0 && $g==0 && $b==0) || $g===null)
383
		$this->DrawColor = sprintf('%.3F G',$r/255);
384
	else
385
		$this->DrawColor = sprintf('%.3F %.3F %.3F RG',$r/255,$g/255,$b/255);
386
	if($this->page>0)
387
		$this->_out($this->DrawColor);
388
}
389
390
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...
391
{
392
	// Set color for all filling operations
393
	if(($r==0 && $g==0 && $b==0) || $g===null)
394
		$this->FillColor = sprintf('%.3F g',$r/255);
395
	else
396
		$this->FillColor = sprintf('%.3F %.3F %.3F rg',$r/255,$g/255,$b/255);
397
	$this->ColorFlag = ($this->FillColor!=$this->TextColor);
398
	if($this->page>0)
399
		$this->_out($this->FillColor);
400
}
401
402
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...
403
{
404
	// Set color for text
405
	if(($r==0 && $g==0 && $b==0) || $g===null)
406
		$this->TextColor = sprintf('%.3F g',$r/255);
407
	else
408
		$this->TextColor = sprintf('%.3F %.3F %.3F rg',$r/255,$g/255,$b/255);
409
	$this->ColorFlag = ($this->FillColor!=$this->TextColor);
410
}
411
412
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...
413
{
414
	// Get width of a string in the current font
415
	$s = (string)$s;
416
	$cw = &$this->CurrentFont['cw'];
417
	$w=0;
418
	if ($this->unifontSubset) {
419
		$unicode = $this->UTF8StringToArray($s);
420
		foreach($unicode as $char) {
421
			if (isset($cw[2*$char])) { $w += (ord($cw[2*$char])<<8) + ord($cw[2*$char+1]); }
422
			else if($char>0 && $char<128 && isset($cw[chr($char)])) { $w += $cw[chr($char)]; }
423
			else if(isset($this->CurrentFont['desc']['MissingWidth'])) { $w += $this->CurrentFont['desc']['MissingWidth']; }
424
			else if(isset($this->CurrentFont['MissingWidth'])) { $w += $this->CurrentFont['MissingWidth']; }
425
			else { $w += 500; }
426
		}
427
	}
428
	else {
429
		$l = strlen($s);
430
		for($i=0;$i<$l;$i++)
431
			$w += $cw[$s[$i]];
432
	}
433
	return $w*$this->FontSize/1000;
434
}
435
436
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...
437
{
438
	// Set line width
439
	$this->LineWidth = $width;
440
	if($this->page>0)
441
		$this->_out(sprintf('%.2F w',$width*$this->k));
442
}
443
444
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...
445
{
446
	// Draw a line
447
	$this->_out(sprintf('%.2F %.2F m %.2F %.2F l S',$x1*$this->k,($this->h-$y1)*$this->k,$x2*$this->k,($this->h-$y2)*$this->k));
448
}
449
450
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...
451
{
452
	// Draw a rectangle
453
	if($style=='F')
454
		$op = 'f';
455
	elseif($style=='FD' || $style=='DF')
456
		$op = 'B';
457
	else
458
		$op = 'S';
459
	$this->_out(sprintf('%.2F %.2F %.2F %.2F re %s',$x*$this->k,($this->h-$y)*$this->k,$w*$this->k,-$h*$this->k,$op));
460
}
461
462
function AddFont($family, $style='', $file='', $uni=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...
463
{
464
	// Add a TrueType, OpenType or Type1 font
465
	$family = strtolower($family);
466
	$style = strtoupper($style);
467
	if($style=='IB')
468
		$style = 'BI';
469
	if($file=='') {
470
	   if ($uni) {
471
		$file = str_replace(' ','',$family).strtolower($style).'.ttf';
472
	   }
473
	   else {
474
		$file = str_replace(' ','',$family).strtolower($style).'.php';
475
	   }
476
	}
477
	$fontkey = $family.$style;
478
	if(isset($this->fonts[$fontkey]))
479
		return;
480
	if ($uni) {
481
		if (defined("_SYSTEM_TTFONTS") && file_exists(_SYSTEM_TTFONTS.$file )) { $ttffilename = _SYSTEM_TTFONTS.$file ; }
482
		else { $ttffilename = $this->fontpath.'unifont/'.$file ; }
483
		$unifilename = $this->fontpath.'unifont/'.strtolower(substr($file ,0,(strpos($file ,'.'))));
484
		$name = '';
485
		$originalsize = 0;
486
		$ttfstat = stat($ttffilename);
487
		if (file_exists($unifilename.'.mtx.php')) {
488
			include($unifilename.'.mtx.php');
489
		}
490
		if (!isset($type) ||  !isset($name) || $originalsize != $ttfstat['size']) {
0 ignored issues
show
Bug introduced by
The variable $type seems only to be defined at a later point. As such the call to isset() seems to always evaluate to false.

This check marks calls to isset(...) or empty(...) that are found before the variable itself is defined. These will always have the same result.

This is likely the result of code being shifted around. Consider removing these calls.

Loading history...
491
			$ttffile = $ttffilename;
492
//			require_once($this->fontpath.'unifont/ttfonts.php');
493
			$ttf = new TTFontFile();
494
			$ttf->getMetrics($ttffile);
495
			$cw = $ttf->charWidths;
496
			$name = preg_replace('/[ ()]/','',$ttf->fullName);
497
498
			$desc= array('Ascent'=>round($ttf->ascent),
499
			'Descent'=>round($ttf->descent),
500
			'CapHeight'=>round($ttf->capHeight),
501
			'Flags'=>$ttf->flags,
502
			'FontBBox'=>'['.round($ttf->bbox[0])." ".round($ttf->bbox[1])." ".round($ttf->bbox[2])." ".round($ttf->bbox[3]).']',
503
			'ItalicAngle'=>$ttf->italicAngle,
504
			'StemV'=>round($ttf->stemV),
505
			'MissingWidth'=>round($ttf->defaultWidth));
506
			$up = round($ttf->underlinePosition);
507
			$ut = round($ttf->underlineThickness);
508
			$originalsize = $ttfstat['size']+0;
509
			$type = 'TTF';
510
			// Generate metrics .php file
511
			$s='<?php'."\n";
512
			$s.='$name=\''.$name."';\n";
513
			$s.='$type=\''.$type."';\n";
514
			$s.='$desc='.var_export($desc,true).";\n";
515
			$s.='$up='.$up.";\n";
516
			$s.='$ut='.$ut.";\n";
517
			$s.='$ttffile=\''.$ttffile."';\n";
518
			$s.='$originalsize='.$originalsize.";\n";
519
			$s.='$fontkey=\''.$fontkey."';\n";
520
			$s.="?>";
521
			if (is_writable(dirname($this->fontpath.'unifont/'.'x'))) {
522
				$fh = fopen($unifilename.'.mtx.php',"w");
523
				fwrite($fh,$s,strlen($s));
524
				fclose($fh);
525
				$fh = fopen($unifilename.'.cw.dat',"wb");
526
				fwrite($fh,$cw,strlen($cw));
527
				fclose($fh);
528
				@unlink($unifilename.'.cw127.php');
529
			}
530
			unset($ttf);
531
		}
532
		else {
533
			$cw = @file_get_contents($unifilename.'.cw.dat'); 
534
		}
535
		$i = count($this->fonts)+1;
536
		if(!empty($this->AliasNbPages))
537
			$sbarr = range(0,57);
538
		else
539
			$sbarr = range(0,32);
540
		$this->fonts[$fontkey] = array('i'=>$i, 'type'=>$type, 'name'=>$name, 'desc'=>$desc, 'up'=>$up, 'ut'=>$ut, 'cw'=>$cw, 'ttffile'=>$ttffile, 'fontkey'=>$fontkey, 'subset'=>$sbarr, 'unifilename'=>$unifilename);
541
542
		$this->FontFiles[$fontkey]=array('length1'=>$originalsize, 'type'=>"TTF", 'ttffile'=>$ttffile);
543
		$this->FontFiles[$file]=array('type'=>"TTF");
544
		unset($cw);
545
	}
546
	else {
547
		$info = $this->_loadfont($file);
548
		$info['i'] = count($this->fonts)+1;
549
		if(!empty($info['file']))
550
		{
551
			// Embedded font
552
			if($info['type']=='TrueType')
553
				$this->FontFiles[$info['file']] = array('length1'=>$info['originalsize']);
554
			else
555
				$this->FontFiles[$info['file']] = array('length1'=>$info['size1'], 'length2'=>$info['size2']);
556
		}
557
		$this->fonts[$fontkey] = $info;
558
	}
559
}
560
561
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...
562
{
563
	// Select a font; size given in points
564
	if($family=='')
565
		$family = $this->FontFamily;
566
	else
567
		$family = strtolower($family);
568
	$style = strtoupper($style);
569
	if(strpos($style,'U')!==false)
570
	{
571
		$this->underline = true;
572
		$style = str_replace('U','',$style);
573
	}
574
	else
575
		$this->underline = false;
576
	if($style=='IB')
577
		$style = 'BI';
578
	if($size==0)
579
		$size = $this->FontSizePt;
580
	// Test if font is already selected
581
	if($this->FontFamily==$family && $this->FontStyle==$style && $this->FontSizePt==$size)
582
		return;
583
584
	// Test if font is already loaded
585
	$fontkey = $family.$style;
586
	if(!isset($this->fonts[$fontkey]))
587
	{
588
		// Test if one of the core fonts
589
		if($family=='arial')
590
			$family = 'helvetica';
591
		if(in_array($family,$this->CoreFonts))
592
		{
593
			if($family=='symbol' || $family=='zapfdingbats')
594
				$style = '';
595
			$fontkey = $family.$style;
596
			if(!isset($this->fonts[$fontkey]))
597
				$this->AddFont($family,$style);
598
		}
599
		else
600
			$this->Error('Undefined font: '.$family.' '.$style);
601
	}
602
	// Select it
603
	$this->FontFamily = $family;
604
	$this->FontStyle = $style;
605
	$this->FontSizePt = $size;
606
	$this->FontSize = $size/$this->k;
607
	$this->CurrentFont = &$this->fonts[$fontkey];
608
	if ($this->fonts[$fontkey]['type']=='TTF') { $this->unifontSubset = true; }
609
	else { $this->unifontSubset = false; }
610
	if($this->page>0)
611
		$this->_out(sprintf('BT /F%d %.2F Tf ET',$this->CurrentFont['i'],$this->FontSizePt));
612
}
613
614
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...
615
{
616
	// Set font size in points
617
	if($this->FontSizePt==$size)
618
		return;
619
	$this->FontSizePt = $size;
620
	$this->FontSize = $size/$this->k;
621
	if($this->page>0)
622
		$this->_out(sprintf('BT /F%d %.2F Tf ET',$this->CurrentFont['i'],$this->FontSizePt));
623
}
624
625
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...
626
{
627
	// Create a new internal link
628
	$n = count($this->links)+1;
629
	$this->links[$n] = array(0, 0);
630
	return $n;
631
}
632
633
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...
634
{
635
	// Set destination of internal link
636
	if($y==-1)
637
		$y = $this->y;
638
	if($page==-1)
639
		$page = $this->page;
640
	$this->links[$link] = array($page, $y);
641
}
642
643
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...
644
{
645
	// Put a link on the page
646
	$this->PageLinks[$this->page][] = array($x*$this->k, $this->hPt-$y*$this->k, $w*$this->k, $h*$this->k, $link);
647
}
648
649
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...
650
{
651
	// Output a string
652
	$txt = (string)$txt;
653
	if(!isset($this->CurrentFont))
654
		$this->Error('No font has been set');
655
	if ($this->unifontSubset)
656
	{
657
		$txt2 = '('.$this->_escape($this->UTF8ToUTF16BE($txt, false)).')';
658
		foreach($this->UTF8StringToArray($txt) as $uni)
659
			$this->CurrentFont['subset'][$uni] = $uni;
660
	}
661
	else 
662
		$txt2 = '('.$this->_escape($txt).')';
663
	$s = sprintf('BT %.2F %.2F Td %s Tj ET',$x*$this->k,($this->h-$y)*$this->k,$txt2);
664
	if($this->underline && $txt!='')
665
		$s .= ' '.$this->_dounderline($x,$y,$txt);
666
	if($this->ColorFlag)
667
		$s = 'q '.$this->TextColor.' '.$s.' Q';
668
	$this->_out($s);
669
}
670
671
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...
672
{
673
	// Accept automatic page break or not
674
	return $this->AutoPageBreak;
675
}
676
677
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...
678
{
679
	// Output a cell
680
	$txt = (string)$txt;
681
	$k = $this->k;
682
	if($this->y+$h>$this->PageBreakTrigger && !$this->InHeader && !$this->InFooter && $this->AcceptPageBreak())
683
	{
684
		// Automatic page break
685
		$x = $this->x;
686
		$ws = $this->ws;
687
		if($ws>0)
688
		{
689
			$this->ws = 0;
690
			$this->_out('0 Tw');
691
		}
692
		$this->AddPage($this->CurOrientation,$this->CurPageSize,$this->CurRotation);
693
		$this->x = $x;
694
		if($ws>0)
695
		{
696
			$this->ws = $ws;
697
			$this->_out(sprintf('%.3F Tw',$ws*$k));
698
		}
699
	}
700
	if($w==0)
701
		$w = $this->w-$this->rMargin-$this->x;
702
	$s = '';
703
	if($fill || $border==1)
704
	{
705
		if($fill)
706
			$op = ($border==1) ? 'B' : 'f';
707
		else
708
			$op = 'S';
709
		$s = sprintf('%.2F %.2F %.2F %.2F re %s ',$this->x*$k,($this->h-$this->y)*$k,$w*$k,-$h*$k,$op);
710
	}
711
	if(is_string($border))
712
	{
713
		$x = $this->x;
714
		$y = $this->y;
715
		if(strpos($border,'L')!==false)
716
			$s .= sprintf('%.2F %.2F m %.2F %.2F l S ',$x*$k,($this->h-$y)*$k,$x*$k,($this->h-($y+$h))*$k);
717
		if(strpos($border,'T')!==false)
718
			$s .= sprintf('%.2F %.2F m %.2F %.2F l S ',$x*$k,($this->h-$y)*$k,($x+$w)*$k,($this->h-$y)*$k);
719
		if(strpos($border,'R')!==false)
720
			$s .= sprintf('%.2F %.2F m %.2F %.2F l S ',($x+$w)*$k,($this->h-$y)*$k,($x+$w)*$k,($this->h-($y+$h))*$k);
721
		if(strpos($border,'B')!==false)
722
			$s .= sprintf('%.2F %.2F m %.2F %.2F l S ',$x*$k,($this->h-($y+$h))*$k,($x+$w)*$k,($this->h-($y+$h))*$k);
723
	}
724
	if($txt!=='')
725
	{
726
		if(!isset($this->CurrentFont))
727
			$this->Error('No font has been set');
728
		if($align=='R')
729
			$dx = $w-$this->cMargin-$this->GetStringWidth($txt);
730
		elseif($align=='C')
731
			$dx = ($w-$this->GetStringWidth($txt))/2;
732
		else
733
			$dx = $this->cMargin;
734
		if($this->ColorFlag)
735
			$s .= 'q '.$this->TextColor.' ';
736
		// If multibyte, Tw has no effect - do word spacing using an adjustment before each space
737
		if ($this->ws && $this->unifontSubset) {
738
			foreach($this->UTF8StringToArray($txt) as $uni)
739
				$this->CurrentFont['subset'][$uni] = $uni;
740
			$space = $this->_escape($this->UTF8ToUTF16BE(' ', false));
741
			$s .= sprintf('BT 0 Tw %.2F %.2F Td [',($this->x+$dx)*$k,($this->h-($this->y+.5*$h+.3*$this->FontSize))*$k);
742
			$t = explode(' ',$txt);
743
			$numt = count($t);
744
			for($i=0;$i<$numt;$i++) {
745
				$tx = $t[$i];
746
				$tx = '('.$this->_escape($this->UTF8ToUTF16BE($tx, false)).')';
747
				$s .= sprintf('%s ',$tx);
748
				if (($i+1)<$numt) {
749
					$adj = -($this->ws*$this->k)*1000/$this->FontSizePt;
750
					$s .= sprintf('%d(%s) ',$adj,$space);
751
				}
752
			}
753
			$s .= '] TJ';
754
			$s .= ' ET';
755
		}
756
		else {
757
			if ($this->unifontSubset)
758
			{
759
				$txt2 = '('.$this->_escape($this->UTF8ToUTF16BE($txt, false)).')';
760
				foreach($this->UTF8StringToArray($txt) as $uni)
761
					$this->CurrentFont['subset'][$uni] = $uni;
762
			}
763
			else
764
				$txt2='('.$this->_escape($txt).')';
765
			$s .= sprintf('BT %.2F %.2F Td %s Tj ET',($this->x+$dx)*$k,($this->h-($this->y+.5*$h+.3*$this->FontSize))*$k,$txt2);
766
		}
767
		if($this->underline)
768
			$s .= ' '.$this->_dounderline($this->x+$dx,$this->y+.5*$h+.3*$this->FontSize,$txt);
769
		if($this->ColorFlag)
770
			$s .= ' Q';
771
		if($link)
772
			$this->Link($this->x+$dx,$this->y+.5*$h-.5*$this->FontSize,$this->GetStringWidth($txt),$this->FontSize,$link);
773
	}
774
	if($s)
775
		$this->_out($s);
776
	$this->lasth = $h;
777
	if($ln>0)
778
	{
779
		// Go to next line
780
		$this->y += $h;
781
		if($ln==1)
782
			$this->x = $this->lMargin;
783
	}
784
	else
785
		$this->x += $w;
786
}
787
788
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...
789
{
790
	// Output text with automatic or explicit line breaks
791
	if(!isset($this->CurrentFont))
792
		$this->Error('No font has been set');
793
	$cw = &$this->CurrentFont['cw'];
794
	if($w==0)
795
		$w = $this->w-$this->rMargin-$this->x;
796
	$wmax = ($w-2*$this->cMargin);
797
	//$wmax = ($w-2*$this->cMargin)*1000/$this->FontSize;
798
	$s = str_replace("\r",'',(string)$txt);
799
	if ($this->unifontSubset) {
800
		$nb=mb_strlen($s, 'utf-8');
801
		while($nb>0 && mb_substr($s,$nb-1,1,'utf-8')=="\n")	$nb--;
802
	}
803
	else {
804
		$nb = strlen($s);
805
		if($nb>0 && $s[$nb-1]=="\n")
806
			$nb--;
807
	}
808
	$b = 0;
809
	if($border)
810
	{
811
		if($border==1)
812
		{
813
			$border = 'LTRB';
814
			$b = 'LRT';
815
			$b2 = 'LR';
816
		}
817
		else
818
		{
819
			$b2 = '';
820
			if(strpos($border,'L')!==false)
821
				$b2 .= 'L';
822
			if(strpos($border,'R')!==false)
823
				$b2 .= 'R';
824
			$b = (strpos($border,'T')!==false) ? $b2.'T' : $b2;
825
		}
826
	}
827
	$sep = -1;
828
	$i = 0;
829
	$j = 0;
830
	$l = 0;
831
	$ns = 0;
832
	$nl = 1;
833
	while($i<$nb)
834
	{
835
		// Get next character
836
		if ($this->unifontSubset) {
837
			$c = mb_substr($s,$i,1,'UTF-8');
838
		}
839
		else {
840
			$c=$s[$i];
841
		}
842
		if($c=="\n")
843
		{
844
			// Explicit line break
845
			if($this->ws>0)
846
			{
847
				$this->ws = 0;
848
				$this->_out('0 Tw');
849
			}
850
			if ($this->unifontSubset) {
851
				$this->Cell($w,$h,mb_substr($s,$j,$i-$j,'UTF-8'),$b,2,$align,$fill);
852
			}
853
			else {
854
				$this->Cell($w,$h,substr($s,$j,$i-$j),$b,2,$align,$fill);
855
			}
856
			$i++;
857
			$sep = -1;
858
			$j = $i;
859
			$l = 0;
860
			$ns = 0;
861
			$nl++;
862
			if($border && $nl==2)
863
				$b = $b2;
864
			continue;
865
		}
866
		if($c==' ')
867
		{
868
			$sep = $i;
869
			$ls = $l;
870
			$ns++;
871
		}
872
873
		if ($this->unifontSubset) { $l += $this->GetStringWidth($c); }
874
		else { $l += $cw[$c]*$this->FontSize/1000; }
875
876
		if($l>$wmax)
877
		{
878
			// Automatic line break
879
			if($sep==-1)
880
			{
881
				if($i==$j)
882
					$i++;
883
				if($this->ws>0)
884
				{
885
					$this->ws = 0;
886
					$this->_out('0 Tw');
887
				}
888
				if ($this->unifontSubset) {
889
					$this->Cell($w,$h,mb_substr($s,$j,$i-$j,'UTF-8'),$b,2,$align,$fill);
890
				}
891
				else {
892
					$this->Cell($w,$h,substr($s,$j,$i-$j),$b,2,$align,$fill);
893
				}
894
			}
895
			else
896
			{
897
				if($align=='J')
898
				{
899
					$this->ws = ($ns>1) ? ($wmax-$ls)/($ns-1) : 0;
900
					$this->_out(sprintf('%.3F Tw',$this->ws*$this->k));
901
				}
902
				if ($this->unifontSubset) {
903
					$this->Cell($w,$h,mb_substr($s,$j,$sep-$j,'UTF-8'),$b,2,$align,$fill);
904
				}
905
				else {
906
					$this->Cell($w,$h,substr($s,$j,$sep-$j),$b,2,$align,$fill);
907
				}
908
				$i = $sep+1;
909
			}
910
			$sep = -1;
911
			$j = $i;
912
			$l = 0;
913
			$ns = 0;
914
			$nl++;
915
			if($border && $nl==2)
916
				$b = $b2;
917
		}
918
		else
919
			$i++;
920
	}
921
	// Last chunk
922
	if($this->ws>0)
923
	{
924
		$this->ws = 0;
925
		$this->_out('0 Tw');
926
	}
927
	if($border && strpos($border,'B')!==false)
928
		$b .= 'B';
929
	if ($this->unifontSubset) {
930
		$this->Cell($w,$h,mb_substr($s,$j,$i-$j,'UTF-8'),$b,2,$align,$fill);
931
	}
932
	else {
933
		$this->Cell($w,$h,substr($s,$j,$i-$j),$b,2,$align,$fill);
934
	}
935
	$this->x = $this->lMargin;
936
}
937
938
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...
939
{
940
	// Output text in flowing mode
941
	if(!isset($this->CurrentFont))
942
		$this->Error('No font has been set');
943
	$cw = &$this->CurrentFont['cw'];
944
	$w = $this->w-$this->rMargin-$this->x;
945
	$wmax = ($w-2*$this->cMargin);
946
	$s = str_replace("\r",'',(string)$txt);
947
	if ($this->unifontSubset) {
948
		$nb = mb_strlen($s, 'UTF-8');
949
		if($nb==1 && $s==" ") {
950
			$this->x += $this->GetStringWidth($s);
951
			return;
952
		}
953
	}
954
	else {
955
		$nb = strlen($s);
956
	}
957
	$sep = -1;
958
	$i = 0;
959
	$j = 0;
960
	$l = 0;
961
	$nl = 1;
962
	while($i<$nb)
963
	{
964
		// Get next character
965
		if ($this->unifontSubset) {
966
			$c = mb_substr($s,$i,1,'UTF-8');
967
		}
968
		else {
969
			$c = $s[$i];
970
		}
971
		if($c=="\n")
972
		{
973
			// Explicit line break
974
			if ($this->unifontSubset) {
975
				$this->Cell($w,$h,mb_substr($s,$j,$i-$j,'UTF-8'),0,2,'',false,$link);
976
			}
977
			else {
978
				$this->Cell($w,$h,substr($s,$j,$i-$j),0,2,'',false,$link);
979
			}
980
			$i++;
981
			$sep = -1;
982
			$j = $i;
983
			$l = 0;
984
			if($nl==1)
985
			{
986
				$this->x = $this->lMargin;
987
				$w = $this->w-$this->rMargin-$this->x;
988
				$wmax = ($w-2*$this->cMargin);
989
			}
990
			$nl++;
991
			continue;
992
		}
993
		if($c==' ')
994
			$sep = $i;
995
996
		if ($this->unifontSubset) { $l += $this->GetStringWidth($c); }
997
		else { $l += $cw[$c]*$this->FontSize/1000; }
998
999
		if($l>$wmax)
1000
		{
1001
			// Automatic line break
1002
			if($sep==-1)
1003
			{
1004
				if($this->x>$this->lMargin)
1005
				{
1006
					// Move to next line
1007
					$this->x = $this->lMargin;
1008
					$this->y += $h;
1009
					$w = $this->w-$this->rMargin-$this->x;
1010
					$wmax = ($w-2*$this->cMargin);
1011
					$i++;
1012
					$nl++;
1013
					continue;
1014
				}
1015
				if($i==$j)
1016
					$i++;
1017
				if ($this->unifontSubset) {
1018
					$this->Cell($w,$h,mb_substr($s,$j,$i-$j,'UTF-8'),0,2,'',false,$link);
1019
				}
1020
				else {
1021
					$this->Cell($w,$h,substr($s,$j,$i-$j),0,2,'',false,$link);
1022
				}
1023
			}
1024
			else
1025
			{
1026
				if ($this->unifontSubset) {
1027
					$this->Cell($w,$h,mb_substr($s,$j,$sep-$j,'UTF-8'),0,2,'',false,$link);
1028
				}
1029
				else {
1030
					$this->Cell($w,$h,substr($s,$j,$sep-$j),0,2,'',false,$link);
1031
				}
1032
				$i = $sep+1;
1033
			}
1034
			$sep = -1;
1035
			$j = $i;
1036
			$l = 0;
1037
			if($nl==1)
1038
			{
1039
				$this->x = $this->lMargin;
1040
				$w = $this->w-$this->rMargin-$this->x;
1041
				$wmax = ($w-2*$this->cMargin);
1042
			}
1043
			$nl++;
1044
		}
1045
		else
1046
			$i++;
1047
	}
1048
	// Last chunk
1049
	if($i!=$j) {
1050
		if ($this->unifontSubset) {
1051
			$this->Cell($l,$h,mb_substr($s,$j,$i-$j,'UTF-8'),0,0,'',false,$link);
1052
		}
1053
		else {
1054
			$this->Cell($l,$h,substr($s,$j),0,0,'',false,$link);
1055
		}
1056
	}
1057
}
1058
1059
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...
1060
{
1061
	// Line feed; default value is the last cell height
1062
	$this->x = $this->lMargin;
1063
	if($h===null)
1064
		$this->y += $this->lasth;
1065
	else
1066
		$this->y += $h;
1067
}
1068
1069
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...
1070
{
1071
	// Put an image on the page
1072
	if($file=='')
1073
		$this->Error('Image file name is empty');
1074
	if(!isset($this->images[$file]))
1075
	{
1076
		// First use of this image, get info
1077
		if($type=='')
1078
		{
1079
			$pos = strrpos($file,'.');
1080
			if(!$pos)
1081
				$this->Error('Image file has no extension and no type was specified: '.$file);
1082
			$type = substr($file,$pos+1);
1083
		}
1084
		$type = strtolower($type);
1085
		if($type=='jpeg')
1086
			$type = 'jpg';
1087
		$mtd = '_parse'.$type;
1088
		if(!method_exists($this,$mtd))
1089
			$this->Error('Unsupported image type: '.$type);
1090
		$info = $this->$mtd($file);
1091
		$info['i'] = count($this->images)+1;
1092
		$this->images[$file] = $info;
1093
	}
1094
	else
1095
		$info = $this->images[$file];
1096
1097
	// Automatic width and height calculation if needed
1098
	if($w==0 && $h==0)
1099
	{
1100
		// Put image at 96 dpi
1101
		$w = -96;
1102
		$h = -96;
1103
	}
1104
	if($w<0)
1105
		$w = -$info['w']*72/$w/$this->k;
1106
	if($h<0)
1107
		$h = -$info['h']*72/$h/$this->k;
1108
	if($w==0)
1109
		$w = $h*$info['w']/$info['h'];
1110
	if($h==0)
1111
		$h = $w*$info['h']/$info['w'];
1112
1113
	// Flowing mode
1114
	if($y===null)
1115
	{
1116
		if($this->y+$h>$this->PageBreakTrigger && !$this->InHeader && !$this->InFooter && $this->AcceptPageBreak())
1117
		{
1118
			// Automatic page break
1119
			$x2 = $this->x;
1120
			$this->AddPage($this->CurOrientation,$this->CurPageSize,$this->CurRotation);
1121
			$this->x = $x2;
1122
		}
1123
		$y = $this->y;
1124
		$this->y += $h;
1125
	}
1126
1127
	if($x===null)
1128
		$x = $this->x;
1129
	$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']));
1130
	if($link)
1131
		$this->Link($x,$y,$w,$h,$link);
1132
}
1133
1134
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...
1135
{
1136
	// Get current page width
1137
	return $this->w;
1138
}
1139
1140
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...
1141
{
1142
	// Get current page height
1143
	return $this->h;
1144
}
1145
1146
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...
1147
{
1148
	// Get x position
1149
	return $this->x;
1150
}
1151
1152
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...
1153
{
1154
	// Set x position
1155
	if($x>=0)
1156
		$this->x = $x;
1157
	else
1158
		$this->x = $this->w+$x;
1159
}
1160
1161
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...
1162
{
1163
	// Get y position
1164
	return $this->y;
1165
}
1166
1167
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...
1168
{
1169
	// Set y position and optionally reset x
1170
	if($y>=0)
1171
		$this->y = $y;
1172
	else
1173
		$this->y = $this->h+$y;
1174
	if($resetX)
1175
		$this->x = $this->lMargin;
1176
}
1177
1178
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...
1179
{
1180
	// Set x and y positions
1181
	$this->SetX($x);
1182
	$this->SetY($y,false);
1183
}
1184
1185
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...
1186
{
1187
	// Output PDF to some destination
1188
	$this->Close();
1189
	if(strlen($name)==1 && strlen($dest)!=1)
1190
	{
1191
		// Fix parameter order
1192
		$tmp = $dest;
1193
		$dest = $name;
1194
		$name = $tmp;
1195
	}
1196
	if($dest=='')
1197
		$dest = 'I';
1198
	if($name=='')
1199
		$name = 'doc.pdf';
1200
	switch(strtoupper($dest))
1201
	{
1202
		case 'I':
1203
			// Send to standard output
1204
			$this->_checkoutput();
1205
			if(PHP_SAPI!='cli')
1206
			{
1207
				// We send to a browser
1208
				header('Content-Type: application/pdf');
1209
				header('Content-Disposition: inline; '.$this->_httpencode('filename',$name,$isUTF8));
1210
				header('Cache-Control: private, max-age=0, must-revalidate');
1211
				header('Pragma: public');
1212
			}
1213
			echo $this->buffer;
1214
			break;
1215
		case 'D':
1216
			// Download file
1217
			$this->_checkoutput();
1218
			header('Content-Type: application/x-download');
1219
			header('Content-Disposition: attachment; '.$this->_httpencode('filename',$name,$isUTF8));
1220
			header('Cache-Control: private, max-age=0, must-revalidate');
1221
			header('Pragma: public');
1222
			echo $this->buffer;
1223
			break;
1224
		case 'F':
1225
			// Save to local file
1226
			if(!file_put_contents($name,$this->buffer))
1227
				$this->Error('Unable to create output file: '.$name);
1228
			break;
1229
		case 'S':
1230
			// Return as a string
1231
			return $this->buffer;
1232
		default:
1233
			$this->Error('Incorrect output destination: '.$dest);
1234
	}
1235
	return '';
1236
}
1237
1238
/*******************************************************************************
1239
*                              Protected methods                               *
1240
*******************************************************************************/
1241
1242
protected function _dochecks()
1243
{
1244
	// Check availability of mbstring
1245
	if(!function_exists('mb_strlen'))
1246
		$this->Error('mbstring extension is not available');
1247
	// Check mbstring overloading
1248
	if(ini_get('mbstring.func_overload') & 2)
1249
		$this->Error('mbstring overloading must be disabled');
1250
}
1251
1252
protected function _checkoutput()
1253
{
1254
	if(PHP_SAPI!='cli')
1255
	{
1256
		if(headers_sent($file,$line))
1257
			$this->Error("Some data has already been output, can't send PDF file (output started at $file:$line)");
1258
	}
1259
	if(ob_get_length())
1260
	{
1261
		// The output buffer is not empty
1262
		if(preg_match('/^(\xEF\xBB\xBF)?\s*$/',ob_get_contents()))
1263
		{
1264
			// It contains only a UTF-8 BOM and/or whitespace, let's clean it
1265
			ob_clean();
1266
		}
1267
		else
1268
			$this->Error("Some data has already been output, can't send PDF file");
1269
	}
1270
}
1271
1272
protected function _getpagesize($size)
1273
{
1274
	if(is_string($size))
1275
	{
1276
		$size = strtolower($size);
1277
		if(!isset($this->StdPageSizes[$size]))
1278
			$this->Error('Unknown page size: '.$size);
1279
		$a = $this->StdPageSizes[$size];
1280
		return array($a[0]/$this->k, $a[1]/$this->k);
1281
	}
1282
	else
1283
	{
1284
		if($size[0]>$size[1])
1285
			return array($size[1], $size[0]);
1286
		else
1287
			return $size;
1288
	}
1289
}
1290
1291
protected function _beginpage($orientation, $size, $rotation)
1292
{
1293
	$this->page++;
1294
	$this->pages[$this->page] = '';
1295
	$this->state = 2;
1296
	$this->x = $this->lMargin;
1297
	$this->y = $this->tMargin;
1298
	$this->FontFamily = '';
1299
	// Check page size and orientation
1300
	if($orientation=='')
1301
		$orientation = $this->DefOrientation;
1302
	else
1303
		$orientation = strtoupper($orientation[0]);
1304
	if($size=='')
1305
		$size = $this->DefPageSize;
1306
	else
1307
		$size = $this->_getpagesize($size);
1308
	if($orientation!=$this->CurOrientation || $size[0]!=$this->CurPageSize[0] || $size[1]!=$this->CurPageSize[1])
1309
	{
1310
		// New size or orientation
1311
		if($orientation=='P')
1312
		{
1313
			$this->w = $size[0];
1314
			$this->h = $size[1];
1315
		}
1316
		else
1317
		{
1318
			$this->w = $size[1];
1319
			$this->h = $size[0];
1320
		}
1321
		$this->wPt = $this->w*$this->k;
1322
		$this->hPt = $this->h*$this->k;
1323
		$this->PageBreakTrigger = $this->h-$this->bMargin;
1324
		$this->CurOrientation = $orientation;
1325
		$this->CurPageSize = $size;
1326
	}
1327
	if($orientation!=$this->DefOrientation || $size[0]!=$this->DefPageSize[0] || $size[1]!=$this->DefPageSize[1])
1328
		$this->PageInfo[$this->page]['size'] = array($this->wPt, $this->hPt);
1329
	if($rotation!=0)
1330
	{
1331
		if($rotation%90!=0)
1332
			$this->Error('Incorrect rotation value: '.$rotation);
1333
		$this->CurRotation = $rotation;
1334
		$this->PageInfo[$this->page]['rotation'] = $rotation;
1335
	}
1336
}
1337
1338
protected function _endpage()
1339
{
1340
	$this->state = 1;
1341
}
1342
1343
protected function _loadfont($font)
1344
{
1345
	// Load a font definition file from the font directory
1346
	if(strpos($font,'/')!==false || strpos($font,"\\")!==false)
1347
		$this->Error('Incorrect font definition file name: '.$font);
1348
	include($this->fontpath.$font);
1349
	if(!isset($name))
0 ignored issues
show
Bug introduced by
The variable $name seems to never exist, and therefore isset should always return false. Did you maybe rename this variable?

This check looks for calls to isset(...) or empty() on variables that are yet undefined. These calls will always produce the same result and can be removed.

This is most likely caused by the renaming of a variable or the removal of a function/method parameter.

Loading history...
1350
		$this->Error('Could not include font definition file');
1351
	if(isset($enc))
0 ignored issues
show
Bug introduced by
The variable $enc seems only to be defined at a later point. As such the call to isset() seems to always evaluate to false.

This check marks calls to isset(...) or empty(...) that are found before the variable itself is defined. These will always have the same result.

This is likely the result of code being shifted around. Consider removing these calls.

Loading history...
1352
		$enc = strtolower($enc);
1353
	if(!isset($subsetted))
0 ignored issues
show
Bug introduced by
The variable $subsetted seems only to be defined at a later point. As such the call to isset() seems to always evaluate to false.

This check marks calls to isset(...) or empty(...) that are found before the variable itself is defined. These will always have the same result.

This is likely the result of code being shifted around. Consider removing these calls.

Loading history...
1354
		$subsetted = false;
1355
	return get_defined_vars();
1356
}
1357
1358
protected function _isascii($s)
1359
{
1360
	// Test if string is ASCII
1361
	$nb = strlen($s);
1362
	for($i=0;$i<$nb;$i++)
1363
	{
1364
		if(ord($s[$i])>127)
1365
			return false;
1366
	}
1367
	return true;
1368
}
1369
1370
protected function _httpencode($param, $value, $isUTF8)
1371
{
1372
	// Encode HTTP header field parameter
1373
	if($this->_isascii($value))
1374
		return $param.'="'.$value.'"';
1375
	if(!$isUTF8)
1376
		$value = utf8_encode($value);
1377
	if(strpos($_SERVER['HTTP_USER_AGENT'],'MSIE')!==false)
1378
		return $param.'="'.rawurlencode($value).'"';
1379
	else
1380
		return $param."*=UTF-8''".rawurlencode($value);
1381
}
1382
1383
protected function _UTF8toUTF16($s)
1384
{
1385
	// Convert UTF-8 to UTF-16BE with BOM
1386
	$res = "\xFE\xFF";
1387
	$nb = strlen($s);
1388
	$i = 0;
1389
	while($i<$nb)
1390
	{
1391
		$c1 = ord($s[$i++]);
1392
		if($c1>=224)
1393
		{
1394
			// 3-byte character
1395
			$c2 = ord($s[$i++]);
1396
			$c3 = ord($s[$i++]);
1397
			$res .= chr((($c1 & 0x0F)<<4) + (($c2 & 0x3C)>>2));
1398
			$res .= chr((($c2 & 0x03)<<6) + ($c3 & 0x3F));
1399
		}
1400
		elseif($c1>=192)
1401
		{
1402
			// 2-byte character
1403
			$c2 = ord($s[$i++]);
1404
			$res .= chr(($c1 & 0x1C)>>2);
1405
			$res .= chr((($c1 & 0x03)<<6) + ($c2 & 0x3F));
1406
		}
1407
		else
1408
		{
1409
			// Single-byte character
1410
			$res .= "\0".chr($c1);
1411
		}
1412
	}
1413
	return $res;
1414
}
1415
1416
protected function _escape($s)
1417
{
1418
	// Escape special characters
1419
	if(strpos($s,'(')!==false || strpos($s,')')!==false || strpos($s,'\\')!==false || strpos($s,"\r")!==false)
1420
		return str_replace(array('\\','(',')',"\r"), array('\\\\','\\(','\\)','\\r'), $s);
1421
	else
1422
		return $s;
1423
}
1424
1425
protected function _textstring($s)
1426
{
1427
	// Format a text string
1428
	if(!$this->_isascii($s))
1429
		$s = $this->_UTF8toUTF16($s);
1430
	return '('.$this->_escape($s).')';
1431
}
1432
1433
protected function _dounderline($x, $y, $txt)
1434
{
1435
	// Underline text
1436
	$up = $this->CurrentFont['up'];
1437
	$ut = $this->CurrentFont['ut'];
1438
	$w = $this->GetStringWidth($txt)+$this->ws*substr_count($txt,' ');
1439
	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);
1440
}
1441
1442
protected function _parsejpg($file)
1443
{
1444
	// Extract info from a JPEG file
1445
	$a = getimagesize($file);
1446
	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...
1447
		$this->Error('Missing or incorrect image file: '.$file);
1448
	if($a[2]!=2)
1449
		$this->Error('Not a JPEG file: '.$file);
1450
	if(!isset($a['channels']) || $a['channels']==3)
1451
		$colspace = 'DeviceRGB';
1452
	elseif($a['channels']==4)
1453
		$colspace = 'DeviceCMYK';
1454
	else
1455
		$colspace = 'DeviceGray';
1456
	$bpc = isset($a['bits']) ? $a['bits'] : 8;
1457
	$data = file_get_contents($file);
1458
	return array('w'=>$a[0], 'h'=>$a[1], 'cs'=>$colspace, 'bpc'=>$bpc, 'f'=>'DCTDecode', 'data'=>$data);
1459
}
1460
1461
protected function _parsepng($file)
1462
{
1463
	// Extract info from a PNG file
1464
	$f = fopen($file,'rb');
1465
	if(!$f)
1466
		$this->Error('Can\'t open image file: '.$file);
1467
	$info = $this->_parsepngstream($f,$file);
1468
	fclose($f);
1469
	return $info;
1470
}
1471
1472
protected function _parsepngstream($f, $file)
1473
{
1474
	// Check signature
1475
	if($this->_readstream($f,8)!=chr(137).'PNG'.chr(13).chr(10).chr(26).chr(10))
1476
		$this->Error('Not a PNG file: '.$file);
1477
1478
	// Read header chunk
1479
	$this->_readstream($f,4);
1480
	if($this->_readstream($f,4)!='IHDR')
1481
		$this->Error('Incorrect PNG file: '.$file);
1482
	$w = $this->_readint($f);
1483
	$h = $this->_readint($f);
1484
	$bpc = ord($this->_readstream($f,1));
1485
	if($bpc>8)
1486
		$this->Error('16-bit depth not supported: '.$file);
1487
	$ct = ord($this->_readstream($f,1));
1488
	if($ct==0 || $ct==4)
1489
		$colspace = 'DeviceGray';
1490
	elseif($ct==2 || $ct==6)
1491
		$colspace = 'DeviceRGB';
1492
	elseif($ct==3)
1493
		$colspace = 'Indexed';
1494
	else
1495
		$this->Error('Unknown color type: '.$file);
1496
	if(ord($this->_readstream($f,1))!=0)
1497
		$this->Error('Unknown compression method: '.$file);
1498
	if(ord($this->_readstream($f,1))!=0)
1499
		$this->Error('Unknown filter method: '.$file);
1500
	if(ord($this->_readstream($f,1))!=0)
1501
		$this->Error('Interlacing not supported: '.$file);
1502
	$this->_readstream($f,4);
1503
	$dp = '/Predictor 15 /Colors '.($colspace=='DeviceRGB' ? 3 : 1).' /BitsPerComponent '.$bpc.' /Columns '.$w;
1504
1505
	// Scan chunks looking for palette, transparency and image data
1506
	$pal = '';
1507
	$trns = '';
1508
	$data = '';
1509
	do
1510
	{
1511
		$n = $this->_readint($f);
1512
		$type = $this->_readstream($f,4);
1513
		if($type=='PLTE')
1514
		{
1515
			// Read palette
1516
			$pal = $this->_readstream($f,$n);
1517
			$this->_readstream($f,4);
1518
		}
1519
		elseif($type=='tRNS')
1520
		{
1521
			// Read transparency info
1522
			$t = $this->_readstream($f,$n);
1523
			if($ct==0)
1524
				$trns = array(ord(substr($t,1,1)));
1525
			elseif($ct==2)
1526
				$trns = array(ord(substr($t,1,1)), ord(substr($t,3,1)), ord(substr($t,5,1)));
1527
			else
1528
			{
1529
				$pos = strpos($t,chr(0));
1530
				if($pos!==false)
1531
					$trns = array($pos);
1532
			}
1533
			$this->_readstream($f,4);
1534
		}
1535
		elseif($type=='IDAT')
1536
		{
1537
			// Read image data block
1538
			$data .= $this->_readstream($f,$n);
1539
			$this->_readstream($f,4);
1540
		}
1541
		elseif($type=='IEND')
1542
			break;
1543
		else
1544
			$this->_readstream($f,$n+4);
1545
	}
1546
	while($n);
1547
1548
	if($colspace=='Indexed' && empty($pal))
1549
		$this->Error('Missing palette in '.$file);
1550
	$info = array('w'=>$w, 'h'=>$h, 'cs'=>$colspace, 'bpc'=>$bpc, 'f'=>'FlateDecode', 'dp'=>$dp, 'pal'=>$pal, 'trns'=>$trns);
1551
	if($ct>=4)
1552
	{
1553
		// Extract alpha channel
1554
		if(!function_exists('gzuncompress'))
1555
			$this->Error('Zlib not available, can\'t handle alpha channel: '.$file);
1556
		$data = gzuncompress($data);
1557
		$color = '';
1558
		$alpha = '';
1559
		if($ct==4)
1560
		{
1561
			// Gray image
1562
			$len = 2*$w;
1563
			for($i=0;$i<$h;$i++)
1564
			{
1565
				$pos = (1+$len)*$i;
1566
				$color .= $data[$pos];
1567
				$alpha .= $data[$pos];
1568
				$line = substr($data,$pos+1,$len);
1569
				$color .= preg_replace('/(.)./s','$1',$line);
1570
				$alpha .= preg_replace('/.(.)/s','$1',$line);
1571
			}
1572
		}
1573
		else
1574
		{
1575
			// RGB image
1576
			$len = 4*$w;
1577
			for($i=0;$i<$h;$i++)
1578
			{
1579
				$pos = (1+$len)*$i;
1580
				$color .= $data[$pos];
1581
				$alpha .= $data[$pos];
1582
				$line = substr($data,$pos+1,$len);
1583
				$color .= preg_replace('/(.{3})./s','$1',$line);
1584
				$alpha .= preg_replace('/.{3}(.)/s','$1',$line);
1585
			}
1586
		}
1587
		unset($data);
1588
		$data = gzcompress($color);
1589
		$info['smask'] = gzcompress($alpha);
1590
		$this->WithAlpha = true;
1591
		if($this->PDFVersion<'1.4')
1592
			$this->PDFVersion = '1.4';
1593
	}
1594
	$info['data'] = $data;
1595
	return $info;
1596
}
1597
1598
protected function _readstream($f, $n)
1599
{
1600
	// Read n bytes from stream
1601
	$res = '';
1602
	while($n>0 && !feof($f))
1603
	{
1604
		$s = fread($f,$n);
1605
		if($s===false)
1606
			$this->Error('Error while reading stream');
1607
		$n -= strlen($s);
1608
		$res .= $s;
1609
	}
1610
	if($n>0)
1611
		$this->Error('Unexpected end of stream');
1612
	return $res;
1613
}
1614
1615
protected function _readint($f)
1616
{
1617
	// Read a 4-byte integer from stream
1618
	$a = unpack('Ni',$this->_readstream($f,4));
1619
	return $a['i'];
1620
}
1621
1622
protected function _parsegif($file)
1623
{
1624
	// Extract info from a GIF file (via PNG conversion)
1625
	if(!function_exists('imagepng'))
1626
		$this->Error('GD extension is required for GIF support');
1627
	if(!function_exists('imagecreatefromgif'))
1628
		$this->Error('GD has no GIF read support');
1629
	$im = imagecreatefromgif($file);
1630
	if(!$im)
1631
		$this->Error('Missing or incorrect image file: '.$file);
1632
	imageinterlace($im,0);
1633
	ob_start();
1634
	imagepng($im);
1635
	$data = ob_get_clean();
1636
	imagedestroy($im);
1637
	$f = fopen('php://temp','rb+');
1638
	if(!$f)
1639
		$this->Error('Unable to create memory stream');
1640
	fwrite($f,$data);
1641
	rewind($f);
1642
	$info = $this->_parsepngstream($f,$file);
1643
	fclose($f);
1644
	return $info;
1645
}
1646
1647
protected function _out($s)
1648
{
1649
	// Add a line to the document
1650
	if($this->state==2)
1651
		$this->pages[$this->page] .= $s."\n";
1652
	elseif($this->state==1)
1653
		$this->_put($s);
1654
	elseif($this->state==0)
1655
		$this->Error('No page has been added yet');
1656
	elseif($this->state==3)
1657
		$this->Error('The document is closed');
1658
}
1659
1660
protected function _put($s)
1661
{
1662
	$this->buffer .= $s."\n";
1663
}
1664
1665
protected function _getoffset()
1666
{
1667
	return strlen($this->buffer);
1668
}
1669
1670
protected function _newobj($n=null)
1671
{
1672
	// Begin a new object
1673
	if($n===null)
1674
		$n = ++$this->n;
1675
	$this->offsets[$n] = $this->_getoffset();
1676
	$this->_put($n.' 0 obj');
1677
}
1678
1679
protected function _putstream($data)
1680
{
1681
	$this->_put('stream');
1682
	$this->_put($data);
1683
	$this->_put('endstream');
1684
}
1685
1686
protected function _putstreamobject($data)
1687
{
1688
	if($this->compress)
1689
	{
1690
		$entries = '/Filter /FlateDecode ';
1691
		$data = gzcompress($data);
1692
	}
1693
	else
1694
		$entries = '';
1695
	$entries .= '/Length '.strlen($data);
1696
	$this->_newobj();
1697
	$this->_put('<<'.$entries.'>>');
1698
	$this->_putstream($data);
1699
	$this->_put('endobj');
1700
}
1701
1702
protected function _putpage($n)
1703
{
1704
	$this->_newobj();
1705
	$this->_put('<</Type /Page');
1706
	$this->_put('/Parent 1 0 R');
1707
	if(isset($this->PageInfo[$n]['size']))
1708
		$this->_put(sprintf('/MediaBox [0 0 %.2F %.2F]',$this->PageInfo[$n]['size'][0],$this->PageInfo[$n]['size'][1]));
1709
	if(isset($this->PageInfo[$n]['rotation']))
1710
		$this->_put('/Rotate '.$this->PageInfo[$n]['rotation']);
1711
	$this->_put('/Resources 2 0 R');
1712
	if(isset($this->PageLinks[$n]))
1713
	{
1714
		// Links
1715
		$annots = '/Annots [';
1716
		foreach($this->PageLinks[$n] as $pl)
1717
		{
1718
			$rect = sprintf('%.2F %.2F %.2F %.2F',$pl[0],$pl[1],$pl[0]+$pl[2],$pl[1]-$pl[3]);
1719
			$annots .= '<</Type /Annot /Subtype /Link /Rect ['.$rect.'] /Border [0 0 0] ';
1720
			if(is_string($pl[4]))
1721
				$annots .= '/A <</S /URI /URI '.$this->_textstring($pl[4]).'>>>>';
1722
			else
1723
			{
1724
				$l = $this->links[$pl[4]];
1725
				if(isset($this->PageInfo[$l[0]]['size']))
1726
					$h = $this->PageInfo[$l[0]]['size'][1];
1727
				else
1728
					$h = ($this->DefOrientation=='P') ? $this->DefPageSize[1]*$this->k : $this->DefPageSize[0]*$this->k;
1729
				$annots .= sprintf('/Dest [%d 0 R /XYZ 0 %.2F null]>>',$this->PageInfo[$l[0]]['n'],$h-$l[1]*$this->k);
1730
			}
1731
		}
1732
		$this->_put($annots.']');
1733
	}
1734
	if($this->WithAlpha)
1735
		$this->_put('/Group <</Type /Group /S /Transparency /CS /DeviceRGB>>');
1736
	$this->_put('/Contents '.($this->n+1).' 0 R>>');
1737
	$this->_put('endobj');
1738
	// Page content
1739
	if(!empty($this->AliasNbPages)) {
1740
		$alias = $this->UTF8ToUTF16BE($this->AliasNbPages, false);
1741
		$r = $this->UTF8ToUTF16BE($this->page, false);
1742
		$this->pages[$n] = str_replace($alias,$r,$this->pages[$n]);
1743
		// Now repeat for no pages in non-subset fonts
1744
1745
		$this->pages[$n] = str_replace($this->AliasNbPages,$this->page,$this->pages[$n]);
1746
	}
1747
	$this->_putstreamobject($this->pages[$n]);
1748
}
1749
1750
protected function _putpages()
1751
{
1752
	$nb = $this->page;
1753
	for($n=1;$n<=$nb;$n++)
1754
		$this->PageInfo[$n]['n'] = $this->n+1+2*($n-1);
1755
	for($n=1;$n<=$nb;$n++)
1756
		$this->_putpage($n);
1757
	// Pages root
1758
	$this->_newobj(1);
1759
	$this->_put('<</Type /Pages');
1760
	$kids = '/Kids [';
1761
	for($n=1;$n<=$nb;$n++)
1762
		$kids .= $this->PageInfo[$n]['n'].' 0 R ';
1763
	$this->_put($kids.']');
1764
	$this->_put('/Count '.$nb);
1765
	if($this->DefOrientation=='P')
1766
	{
1767
		$w = $this->DefPageSize[0];
1768
		$h = $this->DefPageSize[1];
1769
	}
1770
	else
1771
	{
1772
		$w = $this->DefPageSize[1];
1773
		$h = $this->DefPageSize[0];
1774
	}
1775
	$this->_put(sprintf('/MediaBox [0 0 %.2F %.2F]',$w*$this->k,$h*$this->k));
1776
	$this->_put('>>');
1777
	$this->_put('endobj');
1778
}
1779
1780
protected function _putfonts()
1781
{
1782
	foreach($this->FontFiles as $file=>$info)
1783
	{
1784
		if (!isset($info['type']) || $info['type']!='TTF') {
1785
			// Font file embedding
1786
			$this->_newobj();
1787
			$this->FontFiles[$file]['n'] = $this->n;
1788
			$font = file_get_contents($this->fontpath.$file,true);
1789
			if(!$font)
1790
				$this->Error('Font file not found: '.$file);
1791
			$compressed = (substr($file,-2)=='.z');
1792
			if(!$compressed && isset($info['length2']))
1793
				$font = substr($font,6,$info['length1']).substr($font,6+$info['length1']+6,$info['length2']);
1794
			$this->_put('<</Length '.strlen($font));
1795
			if($compressed)
1796
				$this->_put('/Filter /FlateDecode');
1797
			$this->_put('/Length1 '.$info['length1']);
1798
			if(isset($info['length2']))
1799
				$this->_put('/Length2 '.$info['length2'].' /Length3 0');
1800
			$this->_put('>>');
1801
			$this->_putstream($font);
1802
			$this->_put('endobj');
1803
		}
1804
	}
1805
	foreach($this->fonts as $k=>$font)
1806
	{
1807
		// Encoding
1808
		if(isset($font['diff']))
1809
		{
1810
			if(!isset($this->encodings[$font['enc']]))
1811
			{
1812
				$this->_newobj();
1813
				$this->_put('<</Type /Encoding /BaseEncoding /WinAnsiEncoding /Differences ['.$font['diff'].']>>');
1814
				$this->_put('endobj');
1815
				$this->encodings[$font['enc']] = $this->n;
1816
			}
1817
		}
1818
		// ToUnicode CMap
1819
		if(isset($font['uv']))
1820
		{
1821
			if(isset($font['enc']))
1822
				$cmapkey = $font['enc'];
1823
			else
1824
				$cmapkey = $font['name'];
1825
			if(!isset($this->cmaps[$cmapkey]))
1826
			{
1827
				$cmap = $this->_tounicodecmap($font['uv']);
1828
				$this->_putstreamobject($cmap);
1829
				$this->cmaps[$cmapkey] = $this->n;
1830
			}
1831
		}
1832
		// Font object
1833
		$type = $font['type'];
1834
		$name = $font['name'];
1835
		if($type=='Core')
1836
		{
1837
			// Core font
1838
			$this->fonts[$k]['n'] = $this->n+1;
1839
			$this->_newobj();
1840
			$this->_put('<</Type /Font');
1841
			$this->_put('/BaseFont /'.$name);
1842
			$this->_put('/Subtype /Type1');
1843
			if($name!='Symbol' && $name!='ZapfDingbats')
1844
				$this->_put('/Encoding /WinAnsiEncoding');
1845
			if(isset($font['uv']))
1846
				$this->_put('/ToUnicode '.$this->cmaps[$cmapkey].' 0 R');
1847
			$this->_put('>>');
1848
			$this->_put('endobj');
1849
		}
1850
		elseif($type=='Type1' || $type=='TrueType')
1851
		{
1852
			// Additional Type1 or TrueType/OpenType font
1853
			if(isset($font['subsetted']) && $font['subsetted'])
1854
				$name = 'AAAAAA+'.$name;
1855
			$this->fonts[$k]['n'] = $this->n+1;
1856
			$this->_newobj();
1857
			$this->_put('<</Type /Font');
1858
			$this->_put('/BaseFont /'.$name);
1859
			$this->_put('/Subtype /'.$type);
1860
			$this->_put('/FirstChar 32 /LastChar 255');
1861
			$this->_put('/Widths '.($this->n+1).' 0 R');
1862
			$this->_put('/FontDescriptor '.($this->n+2).' 0 R');
1863
1864
			if($font['enc'])
1865
			{
1866
				if(isset($font['diff']))
1867
					$this->_put('/Encoding '.$this->encodings[$font['enc']].' 0 R');
1868
				else
1869
					$this->_put('/Encoding /WinAnsiEncoding');
1870
			}
1871
1872
			if(isset($font['uv']))
1873
				$this->_put('/ToUnicode '.$this->cmaps[$cmapkey].' 0 R');
1874
			$this->_put('>>');
1875
			$this->_put('endobj');
1876
			// Widths
1877
			$this->_newobj();
1878
			$cw = &$font['cw'];
1879
			$s = '[';
1880
			for($i=32;$i<=255;$i++)
1881
				$s .= $cw[chr($i)].' ';
1882
			$this->_put($s.']');
1883
			$this->_put('endobj');
1884
			// Descriptor
1885
			$this->_newobj();
1886
			$s = '<</Type /FontDescriptor /FontName /'.$name;
1887
			foreach($font['desc'] as $k=>$v)
1888
				$s .= ' /'.$k.' '.$v;
1889
1890
			if(!empty($font['file']))
1891
				$s .= ' /FontFile'.($type=='Type1' ? '' : '2').' '.$this->FontFiles[$font['file']]['n'].' 0 R';
1892
			$this->_put($s.'>>');
1893
			$this->_put('endobj');
1894
		}
1895
		// TrueType embedded SUBSETS or FULL
1896
		else if ($type=='TTF') {
1897
			$this->fonts[$k]['n']=$this->n+1;
1898
//			require_once($this->fontpath.'unifont/ttfonts.php');
1899
			$ttf = new TTFontFile();
1900
			$fontname = 'MPDFAA'.'+'.$font['name'];
1901
			$subset = $font['subset'];
1902
			unset($subset[0]);
1903
			$ttfontstream = $ttf->makeSubset($font['ttffile'], $subset);
1904
			$ttfontsize = strlen($ttfontstream);
1905
			$fontstream = gzcompress($ttfontstream);
1906
			$codeToGlyph = $ttf->codeToGlyph;
1907
			unset($codeToGlyph[0]);
1908
1909
			// Type0 Font
1910
			// A composite font - a font composed of other fonts, organized hierarchically
1911
			$this->_newobj();
1912
			$this->_put('<</Type /Font');
1913
			$this->_put('/Subtype /Type0');
1914
			$this->_put('/BaseFont /'.$fontname.'');
1915
			$this->_put('/Encoding /Identity-H'); 
1916
			$this->_put('/DescendantFonts ['.($this->n + 1).' 0 R]');
1917
			$this->_put('/ToUnicode '.($this->n + 2).' 0 R');
1918
			$this->_put('>>');
1919
			$this->_put('endobj');
1920
1921
			// CIDFontType2
1922
			// A CIDFont whose glyph descriptions are based on TrueType font technology
1923
			$this->_newobj();
1924
			$this->_put('<</Type /Font');
1925
			$this->_put('/Subtype /CIDFontType2');
1926
			$this->_put('/BaseFont /'.$fontname.'');
1927
			$this->_put('/CIDSystemInfo '.($this->n + 2).' 0 R'); 
1928
			$this->_put('/FontDescriptor '.($this->n + 3).' 0 R');
1929
			if (isset($font['desc']['MissingWidth'])){
1930
				$this->_out('/DW '.$font['desc']['MissingWidth'].''); 
1931
			}
1932
1933
			$this->_putTTfontwidths($font, $ttf->maxUni);
1934
1935
			$this->_put('/CIDToGIDMap '.($this->n + 4).' 0 R');
1936
			$this->_put('>>');
1937
			$this->_put('endobj');
1938
1939
			// ToUnicode
1940
			$this->_newobj();
1941
			$toUni = "/CIDInit /ProcSet findresource begin\n";
1942
			$toUni .= "12 dict begin\n";
1943
			$toUni .= "begincmap\n";
1944
			$toUni .= "/CIDSystemInfo\n";
1945
			$toUni .= "<</Registry (Adobe)\n";
1946
			$toUni .= "/Ordering (UCS)\n";
1947
			$toUni .= "/Supplement 0\n";
1948
			$toUni .= ">> def\n";
1949
			$toUni .= "/CMapName /Adobe-Identity-UCS def\n";
1950
			$toUni .= "/CMapType 2 def\n";
1951
			$toUni .= "1 begincodespacerange\n";
1952
			$toUni .= "<0000> <FFFF>\n";
1953
			$toUni .= "endcodespacerange\n";
1954
			$toUni .= "1 beginbfrange\n";
1955
			$toUni .= "<0000> <FFFF> <0000>\n";
1956
			$toUni .= "endbfrange\n";
1957
			$toUni .= "endcmap\n";
1958
			$toUni .= "CMapName currentdict /CMap defineresource pop\n";
1959
			$toUni .= "end\n";
1960
			$toUni .= "end";
1961
			$this->_put('<</Length '.(strlen($toUni)).'>>');
1962
			$this->_putstream($toUni);
1963
			$this->_put('endobj');
1964
1965
			// CIDSystemInfo dictionary
1966
			$this->_newobj();
1967
			$this->_put('<</Registry (Adobe)'); 
1968
			$this->_put('/Ordering (UCS)');
1969
			$this->_put('/Supplement 0');
1970
			$this->_put('>>');
1971
			$this->_put('endobj');
1972
1973
			// Font descriptor
1974
			$this->_newobj();
1975
			$this->_put('<</Type /FontDescriptor');
1976
			$this->_put('/FontName /'.$fontname);
1977
			foreach($font['desc'] as $kd=>$v) {
1978
				if ($kd == 'Flags') { $v = $v | 4; $v = $v & ~32; }	// SYMBOLIC font flag
1979
				$this->_out(' /'.$kd.' '.$v);
1980
			}
1981
			$this->_put('/FontFile2 '.($this->n + 2).' 0 R');
1982
			$this->_put('>>');
1983
			$this->_put('endobj');
1984
1985
			// Embed CIDToGIDMap
1986
			// A specification of the mapping from CIDs to glyph indices
1987
			$cidtogidmap = '';
1988
			$cidtogidmap = str_pad('', 256*256*2, "\x00");
1989
			foreach($codeToGlyph as $cc=>$glyph) {
1990
				$cidtogidmap[$cc*2] = chr($glyph >> 8);
1991
				$cidtogidmap[$cc*2 + 1] = chr($glyph & 0xFF);
1992
			}
1993
			$cidtogidmap = gzcompress($cidtogidmap);
1994
			$this->_newobj();
1995
			$this->_put('<</Length '.strlen($cidtogidmap).'');
1996
			$this->_put('/Filter /FlateDecode');
1997
			$this->_put('>>');
1998
			$this->_putstream($cidtogidmap);
1999
			$this->_put('endobj');
2000
2001
			//Font file 
2002
			$this->_newobj();
2003
			$this->_put('<</Length '.strlen($fontstream));
2004
			$this->_put('/Filter /FlateDecode');
2005
			$this->_put('/Length1 '.$ttfontsize);
2006
			$this->_put('>>');
2007
			$this->_putstream($fontstream);
2008
			$this->_put('endobj');
2009
			unset($ttf);
2010
		} 
2011
		else
2012
		{
2013
			// Allow for additional types
2014
			$this->fonts[$k]['n'] = $this->n+1;
2015
			$mtd = '_put'.strtolower($type);
2016
			if(!method_exists($this,$mtd))
2017
				$this->Error('Unsupported font type: '.$type);
2018
			$this->$mtd($font);
2019
		}
2020
	}
2021
}
2022
2023
protected function _putTTfontwidths(&$font, $maxUni) {
2024
	if (file_exists($font['unifilename'].'.cw127.php')) {
2025
		include($font['unifilename'].'.cw127.php') ;
2026
		$startcid = 128;
2027
	}
2028
	else {
2029
		$rangeid = 0;
2030
		$range = array();
2031
		$prevcid = -2;
2032
		$prevwidth = -1;
2033
		$interval = false;
2034
		$startcid = 1;
2035
	}
2036
	$cwlen = $maxUni + 1; 
2037
2038
	// for each character
2039
	for ($cid=$startcid; $cid<$cwlen; $cid++) {
2040
		if ($cid==128 && (!file_exists($font['unifilename'].'.cw127.php'))) {
2041
			if (is_writable(dirname($this->fontpath.'unifont/x'))) {
2042
				$fh = fopen($font['unifilename'].'.cw127.php',"wb");
2043
				$cw127='<?php'."\n";
2044
				$cw127.='$rangeid='.$rangeid.";\n";
2045
				$cw127.='$prevcid='.$prevcid.";\n";
2046
				$cw127.='$prevwidth='.$prevwidth.";\n";
2047
				if ($interval) { $cw127.='$interval=true'.";\n"; }
2048
				else { $cw127.='$interval=false'.";\n"; }
2049
				$cw127.='$range='.var_export($range,true).";\n";
2050
				$cw127.="?>";
2051
				fwrite($fh,$cw127,strlen($cw127));
2052
				fclose($fh);
2053
			}
2054
		}
2055
		if ((!isset($font['cw'][$cid*2]) || !isset($font['cw'][$cid*2+1])) || 
2056
                    ($font['cw'][$cid*2] == "\00" && $font['cw'][$cid*2+1] == "\00")) { continue; }
2057
2058
		$width = (ord($font['cw'][$cid*2]) << 8) + ord($font['cw'][$cid*2+1]);
2059
		if ($width == 65535) { $width = 0; }
2060
		if ($cid > 255 && (!isset($font['subset'][$cid]) || !$font['subset'][$cid])) { continue; }
2061
		if (!isset($font['dw']) || (isset($font['dw']) && $width != $font['dw'])) {
2062
			if ($cid == ($prevcid + 1)) {
2063
				if ($width == $prevwidth) {
2064
					if ($width == $range[$rangeid][0]) {
2065
						$range[$rangeid][] = $width;
2066
					}
2067
					else {
2068
						array_pop($range[$rangeid]);
2069
						// new range
2070
						$rangeid = $prevcid;
2071
						$range[$rangeid] = array();
2072
						$range[$rangeid][] = $prevwidth;
2073
						$range[$rangeid][] = $width;
2074
					}
2075
					$interval = true;
2076
					$range[$rangeid]['interval'] = true;
2077
				} else {
2078
					if ($interval) {
2079
						// new range
2080
						$rangeid = $cid;
2081
						$range[$rangeid] = array();
2082
						$range[$rangeid][] = $width;
2083
					}
2084
					else { $range[$rangeid][] = $width; }
2085
					$interval = false;
2086
				}
2087
			} else {
2088
				$rangeid = $cid;
2089
				$range[$rangeid] = array();
2090
				$range[$rangeid][] = $width;
2091
				$interval = false;
2092
			}
2093
			$prevcid = $cid;
2094
			$prevwidth = $width;
2095
		}
2096
	}
2097
	$prevk = -1;
2098
	$nextk = -1;
2099
	$prevint = false;
2100
	foreach ($range as $k => $ws) {
2101
		$cws = count($ws);
2102
		if (($k == $nextk) AND (!$prevint) AND ((!isset($ws['interval'])) OR ($cws < 4))) {
2103
			if (isset($range[$k]['interval'])) { unset($range[$k]['interval']); }
2104
			$range[$prevk] = array_merge($range[$prevk], $range[$k]);
2105
			unset($range[$k]);
2106
		}
2107
		else { $prevk = $k; }
2108
		$nextk = $k + $cws;
2109
		if (isset($ws['interval'])) {
2110
			if ($cws > 3) { $prevint = true; }
2111
			else { $prevint = false; }
2112
			unset($range[$k]['interval']);
2113
			--$nextk;
2114
		}
2115
		else { $prevint = false; }
2116
	}
2117
	$w = '';
2118
	foreach ($range as $k => $ws) {
2119
		if (count(array_count_values($ws)) == 1) { $w .= ' '.$k.' '.($k + count($ws) - 1).' '.$ws[0]; }
2120
		else { $w .= ' '.$k.' [ '.implode(' ', $ws).' ]' . "\n"; }
2121
	}
2122
	$this->_out('/W ['.$w.' ]');
2123
}
2124
2125
protected function _tounicodecmap($uv)
2126
{
2127
	$ranges = '';
2128
	$nbr = 0;
2129
	$chars = '';
2130
	$nbc = 0;
2131
	foreach($uv as $c=>$v)
2132
	{
2133
		if(is_array($v))
2134
		{
2135
			$ranges .= sprintf("<%02X> <%02X> <%04X>\n",$c,$c+$v[1]-1,$v[0]);
2136
			$nbr++;
2137
		}
2138
		else
2139
		{
2140
			$chars .= sprintf("<%02X> <%04X>\n",$c,$v);
2141
			$nbc++;
2142
		}
2143
	}
2144
	$s = "/CIDInit /ProcSet findresource begin\n";
2145
	$s .= "12 dict begin\n";
2146
	$s .= "begincmap\n";
2147
	$s .= "/CIDSystemInfo\n";
2148
	$s .= "<</Registry (Adobe)\n";
2149
	$s .= "/Ordering (UCS)\n";
2150
	$s .= "/Supplement 0\n";
2151
	$s .= ">> def\n";
2152
	$s .= "/CMapName /Adobe-Identity-UCS def\n";
2153
	$s .= "/CMapType 2 def\n";
2154
	$s .= "1 begincodespacerange\n";
2155
	$s .= "<00> <FF>\n";
2156
	$s .= "endcodespacerange\n";
2157
	if($nbr>0)
2158
	{
2159
		$s .= "$nbr beginbfrange\n";
2160
		$s .= $ranges;
2161
		$s .= "endbfrange\n";
2162
	}
2163
	if($nbc>0)
2164
	{
2165
		$s .= "$nbc beginbfchar\n";
2166
		$s .= $chars;
2167
		$s .= "endbfchar\n";
2168
	}
2169
	$s .= "endcmap\n";
2170
	$s .= "CMapName currentdict /CMap defineresource pop\n";
2171
	$s .= "end\n";
2172
	$s .= "end";
2173
	return $s;
2174
}
2175
2176
protected function _putimages()
2177
{
2178
	foreach(array_keys($this->images) as $file)
2179
	{
2180
		$this->_putimage($this->images[$file]);
2181
		unset($this->images[$file]['data']);
2182
		unset($this->images[$file]['smask']);
2183
	}
2184
}
2185
2186
protected function _putimage(&$info)
2187
{
2188
	$this->_newobj();
2189
	$info['n'] = $this->n;
2190
	$this->_put('<</Type /XObject');
2191
	$this->_put('/Subtype /Image');
2192
	$this->_put('/Width '.$info['w']);
2193
	$this->_put('/Height '.$info['h']);
2194
	if($info['cs']=='Indexed')
2195
		$this->_put('/ColorSpace [/Indexed /DeviceRGB '.(strlen($info['pal'])/3-1).' '.($this->n+1).' 0 R]');
2196
	else
2197
	{
2198
		$this->_put('/ColorSpace /'.$info['cs']);
2199
		if($info['cs']=='DeviceCMYK')
2200
			$this->_put('/Decode [1 0 1 0 1 0 1 0]');
2201
	}
2202
	$this->_put('/BitsPerComponent '.$info['bpc']);
2203
	if(isset($info['f']))
2204
		$this->_put('/Filter /'.$info['f']);
2205
	if(isset($info['dp']))
2206
		$this->_put('/DecodeParms <<'.$info['dp'].'>>');
2207
	if(isset($info['trns']) && is_array($info['trns']))
2208
	{
2209
		$trns = '';
2210
		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...
2211
			$trns .= $info['trns'][$i].' '.$info['trns'][$i].' ';
2212
		$this->_put('/Mask ['.$trns.']');
2213
	}
2214
	if(isset($info['smask']))
2215
		$this->_put('/SMask '.($this->n+1).' 0 R');
2216
	$this->_put('/Length '.strlen($info['data']).'>>');
2217
	$this->_putstream($info['data']);
2218
	$this->_put('endobj');
2219
	// Soft mask
2220
	if(isset($info['smask']))
2221
	{
2222
		$dp = '/Predictor 15 /Colors 1 /BitsPerComponent 8 /Columns '.$info['w'];
2223
		$smask = array('w'=>$info['w'], 'h'=>$info['h'], 'cs'=>'DeviceGray', 'bpc'=>8, 'f'=>$info['f'], 'dp'=>$dp, 'data'=>$info['smask']);
2224
		$this->_putimage($smask);
2225
	}
2226
	// Palette
2227
	if($info['cs']=='Indexed')
2228
		$this->_putstreamobject($info['pal']);
2229
}
2230
2231
protected function _putxobjectdict()
2232
{
2233
	foreach($this->images as $image)
2234
		$this->_put('/I'.$image['i'].' '.$image['n'].' 0 R');
2235
}
2236
2237
protected function _putresourcedict()
2238
{
2239
	$this->_put('/ProcSet [/PDF /Text /ImageB /ImageC /ImageI]');
2240
	$this->_put('/Font <<');
2241
	foreach($this->fonts as $font)
2242
		$this->_put('/F'.$font['i'].' '.$font['n'].' 0 R');
2243
	$this->_put('>>');
2244
	$this->_put('/XObject <<');
2245
	$this->_putxobjectdict();
2246
	$this->_put('>>');
2247
}
2248
2249
protected function _putresources()
2250
{
2251
	$this->_putfonts();
2252
	$this->_putimages();
2253
	// Resource dictionary
2254
	$this->_newobj(2);
2255
	$this->_put('<<');
2256
	$this->_putresourcedict();
2257
	$this->_put('>>');
2258
	$this->_put('endobj');
2259
}
2260
2261
protected function _putinfo()
2262
{
2263
	$this->metadata['Producer'] = 'tFPDF '.tFPDF_VERSION;
2264
	$this->metadata['CreationDate'] = 'D:'.@date('YmdHis');
2265
	foreach($this->metadata as $key=>$value)
2266
		$this->_put('/'.$key.' '.$this->_textstring($value));
2267
}
2268
2269
protected function _putcatalog()
2270
{
2271
	$n = $this->PageInfo[1]['n'];
2272
	$this->_put('/Type /Catalog');
2273
	$this->_put('/Pages 1 0 R');
2274
	if($this->ZoomMode=='fullpage')
2275
		$this->_put('/OpenAction ['.$n.' 0 R /Fit]');
2276
	elseif($this->ZoomMode=='fullwidth')
2277
		$this->_put('/OpenAction ['.$n.' 0 R /FitH null]');
2278
	elseif($this->ZoomMode=='real')
2279
		$this->_put('/OpenAction ['.$n.' 0 R /XYZ null null 1]');
2280
	elseif(!is_string($this->ZoomMode))
2281
		$this->_put('/OpenAction ['.$n.' 0 R /XYZ null null '.sprintf('%.2F',$this->ZoomMode/100).']');
2282
	if($this->LayoutMode=='single')
2283
		$this->_put('/PageLayout /SinglePage');
2284
	elseif($this->LayoutMode=='continuous')
2285
		$this->_put('/PageLayout /OneColumn');
2286
	elseif($this->LayoutMode=='two')
2287
		$this->_put('/PageLayout /TwoColumnLeft');
2288
}
2289
2290
protected function _putheader()
2291
{
2292
	$this->_put('%PDF-'.$this->PDFVersion);
2293
}
2294
2295
protected function _puttrailer()
2296
{
2297
	$this->_put('/Size '.($this->n+1));
2298
	$this->_put('/Root '.$this->n.' 0 R');
2299
	$this->_put('/Info '.($this->n-1).' 0 R');
2300
}
2301
2302
protected function _enddoc()
2303
{
2304
	$this->_putheader();
2305
	$this->_putpages();
2306
	$this->_putresources();
2307
	// Info
2308
	$this->_newobj();
2309
	$this->_put('<<');
2310
	$this->_putinfo();
2311
	$this->_put('>>');
2312
	$this->_put('endobj');
2313
	// Catalog
2314
	$this->_newobj();
2315
	$this->_put('<<');
2316
	$this->_putcatalog();
2317
	$this->_put('>>');
2318
	$this->_put('endobj');
2319
	// Cross-ref
2320
	$offset = $this->_getoffset();
2321
	$this->_put('xref');
2322
	$this->_put('0 '.($this->n+1));
2323
	$this->_put('0000000000 65535 f ');
2324
	for($i=1;$i<=$this->n;$i++)
2325
		$this->_put(sprintf('%010d 00000 n ',$this->offsets[$i]));
2326
	// Trailer
2327
	$this->_put('trailer');
2328
	$this->_put('<<');
2329
	$this->_puttrailer();
2330
	$this->_put('>>');
2331
	$this->_put('startxref');
2332
	$this->_put($offset);
2333
	$this->_put('%%EOF');
2334
	$this->state = 3;
2335
}
2336
2337
// ********* NEW FUNCTIONS *********
2338
// Converts UTF-8 strings to UTF16-BE.
2339
protected function UTF8ToUTF16BE($str, $setbom=true) {
2340
	$outstr = "";
2341
	if ($setbom) {
2342
		$outstr .= "\xFE\xFF"; // Byte Order Mark (BOM)
2343
	}
2344
	$outstr .= mb_convert_encoding($str, 'UTF-16BE', 'UTF-8');
2345
	return $outstr;
2346
}
2347
2348
// Converts UTF-8 strings to codepoints array
2349
protected function UTF8StringToArray($str) {
2350
   $out = array();
2351
   $len = strlen($str);
2352
   for ($i = 0; $i < $len; $i++) {
2353
	$uni = -1;
2354
      $h = ord($str[$i]);
2355
      if ( $h <= 0x7F )
2356
         $uni = $h;
2357
      elseif ( $h >= 0xC2 ) {
2358
         if ( ($h <= 0xDF) && ($i < $len -1) )
2359
            $uni = ($h & 0x1F) << 6 | (ord($str[++$i]) & 0x3F);
2360
         elseif ( ($h <= 0xEF) && ($i < $len -2) )
2361
            $uni = ($h & 0x0F) << 12 | (ord($str[++$i]) & 0x3F) << 6
2362
                                       | (ord($str[++$i]) & 0x3F);
2363
         elseif ( ($h <= 0xF4) && ($i < $len -3) )
2364
            $uni = ($h & 0x0F) << 18 | (ord($str[++$i]) & 0x3F) << 12
2365
                                       | (ord($str[++$i]) & 0x3F) << 6
2366
                                       | (ord($str[++$i]) & 0x3F);
2367
      }
2368
	if ($uni >= 0) {
2369
		$out[] = $uni;
2370
	}
2371
   }
2372
   return $out;
2373
}
2374
2375
2376
2377
}
2378
?>
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...
2379