PluginProbe
Welcart e-Commerce / 2.12.4
Welcart e-Commerce v2.12.4
2.12.4 2.12.3 2.11.35 2.12.2 2.12.1 2.11.34 2.11.33 2.11.32 2.11.31 2.11.30 1.3.16 1.3.17 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 1.3.7 1.3.8 1.3.9 1.4.0 1.4.1 1.4.10 1.4.11 1.4.12 All 292 releases
usc-e-shop / pdf / tcpdf / include / tcpdf_static.php

tcpdf_static.php in Welcart e-Commerce 2.12.4, at pdf/tcpdf/include/tcpdf_static.php

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