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