Subversion Repositories eFlore/Applications.cel

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1665 raphael 1
<?php
2
//============================================================+
3
// File name   : tcpdf_static.php
4
// Version     : 1.0.000
5
// Begin       : 2002-08-03
6
// Last Update : 2013-04-01
7
// Author      : Nicola Asuni - Tecnick.com LTD - www.tecnick.com - info@tecnick.com
8
// License     : GNU-LGPL v3 (http://www.gnu.org/copyleft/lesser.html)
9
// -------------------------------------------------------------------
10
// Copyright (C) 2002-2013 Nicola Asuni - Tecnick.com LTD
11
//
12
// This file is part of TCPDF software library.
13
//
14
// TCPDF is free software: you can redistribute it and/or modify it
15
// under the terms of the GNU Lesser General Public License as
16
// published by the Free Software Foundation, either version 3 of the
17
// License, or (at your option) any later version.
18
//
19
// TCPDF is distributed in the hope that it will be useful, but
20
// WITHOUT ANY WARRANTY; without even the implied warranty of
21
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
22
// See the GNU Lesser General Public License for more details.
23
//
24
// You should have received a copy of the License
25
// along with TCPDF. If not, see
26
// <http://www.tecnick.com/pagefiles/tcpdf/LICENSE.TXT>.
27
//
28
// See LICENSE.TXT file for more information.
29
// -------------------------------------------------------------------
30
//
31
// Description :
32
//   Static methods used by the TCPDF class.
33
//
34
//============================================================+
35
 
36
/**
37
 * @file
38
 * This is a PHP class that contains static methods for the TCPDF class.<br>
39
 * @package com.tecnick.tcpdf
40
 * @author Nicola Asuni
41
 * @version 1.0.000
42
 */
43
 
44
/**
45
 * @class TCPDF_STATIC
46
 * Static methods used by the TCPDF class.
47
 * @package com.tecnick.tcpdf
48
 * @brief PHP class for generating PDF documents without requiring external extensions.
49
 * @version 1.0.000
50
 * @author Nicola Asuni - info@tecnick.com
51
 */
52
class TCPDF_STATIC {
53
 
54
	/**
55
	 * Current TCPDF version.
56
	 * @private static
57
	 */
58
	private static $tcpdf_version = '6.0.020';
59
 
60
	/**
61
	 * String alias for total number of pages.
62
	 * @public static
63
	 */
64
	public static $alias_tot_pages = '{:ptp:}';
65
 
66
	/**
67
	 * String alias for page number.
68
	 * @public static
69
	 */
70
	public static $alias_num_page = '{:pnp:}';
71
 
72
	/**
73
	 * String alias for total number of pages in a single group.
74
	 * @public static
75
	 */
76
	public static $alias_group_tot_pages = '{:ptg:}';
77
 
78
	/**
79
	 * String alias for group page number.
80
	 * @public static
81
	 */
82
	public static $alias_group_num_page = '{:png:}';
83
 
84
	/**
85
	 * String alias for right shift compensation used to correctly align page numbers on the right.
86
	 * @public static
87
	 */
88
	public static $alias_right_shift = '{rsc:';
89
 
90
	/**
91
	 * Encryption padding string.
92
	 * @public static
93
	 */
94
	public static $enc_padding = "\x28\xBF\x4E\x5E\x4E\x75\x8A\x41\x64\x00\x4E\x56\xFF\xFA\x01\x08\x2E\x2E\x00\xB6\xD0\x68\x3E\x80\x2F\x0C\xA9\xFE\x64\x53\x69\x7A";
95
 
96
	/**
97
	 * ByteRange placemark used during digital signature process.
98
	 * @since 4.6.028 (2009-08-25)
99
	 * @public static
100
	 */
101
	public static $byterange_string = '/ByteRange[0 ********** ********** **********]';
102
 
103
	/**
104
	 * Array page boxes names
105
	 * @public static
106
	 */
107
	public static $pageboxes = array('MediaBox', 'CropBox', 'BleedBox', 'TrimBox', 'ArtBox');
108
 
109
	// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
110
 
111
	/**
112
	 * Return the current TCPDF version.
113
	 * @return TCPDF version string
114
	 * @since 5.9.012 (2010-11-10)
115
	 * @public static
116
	 */
117
	public static function getTCPDFVersion() {
118
		return self::$tcpdf_version;
119
	}
120
 
121
	/**
122
	 * Return the current TCPDF producer.
123
	 * @return TCPDF producer string
124
	 * @since 6.0.000 (2013-03-16)
125
	 * @public static
126
	 */
127
	public static function getTCPDFProducer() {
128
		return "\x54\x43\x50\x44\x46\x20".self::getTCPDFVersion()."\x20\x28\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x74\x63\x70\x64\x66\x2e\x6f\x72\x67\x29";
129
	}
130
 
131
	/**
132
	 * Sets the current active configuration setting of magic_quotes_runtime (if the set_magic_quotes_runtime function exist)
133
	 * @param $mqr (boolean) FALSE for off, TRUE for on.
134
	 * @since 4.6.025 (2009-08-17)
135
	 * @public static
136
	 */
137
	public static function set_mqr($mqr) {
138
		if (!defined('PHP_VERSION_ID')) {
139
			$version = PHP_VERSION;
140
			define('PHP_VERSION_ID', (($version{0} * 10000) + ($version{2} * 100) + $version{4}));
141
		}
142
		if (PHP_VERSION_ID < 50300) {
143
			@set_magic_quotes_runtime($mqr);
144
		}
145
	}
146
 
147
	/**
148
	 * Gets the current active configuration setting of magic_quotes_runtime (if the get_magic_quotes_runtime function exist)
149
	 * @return Returns 0 if magic quotes runtime is off or get_magic_quotes_runtime doesn't exist, 1 otherwise.
150
	 * @since 4.6.025 (2009-08-17)
151
	 * @public static
152
	 */
153
	public static function get_mqr() {
154
		if (!defined('PHP_VERSION_ID')) {
155
			$version = PHP_VERSION;
156
			define('PHP_VERSION_ID', (($version{0} * 10000) + ($version{2} * 100) + $version{4}));
157
		}
158
		if (PHP_VERSION_ID < 50300) {
159
			return @get_magic_quotes_runtime();
160
		}
161
		return 0;
162
	}
163
 
164
	/**
165
	 * Get page dimensions from format name.
166
	 * @param $format (mixed) The format name. It can be: <ul>
167
	 * <li><b>ISO 216 A Series + 2 SIS 014711 extensions</b></li>
168
	 * <li>A0 (841x1189 mm ; 33.11x46.81 in)</li>
169
	 * <li>A1 (594x841 mm ; 23.39x33.11 in)</li>
170
	 * <li>A2 (420x594 mm ; 16.54x23.39 in)</li>
171
	 * <li>A3 (297x420 mm ; 11.69x16.54 in)</li>
172
	 * <li>A4 (210x297 mm ; 8.27x11.69 in)</li>
173
	 * <li>A5 (148x210 mm ; 5.83x8.27 in)</li>
174
	 * <li>A6 (105x148 mm ; 4.13x5.83 in)</li>
175
	 * <li>A7 (74x105 mm ; 2.91x4.13 in)</li>
176
	 * <li>A8 (52x74 mm ; 2.05x2.91 in)</li>
177
	 * <li>A9 (37x52 mm ; 1.46x2.05 in)</li>
178
	 * <li>A10 (26x37 mm ; 1.02x1.46 in)</li>
179
	 * <li>A11 (18x26 mm ; 0.71x1.02 in)</li>
180
	 * <li>A12 (13x18 mm ; 0.51x0.71 in)</li>
181
	 * <li><b>ISO 216 B Series + 2 SIS 014711 extensions</b></li>
182
	 * <li>B0 (1000x1414 mm ; 39.37x55.67 in)</li>
183
	 * <li>B1 (707x1000 mm ; 27.83x39.37 in)</li>
184
	 * <li>B2 (500x707 mm ; 19.69x27.83 in)</li>
185
	 * <li>B3 (353x500 mm ; 13.90x19.69 in)</li>
186
	 * <li>B4 (250x353 mm ; 9.84x13.90 in)</li>
187
	 * <li>B5 (176x250 mm ; 6.93x9.84 in)</li>
188
	 * <li>B6 (125x176 mm ; 4.92x6.93 in)</li>
189
	 * <li>B7 (88x125 mm ; 3.46x4.92 in)</li>
190
	 * <li>B8 (62x88 mm ; 2.44x3.46 in)</li>
191
	 * <li>B9 (44x62 mm ; 1.73x2.44 in)</li>
192
	 * <li>B10 (31x44 mm ; 1.22x1.73 in)</li>
193
	 * <li>B11 (22x31 mm ; 0.87x1.22 in)</li>
194
	 * <li>B12 (15x22 mm ; 0.59x0.87 in)</li>
195
	 * <li><b>ISO 216 C Series + 2 SIS 014711 extensions + 2 EXTENSION</b></li>
196
	 * <li>C0 (917x1297 mm ; 36.10x51.06 in)</li>
197
	 * <li>C1 (648x917 mm ; 25.51x36.10 in)</li>
198
	 * <li>C2 (458x648 mm ; 18.03x25.51 in)</li>
199
	 * <li>C3 (324x458 mm ; 12.76x18.03 in)</li>
200
	 * <li>C4 (229x324 mm ; 9.02x12.76 in)</li>
201
	 * <li>C5 (162x229 mm ; 6.38x9.02 in)</li>
202
	 * <li>C6 (114x162 mm ; 4.49x6.38 in)</li>
203
	 * <li>C7 (81x114 mm ; 3.19x4.49 in)</li>
204
	 * <li>C8 (57x81 mm ; 2.24x3.19 in)</li>
205
	 * <li>C9 (40x57 mm ; 1.57x2.24 in)</li>
206
	 * <li>C10 (28x40 mm ; 1.10x1.57 in)</li>
207
	 * <li>C11 (20x28 mm ; 0.79x1.10 in)</li>
208
	 * <li>C12 (14x20 mm ; 0.55x0.79 in)</li>
209
	 * <li>C76 (81x162 mm ; 3.19x6.38 in)</li>
210
	 * <li>DL (110x220 mm ; 4.33x8.66 in)</li>
211
	 * <li><b>SIS 014711 E Series</b></li>
212
	 * <li>E0 (879x1241 mm ; 34.61x48.86 in)</li>
213
	 * <li>E1 (620x879 mm ; 24.41x34.61 in)</li>
214
	 * <li>E2 (440x620 mm ; 17.32x24.41 in)</li>
215
	 * <li>E3 (310x440 mm ; 12.20x17.32 in)</li>
216
	 * <li>E4 (220x310 mm ; 8.66x12.20 in)</li>
217
	 * <li>E5 (155x220 mm ; 6.10x8.66 in)</li>
218
	 * <li>E6 (110x155 mm ; 4.33x6.10 in)</li>
219
	 * <li>E7 (78x110 mm ; 3.07x4.33 in)</li>
220
	 * <li>E8 (55x78 mm ; 2.17x3.07 in)</li>
221
	 * <li>E9 (39x55 mm ; 1.54x2.17 in)</li>
222
	 * <li>E10 (27x39 mm ; 1.06x1.54 in)</li>
223
	 * <li>E11 (19x27 mm ; 0.75x1.06 in)</li>
224
	 * <li>E12 (13x19 mm ; 0.51x0.75 in)</li>
225
	 * <li><b>SIS 014711 G Series</b></li>
226
	 * <li>G0 (958x1354 mm ; 37.72x53.31 in)</li>
227
	 * <li>G1 (677x958 mm ; 26.65x37.72 in)</li>
228
	 * <li>G2 (479x677 mm ; 18.86x26.65 in)</li>
229
	 * <li>G3 (338x479 mm ; 13.31x18.86 in)</li>
230
	 * <li>G4 (239x338 mm ; 9.41x13.31 in)</li>
231
	 * <li>G5 (169x239 mm ; 6.65x9.41 in)</li>
232
	 * <li>G6 (119x169 mm ; 4.69x6.65 in)</li>
233
	 * <li>G7 (84x119 mm ; 3.31x4.69 in)</li>
234
	 * <li>G8 (59x84 mm ; 2.32x3.31 in)</li>
235
	 * <li>G9 (42x59 mm ; 1.65x2.32 in)</li>
236
	 * <li>G10 (29x42 mm ; 1.14x1.65 in)</li>
237
	 * <li>G11 (21x29 mm ; 0.83x1.14 in)</li>
238
	 * <li>G12 (14x21 mm ; 0.55x0.83 in)</li>
239
	 * <li><b>ISO Press</b></li>
240
	 * <li>RA0 (860x1220 mm ; 33.86x48.03 in)</li>
241
	 * <li>RA1 (610x860 mm ; 24.02x33.86 in)</li>
242
	 * <li>RA2 (430x610 mm ; 16.93x24.02 in)</li>
243
	 * <li>RA3 (305x430 mm ; 12.01x16.93 in)</li>
244
	 * <li>RA4 (215x305 mm ; 8.46x12.01 in)</li>
245
	 * <li>SRA0 (900x1280 mm ; 35.43x50.39 in)</li>
246
	 * <li>SRA1 (640x900 mm ; 25.20x35.43 in)</li>
247
	 * <li>SRA2 (450x640 mm ; 17.72x25.20 in)</li>
248
	 * <li>SRA3 (320x450 mm ; 12.60x17.72 in)</li>
249
	 * <li>SRA4 (225x320 mm ; 8.86x12.60 in)</li>
250
	 * <li><b>German DIN 476</b></li>
251
	 * <li>4A0 (1682x2378 mm ; 66.22x93.62 in)</li>
252
	 * <li>2A0 (1189x1682 mm ; 46.81x66.22 in)</li>
253
	 * <li><b>Variations on the ISO Standard</b></li>
254
	 * <li>A2_EXTRA (445x619 mm ; 17.52x24.37 in)</li>
255
	 * <li>A3+ (329x483 mm ; 12.95x19.02 in)</li>
256
	 * <li>A3_EXTRA (322x445 mm ; 12.68x17.52 in)</li>
257
	 * <li>A3_SUPER (305x508 mm ; 12.01x20.00 in)</li>
258
	 * <li>SUPER_A3 (305x487 mm ; 12.01x19.17 in)</li>
259
	 * <li>A4_EXTRA (235x322 mm ; 9.25x12.68 in)</li>
260
	 * <li>A4_SUPER (229x322 mm ; 9.02x12.68 in)</li>
261
	 * <li>SUPER_A4 (227x356 mm ; 8.94x14.02 in)</li>
262
	 * <li>A4_LONG (210x348 mm ; 8.27x13.70 in)</li>
263
	 * <li>F4 (210x330 mm ; 8.27x12.99 in)</li>
264
	 * <li>SO_B5_EXTRA (202x276 mm ; 7.95x10.87 in)</li>
265
	 * <li>A5_EXTRA (173x235 mm ; 6.81x9.25 in)</li>
266
	 * <li><b>ANSI Series</b></li>
267
	 * <li>ANSI_E (864x1118 mm ; 34.00x44.00 in)</li>
268
	 * <li>ANSI_D (559x864 mm ; 22.00x34.00 in)</li>
269
	 * <li>ANSI_C (432x559 mm ; 17.00x22.00 in)</li>
270
	 * <li>ANSI_B (279x432 mm ; 11.00x17.00 in)</li>
271
	 * <li>ANSI_A (216x279 mm ; 8.50x11.00 in)</li>
272
	 * <li><b>Traditional 'Loose' North American Paper Sizes</b></li>
273
	 * <li>LEDGER, USLEDGER (432x279 mm ; 17.00x11.00 in)</li>
274
	 * <li>TABLOID, USTABLOID, BIBLE, ORGANIZERK (279x432 mm ; 11.00x17.00 in)</li>
275
	 * <li>LETTER, USLETTER, ORGANIZERM (216x279 mm ; 8.50x11.00 in)</li>
276
	 * <li>LEGAL, USLEGAL (216x356 mm ; 8.50x14.00 in)</li>
277
	 * <li>GLETTER, GOVERNMENTLETTER (203x267 mm ; 8.00x10.50 in)</li>
278
	 * <li>JLEGAL, JUNIORLEGAL (203x127 mm ; 8.00x5.00 in)</li>
279
	 * <li><b>Other North American Paper Sizes</b></li>
280
	 * <li>QUADDEMY (889x1143 mm ; 35.00x45.00 in)</li>
281
	 * <li>SUPER_B (330x483 mm ; 13.00x19.00 in)</li>
282
	 * <li>QUARTO (229x279 mm ; 9.00x11.00 in)</li>
283
	 * <li>FOLIO, GOVERNMENTLEGAL (216x330 mm ; 8.50x13.00 in)</li>
284
	 * <li>EXECUTIVE, MONARCH (184x267 mm ; 7.25x10.50 in)</li>
285
	 * <li>MEMO, STATEMENT, ORGANIZERL (140x216 mm ; 5.50x8.50 in)</li>
286
	 * <li>FOOLSCAP (210x330 mm ; 8.27x13.00 in)</li>
287
	 * <li>COMPACT (108x171 mm ; 4.25x6.75 in)</li>
288
	 * <li>ORGANIZERJ (70x127 mm ; 2.75x5.00 in)</li>
289
	 * <li><b>Canadian standard CAN 2-9.60M</b></li>
290
	 * <li>P1 (560x860 mm ; 22.05x33.86 in)</li>
291
	 * <li>P2 (430x560 mm ; 16.93x22.05 in)</li>
292
	 * <li>P3 (280x430 mm ; 11.02x16.93 in)</li>
293
	 * <li>P4 (215x280 mm ; 8.46x11.02 in)</li>
294
	 * <li>P5 (140x215 mm ; 5.51x8.46 in)</li>
295
	 * <li>P6 (107x140 mm ; 4.21x5.51 in)</li>
296
	 * <li><b>North American Architectural Sizes</b></li>
297
	 * <li>ARCH_E (914x1219 mm ; 36.00x48.00 in)</li>
298
	 * <li>ARCH_E1 (762x1067 mm ; 30.00x42.00 in)</li>
299
	 * <li>ARCH_D (610x914 mm ; 24.00x36.00 in)</li>
300
	 * <li>ARCH_C, BROADSHEET (457x610 mm ; 18.00x24.00 in)</li>
301
	 * <li>ARCH_B (305x457 mm ; 12.00x18.00 in)</li>
302
	 * <li>ARCH_A (229x305 mm ; 9.00x12.00 in)</li>
303
	 * <li><b>Announcement Envelopes</b></li>
304
	 * <li>ANNENV_A2 (111x146 mm ; 4.37x5.75 in)</li>
305
	 * <li>ANNENV_A6 (121x165 mm ; 4.75x6.50 in)</li>
306
	 * <li>ANNENV_A7 (133x184 mm ; 5.25x7.25 in)</li>
307
	 * <li>ANNENV_A8 (140x206 mm ; 5.50x8.12 in)</li>
308
	 * <li>ANNENV_A10 (159x244 mm ; 6.25x9.62 in)</li>
309
	 * <li>ANNENV_SLIM (98x225 mm ; 3.87x8.87 in)</li>
310
	 * <li><b>Commercial Envelopes</b></li>
311
	 * <li>COMMENV_N6_1/4 (89x152 mm ; 3.50x6.00 in)</li>
312
	 * <li>COMMENV_N6_3/4 (92x165 mm ; 3.62x6.50 in)</li>
313
	 * <li>COMMENV_N8 (98x191 mm ; 3.87x7.50 in)</li>
314
	 * <li>COMMENV_N9 (98x225 mm ; 3.87x8.87 in)</li>
315
	 * <li>COMMENV_N10 (105x241 mm ; 4.12x9.50 in)</li>
316
	 * <li>COMMENV_N11 (114x263 mm ; 4.50x10.37 in)</li>
317
	 * <li>COMMENV_N12 (121x279 mm ; 4.75x11.00 in)</li>
318
	 * <li>COMMENV_N14 (127x292 mm ; 5.00x11.50 in)</li>
319
	 * <li><b>Catalogue Envelopes</b></li>
320
	 * <li>CATENV_N1 (152x229 mm ; 6.00x9.00 in)</li>
321
	 * <li>CATENV_N1_3/4 (165x241 mm ; 6.50x9.50 in)</li>
322
	 * <li>CATENV_N2 (165x254 mm ; 6.50x10.00 in)</li>
323
	 * <li>CATENV_N3 (178x254 mm ; 7.00x10.00 in)</li>
324
	 * <li>CATENV_N6 (191x267 mm ; 7.50x10.50 in)</li>
325
	 * <li>CATENV_N7 (203x279 mm ; 8.00x11.00 in)</li>
326
	 * <li>CATENV_N8 (210x286 mm ; 8.25x11.25 in)</li>
327
	 * <li>CATENV_N9_1/2 (216x267 mm ; 8.50x10.50 in)</li>
328
	 * <li>CATENV_N9_3/4 (222x286 mm ; 8.75x11.25 in)</li>
329
	 * <li>CATENV_N10_1/2 (229x305 mm ; 9.00x12.00 in)</li>
330
	 * <li>CATENV_N12_1/2 (241x318 mm ; 9.50x12.50 in)</li>
331
	 * <li>CATENV_N13_1/2 (254x330 mm ; 10.00x13.00 in)</li>
332
	 * <li>CATENV_N14_1/4 (286x311 mm ; 11.25x12.25 in)</li>
333
	 * <li>CATENV_N14_1/2 (292x368 mm ; 11.50x14.50 in)</li>
334
	 * <li><b>Japanese (JIS P 0138-61) Standard B-Series</b></li>
335
	 * <li>JIS_B0 (1030x1456 mm ; 40.55x57.32 in)</li>
336
	 * <li>JIS_B1 (728x1030 mm ; 28.66x40.55 in)</li>
337
	 * <li>JIS_B2 (515x728 mm ; 20.28x28.66 in)</li>
338
	 * <li>JIS_B3 (364x515 mm ; 14.33x20.28 in)</li>
339
	 * <li>JIS_B4 (257x364 mm ; 10.12x14.33 in)</li>
340
	 * <li>JIS_B5 (182x257 mm ; 7.17x10.12 in)</li>
341
	 * <li>JIS_B6 (128x182 mm ; 5.04x7.17 in)</li>
342
	 * <li>JIS_B7 (91x128 mm ; 3.58x5.04 in)</li>
343
	 * <li>JIS_B8 (64x91 mm ; 2.52x3.58 in)</li>
344
	 * <li>JIS_B9 (45x64 mm ; 1.77x2.52 in)</li>
345
	 * <li>JIS_B10 (32x45 mm ; 1.26x1.77 in)</li>
346
	 * <li>JIS_B11 (22x32 mm ; 0.87x1.26 in)</li>
347
	 * <li>JIS_B12 (16x22 mm ; 0.63x0.87 in)</li>
348
	 * <li><b>PA Series</b></li>
349
	 * <li>PA0 (840x1120 mm ; 33.07x44.09 in)</li>
350
	 * <li>PA1 (560x840 mm ; 22.05x33.07 in)</li>
351
	 * <li>PA2 (420x560 mm ; 16.54x22.05 in)</li>
352
	 * <li>PA3 (280x420 mm ; 11.02x16.54 in)</li>
353
	 * <li>PA4 (210x280 mm ; 8.27x11.02 in)</li>
354
	 * <li>PA5 (140x210 mm ; 5.51x8.27 in)</li>
355
	 * <li>PA6 (105x140 mm ; 4.13x5.51 in)</li>
356
	 * <li>PA7 (70x105 mm ; 2.76x4.13 in)</li>
357
	 * <li>PA8 (52x70 mm ; 2.05x2.76 in)</li>
358
	 * <li>PA9 (35x52 mm ; 1.38x2.05 in)</li>
359
	 * <li>PA10 (26x35 mm ; 1.02x1.38 in)</li>
360
	 * <li><b>Standard Photographic Print Sizes</b></li>
361
	 * <li>PASSPORT_PHOTO (35x45 mm ; 1.38x1.77 in)</li>
362
	 * <li>E (82x120 mm ; 3.25x4.72 in)</li>
363
	 * <li>3R, L (89x127 mm ; 3.50x5.00 in)</li>
364
	 * <li>4R, KG (102x152 mm ; 4.02x5.98 in)</li>
365
	 * <li>4D (120x152 mm ; 4.72x5.98 in)</li>
366
	 * <li>5R, 2L (127x178 mm ; 5.00x7.01 in)</li>
367
	 * <li>6R, 8P (152x203 mm ; 5.98x7.99 in)</li>
368
	 * <li>8R, 6P (203x254 mm ; 7.99x10.00 in)</li>
369
	 * <li>S8R, 6PW (203x305 mm ; 7.99x12.01 in)</li>
370
	 * <li>10R, 4P (254x305 mm ; 10.00x12.01 in)</li>
371
	 * <li>S10R, 4PW (254x381 mm ; 10.00x15.00 in)</li>
372
	 * <li>11R (279x356 mm ; 10.98x14.02 in)</li>
373
	 * <li>S11R (279x432 mm ; 10.98x17.01 in)</li>
374
	 * <li>12R (305x381 mm ; 12.01x15.00 in)</li>
375
	 * <li>S12R (305x456 mm ; 12.01x17.95 in)</li>
376
	 * <li><b>Common Newspaper Sizes</b></li>
377
	 * <li>NEWSPAPER_BROADSHEET (750x600 mm ; 29.53x23.62 in)</li>
378
	 * <li>NEWSPAPER_BERLINER (470x315 mm ; 18.50x12.40 in)</li>
379
	 * <li>NEWSPAPER_COMPACT, NEWSPAPER_TABLOID (430x280 mm ; 16.93x11.02 in)</li>
380
	 * <li><b>Business Cards</b></li>
381
	 * <li>CREDIT_CARD, BUSINESS_CARD, BUSINESS_CARD_ISO7810 (54x86 mm ; 2.13x3.37 in)</li>
382
	 * <li>BUSINESS_CARD_ISO216 (52x74 mm ; 2.05x2.91 in)</li>
383
	 * <li>BUSINESS_CARD_IT, BUSINESS_CARD_UK, BUSINESS_CARD_FR, BUSINESS_CARD_DE, BUSINESS_CARD_ES (55x85 mm ; 2.17x3.35 in)</li>
384
	 * <li>BUSINESS_CARD_US, BUSINESS_CARD_CA (51x89 mm ; 2.01x3.50 in)</li>
385
	 * <li>BUSINESS_CARD_JP (55x91 mm ; 2.17x3.58 in)</li>
386
	 * <li>BUSINESS_CARD_HK (54x90 mm ; 2.13x3.54 in)</li>
387
	 * <li>BUSINESS_CARD_AU, BUSINESS_CARD_DK, BUSINESS_CARD_SE (55x90 mm ; 2.17x3.54 in)</li>
388
	 * <li>BUSINESS_CARD_RU, BUSINESS_CARD_CZ, BUSINESS_CARD_FI, BUSINESS_CARD_HU, BUSINESS_CARD_IL (50x90 mm ; 1.97x3.54 in)</li>
389
	 * <li><b>Billboards</b></li>
390
	 * <li>4SHEET (1016x1524 mm ; 40.00x60.00 in)</li>
391
	 * <li>6SHEET (1200x1800 mm ; 47.24x70.87 in)</li>
392
	 * <li>12SHEET (3048x1524 mm ; 120.00x60.00 in)</li>
393
	 * <li>16SHEET (2032x3048 mm ; 80.00x120.00 in)</li>
394
	 * <li>32SHEET (4064x3048 mm ; 160.00x120.00 in)</li>
395
	 * <li>48SHEET (6096x3048 mm ; 240.00x120.00 in)</li>
396
	 * <li>64SHEET (8128x3048 mm ; 320.00x120.00 in)</li>
397
	 * <li>96SHEET (12192x3048 mm ; 480.00x120.00 in)</li>
398
	 * <li><b>Old Imperial English (some are still used in USA)</b></li>
399
	 * <li>EN_EMPEROR (1219x1829 mm ; 48.00x72.00 in)</li>
400
	 * <li>EN_ANTIQUARIAN (787x1346 mm ; 31.00x53.00 in)</li>
401
	 * <li>EN_GRAND_EAGLE (730x1067 mm ; 28.75x42.00 in)</li>
402
	 * <li>EN_DOUBLE_ELEPHANT (679x1016 mm ; 26.75x40.00 in)</li>
403
	 * <li>EN_ATLAS (660x864 mm ; 26.00x34.00 in)</li>
404
	 * <li>EN_COLOMBIER (597x876 mm ; 23.50x34.50 in)</li>
405
	 * <li>EN_ELEPHANT (584x711 mm ; 23.00x28.00 in)</li>
406
	 * <li>EN_DOUBLE_DEMY (572x902 mm ; 22.50x35.50 in)</li>
407
	 * <li>EN_IMPERIAL (559x762 mm ; 22.00x30.00 in)</li>
408
	 * <li>EN_PRINCESS (546x711 mm ; 21.50x28.00 in)</li>
409
	 * <li>EN_CARTRIDGE (533x660 mm ; 21.00x26.00 in)</li>
410
	 * <li>EN_DOUBLE_LARGE_POST (533x838 mm ; 21.00x33.00 in)</li>
411
	 * <li>EN_ROYAL (508x635 mm ; 20.00x25.00 in)</li>
412
	 * <li>EN_SHEET, EN_HALF_POST (495x597 mm ; 19.50x23.50 in)</li>
413
	 * <li>EN_SUPER_ROYAL (483x686 mm ; 19.00x27.00 in)</li>
414
	 * <li>EN_DOUBLE_POST (483x775 mm ; 19.00x30.50 in)</li>
415
	 * <li>EN_MEDIUM (445x584 mm ; 17.50x23.00 in)</li>
416
	 * <li>EN_DEMY (445x572 mm ; 17.50x22.50 in)</li>
417
	 * <li>EN_LARGE_POST (419x533 mm ; 16.50x21.00 in)</li>
418
	 * <li>EN_COPY_DRAUGHT (406x508 mm ; 16.00x20.00 in)</li>
419
	 * <li>EN_POST (394x489 mm ; 15.50x19.25 in)</li>
420
	 * <li>EN_CROWN (381x508 mm ; 15.00x20.00 in)</li>
421
	 * <li>EN_PINCHED_POST (375x470 mm ; 14.75x18.50 in)</li>
422
	 * <li>EN_BRIEF (343x406 mm ; 13.50x16.00 in)</li>
423
	 * <li>EN_FOOLSCAP (343x432 mm ; 13.50x17.00 in)</li>
424
	 * <li>EN_SMALL_FOOLSCAP (337x419 mm ; 13.25x16.50 in)</li>
425
	 * <li>EN_POTT (318x381 mm ; 12.50x15.00 in)</li>
426
	 * <li><b>Old Imperial Belgian</b></li>
427
	 * <li>BE_GRAND_AIGLE (700x1040 mm ; 27.56x40.94 in)</li>
428
	 * <li>BE_COLOMBIER (620x850 mm ; 24.41x33.46 in)</li>
429
	 * <li>BE_DOUBLE_CARRE (620x920 mm ; 24.41x36.22 in)</li>
430
	 * <li>BE_ELEPHANT (616x770 mm ; 24.25x30.31 in)</li>
431
	 * <li>BE_PETIT_AIGLE (600x840 mm ; 23.62x33.07 in)</li>
432
	 * <li>BE_GRAND_JESUS (550x730 mm ; 21.65x28.74 in)</li>
433
	 * <li>BE_JESUS (540x730 mm ; 21.26x28.74 in)</li>
434
	 * <li>BE_RAISIN (500x650 mm ; 19.69x25.59 in)</li>
435
	 * <li>BE_GRAND_MEDIAN (460x605 mm ; 18.11x23.82 in)</li>
436
	 * <li>BE_DOUBLE_POSTE (435x565 mm ; 17.13x22.24 in)</li>
437
	 * <li>BE_COQUILLE (430x560 mm ; 16.93x22.05 in)</li>
438
	 * <li>BE_PETIT_MEDIAN (415x530 mm ; 16.34x20.87 in)</li>
439
	 * <li>BE_RUCHE (360x460 mm ; 14.17x18.11 in)</li>
440
	 * <li>BE_PROPATRIA (345x430 mm ; 13.58x16.93 in)</li>
441
	 * <li>BE_LYS (317x397 mm ; 12.48x15.63 in)</li>
442
	 * <li>BE_POT (307x384 mm ; 12.09x15.12 in)</li>
443
	 * <li>BE_ROSETTE (270x347 mm ; 10.63x13.66 in)</li>
444
	 * <li><b>Old Imperial French</b></li>
445
	 * <li>FR_UNIVERS (1000x1300 mm ; 39.37x51.18 in)</li>
446
	 * <li>FR_DOUBLE_COLOMBIER (900x1260 mm ; 35.43x49.61 in)</li>
447
	 * <li>FR_GRANDE_MONDE (900x1260 mm ; 35.43x49.61 in)</li>
448
	 * <li>FR_DOUBLE_SOLEIL (800x1200 mm ; 31.50x47.24 in)</li>
449
	 * <li>FR_DOUBLE_JESUS (760x1120 mm ; 29.92x44.09 in)</li>
450
	 * <li>FR_GRAND_AIGLE (750x1060 mm ; 29.53x41.73 in)</li>
451
	 * <li>FR_PETIT_AIGLE (700x940 mm ; 27.56x37.01 in)</li>
452
	 * <li>FR_DOUBLE_RAISIN (650x1000 mm ; 25.59x39.37 in)</li>
453
	 * <li>FR_JOURNAL (650x940 mm ; 25.59x37.01 in)</li>
454
	 * <li>FR_COLOMBIER_AFFICHE (630x900 mm ; 24.80x35.43 in)</li>
455
	 * <li>FR_DOUBLE_CAVALIER (620x920 mm ; 24.41x36.22 in)</li>
456
	 * <li>FR_CLOCHE (600x800 mm ; 23.62x31.50 in)</li>
457
	 * <li>FR_SOLEIL (600x800 mm ; 23.62x31.50 in)</li>
458
	 * <li>FR_DOUBLE_CARRE (560x900 mm ; 22.05x35.43 in)</li>
459
	 * <li>FR_DOUBLE_COQUILLE (560x880 mm ; 22.05x34.65 in)</li>
460
	 * <li>FR_JESUS (560x760 mm ; 22.05x29.92 in)</li>
461
	 * <li>FR_RAISIN (500x650 mm ; 19.69x25.59 in)</li>
462
	 * <li>FR_CAVALIER (460x620 mm ; 18.11x24.41 in)</li>
463
	 * <li>FR_DOUBLE_COURONNE (460x720 mm ; 18.11x28.35 in)</li>
464
	 * <li>FR_CARRE (450x560 mm ; 17.72x22.05 in)</li>
465
	 * <li>FR_COQUILLE (440x560 mm ; 17.32x22.05 in)</li>
466
	 * <li>FR_DOUBLE_TELLIERE (440x680 mm ; 17.32x26.77 in)</li>
467
	 * <li>FR_DOUBLE_CLOCHE (400x600 mm ; 15.75x23.62 in)</li>
468
	 * <li>FR_DOUBLE_POT (400x620 mm ; 15.75x24.41 in)</li>
469
	 * <li>FR_ECU (400x520 mm ; 15.75x20.47 in)</li>
470
	 * <li>FR_COURONNE (360x460 mm ; 14.17x18.11 in)</li>
471
	 * <li>FR_TELLIERE (340x440 mm ; 13.39x17.32 in)</li>
472
	 * <li>FR_POT (310x400 mm ; 12.20x15.75 in)</li>
473
	 * </ul>
474
	 * @return array containing page width and height in points
475
	 * @since 5.0.010 (2010-05-17)
476
	 * @public static
477
	 */
478
	public static function getPageSizeFromFormat($format) {
479
		// Paper cordinates are calculated in this way: (inches * 72) where (1 inch = 25.4 mm)
480
		switch (strtoupper($format)) {
481
			// ISO 216 A Series + 2 SIS 014711 extensions
482
			case 'A0' : {$pf = array( 2383.937, 3370.394); break;}
483
			case 'A1' : {$pf = array( 1683.780, 2383.937); break;}
484
			case 'A2' : {$pf = array( 1190.551, 1683.780); break;}
485
			case 'A3' : {$pf = array(  841.890, 1190.551); break;}
486
			case 'A4' : {$pf = array(  595.276,  841.890); break;}
487
			case 'A5' : {$pf = array(  419.528,  595.276); break;}
488
			case 'A6' : {$pf = array(  297.638,  419.528); break;}
489
			case 'A7' : {$pf = array(  209.764,  297.638); break;}
490
			case 'A8' : {$pf = array(  147.402,  209.764); break;}
491
			case 'A9' : {$pf = array(  104.882,  147.402); break;}
492
			case 'A10': {$pf = array(   73.701,  104.882); break;}
493
			case 'A11': {$pf = array(   51.024,   73.701); break;}
494
			case 'A12': {$pf = array(   36.850,   51.024); break;}
495
			// ISO 216 B Series + 2 SIS 014711 extensions
496
			case 'B0' : {$pf = array( 2834.646, 4008.189); break;}
497
			case 'B1' : {$pf = array( 2004.094, 2834.646); break;}
498
			case 'B2' : {$pf = array( 1417.323, 2004.094); break;}
499
			case 'B3' : {$pf = array( 1000.630, 1417.323); break;}
500
			case 'B4' : {$pf = array(  708.661, 1000.630); break;}
501
			case 'B5' : {$pf = array(  498.898,  708.661); break;}
502
			case 'B6' : {$pf = array(  354.331,  498.898); break;}
503
			case 'B7' : {$pf = array(  249.449,  354.331); break;}
504
			case 'B8' : {$pf = array(  175.748,  249.449); break;}
505
			case 'B9' : {$pf = array(  124.724,  175.748); break;}
506
			case 'B10': {$pf = array(   87.874,  124.724); break;}
507
			case 'B11': {$pf = array(   62.362,   87.874); break;}
508
			case 'B12': {$pf = array(   42.520,   62.362); break;}
509
			// ISO 216 C Series + 2 SIS 014711 extensions + 2 EXTENSION
510
			case 'C0' : {$pf = array( 2599.370, 3676.535); break;}
511
			case 'C1' : {$pf = array( 1836.850, 2599.370); break;}
512
			case 'C2' : {$pf = array( 1298.268, 1836.850); break;}
513
			case 'C3' : {$pf = array(  918.425, 1298.268); break;}
514
			case 'C4' : {$pf = array(  649.134,  918.425); break;}
515
			case 'C5' : {$pf = array(  459.213,  649.134); break;}
516
			case 'C6' : {$pf = array(  323.150,  459.213); break;}
517
			case 'C7' : {$pf = array(  229.606,  323.150); break;}
518
			case 'C8' : {$pf = array(  161.575,  229.606); break;}
519
			case 'C9' : {$pf = array(  113.386,  161.575); break;}
520
			case 'C10': {$pf = array(   79.370,  113.386); break;}
521
			case 'C11': {$pf = array(   56.693,   79.370); break;}
522
			case 'C12': {$pf = array(   39.685,   56.693); break;}
523
			case 'C76': {$pf = array(  229.606,  459.213); break;}
524
			case 'DL' : {$pf = array(  311.811,  623.622); break;}
525
			// SIS 014711 E Series
526
			case 'E0' : {$pf = array( 2491.654, 3517.795); break;}
527
			case 'E1' : {$pf = array( 1757.480, 2491.654); break;}
528
			case 'E2' : {$pf = array( 1247.244, 1757.480); break;}
529
			case 'E3' : {$pf = array(  878.740, 1247.244); break;}
530
			case 'E4' : {$pf = array(  623.622,  878.740); break;}
531
			case 'E5' : {$pf = array(  439.370,  623.622); break;}
532
			case 'E6' : {$pf = array(  311.811,  439.370); break;}
533
			case 'E7' : {$pf = array(  221.102,  311.811); break;}
534
			case 'E8' : {$pf = array(  155.906,  221.102); break;}
535
			case 'E9' : {$pf = array(  110.551,  155.906); break;}
536
			case 'E10': {$pf = array(   76.535,  110.551); break;}
537
			case 'E11': {$pf = array(   53.858,   76.535); break;}
538
			case 'E12': {$pf = array(   36.850,   53.858); break;}
539
			// SIS 014711 G Series
540
			case 'G0' : {$pf = array( 2715.591, 3838.110); break;}
541
			case 'G1' : {$pf = array( 1919.055, 2715.591); break;}
542
			case 'G2' : {$pf = array( 1357.795, 1919.055); break;}
543
			case 'G3' : {$pf = array(  958.110, 1357.795); break;}
544
			case 'G4' : {$pf = array(  677.480,  958.110); break;}
545
			case 'G5' : {$pf = array(  479.055,  677.480); break;}
546
			case 'G6' : {$pf = array(  337.323,  479.055); break;}
547
			case 'G7' : {$pf = array(  238.110,  337.323); break;}
548
			case 'G8' : {$pf = array(  167.244,  238.110); break;}
549
			case 'G9' : {$pf = array(  119.055,  167.244); break;}
550
			case 'G10': {$pf = array(   82.205,  119.055); break;}
551
			case 'G11': {$pf = array(   59.528,   82.205); break;}
552
			case 'G12': {$pf = array(   39.685,   59.528); break;}
553
			// ISO Press
554
			case 'RA0': {$pf = array( 2437.795, 3458.268); break;}
555
			case 'RA1': {$pf = array( 1729.134, 2437.795); break;}
556
			case 'RA2': {$pf = array( 1218.898, 1729.134); break;}
557
			case 'RA3': {$pf = array(  864.567, 1218.898); break;}
558
			case 'RA4': {$pf = array(  609.449,  864.567); break;}
559
			case 'SRA0': {$pf = array( 2551.181, 3628.346); break;}
560
			case 'SRA1': {$pf = array( 1814.173, 2551.181); break;}
561
			case 'SRA2': {$pf = array( 1275.591, 1814.173); break;}
562
			case 'SRA3': {$pf = array(  907.087, 1275.591); break;}
563
			case 'SRA4': {$pf = array(  637.795,  907.087); break;}
564
			// German  DIN 476
565
			case '4A0': {$pf = array( 4767.874, 6740.787); break;}
566
			case '2A0': {$pf = array( 3370.394, 4767.874); break;}
567
			// Variations on the ISO Standard
568
			case 'A2_EXTRA'   : {$pf = array( 1261.417, 1754.646); break;}
569
			case 'A3+'        : {$pf = array(  932.598, 1369.134); break;}
570
			case 'A3_EXTRA'   : {$pf = array(  912.756, 1261.417); break;}
571
			case 'A3_SUPER'   : {$pf = array(  864.567, 1440.000); break;}
572
			case 'SUPER_A3'   : {$pf = array(  864.567, 1380.472); break;}
573
			case 'A4_EXTRA'   : {$pf = array(  666.142,  912.756); break;}
574
			case 'A4_SUPER'   : {$pf = array(  649.134,  912.756); break;}
575
			case 'SUPER_A4'   : {$pf = array(  643.465, 1009.134); break;}
576
			case 'A4_LONG'    : {$pf = array(  595.276,  986.457); break;}
577
			case 'F4'         : {$pf = array(  595.276,  935.433); break;}
578
			case 'SO_B5_EXTRA': {$pf = array(  572.598,  782.362); break;}
579
			case 'A5_EXTRA'   : {$pf = array(  490.394,  666.142); break;}
580
			// ANSI Series
581
			case 'ANSI_E': {$pf = array( 2448.000, 3168.000); break;}
582
			case 'ANSI_D': {$pf = array( 1584.000, 2448.000); break;}
583
			case 'ANSI_C': {$pf = array( 1224.000, 1584.000); break;}
584
			case 'ANSI_B': {$pf = array(  792.000, 1224.000); break;}
585
			case 'ANSI_A': {$pf = array(  612.000,  792.000); break;}
586
			// Traditional 'Loose' North American Paper Sizes
587
			case 'USLEDGER':
588
			case 'LEDGER' : {$pf = array( 1224.000,  792.000); break;}
589
			case 'ORGANIZERK':
590
			case 'BIBLE':
591
			case 'USTABLOID':
592
			case 'TABLOID': {$pf = array(  792.000, 1224.000); break;}
593
			case 'ORGANIZERM':
594
			case 'USLETTER':
595
			case 'LETTER' : {$pf = array(  612.000,  792.000); break;}
596
			case 'USLEGAL':
597
			case 'LEGAL'  : {$pf = array(  612.000, 1008.000); break;}
598
			case 'GOVERNMENTLETTER':
599
			case 'GLETTER': {$pf = array(  576.000,  756.000); break;}
600
			case 'JUNIORLEGAL':
601
			case 'JLEGAL' : {$pf = array(  576.000,  360.000); break;}
602
			// Other North American Paper Sizes
603
			case 'QUADDEMY': {$pf = array( 2520.000, 3240.000); break;}
604
			case 'SUPER_B': {$pf = array(  936.000, 1368.000); break;}
605
			case 'QUARTO': {$pf = array(  648.000,  792.000); break;}
606
			case 'GOVERNMENTLEGAL':
607
			case 'FOLIO': {$pf = array(  612.000,  936.000); break;}
608
			case 'MONARCH':
609
			case 'EXECUTIVE': {$pf = array(  522.000,  756.000); break;}
610
			case 'ORGANIZERL':
611
			case 'STATEMENT':
612
			case 'MEMO': {$pf = array(  396.000,  612.000); break;}
613
			case 'FOOLSCAP': {$pf = array(  595.440,  936.000); break;}
614
			case 'COMPACT': {$pf = array(  306.000,  486.000); break;}
615
			case 'ORGANIZERJ': {$pf = array(  198.000,  360.000); break;}
616
			// Canadian standard CAN 2-9.60M
617
			case 'P1': {$pf = array( 1587.402, 2437.795); break;}
618
			case 'P2': {$pf = array( 1218.898, 1587.402); break;}
619
			case 'P3': {$pf = array(  793.701, 1218.898); break;}
620
			case 'P4': {$pf = array(  609.449,  793.701); break;}
621
			case 'P5': {$pf = array(  396.850,  609.449); break;}
622
			case 'P6': {$pf = array(  303.307,  396.850); break;}
623
			// North American Architectural Sizes
624
			case 'ARCH_E' : {$pf = array( 2592.000, 3456.000); break;}
625
			case 'ARCH_E1': {$pf = array( 2160.000, 3024.000); break;}
626
			case 'ARCH_D' : {$pf = array( 1728.000, 2592.000); break;}
627
			case 'BROADSHEET':
628
			case 'ARCH_C' : {$pf = array( 1296.000, 1728.000); break;}
629
			case 'ARCH_B' : {$pf = array(  864.000, 1296.000); break;}
630
			case 'ARCH_A' : {$pf = array(  648.000,  864.000); break;}
631
			// --- North American Envelope Sizes ---
632
			//   - Announcement Envelopes
633
			case 'ANNENV_A2'  : {$pf = array(  314.640,  414.000); break;}
634
			case 'ANNENV_A6'  : {$pf = array(  342.000,  468.000); break;}
635
			case 'ANNENV_A7'  : {$pf = array(  378.000,  522.000); break;}
636
			case 'ANNENV_A8'  : {$pf = array(  396.000,  584.640); break;}
637
			case 'ANNENV_A10' : {$pf = array(  450.000,  692.640); break;}
638
			case 'ANNENV_SLIM': {$pf = array(  278.640,  638.640); break;}
639
			//   - Commercial Envelopes
640
			case 'COMMENV_N6_1/4': {$pf = array(  252.000,  432.000); break;}
641
			case 'COMMENV_N6_3/4': {$pf = array(  260.640,  468.000); break;}
642
			case 'COMMENV_N8'    : {$pf = array(  278.640,  540.000); break;}
643
			case 'COMMENV_N9'    : {$pf = array(  278.640,  638.640); break;}
644
			case 'COMMENV_N10'   : {$pf = array(  296.640,  684.000); break;}
645
			case 'COMMENV_N11'   : {$pf = array(  324.000,  746.640); break;}
646
			case 'COMMENV_N12'   : {$pf = array(  342.000,  792.000); break;}
647
			case 'COMMENV_N14'   : {$pf = array(  360.000,  828.000); break;}
648
			//   - Catalogue Envelopes
649
			case 'CATENV_N1'     : {$pf = array(  432.000,  648.000); break;}
650
			case 'CATENV_N1_3/4' : {$pf = array(  468.000,  684.000); break;}
651
			case 'CATENV_N2'     : {$pf = array(  468.000,  720.000); break;}
652
			case 'CATENV_N3'     : {$pf = array(  504.000,  720.000); break;}
653
			case 'CATENV_N6'     : {$pf = array(  540.000,  756.000); break;}
654
			case 'CATENV_N7'     : {$pf = array(  576.000,  792.000); break;}
655
			case 'CATENV_N8'     : {$pf = array(  594.000,  810.000); break;}
656
			case 'CATENV_N9_1/2' : {$pf = array(  612.000,  756.000); break;}
657
			case 'CATENV_N9_3/4' : {$pf = array(  630.000,  810.000); break;}
658
			case 'CATENV_N10_1/2': {$pf = array(  648.000,  864.000); break;}
659
			case 'CATENV_N12_1/2': {$pf = array(  684.000,  900.000); break;}
660
			case 'CATENV_N13_1/2': {$pf = array(  720.000,  936.000); break;}
661
			case 'CATENV_N14_1/4': {$pf = array(  810.000,  882.000); break;}
662
			case 'CATENV_N14_1/2': {$pf = array(  828.000, 1044.000); break;}
663
			// Japanese (JIS P 0138-61) Standard B-Series
664
			case 'JIS_B0' : {$pf = array( 2919.685, 4127.244); break;}
665
			case 'JIS_B1' : {$pf = array( 2063.622, 2919.685); break;}
666
			case 'JIS_B2' : {$pf = array( 1459.843, 2063.622); break;}
667
			case 'JIS_B3' : {$pf = array( 1031.811, 1459.843); break;}
668
			case 'JIS_B4' : {$pf = array(  728.504, 1031.811); break;}
669
			case 'JIS_B5' : {$pf = array(  515.906,  728.504); break;}
670
			case 'JIS_B6' : {$pf = array(  362.835,  515.906); break;}
671
			case 'JIS_B7' : {$pf = array(  257.953,  362.835); break;}
672
			case 'JIS_B8' : {$pf = array(  181.417,  257.953); break;}
673
			case 'JIS_B9' : {$pf = array(  127.559,  181.417); break;}
674
			case 'JIS_B10': {$pf = array(   90.709,  127.559); break;}
675
			case 'JIS_B11': {$pf = array(   62.362,   90.709); break;}
676
			case 'JIS_B12': {$pf = array(   45.354,   62.362); break;}
677
			// PA Series
678
			case 'PA0' : {$pf = array( 2381.102, 3174.803,); break;}
679
			case 'PA1' : {$pf = array( 1587.402, 2381.102); break;}
680
			case 'PA2' : {$pf = array( 1190.551, 1587.402); break;}
681
			case 'PA3' : {$pf = array(  793.701, 1190.551); break;}
682
			case 'PA4' : {$pf = array(  595.276,  793.701); break;}
683
			case 'PA5' : {$pf = array(  396.850,  595.276); break;}
684
			case 'PA6' : {$pf = array(  297.638,  396.850); break;}
685
			case 'PA7' : {$pf = array(  198.425,  297.638); break;}
686
			case 'PA8' : {$pf = array(  147.402,  198.425); break;}
687
			case 'PA9' : {$pf = array(   99.213,  147.402); break;}
688
			case 'PA10': {$pf = array(   73.701,   99.213); break;}
689
			// Standard Photographic Print Sizes
690
			case 'PASSPORT_PHOTO': {$pf = array(   99.213,  127.559); break;}
691
			case 'E'   : {$pf = array(  233.858,  340.157); break;}
692
			case 'L':
693
			case '3R'  : {$pf = array(  252.283,  360.000); break;}
694
			case 'KG':
695
			case '4R'  : {$pf = array(  289.134,  430.866); break;}
696
			case '4D'  : {$pf = array(  340.157,  430.866); break;}
697
			case '2L':
698
			case '5R'  : {$pf = array(  360.000,  504.567); break;}
699
			case '8P':
700
			case '6R'  : {$pf = array(  430.866,  575.433); break;}
701
			case '6P':
702
			case '8R'  : {$pf = array(  575.433,  720.000); break;}
703
			case '6PW':
704
			case 'S8R' : {$pf = array(  575.433,  864.567); break;}
705
			case '4P':
706
			case '10R' : {$pf = array(  720.000,  864.567); break;}
707
			case '4PW':
708
			case 'S10R': {$pf = array(  720.000, 1080.000); break;}
709
			case '11R' : {$pf = array(  790.866, 1009.134); break;}
710
			case 'S11R': {$pf = array(  790.866, 1224.567); break;}
711
			case '12R' : {$pf = array(  864.567, 1080.000); break;}
712
			case 'S12R': {$pf = array(  864.567, 1292.598); break;}
713
			// Common Newspaper Sizes
714
			case 'NEWSPAPER_BROADSHEET': {$pf = array( 2125.984, 1700.787); break;}
715
			case 'NEWSPAPER_BERLINER'  : {$pf = array( 1332.283,  892.913); break;}
716
			case 'NEWSPAPER_TABLOID':
717
			case 'NEWSPAPER_COMPACT'   : {$pf = array( 1218.898,  793.701); break;}
718
			// Business Cards
719
			case 'CREDIT_CARD':
720
			case 'BUSINESS_CARD':
721
			case 'BUSINESS_CARD_ISO7810': {$pf = array(  153.014,  242.646); break;}
722
			case 'BUSINESS_CARD_ISO216' : {$pf = array(  147.402,  209.764); break;}
723
			case 'BUSINESS_CARD_IT':
724
			case 'BUSINESS_CARD_UK':
725
			case 'BUSINESS_CARD_FR':
726
			case 'BUSINESS_CARD_DE':
727
			case 'BUSINESS_CARD_ES'     : {$pf = array(  155.906,  240.945); break;}
728
			case 'BUSINESS_CARD_CA':
729
			case 'BUSINESS_CARD_US'     : {$pf = array(  144.567,  252.283); break;}
730
			case 'BUSINESS_CARD_JP'     : {$pf = array(  155.906,  257.953); break;}
731
			case 'BUSINESS_CARD_HK'     : {$pf = array(  153.071,  255.118); break;}
732
			case 'BUSINESS_CARD_AU':
733
			case 'BUSINESS_CARD_DK':
734
			case 'BUSINESS_CARD_SE'     : {$pf = array(  155.906,  255.118); break;}
735
			case 'BUSINESS_CARD_RU':
736
			case 'BUSINESS_CARD_CZ':
737
			case 'BUSINESS_CARD_FI':
738
			case 'BUSINESS_CARD_HU':
739
			case 'BUSINESS_CARD_IL'     : {$pf = array(  141.732,  255.118); break;}
740
			// Billboards
741
			case '4SHEET' : {$pf = array( 2880.000, 4320.000); break;}
742
			case '6SHEET' : {$pf = array( 3401.575, 5102.362); break;}
743
			case '12SHEET': {$pf = array( 8640.000, 4320.000); break;}
744
			case '16SHEET': {$pf = array( 5760.000, 8640.000); break;}
745
			case '32SHEET': {$pf = array(11520.000, 8640.000); break;}
746
			case '48SHEET': {$pf = array(17280.000, 8640.000); break;}
747
			case '64SHEET': {$pf = array(23040.000, 8640.000); break;}
748
			case '96SHEET': {$pf = array(34560.000, 8640.000); break;}
749
			// Old European Sizes
750
			//   - Old Imperial English Sizes
751
			case 'EN_EMPEROR'          : {$pf = array( 3456.000, 5184.000); break;}
752
			case 'EN_ANTIQUARIAN'      : {$pf = array( 2232.000, 3816.000); break;}
753
			case 'EN_GRAND_EAGLE'      : {$pf = array( 2070.000, 3024.000); break;}
754
			case 'EN_DOUBLE_ELEPHANT'  : {$pf = array( 1926.000, 2880.000); break;}
755
			case 'EN_ATLAS'            : {$pf = array( 1872.000, 2448.000); break;}
756
			case 'EN_COLOMBIER'        : {$pf = array( 1692.000, 2484.000); break;}
757
			case 'EN_ELEPHANT'         : {$pf = array( 1656.000, 2016.000); break;}
758
			case 'EN_DOUBLE_DEMY'      : {$pf = array( 1620.000, 2556.000); break;}
759
			case 'EN_IMPERIAL'         : {$pf = array( 1584.000, 2160.000); break;}
760
			case 'EN_PRINCESS'         : {$pf = array( 1548.000, 2016.000); break;}
761
			case 'EN_CARTRIDGE'        : {$pf = array( 1512.000, 1872.000); break;}
762
			case 'EN_DOUBLE_LARGE_POST': {$pf = array( 1512.000, 2376.000); break;}
763
			case 'EN_ROYAL'            : {$pf = array( 1440.000, 1800.000); break;}
764
			case 'EN_SHEET':
765
			case 'EN_HALF_POST'        : {$pf = array( 1404.000, 1692.000); break;}
766
			case 'EN_SUPER_ROYAL'      : {$pf = array( 1368.000, 1944.000); break;}
767
			case 'EN_DOUBLE_POST'      : {$pf = array( 1368.000, 2196.000); break;}
768
			case 'EN_MEDIUM'           : {$pf = array( 1260.000, 1656.000); break;}
769
			case 'EN_DEMY'             : {$pf = array( 1260.000, 1620.000); break;}
770
			case 'EN_LARGE_POST'       : {$pf = array( 1188.000, 1512.000); break;}
771
			case 'EN_COPY_DRAUGHT'     : {$pf = array( 1152.000, 1440.000); break;}
772
			case 'EN_POST'             : {$pf = array( 1116.000, 1386.000); break;}
773
			case 'EN_CROWN'            : {$pf = array( 1080.000, 1440.000); break;}
774
			case 'EN_PINCHED_POST'     : {$pf = array( 1062.000, 1332.000); break;}
775
			case 'EN_BRIEF'            : {$pf = array(  972.000, 1152.000); break;}
776
			case 'EN_FOOLSCAP'         : {$pf = array(  972.000, 1224.000); break;}
777
			case 'EN_SMALL_FOOLSCAP'   : {$pf = array(  954.000, 1188.000); break;}
778
			case 'EN_POTT'             : {$pf = array(  900.000, 1080.000); break;}
779
			//   - Old Imperial Belgian Sizes
780
			case 'BE_GRAND_AIGLE' : {$pf = array( 1984.252, 2948.031); break;}
781
			case 'BE_COLOMBIER'   : {$pf = array( 1757.480, 2409.449); break;}
782
			case 'BE_DOUBLE_CARRE': {$pf = array( 1757.480, 2607.874); break;}
783
			case 'BE_ELEPHANT'    : {$pf = array( 1746.142, 2182.677); break;}
784
			case 'BE_PETIT_AIGLE' : {$pf = array( 1700.787, 2381.102); break;}
785
			case 'BE_GRAND_JESUS' : {$pf = array( 1559.055, 2069.291); break;}
786
			case 'BE_JESUS'       : {$pf = array( 1530.709, 2069.291); break;}
787
			case 'BE_RAISIN'      : {$pf = array( 1417.323, 1842.520); break;}
788
			case 'BE_GRAND_MEDIAN': {$pf = array( 1303.937, 1714.961); break;}
789
			case 'BE_DOUBLE_POSTE': {$pf = array( 1233.071, 1601.575); break;}
790
			case 'BE_COQUILLE'    : {$pf = array( 1218.898, 1587.402); break;}
791
			case 'BE_PETIT_MEDIAN': {$pf = array( 1176.378, 1502.362); break;}
792
			case 'BE_RUCHE'       : {$pf = array( 1020.472, 1303.937); break;}
793
			case 'BE_PROPATRIA'   : {$pf = array(  977.953, 1218.898); break;}
794
			case 'BE_LYS'         : {$pf = array(  898.583, 1125.354); break;}
795
			case 'BE_POT'         : {$pf = array(  870.236, 1088.504); break;}
796
			case 'BE_ROSETTE'     : {$pf = array(  765.354,  983.622); break;}
797
			//   - Old Imperial French Sizes
798
			case 'FR_UNIVERS'          : {$pf = array( 2834.646, 3685.039); break;}
799
			case 'FR_DOUBLE_COLOMBIER' : {$pf = array( 2551.181, 3571.654); break;}
800
			case 'FR_GRANDE_MONDE'     : {$pf = array( 2551.181, 3571.654); break;}
801
			case 'FR_DOUBLE_SOLEIL'    : {$pf = array( 2267.717, 3401.575); break;}
802
			case 'FR_DOUBLE_JESUS'     : {$pf = array( 2154.331, 3174.803); break;}
803
			case 'FR_GRAND_AIGLE'      : {$pf = array( 2125.984, 3004.724); break;}
804
			case 'FR_PETIT_AIGLE'      : {$pf = array( 1984.252, 2664.567); break;}
805
			case 'FR_DOUBLE_RAISIN'    : {$pf = array( 1842.520, 2834.646); break;}
806
			case 'FR_JOURNAL'          : {$pf = array( 1842.520, 2664.567); break;}
807
			case 'FR_COLOMBIER_AFFICHE': {$pf = array( 1785.827, 2551.181); break;}
808
			case 'FR_DOUBLE_CAVALIER'  : {$pf = array( 1757.480, 2607.874); break;}
809
			case 'FR_CLOCHE'           : {$pf = array( 1700.787, 2267.717); break;}
810
			case 'FR_SOLEIL'           : {$pf = array( 1700.787, 2267.717); break;}
811
			case 'FR_DOUBLE_CARRE'     : {$pf = array( 1587.402, 2551.181); break;}
812
			case 'FR_DOUBLE_COQUILLE'  : {$pf = array( 1587.402, 2494.488); break;}
813
			case 'FR_JESUS'            : {$pf = array( 1587.402, 2154.331); break;}
814
			case 'FR_RAISIN'           : {$pf = array( 1417.323, 1842.520); break;}
815
			case 'FR_CAVALIER'         : {$pf = array( 1303.937, 1757.480); break;}
816
			case 'FR_DOUBLE_COURONNE'  : {$pf = array( 1303.937, 2040.945); break;}
817
			case 'FR_CARRE'            : {$pf = array( 1275.591, 1587.402); break;}
818
			case 'FR_COQUILLE'         : {$pf = array( 1247.244, 1587.402); break;}
819
			case 'FR_DOUBLE_TELLIERE'  : {$pf = array( 1247.244, 1927.559); break;}
820
			case 'FR_DOUBLE_CLOCHE'    : {$pf = array( 1133.858, 1700.787); break;}
821
			case 'FR_DOUBLE_POT'       : {$pf = array( 1133.858, 1757.480); break;}
822
			case 'FR_ECU'              : {$pf = array( 1133.858, 1474.016); break;}
823
			case 'FR_COURONNE'         : {$pf = array( 1020.472, 1303.937); break;}
824
			case 'FR_TELLIERE'         : {$pf = array(  963.780, 1247.244); break;}
825
			case 'FR_POT'              : {$pf = array(  878.740, 1133.858); break;}
826
			// DEFAULT ISO A4
827
			default: {$pf = array(  595.276,  841.890); break;}
828
		}
829
		return $pf;
830
	}
831
 
832
	/**
833
	 * Set page boundaries.
834
	 * @param $page (int) page number
835
	 * @param $type (string) valid values are: <ul><li>'MediaBox' : the boundaries of the physical medium on which the page shall be displayed or printed;</li><li>'CropBox' : the visible region of default user space;</li><li>'BleedBox' : the region to which the contents of the page shall be clipped when output in a production environment;</li><li>'TrimBox' : the intended dimensions of the finished page after trimming;</li><li>'ArtBox' : the page's meaningful content (including potential white space).</li></ul>
836
	 * @param $llx (float) lower-left x coordinate in user units.
837
	 * @param $lly (float) lower-left y coordinate in user units.
838
	 * @param $urx (float) upper-right x coordinate in user units.
839
	 * @param $ury (float) upper-right y coordinate in user units.
840
	 * @param $points (boolean) If true uses user units as unit of measure, otherwise uses PDF points.
841
	 * @param $k (float) Scale factor (number of points in user unit).
842
	 * @param $pagedim (array) Array of page dimensions.
843
	 * @return pagedim array of page dimensions.
844
	 * @since 5.0.010 (2010-05-17)
845
	 * @public static
846
	 */
847
	public static function setPageBoxes($page, $type, $llx, $lly, $urx, $ury, $points=false, $k, $pagedim=array()) {
848
		if (!isset($pagedim[$page])) {
849
			// initialize array
850
			$pagedim[$page] = array();
851
		}
852
		if (!in_array($type, self::$pageboxes)) {
853
			return;
854
		}
855
		if ($points) {
856
			$k = 1;
857
		}
858
		$pagedim[$page][$type]['llx'] = ($llx * $k);
859
		$pagedim[$page][$type]['lly'] = ($lly * $k);
860
		$pagedim[$page][$type]['urx'] = ($urx * $k);
861
		$pagedim[$page][$type]['ury'] = ($ury * $k);
862
		return $pagedim;
863
	}
864
 
865
	/**
866
	 * Swap X and Y coordinates of page boxes (change page boxes orientation).
867
	 * @param $page (int) page number
868
	 * @param $pagedim (array) Array of page dimensions.
869
	 * @return pagedim array of page dimensions.
870
	 * @since 5.0.010 (2010-05-17)
871
	 * @public static
872
	 */
873
	public static function swapPageBoxCoordinates($page, $pagedim) {
874
		foreach (self::$pageboxes as $type) {
875
			// swap X and Y coordinates
876
			if (isset($pagedim[$page][$type])) {
877
				$tmp = $pagedim[$page][$type]['llx'];
878
				$pagedim[$page][$type]['llx'] = $pagedim[$page][$type]['lly'];
879
				$pagedim[$page][$type]['lly'] = $tmp;
880
				$tmp = $pagedim[$page][$type]['urx'];
881
				$pagedim[$page][$type]['urx'] = $pagedim[$page][$type]['ury'];
882
				$pagedim[$page][$type]['ury'] = $tmp;
883
			}
884
		}
885
		return $pagedim;
886
	}
887
 
888
	/**
889
	 * Get the canonical page layout mode.
890
	 * @param $layout (string) The page layout. Possible values are:<ul><li>SinglePage Display one page at a time</li><li>OneColumn Display the pages in one column</li><li>TwoColumnLeft Display the pages in two columns, with odd-numbered pages on the left</li><li>TwoColumnRight Display the pages in two columns, with odd-numbered pages on the right</li><li>TwoPageLeft (PDF 1.5) Display the pages two at a time, with odd-numbered pages on the left</li><li>TwoPageRight (PDF 1.5) Display the pages two at a time, with odd-numbered pages on the right</li></ul>
891
	 * @return (string) Canonical page layout name.
892
	 * @public static
893
	 */
894
	public static function getPageLayoutMode($layout='SinglePage') {
895
		switch ($layout) {
896
			case 'default':
897
			case 'single':
898
			case 'SinglePage': {
899
				$layout_mode = 'SinglePage';
900
				break;
901
			}
902
			case 'continuous':
903
			case 'OneColumn': {
904
				$layout_mode = 'OneColumn';
905
				break;
906
			}
907
			case 'two':
908
			case 'TwoColumnLeft': {
909
				$layout_mode = 'TwoColumnLeft';
910
				break;
911
			}
912
			case 'TwoColumnRight': {
913
				$layout_mode = 'TwoColumnRight';
914
				break;
915
			}
916
			case 'TwoPageLeft': {
917
				$layout_mode = 'TwoPageLeft';
918
				break;
919
			}
920
			case 'TwoPageRight': {
921
				$layout_mode = 'TwoPageRight';
922
				break;
923
			}
924
			default: {
925
				$layout_mode = 'SinglePage';
926
			}
927
		}
928
		return $layout_mode;
929
	}
930
 
931
	/**
932
	 * Get the canonical page layout mode.
933
	 * @param $mode (string) A name object specifying how the document should be displayed when opened:<ul><li>UseNone Neither document outline nor thumbnail images visible</li><li>UseOutlines Document outline visible</li><li>UseThumbs Thumbnail images visible</li><li>FullScreen Full-screen mode, with no menu bar, window controls, or any other window visible</li><li>UseOC (PDF 1.5) Optional content group panel visible</li><li>UseAttachments (PDF 1.6) Attachments panel visible</li></ul>
934
	 * @return (string) Canonical page mode name.
935
	 * @public static
936
	 */
937
	public static function getPageMode($mode='UseNone') {
938
		switch ($mode) {
939
			case 'UseNone': {
940
				$page_mode = 'UseNone';
941
				break;
942
			}
943
			case 'UseOutlines': {
944
				$page_mode = 'UseOutlines';
945
				break;
946
			}
947
			case 'UseThumbs': {
948
				$page_mode = 'UseThumbs';
949
				break;
950
			}
951
			case 'FullScreen': {
952
				$page_mode = 'FullScreen';
953
				break;
954
			}
955
			case 'UseOC': {
956
				$page_mode = 'UseOC';
957
				break;
958
			}
959
			case '': {
960
				$page_mode = 'UseAttachments';
961
				break;
962
			}
963
			default: {
964
				$page_mode = 'UseNone';
965
			}
966
		}
967
		return $page_mode;
968
	}
969
 
970
	/**
971
	 * Check if the URL exist.
972
	 * @param $url (string) URL to check.
973
	 * @return Boolean true if the URl exist, false otherwise.
974
	 * @since 5.9.204 (2013-01-28)
975
	 * @public static
976
	 */
977
	public static function isValidURL($url) {
978
		$headers = @get_headers($url);
979
    	return (strpos($headers[0], '200') !== false);
980
	}
981
 
982
	/**
983
	 * Removes SHY characters from text.
984
	 * Unicode Data:<ul>
985
	 * <li>Name : SOFT HYPHEN, commonly abbreviated as SHY</li>
986
	 * <li>HTML Entity (decimal): "&amp;#173;"</li>
987
	 * <li>HTML Entity (hex): "&amp;#xad;"</li>
988
	 * <li>HTML Entity (named): "&amp;shy;"</li>
989
	 * <li>How to type in Microsoft Windows: [Alt +00AD] or [Alt 0173]</li>
990
	 * <li>UTF-8 (hex): 0xC2 0xAD (c2ad)</li>
991
	 * <li>UTF-8 character: chr(194).chr(173)</li>
992
	 * </ul>
993
	 * @param $txt (string) input string
994
	 * @param $unicode (boolean) True if we are in unicode mode, false otherwise.
995
	 * @return string without SHY characters.
996
	 * @since (4.5.019) 2009-02-28
997
	 * @public static
998
	 */
999
	public static function removeSHY($txt='', $unicode=true) {
1000
		$txt = preg_replace('/([\\xc2]{1}[\\xad]{1})/', '', $txt);
1001
		if (!$unicode) {
1002
			$txt = preg_replace('/([\\xad]{1})/', '', $txt);
1003
		}
1004
		return $txt;
1005
	}
1006
 
1007
 
1008
	/**
1009
	 * Get the border mode accounting for multicell position (opens bottom side of multicell crossing pages)
1010
	 * @param $brd (mixed) Indicates if borders must be drawn around the cell block. The value can be a number:<ul><li>0: no border (default)</li><li>1: frame</li></ul>or a string containing some or all of the following characters (in any order):<ul><li>L: left</li><li>T: top</li><li>R: right</li><li>B: bottom</li></ul> or an array of line styles for each border group: array('LTRB' => array('width' => 2, 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => array(0, 0, 0)))
1011
	 * @param $position (string) multicell position: 'start', 'middle', 'end'
1012
	 * @param $opencell (boolean) True when the cell is left open at the page bottom, false otherwise.
1013
	 * @return border mode array
1014
	 * @since 4.4.002 (2008-12-09)
1015
	 * @public static
1016
	 */
1017
	public static function getBorderMode($brd, $position='start', $opencell=true) {
1018
		if ((!$opencell) OR empty($brd)) {
1019
			return $brd;
1020
		}
1021
		if ($brd == 1) {
1022
			$brd = 'LTRB';
1023
		}
1024
		if (is_string($brd)) {
1025
			// convert string to array
1026
			$slen = strlen($brd);
1027
			$newbrd = array();
1028
			for ($i = 0; $i < $slen; ++$i) {
1029
				$newbrd[$brd[$i]] = array('cap' => 'square', 'join' => 'miter');
1030
			}
1031
			$brd = $newbrd;
1032
		}
1033
		foreach ($brd as $border => $style) {
1034
			switch ($position) {
1035
				case 'start': {
1036
					if (strpos($border, 'B') !== false) {
1037
						// remove bottom line
1038
						$newkey = str_replace('B', '', $border);
1039
						if (strlen($newkey) > 0) {
1040
							$brd[$newkey] = $style;
1041
						}
1042
						unset($brd[$border]);
1043
					}
1044
					break;
1045
				}
1046
				case 'middle': {
1047
					if (strpos($border, 'B') !== false) {
1048
						// remove bottom line
1049
						$newkey = str_replace('B', '', $border);
1050
						if (strlen($newkey) > 0) {
1051
							$brd[$newkey] = $style;
1052
						}
1053
						unset($brd[$border]);
1054
						$border = $newkey;
1055
					}
1056
					if (strpos($border, 'T') !== false) {
1057
						// remove bottom line
1058
						$newkey = str_replace('T', '', $border);
1059
						if (strlen($newkey) > 0) {
1060
							$brd[$newkey] = $style;
1061
						}
1062
						unset($brd[$border]);
1063
					}
1064
					break;
1065
				}
1066
				case 'end': {
1067
					if (strpos($border, 'T') !== false) {
1068
						// remove bottom line
1069
						$newkey = str_replace('T', '', $border);
1070
						if (strlen($newkey) > 0) {
1071
							$brd[$newkey] = $style;
1072
						}
1073
						unset($brd[$border]);
1074
					}
1075
					break;
1076
				}
1077
			}
1078
		}
1079
		return $brd;
1080
	}
1081
 
1082
	/**
1083
	 * Determine whether a string is empty.
1084
	 * @param $str (string) string to be checked
1085
	 * @return boolean true if string is empty
1086
	 * @since 4.5.044 (2009-04-16)
1087
	 * @public static
1088
	 */
1089
	public static function empty_string($str) {
1090
		return (is_null($str) OR (is_string($str) AND (strlen($str) == 0)));
1091
	}
1092
 
1093
	/**
1094
	 * Returns a temporary filename for caching object on filesystem.
1095
	 * @param $name (string) Prefix to add to the file name.
1096
	 * @return string filename.
1097
	 * @since 4.5.000 (2008-12-31)
1098
	 * @public static
1099
	 */
1100
	public static function getObjFilename($name) {
1101
		return tempnam(K_PATH_CACHE, $name.'_');
1102
	}
1103
 
1104
	/**
1105
	 * Add "\" before "\", "(" and ")"
1106
	 * @param $s (string) string to escape.
1107
	 * @return string escaped string.
1108
	 * @public static
1109
	 */
1110
	public static function _escape($s) {
1111
		// the chr(13) substitution fixes the Bugs item #1421290.
1112
		return strtr($s, array(')' => '\\)', '(' => '\\(', '\\' => '\\\\', chr(13) => '\r'));
1113
	}
1114
 
1115
	/**
1116
	* Escape some special characters (&lt; &gt; &amp;) for XML output.
1117
	* @param $str (string) Input string to convert.
1118
	* @return converted string
1119
	* @since 5.9.121 (2011-09-28)
1120
	 * @public static
1121
	 */
1122
	public static function _escapeXML($str) {
1123
		$replaceTable = array("\0" => '', '&' => '&amp;', '<' => '&lt;', '>' => '&gt;');
1124
		$str = strtr($str, $replaceTable);
1125
		return $str;
1126
	}
1127
 
1128
	/**
1129
	 * Creates a copy of a class object
1130
	 * @param $object (object) class object to be cloned
1131
	 * @return cloned object
1132
	 * @since 4.5.029 (2009-03-19)
1133
	 * @public static
1134
	 */
1135
	public static function objclone($object) {
1136
		if (($object instanceof Imagick) AND (version_compare(phpversion('imagick'), '3.0.1') !== 1)) {
1137
			// on the versions after 3.0.1 the clone() method was deprecated in favour of clone keyword
1138
			return @$object->clone();
1139
		}
1140
		return @clone($object);
1141
	}
1142
 
1143
	/**
1144
	 * Ouput input data and compress it if possible.
1145
	 * @param $data (string) Data to output.
1146
	 * @param $length (int) Data length in bytes.
1147
	 * @since 5.9.086
1148
	 * @public static
1149
	 */
1150
	public static function sendOutputData($data, $length) {
1151
		if (!isset($_SERVER['HTTP_ACCEPT_ENCODING']) OR empty($_SERVER['HTTP_ACCEPT_ENCODING'])) {
1152
			// the content length may vary if the server is using compression
1153
			header('Content-Length: '.$length);
1154
		}
1155
		echo $data;
1156
	}
1157
 
1158
	/**
1159
	 * Replace page number aliases with number.
1160
	 * @param $page (string) Page content.
1161
	 * @param $replace (array) Array of replacements (array keys are replacement strings, values are alias arrays).
1162
	 * @param $diff (int) If passed, this will be set to the total char number difference between alias and replacements.
1163
	 * @return replaced page content and updated $diff parameter as array.
1164
	 * @public static
1165
	 */
1166
	public static function replacePageNumAliases($page, $replace, $diff=0) {
1167
		foreach ($replace as $rep) {
1168
			foreach ($rep[3] as $a) {
1169
				if (strpos($page, $a) !== false) {
1170
					$page = str_replace($a, $rep[0], $page);
1171
					$diff += ($rep[2] - $rep[1]);
1172
				}
1173
			}
1174
		}
1175
		return array($page, $diff);
1176
	}
1177
 
1178
	/**
1179
	 * Returns timestamp in seconds from formatted date-time.
1180
	 * @param $date (string) Formatted date-time.
1181
	 * @return int seconds.
1182
	 * @since 5.9.152 (2012-03-23)
1183
	 * @public static
1184
	 */
1185
	public static function getTimestamp($date) {
1186
		if (($date[0] == 'D') AND ($date[1] == ':')) {
1187
			// remove date prefix if present
1188
			$date = substr($date, 2);
1189
		}
1190
		return strtotime($date);
1191
	}
1192
 
1193
	/**
1194
	 * Returns a formatted date-time.
1195
	 * @param $time (int) Time in seconds.
1196
	 * @return string escaped date string.
1197
	 * @since 5.9.152 (2012-03-23)
1198
	 * @public static
1199
	 */
1200
	public static function getFormattedDate($time) {
1201
		return substr_replace(date('YmdHisO', intval($time)), '\'', (0 - 2), 0).'\'';
1202
	}
1203
 
1204
	/**
1205
	 * Get ULONG from string (Big Endian 32-bit unsigned integer).
1206
	 * @param $str (string) string from where to extract value
1207
	 * @param $offset (int) point from where to read the data
1208
	 * @return int 32 bit value
1209
	 * @author Nicola Asuni
1210
	 * @since 5.2.000 (2010-06-02)
1211
	 * @public static
1212
	 */
1213
	public static function _getULONG($str, $offset) {
1214
		$v = unpack('Ni', substr($str, $offset, 4));
1215
		return $v['i'];
1216
	}
1217
 
1218
	/**
1219
	 * Get USHORT from string (Big Endian 16-bit unsigned integer).
1220
	 * @param $str (string) string from where to extract value
1221
	 * @param $offset (int) point from where to read the data
1222
	 * @return int 16 bit value
1223
	 * @author Nicola Asuni
1224
	 * @since 5.2.000 (2010-06-02)
1225
	 * @public static
1226
	 */
1227
	public static function _getUSHORT($str, $offset) {
1228
		$v = unpack('ni', substr($str, $offset, 2));
1229
		return $v['i'];
1230
	}
1231
 
1232
	/**
1233
	 * Get SHORT from string (Big Endian 16-bit signed integer).
1234
	 * @param $str (string) String from where to extract value.
1235
	 * @param $offset (int) Point from where to read the data.
1236
	 * @return int 16 bit value
1237
	 * @author Nicola Asuni
1238
	 * @since 5.2.000 (2010-06-02)
1239
	 * @public static
1240
	 */
1241
	public static function _getSHORT($str, $offset) {
1242
		$v = unpack('si', substr($str, $offset, 2));
1243
		return $v['i'];
1244
	}
1245
 
1246
	/**
1247
	 * Get FWORD from string (Big Endian 16-bit signed integer).
1248
	 * @param $str (string) String from where to extract value.
1249
	 * @param $offset (int) Point from where to read the data.
1250
	 * @return int 16 bit value
1251
	 * @author Nicola Asuni
1252
	 * @since 5.9.123 (2011-09-30)
1253
	 * @public static
1254
	 */
1255
	public static function _getFWORD($str, $offset) {
1256
		$v = self::_getUSHORT($str, $offset);
1257
		if ($v > 0x7fff) {
1258
			$v -= 0x10000;
1259
		}
1260
		return $v;
1261
	}
1262
 
1263
	/**
1264
	 * Get UFWORD from string (Big Endian 16-bit unsigned integer).
1265
	 * @param $str (string) string from where to extract value
1266
	 * @param $offset (int) point from where to read the data
1267
	 * @return int 16 bit value
1268
	 * @author Nicola Asuni
1269
	 * @since 5.9.123 (2011-09-30)
1270
	 * @public static
1271
	 */
1272
	public static function _getUFWORD($str, $offset) {
1273
		$v = self::_getUSHORT($str, $offset);
1274
		return $v;
1275
	}
1276
 
1277
	/**
1278
	 * Get FIXED from string (32-bit signed fixed-point number (16.16).
1279
	 * @param $str (string) string from where to extract value
1280
	 * @param $offset (int) point from where to read the data
1281
	 * @return int 16 bit value
1282
	 * @author Nicola Asuni
1283
	 * @since 5.9.123 (2011-09-30)
1284
	 * @public static
1285
	 */
1286
	public static function _getFIXED($str, $offset) {
1287
		// mantissa
1288
		$m = self::_getFWORD($str, $offset);
1289
		// fraction
1290
		$f = self::_getUSHORT($str, ($offset + 2));
1291
		$v = floatval(''.$m.'.'.$f.'');
1292
		return $v;
1293
	}
1294
 
1295
	/**
1296
	 * Get BYTE from string (8-bit unsigned integer).
1297
	 * @param $str (string) String from where to extract value.
1298
	 * @param $offset (int) Point from where to read the data.
1299
	 * @return int 8 bit value
1300
	 * @author Nicola Asuni
1301
	 * @since 5.2.000 (2010-06-02)
1302
	 * @public static
1303
	 */
1304
	public static function _getBYTE($str, $offset) {
1305
		$v = unpack('Ci', substr($str, $offset, 1));
1306
		return $v['i'];
1307
	}
1308
	/**
1309
	 * Binary-safe and URL-safe file read.
1310
	 * Reads up to length bytes from the file pointer referenced by handle. Reading stops as soon as one of the following conditions is met: length bytes have been read; EOF (end of file) is reached.
1311
	 * @param $handle (resource)
1312
	 * @param $length (int)
1313
	 * @return Returns the read string or FALSE in case of error.
1314
	 * @author Nicola Asuni
1315
	 * @since 4.5.027 (2009-03-16)
1316
	 * @public static
1317
	 */
1318
	public static function rfread($handle, $length) {
1319
		$data = fread($handle, $length);
1320
		if ($data === false) {
1321
			return false;
1322
		}
1323
		$rest = ($length - strlen($data));
1324
		if ($rest > 0) {
1325
			$data .= self::rfread($handle, $rest);
1326
		}
1327
		return $data;
1328
	}
1329
 
1330
	/**
1331
	 * Read a 4-byte (32 bit) integer from file.
1332
	 * @param $f (string) file name.
1333
	 * @return 4-byte integer
1334
	 * @public static
1335
	 */
1336
	public static function _freadint($f) {
1337
		$a = unpack('Ni', fread($f, 4));
1338
		return $a['i'];
1339
	}
1340
 
1341
	/**
1342
	 * Returns a string containing random data to be used as a seed for encryption methods.
1343
	 * @param $seed (string) starting seed value
1344
	 * @return string containing random data
1345
	 * @author Nicola Asuni
1346
	 * @since 5.9.006 (2010-10-19)
1347
	 * @public static
1348
	 */
1349
	public static function getRandomSeed($seed='') {
1350
		$seed .= microtime();
1351
		if (function_exists('openssl_random_pseudo_bytes') AND (strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN')) {
1352
			// this is not used on windows systems because it is very slow for a know bug
1353
			$seed .= openssl_random_pseudo_bytes(512);
1354
		} else {
1355
			for ($i = 0; $i < 23; ++$i) {
1356
				$seed .= uniqid('', true);
1357
			}
1358
		}
1359
		$seed .= uniqid('', true);
1360
		$seed .= rand();
1361
		$seed .= getmypid();
1362
		$seed .= __FILE__;
1363
		if (isset($_SERVER['REMOTE_ADDR'])) {
1364
			$seed .= $_SERVER['REMOTE_ADDR'];
1365
		}
1366
		if (isset($_SERVER['HTTP_USER_AGENT'])) {
1367
			$seed .= $_SERVER['HTTP_USER_AGENT'];
1368
		}
1369
		if (isset($_SERVER['HTTP_ACCEPT'])) {
1370
			$seed .= $_SERVER['HTTP_ACCEPT'];
1371
		}
1372
		if (isset($_SERVER['HTTP_ACCEPT_ENCODING'])) {
1373
			$seed .= $_SERVER['HTTP_ACCEPT_ENCODING'];
1374
		}
1375
		if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
1376
			$seed .= $_SERVER['HTTP_ACCEPT_LANGUAGE'];
1377
		}
1378
		if (isset($_SERVER['HTTP_ACCEPT_CHARSET'])) {
1379
			$seed .= $_SERVER['HTTP_ACCEPT_CHARSET'];
1380
		}
1381
		$seed .= rand();
1382
		$seed .= uniqid('', true);
1383
		$seed .= microtime();
1384
		return $seed;
1385
	}
1386
 
1387
	/**
1388
	 * Encrypts a string using MD5 and returns it's value as a binary string.
1389
	 * @param $str (string) input string
1390
	 * @return String MD5 encrypted binary string
1391
	 * @since 2.0.000 (2008-01-02)
1392
	 * @public static
1393
	 */
1394
	public static function _md5_16($str) {
1395
		return pack('H*', md5($str));
1396
	}
1397
 
1398
	/**
1399
	 * Returns the input text exrypted using AES algorithm and the specified key.
1400
	 * This method requires mcrypt.
1401
	 * @param $key (string) encryption key
1402
	 * @param $text (String) input text to be encrypted
1403
	 * @return String encrypted text
1404
	 * @author Nicola Asuni
1405
	 * @since 5.0.005 (2010-05-11)
1406
	 * @public static
1407
	 */
1408
	public static function _AES($key, $text) {
1409
		// padding (RFC 2898, PKCS #5: Password-Based Cryptography Specification Version 2.0)
1410
		$padding = 16 - (strlen($text) % 16);
1411
		$text .= str_repeat(chr($padding), $padding);
1412
		$iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC), MCRYPT_RAND);
1413
		$text = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $text, MCRYPT_MODE_CBC, $iv);
1414
		$text = $iv.$text;
1415
		return $text;
1416
	}
1417
 
1418
	/**
1419
	 * Returns the input text encrypted using RC4 algorithm and the specified key.
1420
	 * RC4 is the standard encryption algorithm used in PDF format
1421
	 * @param $key (string) Encryption key.
1422
	 * @param $text (String) Input text to be encrypted.
1423
	 * @param $last_enc_key (String) Reference to last RC4 key encrypted.
1424
	 * @param $last_enc_key_c (String) Reference to last RC4 computed key.
1425
	 * @return String encrypted text
1426
	 * @since 2.0.000 (2008-01-02)
1427
	 * @author Klemen Vodopivec, Nicola Asuni
1428
	 * @public static
1429
	 */
1430
	public static function _RC4($key, $text, &$last_enc_key, &$last_enc_key_c) {
1431
		if (function_exists('mcrypt_decrypt') AND ($out = @mcrypt_decrypt(MCRYPT_ARCFOUR, $key, $text, MCRYPT_MODE_STREAM, ''))) {
1432
			// try to use mcrypt function if exist
1433
			return $out;
1434
		}
1435
		if ($last_enc_key != $key) {
1436
			$k = str_repeat($key, ((256 / strlen($key)) + 1));
1437
			$rc4 = range(0, 255);
1438
			$j = 0;
1439
			for ($i = 0; $i < 256; ++$i) {
1440
				$t = $rc4[$i];
1441
				$j = ($j + $t + ord($k[$i])) % 256;
1442
				$rc4[$i] = $rc4[$j];
1443
				$rc4[$j] = $t;
1444
			}
1445
			$last_enc_key = $key;
1446
			$last_enc_key_c = $rc4;
1447
		} else {
1448
			$rc4 = $last_enc_key_c;
1449
		}
1450
		$len = strlen($text);
1451
		$a = 0;
1452
		$b = 0;
1453
		$out = '';
1454
		for ($i = 0; $i < $len; ++$i) {
1455
			$a = ($a + 1) % 256;
1456
			$t = $rc4[$a];
1457
			$b = ($b + $t) % 256;
1458
			$rc4[$a] = $rc4[$b];
1459
			$rc4[$b] = $t;
1460
			$k = $rc4[($rc4[$a] + $rc4[$b]) % 256];
1461
			$out .= chr(ord($text[$i]) ^ $k);
1462
		}
1463
		return $out;
1464
	}
1465
 
1466
	/**
1467
	 * Return the premission code used on encryption (P value).
1468
	 * @param $permissions (Array) the set of permissions (specify the ones you want to block).
1469
	 * @param $mode (int) encryption strength: 0 = RC4 40 bit; 1 = RC4 128 bit; 2 = AES 128 bit; 3 = AES 256 bit.
1470
	 * @since 5.0.005 (2010-05-12)
1471
	 * @author Nicola Asuni
1472
	 * @public static
1473
	 */
1474
	public static function getUserPermissionCode($permissions, $mode=0) {
1475
		$options = array(
1476
			'owner' => 2, // bit 2 -- inverted logic: cleared by default
1477
			'print' => 4, // bit 3
1478
			'modify' => 8, // bit 4
1479
			'copy' => 16, // bit 5
1480
			'annot-forms' => 32, // bit 6
1481
			'fill-forms' => 256, // bit 9
1482
			'extract' => 512, // bit 10
1483
			'assemble' => 1024,// bit 11
1484
			'print-high' => 2048 // bit 12
1485
			);
1486
		$protection = 2147422012; // 32 bit: (01111111 11111111 00001111 00111100)
1487
		foreach ($permissions as $permission) {
1488
			if (isset($options[$permission])) {
1489
				if (($mode > 0) OR ($options[$permission] <= 32)) {
1490
					// set only valid permissions
1491
					if ($options[$permission] == 2) {
1492
						// the logic for bit 2 is inverted (cleared by default)
1493
						$protection += $options[$permission];
1494
					} else {
1495
						$protection -= $options[$permission];
1496
					}
1497
				}
1498
			}
1499
		}
1500
		return $protection;
1501
	}
1502
 
1503
	/**
1504
	 * Convert hexadecimal string to string
1505
	 * @param $bs (string) byte-string to convert
1506
	 * @return String
1507
	 * @since 5.0.005 (2010-05-12)
1508
	 * @author Nicola Asuni
1509
	 * @public static
1510
	 */
1511
	public static function convertHexStringToString($bs) {
1512
		$string = ''; // string to be returned
1513
		$bslength = strlen($bs);
1514
		if (($bslength % 2) != 0) {
1515
			// padding
1516
			$bs .= '0';
1517
			++$bslength;
1518
		}
1519
		for ($i = 0; $i < $bslength; $i += 2) {
1520
			$string .= chr(hexdec($bs[$i].$bs[($i + 1)]));
1521
		}
1522
		return $string;
1523
	}
1524
 
1525
	/**
1526
	 * Convert string to hexadecimal string (byte string)
1527
	 * @param $s (string) string to convert
1528
	 * @return byte string
1529
	 * @since 5.0.010 (2010-05-17)
1530
	 * @author Nicola Asuni
1531
	 * @public static
1532
	 */
1533
	public static function convertStringToHexString($s) {
1534
		$bs = '';
1535
		$chars = preg_split('//', $s, -1, PREG_SPLIT_NO_EMPTY);
1536
		foreach ($chars as $c) {
1537
			$bs .= sprintf('%02s', dechex(ord($c)));
1538
		}
1539
		return $bs;
1540
	}
1541
 
1542
	/**
1543
	 * Convert encryption P value to a string of bytes, low-order byte first.
1544
	 * @param $protection (string) 32bit encryption permission value (P value)
1545
	 * @return String
1546
	 * @since 5.0.005 (2010-05-12)
1547
	 * @author Nicola Asuni
1548
	 * @public static
1549
	 */
1550
	public static function getEncPermissionsString($protection) {
1551
		$binprot = sprintf('%032b', $protection);
1552
		$str = chr(bindec(substr($binprot, 24, 8)));
1553
		$str .= chr(bindec(substr($binprot, 16, 8)));
1554
		$str .= chr(bindec(substr($binprot, 8, 8)));
1555
		$str .= chr(bindec(substr($binprot, 0, 8)));
1556
		return $str;
1557
	}
1558
 
1559
	/**
1560
	 * Encode a name object.
1561
	 * @param $name (string) Name object to encode.
1562
	 * @return (string) Encoded name object.
1563
	 * @author Nicola Asuni
1564
	 * @since 5.9.097 (2011-06-23)
1565
	 * @public static
1566
	 */
1567
	public static function encodeNameObject($name) {
1568
		$escname = '';
1569
		$length = strlen($name);
1570
		for ($i = 0; $i < $length; ++$i) {
1571
			$chr = $name[$i];
1572
			if (preg_match('/[0-9a-zA-Z]/', $chr) == 1) {
1573
				$escname .= $chr;
1574
			} else {
1575
				$escname .= sprintf('#%02X', ord($chr));
1576
			}
1577
		}
1578
		return $escname;
1579
	}
1580
 
1581
	/**
1582
	 * Convert JavaScript form fields properties array to Annotation Properties array.
1583
	 * @param $prop (array) javascript field properties. Possible values are described on official Javascript for Acrobat API reference.
1584
	 * @param $spot_colors (array) Reference to spot colors array.
1585
	 * @param $rtl (boolean) True if in Right-To-Left text direction mode, false otherwise.
1586
	 * @return array of annotation properties
1587
	 * @author Nicola Asuni
1588
	 * @since 4.8.000 (2009-09-06)
1589
	 * @public static
1590
	 */
1591
	public static function getAnnotOptFromJSProp($prop, &$spot_colors, $rtl=false) {
1592
		if (isset($prop['aopt']) AND is_array($prop['aopt'])) {
1593
			// the annotation options area lready defined
1594
			return $prop['aopt'];
1595
		}
1596
		$opt = array(); // value to be returned
1597
		// alignment: Controls how the text is laid out within the text field.
1598
		if (isset($prop['alignment'])) {
1599
			switch ($prop['alignment']) {
1600
				case 'left': {
1601
					$opt['q'] = 0;
1602
					break;
1603
				}
1604
				case 'center': {
1605
					$opt['q'] = 1;
1606
					break;
1607
				}
1608
				case 'right': {
1609
					$opt['q'] = 2;
1610
					break;
1611
				}
1612
				default: {
1613
					$opt['q'] = ($rtl)?2:0;
1614
					break;
1615
				}
1616
			}
1617
		}
1618
		// lineWidth: Specifies the thickness of the border when stroking the perimeter of a field's rectangle.
1619
		if (isset($prop['lineWidth'])) {
1620
			$linewidth = intval($prop['lineWidth']);
1621
		} else {
1622
			$linewidth = 1;
1623
		}
1624
		// borderStyle: The border style for a field.
1625
		if (isset($prop['borderStyle'])) {
1626
			switch ($prop['borderStyle']) {
1627
				case 'border.d':
1628
				case 'dashed': {
1629
					$opt['border'] = array(0, 0, $linewidth, array(3, 2));
1630
					$opt['bs'] = array('w'=>$linewidth, 's'=>'D', 'd'=>array(3, 2));
1631
					break;
1632
				}
1633
				case 'border.b':
1634
				case 'beveled': {
1635
					$opt['border'] = array(0, 0, $linewidth);
1636
					$opt['bs'] = array('w'=>$linewidth, 's'=>'B');
1637
					break;
1638
				}
1639
				case 'border.i':
1640
				case 'inset': {
1641
					$opt['border'] = array(0, 0, $linewidth);
1642
					$opt['bs'] = array('w'=>$linewidth, 's'=>'I');
1643
					break;
1644
				}
1645
				case 'border.u':
1646
				case 'underline': {
1647
					$opt['border'] = array(0, 0, $linewidth);
1648
					$opt['bs'] = array('w'=>$linewidth, 's'=>'U');
1649
					break;
1650
				}
1651
				case 'border.s':
1652
				case 'solid': {
1653
					$opt['border'] = array(0, 0, $linewidth);
1654
					$opt['bs'] = array('w'=>$linewidth, 's'=>'S');
1655
					break;
1656
				}
1657
				default: {
1658
					break;
1659
				}
1660
			}
1661
		}
1662
		if (isset($prop['border']) AND is_array($prop['border'])) {
1663
			$opt['border'] = $prop['border'];
1664
		}
1665
		if (!isset($opt['mk'])) {
1666
			$opt['mk'] = array();
1667
		}
1668
		if (!isset($opt['mk']['if'])) {
1669
			$opt['mk']['if'] = array();
1670
		}
1671
		$opt['mk']['if']['a'] = array(0.5, 0.5);
1672
		// buttonAlignX: Controls how space is distributed from the left of the button face with respect to the icon.
1673
		if (isset($prop['buttonAlignX'])) {
1674
			$opt['mk']['if']['a'][0] = $prop['buttonAlignX'];
1675
		}
1676
		// buttonAlignY: Controls how unused space is distributed from the bottom of the button face with respect to the icon.
1677
		if (isset($prop['buttonAlignY'])) {
1678
			$opt['mk']['if']['a'][1] = $prop['buttonAlignY'];
1679
		}
1680
		// buttonFitBounds: If true, the extent to which the icon may be scaled is set to the bounds of the button field.
1681
		if (isset($prop['buttonFitBounds']) AND ($prop['buttonFitBounds'] == 'true')) {
1682
			$opt['mk']['if']['fb'] = true;
1683
		}
1684
		// buttonScaleHow: Controls how the icon is scaled (if necessary) to fit inside the button face.
1685
		if (isset($prop['buttonScaleHow'])) {
1686
			switch ($prop['buttonScaleHow']) {
1687
				case 'scaleHow.proportional': {
1688
					$opt['mk']['if']['s'] = 'P';
1689
					break;
1690
				}
1691
				case 'scaleHow.anamorphic': {
1692
					$opt['mk']['if']['s'] = 'A';
1693
					break;
1694
				}
1695
			}
1696
		}
1697
		// buttonScaleWhen: Controls when an icon is scaled to fit inside the button face.
1698
		if (isset($prop['buttonScaleWhen'])) {
1699
			switch ($prop['buttonScaleWhen']) {
1700
				case 'scaleWhen.always': {
1701
					$opt['mk']['if']['sw'] = 'A';
1702
					break;
1703
				}
1704
				case 'scaleWhen.never': {
1705
					$opt['mk']['if']['sw'] = 'N';
1706
					break;
1707
				}
1708
				case 'scaleWhen.tooBig': {
1709
					$opt['mk']['if']['sw'] = 'B';
1710
					break;
1711
				}
1712
				case 'scaleWhen.tooSmall': {
1713
					$opt['mk']['if']['sw'] = 'S';
1714
					break;
1715
				}
1716
			}
1717
		}
1718
		// buttonPosition: Controls how the text and the icon of the button are positioned with respect to each other within the button face.
1719
		if (isset($prop['buttonPosition'])) {
1720
			switch ($prop['buttonPosition']) {
1721
				case 0:
1722
				case 'position.textOnly': {
1723
					$opt['mk']['tp'] = 0;
1724
					break;
1725
				}
1726
				case 1:
1727
				case 'position.iconOnly': {
1728
					$opt['mk']['tp'] = 1;
1729
					break;
1730
				}
1731
				case 2:
1732
				case 'position.iconTextV': {
1733
					$opt['mk']['tp'] = 2;
1734
					break;
1735
				}
1736
				case 3:
1737
				case 'position.textIconV': {
1738
					$opt['mk']['tp'] = 3;
1739
					break;
1740
				}
1741
				case 4:
1742
				case 'position.iconTextH': {
1743
					$opt['mk']['tp'] = 4;
1744
					break;
1745
				}
1746
				case 5:
1747
				case 'position.textIconH': {
1748
					$opt['mk']['tp'] = 5;
1749
					break;
1750
				}
1751
				case 6:
1752
				case 'position.overlay': {
1753
					$opt['mk']['tp'] = 6;
1754
					break;
1755
				}
1756
			}
1757
		}
1758
		// fillColor: Specifies the background color for a field.
1759
		if (isset($prop['fillColor'])) {
1760
			if (is_array($prop['fillColor'])) {
1761
				$opt['mk']['bg'] = $prop['fillColor'];
1762
			} else {
1763
				$opt['mk']['bg'] = TCPDF_COLORS::convertHTMLColorToDec($prop['fillColor'], $spot_colors);
1764
			}
1765
		}
1766
		// strokeColor: Specifies the stroke color for a field that is used to stroke the rectangle of the field with a line as large as the line width.
1767
		if (isset($prop['strokeColor'])) {
1768
			if (is_array($prop['strokeColor'])) {
1769
				$opt['mk']['bc'] = $prop['strokeColor'];
1770
			} else {
1771
				$opt['mk']['bc'] = TCPDF_COLORS::convertHTMLColorToDec($prop['strokeColor'], $spot_colors);
1772
			}
1773
		}
1774
		// rotation: The rotation of a widget in counterclockwise increments.
1775
		if (isset($prop['rotation'])) {
1776
			$opt['mk']['r'] = $prop['rotation'];
1777
		}
1778
		// charLimit: Limits the number of characters that a user can type into a text field.
1779
		if (isset($prop['charLimit'])) {
1780
			$opt['maxlen'] = intval($prop['charLimit']);
1781
		}
1782
		if (!isset($ff)) {
1783
			$ff = 0; // default value
1784
		}
1785
		// readonly: The read-only characteristic of a field. If a field is read-only, the user can see the field but cannot change it.
1786
		if (isset($prop['readonly']) AND ($prop['readonly'] == 'true')) {
1787
			$ff += 1 << 0;
1788
		}
1789
		// required: Specifies whether a field requires a value.
1790
		if (isset($prop['required']) AND ($prop['required'] == 'true')) {
1791
			$ff += 1 << 1;
1792
		}
1793
		// multiline: Controls how text is wrapped within the field.
1794
		if (isset($prop['multiline']) AND ($prop['multiline'] == 'true')) {
1795
			$ff += 1 << 12;
1796
		}
1797
		// password: Specifies whether the field should display asterisks when data is entered in the field.
1798
		if (isset($prop['password']) AND ($prop['password'] == 'true')) {
1799
			$ff += 1 << 13;
1800
		}
1801
		// NoToggleToOff: If set, exactly one radio button shall be selected at all times; selecting the currently selected button has no effect.
1802
		if (isset($prop['NoToggleToOff']) AND ($prop['NoToggleToOff'] == 'true')) {
1803
			$ff += 1 << 14;
1804
		}
1805
		// Radio: If set, the field is a set of radio buttons.
1806
		if (isset($prop['Radio']) AND ($prop['Radio'] == 'true')) {
1807
			$ff += 1 << 15;
1808
		}
1809
		// Pushbutton: If set, the field is a pushbutton that does not retain a permanent value.
1810
		if (isset($prop['Pushbutton']) AND ($prop['Pushbutton'] == 'true')) {
1811
			$ff += 1 << 16;
1812
		}
1813
		// Combo: If set, the field is a combo box; if clear, the field is a list box.
1814
		if (isset($prop['Combo']) AND ($prop['Combo'] == 'true')) {
1815
			$ff += 1 << 17;
1816
		}
1817
		// editable: Controls whether a combo box is editable.
1818
		if (isset($prop['editable']) AND ($prop['editable'] == 'true')) {
1819
			$ff += 1 << 18;
1820
		}
1821
		// Sort: If set, the field's option items shall be sorted alphabetically.
1822
		if (isset($prop['Sort']) AND ($prop['Sort'] == 'true')) {
1823
			$ff += 1 << 19;
1824
		}
1825
		// fileSelect: If true, sets the file-select flag in the Options tab of the text field (Field is Used for File Selection).
1826
		if (isset($prop['fileSelect']) AND ($prop['fileSelect'] == 'true')) {
1827
			$ff += 1 << 20;
1828
		}
1829
		// multipleSelection: If true, indicates that a list box allows a multiple selection of items.
1830
		if (isset($prop['multipleSelection']) AND ($prop['multipleSelection'] == 'true')) {
1831
			$ff += 1 << 21;
1832
		}
1833
		// doNotSpellCheck: If true, spell checking is not performed on this editable text field.
1834
		if (isset($prop['doNotSpellCheck']) AND ($prop['doNotSpellCheck'] == 'true')) {
1835
			$ff += 1 << 22;
1836
		}
1837
		// doNotScroll: If true, the text field does not scroll and the user, therefore, is limited by the rectangular region designed for the field.
1838
		if (isset($prop['doNotScroll']) AND ($prop['doNotScroll'] == 'true')) {
1839
			$ff += 1 << 23;
1840
		}
1841
		// comb: If set to true, the field background is drawn as series of boxes (one for each character in the value of the field) and each character of the content is drawn within those boxes. The number of boxes drawn is determined from the charLimit property. It applies only to text fields. The setter will also raise if any of the following field properties are also set multiline, password, and fileSelect. A side-effect of setting this property is that the doNotScroll property is also set.
1842
		if (isset($prop['comb']) AND ($prop['comb'] == 'true')) {
1843
			$ff += 1 << 24;
1844
		}
1845
		// radiosInUnison: If false, even if a group of radio buttons have the same name and export value, they behave in a mutually exclusive fashion, like HTML radio buttons.
1846
		if (isset($prop['radiosInUnison']) AND ($prop['radiosInUnison'] == 'true')) {
1847
			$ff += 1 << 25;
1848
		}
1849
		// richText: If true, the field allows rich text formatting.
1850
		if (isset($prop['richText']) AND ($prop['richText'] == 'true')) {
1851
			$ff += 1 << 25;
1852
		}
1853
		// commitOnSelChange: Controls whether a field value is committed after a selection change.
1854
		if (isset($prop['commitOnSelChange']) AND ($prop['commitOnSelChange'] == 'true')) {
1855
			$ff += 1 << 26;
1856
		}
1857
		$opt['ff'] = $ff;
1858
		// defaultValue: The default value of a field - that is, the value that the field is set to when the form is reset.
1859
		if (isset($prop['defaultValue'])) {
1860
			$opt['dv'] = $prop['defaultValue'];
1861
		}
1862
		$f = 4; // default value for annotation flags
1863
		// readonly: The read-only characteristic of a field. If a field is read-only, the user can see the field but cannot change it.
1864
		if (isset($prop['readonly']) AND ($prop['readonly'] == 'true')) {
1865
			$f += 1 << 6;
1866
		}
1867
		// display: Controls whether the field is hidden or visible on screen and in print.
1868
		if (isset($prop['display'])) {
1869
			if ($prop['display'] == 'display.visible') {
1870
				//
1871
			} elseif ($prop['display'] == 'display.hidden') {
1872
				$f += 1 << 1;
1873
			} elseif ($prop['display'] == 'display.noPrint') {
1874
				$f -= 1 << 2;
1875
			} elseif ($prop['display'] == 'display.noView') {
1876
				$f += 1 << 5;
1877
			}
1878
		}
1879
		$opt['f'] = $f;
1880
		// currentValueIndices: Reads and writes single or multiple values of a list box or combo box.
1881
		if (isset($prop['currentValueIndices']) AND is_array($prop['currentValueIndices'])) {
1882
			$opt['i'] = $prop['currentValueIndices'];
1883
		}
1884
		// value: The value of the field data that the user has entered.
1885
		if (isset($prop['value'])) {
1886
			if (is_array($prop['value'])) {
1887
				$opt['opt'] = array();
1888
				foreach ($prop['value'] AS $key => $optval) {
1889
					// exportValues: An array of strings representing the export values for the field.
1890
					if (isset($prop['exportValues'][$key])) {
1891
						$opt['opt'][$key] = array($prop['exportValues'][$key], $prop['value'][$key]);
1892
					} else {
1893
						$opt['opt'][$key] = $prop['value'][$key];
1894
					}
1895
				}
1896
			} else {
1897
				$opt['v'] = $prop['value'];
1898
			}
1899
		}
1900
		// richValue: This property specifies the text contents and formatting of a rich text field.
1901
		if (isset($prop['richValue'])) {
1902
			$opt['rv'] = $prop['richValue'];
1903
		}
1904
		// submitName: If nonempty, used during form submission instead of name. Only applicable if submitting in HTML format (that is, URL-encoded).
1905
		if (isset($prop['submitName'])) {
1906
			$opt['tm'] = $prop['submitName'];
1907
		}
1908
		// name: Fully qualified field name.
1909
		if (isset($prop['name'])) {
1910
			$opt['t'] = $prop['name'];
1911
		}
1912
		// userName: The user name (short description string) of the field.
1913
		if (isset($prop['userName'])) {
1914
			$opt['tu'] = $prop['userName'];
1915
		}
1916
		// highlight: Defines how a button reacts when a user clicks it.
1917
		if (isset($prop['highlight'])) {
1918
			switch ($prop['highlight']) {
1919
				case 'none':
1920
				case 'highlight.n': {
1921
					$opt['h'] = 'N';
1922
					break;
1923
				}
1924
				case 'invert':
1925
				case 'highlight.i': {
1926
					$opt['h'] = 'i';
1927
					break;
1928
				}
1929
				case 'push':
1930
				case 'highlight.p': {
1931
					$opt['h'] = 'P';
1932
					break;
1933
				}
1934
				case 'outline':
1935
				case 'highlight.o': {
1936
					$opt['h'] = 'O';
1937
					break;
1938
				}
1939
			}
1940
		}
1941
		// Unsupported options:
1942
		// - calcOrderIndex: Changes the calculation order of fields in the document.
1943
		// - delay: Delays the redrawing of a field's appearance.
1944
		// - defaultStyle: This property defines the default style attributes for the form field.
1945
		// - style: Allows the user to set the glyph style of a check box or radio button.
1946
		// - textColor, textFont, textSize
1947
		return $opt;
1948
	}
1949
 
1950
	/**
1951
	 * Format the page numbers.
1952
	 * This method can be overriden for custom formats.
1953
	 * @param $num (int) page number
1954
	 * @since 4.2.005 (2008-11-06)
1955
	 * @public static
1956
	 */
1957
	public static function formatPageNumber($num) {
1958
		return number_format((float)$num, 0, '', '.');
1959
	}
1960
 
1961
	/**
1962
	 * Format the page numbers on the Table Of Content.
1963
	 * This method can be overriden for custom formats.
1964
	 * @param $num (int) page number
1965
	 * @since 4.5.001 (2009-01-04)
1966
	 * @see addTOC(), addHTMLTOC()
1967
	 * @public static
1968
	 */
1969
	public static function formatTOCPageNumber($num) {
1970
		return number_format((float)$num, 0, '', '.');
1971
	}
1972
 
1973
	/**
1974
	 * Extracts the CSS properties from a CSS string.
1975
	 * @param $cssdata (string) string containing CSS definitions.
1976
	 * @return An array where the keys are the CSS selectors and the values are the CSS properties.
1977
	 * @author Nicola Asuni
1978
	 * @since 5.1.000 (2010-05-25)
1979
	 * @public static
1980
	 */
1981
	public static function extractCSSproperties($cssdata) {
1982
		if (empty($cssdata)) {
1983
			return array();
1984
		}
1985
		// remove comments
1986
		$cssdata = preg_replace('/\/\*[^\*]*\*\//', '', $cssdata);
1987
		// remove newlines and multiple spaces
1988
		$cssdata = preg_replace('/[\s]+/', ' ', $cssdata);
1989
		// remove some spaces
1990
		$cssdata = preg_replace('/[\s]*([;:\{\}]{1})[\s]*/', '\\1', $cssdata);
1991
		// remove empty blocks
1992
		$cssdata = preg_replace('/([^\}\{]+)\{\}/', '', $cssdata);
1993
		// replace media type parenthesis
1994
		$cssdata = preg_replace('/@media[\s]+([^\{]*)\{/i', '@media \\1§', $cssdata);
1995
		$cssdata = preg_replace('/\}\}/si', '}§', $cssdata);
1996
		// trim string
1997
		$cssdata = trim($cssdata);
1998
		// find media blocks (all, braille, embossed, handheld, print, projection, screen, speech, tty, tv)
1999
		$cssblocks = array();
2000
		$matches = array();
2001
		if (preg_match_all('/@media[\s]+([^\§]*)§([^§]*)§/i', $cssdata, $matches) > 0) {
2002
			foreach ($matches[1] as $key => $type) {
2003
				$cssblocks[$type] = $matches[2][$key];
2004
			}
2005
			// remove media blocks
2006
			$cssdata = preg_replace('/@media[\s]+([^\§]*)§([^§]*)§/i', '', $cssdata);
2007
		}
2008
		// keep 'all' and 'print' media, other media types are discarded
2009
		if (isset($cssblocks['all']) AND !empty($cssblocks['all'])) {
2010
			$cssdata .= $cssblocks['all'];
2011
		}
2012
		if (isset($cssblocks['print']) AND !empty($cssblocks['print'])) {
2013
			$cssdata .= $cssblocks['print'];
2014
		}
2015
		// reset css blocks array
2016
		$cssblocks = array();
2017
		$matches = array();
2018
		// explode css data string into array
2019
		if (substr($cssdata, -1) == '}') {
2020
			// remove last parethesis
2021
			$cssdata = substr($cssdata, 0, -1);
2022
		}
2023
		$matches = explode('}', $cssdata);
2024
		foreach ($matches as $key => $block) {
2025
			// index 0 contains the CSS selector, index 1 contains CSS properties
2026
			$cssblocks[$key] = explode('{', $block);
2027
			if (!isset($cssblocks[$key][1])) {
2028
				// remove empty definitions
2029
				unset($cssblocks[$key]);
2030
			}
2031
		}
2032
		// split groups of selectors (comma-separated list of selectors)
2033
		foreach ($cssblocks as $key => $block) {
2034
			if (strpos($block[0], ',') > 0) {
2035
				$selectors = explode(',', $block[0]);
2036
				foreach ($selectors as $sel) {
2037
					$cssblocks[] = array(0 => trim($sel), 1 => $block[1]);
2038
				}
2039
				unset($cssblocks[$key]);
2040
			}
2041
		}
2042
		// covert array to selector => properties
2043
		$cssdata = array();
2044
		foreach ($cssblocks as $block) {
2045
			$selector = $block[0];
2046
			// calculate selector's specificity
2047
			$matches = array();
2048
			$a = 0; // the declaration is not from is a 'style' attribute
2049
			$b = intval(preg_match_all('/[\#]/', $selector, $matches)); // number of ID attributes
2050
			$c = intval(preg_match_all('/[\[\.]/', $selector, $matches)); // number of other attributes
2051
			$c += intval(preg_match_all('/[\:]link|visited|hover|active|focus|target|lang|enabled|disabled|checked|indeterminate|root|nth|first|last|only|empty|contains|not/i', $selector, $matches)); // number of pseudo-classes
2052
			$d = intval(preg_match_all('/[\>\+\~\s]{1}[a-zA-Z0-9]+/', ' '.$selector, $matches)); // number of element names
2053
			$d += intval(preg_match_all('/[\:][\:]/', $selector, $matches)); // number of pseudo-elements
2054
			$specificity = $a.$b.$c.$d;
2055
			// add specificity to the beginning of the selector
2056
			$cssdata[$specificity.' '.$selector] = $block[1];
2057
		}
2058
		// sort selectors alphabetically to account for specificity
2059
		ksort($cssdata, SORT_STRING);
2060
		// return array
2061
		return $cssdata;
2062
	}
2063
 
2064
	/**
2065
	 * Cleanup HTML code (requires HTML Tidy library).
2066
	 * @param $html (string) htmlcode to fix
2067
	 * @param $default_css (string) CSS commands to add
2068
	 * @param $tagvs (array) parameters for setHtmlVSpace method
2069
	 * @param $tidy_options (array) options for tidy_parse_string function
2070
	 * @param $tagvspaces (array) Array of vertical spaces for tags.
2071
	 * @return string XHTML code cleaned up
2072
	 * @author Nicola Asuni
2073
	 * @since 5.9.017 (2010-11-16)
2074
	 * @see setHtmlVSpace()
2075
	 * @public static
2076
	 */
2077
	public static function fixHTMLCode($html, $default_css='', $tagvs='', $tidy_options='', &$tagvspaces) {
2078
		// configure parameters for HTML Tidy
2079
		if ($tidy_options === '') {
2080
			$tidy_options = array (
2081
				'clean' => 1,
2082
				'drop-empty-paras' => 0,
2083
				'drop-proprietary-attributes' => 1,
2084
				'fix-backslash' => 1,
2085
				'hide-comments' => 1,
2086
				'join-styles' => 1,
2087
				'lower-literals' => 1,
2088
				'merge-divs' => 1,
2089
				'merge-spans' => 1,
2090
				'output-xhtml' => 1,
2091
				'word-2000' => 1,
2092
				'wrap' => 0,
2093
				'output-bom' => 0,
2094
				//'char-encoding' => 'utf8',
2095
				//'input-encoding' => 'utf8',
2096
				//'output-encoding' => 'utf8'
2097
			);
2098
		}
2099
		// clean up the HTML code
2100
		$tidy = tidy_parse_string($html, $tidy_options);
2101
		// fix the HTML
2102
		$tidy->cleanRepair();
2103
		// get the CSS part
2104
		$tidy_head = tidy_get_head($tidy);
2105
		$css = $tidy_head->value;
2106
		$css = preg_replace('/<style([^>]+)>/ims', '<style>', $css);
2107
		$css = preg_replace('/<\/style>(.*)<style>/ims', "\n", $css);
2108
		$css = str_replace('/*<![CDATA[*/', '', $css);
2109
		$css = str_replace('/*]]>*/', '', $css);
2110
		preg_match('/<style>(.*)<\/style>/ims', $css, $matches);
2111
		if (isset($matches[1])) {
2112
			$css = strtolower($matches[1]);
2113
		} else {
2114
			$css = '';
2115
		}
2116
		// include default css
2117
		$css = '<style>'.$default_css.$css.'</style>';
2118
		// get the body part
2119
		$tidy_body = tidy_get_body($tidy);
2120
		$html = $tidy_body->value;
2121
		// fix some self-closing tags
2122
		$html = str_replace('<br>', '<br />', $html);
2123
		// remove some empty tag blocks
2124
		$html = preg_replace('/<div([^\>]*)><\/div>/', '', $html);
2125
		$html = preg_replace('/<p([^\>]*)><\/p>/', '', $html);
2126
		if ($tagvs !== '') {
2127
			// set vertical space for some XHTML tags
2128
			$tagvspaces = $tagvs;
2129
		}
2130
		// return the cleaned XHTML code + CSS
2131
		return $css.$html;
2132
	}
2133
 
2134
	/**
2135
	 * Returns true if the CSS selector is valid for the selected HTML tag
2136
	 * @param $dom (array) array of HTML tags and properties
2137
	 * @param $key (int) key of the current HTML tag
2138
	 * @param $selector (string) CSS selector string
2139
	 * @return true if the selector is valid, false otherwise
2140
	 * @since 5.1.000 (2010-05-25)
2141
	 * @public static
2142
	 */
2143
	public static function isValidCSSSelectorForTag($dom, $key, $selector) {
2144
		$valid = false; // value to be returned
2145
		$tag = $dom[$key]['value'];
2146
		$class = array();
2147
		if (isset($dom[$key]['attribute']['class']) AND !empty($dom[$key]['attribute']['class'])) {
2148
			$class = explode(' ', strtolower($dom[$key]['attribute']['class']));
2149
		}
2150
		$id = '';
2151
		if (isset($dom[$key]['attribute']['id']) AND !empty($dom[$key]['attribute']['id'])) {
2152
			$id = strtolower($dom[$key]['attribute']['id']);
2153
		}
2154
		$selector = preg_replace('/([\>\+\~\s]{1})([\.]{1})([^\>\+\~\s]*)/si', '\\1*.\\3', $selector);
2155
		$matches = array();
2156
		if (preg_match_all('/([\>\+\~\s]{1})([a-zA-Z0-9\*]+)([^\>\+\~\s]*)/si', $selector, $matches, PREG_PATTERN_ORDER | PREG_OFFSET_CAPTURE) > 0) {
2157
			$parentop = array_pop($matches[1]);
2158
			$operator = $parentop[0];
2159
			$offset = $parentop[1];
2160
			$lasttag = array_pop($matches[2]);
2161
			$lasttag = strtolower(trim($lasttag[0]));
2162
			if (($lasttag == '*') OR ($lasttag == $tag)) {
2163
				// the last element on selector is our tag or 'any tag'
2164
				$attrib = array_pop($matches[3]);
2165
				$attrib = strtolower(trim($attrib[0]));
2166
				if (!empty($attrib)) {
2167
					// check if matches class, id, attribute, pseudo-class or pseudo-element
2168
					switch ($attrib{0}) {
2169
						case '.': { // class
2170
							if (in_array(substr($attrib, 1), $class)) {
2171
								$valid = true;
2172
							}
2173
							break;
2174
						}
2175
						case '#': { // ID
2176
							if (substr($attrib, 1) == $id) {
2177
								$valid = true;
2178
							}
2179
							break;
2180
						}
2181
						case '[': { // attribute
2182
							$attrmatch = array();
2183
							if (preg_match('/\[([a-zA-Z0-9]*)[\s]*([\~\^\$\*\|\=]*)[\s]*["]?([^"\]]*)["]?\]/i', $attrib, $attrmatch) > 0) {
2184
								$att = strtolower($attrmatch[1]);
2185
								$val = $attrmatch[3];
2186
								if (isset($dom[$key]['attribute'][$att])) {
2187
									switch ($attrmatch[2]) {
2188
										case '=': {
2189
											if ($dom[$key]['attribute'][$att] == $val) {
2190
												$valid = true;
2191
											}
2192
											break;
2193
										}
2194
										case '~=': {
2195
											if (in_array($val, explode(' ', $dom[$key]['attribute'][$att]))) {
2196
												$valid = true;
2197
											}
2198
											break;
2199
										}
2200
										case '^=': {
2201
											if ($val == substr($dom[$key]['attribute'][$att], 0, strlen($val))) {
2202
												$valid = true;
2203
											}
2204
											break;
2205
										}
2206
										case '$=': {
2207
											if ($val == substr($dom[$key]['attribute'][$att], -strlen($val))) {
2208
												$valid = true;
2209
											}
2210
											break;
2211
										}
2212
										case '*=': {
2213
											if (strpos($dom[$key]['attribute'][$att], $val) !== false) {
2214
												$valid = true;
2215
											}
2216
											break;
2217
										}
2218
										case '|=': {
2219
											if ($dom[$key]['attribute'][$att] == $val) {
2220
												$valid = true;
2221
											} elseif (preg_match('/'.$val.'[\-]{1}/i', $dom[$key]['attribute'][$att]) > 0) {
2222
												$valid = true;
2223
											}
2224
											break;
2225
										}
2226
										default: {
2227
											$valid = true;
2228
										}
2229
									}
2230
								}
2231
							}
2232
							break;
2233
						}
2234
						case ':': { // pseudo-class or pseudo-element
2235
							if ($attrib{1} == ':') { // pseudo-element
2236
								// pseudo-elements are not supported!
2237
								// (::first-line, ::first-letter, ::before, ::after)
2238
							} else { // pseudo-class
2239
								// pseudo-classes are not supported!
2240
								// (:root, :nth-child(n), :nth-last-child(n), :nth-of-type(n), :nth-last-of-type(n), :first-child, :last-child, :first-of-type, :last-of-type, :only-child, :only-of-type, :empty, :link, :visited, :active, :hover, :focus, :target, :lang(fr), :enabled, :disabled, :checked)
2241
							}
2242
							break;
2243
						}
2244
					} // end of switch
2245
				} else {
2246
					$valid = true;
2247
				}
2248
				if ($valid AND ($offset > 0)) {
2249
					$valid = false;
2250
					// check remaining selector part
2251
					$selector = substr($selector, 0, $offset);
2252
					switch ($operator) {
2253
						case ' ': { // descendant of an element
2254
							while ($dom[$key]['parent'] > 0) {
2255
								if (self::isValidCSSSelectorForTag($dom, $dom[$key]['parent'], $selector)) {
2256
									$valid = true;
2257
									break;
2258
								} else {
2259
									$key = $dom[$key]['parent'];
2260
								}
2261
							}
2262
							break;
2263
						}
2264
						case '>': { // child of an element
2265
							$valid = self::isValidCSSSelectorForTag($dom, $dom[$key]['parent'], $selector);
2266
							break;
2267
						}
2268
						case '+': { // immediately preceded by an element
2269
							for ($i = ($key - 1); $i > $dom[$key]['parent']; --$i) {
2270
								if ($dom[$i]['tag'] AND $dom[$i]['opening']) {
2271
									$valid = self::isValidCSSSelectorForTag($dom, $i, $selector);
2272
									break;
2273
								}
2274
							}
2275
							break;
2276
						}
2277
						case '~': { // preceded by an element
2278
							for ($i = ($key - 1); $i > $dom[$key]['parent']; --$i) {
2279
								if ($dom[$i]['tag'] AND $dom[$i]['opening']) {
2280
									if (self::isValidCSSSelectorForTag($dom, $i, $selector)) {
2281
										break;
2282
									}
2283
								}
2284
							}
2285
							break;
2286
						}
2287
					}
2288
				}
2289
			}
2290
		}
2291
		return $valid;
2292
	}
2293
 
2294
	/**
2295
	 * Returns the styles array that apply for the selected HTML tag.
2296
	 * @param $dom (array) array of HTML tags and properties
2297
	 * @param $key (int) key of the current HTML tag
2298
	 * @param $css (array) array of CSS properties
2299
	 * @return array containing CSS properties
2300
	 * @since 5.1.000 (2010-05-25)
2301
	 * @public static
2302
	 */
2303
	public static function getCSSdataArray($dom, $key, $css) {
2304
		$cssarray = array(); // style to be returned
2305
		// get parent CSS selectors
2306
		$selectors = array();
2307
		if (isset($dom[($dom[$key]['parent'])]['csssel'])) {
2308
			$selectors = $dom[($dom[$key]['parent'])]['csssel'];
2309
		}
2310
		// get all styles that apply
2311
		foreach($css as $selector => $style) {
2312
			$pos = strpos($selector, ' ');
2313
			// get specificity
2314
			$specificity = substr($selector, 0, $pos);
2315
			// remove specificity
2316
			$selector = substr($selector, $pos);
2317
			// check if this selector apply to current tag
2318
			if (self::isValidCSSSelectorForTag($dom, $key, $selector)) {
2319
				if (!in_array($selector, $selectors)) {
2320
					// add style if not already added on parent selector
2321
					$cssarray[] = array('k' => $selector, 's' => $specificity, 'c' => $style);
2322
					$selectors[] = $selector;
2323
				}
2324
			}
2325
		}
2326
		if (isset($dom[$key]['attribute']['style'])) {
2327
			// attach inline style (latest properties have high priority)
2328
			$cssarray[] = array('k' => '', 's' => '1000', 'c' => $dom[$key]['attribute']['style']);
2329
		}
2330
		// order the css array to account for specificity
2331
		$cssordered = array();
2332
		foreach ($cssarray as $key => $val) {
2333
			$skey = sprintf('%04d', $key);
2334
			$cssordered[$val['s'].'_'.$skey] = $val;
2335
		}
2336
		// sort selectors alphabetically to account for specificity
2337
		ksort($cssordered, SORT_STRING);
2338
		return array($selectors, $cssordered);
2339
	}
2340
 
2341
	/**
2342
	 * Compact CSS data array into single string.
2343
	 * @param $css (array) array of CSS properties
2344
	 * @return string containing merged CSS properties
2345
	 * @since 5.9.070 (2011-04-19)
2346
	 * @public static
2347
	 */
2348
	public static function getTagStyleFromCSSarray($css) {
2349
		$tagstyle = ''; // value to be returned
2350
		foreach ($css as $style) {
2351
			// split single css commands
2352
			$csscmds = explode(';', $style['c']);
2353
			foreach ($csscmds as $cmd) {
2354
				if (!empty($cmd)) {
2355
					$pos = strpos($cmd, ':');
2356
					if ($pos !== false) {
2357
						$cmd = substr($cmd, 0, ($pos + 1));
2358
						if (strpos($tagstyle, $cmd) !== false) {
2359
							// remove duplicate commands (last commands have high priority)
2360
							$tagstyle = preg_replace('/'.$cmd.'[^;]+/i', '', $tagstyle);
2361
						}
2362
					}
2363
				}
2364
			}
2365
			$tagstyle .= ';'.$style['c'];
2366
		}
2367
		// remove multiple semicolons
2368
		$tagstyle = preg_replace('/[;]+/', ';', $tagstyle);
2369
		return $tagstyle;
2370
	}
2371
 
2372
	/**
2373
	 * Returns the Roman representation of an integer number
2374
	 * @param $number (int) number to convert
2375
	 * @return string roman representation of the specified number
2376
	 * @since 4.4.004 (2008-12-10)
2377
	 * @public static
2378
	 */
2379
	public static function intToRoman($number) {
2380
		$roman = '';
2381
		while ($number >= 1000) {
2382
			$roman .= 'M';
2383
			$number -= 1000;
2384
		}
2385
		while ($number >= 900) {
2386
			$roman .= 'CM';
2387
			$number -= 900;
2388
		}
2389
		while ($number >= 500) {
2390
			$roman .= 'D';
2391
			$number -= 500;
2392
		}
2393
		while ($number >= 400) {
2394
			$roman .= 'CD';
2395
			$number -= 400;
2396
		}
2397
		while ($number >= 100) {
2398
			$roman .= 'C';
2399
			$number -= 100;
2400
		}
2401
		while ($number >= 90) {
2402
			$roman .= 'XC';
2403
			$number -= 90;
2404
		}
2405
		while ($number >= 50) {
2406
			$roman .= 'L';
2407
			$number -= 50;
2408
		}
2409
		while ($number >= 40) {
2410
			$roman .= 'XL';
2411
			$number -= 40;
2412
		}
2413
		while ($number >= 10) {
2414
			$roman .= 'X';
2415
			$number -= 10;
2416
		}
2417
		while ($number >= 9) {
2418
			$roman .= 'IX';
2419
			$number -= 9;
2420
		}
2421
		while ($number >= 5) {
2422
			$roman .= 'V';
2423
			$number -= 5;
2424
		}
2425
		while ($number >= 4) {
2426
			$roman .= 'IV';
2427
			$number -= 4;
2428
		}
2429
		while ($number >= 1) {
2430
			$roman .= 'I';
2431
			--$number;
2432
		}
2433
		return $roman;
2434
	}
2435
 
2436
	/**
2437
	 * Find position of last occurrence of a substring in a string
2438
	 * @param $haystack (string) The string to search in.
2439
	 * @param $needle (string) substring to search.
2440
	 * @param $offset (int) May be specified to begin searching an arbitrary number of characters into the string.
2441
	 * @return Returns the position where the needle exists. Returns FALSE if the needle was not found.
2442
	 * @since 4.8.038 (2010-03-13)
2443
	 * @public static
2444
	 */
2445
	public static function revstrpos($haystack, $needle, $offset = 0) {
2446
		$length = strlen($haystack);
2447
		$offset = ($offset > 0)?($length - $offset):abs($offset);
2448
		$pos = strpos(strrev($haystack), strrev($needle), $offset);
2449
		return ($pos === false)?false:($length - $pos - strlen($needle));
2450
	}
2451
 
2452
	/**
2453
	 * Serialize an array of parameters to be used with TCPDF tag in HTML code.
2454
	 * @param $pararray (array) parameters array
2455
	 * @return sting containing serialized data
2456
	 * @since 4.9.006 (2010-04-02)
2457
	 * @public static
2458
	 */
2459
	public static function serializeTCPDFtagParameters($pararray) {
2460
		return urlencode(serialize($pararray));
2461
	}
2462
 
2463
	/**
2464
	 * Returns an array of hyphenation patterns.
2465
	 * @param $file (string) TEX file containing hypenation patterns. TEX pattrns can be downloaded from http://www.ctan.org/tex-archive/language/hyph-utf8/tex/generic/hyph-utf8/patterns/
2466
	 * @return array of hyphenation patterns
2467
	 * @author Nicola Asuni
2468
	 * @since 4.9.012 (2010-04-12)
2469
	 * @public static
2470
	 */
2471
	public static function getHyphenPatternsFromTEX($file) {
2472
		// TEX patterns are available at:
2473
		// http://www.ctan.org/tex-archive/language/hyph-utf8/tex/generic/hyph-utf8/patterns/
2474
		$data = file_get_contents($file);
2475
		$patterns = array();
2476
		// remove comments
2477
		$data = preg_replace('/\%[^\n]*/', '', $data);
2478
		// extract the patterns part
2479
		preg_match('/\\\\patterns\{([^\}]*)\}/i', $data, $matches);
2480
		$data = trim(substr($matches[0], 10, -1));
2481
		// extract each pattern
2482
		$patterns_array = preg_split('/[\s]+/', $data);
2483
		// create new language array of patterns
2484
		$patterns = array();
2485
		foreach($patterns_array as $val) {
2486
			if (!TCPDF_STATIC::empty_string($val)) {
2487
				$val = trim($val);
2488
				$val = str_replace('\'', '\\\'', $val);
2489
				$key = preg_replace('/[0-9]+/', '', $val);
2490
				$patterns[$key] = $val;
2491
			}
2492
		}
2493
		return $patterns;
2494
	}
2495
 
2496
	/**
2497
	 * Get the Path-Painting Operators.
2498
	 * @param $style (string) Style of rendering. Possible values are:
2499
	 * <ul>
2500
	 *   <li>S or D: Stroke the path.</li>
2501
	 *   <li>s or d: Close and stroke the path.</li>
2502
	 *   <li>f or F: Fill the path, using the nonzero winding number rule to determine the region to fill.</li>
2503
	 *   <li>f* or F*: Fill the path, using the even-odd rule to determine the region to fill.</li>
2504
	 *   <li>B or FD or DF: Fill and then stroke the path, using the nonzero winding number rule to determine the region to fill.</li>
2505
	 *   <li>B* or F*D or DF*: Fill and then stroke the path, using the even-odd rule to determine the region to fill.</li>
2506
	 *   <li>b or fd or df: Close, fill, and then stroke the path, using the nonzero winding number rule to determine the region to fill.</li>
2507
	 *   <li>b or f*d or df*: Close, fill, and then stroke the path, using the even-odd rule to determine the region to fill.</li>
2508
	 *   <li>CNZ: Clipping mode using the even-odd rule to determine which regions lie inside the clipping path.</li>
2509
	 *   <li>CEO: Clipping mode using the nonzero winding number rule to determine which regions lie inside the clipping path</li>
2510
	 *   <li>n: End the path object without filling or stroking it.</li>
2511
	 * </ul>
2512
	 * @param $default (string) default style
2513
	 * @author Nicola Asuni
2514
	 * @since 5.0.000 (2010-04-30)
2515
	 * @public static
2516
	 */
2517
	public static function getPathPaintOperator($style, $default='S') {
2518
		$op = '';
2519
		switch($style) {
2520
			case 'S':
2521
			case 'D': {
2522
				$op = 'S';
2523
				break;
2524
			}
2525
			case 's':
2526
			case 'd': {
2527
				$op = 's';
2528
				break;
2529
			}
2530
			case 'f':
2531
			case 'F': {
2532
				$op = 'f';
2533
				break;
2534
			}
2535
			case 'f*':
2536
			case 'F*': {
2537
				$op = 'f*';
2538
				break;
2539
			}
2540
			case 'B':
2541
			case 'FD':
2542
			case 'DF': {
2543
				$op = 'B';
2544
				break;
2545
			}
2546
			case 'B*':
2547
			case 'F*D':
2548
			case 'DF*': {
2549
				$op = 'B*';
2550
				break;
2551
			}
2552
			case 'b':
2553
			case 'fd':
2554
			case 'df': {
2555
				$op = 'b';
2556
				break;
2557
			}
2558
			case 'b*':
2559
			case 'f*d':
2560
			case 'df*': {
2561
				$op = 'b*';
2562
				break;
2563
			}
2564
			case 'CNZ': {
2565
				$op = 'W n';
2566
				break;
2567
			}
2568
			case 'CEO': {
2569
				$op = 'W* n';
2570
				break;
2571
			}
2572
			case 'n': {
2573
				$op = 'n';
2574
				break;
2575
			}
2576
			default: {
2577
				if (!empty($default)) {
2578
					$op = self::getPathPaintOperator($default, '');
2579
				} else {
2580
					$op = '';
2581
				}
2582
			}
2583
		}
2584
		return $op;
2585
	}
2586
 
2587
	/**
2588
	 * Get the product of two SVG tranformation matrices
2589
	 * @param $ta (array) first SVG tranformation matrix
2590
	 * @param $tb (array) second SVG tranformation matrix
2591
	 * @return transformation array
2592
	 * @author Nicola Asuni
2593
	 * @since 5.0.000 (2010-05-02)
2594
	 * @public static
2595
	 */
2596
	public static function getTransformationMatrixProduct($ta, $tb) {
2597
		$tm = array();
2598
		$tm[0] = ($ta[0] * $tb[0]) + ($ta[2] * $tb[1]);
2599
		$tm[1] = ($ta[1] * $tb[0]) + ($ta[3] * $tb[1]);
2600
		$tm[2] = ($ta[0] * $tb[2]) + ($ta[2] * $tb[3]);
2601
		$tm[3] = ($ta[1] * $tb[2]) + ($ta[3] * $tb[3]);
2602
		$tm[4] = ($ta[0] * $tb[4]) + ($ta[2] * $tb[5]) + $ta[4];
2603
		$tm[5] = ($ta[1] * $tb[4]) + ($ta[3] * $tb[5]) + $ta[5];
2604
		return $tm;
2605
	}
2606
 
2607
	/**
2608
	 * Get the tranformation matrix from SVG transform attribute
2609
	 * @param $attribute (string) transformation
2610
	 * @return array of transformations
2611
	 * @author Nicola Asuni
2612
	 * @since 5.0.000 (2010-05-02)
2613
	 * @public static
2614
	 */
2615
	public static function getSVGTransformMatrix($attribute) {
2616
		// identity matrix
2617
		$tm = array(1, 0, 0, 1, 0, 0);
2618
		$transform = array();
2619
		if (preg_match_all('/(matrix|translate|scale|rotate|skewX|skewY)[\s]*\(([^\)]+)\)/si', $attribute, $transform, PREG_SET_ORDER) > 0) {
2620
			foreach ($transform as $key => $data) {
2621
				if (!empty($data[2])) {
2622
					$a = 1;
2623
					$b = 0;
2624
					$c = 0;
2625
					$d = 1;
2626
					$e = 0;
2627
					$f = 0;
2628
					$regs = array();
2629
					switch ($data[1]) {
2630
						case 'matrix': {
2631
							if (preg_match('/([a-z0-9\-\.]+)[\,\s]+([a-z0-9\-\.]+)[\,\s]+([a-z0-9\-\.]+)[\,\s]+([a-z0-9\-\.]+)[\,\s]+([a-z0-9\-\.]+)[\,\s]+([a-z0-9\-\.]+)/si', $data[2], $regs)) {
2632
								$a = $regs[1];
2633
								$b = $regs[2];
2634
								$c = $regs[3];
2635
								$d = $regs[4];
2636
								$e = $regs[5];
2637
								$f = $regs[6];
2638
							}
2639
							break;
2640
						}
2641
						case 'translate': {
2642
							if (preg_match('/([a-z0-9\-\.]+)[\,\s]+([a-z0-9\-\.]+)/si', $data[2], $regs)) {
2643
								$e = $regs[1];
2644
								$f = $regs[2];
2645
							} elseif (preg_match('/([a-z0-9\-\.]+)/si', $data[2], $regs)) {
2646
								$e = $regs[1];
2647
							}
2648
							break;
2649
						}
2650
						case 'scale': {
2651
							if (preg_match('/([a-z0-9\-\.]+)[\,\s]+([a-z0-9\-\.]+)/si', $data[2], $regs)) {
2652
								$a = $regs[1];
2653
								$d = $regs[2];
2654
							} elseif (preg_match('/([a-z0-9\-\.]+)/si', $data[2], $regs)) {
2655
								$a = $regs[1];
2656
								$d = $a;
2657
							}
2658
							break;
2659
						}
2660
						case 'rotate': {
2661
							if (preg_match('/([0-9\-\.]+)[\,\s]+([a-z0-9\-\.]+)[\,\s]+([a-z0-9\-\.]+)/si', $data[2], $regs)) {
2662
								$ang = deg2rad($regs[1]);
2663
								$x = $regs[2];
2664
								$y = $regs[3];
2665
								$a = cos($ang);
2666
								$b = sin($ang);
2667
								$c = -$b;
2668
								$d = $a;
2669
								$e = ($x * (1 - $a)) - ($y * $c);
2670
								$f = ($y * (1 - $d)) - ($x * $b);
2671
							} elseif (preg_match('/([0-9\-\.]+)/si', $data[2], $regs)) {
2672
								$ang = deg2rad($regs[1]);
2673
								$a = cos($ang);
2674
								$b = sin($ang);
2675
								$c = -$b;
2676
								$d = $a;
2677
								$e = 0;
2678
								$f = 0;
2679
							}
2680
							break;
2681
						}
2682
						case 'skewX': {
2683
							if (preg_match('/([0-9\-\.]+)/si', $data[2], $regs)) {
2684
								$c = tan(deg2rad($regs[1]));
2685
							}
2686
							break;
2687
						}
2688
						case 'skewY': {
2689
							if (preg_match('/([0-9\-\.]+)/si', $data[2], $regs)) {
2690
								$b = tan(deg2rad($regs[1]));
2691
							}
2692
							break;
2693
						}
2694
					}
2695
					$tm = self::getTransformationMatrixProduct($tm, array($a, $b, $c, $d, $e, $f));
2696
				}
2697
			}
2698
		}
2699
		return $tm;
2700
	}
2701
 
2702
	/**
2703
	 * Returns the angle in radiants between two vectors
2704
	 * @param $x1 (int) X coordinate of first vector point
2705
	 * @param $y1 (int) Y coordinate of first vector point
2706
	 * @param $x2 (int) X coordinate of second vector point
2707
	 * @param $y2 (int) Y coordinate of second vector point
2708
	 * @author Nicola Asuni
2709
	 * @since 5.0.000 (2010-05-04)
2710
	 * @public static
2711
	 */
2712
	public static function getVectorsAngle($x1, $y1, $x2, $y2) {
2713
		$dprod = ($x1 * $x2) + ($y1 * $y2);
2714
		$dist1 = sqrt(($x1 * $x1) + ($y1 * $y1));
2715
		$dist2 = sqrt(($x2 * $x2) + ($y2 * $y2));
2716
		$angle = acos($dprod / ($dist1 * $dist2));
2717
		if (is_nan($angle)) {
2718
			$angle = M_PI;
2719
		}
2720
		if ((($x1 * $y2) - ($x2 * $y1)) < 0) {
2721
			$angle *= -1;
2722
		}
2723
		return $angle;
2724
	}
2725
 
2726
} // END OF TCPDF_STATIC CLASS
2727
 
2728
//============================================================+
2729
// END OF FILE
2730
//============================================================+