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