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